ehea: interface to network stack
Subsystems (2)
PATCH 1/6 ehea: interface to network stack
drivers/net/ehea/ehea_main.c | 2738 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2738 insertions(+)
drivers/net/ehea/ehea_main.c +2738 -0
@@ -0,0 +1,2738 @@ +/* +* linux/drivers/net/ehea/ehea_main.c +* +* eHEA ethernet device driver for IBM eServer System p +* +* (C) Copyright IBM Corp. 2006 +* +* Authors: +* Christoph Raisch <[email protected]> +* Jan-Bernd Themann <[email protected]> +* Heiko-Joerg Schick <[email protected]> +* Thomas Klein <[email protected]> +* +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEB_PREFIX "main" + +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/if.h> +#include <linux/list.h> +#include <net/ip.h> + +#include "ehea.h" +#include "ehea_qmr.h" +#include "ehea_phyp.h" + + +MODULE_LICENSE ("GPL" ); +MODULE_AUTHOR ("Christoph Raisch <[email protected]>" ); +MODULE_DESCRIPTION ("IBM eServer HEA Driver" ); +MODULE_VERSION (EHEA_DRIVER_VERSION ); + +static int __devinit ehea_probe (struct ibmebus_dev *dev, +const struct of_device_id *id); +static int __devexit ehea_remove(struct ibmebus_dev *dev); +static int ehea_sense_port_attr (struct ehea_adapter *adapter,int portnum); + + +int ehea_trace_level =5 ; + +static struct net_device_stats *ehea_get_stats (struct net_device *dev) +{ +int i; +u64 hret =H_HARDWARE ; +u64 rx_packets =0 ; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_adapter *adapter = port->adapter; +struct hcp_query_ehea_port_cb_2 *cb2 =NULL ; +struct net_device_stats *stats = &port->stats; + +EDEB_EN (7 ,"net_device=%p" , dev); + + cb2 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb2) { +EDEB_ERR (4 ,"No memory for cb2" ); + goto get_stat_exit; + } + + hret =ehea_h_query_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB2 , +H_PORT_CB2_ALL , + cb2); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_port failed for cb2" ); + goto get_stat_exit; + } + +EDEB_DMP (7 , (u8 *)cb2, +sizeof (struct hcp_query_ehea_port_cb_2 ),"After HCALL" ); + +for (i =0 ; i < port->num_def_qps; i++) { + rx_packets += port->port_res[i].rx_packets; + } + + stats->tx_packets = cb2->txucp + cb2->txmcp + cb2->txbcp; + stats->multicast = cb2->rxmcp; + stats->rx_errors = cb2->rxuerr; + stats->rx_bytes = cb2->rxo; + stats->tx_bytes = cb2->txo; + stats->rx_packets = rx_packets; + +get_stat_exit: +EDEB_EX (7 ,"" ); +return stats; +} + +static inline u32 ehea_get_send_lkey (struct ehea_port_res *pr) +{ +return pr->send_mr.lkey; +} + +static inline u32 ehea_get_recv_lkey (struct ehea_port_res *pr) +{ +return pr->recv_mr.lkey; +} + +#define EHEA_OD_ADDR (address, segment) (((address) & (PAGE_SIZE - 1)) \ + | ((segment) << 12)); + +static inline u64 get_swqe_addr (u64 tmp_addr,int addr_seg) +{ +u64 addr; + addr = tmp_addr; +return addr; +} + +static inline u64 get_rwqe_addr (u64 tmp_addr) +{ +return tmp_addr; +} + + +static inline int ehea_refill_rq1 (struct ehea_port_res *port_res,int arr_index, +int nr_of_wqes) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +int skb_arr_rq1_len = port_res->skb_arr_rq1_len; +struct sk_buff **skb_arr_rq1 = port_res->skb_arr_rq1; +EDEB_EN (7 ,"port_res=%p, arr_index=%d, nr_of_wqes=%d, arr_rq1_len=%d" , + port_res, arr_index, nr_of_wqes, skb_arr_rq1_len); + + qp = port_res->qp; +if (unlikely (nr_of_wqes ==0 )) +return -EINVAL ; +for (i =0 ; i < nr_of_wqes; i++) { +int index = ((skb_arr_rq1_len + arr_index) - i) + % skb_arr_rq1_len; +if (!skb_arr_rq1[index]) { + skb_arr_rq1[index] =dev_alloc_skb (EHEA_LL_PKT_SIZE ); + +if (!skb_arr_rq1[index]) { +EDEB_ERR (4 ,"No mem for skb/%d wqes filled" , i); + ret = -ENOMEM ; +break ; + } + } + } +/* Ring doorbell */ +ehea_update_rq1a (qp, nr_of_wqes); +EDEB_EX (7 ,"" ); +return ret; +} + +static int ehea_init_fill_rq1 (struct ehea_port_res *port_res,int nr_rq1a) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +EDEB_EN (7 ,"port_res=%p, nr_rq1a=%d" , port_res, nr_rq1a); + qp = port_res->qp; + +for (i =0 ; i < port_res->skb_arr_rq1_len; i++) { + port_res->skb_arr_rq1[i] =dev_alloc_skb (EHEA_LL_PKT_SIZE ); +if (!port_res->skb_arr_rq1[i]) { +EDEB_ERR (4 ,"dev_alloc_skb failed. Only %d skb filled." , + i); + ret = -ENOMEM ; +break ; + } + } +/* Ring doorbell */ +ehea_update_rq1a (qp, nr_rq1a); +EDEB_EX (7 ,"" ); +return ret; +} + +static inline int ehea_refill_rq2_def (struct ehea_port_res *pr,int nr_of_wqes) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +struct ehea_rwqe *rwqe; +int skb_arr_rq2_len = pr->skb_arr_rq2_len; +struct sk_buff **skb_arr_rq2 = pr->skb_arr_rq2; + +EDEB_EN (8 ,"pr=%p, nr_of_wqes=%d" , pr, nr_of_wqes); +if (nr_of_wqes ==0 ) +return -EINVAL ; + qp = pr->qp; +for (i =0 ; i < nr_of_wqes; i++) { +int index = pr->skb_rq2_index++; +struct sk_buff *skb =dev_alloc_skb (EHEA_RQ2_PKT_SIZE + +NET_IP_ALIGN ); + +if (!skb) { +EDEB_ERR (4 ,"dev_alloc_skb nr %d failed" , i); + ret = -ENOMEM ; +break ; + } +skb_reserve (skb,NET_IP_ALIGN ); + pr->skb_rq2_index %= skb_arr_rq2_len; + skb_arr_rq2[index] = skb; + rwqe =ehea_get_next_rwqe (qp,2 ); + rwqe->wr_id =EHEA_BMASK_SET (EHEA_WR_ID_TYPE ,EHEA_RWQE2_TYPE ) + |EHEA_BMASK_SET (EHEA_WR_ID_INDEX , index); + rwqe->sg_list[0 ].l_key =ehea_get_recv_lkey (pr); + rwqe->sg_list[0 ].vaddr =get_rwqe_addr ((u64 )skb->data); + rwqe->sg_list[0 ].len =EHEA_RQ2_PKT_SIZE ; + rwqe->data_segments =1 ; + } + +/* Ring doorbell */ +iosync (); +ehea_update_rq2a (qp, i); +EDEB_EX (8 ,"" ); +return ret; +} + + +static inline int ehea_refill_rq2 (struct ehea_port_res *pr,int nr_of_wqes) +{ +return ehea_refill_rq2_def (pr, nr_of_wqes); +} + +static inline int ehea_refill_rq3_def (struct ehea_port_res *pr,int nr_of_wqes) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +struct ehea_rwqe *rwqe; +int skb_arr_rq3_len = pr->skb_arr_rq3_len; +struct sk_buff **skb_arr_rq3 = pr->skb_arr_rq3; +EDEB_EN (8 ,"pr=%p, nr_of_wqes=%d" , pr, nr_of_wqes); +if (nr_of_wqes ==0 ) +return -EINVAL ; + qp = pr->qp; +for (i =0 ; i < nr_of_wqes; i++) { +int index = pr->skb_rq3_index++; +struct sk_buff *skb =dev_alloc_skb (EHEA_MAX_PACKET_SIZE + +NET_IP_ALIGN ); + +if (!skb) { +EDEB_ERR (4 ,"No memory for skb. Only %d rwqe filled." , + i); + ret = -ENOMEM ; +break ; + } +skb_reserve (skb,NET_IP_ALIGN ); + + rwqe =ehea_get_next_rwqe (qp,3 ); + pr->skb_rq3_index %= skb_arr_rq3_len; + skb_arr_rq3[index] = skb; + rwqe->wr_id =EHEA_BMASK_SET (EHEA_WR_ID_TYPE ,EHEA_RWQE3_TYPE ) + |EHEA_BMASK_SET (EHEA_WR_ID_INDEX , index); + rwqe->sg_list[0 ].l_key =ehea_get_recv_lkey (pr); + rwqe->sg_list[0 ].vaddr =get_rwqe_addr ((u64 )skb->data); + rwqe->sg_list[0 ].len =EHEA_MAX_PACKET_SIZE ; + rwqe->data_segments =1 ; + } + +/* Ring doorbell */ +iosync (); +ehea_update_rq3a (qp, i); +EDEB_EX (8 ,"" ); +return ret; +} + + +static inline int ehea_refill_rq3 (struct ehea_port_res *pr,int nr_of_wqes) +{ +return ehea_refill_rq3_def (pr, nr_of_wqes); +} + + +static inline int ehea_check_cqe (struct ehea_cqe *cqe,int *rq_num) +{ + *rq_num = (cqe->type &EHEA_CQE_TYPE_RQ ) >>5 ; +EDEB (7 ,"RQ used=%d, status=%X" , *rq_num, cqe->status); +if ((cqe->status &EHEA_CQE_STAT_ERR_MASK ) ==0 ) +return 0 ; +if (((cqe->status &EHEA_CQE_STAT_ERR_TCP ) !=0 ) + && (cqe->header_length ==0 )) +return 0 ; +else +printk ("WARNING: Packet discarded. Wrong TCP/UDP chksum" +"and header_length != 0. cqe->status=%X" , cqe->status); + +return -EINVAL ; +} + +static inline void ehea_fill_skb_ll (struct net_device *dev, +struct sk_buff *skb,struct ehea_cqe *cqe) +{ +int length = cqe->num_bytes_transfered -4 ;/*remove CRC */ +EDEB_EN (7 ,"dev=%p, skb=%p, cqe=%p" , dev, skb, cqe); +memcpy (skb->data, ((char *)cqe) +64 , length); +skb_put (skb, length); + skb->dev = dev; + skb->ip_summed =CHECKSUM_UNNECESSARY ; + skb->protocol =eth_type_trans (skb, dev); +EDEB_EX (7 ,"" ); +} + +static inline void ehea_fill_skb (struct net_device *dev, +struct sk_buff *skb,struct ehea_cqe *cqe) +{ +int length = cqe->num_bytes_transfered -4 ;/*remove CRC */ +EDEB_EN (7 ,"dev=%p, skb=%p, cqe=%p" , dev, skb, cqe); +skb_put (skb, length); + skb->dev = dev; + skb->ip_summed =CHECKSUM_UNNECESSARY ; + skb->protocol =eth_type_trans (skb, dev); +EDEB_EX (7 ,"" ); +} + + +#define EHEA_MAX_RWQE 1000 + +static int ehea_poll (struct net_device *dev,int *budget) +{ +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_port_res *port_res = &port->port_res[0 ]; +struct ehea_cqe *cqe; +struct ehea_qp *qp = port_res->qp; +int wqe_index =0 ; +int last_wqe_index =0 ; +int x =0 ; +int processed =0 ; +int processed_RQ1 =0 ; +int processed_RQ2 =0 ; +int processed_RQ3 =0 ; +int rq; +int intreq; +struct sk_buff **skb_arr_rq1 = port_res->skb_arr_rq1; +struct sk_buff **skb_arr_rq2 = port_res->skb_arr_rq2; +struct sk_buff **skb_arr_rq3 = port_res->skb_arr_rq3; +int skb_arr_rq1_len = port_res->skb_arr_rq1_len; +int my_quota =min (*budget, dev->quota); + +EDEB_EN (7 ,"dev=%p, port_res=%p, budget=%d, quota=%d, qp_nr=%x" , + dev, port_res, *budget, dev->quota, + port_res->qp->init_attr.qp_nr); + my_quota =min (my_quota,EHEA_MAX_RWQE ); + +/* rq0 is low latency RQ */ + cqe =ehea_poll_rq1 (qp, &wqe_index); +while ((my_quota >0 ) && cqe) { +ehea_inc_rq1 (qp); + processed_RQ1++; + processed++; + my_quota--; + +EDEB_DMP (6 , (u8 *)cqe,4 *16 ,"CQE" ); + last_wqe_index = wqe_index; +rmb (); +if (!ehea_check_cqe (cqe, &rq)) { +struct sk_buff *skb; +if (rq ==1 ) {/* LL RQ1 */ +void *pref; + + x = (wqe_index +1 ) % skb_arr_rq1_len; + pref = (void *)skb_arr_rq1[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (wqe_index +1 ) % skb_arr_rq1_len; + pref = (void *)(skb_arr_rq1[x]->data); +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + skb = skb_arr_rq1[wqe_index]; +if (unlikely (!skb)) { +EDEB_ERR (4 ,"LL SBK=NULL, wqe_index=%d" , + wqe_index); + skb =dev_alloc_skb (EHEA_LL_PKT_SIZE ); +if (!skb) +panic ("Alloc SKB failed" ); + } + skb_arr_rq1[wqe_index] =NULL ; +ehea_fill_skb_ll (dev, skb, cqe); + }else if (rq ==2 ) {/* RQ2 */ +void *pref; +int skb_index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); + x = (skb_index +1 ) % port_res->skb_arr_rq2_len; + pref = (void *)skb_arr_rq2[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (skb_index +1 ) % port_res->skb_arr_rq2_len; + pref = (void *)(skb_arr_rq2[x]->data); + +prefetch (pref); +prefetch (pref +EHEA_CACHE_LINE ); +prefetch (pref +EHEA_CACHE_LINE *2 ); +prefetch (pref +EHEA_CACHE_LINE *3 ); + skb = skb_arr_rq2[skb_index]; + +if (unlikely (!skb)) { +EDEB_ERR (4 ,"rq2: SKB=NULL, index=%d" , + skb_index); +break ; + } + skb_arr_rq2[skb_index] =NULL ; +ehea_fill_skb (dev, skb, cqe); + processed_RQ2++; + }else { +void *pref; +int skb_index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); + x = (skb_index +1 ) % port_res->skb_arr_rq3_len; + pref = (void *)skb_arr_rq3[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (skb_index +1 ) % port_res->skb_arr_rq3_len; + pref = (void *)(skb_arr_rq3[x]->data); +prefetch (pref); +prefetch (pref +EHEA_CACHE_LINE ); +prefetch (pref +EHEA_CACHE_LINE *2 ); +prefetch (pref +EHEA_CACHE_LINE *3 ); + + skb = skb_arr_rq3[skb_index]; +if (unlikely (!skb)) { +EDEB_ERR (4 ,"rq3: SKB=NULL, index=%d" , + skb_index); +break ; + } + skb_arr_rq3[skb_index] =NULL ; +ehea_fill_skb (dev, skb, cqe); + processed_RQ3++; + } + +EDEB (6 ,"About to pass SKB: dev=%p\n" +"skb=%p skb->data=%p skb->len=%d" +" skb->data_len=0x%x nr_frags=%d" , + dev, + skb, + skb->data, + skb->len, + skb->data_len,skb_shinfo (skb)->nr_frags); +if (cqe->status &EHEA_CQE_VLAN_TAG_XTRACT ) { +EDEB (7 ,"VLAN TAG extracted: %4x, vgrp=%p" , + cqe->vlan_tag, port->vgrp); +EDEB (7 ,"vlan_devices[vlan_tag]=%p" , + port->vgrp->vlan_devices[cqe->vlan_tag]); +vlan_hwaccel_receive_skb (skb, port->vgrp, + cqe->vlan_tag); + }else { +EDEB (7 ,"netif_receive_skb" ); +netif_receive_skb (skb); + } +EDEB (7 ,"SKB passed (netif_receive(skb) called)" ); + + }else { +struct sk_buff *skb; + +EDEB_ERR (4 ,"cqe->status indicating error: CQE:" ); +EDEB_DMP (4 , (u8 *)cqe,4 *16 ,"" ); +if (rq ==2 ) { + processed_RQ2++; + skb = skb_arr_rq2[ +EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)]; + skb_arr_rq2[EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)] =NULL ; +dev_kfree_skb (skb); + } +if (rq ==3 ) { + processed_RQ3++; + skb = skb_arr_rq3[ +EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)]; + skb_arr_rq3[EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)] =NULL ; +dev_kfree_skb (skb); + } + } + cqe =ehea_poll_rq1 (qp, &wqe_index); + } + + dev->quota -= processed; + *budget -= processed; + + port_res->p_state.ehea_poll +=1 ; + + port_res->rx_packets += processed; + +ehea_refill_rq1 (port_res, last_wqe_index, processed_RQ1); +ehea_refill_rq2 (port_res, processed_RQ2); +ehea_refill_rq3 (port_res, processed_RQ3); + + intreq = ((port_res->p_state.ehea_poll &0xF ) ==0xF ); + +EDEB_EX (7 ,"processed=%d, *budget=%d, dev->quota=%d" , + processed, *budget, dev->quota); + +if (!cqe || intreq) { +netif_rx_complete (dev); +ehea_reset_cq_ep (port_res->recv_cq); +ehea_reset_cq_n1 (port_res->recv_cq); + cqe =ipz_qeit_get_valid (&qp->ipz_rqueue1); +EDEB (7 ,"CQE=%p, break ehea_poll while loop" , cqe); +if (!cqe || intreq) +return 0 ; +if (!netif_rx_reschedule (dev, my_quota)) +return 0 ; + } +return 1 ; +} + +#define MAX_SENDCOMP_QUOTA 400 +void ehea_send_irq_tasklet (unsigned long data) +{ +int quota =MAX_SENDCOMP_QUOTA ; +int skb_index; +int cqe_counter =0 ; +int swqe_av =0 ; +unsigned long flags; +struct sk_buff *skb; +struct ehea_cqe *cqe; +struct ehea_port_res *port_res = (struct ehea_port_res *)data; +struct ehea_cq *send_cq = port_res->send_cq; +struct net_device *dev = port_res->port->netdev; + +EDEB_EN (7 ,"port_res=%p" , port_res); + +do { + cqe =ehea_poll_cq (send_cq); +if (!cqe) { +EDEB (7 ,"No further cqe found" ); +ehea_reset_cq_ep (send_cq); +ehea_reset_cq_n1 (send_cq); + cqe =ehea_poll_cq (send_cq); +if (!cqe) { +EDEB (7 ,"No cqe found after having" +" reset N1/EP\n" ); +break ; + } + } + cqe_counter++; +EDEB (7 ,"CQE found on Send-CQ:" ); +EDEB_DMP (7 , (u8 *)cqe,4 *16 ,"" ); +rmb (); +if (likely (EHEA_BMASK_GET (EHEA_WR_ID_TYPE , cqe->wr_id) + ==EHEA_SWQE2_TYPE )) {/* is swqe format 2 */ +int i; +int index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); +for (i =0 ; i <EHEA_BMASK_GET (EHEA_WR_ID_REFILL , + cqe->wr_id); i++) { + + skb_index = ((index - i + + port_res->skb_arr_sq_len) + % port_res->skb_arr_sq_len); + skb = port_res->skb_arr_sq[skb_index]; + port_res->skb_arr_sq[skb_index] =NULL ; + +if (unlikely (!skb)) { +EDEB_ERR (4 ,"s_irq_tasklet: SKB=NULL " +"WQ_ID=%lX, loop=%d, index=%d" , + cqe->wr_id, i, skb_index); +break ; + } +dev_kfree_skb (skb); + } + } + swqe_av +=EHEA_BMASK_GET (EHEA_WR_ID_REFILL , cqe->wr_id); + quota--; + }while (quota >0 ); + +ehea_update_feca (send_cq, cqe_counter); + +atomic_add (swqe_av, &port_res->swqe_avail); +EDEB (7 ,"port_res->swqe_avail=%d" , +atomic_read (&port_res->swqe_avail)); + +if (unlikely (netif_queue_stopped (dev))) { +spin_lock_irqsave (&port_res->netif_queue, flags); +if (unlikely ((atomic_read (&port_res->swqe_avail) + >=EHEA_SWQE_REFILL_TH ))) { +EDEB (7 ,"port %d swqes_avail >=10 (%d)," +"netif_wake_queue called" , + port_res->port->logical_port_id, +atomic_read (&port_res->swqe_avail)); +netif_wake_queue (port_res->port->netdev); + } +spin_unlock_irqrestore (&port_res->netif_queue, flags); + } + +if (unlikely (cqe)) +tasklet_hi_schedule (&port_res->send_comp_task); + +EDEB_EX (7 ,"" ); +} + +irqreturn_t ehea_send_irq_handler (int irq,void *param,struct pt_regs *regs) +{ +struct ehea_port_res *pr = (struct ehea_port_res *)param; +EDEB_EN (7 ,"irq=%d, param=%p, pt_regs=%p" , irq, param, regs); +tasklet_hi_schedule (&pr->send_comp_task); +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + +irqreturn_t ehea_recv_irq_handler (int irq,void *param,struct pt_regs * regs) +{ +struct ehea_port_res *pr = (struct ehea_port_res *)param; +struct ehea_port *port = pr->port; +EDEB_EN (7 ,"irq=%d, param=%p, pt_regs=%p" , irq, param, regs); +netif_rx_schedule (port->netdev); +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + +irqreturn_t ehea_qp_aff_irq_handler (int irq,void *param,struct pt_regs * regs) +{ +struct ehea_port *port = (struct ehea_port *)param; +struct ehea_eqe *eqe; +u32 qp_token; + +EDEB_EN (7 ,"irq=%d, param=%p, pt_regs=%p" , irq, param, regs); + eqe = (struct ehea_eqe *)ehea_poll_eq (port->qp_eq); +EDEB (7 ,"eqe=%p" , eqe); +while (eqe) { +EDEB (7 ,"*eqe=%lx" , *(u64 *)eqe); + eqe = (struct ehea_eqe *)ehea_poll_eq (port->qp_eq); + qp_token =EHEA_BMASK_GET (EHEA_EQE_QP_TOKEN , eqe->entry); +EDEB (7 ,"next eqe=%p" , eqe); + } + +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + +static struct ehea_port *ehea_get_port (struct ehea_adapter *adapter, +int logical_port) +{ +int i; + +for (i =0 ; i < adapter->num_ports; i++) +if (adapter->port[i]->logical_port_id == logical_port) +return adapter->port[i]; +return NULL ; +} + +static void ehea_parse_eqe (struct ehea_adapter *adapter,u64 eqe) +{ +int ret = -EINVAL ; +u8 ec =0 ; +u8 portnum =0 ; +struct ehea_port *port =NULL ; + +EDEB_EN (7 ,"eqe=%lx" , eqe); + + ec =EHEA_BMASK_GET (NEQE_EVENT_CODE , eqe); + +switch (ec) { +case EHEA_EC_PORTSTATE_CHG :/* port state change */ +EDEB (7 ,"Port state change" ); + portnum =EHEA_BMASK_GET (NEQE_PORTNUM , eqe); + port =ehea_get_port (adapter, portnum); + +if (!port) { +EDEB_ERR (4 ,"Unknown portnum %x" , portnum); +break ; + } + +if (EHEA_BMASK_GET (NEQE_PORT_UP , eqe)) { +if (!netif_carrier_ok (port->netdev)) { + ret =ehea_sense_port_attr (adapter, portnum); +if (ret) { +EDEB_ERR (4 ,"Failed resensing port" ); +break ; + } + +printk ("%s: Logical port up: %dMbps %s Duplex" , + port->netdev->name, + port->port_speed, + port->full_duplex == +1 ?"Full" :"Half" ); + +netif_carrier_on (port->netdev); +netif_wake_queue (port->netdev); + } + }else +if (netif_carrier_ok (port->netdev)) { +printk ("%s: Logical port down" , + port->netdev->name); +netif_carrier_off (port->netdev); +netif_stop_queue (port->netdev); + } + +if (EHEA_BMASK_GET (NEQE_EXTSWITCH_PORT_UP , eqe)) +printk ("%s: Physical port up" , port->netdev->name); +else +printk ("%s: Physical port down" , port->netdev->name); + +if (EHEA_BMASK_GET (NEQE_EXTSWITCH_PRIMARY , eqe)) +printk ("Externel switch port is primary port" ); +else +printk ("Externel switch port is backup port" ); + +break ; +case EHEA_EC_ADAPTER_MALFUNC :/* adapter malfunction */ +EDEB_ERR (4 ,"Adapter malfunction" ); +break ; +case EHEA_EC_PORT_MALFUNC :/* port malfunction */ +EDEB_ERR (4 ,"Port malfunction" ); +/* TODO Determine the port structure of the malfunctioning port +* netif_carrier_off(port->netdev); +* netif_stop_queue(port->netdev); +*/ +break ; +default : +EDEB_ERR (4 ,"Unknown event code %x" , ec); +break ; + } + +EDEB_EX (7 ,"" ); +} + +void ehea_neq_tasklet (unsigned long data) +{ +struct ehea_adapter *adapter = (struct ehea_adapter *)data; +struct ehea_eqe *eqe; +u64 event_mask; + +EDEB_EN (7 ,"" ); + eqe = (struct ehea_eqe *)ehea_poll_eq (adapter->neq); +EDEB (7 ,"eqe=%p" , eqe); + +while (eqe) { +EDEB (7 ,"*eqe=%lx" , eqe->entry); +ehea_parse_eqe (adapter, eqe->entry); + eqe = (struct ehea_eqe *)ehea_poll_eq (adapter->neq); +EDEB (7 ,"next eqe=%p" , eqe); + } + + event_mask =EHEA_BMASK_SET (NELR_PORTSTATE_CHG ,1 ) + |EHEA_BMASK_SET (NELR_ADAPTER_MALFUNC ,1 ) + |EHEA_BMASK_SET (NELR_PORT_MALFUNC ,1 ); + +ehea_h_reset_events (adapter->handle, + adapter->neq->ipz_eq_handle, event_mask); +EDEB_EX (7 ,"" ); +} + +irqreturn_t ehea_interrupt_neq (int irq,void *param,struct pt_regs *regs) +{ +struct ehea_adapter *adapter = (struct ehea_adapter *)param; +EDEB_EN (7 ,"dev_id=%p" , adapter); +tasklet_hi_schedule (&adapter->neq_tasklet); +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + + + +static void ehea_fill_port_res (struct ehea_port_res *pr) +{ +struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr; + +/* RQ 1 */ +ehea_init_fill_rq1 (pr, init_attr->act_nr_rwqes_rq1 + - init_attr->act_nr_rwqes_rq2 + - init_attr->act_nr_rwqes_rq3 -1 ); + +/* RQ 2 */ +ehea_refill_rq2 (pr, init_attr->act_nr_rwqes_rq2); + +/* RQ 3 */ +ehea_refill_rq3 (pr, init_attr->act_nr_rwqes_rq3); +} + +static int ehea_reg_interrupts (struct net_device *dev) +{ +int ret = -EINVAL ; +int i; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_port_res *pr = &port->port_res[0 ]; + +EDEB_EN (7 ,"" ); +for (i =0 ; i < port->num_def_qps; i++) { + pr = &port->port_res[i]; +snprintf (pr->int_recv_name,EHEA_IRQ_NAME_SIZE -1 + ,"%s-recv%d" , dev->name, i); + ret =ibmebus_request_irq (NULL , + pr->recv_eq->attr.ist1, + ehea_recv_irq_handler, +SA_INTERRUPT , pr->int_recv_name, pr); +if (ret) { +EDEB_ERR (4 ,"Failed registering irq for ehea_recv_int:" +"port_res_nr:%d, ist=%X" , i, + pr->recv_eq->attr.ist1); + goto failure; + } +EDEB (7 ,"irq_handle 0x%X for function ehea_recv_int %d " +" registered" , pr->recv_eq->attr.ist1, i); + } + +snprintf (port->int_aff_name,EHEA_IRQ_NAME_SIZE -1 , +"%s-aff" , dev->name); + ret =ibmebus_request_irq (NULL , + port->qp_eq->attr.ist1, + ehea_qp_aff_irq_handler, +SA_INTERRUPT , port->int_aff_name, port); +if (ret) { +EDEB_ERR (4 ,"Failed registering irq for qp_aff_irq_handler:" +" ist=%X" , port->qp_eq->attr.ist1); + goto failure; + } +EDEB (7 ,"irq_handle 0x%X for function qp_aff_irq_handler registered" , + port->qp_eq->attr.ist1); + +for (i =0 ; i < port->num_def_qps + port->num_tx_qps; i++) { + pr = &port->port_res[i]; +snprintf (pr->int_send_name,EHEA_IRQ_NAME_SIZE -1 , +"%s-send%d" , dev->name, i); + ret =ibmebus_request_irq (NULL , + pr->send_eq->attr.ist1, + ehea_send_irq_handler, +SA_INTERRUPT , pr->int_send_name, + pr); +if (ret) { +EDEB_ERR (4 ,"Registering irq for ehea_send failed" +" port_res_nr:%d, ist=%X" , i, + pr->send_eq->attr.ist1); + goto failure; + } +EDEB (7 ,"irq_handle 0x%X for function ehea_send_int %d" +" registered" , pr->send_eq->attr.ist1, i); + } +failure: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static void ehea_free_interrupts (struct net_device *dev) +{ +struct ehea_port *port = (struct ehea_port *)dev->priv; +int i; + +EDEB_EN (7 ,"" ); +/* send */ +for (i =0 ; i < port->num_def_qps + port->num_tx_qps; i++) { +ibmebus_free_irq (NULL , port->port_res[i].send_eq->attr.ist1, + &port->port_res[i]); +EDEB (7 ,"free send interrupt for res %d with handle 0x%X" , + i, port->port_res[i].send_eq->attr.ist1); + } + +/* receive */ +for (i =0 ; i < port->num_def_qps; i++) { +ibmebus_free_irq (NULL , port->port_res[i].recv_eq->attr.ist1, + &port->port_res[i]); +EDEB (7 ,"free recv intterupt for res %d with handle 0x%X" , + i, port->port_res[i].recv_eq->attr.ist1); + } +/* associated events */ +ibmebus_free_irq (NULL , port->qp_eq->attr.ist1, port); +EDEB (7 ,"associated event interrupt for handle 0x%X freed" , + port->qp_eq->attr.ist1); +EDEB_EX (7 ,"" ); +} + +static int ehea_configure_port (struct ehea_port *port) +{ +int ret = -EINVAL ; +u64 hret =H_HARDWARE ; +struct hcp_query_ehea_port_cb_0 *ehea_port_cb_0 =NULL ; +u64 mask =0 ; +int i; + +EDEB_EN (7 ,"" ); + + ehea_port_cb_0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!ehea_port_cb_0) { +EDEB_ERR (4 ,"No memory for ehea_port control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + + ehea_port_cb_0->port_rc =EHEA_BMASK_SET (PXLY_RC_VALID ,1 ) + |EHEA_BMASK_SET (PXLY_RC_IP_CHKSUM ,1 ) + |EHEA_BMASK_SET (PXLY_RC_TCP_UDP_CHKSUM ,1 ) + |EHEA_BMASK_SET (PXLY_RC_VLAN_XTRACT ,1 ) + |EHEA_BMASK_SET (PXLY_RC_VLAN_TAG_FILTER , +PXLY_RC_VLAN_FILTER ) + |EHEA_BMASK_SET (PXLY_RC_JUMBO_FRAME ,1 ); + +for (i =0 ; i < port->num_def_qps; i++) { + ehea_port_cb_0->default_qpn_array[i] = + port->port_res[i].qp->init_attr.qp_nr; + +EDEB (7 ,"default_qpn_array[%d]=%d" , + i, port->port_res[i].qp->init_attr.qp_nr); + } + +EDEB (7 ,"ehea_port_cb_0" ); +EDEB_DMP (7 , (u8 *)ehea_port_cb_0,sizeof (*ehea_port_cb_0),"" ); + + mask =EHEA_BMASK_SET (H_PORT_CB0_PRC ,1 ) + |EHEA_BMASK_SET (H_PORT_CB0_DEFQPNARRAY ,1 ); + + hret =ehea_h_modify_ehea_port (port->adapter->handle, + port->logical_port_id, +H_PORT_CB0 , + mask, + (void *)ehea_port_cb_0); + +if (hret !=H_SUCCESS ) { + goto modify_ehea_port_failed; + } + + ret =0 ; + +modify_ehea_port_failed: +kfree (ehea_port_cb_0); + +kzalloc_failed: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + + +static int ehea_gen_smrs (struct ehea_port_res *pr) +{ +u64 hret =H_HARDWARE ; +struct ehea_adapter *adapter = pr->port->adapter; +EDEB_EN (7 ,"ehea_port_res=%p" , pr); + hret =hipz_h_register_smr (adapter->handle, + adapter->mr.handle, + adapter->mr.vaddr, +EHEA_MR_ACC_CTRL , + adapter->pd, + &pr->send_mr); +if (hret !=H_SUCCESS ) + goto ehea_gen_smrs_err1; + + hret =hipz_h_register_smr (adapter->handle, + adapter->mr.handle, + adapter->mr.vaddr, +EHEA_MR_ACC_CTRL , + adapter->pd, + &pr->recv_mr); +if (hret !=H_SUCCESS ) + goto ehea_gen_smrs_err2; +EDEB_EX (7 ,"" ); +return 0 ; + +ehea_gen_smrs_err2: + hret =ehea_h_free_resource_mr (adapter->handle, pr->send_mr.handle); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Could not free SMR" ); +ehea_gen_smrs_err1: +return -EINVAL ; +} + +static void ehea_rem_smrs (struct ehea_port_res *pr) +{ +u64 hret =H_HARDWARE ; +struct ehea_adapter *adapter = pr->port->adapter; +EDEB_EN (7 ,"ehea_port_res=%p" , pr); + hret =ehea_h_free_resource_mr (adapter->handle, pr->send_mr.handle); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Could not free send SMR for pr=%p" , pr); + + hret =ehea_h_free_resource_mr (adapter->handle, pr->recv_mr.handle); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Could not free receive SMR for pr=%p" , pr); +EDEB_EX (7 ,"" ); +} + +static int ehea_init_port_res (struct ehea_port *port,struct ehea_port_res *pr, +struct port_res_cfg *pr_cfg,int queue_token) +{ +int ret = -EINVAL ; +int max_rq_entries =0 ; +enum ehea_eq_type eq_type =EHEA_EQ ; +struct ehea_qp_init_attr *init_attr; +struct ehea_adapter *adapter = port->adapter; + +EDEB_EN (7 ,"port=%p, pr=%p" , port, pr); + +memset (pr,0 ,sizeof (struct ehea_port_res )); + + pr->port = port; +spin_lock_init (&pr->send_lock); +spin_lock_init (&pr->recv_lock); +spin_lock_init (&pr->xmit_lock); +spin_lock_init (&pr->netif_queue); + + pr->recv_eq =ehea_create_eq (adapter, eq_type, +EHEA_MAX_ENTRIES_EQ ,0 ); +if (!pr->recv_eq) { +EDEB_ERR (4 ,"ehea_create_eq failed (recv_eq)" ); + goto ehea_init_port_res_err1; + } + pr->send_eq =ehea_create_eq (adapter, eq_type, +EHEA_MAX_ENTRIES_EQ ,0 ); +if (!pr->send_eq) { +EDEB_ERR (4 ,"ehea_create_eq failed (send_eq)" ); + goto ehea_init_port_res_err2; + } + + pr->recv_cq =ehea_create_cq (adapter, pr_cfg->max_entries_rcq, + pr->recv_eq->ipz_eq_handle, + port->logical_port_id); +if (!pr->recv_cq) { +EDEB_ERR (4 ,"ehea_create_cq failed (cq_recv)" ); + goto ehea_init_port_res_err3; + } + + pr->send_cq =ehea_create_cq (adapter, pr_cfg->max_entries_scq, + pr->send_eq->ipz_eq_handle, + port->logical_port_id); +if (!pr->send_cq) { +EDEB_ERR (4 ,"ehea_create_cq failed (cq_send)" ); + goto ehea_init_port_res_err4; + } + + init_attr = (struct ehea_qp_init_attr *) +kzalloc (sizeof (struct ehea_qp_init_attr ),GFP_KERNEL ); + +if (!init_attr) { +EDEB_ERR (4 ,"no mem for init_attr struct" ); + ret = -ENOMEM ; + goto ehea_init_port_res_err5; + } + + init_attr->low_lat_rq1 =1 ; + init_attr->signalingtype =1 ;/* generate CQE if specified in WQE */ + init_attr->rq_count =3 ; + init_attr->qp_token = queue_token; + + init_attr->max_nr_send_wqes = pr_cfg->max_entries_sq; + init_attr->max_nr_rwqes_rq1 = pr_cfg->max_entries_rq1; + init_attr->max_nr_rwqes_rq2 = pr_cfg->max_entries_rq2; + init_attr->max_nr_rwqes_rq3 = pr_cfg->max_entries_rq3; + + init_attr->wqe_size_enc_sq =EHEA_SG_SQ ; + init_attr->wqe_size_enc_rq1 =EHEA_SG_RQ1 ; + init_attr->wqe_size_enc_rq2 =EHEA_SG_RQ2 ; + init_attr->wqe_size_enc_rq3 =EHEA_SG_RQ3 ; + + init_attr->rq2_threshold =EHEA_RQ2_THRESHOLD ; + init_attr->rq3_threshold =EHEA_RQ3_THRESHOLD ; + init_attr->port_nr = port->logical_port_id; + init_attr->send_cq_handle = pr->send_cq->ipz_cq_handle; + init_attr->recv_cq_handle = pr->recv_cq->ipz_cq_handle; + init_attr->aff_eq_handle = port->qp_eq->ipz_eq_handle; + + pr->qp =ehea_create_qp (adapter, adapter->pd, init_attr); +if (!pr->qp) { +EDEB_ERR (4 ,"could not create queue pair" ); + goto ehea_init_port_res_err6; + } + +/* SQ */ + max_rq_entries = init_attr->act_nr_send_wqes; + pr->skb_arr_sq = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_sq) { +EDEB_ERR (4 ,"vmalloc for skb_arr_sq failed" ); + goto ehea_init_port_res_err7; + } +memset (pr->skb_arr_sq,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_sq_index =0 ; + pr->skb_arr_sq_len = max_rq_entries +1 ; + +/* RQ 1 */ + max_rq_entries = init_attr->act_nr_rwqes_rq1; + pr->skb_arr_rq1 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_rq1) { +EDEB_ERR (4 ,"vmalloc for skb_arr_rq1 failed" ); + goto ehea_init_port_res_err8; + } +memset (pr->skb_arr_rq1,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_arr_rq1_len = max_rq_entries +1 ; + +/* RQ 2 */ + max_rq_entries = init_attr->act_nr_rwqes_rq2; + pr->skb_arr_rq2 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_rq2) { +EDEB_ERR (4 ,"vmalloc for skb_arr_rq2 failed" ); + goto ehea_init_port_res_err9; + } +memset (pr->skb_arr_rq2,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_arr_rq2_len = max_rq_entries; + pr->skb_rq2_index =0 ; + +/* RQ 3 */ + max_rq_entries = init_attr->act_nr_rwqes_rq3; + pr->skb_arr_rq3 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_rq3) { +EDEB_ERR (4 ,"vmalloc for skb_arr_rq3 failed" ); + goto ehea_init_port_res_err10; + } +memset (pr->skb_arr_rq3,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_arr_rq3_len = max_rq_entries; + pr->skb_rq3_index =0 ; + +if (ehea_gen_smrs (pr) !=0 ) + goto ehea_init_port_res_err11; +tasklet_init (&pr->send_comp_task, ehea_send_irq_tasklet, + (unsigned long )pr); +atomic_set (&pr->swqe_avail,EHEA_MAX_ENTRIES_SQ -1 ); + +kfree (init_attr); + ret =0 ; + goto done; + +ehea_init_port_res_err11: +vfree (pr->skb_arr_rq3); +ehea_init_port_res_err10: +vfree (pr->skb_arr_rq2); +ehea_init_port_res_err9: +vfree (pr->skb_arr_rq1); +ehea_init_port_res_err8: +vfree (pr->skb_arr_sq); +ehea_init_port_res_err7: +ehea_destroy_qp (pr->qp); +ehea_init_port_res_err6: +kfree (init_attr); +ehea_init_port_res_err5: +ehea_destroy_cq (pr->send_cq); +ehea_init_port_res_err4: +ehea_destroy_cq (pr->recv_cq); +ehea_init_port_res_err3: +ehea_destroy_eq (pr->send_eq); +ehea_init_port_res_err2: +ehea_destroy_eq (pr->recv_eq); +ehea_init_port_res_err1: +done: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static int ehea_clean_port_res (struct ehea_port *port,struct ehea_port_res *pr) +{ +int i; +int ret = -EINVAL ; + +EDEB_EN (7 ,"Not completed yet..." ); + + ret =ehea_destroy_qp (pr->qp); +if (ret) +EDEB_ERR (4 ,"could not destroy queue pair" ); + + ret =ehea_destroy_cq (pr->send_cq); +if (ret) +EDEB_ERR (4 ,"could not destroy send_cq" ); + + ret =ehea_destroy_cq (pr->recv_cq); +if (ret) +EDEB_ERR (4 ,"could not destroy recv_cq" ); + + ret =ehea_destroy_eq (pr->send_eq); +if (ret) +EDEB_ERR (4 ,"could not destroy send_eq" ); + + ret =ehea_destroy_eq (pr->recv_eq); +if (ret) +EDEB_ERR (4 ,"could not destroy recv_eq" ); + +for (i =0 ; i < pr->skb_arr_rq1_len; i++) { +if (pr->skb_arr_rq1[i]) +dev_kfree_skb (pr->skb_arr_rq1[i]); + } + +for (i =0 ; i < pr->skb_arr_rq2_len; i++) +if (pr->skb_arr_rq2[i]) +dev_kfree_skb (pr->skb_arr_rq2[i]); + +for (i =0 ; i < pr->skb_arr_rq3_len; i++) +if (pr->skb_arr_rq3[i]) +dev_kfree_skb (pr->skb_arr_rq3[i]); + +for (i =0 ; i < pr->skb_arr_sq_len; i++) +if (pr->skb_arr_sq[i]) +dev_kfree_skb (pr->skb_arr_sq[i]); + +vfree (pr->skb_arr_sq); +vfree (pr->skb_arr_rq1); +vfree (pr->skb_arr_rq2); +vfree (pr->skb_arr_rq3); + +ehea_rem_smrs (pr); +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static inline void write_ip_start_end (struct ehea_swqe *swqe, +const struct sk_buff *skb) +{ + + swqe->ip_start = (u8)(((u64 )skb->nh.iph) - ((u64 )skb->data)); + swqe->ip_end = (u8)(swqe->ip_start + skb->nh.iph->ihl *4 -1 ); +} + +static inline void write_tcp_offset_end (struct ehea_swqe *swqe, +const struct sk_buff *skb) +{ + swqe->tcp_offset = (u8)(swqe->ip_end +1 + offsetof(struct tcphdr , + check)); + swqe->tcp_end = (u16 )skb->len -1 ; +} + +static inline void write_udp_offset_end (struct ehea_swqe *swqe, +const struct sk_buff *skb) +{ + swqe->tcp_offset = (u8)(swqe->ip_end +1 + offsetof(struct udphdr , + check)); + swqe->tcp_end = (u16 )skb->len -1 ; +} + +static inline void write_swqe2_data (struct sk_buff *skb, +struct net_device *dev, +struct ehea_swqe *swqe, +u32 lkey) +{ +int skb_data_size, nfrags, headersize, i, sg1entry_contains_frag_data; +struct ehea_vsgentry *sg_list; +struct ehea_vsgentry *sg1entry; +struct ehea_vsgentry *sgentry; +u8 *imm_data; +u64 tmp_addr; +skb_frag_t *frag; +EDEB_EN (7 ,"" ); + + skb_data_size = skb->len - skb->data_len; + nfrags =skb_shinfo (skb)->nr_frags; + sg1entry = &swqe->u.immdata_desc.sg_entry; + sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list; + imm_data = &swqe->u.immdata_desc.immediate_data[0 ]; + swqe->descriptors =0 ; + sg1entry_contains_frag_data =0 ; + +if ((dev->features &NETIF_F_TSO ) &&skb_shinfo (skb)->gso_size) { +/* Packet is TCP with TSO enabled */ + swqe->tx_control |=EHEA_SWQE_TSO ; + swqe->mss =skb_shinfo (skb)->gso_size; +/* copy only eth/ip/tcp headers to immediate data and +* the rest of skb->data to sg1entry +*/ + headersize =ETH_HLEN + (skb->nh.iph->ihl *4 ) + + skb->h.th->doff *4 ; + skb_data_size = skb->len - skb->data_len; + +if (skb_data_size >= headersize) { +/* copy immediate data */ +memcpy (imm_data, skb->data, headersize); + swqe->immediate_data_length = headersize; + +if (skb_data_size > headersize) { +/* set sg1entry data */ + sg1entry->l_key = lkey; + sg1entry->len = skb_data_size - headersize; + + tmp_addr = (u64)(skb->data + headersize); + sg1entry->vaddr = +get_swqe_addr (tmp_addr,0 ); + + swqe->descriptors++; + } + }else +EDEB_ERR (4 ,"Cannot handle fragmented headers" ); + }else { +/* Packet is any nonTSO type +* +* Copy as much as possible skb->data to immediate data and +* the rest to sg1entry +*/ +if (skb_data_size >=SWQE2_MAX_IMM ) { +/* copy immediate data */ +memcpy (imm_data, skb->data,SWQE2_MAX_IMM ); + + swqe->immediate_data_length =SWQE2_MAX_IMM ; + +if (skb_data_size >SWQE2_MAX_IMM ) { +/* copy sg1entry data */ + sg1entry->l_key = lkey; + sg1entry->len = skb_data_size -SWQE2_MAX_IMM ; + tmp_addr = (u64)(skb->data +SWQE2_MAX_IMM ); + sg1entry->vaddr =get_swqe_addr (tmp_addr,0 ); + swqe->descriptors++; + } + }else { +memcpy (imm_data, skb->data, skb_data_size); + swqe->immediate_data_length = skb_data_size; + } + } + +/* write descriptors */ +if (nfrags >0 ) { +if (swqe->descriptors ==0 ) { +/* sg1entry not yet used */ + frag = &skb_shinfo (skb)->frags[0 ]; + +/* copy sg1entry data */ + sg1entry->l_key = lkey; + sg1entry->len = frag->size; + tmp_addr = (u64)(page_address (frag->page) + + frag->page_offset); + sg1entry->vaddr =get_swqe_addr (tmp_addr, +EHEA_MR_TX_DATA_PN ); + swqe->descriptors++; + sg1entry_contains_frag_data =1 ; + } + +for (i = sg1entry_contains_frag_data; i < nfrags; i++) { + + frag = &skb_shinfo (skb)->frags[i]; + sgentry = &sg_list[i - sg1entry_contains_frag_data]; + + sgentry->l_key = lkey; + sgentry->len = frag->size; + + tmp_addr = (u64)(page_address (frag->page) + + frag->page_offset); + sgentry->vaddr =get_swqe_addr (tmp_addr, +EHEA_MR_TX_DATA_PN + i); + } + } + +EDEB_EX (7 ,"" ); +} + +static int ehea_ioctl (struct net_device *dev,struct ifreq *ifr,int cmd) +{ +EDEB_ERR (4 ,"ioctl not supported: dev=%s cmd=%d" , dev->name, cmd); +return -EOPNOTSUPP ; +} + +static u64 ehea_broadcast_reg_helper (struct ehea_port *port,u32 hcallid) +{ +u64 hret =H_HARDWARE ; +u8 reg_type =0 ; + +if (hcallid ==H_REG_BCMC ) { +EDEB (7 ,"REGistering MAC for broadcast" ); + }else { +EDEB (7 ,"DEREGistering MAC for broadcast" ); + } + +/* De/Register untagged packets */ + reg_type =EHEA_BCMC_BROADCAST |EHEA_BCMC_UNTAGGED ; + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, port->mac_addr,0 , hcallid); +if (hret !=H_SUCCESS ) + goto hcall_failed; + +/* De/Register VLAN packets */ + reg_type =EHEA_BCMC_BROADCAST |EHEA_BCMC_VLANID_ALL ; + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, port->mac_addr,0 , hcallid); +hcall_failed: +return hret; +} + +static int ehea_set_mac_addr (struct net_device *dev,void *sa) +{ +int ret = -EOPNOTSUPP ; +u64 hret =H_HARDWARE ; +struct hcp_query_ehea_port_cb_0 *ehea_port_cb_0 =NULL ; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct sockaddr *mac_addr = (struct sockaddr *)sa; + +EDEB_EN (7 ,"devname=%s" , dev->name); +EDEB_DMP (7 , (u8 *)&(mac_addr->sa_data[0 ]),14 ,"" ); + +if (!is_valid_ether_addr (mac_addr->sa_data)) { + ret = -EADDRNOTAVAIL ; + goto invalid_mac; + } + + ehea_port_cb_0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!ehea_port_cb_0) { +EDEB_ERR (4 ,"No memory for ehea_port control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + +memcpy ((u8 *)(&(ehea_port_cb_0->port_mac_addr)), + (u8 *)&(mac_addr->sa_data[0 ]),6 ); + + ehea_port_cb_0->port_mac_addr = ehea_port_cb_0->port_mac_addr >>16 ; + +EDEB (7 ,"ehea_port_cb_0" ); +EDEB_DMP (7 , (u8 *)ehea_port_cb_0, +sizeof (struct hcp_query_ehea_port_cb_0 ),"" ); + + hret =ehea_h_modify_ehea_port (port->adapter->handle, + port->logical_port_id, +H_PORT_CB0 , +EHEA_BMASK_SET (H_PORT_CB0_MAC ,1 ), + (void *)ehea_port_cb_0); +if (hret !=H_SUCCESS ) { + ret = -EOPNOTSUPP ; + goto hcall_failed; + } + +memcpy (dev->dev_addr, mac_addr->sa_data, dev->addr_len); + +/* Deregister old MAC in PHYP */ + hret =ehea_broadcast_reg_helper (port,H_DEREG_BCMC ); +if (hret) { + ret = -EOPNOTSUPP ; + goto hcall_failed; + } + + port->mac_addr = ehea_port_cb_0->port_mac_addr <<16 ; + +/* Register new MAC in PHYP */ + hret =ehea_broadcast_reg_helper (port,H_REG_BCMC ); +if (hret) { + ret = -EOPNOTSUPP ; + goto hcall_failed; + } + + ret =0 ; + +hcall_failed: +kfree (ehea_port_cb_0); + +kzalloc_failed: +invalid_mac: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static void ehea_promiscuous (struct net_device *dev,int enable) +{ +struct ehea_port *port = dev->priv; + +if (!port->promisc) { +if (enable) { +/* Enable promiscuous mode */ +EDEB (7 ,"Enabling IFF_PROMISC" ); +EDEB_ERR (4 ,"Enable promiscuous mode: " +"not yet implemented" ); + port->promisc =EHEA_ENABLE ; + } + }else { +if (!enable) { +/* Disable promiscuous mode */ +EDEB (7 ,"Disabling IFF_PROMISC" ); +EDEB_ERR (4 ,"Disable promiscuous mode: " +"not yet implemented" ); + port->promisc =EHEA_DISABLE ; + } + } +} + +static u64 ehea_multicast_reg_helper (struct ehea_port *port, +u64 mc_mac_addr, +u32 hcallid) +{ +u64 hret =H_HARDWARE ; +u8 reg_type =0 ; + + reg_type =EHEA_BCMC_SCOPE_ALL |EHEA_BCMC_MULTICAST + |EHEA_BCMC_UNTAGGED ; + + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, mc_mac_addr,0 , hcallid); +if (hret) + goto hcall_failed; + + reg_type =EHEA_BCMC_SCOPE_ALL |EHEA_BCMC_MULTICAST + |EHEA_BCMC_VLANID_ALL ; + + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, mc_mac_addr,0 , hcallid); +hcall_failed: +return hret; +} + +static int ehea_drop_multicast_list (struct net_device *dev) +{ +int ret =0 ; +u64 hret =H_HARDWARE ; +struct ehea_port *port = dev->priv; +struct ehea_mc_list *mc_entry = port->mc_list; +struct list_head *pos; +struct list_head *temp; + +EDEB_EN (7 ,"devname=%s" , dev->name); + +if (!list_empty (&mc_entry->list)) { +list_for_each_safe (pos, temp, &(port->mc_list->list)) { + mc_entry = list_entry(pos, struct ehea_mc_list, list); + +EDEB (7 ,"Deregistering MAC %lx" , mc_entry->macaddr); + + hret =ehea_multicast_reg_helper (port, + mc_entry->macaddr, +H_DEREG_BCMC ); +if (hret) { +EDEB_ERR (4 ,"Failed deregistering mcast MAC" ); + ret = -EINVAL ; + } + +list_del (pos); +kfree (mc_entry); + } + } + +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static void ehea_allmulti (struct net_device *dev,int enable) +{ +u64 hret =H_HARDWARE ; +struct ehea_port *port = dev->priv; + +if (!port->allmulti) { +if (enable) { +/* Enable ALLMULTI */ +EDEB (7 ,"Enabling IFF_ALLMULTI" ); +ehea_drop_multicast_list (dev); + hret =ehea_multicast_reg_helper (port,0 ,H_REG_BCMC ); +if (!hret) + port->allmulti =EHEA_ENABLE ; +else +EDEB_ERR (4 ,"Enabling IFF_ALLMULTI failed!" ); + } + }else +if (!enable) { +/* Disable ALLMULTI */ +EDEB (7 ,"Disabling IFF_ALLMULTI" ); + hret =ehea_multicast_reg_helper (port,0 ,H_DEREG_BCMC ); +if (!hret) + port->allmulti =EHEA_DISABLE ; +else +EDEB_ERR (4 ,"Disabling IFF_ALLMULTI failed!" ); + } +} + +static void ehea_add_multicast_entry (struct ehea_port * port,u8 * mc_mac_addr) +{ +u64 hret =H_HARDWARE ; +struct ehea_mc_list *ehea_mcl_entry; + +EDEB_EN (7 ,"port=%p" , port); +EDEB_DMP (7 , mc_mac_addr,MAX_ADDR_LEN ,"dmi_addr" ); + + ehea_mcl_entry = + (struct ehea_mc_list *)kzalloc (sizeof (struct ehea_mc_list ), +GFP_KERNEL ); +if (!ehea_mcl_entry) { +EDEB_ERR (4 ,"Out of memory" ); +return ; + } + +INIT_LIST_HEAD (&ehea_mcl_entry->list); + +memcpy ((u8 *)&ehea_mcl_entry->macaddr, mc_mac_addr,ETH_ALEN ); + + hret =ehea_multicast_reg_helper (port, ehea_mcl_entry->macaddr, +H_REG_BCMC ); +if (!hret) +list_add (&ehea_mcl_entry->list, &port->mc_list->list); +else { +EDEB_ERR (4 ,"Failed registering mcast MAC" ); +kfree (ehea_mcl_entry); + } + +EDEB_EX (7 ,"" ); +} + +static void ehea_set_multicast_list (struct net_device *dev) +{ +int ret; +int i; +struct ehea_port *port = dev->priv; +struct dev_mc_list *k_mcl_entry; + +EDEB_EN (7 ,"devname=%s, mc_count=%d" , dev->name, dev->mc_count); + +if (dev->flags &IFF_PROMISC ) { +ehea_promiscuous (dev,EHEA_ENABLE ); +return ; + } +ehea_promiscuous (dev,EHEA_DISABLE ); + +if (dev->flags &IFF_ALLMULTI ) { +ehea_allmulti (dev,EHEA_ENABLE ); +return ; + } +ehea_allmulti (dev,EHEA_DISABLE ); + +EDEB (7 ,"Set individual multicast list" ); +if (dev->mc_count) { + ret =ehea_drop_multicast_list (dev); +if (ret) { +/* Dropping the current multicast list failed. +* Enabling ALL_MULTI is the best we can do. +*/ +ehea_allmulti (dev,EHEA_ENABLE ); + } + +if (dev->mc_count > port->adapter->max_mc_mac) { +EDEB_ERR (4 ,"Mcast registration limit reached " +"(0x%lx). Use ALLMULTI!" , + port->adapter->max_mc_mac); + goto escape; + } + +for (i =0 , k_mcl_entry = dev->mc_list; + i < dev->mc_count; + i++, k_mcl_entry = k_mcl_entry->next) { +ehea_add_multicast_entry (port, + k_mcl_entry->dmi_addr); + } + } + +escape: +EDEB_EX (7 ,"" ); +return ; +} + +static int ehea_change_mtu (struct net_device *dev,int new_mtu) +{ +if ((new_mtu <68 ) || (new_mtu >EHEA_MAX_PACKET_SIZE )) +return -EINVAL ; + dev->mtu = new_mtu; +return 0 ; +} + +static inline void ehea_xmit2 (struct sk_buff *skb, +struct net_device *dev,struct ehea_swqe *swqe, +u32 lkey) +{ +int nfrags; +unsigned short skb_protocol = skb->protocol; + nfrags =skb_shinfo (skb)->nr_frags; +EDEB_EN (7 ,"skb->nfrags=%d (0x%X)" , nfrags, nfrags); + +if (skb_protocol ==ETH_P_IP ) { +/* IPv4 */ + swqe->tx_control |=EHEA_SWQE_CRC + |EHEA_SWQE_IP_CHECKSUM + |EHEA_SWQE_TCP_CHECKSUM + |EHEA_SWQE_IMM_DATA_PRESENT + |EHEA_SWQE_DESCRIPTORS_PRESENT ; + +write_ip_start_end (swqe, skb); + +if (skb->nh.iph->protocol ==IPPROTO_UDP ) { +if ((skb->nh.iph->frag_off &IP_MF ) + || (skb->nh.iph->frag_off &IP_OFFSET )) +/* IP fragment, so don't change cs */ + swqe->tx_control &= ~EHEA_SWQE_TCP_CHECKSUM ; +else +write_udp_offset_end (swqe, skb); + + }else if (skb->nh.iph->protocol ==IPPROTO_TCP ) { +write_tcp_offset_end (swqe, skb); + } + +/* icmp (big data) and ip segmentation packets (all other ip +packets) do not require any special handling */ + + }else { +/* Other Ethernet Protocol */ + swqe->tx_control |=EHEA_SWQE_CRC + |EHEA_SWQE_IMM_DATA_PRESENT + |EHEA_SWQE_DESCRIPTORS_PRESENT ; + } + +write_swqe2_data (skb, dev, swqe, lkey); + +EDEB_EX (7 ,"" ); +} + +static inline void ehea_xmit3 (struct sk_buff *skb, +struct net_device *dev,struct ehea_swqe *swqe) +{ +int i; +skb_frag_t *frag; +int nfrags =skb_shinfo (skb)->nr_frags; +u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0 ]; +u64 skb_protocol = skb->protocol; + +EDEB_EN (7 ,"" ); +if (likely (skb_protocol ==ETH_P_IP )) { +/* IPv4 */ +write_ip_start_end (swqe, skb); + +if (skb->nh.iph->protocol ==IPPROTO_TCP ) { + swqe->tx_control |=EHEA_SWQE_CRC + |EHEA_SWQE_IP_CHECKSUM + |EHEA_SWQE_TCP_CHECKSUM + |EHEA_SWQE_IMM_DATA_PRESENT ; + +write_tcp_offset_end (swqe, skb); + + }else if (skb->nh.iph->protocol ==IPPROTO_UDP ) { +if ((skb->nh.iph->frag_off &IP_MF ) + || (skb->nh.iph->frag_off &IP_OFFSET )) +/* IP fragment, so don't change cs */ + swqe->tx_control |=EHEA_SWQE_CRC + |EHEA_SWQE_IMM_DATA_PRESENT ; +else { + swqe->tx_control |=EHEA_SWQE_CRC + |EHEA_SWQE_IP_CHECKSUM + |EHEA_SWQE_TCP_CHECKSUM + |EHEA_SWQE_IMM_DATA_PRESENT ; +write_udp_offset_end (swqe, skb); + } + }else { +/* icmp (big data) and +ip segmentation packets (all other ip packets) */ + swqe->tx_control |=EHEA_SWQE_CRC + |EHEA_SWQE_IP_CHECKSUM + |EHEA_SWQE_IMM_DATA_PRESENT ; + } + }else { +/* Other Ethernet Protocol */ + swqe->tx_control |=EHEA_SWQE_CRC |EHEA_SWQE_IMM_DATA_PRESENT ; + } +/* copy (immediate) data */ +if (nfrags ==0 ) { +/* data is in a single piece */ +memcpy (imm_data, skb->data, skb->len); + }else { +/* first copy data from the skb->data buffer ... */ +memcpy (imm_data, skb->data, skb->len - skb->data_len); + imm_data += skb->len - skb->data_len; + +/* ... then copy data from the fragments */ +for (i =0 ; i < nfrags; i++) { + frag = &skb_shinfo (skb)->frags[i]; +memcpy (imm_data, +page_address (frag->page) + frag->page_offset, + frag->size); + imm_data += frag->size; + } + } + swqe->immediate_data_length = skb->len; +dev_kfree_skb (skb); + +EDEB_EX (7 ,"" ); +} + +static int ehea_start_xmit (struct sk_buff *skb,struct net_device *dev) +{ +unsigned long flags; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_port_res *pr; +struct ehea_swqe *swqe; +u32 lkey; +int swqe_index; +EDEB_EN (7 ,"" ); + + pr = &port->port_res[0 ]; + +EDEB (6 ,"MACaddr=0x%X, dev=%p\n" +"PAGE_SIZE=%d MAX_SKB_FRAGS=%d" +"skb=%p skb->data=%p skb->len=%d skb->data_len=0x%x nr_frags=%d" , + *(u32 *)port->netdev->dev_addr, dev, + (int )PAGE_SIZE , + (int )MAX_SKB_FRAGS , + skb, + skb->data, skb->len, skb->data_len,skb_shinfo (skb)->nr_frags); + + +if (unlikely (atomic_read (&pr->swqe_avail) <=1 )) { +spin_lock_irqsave (&pr->netif_queue, flags); +if (unlikely (atomic_read (&pr->swqe_avail) <=1 )) { +EDEB (7 ,"netif_stop_queue to be called" ); +netif_stop_queue (dev); +spin_unlock_irqrestore (&pr->netif_queue, flags); +return NETDEV_TX_BUSY ; + } +spin_unlock_irqrestore (&pr->netif_queue, flags); + } +atomic_dec (&pr->swqe_avail); + + +EDEB_DMP (7 , (u8 *)skb->data, (skb->len - skb->data_len),"SKB_DATA" ); + +spin_lock (&pr->xmit_lock); + + swqe =ehea_get_swqe (pr->qp, &swqe_index); +EDEB (7 ,"Posting SWQE on QP wit qp_nr=%X\n" , + pr->qp->init_attr.qp_nr); + +memset (swqe,0 ,32 ); + +if (skb->len <=SWQE3_MAX_IMM ) { +u32 swqe_num = pr->swqe_id_counter; +ehea_xmit3 (skb, dev, swqe); + swqe->wr_id =EHEA_BMASK_SET (EHEA_WR_ID_REFILL ,EHEA_SIG_IV ) + |EHEA_BMASK_SET (EHEA_WR_ID_TYPE ,EHEA_SWQE3_TYPE ) + |EHEA_BMASK_SET (EHEA_WR_ID_COUNT , swqe_num); +if (pr->swqe_ll_count >= (EHEA_SIG_IV -1 )) { + swqe->tx_control |=EHEA_SWQE_SIGNALLED_COMPLETION ; + pr->swqe_ll_count =0 ; + }else + pr->swqe_ll_count +=1 ; +/* only for debugging purpose */ +EDEB_DMP (6 , (u8 *)swqe,128 ,"swqe format 3" ); + + }else { + swqe->wr_id = +EHEA_BMASK_SET (EHEA_WR_ID_REFILL ,EHEA_SIG_IV_LONG ) + |EHEA_BMASK_SET (EHEA_WR_ID_TYPE ,EHEA_SWQE2_TYPE ) + |EHEA_BMASK_SET (EHEA_WR_ID_COUNT , pr->swqe_id_counter) + |EHEA_BMASK_SET (EHEA_WR_ID_INDEX , pr->skb_sq_index); + pr->skb_arr_sq[pr->skb_sq_index] = skb; + pr->skb_sq_index = (pr->skb_sq_index +1 ) % pr->skb_arr_sq_len; + + lkey =ehea_get_send_lkey (pr); +ehea_xmit2 (skb, dev, swqe, lkey); + +if (pr->swqe_count >= (EHEA_SIG_IV_LONG -1 )) { + swqe->tx_control |=EHEA_SWQE_SIGNALLED_COMPLETION ; + pr->swqe_count =0 ; + }else + pr->swqe_count +=1 ; +/* only for debugging purpose */ +EDEB_DMP (6 , (u8 *)swqe,256 ,"swqe format 2" ); + } + pr->swqe_id_counter +=1 ; + +if (port->vgrp &&vlan_tx_tag_present (skb)) { +EDEB (7 ,"VLAN TAG included" ); + swqe->tx_control |=EHEA_SWQE_VLAN_INSERT ; + swqe->vlan_tag =vlan_tx_tag_get (skb); + } +ehea_post_swqe (pr->qp, swqe); + pr->tx_packets++; + +spin_unlock (&pr->xmit_lock); + +EDEB_EX (7 ,"" ); +return NETDEV_TX_OK ; +} + +static void ehea_vlan_rx_register (struct net_device *dev, +struct vlan_group *grp) +{ +u64 hret =H_HARDWARE ; +struct hcp_query_ehea_port_cb_1 *cb1 =NULL ; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_adapter *adapter = port->adapter; + +EDEB_EN (7 ,"net_device=%p port=%p adapter=%p" , dev, port, adapter); + + port->vgrp = grp; + + cb1 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb1) { +EDEB_ERR (4 ,"No memory for cb1" ); + goto vlan_reg_exit; + } + +if (grp) +memset (cb1->vlan_filter,0 ,sizeof (cb1->vlan_filter)); +else +memset (cb1->vlan_filter,1 ,sizeof (cb1->vlan_filter)); + + hret =ehea_h_modify_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB1 , +H_PORT_CB1_ALL , + cb1); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_port failed for cb3" ); + } +kfree (cb1); + +vlan_reg_exit: +EDEB_EN (7 ,"dev=%p, vlan_group=%p" , dev, grp); +} + +static void ehea_vlan_rx_add_vid (struct net_device *dev,unsigned short vid) +{ +int index; +u64 hret =H_HARDWARE ; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct hcp_query_ehea_port_cb_1 *cb1 =NULL ; +struct ehea_adapter *adapter = port->adapter; +EDEB_EN (7 ,"dev=%p, vlan_id=%d" , dev, vid); + + cb1 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb1) { +EDEB_ERR (4 ,"No memory for cb1" ); + goto vlan_kill_exit; + } + hret =ehea_h_query_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB1 , +H_PORT_CB1_ALL , + cb1); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_port failed for cb1" ); + goto vlan_kill_exit; + } + + index = (vid /64 ); + cb1->vlan_filter[index] |= ((u64)(1 << (vid &0x3F ))); + + hret =ehea_h_modify_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB1 , +H_PORT_CB1_ALL , + cb1); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"modify_ehea_port failed for cb3" ); + +kfree (cb1); + +vlan_kill_exit: +EDEB_EX (7 ,"" ); + +} + +static void ehea_vlan_rx_kill_vid (struct net_device *dev,unsigned short vid) +{ +int index; +u64 hret =H_HARDWARE ; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_adapter *adapter = port->adapter; +struct hcp_query_ehea_port_cb_1 *cb1 =NULL ; +EDEB_EN (7 ,"dev=%p, vlan_id=%d" , dev, vid); +if (port->vgrp) + port->vgrp->vlan_devices[vid] =NULL ; + + cb1 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb1) { +EDEB_ERR (4 ,"No memory for cb1" ); + goto vlan_kill_exit; + } + hret =ehea_h_query_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB1 , +H_PORT_CB1_ALL , + cb1); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_port failed for cb1" ); + goto vlan_kill_exit; + } + + index = (vid /64 ); + cb1->vlan_filter[index] &= ~((u64)(1 << (vid &0x3F ))); + + hret =ehea_h_modify_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB1 , +H_PORT_CB1_ALL , + cb1); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"modify_ehea_port failed for cb3" ); +kfree (cb1); + +vlan_kill_exit: +EDEB_EX (7 ,"" ); +} + +int ehea_stop_qp (struct ehea_adapter *adapter,struct ehea_qp *qp) +{ +int ret = -EINVAL ; +u64 hret =H_HARDWARE ; +u16 dummy16; +u64 dummy64; +struct hcp_modify_qp_cb_0 *cb0 =NULL ; + +EDEB_EN (7 ,"qp=%p" , qp); + + cb0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!cb0) { +EDEB_ERR (4 ,"No memory for modify_qp control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + +/* Reset queue pair */ + cb0->qp_ctl_reg =H_QP_CR_ENABLED |H_QP_CR_STATE_RESET ; + hret =ehea_h_modify_ehea_qp (adapter->handle, +0 , + qp->ipz_qp_handle, +EHEA_BMASK_SET (H_QPCB0_QP_CTL_REG ,1 ), + cb0, + &dummy64, &dummy64, &dummy16, &dummy16); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"Failed resetting the queue pair" ); + goto modify_qp_failed; + } + +/* Disable queue pair */ + cb0->qp_ctl_reg =H_QP_CR_STATE_RESET ; + hret =ehea_h_modify_ehea_qp (adapter->handle, +0 , + qp->ipz_qp_handle, +EHEA_BMASK_SET (H_QPCB0_QP_CTL_REG ,1 ), + cb0, + &dummy64, &dummy64, &dummy16, &dummy16); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"Failed disabling the queue pair" ); + goto modify_qp_failed; + } + + ret =0 ; + +modify_qp_failed: +kfree (cb0); + +kzalloc_failed: +return ret; +} + +int ehea_activate_qp (struct ehea_adapter *adapter,struct ehea_qp *qp) +{ +int ret = -EINVAL ; +u64 hret =H_HARDWARE ; +u16 dummy16 =0 ; +u64 dummy64 =0 ; +struct hcp_modify_qp_cb_0 * cb0 =NULL ; + +EDEB_EN (7 ,"qp=%p" , qp); + + cb0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb0) { +EDEB_ERR (4 ,"No mem to allocate control block" ); + ret = -ENOMEM ; + goto failure; + } + + hret =ehea_h_query_ehea_qp (adapter->handle, +0 , qp->ipz_qp_handle, +EHEA_BMASK_SET (H_QPCB0_ALL ,0xFFFF ), cb0); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_qp failed (1)\n" ); + goto failure; + } + + cb0->qp_ctl_reg =H_QP_CR_STATE_INITIALIZED ; + hret =ehea_h_modify_ehea_qp (adapter->handle, +0 , qp->ipz_qp_handle, +EHEA_BMASK_SET (H_QPCB0_QP_CTL_REG ,1 ), cb0, + &dummy64, &dummy64, &dummy16, &dummy16); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"modify_ehea_qp failed (1)\n" ); + goto failure; + } + + hret =ehea_h_query_ehea_qp (adapter->handle, +0 , qp->ipz_qp_handle, +EHEA_BMASK_SET (H_QPCB0_ALL ,0xFFFF ), cb0); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_qp failed (2)\n" ); + goto failure; + } + + cb0->qp_ctl_reg =H_QP_CR_ENABLED |H_QP_CR_STATE_INITIALIZED ; + hret =ehea_h_modify_ehea_qp (adapter->handle, +0 , qp->ipz_qp_handle, +EHEA_BMASK_SET (H_QPCB0_QP_CTL_REG ,1 ), cb0, + &dummy64, &dummy64, &dummy16, &dummy16); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"modify_ehea_qp failed (2)\n" ); + goto failure; + } + + hret =ehea_h_query_ehea_qp (adapter->handle, +0 , qp->ipz_qp_handle, +EHEA_BMASK_SET (H_QPCB0_ALL ,0xFFFF ), cb0); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_qp failed (3)\n" ); + goto failure; + } + + cb0->qp_ctl_reg =H_QP_CR_ENABLED |H_QP_CR_STATE_RDY2SND ; + hret =ehea_h_modify_ehea_qp (adapter->handle, +0 , qp->ipz_qp_handle, +EHEA_BMASK_SET (H_QPCB0_QP_CTL_REG ,1 ), cb0, + &dummy64, &dummy64, &dummy16, &dummy16); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"modify_ehea_qp failed (3)\n" ); + goto failure; + } + + hret =ehea_h_query_ehea_qp (adapter->handle, +0 , qp->ipz_qp_handle, +EHEA_BMASK_SET (H_QPCB0_ALL ,0xFFFF ), cb0); +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_qp failed (4)\n" ); + goto failure; + } + + ret =0 ; + +failure: +kfree (cb0); +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static int ehea_port_res_setup (struct ehea_port *port,int def_qps, +int add_tx_qps) +{ +int i, k; +int ret; +struct port_res_cfg pr_cfg, pr_cfg_small_rx; +enum ehea_eq_type eq_type =EHEA_EQ ; + +EDEB_EN (7 ,"" ); + + port->qp_eq =ehea_create_eq (port->adapter, eq_type, +EHEA_MAX_ENTRIES_EQ ,1 ); +if (!port->qp_eq) { +EDEB_ERR (4 ,"ehea_create_eq failed (qp_eq)" ); + goto port_res_setup_failed2; + } + + pr_cfg.max_entries_rcq =EHEA_MAX_CQE_COUNT ; + pr_cfg.max_entries_scq =EHEA_MAX_CQE_COUNT ; + pr_cfg.max_entries_sq =EHEA_MAX_ENTRIES_SQ ; + pr_cfg.max_entries_rq1 =EHEA_MAX_ENTRIES_RQ1 ; + pr_cfg.max_entries_rq2 =EHEA_MAX_ENTRIES_RQ2 ; + pr_cfg.max_entries_rq3 =EHEA_MAX_ENTRIES_RQ3 ; + + pr_cfg_small_rx.max_entries_rcq =1 ; + pr_cfg_small_rx.max_entries_scq =EHEA_MAX_CQE_COUNT ; + pr_cfg_small_rx.max_entries_sq =EHEA_MAX_ENTRIES_SQ ; + pr_cfg_small_rx.max_entries_rq1 =1 ; + pr_cfg_small_rx.max_entries_rq2 =1 ; + pr_cfg_small_rx.max_entries_rq3 =1 ; + + +for (i =0 ; i < def_qps; i++) { + ret =ehea_init_port_res (port, &port->port_res[i], + &pr_cfg, i); +if (ret) + goto port_res_setup_failed; + } +for (i = def_qps; i < def_qps + add_tx_qps; i++) { + ret =ehea_init_port_res (port, &port->port_res[i], + &pr_cfg_small_rx, i); +if (ret) + goto port_res_setup_failed; + } +EDEB_EX (7 ,"" ); +return 0 ; + +port_res_setup_failed: +for (k =0 ; k < i; k++) { +ehea_clean_port_res (port, &port->port_res[k]); + } +port_res_setup_failed2: + ret =ehea_destroy_eq (port->qp_eq); +if (ret) +EDEB_ERR (4 ,"could not destroy qp_eq" ); + +EDEB_EX (7 ,"" ); +return -EINVAL ; +} + +void ehea_clean_all_port_res (struct ehea_port *port) +{ +int ret; +int i; +for (i =0 ; i < port->num_def_qps + port->num_tx_qps; i++) +ehea_clean_port_res (port, &port->port_res[i]); + + ret =ehea_destroy_eq (port->qp_eq); +if (ret) +EDEB_ERR (4 ,"could not destroy qp_eq" ); +} + +int ehea_open (struct net_device *dev) +{ +u64 hret =H_HARDWARE ; +int i; +int ret = -EIO ; +struct ehea_port *port = (struct ehea_port *)dev->priv; +u64 mac_addr =0 ; + +EDEB_EN (7 ,"logical_port_id=%d" , port->logical_port_id); + + ret =ehea_port_res_setup (port, port->num_def_qps, port->num_tx_qps); + +if (ret) + goto port_res_setup_failed; + +/* Set default QP for this port */ + ret =ehea_configure_port (port); +if (ret) { +EDEB_ERR (4 ,"ehea_configure_port failed" ); + goto reg_failed; + } + + hret =ehea_broadcast_reg_helper (port,H_REG_BCMC ); +if (hret) { + ret = -EIO ; + goto reg_failed; + } + mac_addr = (*(u64 *)dev->dev_addr) >>16 ; + + ret =ehea_reg_interrupts (dev); +if (ret) + goto irq_reg_failed; + +for (i =0 ; i < port->num_def_qps + port->num_tx_qps; i++) { + ret =ehea_activate_qp (port->adapter, port->port_res[i].qp); +if (ret) + goto activate_qp_failed; + } + +for (i =0 ; i < port->num_def_qps + port->num_tx_qps; i++) +ehea_fill_port_res (&port->port_res[i]); + +netif_start_queue (dev); + ret =0 ; + goto done; + +activate_qp_failed: +ehea_free_interrupts (dev); + +irq_reg_failed: +ehea_broadcast_reg_helper (port,H_DEREG_BCMC ); + +reg_failed: +ehea_clean_all_port_res (port); + +port_res_setup_failed: +done: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static int ehea_stop (struct net_device *dev) +{ +struct ehea_port *port = (struct ehea_port *)dev->priv; + +EDEB_EN (7 ,"" ); +netif_stop_queue (dev); +ehea_drop_multicast_list (dev); +ehea_stop_qp (port->adapter, port->port_res[0 ].qp); +ehea_free_interrupts (dev); + +ehea_broadcast_reg_helper (port,H_DEREG_BCMC ); +ehea_clean_all_port_res (port); + +EDEB_EX (7 ,"" ); +return 0 ; +} + +static struct of_device_id ehea_device_table[] = { + { + .name ="lhea" , + .compatible ="IBM,lhea" , + }, + {}, +}; + +static struct ibmebus_driver ehea_driver = { + .name ="ehea" , + .id_table = ehea_device_table, + .probe = ehea_probe, + .remove = ehea_remove, +}; + +int ehea_sense_adapter_attr (struct ehea_adapter *adapter) +{ +int ret = -EINVAL ; +u64 hret =H_HARDWARE ; +struct hcp_query_ehea *query_ehea_cb =NULL ; + +EDEB_EN (7 ,"" ); + + query_ehea_cb =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!query_ehea_cb) { +EDEB_ERR (4 ,"No memory for query_ehea control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + + hret =ehea_h_query_ehea (adapter->handle, query_ehea_cb); +if (hret !=H_SUCCESS ) { + goto query_ehea_failed; + } + + adapter->num_ports = query_ehea_cb->num_ports; + adapter->max_mc_mac = query_ehea_cb->max_mc_mac -1 ; + + ret =0 ; + +query_ehea_failed: +kfree (query_ehea_cb); + +kzalloc_failed: +EDEB_EX (7 ,"ret=%d, num_ports=%d, max_mc_mac=0x%lx" , + ret, adapter->num_ports, adapter->max_mc_mac); +return ret; +} + +static int ehea_sense_port_attr (struct ehea_adapter *adapter,int portnum) +{ +int ret = -EINVAL ; +u64 hret =H_HARDWARE ; +struct ehea_port *port = adapter->port[portnum]; +struct hcp_query_ehea_port_cb_0 *query_ehea_port_cb_0 =NULL ; + +EDEB_EN (7 ,"adapter=%p, portnum=%d" , adapter, portnum); + +/* allocate memory for control block */ + query_ehea_port_cb_0 = +kzalloc (sizeof (*query_ehea_port_cb_0),GFP_KERNEL ); + +if (!query_ehea_port_cb_0) { +EDEB_ERR (4 ,"No memory for query_ehea_port control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + + hret =ehea_h_query_ehea_port (adapter->handle, + adapter->port[portnum]->logical_port_id, +H_PORT_CB0 , +EHEA_BMASK_SET (H_PORT_CB0_ALL ,0xFFFF ), + query_ehea_port_cb_0); + +if (hret !=H_SUCCESS ) { + ret = -EPERM ; + goto query_ehea_port_failed; + } + +EDEB_DMP (7 , (u8 *) query_ehea_port_cb_0, +sizeof (struct hcp_query_ehea_port_cb_0 ),"After HCALL" ); + + +/* MAC address */ + port->mac_addr = query_ehea_port_cb_0->port_mac_addr <<16 ; + +/* Port speed */ +switch (query_ehea_port_cb_0->port_speed) { +case H_PORT_SPEED_10M_H : + port->port_speed =EHEA_SPEED_10M ; + port->full_duplex =0 ; +break ; +case H_PORT_SPEED_10M_F : + port->port_speed =EHEA_SPEED_10M ; + port->full_duplex =1 ; +break ; +case H_PORT_SPEED_100M_H : + port->port_speed =EHEA_SPEED_100M ; + port->full_duplex =0 ; +break ; +case H_PORT_SPEED_100M_F : + port->port_speed =EHEA_SPEED_100M ; + port->full_duplex =1 ; +break ; +case H_PORT_SPEED_1G_F : + port->port_speed =EHEA_SPEED_1G ; + port->full_duplex =1 ; +break ; +case H_PORT_SPEED_10G_F : + port->port_speed =EHEA_SPEED_10G ; + port->full_duplex =1 ; +break ; +default : + port->port_speed =0 ; + port->full_duplex =0 ; +break ; + } + +/* Number of default QPs */ + port->num_def_qps = query_ehea_port_cb_0->num_default_qps; +if (port->num_def_qps >=EHEA_NUM_TX_QP ) + port->num_tx_qps =0 ; +else + port->num_tx_qps =EHEA_NUM_TX_QP - port->num_def_qps; + +EDEB (7 ,"MAC address=0x%lX" , adapter->port[portnum]->mac_addr >>16 ); + + ret =0 ; + +query_ehea_port_failed: +kfree (query_ehea_port_cb_0); + +kzalloc_failed: +EDEB_EX (7 ,"MACaddr=0x%lX, portspeed=%dMbps, fullduplex=%d, " +"num_def_qps=%d" , + port->mac_addr >>16 , + port->port_speed, port->full_duplex, port->num_def_qps); +return ret; +} + +static int ehea_setup_single_port (struct ehea_adapter *adapter, +int portnum,struct device_node *dn) +{ +int ret = -EINVAL ; +u64 hret =H_HARDWARE ; +struct ehea_port *port =NULL ; +struct net_device *dev =NULL ; +struct hcp_query_ehea_port_cb_4 *cb4; +u32 *dn_log_port_id =NULL ; + +EDEB_EN (7 ,"Initializing port #%d. adapter=%p" , portnum, adapter); + + port = adapter->port[portnum]; + +if (!dn) { +EDEB_ERR (4 ,"Bad device node: dn=%p" , dn); + goto done; + } + + port->of_dev_node = dn; + +/* Determine logical port id */ + dn_log_port_id = (u32 *)get_property (dn,"ibm,hea-port-no" ,NULL ); + +if (!dn_log_port_id) { +EDEB_ERR (4 ,"Bad device node: dn_log_port_id=%p" , + dn_log_port_id); + goto done; + } + port->logical_port_id = *dn_log_port_id; + port->adapter = adapter; + port->mc_list = + (struct ehea_mc_list *)kzalloc (sizeof (struct ehea_mc_list ), +GFP_KERNEL ); +if (!port->mc_list) { +EDEB_ERR (4 ,"No memory for multicast list" ); + goto done; + } + +INIT_LIST_HEAD (&port->mc_list->list); + + ret =ehea_sense_port_attr (adapter, portnum); +if (ret) + goto done; + +/* initialize net_device structure */ + dev =alloc_etherdev (sizeof (struct ehea_port )); + +if (!dev) { +EDEB_ERR (4 ,"No memory for net_device" ); + ret = -ENOMEM ; + goto done; + } + + cb4 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb4) { +EDEB_ERR (4 ,"No memory for cb4" ); + }else { + cb4->jumbo_frame =1 ; + hret =ehea_h_modify_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB4 , +H_PORT_CB4_JUMBO , + (void *)cb4); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Jumbo frames not activated" ); + } + +SET_MODULE_OWNER (dev); + +memcpy (dev->dev_addr, &port->mac_addr,ETH_ALEN ); + + dev->open = ehea_open; + dev->poll = ehea_poll; + dev->weight =64 ; + dev->stop = ehea_stop; + dev->hard_start_xmit = ehea_start_xmit; + dev->get_stats = ehea_get_stats; + dev->set_multicast_list = ehea_set_multicast_list; + dev->do_ioctl = ehea_ioctl; + dev->set_mac_address = ehea_set_mac_addr; + dev->change_mtu = ehea_change_mtu; + dev->priv = port; + + dev->features =NETIF_F_SG |NETIF_F_FRAGLIST |NETIF_F_TSO + |NETIF_F_HIGHDMA |NETIF_F_HW_CSUM |NETIF_F_HW_VLAN_TX + |NETIF_F_HW_VLAN_RX |NETIF_F_HW_VLAN_FILTER + |NETIF_F_LLTX ; + + dev->vlan_rx_register = ehea_vlan_rx_register; + dev->vlan_rx_add_vid = ehea_vlan_rx_add_vid; + dev->vlan_rx_kill_vid = ehea_vlan_rx_kill_vid; + +ehea_set_ethtool_ops (dev); + + ret =register_netdev (dev); +if (ret) { +EDEB_ERR (4 ,"register_netdev failed. ret=%d" , ret); + goto reg_netdev_failed; + } + + port->netdev = dev; + + ret =0 ; + + goto done; + +reg_netdev_failed: +free_netdev (port->netdev); +kfree (port->mc_list); + +done: +EDEB_EX (7 ,"logical port id=0x%x" , port->logical_port_id); +return ret; +} + +static int ehea_setup_ports (struct ehea_adapter *adapter) +{ +int ret = -EINVAL ; +int i; +int port_setup_ok =0 ; +struct ehea_port *port =NULL ; +struct device_node *dn =NULL ; + +EDEB_EX (7 ,"" ); + +/* get port properties for all ports */ +for (i =0 ; i < adapter->num_ports; i++) { + +if (adapter->port[i]) +continue ;/* port already up and running */ + +/* allocate memory for the port structures */ + port =kzalloc (sizeof (struct ehea_port ),GFP_KERNEL ); + +if (!port) { +EDEB_ERR (4 ,"No memory for ehea_port" ); +break ;/* continuing not reasonable */ + } + + adapter->port[i] = port; + dn =of_find_node_by_name (dn,"ethernet" ); + ret =ehea_setup_single_port (adapter, i, dn); + +if (ret) { +/* Free mem for this port struct. the others will be +processed on rollback */ +kfree (port); + adapter->port[i] =NULL ; + } + } + +of_node_put (dn); + +/* Check for succesfully set up ports */ +for (i =0 ; i < adapter->num_ports; i++) +if (adapter->port[i]) + port_setup_ok++; + +if (port_setup_ok >0 ) + ret =0 ;/* At least some ports are setup correctly */ + +EDEB_EX (7 ,"" ); +return ret; +} + +static int __devinit ehea_probe (struct ibmebus_dev *dev, +const struct of_device_id *id) +{ +int ret = -EINVAL ; +struct ehea_adapter *adapter =NULL ; +u64 *adapter_handle =NULL ; + +EDEB_EN (7 ,"ibmebus_dev=%p, of_device_id=%p" , dev, id); + + adapter =kzalloc (sizeof (*adapter),GFP_KERNEL ); + +if (!adapter) { +EDEB_ERR (4 ,"No memory for ehea_adapter" ); + ret = -ENOMEM ; + goto kzalloc_adapter_failed; + } + + + adapter_handle = (u64 *)get_property (dev->ofdev.node,"ibm,hea-handle" , +NULL ); + +if (!adapter_handle) { +EDEB_ERR (4 ,"Failed getting handle for adapter '%s'" , + dev->ofdev.node->full_name); + ret = -ENODEV ; + goto get_property_failed; + } + + adapter->handle = *adapter_handle; + adapter->pd =EHEA_PD_ID ; + + dev->ofdev.dev.driver_data = adapter; + + ret =ehea_reg_mr_adapter (adapter); +if (ret) + goto register_mr_failed; + +/* initialize adapter and ports */ +/* get adapter properties */ + ret =ehea_sense_adapter_attr (adapter); +if (ret) + goto sense_adapter_failed; + + adapter->neq =ehea_create_eq (adapter, +EHEA_NEQ ,EHEA_MAX_ENTRIES_EQ ,1 ); +if (!adapter->neq) + goto create_neq_failed; + +tasklet_init (&adapter->neq_tasklet, ehea_neq_tasklet, + (unsigned long )adapter); + + ret =ibmebus_request_irq (NULL , adapter->neq->attr.ist1, + ehea_interrupt_neq,SA_INTERRUPT ,"ehea_neq" , + (void *)adapter); +if (ret) + goto request_irq_failed; + + ret =ehea_setup_ports (adapter); +if (ret) + goto setup_ports_failed; + + ret =0 ; + goto done; + +setup_ports_failed: +request_irq_failed: +ehea_destroy_eq (adapter->neq); +create_neq_failed: +sense_adapter_failed: +ehea_dereg_mr_adapter (adapter); +register_mr_failed: +get_property_failed: +kfree (adapter); +kzalloc_adapter_failed: +done: +EDEB_EX (7 ,"" ); +return ret; +} + +int __init ehea_module_init (void ) +{ +int ret = -EINVAL ; + +EDEB_EN (7 ,"" ); + +printk (KERN_INFO "%s Ethernet Device Driver (Release %s)\n" , +EHEA_DRIVER_NAME , +EHEA_DRIVER_VERSION ); + + + ret =ibmebus_register_driver (&ehea_driver); +if (ret) { +EDEB_ERR (4 ,"Failed registering eHEA device driver on ebus" ); +return -EINVAL ; + } + +EDEB_EX (7 ,"" ); +return 0 ; +} + +static void ehea_shutdown_single_port (struct ehea_adapter *adapter,int portnum) +{ +struct ehea_port *port = adapter->port[portnum]; + +EDEB_EN (7 ,"" ); + +if (port) { +EDEB (7 ,"Shutting down port #%d." , portnum); +unregister_netdev (port->netdev); +free_netdev (port->netdev); +kfree (port->mc_list); +kfree (port); + adapter->port[portnum] =NULL ; + }else +EDEB (7 ,"Port #%d not setup. Doing nothing." , portnum); + +EDEB_EX (7 ,"" ); +} + +static int __devexit ehea_remove(struct ibmebus_dev *dev) +{ +int ret = -EINVAL ; +struct ehea_adapter *adapter = dev->ofdev.dev.driver_data; +int i; + +EDEB_EN (7 ,"ibmebus_dev=%p" , dev); + +for (i =0 ; i < adapter->num_ports; i++) +ehea_shutdown_single_port (adapter, i); + +ibmebus_free_irq (NULL , adapter->neq->attr.ist1, adapter); + +ehea_destroy_eq (adapter->neq); + + ret =ehea_dereg_mr_adapter (adapter); +if (ret) + goto deregister_mr_failed; +kfree (adapter); + ret =0 ; + +deregister_mr_failed: +EDEB_EX (7 ,"" ); +return ret; +} + +static void __exit ehea_module_exit(void) +{ +EDEB_EN (7 ,"" ); + +ibmebus_unregister_driver (&ehea_driver); +EDEB_EX (7 ,"" ); +} + +module_init (ehea_module_init); +module_exit (ehea_module_exit);
Hi Jan-Bernd,
I had some minutes, here are some finding after a quick look.
drivers/net/ehea/ehea_main.c line 63
Quoted 6 lines · you
drivers/net/ehea/ehea_main.c +6
-0+static struct net_device_stats *ehea_get_stats (struct net_device *dev) +{ +int i; +u64 hret =H_HARDWARE ; +u64 rx_packets =0 ; +struct ehea_port *port = (struct ehea_port *)dev->priv;
dev->priv is a void pointer, this cast is unnecessary. When we are at it, have you considered the netdev_priv macro? This will require some prep in alloc_netdev and might not always pe possible.
Quoted 12 lines
drivers/net/ehea/ehea_main.c +12
-0+struct ehea_adapter *adapter = port->adapter; +struct hcp_query_ehea_port_cb_2 *cb2 =NULL ; +struct net_device_stats *stats = &port->stats; + +EDEB_EN (7 ,"net_device=%p" , dev); + + cb2 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb2) { +EDEB_ERR (4 ,"No memory for cb2" ); + goto get_stat_exit; + } +
drivers/net/ehea/ehea_main.c line 85
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ hret =ehea_h_query_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB2 , +H_PORT_CB2_ALL , + cb2); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_port failed for cb2" ); + goto get_stat_exit; + }
You leak memory here, dont you? (cb2 points to allocated memory and you are in an error path.)
Quoted 9 lines
drivers/net/ehea/ehea_main.c +9
-0+ +EDEB_DMP (7 , (u8 *)cb2, +sizeof (struct hcp_query_ehea_port_cb_2 ),"After HCALL" ); + +for (i =0 ; i < port->num_def_qps; i++) { + rx_packets += port->port_res[i].rx_packets; + } + + stats->tx_packets = cb2->txucp + cb2->txmcp + cb2->txbcp;
drivers/net/ehea/ehea_main.c line 104
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ stats->multicast = cb2->rxmcp; + stats->rx_errors = cb2->rxuerr; + stats->rx_bytes = cb2->rxo; + stats->tx_bytes = cb2->txo; + stats->rx_packets = rx_packets; + +get_stat_exit: +EDEB_EX (7 ,"" ); +return stats; +}
again, cb2 is not freed.
[...]
drivers/net/ehea/ehea_main.c line 124
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+static inline u64 get_swqe_addr (u64 tmp_addr,int addr_seg) +{ +u64 addr; + addr = tmp_addr; +return addr; +}
This is suppsed to change in the future? If not you can get rid of it.
drivers/net/ehea/ehea_main.c line 129
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+ +static inline u64 get_rwqe_addr (u64 tmp_addr) +{ +return tmp_addr; +}
same here.
drivers/net/ehea/ehea_main.c line 332
Quoted 4 lines
drivers/net/ehea/ehea_main.c +4
-0+ +static int ehea_poll (struct net_device *dev,int *budget) +{ +struct ehea_port *port = (struct ehea_port *)dev->priv;
Again. no cast, maybe netdev_priv macro.
Quoted 179 lines
drivers/net/ehea/ehea_main.c +179
-0+struct ehea_port_res *port_res = &port->port_res[0 ]; +struct ehea_cqe *cqe; +struct ehea_qp *qp = port_res->qp; +int wqe_index =0 ; +int last_wqe_index =0 ; +int x =0 ; +int processed =0 ; +int processed_RQ1 =0 ; +int processed_RQ2 =0 ; +int processed_RQ3 =0 ; +int rq; +int intreq; +struct sk_buff **skb_arr_rq1 = port_res->skb_arr_rq1; +struct sk_buff **skb_arr_rq2 = port_res->skb_arr_rq2; +struct sk_buff **skb_arr_rq3 = port_res->skb_arr_rq3; +int skb_arr_rq1_len = port_res->skb_arr_rq1_len; +int my_quota =min (*budget, dev->quota); + +EDEB_EN (7 ,"dev=%p, port_res=%p, budget=%d, quota=%d, qp_nr=%x" , + dev, port_res, *budget, dev->quota, + port_res->qp->init_attr.qp_nr); + my_quota =min (my_quota,EHEA_MAX_RWQE ); + +/* rq0 is low latency RQ */ + cqe =ehea_poll_rq1 (qp, &wqe_index); +while ((my_quota >0 ) && cqe) { +ehea_inc_rq1 (qp); + processed_RQ1++; + processed++; + my_quota--; + +EDEB_DMP (6 , (u8 *)cqe,4 *16 ,"CQE" ); + last_wqe_index = wqe_index; +rmb (); +if (!ehea_check_cqe (cqe, &rq)) { +struct sk_buff *skb; +if (rq ==1 ) {/* LL RQ1 */ +void *pref; + + x = (wqe_index +1 ) % skb_arr_rq1_len; + pref = (void *)skb_arr_rq1[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (wqe_index +1 ) % skb_arr_rq1_len; + pref = (void *)(skb_arr_rq1[x]->data); +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + skb = skb_arr_rq1[wqe_index]; +if (unlikely (!skb)) { +EDEB_ERR (4 ,"LL SBK=NULL, wqe_index=%d" , + wqe_index); + skb =dev_alloc_skb (EHEA_LL_PKT_SIZE ); +if (!skb) +panic ("Alloc SKB failed" ); + } + skb_arr_rq1[wqe_index] =NULL ; +ehea_fill_skb_ll (dev, skb, cqe); + }else if (rq ==2 ) {/* RQ2 */ +void *pref; +int skb_index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); + x = (skb_index +1 ) % port_res->skb_arr_rq2_len; + pref = (void *)skb_arr_rq2[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (skb_index +1 ) % port_res->skb_arr_rq2_len; + pref = (void *)(skb_arr_rq2[x]->data); + +prefetch (pref); +prefetch (pref +EHEA_CACHE_LINE ); +prefetch (pref +EHEA_CACHE_LINE *2 ); +prefetch (pref +EHEA_CACHE_LINE *3 ); + skb = skb_arr_rq2[skb_index]; + +if (unlikely (!skb)) { +EDEB_ERR (4 ,"rq2: SKB=NULL, index=%d" , + skb_index); +break ; + } + skb_arr_rq2[skb_index] =NULL ; +ehea_fill_skb (dev, skb, cqe); + processed_RQ2++; + }else { +void *pref; +int skb_index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); + x = (skb_index +1 ) % port_res->skb_arr_rq3_len; + pref = (void *)skb_arr_rq3[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (skb_index +1 ) % port_res->skb_arr_rq3_len; + pref = (void *)(skb_arr_rq3[x]->data); +prefetch (pref); +prefetch (pref +EHEA_CACHE_LINE ); +prefetch (pref +EHEA_CACHE_LINE *2 ); +prefetch (pref +EHEA_CACHE_LINE *3 ); + + skb = skb_arr_rq3[skb_index]; +if (unlikely (!skb)) { +EDEB_ERR (4 ,"rq3: SKB=NULL, index=%d" , + skb_index); +break ; + } + skb_arr_rq3[skb_index] =NULL ; +ehea_fill_skb (dev, skb, cqe); + processed_RQ3++; + } + +EDEB (6 ,"About to pass SKB: dev=%p\n" +"skb=%p skb->data=%p skb->len=%d" +" skb->data_len=0x%x nr_frags=%d" , + dev, + skb, + skb->data, + skb->len, + skb->data_len,skb_shinfo (skb)->nr_frags); +if (cqe->status &EHEA_CQE_VLAN_TAG_XTRACT ) { +EDEB (7 ,"VLAN TAG extracted: %4x, vgrp=%p" , + cqe->vlan_tag, port->vgrp); +EDEB (7 ,"vlan_devices[vlan_tag]=%p" , + port->vgrp->vlan_devices[cqe->vlan_tag]); +vlan_hwaccel_receive_skb (skb, port->vgrp, + cqe->vlan_tag); + }else { +EDEB (7 ,"netif_receive_skb" ); +netif_receive_skb (skb); + } +EDEB (7 ,"SKB passed (netif_receive(skb) called)" ); + + }else { +struct sk_buff *skb; + +EDEB_ERR (4 ,"cqe->status indicating error: CQE:" ); +EDEB_DMP (4 , (u8 *)cqe,4 *16 ,"" ); +if (rq ==2 ) { + processed_RQ2++; + skb = skb_arr_rq2[ +EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)]; + skb_arr_rq2[EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)] =NULL ; +dev_kfree_skb (skb); + } +if (rq ==3 ) { + processed_RQ3++; + skb = skb_arr_rq3[ +EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)]; + skb_arr_rq3[EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)] =NULL ; +dev_kfree_skb (skb); + } + } + cqe =ehea_poll_rq1 (qp, &wqe_index); + } + + dev->quota -= processed; + *budget -= processed; + + port_res->p_state.ehea_poll +=1 ; + + port_res->rx_packets += processed; + +ehea_refill_rq1 (port_res, last_wqe_index, processed_RQ1); +ehea_refill_rq2 (port_res, processed_RQ2); +ehea_refill_rq3 (port_res, processed_RQ3); + + intreq = ((port_res->p_state.ehea_poll &0xF ) ==0xF ); + +EDEB_EX (7 ,"processed=%d, *budget=%d, dev->quota=%d" , + processed, *budget, dev->quota); + +if (!cqe || intreq) { +netif_rx_complete (dev); +ehea_reset_cq_ep (port_res->recv_cq);
drivers/net/ehea/ehea_main.c line 521
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ehea_reset_cq_n1 (port_res->recv_cq); + cqe =ipz_qeit_get_valid (&qp->ipz_rqueue1); +EDEB (7 ,"CQE=%p, break ehea_poll while loop" , cqe); +if (!cqe || intreq) +return 0 ; +if (!netif_rx_reschedule (dev, my_quota)) +return 0 ; + } +return 1 ; +}
The poll function seems too long and therefore hard to review. Please consider splitting it.
Signature · 4 lines
Mit freundlichen Grüßen / Best Regards Christian Borntraeger Linux Software Engineer zSeries Linux & Virtualization
Hi Christian,
thanks for your comments, we'll send an updated patch set soon.
Jan-Bernd
Quoted 5 lines · Christian Borntraeger
Hi Jan-Bernd,
I had some minutes, here are some finding after a quick look.
On Wednesday 09 August 2006 10:38, you wrote:
Quoted 8 lines
drivers/net/ehea/ehea_main.c line 63
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+static struct net_device_stats *ehea_get_stats (struct net_device *dev) +{ +int i; +u64 hret =H_HARDWARE ; +u64 rx_packets =0 ; +struct ehea_port *port = (struct ehea_port *)dev->priv;
dev->privis a void pointer, this cast is unnecessary. When we are at it, have you considered thenetdev_privmacro? This will require some prep inalloc_netdevand might not always pe possible.
good point, we'll use alloc_etherdev / netdev_priv
Quoted 14 lines
Quoted 14 lines
drivers/net/ehea/ehea_main.c +14
-0+ +EDEB_DMP (7 , (u8 *)cb2, +sizeof (struct hcp_query_ehea_port_cb_2 ),"After HCALL" ); + +for (i =0 ; i < port->num_def_qps; i++) { + rx_packets += port->port_res[i].rx_packets; + } + + stats->tx_packets = cb2->txucp + cb2->txmcp + cb2->txbcp; + stats->multicast = cb2->rxmcp; + stats->rx_errors = cb2->rxuerr; + stats->rx_bytes = cb2->rxo; + stats->tx_bytes = cb2->txo; + stats->rx_packets = rx_packets;
Quoted 8 lines
drivers/net/ehea/ehea_main.c line 104
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+ +get_stat_exit: +EDEB_EX (7 ,"" ); +return stats; +}again, cb2 is not freed.
[...]
yep, done
Quoted 10 lines
drivers/net/ehea/ehea_main.c line 124
Quoted 7 lines
drivers/net/ehea/ehea_main.c +6
-0+static inline u64 get_swqe_addr (u64 tmp_addr,int addr_seg) +{ +u64 addr; + addr = tmp_addr; +return addr; +}This is suppsed to change in the future? If not you can get rid of it.
Quoted 7 lines
drivers/net/ehea/ehea_main.c line 129
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+ +static inline u64 get_rwqe_addr (u64 tmp_addr) +{ +return tmp_addr; +}same here.
removed
Quoted 5 lines
Quoted 1 line
+
ehea_poll()The poll function seems too long and therefore hard to review. Please consider splitting it.
done
Quoted 4 lines · Jan-Bernd Themann
drivers/net/ehea/ehea_main.c +1
-0+static inline u64 get_swqe_addr (u64 tmp_addr,int addr_seg)
drivers/net/ehea/ehea_main.c line 129
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+{ +u64 addr; + addr = tmp_addr; +return addr; +} + +static inline u64 get_rwqe_addr (u64 tmp_addr) +{ +return tmp_addr; +}
The point of this exercise?
Quoted 1 line
+static inline int
ehea_refill_rq3_def(struct ehea_port_res *pr, int nr_of_wqes)
Way too big to be inline function.
Quoted 39 lines
drivers/net/ehea/ehea_main.c +18
-0+{ +int i; +int ret =0 ; +struct ehea_qp *qp; +struct ehea_rwqe *rwqe; +int skb_arr_rq3_len = pr->skb_arr_rq3_len; +struct sk_buff **skb_arr_rq3 = pr->skb_arr_rq3; +EDEB_EN (8 ,"pr=%p, nr_of_wqes=%d" , pr, nr_of_wqes); +if (nr_of_wqes ==0 ) +return -EINVAL ; + qp = pr->qp; +for (i =0 ; i < nr_of_wqes; i++) { +int index = pr->skb_rq3_index++; +struct sk_buff *skb =dev_alloc_skb (EHEA_MAX_PACKET_SIZE + +NET_IP_ALIGN ); + +if (!skb) { + EDEB_ERR(4, "No memory for skb. Only %d rwqefilled.",
drivers/net/ehea/ehea_main.c +10
-0+ i); + ret = -ENOMEM ; +break ; + } +skb_reserve (skb,NET_IP_ALIGN ); + + rwqe =ehea_get_next_rwqe (qp,3 ); + pr->skb_rq3_index %= skb_arr_rq3_len; + skb_arr_rq3[index] = skb; + rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE,
EHEA_RWQE3_TYPE)drivers/net/ehea/ehea_main.c +9
-0+ | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index); + rwqe->sg_list[0 ].l_key =ehea_get_recv_lkey (pr); + rwqe->sg_list[0 ].vaddr =get_rwqe_addr ((u64 )skb->data); + rwqe->sg_list[0 ].len =EHEA_MAX_PACKET_SIZE ; + rwqe->data_segments =1 ; + } + +/* Ring doorbell */ +iosync ();
drivers/net/ehea/ehea_main.c line 283
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ehea_update_rq3a (qp, i); +EDEB_EX (8 ,"" ); +return ret; +} + + +static inline int ehea_refill_rq3 (struct ehea_port_res *pr,int nr_of_wqes) +{ +return ehea_refill_rq3_def (pr, nr_of_wqes); +}
ehea_refill_rq3[123] appears to be 1:1 wrappers around ehea_refill_rq3[123]_def. Any idea behind them?
drivers/net/ehea/ehea_main.c line 1036
Quoted 2 lines
drivers/net/ehea/ehea_main.c +2
-0+ init_attr = (struct ehea_qp_init_attr *) +kzalloc (sizeof (struct ehea_qp_init_attr ),GFP_KERNEL );
Useless cast.
drivers/net/ehea/ehea_main.c
Quoted 2 lines
drivers/net/ehea/ehea_main.c +2
-0+ pr->skb_arr_sq = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 ));
Useless cast
drivers/net/ehea/ehea_main.c
Quoted 12 lines
drivers/net/ehea/ehea_main.c +9
-0+ pr->skb_arr_rq1 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); + pr->skb_arr_rq2 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); + pr->skb_arr_rq3 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +static int ehea_ioctl (struct net_device *dev,struct ifreq *ifr,int cmd) +{ +EDEB_ERR (4 ,"ioctl not supported: dev=%s cmd=%d" , dev->name, cmd);
Then copy NULL into ->do_ioctl!
drivers/net/ehea/ehea_main.c line 1404
Quoted 13 lines
drivers/net/ehea/ehea_main.c +12
-0+return -EOPNOTSUPP ; +} + ehea_port_cb_0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!ehea_port_cb_0) { +EDEB_ERR (4 ,"No memory for ehea_port control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + +memcpy ((u8 *)(&(ehea_port_cb_0->port_mac_addr)), + (u8 *)&(mac_addr->sa_data[0 ]),6 );
No casts on memcpy arguments.
drivers/net/ehea/ehea_main.c line 1658
Quoted 8 lines
drivers/net/ehea/ehea_main.c +7
-0+memcpy ((u8 *)&ehea_mcl_entry->macaddr, mc_mac_addr,ETH_ALEN ); +static inline void ehea_xmit2 (struct sk_buff *skb, +struct net_device *dev,struct ehea_swqe *swqe, +u32 lkey) +{ +int nfrags; +unsigned short skb_protocol = skb->protocol;
Useless variable. And it should be __be16, FYI.
drivers/net/ehea/ehea_main.c line 1662
Quoted 4 lines
drivers/net/ehea/ehea_main.c +4
-0+ nfrags =skb_shinfo (skb)->nr_frags; +EDEB_EN (7 ,"skb->nfrags=%d (0x%X)" , nfrags, nfrags); + +if (skb_protocol ==ETH_P_IP ) {
ITYM, htons(ETH_P_IP).
drivers/net/ehea/ehea_main.c line 1706
Quoted 8 lines
drivers/net/ehea/ehea_main.c +8
-0+static inline void ehea_xmit3 (struct sk_buff *skb, +struct net_device *dev,struct ehea_swqe *swqe) +{ +int i; +skb_frag_t *frag; +int nfrags =skb_shinfo (skb)->nr_frags; +u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0 ]; +u64 skb_protocol = skb->protocol;
Useless var.
drivers/net/ehea/ehea_main.c line 1709
Quoted 3 lines
drivers/net/ehea/ehea_main.c +3
-0+ +EDEB_EN (7 ,"" ); +if (likely (skb_protocol ==ETH_P_IP )) {
htons(ETH_P_IP)
Hi,
thanks for your comments!
We'll post a modified patch very soon.
Jan-Bernd
Quoted 4 lines · Alexey Dobriyan
Quoted 2 lines · Jan-Bernd Themann
drivers/net/ehea/ehea_main.c +0
-0
Quoted 13 lines
drivers/net/ehea/ehea_main.c line 129
Quoted 11 lines
drivers/net/ehea/ehea_main.c +11
-0+static inline u64 get_swqe_addr (u64 tmp_addr,int addr_seg) +{ +u64 addr; + addr = tmp_addr; +return addr; +} + +static inline u64 get_rwqe_addr (u64 tmp_addr) +{ +return tmp_addr; +}The point of this exercise?
has been removed
Quoted 49 lines
Quoted 2 lines
+static inline int
ehea_refill_rq3_def(struct ehea_port_res *pr, int nr_of_wqes)Way too big to be inline function.
Quoted 44 lines
drivers/net/ehea/ehea_main.c +18
-0+{ +int i; +int ret =0 ; +struct ehea_qp *qp; +struct ehea_rwqe *rwqe; +int skb_arr_rq3_len = pr->skb_arr_rq3_len; +struct sk_buff **skb_arr_rq3 = pr->skb_arr_rq3; +EDEB_EN (8 ,"pr=%p, nr_of_wqes=%d" , pr, nr_of_wqes); +if (nr_of_wqes ==0 ) +return -EINVAL ; + qp = pr->qp; +for (i =0 ; i < nr_of_wqes; i++) { +int index = pr->skb_rq3_index++; +struct sk_buff *skb =dev_alloc_skb (EHEA_MAX_PACKET_SIZE + +NET_IP_ALIGN ); + +if (!skb) { + EDEB_ERR(4, "No memory for skb. Only %d rwqefilled.",
drivers/net/ehea/ehea_main.c +10
-0+ i); + ret = -ENOMEM ; +break ; + } +skb_reserve (skb,NET_IP_ALIGN ); + + rwqe =ehea_get_next_rwqe (qp,3 ); + pr->skb_rq3_index %= skb_arr_rq3_len; + skb_arr_rq3[index] = skb; + rwqe->wr_id = EHEA_BMASK_SET(EHEA_WR_ID_TYPE,
EHEA_RWQE3_TYPE)drivers/net/ehea/ehea_main.c +14
-0+ | EHEA_BMASK_SET(EHEA_WR_ID_INDEX, index); + rwqe->sg_list[0 ].l_key =ehea_get_recv_lkey (pr); + rwqe->sg_list[0 ].vaddr =get_rwqe_addr ((u64 )skb->data); + rwqe->sg_list[0 ].len =EHEA_MAX_PACKET_SIZE ; + rwqe->data_segments =1 ; + } + +/* Ring doorbell */ +iosync (); +ehea_update_rq3a (qp, i); +EDEB_EX (8 ,"" ); +return ret; +} +
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 283
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+ +static inline int ehea_refill_rq3 (struct ehea_port_res *pr,int nr_of_wqes) +{ +return ehea_refill_rq3_def (pr, nr_of_wqes); +}ehea_refill_rq3[123] appears to be 1:1 wrappers around ehea_refill_rq3[123]_def. Any idea behind them?
introduced for near future features
Quoted 5 lines
drivers/net/ehea/ehea_main.c line 1036
Quoted 2 lines
drivers/net/ehea/ehea_main.c +2
-0+ init_attr = (struct ehea_qp_init_attr *) +kzalloc (sizeof (struct ehea_qp_init_attr ),GFP_KERNEL );Useless cast.
removed
Quoted 4 lines
drivers/net/ehea/ehea_main.c
Quoted 2 lines
drivers/net/ehea/ehea_main.c +2
-0+ pr->skb_arr_sq = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 ));Useless cast
removed
Quoted 7 lines
Quoted 6 lines
drivers/net/ehea/ehea_main.c +4
-0+ pr->skb_arr_rq1 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); + pr->skb_arr_rq2 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 ));
Quoted 9 lines
drivers/net/ehea/ehea_main.c
Quoted 6 lines
drivers/net/ehea/ehea_main.c +5
-0+ pr->skb_arr_rq3 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +static int ehea_ioctl (struct net_device *dev,struct ifreq *ifr,int cmd) +{ +EDEB_ERR (4 ,"ioctl not supported: dev=%s cmd=%d" , dev->name, cmd);Then copy NULL into ->do_ioctl!
done
Quoted 15 lines
drivers/net/ehea/ehea_main.c line 1404
Quoted 13 lines
drivers/net/ehea/ehea_main.c +12
-0+return -EOPNOTSUPP ; +} + ehea_port_cb_0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!ehea_port_cb_0) { +EDEB_ERR (4 ,"No memory for ehea_port control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + +memcpy ((u8 *)(&(ehea_port_cb_0->port_mac_addr)), + (u8 *)&(mac_addr->sa_data[0 ]),6 );No casts on memcpy arguments.
done
Quoted 12 lines
drivers/net/ehea/ehea_main.c line 1658
Quoted 9 lines
drivers/net/ehea/ehea_main.c +7
-0+memcpy ((u8 *)&ehea_mcl_entry->macaddr, mc_mac_addr,ETH_ALEN ); +static inline void ehea_xmit2 (struct sk_buff *skb, +struct net_device *dev,struct ehea_swqe *swqe, +u32 lkey) +{ +int nfrags; +unsigned short skb_protocol = skb->protocol;Useless variable. And it should be
__be16, FYI.
changed
Quoted 7 lines
drivers/net/ehea/ehea_main.c line 1662
Quoted 4 lines
drivers/net/ehea/ehea_main.c +4
-0+ nfrags =skb_shinfo (skb)->nr_frags; +EDEB_EN (7 ,"skb->nfrags=%d (0x%X)" , nfrags, nfrags); + +if (skb_protocol ==ETH_P_IP ) {ITYM,
htons(ETH_P_IP).
good point, thx
Quoted 10 lines
drivers/net/ehea/ehea_main.c line 1706
Quoted 8 lines
drivers/net/ehea/ehea_main.c +8
-0+static inline void ehea_xmit3 (struct sk_buff *skb, +struct net_device *dev,struct ehea_swqe *swqe) +{ +int i; +skb_frag_t *frag; +int nfrags =skb_shinfo (skb)->nr_frags; +u8 *imm_data = &swqe->u.immdata_nodesc.immediate_data[0 ]; +u64 skb_protocol = skb->protocol;Useless var.
removed
Quoted 7 lines
drivers/net/ehea/ehea_main.c line 1709
Quoted 4 lines
drivers/net/ehea/ehea_main.c +3
-0+ +EDEB_EN (7 ,"" ); +if (likely (skb_protocol ==ETH_P_IP )) {htons(ETH_P_IP)
Hi Jan-Bernd,
Comments below the code they refer to.
drivers/net/ehea/ehea_main.c line 2
Quoted 10 lines · Jan-Bernd Themann
Signed-off-by Jan-Bernd Themann <[email protected]>drivers/net/ehea/ehea_main.c | 2738 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2738 insertions(+)drivers/net/ehea/ehea_main.c +2
-0@@ -0,0 +1,2738 @@ +/* +* linux/drivers/net/ehea/ehea_main.c
Putting the file name in the file is fairly redundant IMHO.
drivers/net/ehea/ehea_main.c line 4
Quoted 1 line
drivers/net/ehea/ehea_main.c +1
-0+* eHEA ethernet device driver for IBM eServer System p
What's the actual hardware that this is for? System p covers a whole range of machines, do they really all support this driver?
Quoted 38 lines
drivers/net/ehea/ehea_main.c +38
-0+* (C) Copyright IBM Corp. 2006 +* +* Authors: +* Christoph Raisch <[email protected]> +* Jan-Bernd Themann <[email protected]> +* Heiko-Joerg Schick <[email protected]> +* Thomas Klein <[email protected]> +* +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEB_PREFIX "main" + +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/if.h> +#include <linux/list.h> +#include <net/ip.h> + +#include "ehea.h" +#include "ehea_qmr.h" +#include "ehea_phyp.h" +
drivers/net/ehea/ehea_main.c line 53
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ +MODULE_LICENSE ("GPL" ); +MODULE_AUTHOR ("Christoph Raisch <[email protected]>" ); +MODULE_DESCRIPTION ("IBM eServer HEA Driver" ); +MODULE_VERSION (EHEA_DRIVER_VERSION ); + +static int __devinit ehea_probe (struct ibmebus_dev *dev, +const struct of_device_id *id); +static int __devexit ehea_remove(struct ibmebus_dev *dev); +static int ehea_sense_port_attr (struct ehea_adapter *adapter,int portnum);
I haven't looked closely, but can you rearrange the functions so you don't need these forward declarations?
drivers/net/ehea/ehea_main.c line 61
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+int ehea_trace_level =5 ; + +static struct net_device_stats *ehea_get_stats (struct net_device *dev) +{ +int i; +u64 hret =H_HARDWARE ;
You unconditionally assign to hret below.
drivers/net/ehea/ehea_main.c line 62
Quoted 1 line
drivers/net/ehea/ehea_main.c +1
-0+u64 rx_packets =0 ;
Why not just update stats->rx_packets directly?
drivers/net/ehea/ehea_main.c line 60
Quoted 2 lines
drivers/net/ehea/ehea_main.c +2
-0+struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_adapter *adapter = port->adapter;
I don't think you need adapter, you only use it in one place, just access it through port->adapter->handle (below).
drivers/net/ehea/ehea_main.c line 73
Quoted 9 lines
drivers/net/ehea/ehea_main.c +9
-0+struct hcp_query_ehea_port_cb_2 *cb2 =NULL ; +struct net_device_stats *stats = &port->stats; + +EDEB_EN (7 ,"net_device=%p" , dev); + + cb2 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb2) { +EDEB_ERR (4 ,"No memory for cb2" ); + goto get_stat_exit;
You leak cb2 here.
Quoted 26 lines
drivers/net/ehea/ehea_main.c +26
-0+ } + + hret =ehea_h_query_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB2 , +H_PORT_CB2_ALL , + cb2); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_port failed for cb2" ); + goto get_stat_exit; + } + +EDEB_DMP (7 , (u8 *)cb2, +sizeof (struct hcp_query_ehea_port_cb_2 ),"After HCALL" ); + +for (i =0 ; i < port->num_def_qps; i++) { + rx_packets += port->port_res[i].rx_packets; + } + + stats->tx_packets = cb2->txucp + cb2->txmcp + cb2->txbcp; + stats->multicast = cb2->rxmcp; + stats->rx_errors = cb2->rxuerr; + stats->rx_bytes = cb2->rxo; + stats->tx_bytes = cb2->txo; + stats->rx_packets = rx_packets;
drivers/net/ehea/ehea_main.c line 109
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ +get_stat_exit: +EDEB_EX (7 ,"" ); +return stats; +} + +static inline u32 ehea_get_send_lkey (struct ehea_port_res *pr) +{ +return pr->send_mr.lkey; +}
Get rid of this, it's only used once.
drivers/net/ehea/ehea_main.c line 114
Quoted 4 lines
drivers/net/ehea/ehea_main.c +4
-0+static inline u32 ehea_get_recv_lkey (struct ehea_port_res *pr) +{ +return pr->recv_mr.lkey; +}
And this one only twice? Is it really useful?
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+ +#define EHEA_OD_ADDR (address, segment) (((address) & (PAGE_SIZE - 1)) \ + | ((segment) << 12)); + +static inline u64 get_swqe_addr (u64 tmp_addr,int addr_seg)
drivers/net/ehea/ehea_main.c line 129
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+{ +u64 addr; + addr = tmp_addr; +return addr; +} + +static inline u64 get_rwqe_addr (u64 tmp_addr) +{ +return tmp_addr; +}
This two functions seem useless or wrong.
drivers/net/ehea/ehea_main.c line 143
Quoted 12 lines
drivers/net/ehea/ehea_main.c +12
-0+static inline int ehea_refill_rq1 (struct ehea_port_res *port_res,int arr_index, +int nr_of_wqes) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +int skb_arr_rq1_len = port_res->skb_arr_rq1_len; +struct sk_buff **skb_arr_rq1 = port_res->skb_arr_rq1; +EDEB_EN (7 ,"port_res=%p, arr_index=%d, nr_of_wqes=%d, arr_rq1_len=%d" , + port_res, arr_index, nr_of_wqes, skb_arr_rq1_len); + + qp = port_res->qp;
You don't need the qp variable, just use port_res->qp below.
drivers/net/ehea/ehea_main.c line 138
Quoted 2 lines
drivers/net/ehea/ehea_main.c +2
-0+if (unlikely (nr_of_wqes ==0 )) +return -EINVAL ;
Newline needed here.
drivers/net/ehea/ehea_main.c line 148
Quoted 3 lines
drivers/net/ehea/ehea_main.c +3
-0+for (i =0 ; i < nr_of_wqes; i++) { +int index = ((skb_arr_rq1_len + arr_index) - i) + % skb_arr_rq1_len;
The wrapped line should be indented further to the right.
Quoted 76 lines
drivers/net/ehea/ehea_main.c +76
-0+if (!skb_arr_rq1[index]) { + skb_arr_rq1[index] =dev_alloc_skb (EHEA_LL_PKT_SIZE ); + +if (!skb_arr_rq1[index]) { +EDEB_ERR (4 ,"No mem for skb/%d wqes filled" , i); + ret = -ENOMEM ; +break ; + } + } + } +/* Ring doorbell */ +ehea_update_rq1a (qp, nr_of_wqes); +EDEB_EX (7 ,"" ); +return ret; +} + +static int ehea_init_fill_rq1 (struct ehea_port_res *port_res,int nr_rq1a) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +EDEB_EN (7 ,"port_res=%p, nr_rq1a=%d" , port_res, nr_rq1a); + qp = port_res->qp; + +for (i =0 ; i < port_res->skb_arr_rq1_len; i++) { + port_res->skb_arr_rq1[i] =dev_alloc_skb (EHEA_LL_PKT_SIZE ); +if (!port_res->skb_arr_rq1[i]) { +EDEB_ERR (4 ,"dev_alloc_skb failed. Only %d skb filled." , + i); + ret = -ENOMEM ; +break ; + } + } +/* Ring doorbell */ +ehea_update_rq1a (qp, nr_rq1a); +EDEB_EX (7 ,"" ); +return ret; +} + +static inline int ehea_refill_rq2_def (struct ehea_port_res *pr,int nr_of_wqes) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +struct ehea_rwqe *rwqe; +int skb_arr_rq2_len = pr->skb_arr_rq2_len; +struct sk_buff **skb_arr_rq2 = pr->skb_arr_rq2; + +EDEB_EN (8 ,"pr=%p, nr_of_wqes=%d" , pr, nr_of_wqes); +if (nr_of_wqes ==0 ) +return -EINVAL ; + qp = pr->qp; +for (i =0 ; i < nr_of_wqes; i++) { +int index = pr->skb_rq2_index++; +struct sk_buff *skb =dev_alloc_skb (EHEA_RQ2_PKT_SIZE + +NET_IP_ALIGN ); + +if (!skb) { +EDEB_ERR (4 ,"dev_alloc_skb nr %d failed" , i); + ret = -ENOMEM ; +break ; + } +skb_reserve (skb,NET_IP_ALIGN ); + pr->skb_rq2_index %= skb_arr_rq2_len; + skb_arr_rq2[index] = skb; + rwqe =ehea_get_next_rwqe (qp,2 ); + rwqe->wr_id =EHEA_BMASK_SET (EHEA_WR_ID_TYPE ,EHEA_RWQE2_TYPE ) + |EHEA_BMASK_SET (EHEA_WR_ID_INDEX , index); + rwqe->sg_list[0 ].l_key =ehea_get_recv_lkey (pr); + rwqe->sg_list[0 ].vaddr =get_rwqe_addr ((u64 )skb->data); + rwqe->sg_list[0 ].len =EHEA_RQ2_PKT_SIZE ; + rwqe->data_segments =1 ; + } + +/* Ring doorbell */ +iosync ();
drivers/net/ehea/ehea_main.c line 234
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ehea_update_rq2a (qp, i); +EDEB_EX (8 ,"" ); +return ret; +} + + +static inline int ehea_refill_rq2 (struct ehea_port_res *pr,int nr_of_wqes) +{ +return ehea_refill_rq2_def (pr, nr_of_wqes); +}
Why do you need this function?
Quoted 32 lines
drivers/net/ehea/ehea_main.c +32
-0+static inline int ehea_refill_rq3_def (struct ehea_port_res *pr,int nr_of_wqes) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +struct ehea_rwqe *rwqe; +int skb_arr_rq3_len = pr->skb_arr_rq3_len; +struct sk_buff **skb_arr_rq3 = pr->skb_arr_rq3; +EDEB_EN (8 ,"pr=%p, nr_of_wqes=%d" , pr, nr_of_wqes); +if (nr_of_wqes ==0 ) +return -EINVAL ; + qp = pr->qp; +for (i =0 ; i < nr_of_wqes; i++) { +int index = pr->skb_rq3_index++; +struct sk_buff *skb =dev_alloc_skb (EHEA_MAX_PACKET_SIZE + +NET_IP_ALIGN ); + +if (!skb) { +EDEB_ERR (4 ,"No memory for skb. Only %d rwqe filled." , + i); + ret = -ENOMEM ; +break ; + } +skb_reserve (skb,NET_IP_ALIGN ); + + rwqe =ehea_get_next_rwqe (qp,3 ); + pr->skb_rq3_index %= skb_arr_rq3_len; + skb_arr_rq3[index] = skb; + rwqe->wr_id =EHEA_BMASK_SET (EHEA_WR_ID_TYPE ,EHEA_RWQE3_TYPE ) + |EHEA_BMASK_SET (EHEA_WR_ID_INDEX , index); + rwqe->sg_list[0 ].l_key =ehea_get_recv_lkey (pr); + rwqe->sg_list[0 ].vaddr =get_rwqe_addr ((u64 )skb->data);
drivers/net/ehea/ehea_main.c line 277
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ rwqe->sg_list[0 ].len =EHEA_MAX_PACKET_SIZE ; + rwqe->data_segments =1 ; + } + +/* Ring doorbell */ +iosync (); +ehea_update_rq3a (qp, i); +EDEB_EX (8 ,"" ); +return ret; +}
You "Ring doorbell" in four places, but only in two do you do iosync(), that might be ok, but it looks suspicious. Also, what is the iosync trying to achieve?
ehea_refill_rq3_def() and ehea_refill_rq2_def() look quite similar, can they be combined?
Quoted 38 lines
drivers/net/ehea/ehea_main.c +38
-0+ + +static inline int ehea_refill_rq3 (struct ehea_port_res *pr,int nr_of_wqes) +{ +return ehea_refill_rq3_def (pr, nr_of_wqes); +} + + +static inline int ehea_check_cqe (struct ehea_cqe *cqe,int *rq_num) +{ + *rq_num = (cqe->type &EHEA_CQE_TYPE_RQ ) >>5 ; +EDEB (7 ,"RQ used=%d, status=%X" , *rq_num, cqe->status); +if ((cqe->status &EHEA_CQE_STAT_ERR_MASK ) ==0 ) +return 0 ; +if (((cqe->status &EHEA_CQE_STAT_ERR_TCP ) !=0 ) + && (cqe->header_length ==0 )) +return 0 ; +else +printk ("WARNING: Packet discarded. Wrong TCP/UDP chksum" +"and header_length != 0. cqe->status=%X" , cqe->status); + +return -EINVAL ; +} + +static inline void ehea_fill_skb_ll (struct net_device *dev, +struct sk_buff *skb,struct ehea_cqe *cqe) +{ +int length = cqe->num_bytes_transfered -4 ;/*remove CRC */ +EDEB_EN (7 ,"dev=%p, skb=%p, cqe=%p" , dev, skb, cqe); +memcpy (skb->data, ((char *)cqe) +64 , length); +skb_put (skb, length); + skb->dev = dev; + skb->ip_summed =CHECKSUM_UNNECESSARY ; + skb->protocol =eth_type_trans (skb, dev); +EDEB_EX (7 ,"" ); +} + +static inline void ehea_fill_skb(struct net_device *dev,
drivers/net/ehea/ehea_main.c line 325
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ struct sk_buff *skb, struct ehea_cqe *cqe) +{ + int length = cqe->num_bytes_transfered - 4; /*remove CRC */ +EDEB_EN (7 ,"dev=%p, skb=%p, cqe=%p" , dev, skb, cqe); +skb_put (skb, length); + skb->dev = dev; + skb->ip_summed =CHECKSUM_UNNECESSARY ; + skb->protocol =eth_type_trans (skb, dev); +EDEB_EX (7 ,"" ); +}
What's the difference between the above two functions?
drivers/net/ehea/ehea_main.c line 328
Quoted 1 line
drivers/net/ehea/ehea_main.c +1
-0+#define EHEA_MAX_RWQE 1000
Should probably be in a header.
Quoted 182 lines
drivers/net/ehea/ehea_main.c +182
-0+static int ehea_poll (struct net_device *dev,int *budget) +{ +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_port_res *port_res = &port->port_res[0 ]; +struct ehea_cqe *cqe; +struct ehea_qp *qp = port_res->qp; +int wqe_index =0 ; +int last_wqe_index =0 ; +int x =0 ; +int processed =0 ; +int processed_RQ1 =0 ; +int processed_RQ2 =0 ; +int processed_RQ3 =0 ; +int rq; +int intreq; +struct sk_buff **skb_arr_rq1 = port_res->skb_arr_rq1; +struct sk_buff **skb_arr_rq2 = port_res->skb_arr_rq2; +struct sk_buff **skb_arr_rq3 = port_res->skb_arr_rq3; +int skb_arr_rq1_len = port_res->skb_arr_rq1_len; +int my_quota =min (*budget, dev->quota); + +EDEB_EN (7 ,"dev=%p, port_res=%p, budget=%d, quota=%d, qp_nr=%x" , + dev, port_res, *budget, dev->quota, + port_res->qp->init_attr.qp_nr); + my_quota =min (my_quota,EHEA_MAX_RWQE ); + +/* rq0 is low latency RQ */ + cqe =ehea_poll_rq1 (qp, &wqe_index); +while ((my_quota >0 ) && cqe) { +ehea_inc_rq1 (qp); + processed_RQ1++; + processed++; + my_quota--; + +EDEB_DMP (6 , (u8 *)cqe,4 *16 ,"CQE" ); + last_wqe_index = wqe_index; +rmb (); +if (!ehea_check_cqe (cqe, &rq)) { +struct sk_buff *skb; +if (rq ==1 ) {/* LL RQ1 */ +void *pref; + + x = (wqe_index +1 ) % skb_arr_rq1_len; + pref = (void *)skb_arr_rq1[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (wqe_index +1 ) % skb_arr_rq1_len; + pref = (void *)(skb_arr_rq1[x]->data); +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + skb = skb_arr_rq1[wqe_index]; +if (unlikely (!skb)) { +EDEB_ERR (4 ,"LL SBK=NULL, wqe_index=%d" , + wqe_index); + skb =dev_alloc_skb (EHEA_LL_PKT_SIZE ); +if (!skb) +panic ("Alloc SKB failed" ); + } + skb_arr_rq1[wqe_index] =NULL ; +ehea_fill_skb_ll (dev, skb, cqe); + }else if (rq ==2 ) {/* RQ2 */ +void *pref; +int skb_index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); + x = (skb_index +1 ) % port_res->skb_arr_rq2_len; + pref = (void *)skb_arr_rq2[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (skb_index +1 ) % port_res->skb_arr_rq2_len; + pref = (void *)(skb_arr_rq2[x]->data); + +prefetch (pref); +prefetch (pref +EHEA_CACHE_LINE ); +prefetch (pref +EHEA_CACHE_LINE *2 ); +prefetch (pref +EHEA_CACHE_LINE *3 ); + skb = skb_arr_rq2[skb_index]; + +if (unlikely (!skb)) { +EDEB_ERR (4 ,"rq2: SKB=NULL, index=%d" , + skb_index); +break ; + } + skb_arr_rq2[skb_index] =NULL ; +ehea_fill_skb (dev, skb, cqe); + processed_RQ2++; + }else { +void *pref; +int skb_index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); + x = (skb_index +1 ) % port_res->skb_arr_rq3_len; + pref = (void *)skb_arr_rq3[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (skb_index +1 ) % port_res->skb_arr_rq3_len; + pref = (void *)(skb_arr_rq3[x]->data); +prefetch (pref); +prefetch (pref +EHEA_CACHE_LINE ); +prefetch (pref +EHEA_CACHE_LINE *2 ); +prefetch (pref +EHEA_CACHE_LINE *3 ); + + skb = skb_arr_rq3[skb_index]; +if (unlikely (!skb)) { +EDEB_ERR (4 ,"rq3: SKB=NULL, index=%d" , + skb_index); +break ; + } + skb_arr_rq3[skb_index] =NULL ; +ehea_fill_skb (dev, skb, cqe); + processed_RQ3++; + } + +EDEB (6 ,"About to pass SKB: dev=%p\n" +"skb=%p skb->data=%p skb->len=%d" +" skb->data_len=0x%x nr_frags=%d" , + dev, + skb, + skb->data, + skb->len, + skb->data_len,skb_shinfo (skb)->nr_frags); +if (cqe->status &EHEA_CQE_VLAN_TAG_XTRACT ) { +EDEB (7 ,"VLAN TAG extracted: %4x, vgrp=%p" , + cqe->vlan_tag, port->vgrp); +EDEB (7 ,"vlan_devices[vlan_tag]=%p" , + port->vgrp->vlan_devices[cqe->vlan_tag]); +vlan_hwaccel_receive_skb (skb, port->vgrp, + cqe->vlan_tag); + }else { +EDEB (7 ,"netif_receive_skb" ); +netif_receive_skb (skb); + } +EDEB (7 ,"SKB passed (netif_receive(skb) called)" ); + + }else { +struct sk_buff *skb; + +EDEB_ERR (4 ,"cqe->status indicating error: CQE:" ); +EDEB_DMP (4 , (u8 *)cqe,4 *16 ,"" ); +if (rq ==2 ) { + processed_RQ2++; + skb = skb_arr_rq2[ +EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)]; + skb_arr_rq2[EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)] =NULL ; +dev_kfree_skb (skb); + } +if (rq ==3 ) { + processed_RQ3++; + skb = skb_arr_rq3[ +EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)]; + skb_arr_rq3[EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)] =NULL ; +dev_kfree_skb (skb); + } + } + cqe =ehea_poll_rq1 (qp, &wqe_index); + } + + dev->quota -= processed; + *budget -= processed; + + port_res->p_state.ehea_poll +=1 ; + + port_res->rx_packets += processed; + +ehea_refill_rq1 (port_res, last_wqe_index, processed_RQ1); +ehea_refill_rq2 (port_res, processed_RQ2); +ehea_refill_rq3 (port_res, processed_RQ3); + + intreq = ((port_res->p_state.ehea_poll &0xF ) ==0xF ); + +EDEB_EX (7 ,"processed=%d, *budget=%d, dev->quota=%d" , + processed, *budget, dev->quota); + +if (!cqe || intreq) { +netif_rx_complete (dev); +ehea_reset_cq_ep (port_res->recv_cq);
drivers/net/ehea/ehea_main.c line 521
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ehea_reset_cq_n1 (port_res->recv_cq); + cqe =ipz_qeit_get_valid (&qp->ipz_rqueue1); +EDEB (7 ,"CQE=%p, break ehea_poll while loop" , cqe); +if (!cqe || intreq) +return 0 ; +if (!netif_rx_reschedule (dev, my_quota)) +return 0 ; + } +return 1 ; +}
This function is _way_ too big.
Quoted 74 lines
drivers/net/ehea/ehea_main.c +74
-0+#define MAX_SENDCOMP_QUOTA 400 +void ehea_send_irq_tasklet (unsigned long data) +{ +int quota =MAX_SENDCOMP_QUOTA ; +int skb_index; +int cqe_counter =0 ; +int swqe_av =0 ; +unsigned long flags; +struct sk_buff *skb; +struct ehea_cqe *cqe; +struct ehea_port_res *port_res = (struct ehea_port_res *)data; +struct ehea_cq *send_cq = port_res->send_cq; +struct net_device *dev = port_res->port->netdev; + +EDEB_EN (7 ,"port_res=%p" , port_res); + +do { + cqe =ehea_poll_cq (send_cq); +if (!cqe) { +EDEB (7 ,"No further cqe found" ); +ehea_reset_cq_ep (send_cq); +ehea_reset_cq_n1 (send_cq); + cqe =ehea_poll_cq (send_cq); +if (!cqe) { +EDEB (7 ,"No cqe found after having" +" reset N1/EP\n" ); +break ; + } + } + cqe_counter++; +EDEB (7 ,"CQE found on Send-CQ:" ); +EDEB_DMP (7 , (u8 *)cqe,4 *16 ,"" ); +rmb (); +if (likely (EHEA_BMASK_GET (EHEA_WR_ID_TYPE , cqe->wr_id) + ==EHEA_SWQE2_TYPE )) {/* is swqe format 2 */ +int i; +int index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); +for (i =0 ; i <EHEA_BMASK_GET (EHEA_WR_ID_REFILL , + cqe->wr_id); i++) { + + skb_index = ((index - i + + port_res->skb_arr_sq_len) + % port_res->skb_arr_sq_len); + skb = port_res->skb_arr_sq[skb_index]; + port_res->skb_arr_sq[skb_index] =NULL ; + +if (unlikely (!skb)) { +EDEB_ERR (4 ,"s_irq_tasklet: SKB=NULL " +"WQ_ID=%lX, loop=%d, index=%d" , + cqe->wr_id, i, skb_index); +break ; + } +dev_kfree_skb (skb); + } + } + swqe_av +=EHEA_BMASK_GET (EHEA_WR_ID_REFILL , cqe->wr_id); + quota--; + }while (quota >0 ); + +ehea_update_feca (send_cq, cqe_counter); + +atomic_add (swqe_av, &port_res->swqe_avail); +EDEB (7 ,"port_res->swqe_avail=%d" , +atomic_read (&port_res->swqe_avail)); + +if (unlikely (netif_queue_stopped (dev))) { +spin_lock_irqsave (&port_res->netif_queue, flags); +if (unlikely ((atomic_read (&port_res->swqe_avail) + >=EHEA_SWQE_REFILL_TH ))) { +EDEB (7 ,"port %d swqes_avail >=10 (%d)," +"netif_wake_queue called" , + port_res->port->logical_port_id, +atomic_read (&port_res->swqe_avail));
drivers/net/ehea/ehea_main.c line 606
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+netif_wake_queue (port_res->port->netdev); + } +spin_unlock_irqrestore (&port_res->netif_queue, flags); + } + +if (unlikely (cqe)) +tasklet_hi_schedule (&port_res->send_comp_task); + +EDEB_EX (7 ,"" ); +}
This one's pretty big too.
Quoted 18 lines
drivers/net/ehea/ehea_main.c +18
-0+ +irqreturn_t ehea_send_irq_handler (int irq,void *param,struct pt_regs *regs) +{ +struct ehea_port_res *pr = (struct ehea_port_res *)param; +EDEB_EN (7 ,"irq=%d, param=%p, pt_regs=%p" , irq, param, regs); +tasklet_hi_schedule (&pr->send_comp_task); +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + +irqreturn_t ehea_recv_irq_handler (int irq,void *param,struct pt_regs * regs) +{ +struct ehea_port_res *pr = (struct ehea_port_res *)param; +struct ehea_port *port = pr->port; +EDEB_EN (7 ,"irq=%d, param=%p, pt_regs=%p" , irq, param, regs); +netif_rx_schedule (port->netdev); +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ;
drivers/net/ehea/ehea_main.c line 634
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+} + +irqreturn_t ehea_qp_aff_irq_handler (int irq,void *param,struct pt_regs * regs) +{ +struct ehea_port *port = (struct ehea_port *)param; +struct ehea_eqe *eqe; +u32 qp_token; + +EDEB_EN (7 ,"irq=%d, param=%p, pt_regs=%p" , irq, param, regs); + eqe = (struct ehea_eqe *)ehea_poll_eq (port->qp_eq);
Suspicious cast?
drivers/net/ehea/ehea_main.c line 639
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+EDEB (7 ,"eqe=%p" , eqe); +while (eqe) { +EDEB (7 ,"*eqe=%lx" , *(u64 *)eqe); + eqe = (struct ehea_eqe *)ehea_poll_eq (port->qp_eq); + qp_token =EHEA_BMASK_GET (EHEA_EQE_QP_TOKEN , eqe->entry);
You don't seem to use qp_token?
Quoted 14 lines
drivers/net/ehea/ehea_main.c +14
-0+EDEB (7 ,"next eqe=%p" , eqe); + } + +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + +static struct ehea_port *ehea_get_port (struct ehea_adapter *adapter, +int logical_port) +{ +int i; + +for (i =0 ; i < adapter->num_ports; i++) +if (adapter->port[i]->logical_port_id == logical_port)
drivers/net/ehea/ehea_main.c line 663
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+return adapter->port[i]; +return NULL ; +} + +static void ehea_parse_eqe (struct ehea_adapter *adapter,u64 eqe) +{ +int ret = -EINVAL ; +u8 ec =0 ; +u8 portnum =0 ; +struct ehea_port *port =NULL ;
You don't need to initialise these three variables.
Quoted 40 lines
drivers/net/ehea/ehea_main.c +40
-0+ +EDEB_EN (7 ,"eqe=%lx" , eqe); + + ec =EHEA_BMASK_GET (NEQE_EVENT_CODE , eqe); + +switch (ec) { +case EHEA_EC_PORTSTATE_CHG :/* port state change */ +EDEB (7 ,"Port state change" ); + portnum =EHEA_BMASK_GET (NEQE_PORTNUM , eqe); + port =ehea_get_port (adapter, portnum); + +if (!port) { +EDEB_ERR (4 ,"Unknown portnum %x" , portnum); +break ; + } + +if (EHEA_BMASK_GET (NEQE_PORT_UP , eqe)) { +if (!netif_carrier_ok (port->netdev)) { + ret =ehea_sense_port_attr (adapter, portnum); +if (ret) { +EDEB_ERR (4 ,"Failed resensing port" ); +break ; + } + +printk ("%s: Logical port up: %dMbps %s Duplex" , + port->netdev->name, + port->port_speed, + port->full_duplex == +1 ?"Full" :"Half" ); + +netif_carrier_on (port->netdev); +netif_wake_queue (port->netdev); + } + }else +if (netif_carrier_ok (port->netdev)) { +printk ("%s: Logical port down" , + port->netdev->name); +netif_carrier_off (port->netdev); +netif_stop_queue (port->netdev); + }
drivers/net/ehea/ehea_main.c line 713
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ +if (EHEA_BMASK_GET (NEQE_EXTSWITCH_PORT_UP , eqe)) +printk ("%s: Physical port up" , port->netdev->name); +else +printk ("%s: Physical port down" , port->netdev->name); + +if (EHEA_BMASK_GET (NEQE_EXTSWITCH_PRIMARY , eqe)) +printk ("Externel switch port is primary port" ); +else +printk ("Externel switch port is backup port" );
These printks should probably use KERN_DEBUG, or netif_msg_foo().
drivers/net/ehea/ehea_main.c line 725
Quoted 11 lines
drivers/net/ehea/ehea_main.c +11
-0+break ; +case EHEA_EC_ADAPTER_MALFUNC :/* adapter malfunction */ +EDEB_ERR (4 ,"Adapter malfunction" ); +break ; +case EHEA_EC_PORT_MALFUNC :/* port malfunction */ +EDEB_ERR (4 ,"Port malfunction" ); +/* TODO Determine the port structure of the malfunctioning port +* netif_carrier_off(port->netdev); +* netif_stop_queue(port->netdev); +*/ +break ;
The two malfunction states could probably use a printk(KERN_WARNING .. ) for now.
Quoted 14 lines
drivers/net/ehea/ehea_main.c +14
-0+default : +EDEB_ERR (4 ,"Unknown event code %x" , ec); +break ; + } + +EDEB_EX (7 ,"" ); +} + +void ehea_neq_tasklet (unsigned long data) +{ +struct ehea_adapter *adapter = (struct ehea_adapter *)data; +struct ehea_eqe *eqe; +u64 event_mask; +
drivers/net/ehea/ehea_main.c line 749
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+EDEB_EN (7 ,"" ); + eqe = (struct ehea_eqe *)ehea_poll_eq (adapter->neq); +EDEB (7 ,"eqe=%p" , eqe); + +while (eqe) { +EDEB (7 ,"*eqe=%lx" , eqe->entry); +ehea_parse_eqe (adapter, eqe->entry); + eqe = (struct ehea_eqe *)ehea_poll_eq (adapter->neq); +EDEB (7 ,"next eqe=%p" , eqe); + }
I think I've seen this code before.
Quoted 33 lines
drivers/net/ehea/ehea_main.c +33
-0+ + event_mask =EHEA_BMASK_SET (NELR_PORTSTATE_CHG ,1 ) + |EHEA_BMASK_SET (NELR_ADAPTER_MALFUNC ,1 ) + |EHEA_BMASK_SET (NELR_PORT_MALFUNC ,1 ); + +ehea_h_reset_events (adapter->handle, + adapter->neq->ipz_eq_handle, event_mask); +EDEB_EX (7 ,"" ); +} + +irqreturn_t ehea_interrupt_neq (int irq,void *param,struct pt_regs *regs) +{ +struct ehea_adapter *adapter = (struct ehea_adapter *)param; +EDEB_EN (7 ,"dev_id=%p" , adapter); +tasklet_hi_schedule (&adapter->neq_tasklet); +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + + + +static void ehea_fill_port_res (struct ehea_port_res *pr) +{ +struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr; + +/* RQ 1 */ +ehea_init_fill_rq1 (pr, init_attr->act_nr_rwqes_rq1 + - init_attr->act_nr_rwqes_rq2 + - init_attr->act_nr_rwqes_rq3 -1 ); + +/* RQ 2 */ +ehea_refill_rq2 (pr, init_attr->act_nr_rwqes_rq2); +
drivers/net/ehea/ehea_main.c line 792
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+/* RQ 3 */ +ehea_refill_rq3 (pr, init_attr->act_nr_rwqes_rq3); +} + +static int ehea_reg_interrupts (struct net_device *dev) +{ +int ret = -EINVAL ; +int i; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_port_res *pr = &port->port_res[0 ];
Don't need to initalise pr.
Quoted 42 lines
drivers/net/ehea/ehea_main.c +42
-0+ +EDEB_EN (7 ,"" ); +for (i =0 ; i < port->num_def_qps; i++) { + pr = &port->port_res[i]; +snprintf (pr->int_recv_name,EHEA_IRQ_NAME_SIZE -1 + ,"%s-recv%d" , dev->name, i); + ret =ibmebus_request_irq (NULL , + pr->recv_eq->attr.ist1, + ehea_recv_irq_handler, +SA_INTERRUPT , pr->int_recv_name, pr); +if (ret) { +EDEB_ERR (4 ,"Failed registering irq for ehea_recv_int:" +"port_res_nr:%d, ist=%X" , i, + pr->recv_eq->attr.ist1); + goto failure; + } +EDEB (7 ,"irq_handle 0x%X for function ehea_recv_int %d " +" registered" , pr->recv_eq->attr.ist1, i); + } + +snprintf (port->int_aff_name,EHEA_IRQ_NAME_SIZE -1 , +"%s-aff" , dev->name); + ret =ibmebus_request_irq (NULL , + port->qp_eq->attr.ist1, + ehea_qp_aff_irq_handler, +SA_INTERRUPT , port->int_aff_name, port); +if (ret) { +EDEB_ERR (4 ,"Failed registering irq for qp_aff_irq_handler:" +" ist=%X" , port->qp_eq->attr.ist1); + goto failure; + } +EDEB (7 ,"irq_handle 0x%X for function qp_aff_irq_handler registered" , + port->qp_eq->attr.ist1); + +for (i =0 ; i < port->num_def_qps + port->num_tx_qps; i++) { + pr = &port->port_res[i]; +snprintf (pr->int_send_name,EHEA_IRQ_NAME_SIZE -1 , +"%s-send%d" , dev->name, i); + ret = ibmebus_request_irq(NULL, + pr->send_eq->attr.ist1, + ehea_send_irq_handler, + SA_INTERRUPT, pr->int_send_name,
drivers/net/ehea/ehea_main.c line 844
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ pr); +if (ret) { +EDEB_ERR (4 ,"Registering irq for ehea_send failed" +" port_res_nr:%d, ist=%X" , i, + pr->send_eq->attr.ist1); + goto failure; + } +EDEB (7 ,"irq_handle 0x%X for function ehea_send_int %d" +" registered" , pr->send_eq->attr.ist1, i); + }
You seem to be iterating over some of the port_res structs twice, is that what you intended?
drivers/net/ehea/ehea_main.c line 847
Quoted 3 lines
drivers/net/ehea/ehea_main.c +3
-0+failure: +EDEB_EX (7 ,"ret=%d" , ret); +return ret;
No further cleanup required? Should you be calling ehea_free_interrupts?
Quoted 84 lines
drivers/net/ehea/ehea_main.c +84
-0+} + +static void ehea_free_interrupts (struct net_device *dev) +{ +struct ehea_port *port = (struct ehea_port *)dev->priv; +int i; + +EDEB_EN (7 ,"" ); +/* send */ +for (i =0 ; i < port->num_def_qps + port->num_tx_qps; i++) { +ibmebus_free_irq (NULL , port->port_res[i].send_eq->attr.ist1, + &port->port_res[i]); +EDEB (7 ,"free send interrupt for res %d with handle 0x%X" , + i, port->port_res[i].send_eq->attr.ist1); + } + +/* receive */ +for (i =0 ; i < port->num_def_qps; i++) { +ibmebus_free_irq (NULL , port->port_res[i].recv_eq->attr.ist1, + &port->port_res[i]); +EDEB (7 ,"free recv intterupt for res %d with handle 0x%X" , + i, port->port_res[i].recv_eq->attr.ist1); + } +/* associated events */ +ibmebus_free_irq (NULL , port->qp_eq->attr.ist1, port); +EDEB (7 ,"associated event interrupt for handle 0x%X freed" , + port->qp_eq->attr.ist1); +EDEB_EX (7 ,"" ); +} + +static int ehea_configure_port (struct ehea_port *port) +{ +int ret = -EINVAL ; +u64 hret =H_HARDWARE ; +struct hcp_query_ehea_port_cb_0 *ehea_port_cb_0 =NULL ; +u64 mask =0 ; +int i; + +EDEB_EN (7 ,"" ); + + ehea_port_cb_0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!ehea_port_cb_0) { +EDEB_ERR (4 ,"No memory for ehea_port control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + + ehea_port_cb_0->port_rc =EHEA_BMASK_SET (PXLY_RC_VALID ,1 ) + |EHEA_BMASK_SET (PXLY_RC_IP_CHKSUM ,1 ) + |EHEA_BMASK_SET (PXLY_RC_TCP_UDP_CHKSUM ,1 ) + |EHEA_BMASK_SET (PXLY_RC_VLAN_XTRACT ,1 ) + |EHEA_BMASK_SET (PXLY_RC_VLAN_TAG_FILTER , +PXLY_RC_VLAN_FILTER ) + |EHEA_BMASK_SET (PXLY_RC_JUMBO_FRAME ,1 ); + +for (i =0 ; i < port->num_def_qps; i++) { + ehea_port_cb_0->default_qpn_array[i] = + port->port_res[i].qp->init_attr.qp_nr; + +EDEB (7 ,"default_qpn_array[%d]=%d" , + i, port->port_res[i].qp->init_attr.qp_nr); + } + +EDEB (7 ,"ehea_port_cb_0" ); +EDEB_DMP (7 , (u8 *)ehea_port_cb_0,sizeof (*ehea_port_cb_0),"" ); + + mask =EHEA_BMASK_SET (H_PORT_CB0_PRC ,1 ) + |EHEA_BMASK_SET (H_PORT_CB0_DEFQPNARRAY ,1 ); + + hret =ehea_h_modify_ehea_port (port->adapter->handle, + port->logical_port_id, +H_PORT_CB0 , + mask, + (void *)ehea_port_cb_0); + +if (hret !=H_SUCCESS ) { + goto modify_ehea_port_failed; + } + + ret =0 ; + +modify_ehea_port_failed: +kfree (ehea_port_cb_0);
drivers/net/ehea/ehea_main.c line 941
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ +kzalloc_failed: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + + +static int ehea_gen_smrs (struct ehea_port_res *pr) +{ +u64 hret =H_HARDWARE ;
No need to set hret. You do that a lot, int foo = 0; foo = bar();
Quoted 34 lines
drivers/net/ehea/ehea_main.c +34
-0+struct ehea_adapter *adapter = pr->port->adapter; +EDEB_EN (7 ,"ehea_port_res=%p" , pr); + hret =hipz_h_register_smr (adapter->handle, + adapter->mr.handle, + adapter->mr.vaddr, +EHEA_MR_ACC_CTRL , + adapter->pd, + &pr->send_mr); +if (hret !=H_SUCCESS ) + goto ehea_gen_smrs_err1; + + hret =hipz_h_register_smr (adapter->handle, + adapter->mr.handle, + adapter->mr.vaddr, +EHEA_MR_ACC_CTRL , + adapter->pd, + &pr->recv_mr); +if (hret !=H_SUCCESS ) + goto ehea_gen_smrs_err2; +EDEB_EX (7 ,"" ); +return 0 ; + +ehea_gen_smrs_err2: + hret =ehea_h_free_resource_mr (adapter->handle, pr->send_mr.handle); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Could not free SMR" ); +ehea_gen_smrs_err1: +return -EINVAL ; +} + +static void ehea_rem_smrs (struct ehea_port_res *pr) +{ +u64 hret =H_HARDWARE ; +struct ehea_adapter *adapter = pr->port->adapter;
drivers/net/ehea/ehea_main.c line 985
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+EDEB_EN (7 ,"ehea_port_res=%p" , pr); + hret =ehea_h_free_resource_mr (adapter->handle, pr->send_mr.handle); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Could not free send SMR for pr=%p" , pr); + + hret =ehea_h_free_resource_mr (adapter->handle, pr->recv_mr.handle); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Could not free receive SMR for pr=%p" , pr); +EDEB_EX (7 ,"" ); +}
It's a bit worrying that this routine can fail, but returns void, ie. it can't report failure to its caller. (but perhaps it's ok).
Quoted 122 lines
drivers/net/ehea/ehea_main.c +122
-0+ +static int ehea_init_port_res (struct ehea_port *port,struct ehea_port_res *pr, +struct port_res_cfg *pr_cfg,int queue_token) +{ +int ret = -EINVAL ; +int max_rq_entries =0 ; +enum ehea_eq_type eq_type =EHEA_EQ ; +struct ehea_qp_init_attr *init_attr; +struct ehea_adapter *adapter = port->adapter; + +EDEB_EN (7 ,"port=%p, pr=%p" , port, pr); + +memset (pr,0 ,sizeof (struct ehea_port_res )); + + pr->port = port; +spin_lock_init (&pr->send_lock); +spin_lock_init (&pr->recv_lock); +spin_lock_init (&pr->xmit_lock); +spin_lock_init (&pr->netif_queue); + + pr->recv_eq =ehea_create_eq (adapter, eq_type, +EHEA_MAX_ENTRIES_EQ ,0 ); +if (!pr->recv_eq) { +EDEB_ERR (4 ,"ehea_create_eq failed (recv_eq)" ); + goto ehea_init_port_res_err1; + } + pr->send_eq =ehea_create_eq (adapter, eq_type, +EHEA_MAX_ENTRIES_EQ ,0 ); +if (!pr->send_eq) { +EDEB_ERR (4 ,"ehea_create_eq failed (send_eq)" ); + goto ehea_init_port_res_err2; + } + + pr->recv_cq =ehea_create_cq (adapter, pr_cfg->max_entries_rcq, + pr->recv_eq->ipz_eq_handle, + port->logical_port_id); +if (!pr->recv_cq) { +EDEB_ERR (4 ,"ehea_create_cq failed (cq_recv)" ); + goto ehea_init_port_res_err3; + } + + pr->send_cq =ehea_create_cq (adapter, pr_cfg->max_entries_scq, + pr->send_eq->ipz_eq_handle, + port->logical_port_id); +if (!pr->send_cq) { +EDEB_ERR (4 ,"ehea_create_cq failed (cq_send)" ); + goto ehea_init_port_res_err4; + } + + init_attr = (struct ehea_qp_init_attr *) +kzalloc (sizeof (struct ehea_qp_init_attr ),GFP_KERNEL ); + +if (!init_attr) { +EDEB_ERR (4 ,"no mem for init_attr struct" ); + ret = -ENOMEM ; + goto ehea_init_port_res_err5; + } + + init_attr->low_lat_rq1 =1 ; + init_attr->signalingtype =1 ;/* generate CQE if specified in WQE */ + init_attr->rq_count =3 ; + init_attr->qp_token = queue_token; + + init_attr->max_nr_send_wqes = pr_cfg->max_entries_sq; + init_attr->max_nr_rwqes_rq1 = pr_cfg->max_entries_rq1; + init_attr->max_nr_rwqes_rq2 = pr_cfg->max_entries_rq2; + init_attr->max_nr_rwqes_rq3 = pr_cfg->max_entries_rq3; + + init_attr->wqe_size_enc_sq =EHEA_SG_SQ ; + init_attr->wqe_size_enc_rq1 =EHEA_SG_RQ1 ; + init_attr->wqe_size_enc_rq2 =EHEA_SG_RQ2 ; + init_attr->wqe_size_enc_rq3 =EHEA_SG_RQ3 ; + + init_attr->rq2_threshold =EHEA_RQ2_THRESHOLD ; + init_attr->rq3_threshold =EHEA_RQ3_THRESHOLD ; + init_attr->port_nr = port->logical_port_id; + init_attr->send_cq_handle = pr->send_cq->ipz_cq_handle; + init_attr->recv_cq_handle = pr->recv_cq->ipz_cq_handle; + init_attr->aff_eq_handle = port->qp_eq->ipz_eq_handle; + + pr->qp =ehea_create_qp (adapter, adapter->pd, init_attr); +if (!pr->qp) { +EDEB_ERR (4 ,"could not create queue pair" ); + goto ehea_init_port_res_err6; + } + +/* SQ */ + max_rq_entries = init_attr->act_nr_send_wqes; + pr->skb_arr_sq = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_sq) { +EDEB_ERR (4 ,"vmalloc for skb_arr_sq failed" ); + goto ehea_init_port_res_err7; + } +memset (pr->skb_arr_sq,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_sq_index =0 ; + pr->skb_arr_sq_len = max_rq_entries +1 ; + +/* RQ 1 */ + max_rq_entries = init_attr->act_nr_rwqes_rq1; + pr->skb_arr_rq1 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_rq1) { +EDEB_ERR (4 ,"vmalloc for skb_arr_rq1 failed" ); + goto ehea_init_port_res_err8; + } +memset (pr->skb_arr_rq1,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_arr_rq1_len = max_rq_entries +1 ; + +/* RQ 2 */ + max_rq_entries = init_attr->act_nr_rwqes_rq2; + pr->skb_arr_rq2 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_rq2) { +EDEB_ERR (4 ,"vmalloc for skb_arr_rq2 failed" ); + goto ehea_init_port_res_err9; + } +memset (pr->skb_arr_rq2,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_arr_rq2_len = max_rq_entries; + pr->skb_rq2_index =0 ; + +/* RQ 3 */
drivers/net/ehea/ehea_main.c line 1117
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ max_rq_entries = init_attr->act_nr_rwqes_rq3; + pr->skb_arr_rq3 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_rq3) { +EDEB_ERR (4 ,"vmalloc for skb_arr_rq3 failed" ); + goto ehea_init_port_res_err10; + } +memset (pr->skb_arr_rq3,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_arr_rq3_len = max_rq_entries; + pr->skb_rq3_index =0 ;
You shouldn't need the sk_buff** casts here. You probably should use kzalloc here, instead of vmalloc + memset. Depends on how big max_rq_entries can be.
Quoted 26 lines
drivers/net/ehea/ehea_main.c +26
-0+ +if (ehea_gen_smrs (pr) !=0 ) + goto ehea_init_port_res_err11; +tasklet_init (&pr->send_comp_task, ehea_send_irq_tasklet, + (unsigned long )pr); +atomic_set (&pr->swqe_avail,EHEA_MAX_ENTRIES_SQ -1 ); + +kfree (init_attr); + ret =0 ; + goto done; + +ehea_init_port_res_err11: +vfree (pr->skb_arr_rq3); +ehea_init_port_res_err10: +vfree (pr->skb_arr_rq2); +ehea_init_port_res_err9: +vfree (pr->skb_arr_rq1); +ehea_init_port_res_err8: +vfree (pr->skb_arr_sq); +ehea_init_port_res_err7: +ehea_destroy_qp (pr->qp); +ehea_init_port_res_err6: +kfree (init_attr); +ehea_init_port_res_err5: +ehea_destroy_cq (pr->send_cq); +ehea_init_port_res_err4:
drivers/net/ehea/ehea_main.c line 1153
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ehea_destroy_cq (pr->recv_cq); +ehea_init_port_res_err3: +ehea_destroy_eq (pr->send_eq); +ehea_init_port_res_err2: +ehea_destroy_eq (pr->recv_eq); +ehea_init_port_res_err1: +done: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +}
You can vfree/kfree a NULL pointer, so you can probably amalgamate some of these error cases if you initialise the pointers to NULL at the beginning.
Quoted 17 lines
drivers/net/ehea/ehea_main.c +17
-0+ +static int ehea_clean_port_res (struct ehea_port *port,struct ehea_port_res *pr) +{ +int i; +int ret = -EINVAL ; + +EDEB_EN (7 ,"Not completed yet..." ); + + ret =ehea_destroy_qp (pr->qp); +if (ret) +EDEB_ERR (4 ,"could not destroy queue pair" ); + + ret =ehea_destroy_cq (pr->send_cq); +if (ret) +EDEB_ERR (4 ,"could not destroy send_cq" ); + + ret =ehea_destroy_cq (pr->recv_cq);
drivers/net/ehea/ehea_main.c line 1180
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+if (ret) +EDEB_ERR (4 ,"could not destroy recv_cq" ); + + ret =ehea_destroy_eq (pr->send_eq); +if (ret) +EDEB_ERR (4 ,"could not destroy send_eq" ); + + ret =ehea_destroy_eq (pr->recv_eq); +if (ret) +EDEB_ERR (4 ,"could not destroy recv_eq" );
If these are leaking memory they're probably worth a printk.
Quoted 40 lines
drivers/net/ehea/ehea_main.c +39
-0+for (i =0 ; i < pr->skb_arr_rq1_len; i++) { +if (pr->skb_arr_rq1[i]) +dev_kfree_skb (pr->skb_arr_rq1[i]); + } + +for (i =0 ; i < pr->skb_arr_rq2_len; i++) +if (pr->skb_arr_rq2[i]) +dev_kfree_skb (pr->skb_arr_rq2[i]); + +for (i =0 ; i < pr->skb_arr_rq3_len; i++) +if (pr->skb_arr_rq3[i]) +dev_kfree_skb (pr->skb_arr_rq3[i]); + +for (i =0 ; i < pr->skb_arr_sq_len; i++) +if (pr->skb_arr_sq[i]) +dev_kfree_skb (pr->skb_arr_sq[i]); + +vfree (pr->skb_arr_sq); +vfree (pr->skb_arr_rq1); +vfree (pr->skb_arr_rq2); +vfree (pr->skb_arr_rq3); + +ehea_rem_smrs (pr); +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static inline void write_ip_start_end (struct ehea_swqe *swqe, +const struct sk_buff *skb) +{ + + swqe->ip_start = (u8)(((u64 )skb->nh.iph) - ((u64 )skb->data)); + swqe->ip_end = (u8)(swqe->ip_start + skb->nh.iph->ihl *4 -1 ); +} +static inline void write_tcp_offset_end (struct ehea_swqe *swqe, +const struct sk_buff *skb) +{ + swqe->tcp_offset = (u8)(swqe->ip_end +1 + offsetof(struct tcphdr , + check));
drivers/net/ehea/ehea_main.c line 1231
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ swqe->tcp_end = (u16 )skb->len -1 ; +} + +static inline void write_udp_offset_end (struct ehea_swqe *swqe, +const struct sk_buff *skb) +{ + swqe->tcp_offset = (u8)(swqe->ip_end +1 + offsetof(struct udphdr , + check)); + swqe->tcp_end = (u16 )skb->len -1 ; +}
These three need some explanation at best.
Quoted 134 lines
drivers/net/ehea/ehea_main.c +134
-0+ +static inline void write_swqe2_data (struct sk_buff *skb, +struct net_device *dev, +struct ehea_swqe *swqe, +u32 lkey) +{ +int skb_data_size, nfrags, headersize, i, sg1entry_contains_frag_data; +struct ehea_vsgentry *sg_list; +struct ehea_vsgentry *sg1entry; +struct ehea_vsgentry *sgentry; +u8 *imm_data; +u64 tmp_addr; +skb_frag_t *frag; +EDEB_EN (7 ,"" ); + + skb_data_size = skb->len - skb->data_len; + nfrags =skb_shinfo (skb)->nr_frags; + sg1entry = &swqe->u.immdata_desc.sg_entry; + sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list; + imm_data = &swqe->u.immdata_desc.immediate_data[0 ]; + swqe->descriptors =0 ; + sg1entry_contains_frag_data =0 ; + +if ((dev->features &NETIF_F_TSO ) &&skb_shinfo (skb)->gso_size) { +/* Packet is TCP with TSO enabled */ + swqe->tx_control |=EHEA_SWQE_TSO ; + swqe->mss =skb_shinfo (skb)->gso_size; +/* copy only eth/ip/tcp headers to immediate data and +* the rest of skb->data to sg1entry +*/ + headersize =ETH_HLEN + (skb->nh.iph->ihl *4 ) + + skb->h.th->doff *4 ; + skb_data_size = skb->len - skb->data_len; + +if (skb_data_size >= headersize) { +/* copy immediate data */ +memcpy (imm_data, skb->data, headersize); + swqe->immediate_data_length = headersize; + +if (skb_data_size > headersize) { +/* set sg1entry data */ + sg1entry->l_key = lkey; + sg1entry->len = skb_data_size - headersize; + + tmp_addr = (u64)(skb->data + headersize); + sg1entry->vaddr = +get_swqe_addr (tmp_addr,0 ); + + swqe->descriptors++; + } + }else +EDEB_ERR (4 ,"Cannot handle fragmented headers" ); + }else { +/* Packet is any nonTSO type +* +* Copy as much as possible skb->data to immediate data and +* the rest to sg1entry +*/ +if (skb_data_size >=SWQE2_MAX_IMM ) { +/* copy immediate data */ +memcpy (imm_data, skb->data,SWQE2_MAX_IMM ); + + swqe->immediate_data_length =SWQE2_MAX_IMM ; + +if (skb_data_size >SWQE2_MAX_IMM ) { +/* copy sg1entry data */ + sg1entry->l_key = lkey; + sg1entry->len = skb_data_size -SWQE2_MAX_IMM ; + tmp_addr = (u64)(skb->data +SWQE2_MAX_IMM ); + sg1entry->vaddr =get_swqe_addr (tmp_addr,0 ); + swqe->descriptors++; + } + }else { +memcpy (imm_data, skb->data, skb_data_size); + swqe->immediate_data_length = skb_data_size; + } + } + +/* write descriptors */ +if (nfrags >0 ) { +if (swqe->descriptors ==0 ) { +/* sg1entry not yet used */ + frag = &skb_shinfo (skb)->frags[0 ]; + +/* copy sg1entry data */ + sg1entry->l_key = lkey; + sg1entry->len = frag->size; + tmp_addr = (u64)(page_address (frag->page) + + frag->page_offset); + sg1entry->vaddr =get_swqe_addr (tmp_addr, +EHEA_MR_TX_DATA_PN ); + swqe->descriptors++; + sg1entry_contains_frag_data =1 ; + } + +for (i = sg1entry_contains_frag_data; i < nfrags; i++) { + + frag = &skb_shinfo (skb)->frags[i]; + sgentry = &sg_list[i - sg1entry_contains_frag_data]; + + sgentry->l_key = lkey; + sgentry->len = frag->size; + + tmp_addr = (u64)(page_address (frag->page) + + frag->page_offset); + sgentry->vaddr =get_swqe_addr (tmp_addr, +EHEA_MR_TX_DATA_PN + i); + } + } + +EDEB_EX (7 ,"" ); +} + +static int ehea_ioctl (struct net_device *dev,struct ifreq *ifr,int cmd) +{ +EDEB_ERR (4 ,"ioctl not supported: dev=%s cmd=%d" , dev->name, cmd); +return -EOPNOTSUPP ; +} + +static u64 ehea_broadcast_reg_helper (struct ehea_port *port,u32 hcallid) +{ +u64 hret =H_HARDWARE ; +u8 reg_type =0 ; + +if (hcallid ==H_REG_BCMC ) { +EDEB (7 ,"REGistering MAC for broadcast" ); + }else { +EDEB (7 ,"DEREGistering MAC for broadcast" ); + } + +/* De/Register untagged packets */ + reg_type =EHEA_BCMC_BROADCAST |EHEA_BCMC_UNTAGGED ; + hret = ehea_h_reg_dereg_bcmc(port->adapter->handle, + port->logical_port_id,
drivers/net/ehea/ehea_main.c line 1375
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ reg_type, port->mac_addr, 0, hcallid); +if (hret !=H_SUCCESS ) + goto hcall_failed; + +/* De/Register VLAN packets */ + reg_type =EHEA_BCMC_BROADCAST |EHEA_BCMC_VLANID_ALL ; + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, port->mac_addr,0 , hcallid); +hcall_failed:
unregister here?
Quoted 19 lines
drivers/net/ehea/ehea_main.c +19
-0+return hret; +} + +static int ehea_set_mac_addr (struct net_device *dev,void *sa) +{ +int ret = -EOPNOTSUPP ; +u64 hret =H_HARDWARE ; +struct hcp_query_ehea_port_cb_0 *ehea_port_cb_0 =NULL ; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct sockaddr *mac_addr = (struct sockaddr *)sa; + +EDEB_EN (7 ,"devname=%s" , dev->name); +EDEB_DMP (7 , (u8 *)&(mac_addr->sa_data[0 ]),14 ,"" ); + +if (!is_valid_ether_addr (mac_addr->sa_data)) { + ret = -EADDRNOTAVAIL ; + goto invalid_mac; + } +
drivers/net/ehea/ehea_main.c line 1404
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ ehea_port_cb_0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!ehea_port_cb_0) { +EDEB_ERR (4 ,"No memory for ehea_port control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + +memcpy ((u8 *)(&(ehea_port_cb_0->port_mac_addr)), + (u8 *)&(mac_addr->sa_data[0 ]),6 );
Don't need casts, memcpy takes void *. You should use ETH_ALEN (include/linux/if_ether.h) instead of 6.
Quoted 14 lines
drivers/net/ehea/ehea_main.c +14
-0+ + ehea_port_cb_0->port_mac_addr = ehea_port_cb_0->port_mac_addr >>16 ; + +EDEB (7 ,"ehea_port_cb_0" ); +EDEB_DMP (7 , (u8 *)ehea_port_cb_0, +sizeof (struct hcp_query_ehea_port_cb_0 ),"" ); + + hret =ehea_h_modify_ehea_port (port->adapter->handle, + port->logical_port_id, +H_PORT_CB0 , +EHEA_BMASK_SET (H_PORT_CB0_MAC ,1 ), + (void *)ehea_port_cb_0); +if (hret !=H_SUCCESS ) { + ret = -EOPNOTSUPP ;
drivers/net/ehea/ehea_main.c line 1428
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ goto hcall_failed; + } + +memcpy (dev->dev_addr, mac_addr->sa_data, dev->addr_len); + +/* Deregister old MAC in PHYP */ + hret =ehea_broadcast_reg_helper (port,H_DEREG_BCMC ); +if (hret) { + ret = -EOPNOTSUPP ; + goto hcall_failed;
What happens here? No mac? Old mac?
Quoted 90 lines
drivers/net/ehea/ehea_main.c +90
-0+ } + + port->mac_addr = ehea_port_cb_0->port_mac_addr <<16 ; + +/* Register new MAC in PHYP */ + hret =ehea_broadcast_reg_helper (port,H_REG_BCMC ); +if (hret) { + ret = -EOPNOTSUPP ; + goto hcall_failed; + } + + ret =0 ; + +hcall_failed: +kfree (ehea_port_cb_0); + +kzalloc_failed: +invalid_mac: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static void ehea_promiscuous (struct net_device *dev,int enable) +{ +struct ehea_port *port = dev->priv; + +if (!port->promisc) { +if (enable) { +/* Enable promiscuous mode */ +EDEB (7 ,"Enabling IFF_PROMISC" ); +EDEB_ERR (4 ,"Enable promiscuous mode: " +"not yet implemented" ); + port->promisc =EHEA_ENABLE ; + } + }else { +if (!enable) { +/* Disable promiscuous mode */ +EDEB (7 ,"Disabling IFF_PROMISC" ); +EDEB_ERR (4 ,"Disable promiscuous mode: " +"not yet implemented" ); + port->promisc =EHEA_DISABLE ; + } + } +} + +static u64 ehea_multicast_reg_helper (struct ehea_port *port, +u64 mc_mac_addr, +u32 hcallid) +{ +u64 hret =H_HARDWARE ; +u8 reg_type =0 ; + + reg_type =EHEA_BCMC_SCOPE_ALL |EHEA_BCMC_MULTICAST + |EHEA_BCMC_UNTAGGED ; + + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, mc_mac_addr,0 , hcallid); +if (hret) + goto hcall_failed; + + reg_type =EHEA_BCMC_SCOPE_ALL |EHEA_BCMC_MULTICAST + |EHEA_BCMC_VLANID_ALL ; + + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, mc_mac_addr,0 , hcallid); +hcall_failed: +return hret; +} + +static int ehea_drop_multicast_list (struct net_device *dev) +{ +int ret =0 ; +u64 hret =H_HARDWARE ; +struct ehea_port *port = dev->priv; +struct ehea_mc_list *mc_entry = port->mc_list; +struct list_head *pos; +struct list_head *temp; + +EDEB_EN (7 ,"devname=%s" , dev->name); + +if (!list_empty (&mc_entry->list)) { +list_for_each_safe (pos, temp, &(port->mc_list->list)) { + mc_entry = list_entry(pos, struct ehea_mc_list, list); + +EDEB (7 ,"Deregistering MAC %lx" , mc_entry->macaddr); + + hret = ehea_multicast_reg_helper(port, + mc_entry->macaddr,
drivers/net/ehea/ehea_main.c line 1528
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ H_DEREG_BCMC); +if (hret) { +EDEB_ERR (4 ,"Failed deregistering mcast MAC" ); + ret = -EINVAL ; + } + +list_del (pos); +kfree (mc_entry); + } + }
You don't need the if.
Ok, I'm tired now, I might read the rest later.
cheers
Signature · 8 lines
Michael Ellerman IBM OzLabs wwweb: http://michael.ellerman.id.au phone: +61 2 6212 1183 (tie line 70 21183) We do not inherit the earth from our ancestors, we borrow it from our children. - S.M.A.R.T Person
Quoted 12 lines · Michael Ellerman
drivers/net/ehea/ehea_main.c line 73
Quoted 9 lines
drivers/net/ehea/ehea_main.c +9
-0+struct hcp_query_ehea_port_cb_2 *cb2 =NULL ; +struct net_device_stats *stats = &port->stats; + +EDEB_EN (7 ,"net_device=%p" , dev); + + cb2 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb2) { +EDEB_ERR (4 ,"No memory for cb2" ); + goto get_stat_exit;You leak cb2 here.
Quoted 11 lines
drivers/net/ehea/ehea_main.c line 84
Quoted 11 lines
drivers/net/ehea/ehea_main.c +11
-0+ } + + hret =ehea_h_query_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB2 , +H_PORT_CB2_ALL , + cb2); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_port failed for cb2" ); + goto get_stat_exit;
Sorry, here.
cheers
Signature · 8 lines
Michael Ellerman IBM OzLabs wwweb: http://michael.ellerman.id.au phone: +61 2 6212 1183 (tie line 70 21183) We do not inherit the earth from our ancestors, we borrow it from our children. - S.M.A.R.T Person
Hi Michael,
thanks for your very helpful comments so far, we'll provide a patch with these and other fixes very soon.
See comments below.
Jan-Bernd
Quoted 66 lines · Michael Ellerman
Hi Jan-Bernd,
Comments below the code they refer to.
drivers/net/ehea/ehea_main.c line 2
Quoted 10 lines · Jan-Bernd Themann
Signed-off-by Jan-Bernd Themann <[email protected]>drivers/net/ehea/ehea_main.c | 2738 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 2738 insertions(+)drivers/net/ehea/ehea_main.c +2
-0@@ -0,0 +1,2738 @@ +/* +* linux/drivers/net/ehea/ehea_main.c Putting the file name in the file is fairly redundant IMHO.
drivers/net/ehea/ehea_main.c line 4
Quoted 1 line
drivers/net/ehea/ehea_main.c +1
-0+* eHEA ethernet device driver for IBM eServer System p What's the actual hardware that this is for? System p covers a whole range of machines, do they really all support this driver?
Quoted 43 lines
drivers/net/ehea/ehea_main.c +43
-0+* (C) Copyright IBM Corp. 2006 +* +* Authors: +* Christoph Raisch <[email protected]> +* Jan-Bernd Themann <[email protected]> +* Heiko-Joerg Schick <[email protected]> +* Thomas Klein <[email protected]> +* +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation; either version 2, or (at your option) +* any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software +* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#define DEB_PREFIX "main" + +#include <linux/in.h> +#include <linux/ip.h> +#include <linux/tcp.h> +#include <linux/udp.h> +#include <linux/if.h> +#include <linux/list.h> +#include <net/ip.h> + +#include "ehea.h" +#include "ehea_qmr.h" +#include "ehea_phyp.h" + + +MODULE_LICENSE ("GPL" ); +MODULE_AUTHOR ("Christoph Raisch <[email protected]>" ); +MODULE_DESCRIPTION ("IBM eServer HEA Driver" ); +MODULE_VERSION (EHEA_DRIVER_VERSION );
Quoted 8 lines
drivers/net/ehea/ehea_main.c line 53
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+ +static int __devinit ehea_probe (struct ibmebus_dev *dev, +const struct of_device_id *id); +static int __devexit ehea_remove(struct ibmebus_dev *dev); +static int ehea_sense_port_attr (struct ehea_adapter *adapter,int portnum);I haven't looked closely, but can you rearrange the functions so you don't need these forward declarations?
yes, rearrangement is possible. Done.
Quoted 14 lines
drivers/net/ehea/ehea_main.c line 61
Quoted 7 lines
drivers/net/ehea/ehea_main.c +6
-0+int ehea_trace_level =5 ; + +static struct net_device_stats *ehea_get_stats (struct net_device *dev) +{ +int i; +u64 hret =H_HARDWARE ;You unconditionally assign to hret below.
drivers/net/ehea/ehea_main.c line 62
Quoted 1 line
drivers/net/ehea/ehea_main.c +1
-0+u64 rx_packets =0 ;Why not just update
stats->rx_packetsdirectly?
Quoted 5 lines
drivers/net/ehea/ehea_main.c line 60
Quoted 2 lines
drivers/net/ehea/ehea_main.c +2
-0+struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_adapter *adapter = port->adapter;I don't think you need adapter, you only use it in one place, just access it through
port->adapter->handle(below).
done
Quoted 13 lines
drivers/net/ehea/ehea_main.c line 73
Quoted 10 lines
drivers/net/ehea/ehea_main.c +9
-0+struct hcp_query_ehea_port_cb_2 *cb2 =NULL ; +struct net_device_stats *stats = &port->stats; + +EDEB_EN (7 ,"net_device=%p" , dev); + + cb2 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); +if (!cb2) { +EDEB_ERR (4 ,"No memory for cb2" ); + goto get_stat_exit;You leak cb2 here.
done
Quoted 30 lines
Quoted 30 lines
drivers/net/ehea/ehea_main.c +30
-0+ } + + hret =ehea_h_query_ehea_port (adapter->handle, + port->logical_port_id, +H_PORT_CB2 , +H_PORT_CB2_ALL , + cb2); + +if (hret !=H_SUCCESS ) { +EDEB_ERR (4 ,"query_ehea_port failed for cb2" ); + goto get_stat_exit; + } + +EDEB_DMP (7 , (u8 *)cb2, +sizeof (struct hcp_query_ehea_port_cb_2 ),"After HCALL" ); + +for (i =0 ; i < port->num_def_qps; i++) { + rx_packets += port->port_res[i].rx_packets; + } + + stats->tx_packets = cb2->txucp + cb2->txmcp + cb2->txbcp; + stats->multicast = cb2->rxmcp; + stats->rx_errors = cb2->rxuerr; + stats->rx_bytes = cb2->rxo; + stats->tx_bytes = cb2->txo; + stats->rx_packets = rx_packets; + +get_stat_exit: +EDEB_EX (7 ,"" ); +return stats;
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 109
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+} + +static inline u32 ehea_get_send_lkey (struct ehea_port_res *pr) +{ +return pr->send_mr.lkey; +}Get rid of this, it's only used once.
done
Quoted 7 lines
drivers/net/ehea/ehea_main.c line 114
Quoted 4 lines
drivers/net/ehea/ehea_main.c +4
-0+static inline u32 ehea_get_recv_lkey (struct ehea_port_res *pr) +{ +return pr->recv_mr.lkey; +}And this one only twice? Is it really useful?
done
Quoted 9 lines
Quoted 9 lines
drivers/net/ehea/ehea_main.c +9
-0+ +#define EHEA_OD_ADDR (address, segment) (((address) & (PAGE_SIZE - 1)) \ + | ((segment) << 12)); + +static inline u64 get_swqe_addr (u64 tmp_addr,int addr_seg) +{ +u64 addr; + addr = tmp_addr; +return addr;
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 129
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+} + +static inline u64 get_rwqe_addr (u64 tmp_addr) +{ +return tmp_addr; +}This two functions seem useless or wrong.
removed
Quoted 6 lines
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+static inline int ehea_refill_rq1 (struct ehea_port_res *port_res,int arr_index, +int nr_of_wqes) +{ +int i; +int ret =0 ; +struct ehea_qp *qp;
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 143
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+int skb_arr_rq1_len = port_res->skb_arr_rq1_len; +struct sk_buff **skb_arr_rq1 = port_res->skb_arr_rq1; +EDEB_EN (7 ,"port_res=%p, arr_index=%d, nr_of_wqes=%d, arr_rq1_len=%d" , + port_res, arr_index, nr_of_wqes, skb_arr_rq1_len); + + qp = port_res->qp;You don't need the qp variable, just use
port_res->qpbelow.
done
Quoted 5 lines
drivers/net/ehea/ehea_main.c line 138
Quoted 2 lines
drivers/net/ehea/ehea_main.c +2
-0+if (unlikely (nr_of_wqes ==0 )) +return -EINVAL ;Newline needed here.
done
Quoted 6 lines
drivers/net/ehea/ehea_main.c line 148
Quoted 3 lines
drivers/net/ehea/ehea_main.c +3
-0+for (i =0 ; i < nr_of_wqes; i++) { +int index = ((skb_arr_rq1_len + arr_index) - i) + % skb_arr_rq1_len;The wrapped line should be indented further to the right.
done
Quoted 80 lines
Quoted 80 lines
drivers/net/ehea/ehea_main.c +80
-0+if (!skb_arr_rq1[index]) { + skb_arr_rq1[index] =dev_alloc_skb (EHEA_LL_PKT_SIZE ); + +if (!skb_arr_rq1[index]) { +EDEB_ERR (4 ,"No mem for skb/%d wqes filled" , i); + ret = -ENOMEM ; +break ; + } + } + } +/* Ring doorbell */ +ehea_update_rq1a (qp, nr_of_wqes); +EDEB_EX (7 ,"" ); +return ret; +} + +static int ehea_init_fill_rq1 (struct ehea_port_res *port_res,int nr_rq1a) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +EDEB_EN (7 ,"port_res=%p, nr_rq1a=%d" , port_res, nr_rq1a); + qp = port_res->qp; + +for (i =0 ; i < port_res->skb_arr_rq1_len; i++) { + port_res->skb_arr_rq1[i] =dev_alloc_skb (EHEA_LL_PKT_SIZE ); +if (!port_res->skb_arr_rq1[i]) { +EDEB_ERR (4 ,"dev_alloc_skb failed. Only %d skb filled." , + i); + ret = -ENOMEM ; +break ; + } + } +/* Ring doorbell */ +ehea_update_rq1a (qp, nr_rq1a); +EDEB_EX (7 ,"" ); +return ret; +} + +static inline int ehea_refill_rq2_def (struct ehea_port_res *pr,int nr_of_wqes) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +struct ehea_rwqe *rwqe; +int skb_arr_rq2_len = pr->skb_arr_rq2_len; +struct sk_buff **skb_arr_rq2 = pr->skb_arr_rq2; + +EDEB_EN (8 ,"pr=%p, nr_of_wqes=%d" , pr, nr_of_wqes); +if (nr_of_wqes ==0 ) +return -EINVAL ; + qp = pr->qp; +for (i =0 ; i < nr_of_wqes; i++) { +int index = pr->skb_rq2_index++; +struct sk_buff *skb =dev_alloc_skb (EHEA_RQ2_PKT_SIZE + +NET_IP_ALIGN ); + +if (!skb) { +EDEB_ERR (4 ,"dev_alloc_skb nr %d failed" , i); + ret = -ENOMEM ; +break ; + } +skb_reserve (skb,NET_IP_ALIGN ); + pr->skb_rq2_index %= skb_arr_rq2_len; + skb_arr_rq2[index] = skb; + rwqe =ehea_get_next_rwqe (qp,2 ); + rwqe->wr_id =EHEA_BMASK_SET (EHEA_WR_ID_TYPE ,EHEA_RWQE2_TYPE ) + |EHEA_BMASK_SET (EHEA_WR_ID_INDEX , index); + rwqe->sg_list[0 ].l_key =ehea_get_recv_lkey (pr); + rwqe->sg_list[0 ].vaddr =get_rwqe_addr ((u64 )skb->data); + rwqe->sg_list[0 ].len =EHEA_RQ2_PKT_SIZE ; + rwqe->data_segments =1 ; + } + +/* Ring doorbell */ +iosync (); +ehea_update_rq2a (qp, i); +EDEB_EX (8 ,"" ); +return ret; +}
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 234
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+ + +static inline int ehea_refill_rq2 (struct ehea_port_res *pr,int nr_of_wqes) +{ +return ehea_refill_rq2_def (pr, nr_of_wqes); +}Why do you need this function?
this is for near future features
Quoted 38 lines
Quoted 38 lines
drivers/net/ehea/ehea_main.c +38
-0+static inline int ehea_refill_rq3_def (struct ehea_port_res *pr,int nr_of_wqes) +{ +int i; +int ret =0 ; +struct ehea_qp *qp; +struct ehea_rwqe *rwqe; +int skb_arr_rq3_len = pr->skb_arr_rq3_len; +struct sk_buff **skb_arr_rq3 = pr->skb_arr_rq3; +EDEB_EN (8 ,"pr=%p, nr_of_wqes=%d" , pr, nr_of_wqes); +if (nr_of_wqes ==0 ) +return -EINVAL ; + qp = pr->qp; +for (i =0 ; i < nr_of_wqes; i++) { +int index = pr->skb_rq3_index++; +struct sk_buff *skb =dev_alloc_skb (EHEA_MAX_PACKET_SIZE + +NET_IP_ALIGN ); + +if (!skb) { +EDEB_ERR (4 ,"No memory for skb. Only %d rwqe filled." , + i); + ret = -ENOMEM ; +break ; + } +skb_reserve (skb,NET_IP_ALIGN ); + + rwqe =ehea_get_next_rwqe (qp,3 ); + pr->skb_rq3_index %= skb_arr_rq3_len; + skb_arr_rq3[index] = skb; + rwqe->wr_id =EHEA_BMASK_SET (EHEA_WR_ID_TYPE ,EHEA_RWQE3_TYPE ) + |EHEA_BMASK_SET (EHEA_WR_ID_INDEX , index); + rwqe->sg_list[0 ].l_key =ehea_get_recv_lkey (pr); + rwqe->sg_list[0 ].vaddr =get_rwqe_addr ((u64 )skb->data); + rwqe->sg_list[0 ].len =EHEA_MAX_PACKET_SIZE ; + rwqe->data_segments =1 ; + } + +/* Ring doorbell */ +iosync ();
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 277
Quoted 4 lines
drivers/net/ehea/ehea_main.c +4
-0+ehea_update_rq3a (qp, i); +EDEB_EX (8 ,"" ); +return ret; +}You "Ring doorbell" in four places, but only in two do you do
iosync(), that might be ok, but it looks suspicious. Also, what is the iosync trying to achieve?
That is ok. We do a iosync to make sure that the hardware sees the entire wqe we put on the queue. For RQ1, we don't put something on the queue that has to be read by the hea hardware -> no iosync needed
Quoted 3 lines
ehea_refill_rq3_def()andehea_refill_rq2_def()look quite similar, can they be combined?
Well, it seems to be a tradeoff between a function with lots of parameters and two separate functions. Our choice was the last option.
Quoted 42 lines
Quoted 42 lines
drivers/net/ehea/ehea_main.c +42
-0+ + +static inline int ehea_refill_rq3 (struct ehea_port_res *pr,int nr_of_wqes) +{ +return ehea_refill_rq3_def (pr, nr_of_wqes); +} + + +static inline int ehea_check_cqe (struct ehea_cqe *cqe,int *rq_num) +{ + *rq_num = (cqe->type &EHEA_CQE_TYPE_RQ ) >>5 ; +EDEB (7 ,"RQ used=%d, status=%X" , *rq_num, cqe->status); +if ((cqe->status &EHEA_CQE_STAT_ERR_MASK ) ==0 ) +return 0 ; +if (((cqe->status &EHEA_CQE_STAT_ERR_TCP ) !=0 ) + && (cqe->header_length ==0 )) +return 0 ; +else +printk ("WARNING: Packet discarded. Wrong TCP/UDP chksum" +"and header_length != 0. cqe->status=%X" , cqe->status); + +return -EINVAL ; +} + +static inline void ehea_fill_skb_ll (struct net_device *dev, +struct sk_buff *skb,struct ehea_cqe *cqe) +{ +int length = cqe->num_bytes_transfered -4 ;/*remove CRC */ +EDEB_EN (7 ,"dev=%p, skb=%p, cqe=%p" , dev, skb, cqe); +memcpy (skb->data, ((char *)cqe) +64 , length); +skb_put (skb, length); + skb->dev = dev; + skb->ip_summed =CHECKSUM_UNNECESSARY ; + skb->protocol =eth_type_trans (skb, dev); +EDEB_EX (7 ,"" ); +} + +static inline void ehea_fill_skb (struct net_device *dev, +struct sk_buff *skb,struct ehea_cqe *cqe) +{ +int length = cqe->num_bytes_transfered -4 ;/*remove CRC */ +EDEB_EN (7 ,"dev=%p, skb=%p, cqe=%p" , dev, skb, cqe);
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 313
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+skb_put (skb, length); + skb->dev = dev; + skb->ip_summed =CHECKSUM_UNNECESSARY ; + skb->protocol =eth_type_trans (skb, dev); +EDEB_EX (7 ,"" ); +}What's the difference between the above two functions?
the first one has an additional copy. But you are right, we get rid of ehea_fill_skb_ll
Quoted 4 lines
drivers/net/ehea/ehea_main.c line 328
Quoted 1 line
drivers/net/ehea/ehea_main.c +1
-0+#define EHEA_MAX_RWQE 1000Should probably be in a header.
agreed
Quoted 186 lines
Quoted 186 lines
drivers/net/ehea/ehea_main.c +186
-0+static int ehea_poll (struct net_device *dev,int *budget) +{ +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_port_res *port_res = &port->port_res[0 ]; +struct ehea_cqe *cqe; +struct ehea_qp *qp = port_res->qp; +int wqe_index =0 ; +int last_wqe_index =0 ; +int x =0 ; +int processed =0 ; +int processed_RQ1 =0 ; +int processed_RQ2 =0 ; +int processed_RQ3 =0 ; +int rq; +int intreq; +struct sk_buff **skb_arr_rq1 = port_res->skb_arr_rq1; +struct sk_buff **skb_arr_rq2 = port_res->skb_arr_rq2; +struct sk_buff **skb_arr_rq3 = port_res->skb_arr_rq3; +int skb_arr_rq1_len = port_res->skb_arr_rq1_len; +int my_quota =min (*budget, dev->quota); + +EDEB_EN (7 ,"dev=%p, port_res=%p, budget=%d, quota=%d, qp_nr=%x" , + dev, port_res, *budget, dev->quota, + port_res->qp->init_attr.qp_nr); + my_quota =min (my_quota,EHEA_MAX_RWQE ); + +/* rq0 is low latency RQ */ + cqe =ehea_poll_rq1 (qp, &wqe_index); +while ((my_quota >0 ) && cqe) { +ehea_inc_rq1 (qp); + processed_RQ1++; + processed++; + my_quota--; + +EDEB_DMP (6 , (u8 *)cqe,4 *16 ,"CQE" ); + last_wqe_index = wqe_index; +rmb (); +if (!ehea_check_cqe (cqe, &rq)) { +struct sk_buff *skb; +if (rq ==1 ) {/* LL RQ1 */ +void *pref; + + x = (wqe_index +1 ) % skb_arr_rq1_len; + pref = (void *)skb_arr_rq1[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (wqe_index +1 ) % skb_arr_rq1_len; + pref = (void *)(skb_arr_rq1[x]->data); +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + skb = skb_arr_rq1[wqe_index]; +if (unlikely (!skb)) { +EDEB_ERR (4 ,"LL SBK=NULL, wqe_index=%d" , + wqe_index); + skb =dev_alloc_skb (EHEA_LL_PKT_SIZE ); +if (!skb) +panic ("Alloc SKB failed" ); + } + skb_arr_rq1[wqe_index] =NULL ; +ehea_fill_skb_ll (dev, skb, cqe); + }else if (rq ==2 ) {/* RQ2 */ +void *pref; +int skb_index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); + x = (skb_index +1 ) % port_res->skb_arr_rq2_len; + pref = (void *)skb_arr_rq2[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (skb_index +1 ) % port_res->skb_arr_rq2_len; + pref = (void *)(skb_arr_rq2[x]->data); + +prefetch (pref); +prefetch (pref +EHEA_CACHE_LINE ); +prefetch (pref +EHEA_CACHE_LINE *2 ); +prefetch (pref +EHEA_CACHE_LINE *3 ); + skb = skb_arr_rq2[skb_index]; + +if (unlikely (!skb)) { +EDEB_ERR (4 ,"rq2: SKB=NULL, index=%d" , + skb_index); +break ; + } + skb_arr_rq2[skb_index] =NULL ; +ehea_fill_skb (dev, skb, cqe); + processed_RQ2++; + }else { +void *pref; +int skb_index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); + x = (skb_index +1 ) % port_res->skb_arr_rq3_len; + pref = (void *)skb_arr_rq3[x]; +prefetchw (pref); +prefetchw (pref +EHEA_CACHE_LINE ); + + x = (skb_index +1 ) % port_res->skb_arr_rq3_len; + pref = (void *)(skb_arr_rq3[x]->data); +prefetch (pref); +prefetch (pref +EHEA_CACHE_LINE ); +prefetch (pref +EHEA_CACHE_LINE *2 ); +prefetch (pref +EHEA_CACHE_LINE *3 ); + + skb = skb_arr_rq3[skb_index]; +if (unlikely (!skb)) { +EDEB_ERR (4 ,"rq3: SKB=NULL, index=%d" , + skb_index); +break ; + } + skb_arr_rq3[skb_index] =NULL ; +ehea_fill_skb (dev, skb, cqe); + processed_RQ3++; + } + +EDEB (6 ,"About to pass SKB: dev=%p\n" +"skb=%p skb->data=%p skb->len=%d" +" skb->data_len=0x%x nr_frags=%d" , + dev, + skb, + skb->data, + skb->len, + skb->data_len,skb_shinfo (skb)->nr_frags); +if (cqe->status &EHEA_CQE_VLAN_TAG_XTRACT ) { +EDEB (7 ,"VLAN TAG extracted: %4x, vgrp=%p" , + cqe->vlan_tag, port->vgrp); +EDEB (7 ,"vlan_devices[vlan_tag]=%p" , + port->vgrp->vlan_devices[cqe->vlan_tag]); +vlan_hwaccel_receive_skb (skb, port->vgrp, + cqe->vlan_tag); + }else { +EDEB (7 ,"netif_receive_skb" ); +netif_receive_skb (skb); + } +EDEB (7 ,"SKB passed (netif_receive(skb) called)" ); + + }else { +struct sk_buff *skb; + +EDEB_ERR (4 ,"cqe->status indicating error: CQE:" ); +EDEB_DMP (4 , (u8 *)cqe,4 *16 ,"" ); +if (rq ==2 ) { + processed_RQ2++; + skb = skb_arr_rq2[ +EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)]; + skb_arr_rq2[EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)] =NULL ; +dev_kfree_skb (skb); + } +if (rq ==3 ) { + processed_RQ3++; + skb = skb_arr_rq3[ +EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)]; + skb_arr_rq3[EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id)] =NULL ; +dev_kfree_skb (skb); + } + } + cqe =ehea_poll_rq1 (qp, &wqe_index); + } + + dev->quota -= processed; + *budget -= processed; + + port_res->p_state.ehea_poll +=1 ; + + port_res->rx_packets += processed; + +ehea_refill_rq1 (port_res, last_wqe_index, processed_RQ1); +ehea_refill_rq2 (port_res, processed_RQ2); +ehea_refill_rq3 (port_res, processed_RQ3); + + intreq = ((port_res->p_state.ehea_poll &0xF ) ==0xF ); + +EDEB_EX (7 ,"processed=%d, *budget=%d, dev->quota=%d" , + processed, *budget, dev->quota); + +if (!cqe || intreq) { +netif_rx_complete (dev); +ehea_reset_cq_ep (port_res->recv_cq); +ehea_reset_cq_n1 (port_res->recv_cq); + cqe =ipz_qeit_get_valid (&qp->ipz_rqueue1); +EDEB (7 ,"CQE=%p, break ehea_poll while loop" , cqe); +if (!cqe || intreq)
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 521
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+return 0 ; +if (!netif_rx_reschedule (dev, my_quota)) +return 0 ; + } +return 1 ; +}This function is _way_ too big.
Ok, we will make it smaller
Quoted 78 lines
Quoted 78 lines
drivers/net/ehea/ehea_main.c +78
-0+#define MAX_SENDCOMP_QUOTA 400 +void ehea_send_irq_tasklet (unsigned long data) +{ +int quota =MAX_SENDCOMP_QUOTA ; +int skb_index; +int cqe_counter =0 ; +int swqe_av =0 ; +unsigned long flags; +struct sk_buff *skb; +struct ehea_cqe *cqe; +struct ehea_port_res *port_res = (struct ehea_port_res *)data; +struct ehea_cq *send_cq = port_res->send_cq; +struct net_device *dev = port_res->port->netdev; + +EDEB_EN (7 ,"port_res=%p" , port_res); + +do { + cqe =ehea_poll_cq (send_cq); +if (!cqe) { +EDEB (7 ,"No further cqe found" ); +ehea_reset_cq_ep (send_cq); +ehea_reset_cq_n1 (send_cq); + cqe =ehea_poll_cq (send_cq); +if (!cqe) { +EDEB (7 ,"No cqe found after having" +" reset N1/EP\n" ); +break ; + } + } + cqe_counter++; +EDEB (7 ,"CQE found on Send-CQ:" ); +EDEB_DMP (7 , (u8 *)cqe,4 *16 ,"" ); +rmb (); +if (likely (EHEA_BMASK_GET (EHEA_WR_ID_TYPE , cqe->wr_id) + ==EHEA_SWQE2_TYPE )) {/* is swqe format 2 */ +int i; +int index =EHEA_BMASK_GET (EHEA_WR_ID_INDEX , + cqe->wr_id); +for (i =0 ; i <EHEA_BMASK_GET (EHEA_WR_ID_REFILL , + cqe->wr_id); i++) { + + skb_index = ((index - i + + port_res->skb_arr_sq_len) + % port_res->skb_arr_sq_len); + skb = port_res->skb_arr_sq[skb_index]; + port_res->skb_arr_sq[skb_index] =NULL ; + +if (unlikely (!skb)) { +EDEB_ERR (4 ,"s_irq_tasklet: SKB=NULL " +"WQ_ID=%lX, loop=%d, index=%d" , + cqe->wr_id, i, skb_index); +break ; + } +dev_kfree_skb (skb); + } + } + swqe_av +=EHEA_BMASK_GET (EHEA_WR_ID_REFILL , cqe->wr_id); + quota--; + }while (quota >0 ); + +ehea_update_feca (send_cq, cqe_counter); + +atomic_add (swqe_av, &port_res->swqe_avail); +EDEB (7 ,"port_res->swqe_avail=%d" , +atomic_read (&port_res->swqe_avail)); + +if (unlikely (netif_queue_stopped (dev))) { +spin_lock_irqsave (&port_res->netif_queue, flags); +if (unlikely ((atomic_read (&port_res->swqe_avail) + >=EHEA_SWQE_REFILL_TH ))) { +EDEB (7 ,"port %d swqes_avail >=10 (%d)," +"netif_wake_queue called" , + port_res->port->logical_port_id, +atomic_read (&port_res->swqe_avail)); +netif_wake_queue (port_res->port->netdev); + } +spin_unlock_irqrestore (&port_res->netif_queue, flags); + }
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 606
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+ +if (unlikely (cqe)) +tasklet_hi_schedule (&port_res->send_comp_task); + +EDEB_EX (7 ,"" ); +}This one's pretty big too.
Done
Quoted 22 lines
Quoted 22 lines
drivers/net/ehea/ehea_main.c +22
-0+ +irqreturn_t ehea_send_irq_handler (int irq,void *param,struct pt_regs *regs) +{ +struct ehea_port_res *pr = (struct ehea_port_res *)param; +EDEB_EN (7 ,"irq=%d, param=%p, pt_regs=%p" , irq, param, regs); +tasklet_hi_schedule (&pr->send_comp_task); +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + +irqreturn_t ehea_recv_irq_handler (int irq,void *param,struct pt_regs * regs) +{ +struct ehea_port_res *pr = (struct ehea_port_res *)param; +struct ehea_port *port = pr->port; +EDEB_EN (7 ,"irq=%d, param=%p, pt_regs=%p" , irq, param, regs); +netif_rx_schedule (port->netdev); +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + +irqreturn_t ehea_qp_aff_irq_handler (int irq,void *param,struct pt_regs * regs) +{
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 634
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+struct ehea_port *port = (struct ehea_port *)param; +struct ehea_eqe *eqe; +u32 qp_token; + +EDEB_EN (7 ,"irq=%d, param=%p, pt_regs=%p" , irq, param, regs); + eqe = (struct ehea_eqe *)ehea_poll_eq (port->qp_eq);Suspicious cast?
ehea_poll_eq changed so that this cast is not necessary anymore
Quoted 8 lines
drivers/net/ehea/ehea_main.c line 639
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+EDEB (7 ,"eqe=%p" , eqe); +while (eqe) { +EDEB (7 ,"*eqe=%lx" , *(u64 *)eqe); + eqe = (struct ehea_eqe *)ehea_poll_eq (port->qp_eq); + qp_token =EHEA_BMASK_GET (EHEA_EQE_QP_TOKEN , eqe->entry);You don't seem to use
qp_token?
planned for recovery, we are working on that
Quoted 18 lines
Quoted 18 lines
drivers/net/ehea/ehea_main.c +18
-0+EDEB (7 ,"next eqe=%p" , eqe); + } + +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + +static struct ehea_port *ehea_get_port (struct ehea_adapter *adapter, +int logical_port) +{ +int i; + +for (i =0 ; i < adapter->num_ports; i++) +if (adapter->port[i]->logical_port_id == logical_port) +return adapter->port[i]; +return NULL ; +} +
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 663
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+static void ehea_parse_eqe (struct ehea_adapter *adapter,u64 eqe) +{ +int ret = -EINVAL ; +u8 ec =0 ; +u8 portnum =0 ; +struct ehea_port *port =NULL ;You don't need to initialise these three variables.
true
Quoted 44 lines
Quoted 44 lines
drivers/net/ehea/ehea_main.c +44
-0+ +EDEB_EN (7 ,"eqe=%lx" , eqe); + + ec =EHEA_BMASK_GET (NEQE_EVENT_CODE , eqe); + +switch (ec) { +case EHEA_EC_PORTSTATE_CHG :/* port state change */ +EDEB (7 ,"Port state change" ); + portnum =EHEA_BMASK_GET (NEQE_PORTNUM , eqe); + port =ehea_get_port (adapter, portnum); + +if (!port) { +EDEB_ERR (4 ,"Unknown portnum %x" , portnum); +break ; + } + +if (EHEA_BMASK_GET (NEQE_PORT_UP , eqe)) { +if (!netif_carrier_ok (port->netdev)) { + ret =ehea_sense_port_attr (adapter, portnum); +if (ret) { +EDEB_ERR (4 ,"Failed resensing port" ); +break ; + } + +printk ("%s: Logical port up: %dMbps %s Duplex" , + port->netdev->name, + port->port_speed, + port->full_duplex == +1 ?"Full" :"Half" ); + +netif_carrier_on (port->netdev); +netif_wake_queue (port->netdev); + } + }else +if (netif_carrier_ok (port->netdev)) { +printk ("%s: Logical port down" , + port->netdev->name); +netif_carrier_off (port->netdev); +netif_stop_queue (port->netdev); + } + +if (EHEA_BMASK_GET (NEQE_EXTSWITCH_PORT_UP , eqe)) +printk ("%s: Physical port up" , port->netdev->name); +else
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 713
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+printk ("%s: Physical port down" , port->netdev->name); + +if (EHEA_BMASK_GET (NEQE_EXTSWITCH_PRIMARY , eqe)) +printk ("Externel switch port is primary port" ); +else +printk ("Externel switch port is backup port" );These printks should probably use
KERN_DEBUG, ornetif_msg_foo().
I guess, KERN_INFO would be a good choice
Quoted 6 lines
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+break ; +case EHEA_EC_ADAPTER_MALFUNC :/* adapter malfunction */ +EDEB_ERR (4 ,"Adapter malfunction" ); +break ; +case EHEA_EC_PORT_MALFUNC :/* port malfunction */ +EDEB_ERR (4 ,"Port malfunction" );
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 725
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+/* TODO Determine the port structure of the malfunctioning port +* netif_carrier_off(port->netdev); +* netif_stop_queue(port->netdev); +*/ +break ;The two malfunction states could probably use a printk(KERN_WARNING .. ) for now.
done
Quoted 18 lines
Quoted 18 lines
drivers/net/ehea/ehea_main.c +18
-0+default : +EDEB_ERR (4 ,"Unknown event code %x" , ec); +break ; + } + +EDEB_EX (7 ,"" ); +} + +void ehea_neq_tasklet (unsigned long data) +{ +struct ehea_adapter *adapter = (struct ehea_adapter *)data; +struct ehea_eqe *eqe; +u64 event_mask; + +EDEB_EN (7 ,"" ); + eqe = (struct ehea_eqe *)ehea_poll_eq (adapter->neq); +EDEB (7 ,"eqe=%p" , eqe); +
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 749
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+while (eqe) { +EDEB (7 ,"*eqe=%lx" , eqe->entry); +ehea_parse_eqe (adapter, eqe->entry); + eqe = (struct ehea_eqe *)ehea_poll_eq (adapter->neq); +EDEB (7 ,"next eqe=%p" , eqe); + }I think I've seen this code before.
there is a similar function, but it will be used for a different error recovery
Quoted 37 lines
Quoted 37 lines
drivers/net/ehea/ehea_main.c +37
-0+ + event_mask =EHEA_BMASK_SET (NELR_PORTSTATE_CHG ,1 ) + |EHEA_BMASK_SET (NELR_ADAPTER_MALFUNC ,1 ) + |EHEA_BMASK_SET (NELR_PORT_MALFUNC ,1 ); + +ehea_h_reset_events (adapter->handle, + adapter->neq->ipz_eq_handle, event_mask); +EDEB_EX (7 ,"" ); +} + +irqreturn_t ehea_interrupt_neq (int irq,void *param,struct pt_regs *regs) +{ +struct ehea_adapter *adapter = (struct ehea_adapter *)param; +EDEB_EN (7 ,"dev_id=%p" , adapter); +tasklet_hi_schedule (&adapter->neq_tasklet); +EDEB_EX (7 ,"" ); +return IRQ_HANDLED ; +} + + + +static void ehea_fill_port_res (struct ehea_port_res *pr) +{ +struct ehea_qp_init_attr *init_attr = &pr->qp->init_attr; + +/* RQ 1 */ +ehea_init_fill_rq1 (pr, init_attr->act_nr_rwqes_rq1 + - init_attr->act_nr_rwqes_rq2 + - init_attr->act_nr_rwqes_rq3 -1 ); + +/* RQ 2 */ +ehea_refill_rq2 (pr, init_attr->act_nr_rwqes_rq2); + +/* RQ 3 */ +ehea_refill_rq3 (pr, init_attr->act_nr_rwqes_rq3); +} +
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 792
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+static int ehea_reg_interrupts (struct net_device *dev) +{ +int ret = -EINVAL ; +int i; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct ehea_port_res *pr = &port->port_res[0 ];Don't need to initalise pr.
done
Quoted 47 lines
Quoted 47 lines
drivers/net/ehea/ehea_main.c +47
-0+ +EDEB_EN (7 ,"" ); +for (i =0 ; i < port->num_def_qps; i++) { + pr = &port->port_res[i]; +snprintf (pr->int_recv_name,EHEA_IRQ_NAME_SIZE -1 + ,"%s-recv%d" , dev->name, i); + ret =ibmebus_request_irq (NULL , + pr->recv_eq->attr.ist1, + ehea_recv_irq_handler, +SA_INTERRUPT , pr->int_recv_name, pr); +if (ret) { +EDEB_ERR (4 ,"Failed registering irq for ehea_recv_int:" +"port_res_nr:%d, ist=%X" , i, + pr->recv_eq->attr.ist1); + goto failure; + } +EDEB (7 ,"irq_handle 0x%X for function ehea_recv_int %d " +" registered" , pr->recv_eq->attr.ist1, i); + } + +snprintf (port->int_aff_name,EHEA_IRQ_NAME_SIZE -1 , +"%s-aff" , dev->name); + ret =ibmebus_request_irq (NULL , + port->qp_eq->attr.ist1, + ehea_qp_aff_irq_handler, +SA_INTERRUPT , port->int_aff_name, port); +if (ret) { +EDEB_ERR (4 ,"Failed registering irq for qp_aff_irq_handler:" +" ist=%X" , port->qp_eq->attr.ist1); + goto failure; + } +EDEB (7 ,"irq_handle 0x%X for function qp_aff_irq_handler registered" , + port->qp_eq->attr.ist1); + +for (i =0 ; i < port->num_def_qps + port->num_tx_qps; i++) { + pr = &port->port_res[i]; +snprintf (pr->int_send_name,EHEA_IRQ_NAME_SIZE -1 , +"%s-send%d" , dev->name, i); + ret =ibmebus_request_irq (NULL , + pr->send_eq->attr.ist1, + ehea_send_irq_handler, +SA_INTERRUPT , pr->int_send_name, + pr); +if (ret) { +EDEB_ERR (4 ,"Registering irq for ehea_send failed" +" port_res_nr:%d, ist=%X" , i, + pr->send_eq->attr.ist1);
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 844
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+ goto failure; + } +EDEB (7 ,"irq_handle 0x%X for function ehea_send_int %d" +" registered" , pr->send_eq->attr.ist1, i); + }You seem to be iterating over some of the
port_resstructs twice, is that what you intended?
yes
Quoted 6 lines
drivers/net/ehea/ehea_main.c line 847
Quoted 3 lines
drivers/net/ehea/ehea_main.c +3
-0+failure: +EDEB_EX (7 ,"ret=%d" , ret); +return ret;No further cleanup required? Should you be calling
ehea_free_interrupts?
good point, a proper error handling will be included
Quoted 314 lines
Quoted 84 lines
drivers/net/ehea/ehea_main.c +84
-0+} + +static void ehea_free_interrupts (struct net_device *dev) +{ +struct ehea_port *port = (struct ehea_port *)dev->priv; +int i; + +EDEB_EN (7 ,"" ); +/* send */ +for (i =0 ; i < port->num_def_qps + port->num_tx_qps; i++) { +ibmebus_free_irq (NULL , port->port_res[i].send_eq->attr.ist1, + &port->port_res[i]); +EDEB (7 ,"free send interrupt for res %d with handle 0x%X" , + i, port->port_res[i].send_eq->attr.ist1); + } + +/* receive */ +for (i =0 ; i < port->num_def_qps; i++) { +ibmebus_free_irq (NULL , port->port_res[i].recv_eq->attr.ist1, + &port->port_res[i]); +EDEB (7 ,"free recv intterupt for res %d with handle 0x%X" , + i, port->port_res[i].recv_eq->attr.ist1); + } +/* associated events */ +ibmebus_free_irq (NULL , port->qp_eq->attr.ist1, port); +EDEB (7 ,"associated event interrupt for handle 0x%X freed" , + port->qp_eq->attr.ist1); +EDEB_EX (7 ,"" ); +} + +static int ehea_configure_port (struct ehea_port *port) +{ +int ret = -EINVAL ; +u64 hret =H_HARDWARE ; +struct hcp_query_ehea_port_cb_0 *ehea_port_cb_0 =NULL ; +u64 mask =0 ; +int i; + +EDEB_EN (7 ,"" ); + + ehea_port_cb_0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!ehea_port_cb_0) { +EDEB_ERR (4 ,"No memory for ehea_port control block" ); + ret = -ENOMEM ; + goto kzalloc_failed; + } + + ehea_port_cb_0->port_rc =EHEA_BMASK_SET (PXLY_RC_VALID ,1 ) + |EHEA_BMASK_SET (PXLY_RC_IP_CHKSUM ,1 ) + |EHEA_BMASK_SET (PXLY_RC_TCP_UDP_CHKSUM ,1 ) + |EHEA_BMASK_SET (PXLY_RC_VLAN_XTRACT ,1 ) + |EHEA_BMASK_SET (PXLY_RC_VLAN_TAG_FILTER , +PXLY_RC_VLAN_FILTER ) + |EHEA_BMASK_SET (PXLY_RC_JUMBO_FRAME ,1 ); + +for (i =0 ; i < port->num_def_qps; i++) { + ehea_port_cb_0->default_qpn_array[i] = + port->port_res[i].qp->init_attr.qp_nr; + +EDEB (7 ,"default_qpn_array[%d]=%d" , + i, port->port_res[i].qp->init_attr.qp_nr); + } + +EDEB (7 ,"ehea_port_cb_0" ); +EDEB_DMP (7 , (u8 *)ehea_port_cb_0,sizeof (*ehea_port_cb_0),"" ); + + mask =EHEA_BMASK_SET (H_PORT_CB0_PRC ,1 ) + |EHEA_BMASK_SET (H_PORT_CB0_DEFQPNARRAY ,1 ); + + hret =ehea_h_modify_ehea_port (port->adapter->handle, + port->logical_port_id, +H_PORT_CB0 , + mask, + (void *)ehea_port_cb_0); + +if (hret !=H_SUCCESS ) { + goto modify_ehea_port_failed; + } + + ret =0 ; + +modify_ehea_port_failed: +kfree (ehea_port_cb_0);drivers/net/ehea/ehea_main.c line 941
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ +kzalloc_failed: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + + +static int ehea_gen_smrs (struct ehea_port_res *pr) +{ +u64 hret =H_HARDWARE ;No need to set hret. You do that a lot, int foo = 0; foo =
bar();Quoted 34 lines
drivers/net/ehea/ehea_main.c +34
-0+struct ehea_adapter *adapter = pr->port->adapter; +EDEB_EN (7 ,"ehea_port_res=%p" , pr); + hret =hipz_h_register_smr (adapter->handle, + adapter->mr.handle, + adapter->mr.vaddr, +EHEA_MR_ACC_CTRL , + adapter->pd, + &pr->send_mr); +if (hret !=H_SUCCESS ) + goto ehea_gen_smrs_err1; + + hret =hipz_h_register_smr (adapter->handle, + adapter->mr.handle, + adapter->mr.vaddr, +EHEA_MR_ACC_CTRL , + adapter->pd, + &pr->recv_mr); +if (hret !=H_SUCCESS ) + goto ehea_gen_smrs_err2; +EDEB_EX (7 ,"" ); +return 0 ; + +ehea_gen_smrs_err2: + hret =ehea_h_free_resource_mr (adapter->handle, pr->send_mr.handle); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Could not free SMR" ); +ehea_gen_smrs_err1: +return -EINVAL ; +} + +static void ehea_rem_smrs (struct ehea_port_res *pr) +{ +u64 hret =H_HARDWARE ; +struct ehea_adapter *adapter = pr->port->adapter;drivers/net/ehea/ehea_main.c line 985
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+EDEB_EN (7 ,"ehea_port_res=%p" , pr); + hret =ehea_h_free_resource_mr (adapter->handle, pr->send_mr.handle); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Could not free send SMR for pr=%p" , pr); + + hret =ehea_h_free_resource_mr (adapter->handle, pr->recv_mr.handle); +if (hret !=H_SUCCESS ) +EDEB_ERR (4 ,"Could not free receive SMR for pr=%p" , pr); +EDEB_EX (7 ,"" ); +}It's a bit worrying that this routine can fail, but returns void, ie. it can't report failure to its caller. (but perhaps it's ok).
Quoted 122 lines
drivers/net/ehea/ehea_main.c +122
-0+ +static int ehea_init_port_res (struct ehea_port *port,struct ehea_port_res *pr, +struct port_res_cfg *pr_cfg,int queue_token) +{ +int ret = -EINVAL ; +int max_rq_entries =0 ; +enum ehea_eq_type eq_type =EHEA_EQ ; +struct ehea_qp_init_attr *init_attr; +struct ehea_adapter *adapter = port->adapter; + +EDEB_EN (7 ,"port=%p, pr=%p" , port, pr); + +memset (pr,0 ,sizeof (struct ehea_port_res )); + + pr->port = port; +spin_lock_init (&pr->send_lock); +spin_lock_init (&pr->recv_lock); +spin_lock_init (&pr->xmit_lock); +spin_lock_init (&pr->netif_queue); + + pr->recv_eq =ehea_create_eq (adapter, eq_type, +EHEA_MAX_ENTRIES_EQ ,0 ); +if (!pr->recv_eq) { +EDEB_ERR (4 ,"ehea_create_eq failed (recv_eq)" ); + goto ehea_init_port_res_err1; + } + pr->send_eq =ehea_create_eq (adapter, eq_type, +EHEA_MAX_ENTRIES_EQ ,0 ); +if (!pr->send_eq) { +EDEB_ERR (4 ,"ehea_create_eq failed (send_eq)" ); + goto ehea_init_port_res_err2; + } + + pr->recv_cq =ehea_create_cq (adapter, pr_cfg->max_entries_rcq, + pr->recv_eq->ipz_eq_handle, + port->logical_port_id); +if (!pr->recv_cq) { +EDEB_ERR (4 ,"ehea_create_cq failed (cq_recv)" ); + goto ehea_init_port_res_err3; + } + + pr->send_cq =ehea_create_cq (adapter, pr_cfg->max_entries_scq, + pr->send_eq->ipz_eq_handle, + port->logical_port_id); +if (!pr->send_cq) { +EDEB_ERR (4 ,"ehea_create_cq failed (cq_send)" ); + goto ehea_init_port_res_err4; + } + + init_attr = (struct ehea_qp_init_attr *) +kzalloc (sizeof (struct ehea_qp_init_attr ),GFP_KERNEL ); + +if (!init_attr) { +EDEB_ERR (4 ,"no mem for init_attr struct" ); + ret = -ENOMEM ; + goto ehea_init_port_res_err5; + } + + init_attr->low_lat_rq1 =1 ; + init_attr->signalingtype =1 ;/* generate CQE if specified in WQE */ + init_attr->rq_count =3 ; + init_attr->qp_token = queue_token; + + init_attr->max_nr_send_wqes = pr_cfg->max_entries_sq; + init_attr->max_nr_rwqes_rq1 = pr_cfg->max_entries_rq1; + init_attr->max_nr_rwqes_rq2 = pr_cfg->max_entries_rq2; + init_attr->max_nr_rwqes_rq3 = pr_cfg->max_entries_rq3; + + init_attr->wqe_size_enc_sq =EHEA_SG_SQ ; + init_attr->wqe_size_enc_rq1 =EHEA_SG_RQ1 ; + init_attr->wqe_size_enc_rq2 =EHEA_SG_RQ2 ; + init_attr->wqe_size_enc_rq3 =EHEA_SG_RQ3 ; + + init_attr->rq2_threshold =EHEA_RQ2_THRESHOLD ; + init_attr->rq3_threshold =EHEA_RQ3_THRESHOLD ; + init_attr->port_nr = port->logical_port_id; + init_attr->send_cq_handle = pr->send_cq->ipz_cq_handle; + init_attr->recv_cq_handle = pr->recv_cq->ipz_cq_handle; + init_attr->aff_eq_handle = port->qp_eq->ipz_eq_handle; + + pr->qp =ehea_create_qp (adapter, adapter->pd, init_attr); +if (!pr->qp) { +EDEB_ERR (4 ,"could not create queue pair" ); + goto ehea_init_port_res_err6; + } + +/* SQ */ + max_rq_entries = init_attr->act_nr_send_wqes; + pr->skb_arr_sq = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_sq) { +EDEB_ERR (4 ,"vmalloc for skb_arr_sq failed" ); + goto ehea_init_port_res_err7; + } +memset (pr->skb_arr_sq,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_sq_index =0 ; + pr->skb_arr_sq_len = max_rq_entries +1 ; + +/* RQ 1 */ + max_rq_entries = init_attr->act_nr_rwqes_rq1; + pr->skb_arr_rq1 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_rq1) { +EDEB_ERR (4 ,"vmalloc for skb_arr_rq1 failed" ); + goto ehea_init_port_res_err8; + } +memset (pr->skb_arr_rq1,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_arr_rq1_len = max_rq_entries +1 ; + +/* RQ 2 */ + max_rq_entries = init_attr->act_nr_rwqes_rq2; + pr->skb_arr_rq2 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_rq2) { +EDEB_ERR (4 ,"vmalloc for skb_arr_rq2 failed" ); + goto ehea_init_port_res_err9; + } +memset (pr->skb_arr_rq2,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_arr_rq2_len = max_rq_entries; + pr->skb_rq2_index =0 ; + +/* RQ 3 */ drivers/net/ehea/ehea_main.c line 1117
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ max_rq_entries = init_attr->act_nr_rwqes_rq3; + pr->skb_arr_rq3 = (struct sk_buff **)vmalloc (sizeof (struct sk_buff *) + * (max_rq_entries +1 )); +if (!pr->skb_arr_rq3) { +EDEB_ERR (4 ,"vmalloc for skb_arr_rq3 failed" ); + goto ehea_init_port_res_err10; + } +memset (pr->skb_arr_rq3,0 ,sizeof (void *) * (max_rq_entries +1 )); + pr->skb_arr_rq3_len = max_rq_entries; + pr->skb_rq3_index =0 ;You shouldn't need the sk_buff** casts here. You probably should use kzalloc here, instead of vmalloc + memset. Depends on how big
max_rq_entriescan be.Quoted 32 lines
drivers/net/ehea/ehea_main.c +32
-0+ +if (ehea_gen_smrs (pr) !=0 ) + goto ehea_init_port_res_err11; +tasklet_init (&pr->send_comp_task, ehea_send_irq_tasklet, + (unsigned long )pr); +atomic_set (&pr->swqe_avail,EHEA_MAX_ENTRIES_SQ -1 ); + +kfree (init_attr); + ret =0 ; + goto done; + +ehea_init_port_res_err11: +vfree (pr->skb_arr_rq3); +ehea_init_port_res_err10: +vfree (pr->skb_arr_rq2); +ehea_init_port_res_err9: +vfree (pr->skb_arr_rq1); +ehea_init_port_res_err8: +vfree (pr->skb_arr_sq); +ehea_init_port_res_err7: +ehea_destroy_qp (pr->qp); +ehea_init_port_res_err6: +kfree (init_attr); +ehea_init_port_res_err5: +ehea_destroy_cq (pr->send_cq); +ehea_init_port_res_err4: +ehea_destroy_cq (pr->recv_cq); +ehea_init_port_res_err3: +ehea_destroy_eq (pr->send_eq); +ehea_init_port_res_err2: +ehea_destroy_eq (pr->recv_eq); +ehea_init_port_res_err1:
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 1153
Quoted 4 lines
drivers/net/ehea/ehea_main.c +4
-0+done: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +}You can vfree/kfree a NULL pointer, so you can probably amalgamate some of these error cases if you initialise the pointers to NULL at the beginning.
very good point, this mechanism can also be used for ehea_destroy_xx which will simplify the error path.
done
Quoted 74 lines
Quoted 17 lines
drivers/net/ehea/ehea_main.c +17
-0+ +static int ehea_clean_port_res (struct ehea_port *port,struct ehea_port_res *pr) +{ +int i; +int ret = -EINVAL ; + +EDEB_EN (7 ,"Not completed yet..." ); + + ret =ehea_destroy_qp (pr->qp); +if (ret) +EDEB_ERR (4 ,"could not destroy queue pair" ); + + ret =ehea_destroy_cq (pr->send_cq); +if (ret) +EDEB_ERR (4 ,"could not destroy send_cq" ); + + ret =ehea_destroy_cq (pr->recv_cq);drivers/net/ehea/ehea_main.c line 1180
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+if (ret) +EDEB_ERR (4 ,"could not destroy recv_cq" ); + + ret =ehea_destroy_eq (pr->send_eq); +if (ret) +EDEB_ERR (4 ,"could not destroy send_eq" ); + + ret =ehea_destroy_eq (pr->recv_eq); +if (ret) +EDEB_ERR (4 ,"could not destroy recv_eq" );If these are leaking memory they're probably worth a printk.
Quoted 44 lines
drivers/net/ehea/ehea_main.c +43
-0+for (i =0 ; i < pr->skb_arr_rq1_len; i++) { +if (pr->skb_arr_rq1[i]) +dev_kfree_skb (pr->skb_arr_rq1[i]); + } + +for (i =0 ; i < pr->skb_arr_rq2_len; i++) +if (pr->skb_arr_rq2[i]) +dev_kfree_skb (pr->skb_arr_rq2[i]); + +for (i =0 ; i < pr->skb_arr_rq3_len; i++) +if (pr->skb_arr_rq3[i]) +dev_kfree_skb (pr->skb_arr_rq3[i]); + +for (i =0 ; i < pr->skb_arr_sq_len; i++) +if (pr->skb_arr_sq[i]) +dev_kfree_skb (pr->skb_arr_sq[i]); + +vfree (pr->skb_arr_sq); +vfree (pr->skb_arr_rq1); +vfree (pr->skb_arr_rq2); +vfree (pr->skb_arr_rq3); + +ehea_rem_smrs (pr); +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static inline void write_ip_start_end (struct ehea_swqe *swqe, +const struct sk_buff *skb) +{ + + swqe->ip_start = (u8)(((u64 )skb->nh.iph) - ((u64 )skb->data)); + swqe->ip_end = (u8)(swqe->ip_start + skb->nh.iph->ihl *4 -1 ); +} +static inline void write_tcp_offset_end (struct ehea_swqe *swqe, +const struct sk_buff *skb) +{ + swqe->tcp_offset = (u8)(swqe->ip_end +1 + offsetof(struct tcphdr , + check)); + swqe->tcp_end = (u16 )skb->len -1 ; +} + +static inline void write_udp_offset_end(struct ehea_swqe *swqe,
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 1231
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+ const struct sk_buff *skb) +{ + swqe->tcp_offset = (u8)(swqe->ip_end +1 + offsetof(struct udphdr , + check)); + swqe->tcp_end = (u16 )skb->len -1 ; +}These three need some explanation at best.
ok, done
Quoted 171 lines
Quoted 134 lines
drivers/net/ehea/ehea_main.c +134
-0+ +static inline void write_swqe2_data (struct sk_buff *skb, +struct net_device *dev, +struct ehea_swqe *swqe, +u32 lkey) +{ +int skb_data_size, nfrags, headersize, i, sg1entry_contains_frag_data; +struct ehea_vsgentry *sg_list; +struct ehea_vsgentry *sg1entry; +struct ehea_vsgentry *sgentry; +u8 *imm_data; +u64 tmp_addr; +skb_frag_t *frag; +EDEB_EN (7 ,"" ); + + skb_data_size = skb->len - skb->data_len; + nfrags =skb_shinfo (skb)->nr_frags; + sg1entry = &swqe->u.immdata_desc.sg_entry; + sg_list = (struct ehea_vsgentry *)&swqe->u.immdata_desc.sg_list; + imm_data = &swqe->u.immdata_desc.immediate_data[0 ]; + swqe->descriptors =0 ; + sg1entry_contains_frag_data =0 ; + +if ((dev->features &NETIF_F_TSO ) &&skb_shinfo (skb)->gso_size) { +/* Packet is TCP with TSO enabled */ + swqe->tx_control |=EHEA_SWQE_TSO ; + swqe->mss =skb_shinfo (skb)->gso_size; +/* copy only eth/ip/tcp headers to immediate data and +* the rest of skb->data to sg1entry +*/ + headersize =ETH_HLEN + (skb->nh.iph->ihl *4 ) + + skb->h.th->doff *4 ; + skb_data_size = skb->len - skb->data_len; + +if (skb_data_size >= headersize) { +/* copy immediate data */ +memcpy (imm_data, skb->data, headersize); + swqe->immediate_data_length = headersize; + +if (skb_data_size > headersize) { +/* set sg1entry data */ + sg1entry->l_key = lkey; + sg1entry->len = skb_data_size - headersize; + + tmp_addr = (u64)(skb->data + headersize); + sg1entry->vaddr = +get_swqe_addr (tmp_addr,0 ); + + swqe->descriptors++; + } + }else +EDEB_ERR (4 ,"Cannot handle fragmented headers" ); + }else { +/* Packet is any nonTSO type +* +* Copy as much as possible skb->data to immediate data and +* the rest to sg1entry +*/ +if (skb_data_size >=SWQE2_MAX_IMM ) { +/* copy immediate data */ +memcpy (imm_data, skb->data,SWQE2_MAX_IMM ); + + swqe->immediate_data_length =SWQE2_MAX_IMM ; + +if (skb_data_size >SWQE2_MAX_IMM ) { +/* copy sg1entry data */ + sg1entry->l_key = lkey; + sg1entry->len = skb_data_size -SWQE2_MAX_IMM ; + tmp_addr = (u64)(skb->data +SWQE2_MAX_IMM ); + sg1entry->vaddr =get_swqe_addr (tmp_addr,0 ); + swqe->descriptors++; + } + }else { +memcpy (imm_data, skb->data, skb_data_size); + swqe->immediate_data_length = skb_data_size; + } + } + +/* write descriptors */ +if (nfrags >0 ) { +if (swqe->descriptors ==0 ) { +/* sg1entry not yet used */ + frag = &skb_shinfo (skb)->frags[0 ]; + +/* copy sg1entry data */ + sg1entry->l_key = lkey; + sg1entry->len = frag->size; + tmp_addr = (u64)(page_address (frag->page) + + frag->page_offset); + sg1entry->vaddr =get_swqe_addr (tmp_addr, +EHEA_MR_TX_DATA_PN ); + swqe->descriptors++; + sg1entry_contains_frag_data =1 ; + } + +for (i = sg1entry_contains_frag_data; i < nfrags; i++) { + + frag = &skb_shinfo (skb)->frags[i]; + sgentry = &sg_list[i - sg1entry_contains_frag_data]; + + sgentry->l_key = lkey; + sgentry->len = frag->size; + + tmp_addr = (u64)(page_address (frag->page) + + frag->page_offset); + sgentry->vaddr =get_swqe_addr (tmp_addr, +EHEA_MR_TX_DATA_PN + i); + } + } + +EDEB_EX (7 ,"" ); +} + +static int ehea_ioctl (struct net_device *dev,struct ifreq *ifr,int cmd) +{ +EDEB_ERR (4 ,"ioctl not supported: dev=%s cmd=%d" , dev->name, cmd); +return -EOPNOTSUPP ; +} + +static u64 ehea_broadcast_reg_helper (struct ehea_port *port,u32 hcallid) +{ +u64 hret =H_HARDWARE ; +u8 reg_type =0 ; + +if (hcallid ==H_REG_BCMC ) { +EDEB (7 ,"REGistering MAC for broadcast" ); + }else { +EDEB (7 ,"DEREGistering MAC for broadcast" ); + } + +/* De/Register untagged packets */ + reg_type =EHEA_BCMC_BROADCAST |EHEA_BCMC_UNTAGGED ; + hret = ehea_h_reg_dereg_bcmc(port->adapter->handle, + port->logical_port_id,drivers/net/ehea/ehea_main.c line 1375
Quoted 10 lines
drivers/net/ehea/ehea_main.c +10
-0+ reg_type, port->mac_addr, 0, hcallid); +if (hret !=H_SUCCESS ) + goto hcall_failed; + +/* De/Register VLAN packets */ + reg_type =EHEA_BCMC_BROADCAST |EHEA_BCMC_VLANID_ALL ; + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, port->mac_addr,0 , hcallid); +hcall_failed:unregister here?
Quoted 24 lines
drivers/net/ehea/ehea_main.c +24
-0+return hret; +} + +static int ehea_set_mac_addr (struct net_device *dev,void *sa) +{ +int ret = -EOPNOTSUPP ; +u64 hret =H_HARDWARE ; +struct hcp_query_ehea_port_cb_0 *ehea_port_cb_0 =NULL ; +struct ehea_port *port = (struct ehea_port *)dev->priv; +struct sockaddr *mac_addr = (struct sockaddr *)sa; + +EDEB_EN (7 ,"devname=%s" , dev->name); +EDEB_DMP (7 , (u8 *)&(mac_addr->sa_data[0 ]),14 ,"" ); + +if (!is_valid_ether_addr (mac_addr->sa_data)) { + ret = -EADDRNOTAVAIL ; + goto invalid_mac; + } + + ehea_port_cb_0 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL ); + +if (!ehea_port_cb_0) { +EDEB_ERR (4 ,"No memory for ehea_port control block" ); + ret = -ENOMEM ;
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 1404
Quoted 5 lines
drivers/net/ehea/ehea_main.c +5
-0+ goto kzalloc_failed; + } + +memcpy ((u8 *)(&(ehea_port_cb_0->port_mac_addr)), + (u8 *)&(mac_addr->sa_data[0 ]),6 );Don't need casts, memcpy takes void *. You should use
ETH_ALEN(include/linux/if_ether.h) instead of 6.
done
Quoted 18 lines
Quoted 18 lines
drivers/net/ehea/ehea_main.c +18
-0+ + ehea_port_cb_0->port_mac_addr = ehea_port_cb_0->port_mac_addr >>16 ; + +EDEB (7 ,"ehea_port_cb_0" ); +EDEB_DMP (7 , (u8 *)ehea_port_cb_0, +sizeof (struct hcp_query_ehea_port_cb_0 ),"" ); + + hret =ehea_h_modify_ehea_port (port->adapter->handle, + port->logical_port_id, +H_PORT_CB0 , +EHEA_BMASK_SET (H_PORT_CB0_MAC ,1 ), + (void *)ehea_port_cb_0); +if (hret !=H_SUCCESS ) { + ret = -EOPNOTSUPP ; + goto hcall_failed; + } + +memcpy (dev->dev_addr, mac_addr->sa_data, dev->addr_len);
Quoted 9 lines
drivers/net/ehea/ehea_main.c line 1428
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+ +/* Deregister old MAC in PHYP */ + hret =ehea_broadcast_reg_helper (port,H_DEREG_BCMC ); +if (hret) { + ret = -EOPNOTSUPP ; + goto hcall_failed;What happens here? No mac? Old mac?
good question, we have to think about a reasonable recovery strategy
Quoted 94 lines
Quoted 94 lines
drivers/net/ehea/ehea_main.c +94
-0+ } + + port->mac_addr = ehea_port_cb_0->port_mac_addr <<16 ; + +/* Register new MAC in PHYP */ + hret =ehea_broadcast_reg_helper (port,H_REG_BCMC ); +if (hret) { + ret = -EOPNOTSUPP ; + goto hcall_failed; + } + + ret =0 ; + +hcall_failed: +kfree (ehea_port_cb_0); + +kzalloc_failed: +invalid_mac: +EDEB_EX (7 ,"ret=%d" , ret); +return ret; +} + +static void ehea_promiscuous (struct net_device *dev,int enable) +{ +struct ehea_port *port = dev->priv; + +if (!port->promisc) { +if (enable) { +/* Enable promiscuous mode */ +EDEB (7 ,"Enabling IFF_PROMISC" ); +EDEB_ERR (4 ,"Enable promiscuous mode: " +"not yet implemented" ); + port->promisc =EHEA_ENABLE ; + } + }else { +if (!enable) { +/* Disable promiscuous mode */ +EDEB (7 ,"Disabling IFF_PROMISC" ); +EDEB_ERR (4 ,"Disable promiscuous mode: " +"not yet implemented" ); + port->promisc =EHEA_DISABLE ; + } + } +} + +static u64 ehea_multicast_reg_helper (struct ehea_port *port, +u64 mc_mac_addr, +u32 hcallid) +{ +u64 hret =H_HARDWARE ; +u8 reg_type =0 ; + + reg_type =EHEA_BCMC_SCOPE_ALL |EHEA_BCMC_MULTICAST + |EHEA_BCMC_UNTAGGED ; + + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, mc_mac_addr,0 , hcallid); +if (hret) + goto hcall_failed; + + reg_type =EHEA_BCMC_SCOPE_ALL |EHEA_BCMC_MULTICAST + |EHEA_BCMC_VLANID_ALL ; + + hret =ehea_h_reg_dereg_bcmc (port->adapter->handle, + port->logical_port_id, + reg_type, mc_mac_addr,0 , hcallid); +hcall_failed: +return hret; +} + +static int ehea_drop_multicast_list (struct net_device *dev) +{ +int ret =0 ; +u64 hret =H_HARDWARE ; +struct ehea_port *port = dev->priv; +struct ehea_mc_list *mc_entry = port->mc_list; +struct list_head *pos; +struct list_head *temp; + +EDEB_EN (7 ,"devname=%s" , dev->name); + +if (!list_empty (&mc_entry->list)) { +list_for_each_safe (pos, temp, &(port->mc_list->list)) { + mc_entry = list_entry(pos, struct ehea_mc_list, list); + +EDEB (7 ,"Deregistering MAC %lx" , mc_entry->macaddr); + + hret =ehea_multicast_reg_helper (port, + mc_entry->macaddr, +H_DEREG_BCMC ); +if (hret) { +EDEB_ERR (4 ,"Failed deregistering mcast MAC" ); + ret = -EINVAL ;
Quoted 10 lines
drivers/net/ehea/ehea_main.c line 1528
Quoted 6 lines
drivers/net/ehea/ehea_main.c +6
-0+ } + +list_del (pos); +kfree (mc_entry); + } + }You don't need the if.
ok, removed
Quoted 4 lines
Ok, I'm tired now, I might read the rest later.
cheers
Hi,
Quoted 3 lines
---
linux-2.6.18-rc4-orig/drivers/net/ehea/ehea_main.c1969-12-31+#define
DEB_PREFIX"main"
Doesnt appear to be used.
Quoted 1 line
+static struct
net_device_stats*ehea_get_stats(structnet_device*dev)
...
drivers/net/ehea/ehea_main.c line 70
Quoted 1 line
drivers/net/ehea/ehea_main.c +1
-0+ cb2 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL );
I cant see where this gets freed.
drivers/net/ehea/ehea_main.c line 566
Quoted 4 lines
drivers/net/ehea/ehea_main.c +4
-0+ + skb_index = ((index - i + + port_res->skb_arr_sq_len) + % port_res->skb_arr_sq_len);
This is going to force an expensive divide. Its much better to change this to the simpler and quicker:
i++;
if (i > max)
i = 0;
There are a few places in the driver can be changed to do this.
Quoted 2 lines
(quoted diff) +2
-0+static int ehea_setup_single_port(struct ehea_adapter *adapter,A + int portnum, struct device_node *dn)
...
drivers/net/ehea/ehea_main.c line 2472
Quoted 1 line
drivers/net/ehea/ehea_main.c +1
-0+ cb4 =kzalloc (H_CB_ALIGNMENT ,GFP_KERNEL );
I cant see where this is freed.
Anton
Quoted 9 lines · Anton Blanchard
drivers/net/ehea/ehea_main.c line 566
Quoted 5 lines
drivers/net/ehea/ehea_main.c +4
-0+ + skb_index = ((index - i + + port_res->skb_arr_sq_len) + % port_res->skb_arr_sq_len);This is going to force an expensive divide. Its much better to change this to the simpler and quicker:
Quoted 3 lines
i++;
if (i > max)i = 0;
Is a conditional cheaper than a divide? In case of a misprediction I would assume it to be significantly slower and I don't know the ratio of mispredictions for this branch.
Jörn
Signature · 2 lines
Victory in war is not repetitious. -- Sun Tzu
Quoted 4 lines
Is a conditional cheaper than a divide? In case of a misprediction I would assume it to be significantly slower and I don't know the ratio of mispredictions for this branch.
A quick scan of the web shows 40 cycles for athlon64 idiv, and its similarly slow on many other cpus. Even assuming you mispredict every branch its going to be a win.
Anton
Hi,
Quoted 9 lines · Anton Blanchard
Quoted 3 lines
Is a conditional cheaper than a divide? In case of a misprediction I would assume it to be significantly slower and I don't know the ratio of mispredictions for this branch.
A quick scan of the web shows 40 cycles for athlon64 idiv, and its similarly slow on many other cpus. Even assuming you mispredict every branch its going to be a win.
Anton
as our queue size is always a power of 2, we simply use:
i++;
i &= (ringbufferlength - 1)
So we can get along without the if.
Jan-Bernd
Quoted 6 lines · Jan-Bernd Themann
as our queue size is always a power of 2, we simply use:
i++;
i &= (ringbufferlength - 1)So we can get along without the if.
The recommended (by Linus) way for dealing with ring buffers like that is to always read the counter through an accessor and don't care about the overflow when updating it.
You can write small access functions for that:
struct my_struct {
...
unsigned rbuf_index;
unsigned rbuf_mask;
...
};static inline unsigned int my_index(struct my_struct *p)
{
return p->rb_index & p->rb_mask;
}static inline unsigned int my_index_next(struct my_struct *p)
{
return (++p->rb_index) & p->rb_mask;
}Arnd <><