X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fnet%2Fbenet%2Fbe_main.c;h=2db879c03c6d66e7c274bfc3a72936b4f4c35c1d;hb=ca00392cb8f5227c67ff52c656d91a764d022ab9;hp=347d002fa4251e37b704eafee089768e484ea3c8;hpb=ebc8d2ab61dde6cf775ae7bb1ed9e38dfe12ca65;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 347d002..2db879c 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c @@ -16,6 +16,7 @@ */ #include "be.h" +#include "be_cmds.h" #include MODULE_VERSION(DRV_VER); @@ -60,60 +61,39 @@ static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q, return 0; } -static inline void *queue_head_node(struct be_queue_info *q) +static void be_intr_set(struct be_adapter *adapter, bool enable) { - return q->dma_mem.va + q->head * q->entry_size; -} - -static inline void *queue_tail_node(struct be_queue_info *q) -{ - return q->dma_mem.va + q->tail * q->entry_size; -} - -static inline void queue_head_inc(struct be_queue_info *q) -{ - index_inc(&q->head, q->len); -} - -static inline void queue_tail_inc(struct be_queue_info *q) -{ - index_inc(&q->tail, q->len); -} - -static void be_intr_set(struct be_ctrl_info *ctrl, bool enable) -{ - u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; + u8 __iomem *addr = adapter->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET; u32 reg = ioread32(addr); u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - if (!enabled && enable) { + + if (!enabled && enable) reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - } else if (enabled && !enable) { + else if (enabled && !enable) reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK; - } else { - printk(KERN_WARNING DRV_NAME - ": bad value in membar_int_ctrl reg=0x%x\n", reg); + else return; - } + iowrite32(reg, addr); } -static void be_rxq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted) +static void be_rxq_notify(struct be_adapter *adapter, u16 qid, u16 posted) { u32 val = 0; val |= qid & DB_RQ_RING_ID_MASK; val |= posted << DB_RQ_NUM_POSTED_SHIFT; - iowrite32(val, ctrl->db + DB_RQ_OFFSET); + iowrite32(val, adapter->db + DB_RQ_OFFSET); } -static void be_txq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted) +static void be_txq_notify(struct be_adapter *adapter, u16 qid, u16 posted) { u32 val = 0; val |= qid & DB_TXULP_RING_ID_MASK; val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT; - iowrite32(val, ctrl->db + DB_TXULP1_OFFSET); + iowrite32(val, adapter->db + DB_TXULP1_OFFSET); } -static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid, +static void be_eq_notify(struct be_adapter *adapter, u16 qid, bool arm, bool clear_int, u16 num_popped) { u32 val = 0; @@ -124,18 +104,17 @@ static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid, val |= 1 << DB_EQ_CLR_SHIFT; val |= 1 << DB_EQ_EVNT_SHIFT; val |= num_popped << DB_EQ_NUM_POPPED_SHIFT; - iowrite32(val, ctrl->db + DB_EQ_OFFSET); + iowrite32(val, adapter->db + DB_EQ_OFFSET); } -static void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid, - bool arm, u16 num_popped) +void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm, u16 num_popped) { u32 val = 0; val |= qid & DB_CQ_RING_ID_MASK; if (arm) val |= 1 << DB_CQ_REARM_SHIFT; val |= num_popped << DB_CQ_NUM_POPPED_SHIFT; - iowrite32(val, ctrl->db + DB_CQ_OFFSET); + iowrite32(val, adapter->db + DB_CQ_OFFSET); } @@ -146,12 +125,12 @@ static int be_mac_addr_set(struct net_device *netdev, void *p) int status = 0; if (netif_running(netdev)) { - status = be_cmd_pmac_del(&adapter->ctrl, adapter->if_handle, + status = be_cmd_pmac_del(adapter, adapter->if_handle, adapter->pmac_id); if (status) return status; - status = be_cmd_pmac_add(&adapter->ctrl, (u8 *)addr->sa_data, + status = be_cmd_pmac_add(adapter, (u8 *)addr->sa_data, adapter->if_handle, &adapter->pmac_id); } @@ -168,6 +147,7 @@ static void netdev_stats_update(struct be_adapter *adapter) struct be_port_rxf_stats *port_stats = &rxf_stats->port[adapter->port_num]; struct net_device_stats *dev_stats = &adapter->stats.net_stats; + struct be_erx_stats *erx_stats = &hw_stats->erx; dev_stats->rx_packets = port_stats->rx_total_frames; dev_stats->tx_packets = port_stats->tx_unicastframes + @@ -181,29 +161,33 @@ static void netdev_stats_update(struct be_adapter *adapter) dev_stats->rx_errors = port_stats->rx_crc_errors + port_stats->rx_alignment_symbol_errors + port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; - - /* packet transmit problems */ - dev_stats->tx_errors = 0; - - /* no space in linux buffers */ - dev_stats->rx_dropped = 0; - - /* no space available in linux */ - dev_stats->tx_dropped = 0; - - dev_stats->multicast = port_stats->tx_multicastframes; - dev_stats->collisions = 0; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long + + port_stats->rx_dropped_too_small + + port_stats->rx_dropped_too_short + + port_stats->rx_dropped_header_too_small + + port_stats->rx_dropped_tcp_length + + port_stats->rx_dropped_runt + + port_stats->rx_tcp_checksum_errs + + port_stats->rx_ip_checksum_errs + + port_stats->rx_udp_checksum_errs; + + /* no space in linux buffers: best possible approximation */ + dev_stats->rx_dropped = erx_stats->rx_drops_no_fragments[0]; /* detailed rx errors */ dev_stats->rx_length_errors = port_stats->rx_in_range_errors + - port_stats->rx_out_range_errors + port_stats->rx_frame_too_long; + port_stats->rx_out_range_errors + + port_stats->rx_frame_too_long; + /* receive ring buffer overflow */ dev_stats->rx_over_errors = 0; + dev_stats->rx_crc_errors = port_stats->rx_crc_errors; /* frame alignment errors */ dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors; + /* receiver fifo overrun */ /* drops_no_pbuf is no per i/f, it's per BE card */ dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow + @@ -211,6 +195,16 @@ static void netdev_stats_update(struct be_adapter *adapter) rxf_stats->rx_drops_no_pbuf; /* receiver missed packetd */ dev_stats->rx_missed_errors = 0; + + /* packet transmit problems */ + dev_stats->tx_errors = 0; + + /* no space available in linux */ + dev_stats->tx_dropped = 0; + + dev_stats->multicast = port_stats->tx_multicastframes; + dev_stats->collisions = 0; + /* detailed tx_errors */ dev_stats->tx_aborted_errors = 0; dev_stats->tx_carrier_errors = 0; @@ -219,34 +213,28 @@ static void netdev_stats_update(struct be_adapter *adapter) dev_stats->tx_window_errors = 0; } -static void be_link_status_update(struct be_adapter *adapter) +void be_link_status_update(struct be_adapter *adapter, bool link_up) { - struct be_link_info *prev = &adapter->link; - struct be_link_info now = { 0 }; struct net_device *netdev = adapter->netdev; - be_cmd_link_status_query(&adapter->ctrl, &now); - /* If link came up or went down */ - if (now.speed != prev->speed && (now.speed == PHY_LINK_SPEED_ZERO || - prev->speed == PHY_LINK_SPEED_ZERO)) { - if (now.speed == PHY_LINK_SPEED_ZERO) { - netif_stop_queue(netdev); - netif_carrier_off(netdev); - printk(KERN_INFO "%s: Link down\n", netdev->name); - } else { + if (adapter->link_up != link_up) { + if (link_up) { netif_start_queue(netdev); netif_carrier_on(netdev); printk(KERN_INFO "%s: Link up\n", netdev->name); + } else { + netif_stop_queue(netdev); + netif_carrier_off(netdev); + printk(KERN_INFO "%s: Link down\n", netdev->name); } + adapter->link_up = link_up; } - *prev = now; } /* Update the EQ delay n BE based on the RX frags consumed / sec */ static void be_rx_eqd_update(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_drvr_stats *stats = &adapter->stats.drvr_stats; ulong now = jiffies; @@ -279,7 +267,7 @@ static void be_rx_eqd_update(struct be_adapter *adapter) if (eqd < 10) eqd = 0; if (eqd != rx_eq->cur_eqd) - be_cmd_modify_eqd(ctrl, rx_eq->q.id, eqd); + be_cmd_modify_eqd(adapter, rx_eq->q.id, eqd); rx_eq->cur_eqd = eqd; } @@ -421,8 +409,8 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i]; busaddr = pci_map_page(pdev, frag->page, - frag->page_offset, - frag->size, PCI_DMA_TODEVICE); + frag->page_offset, + frag->size, PCI_DMA_TODEVICE); wrb = queue_head_node(txq); wrb_fill(wrb, busaddr, frag->size); be_dws_cpu_to_le(wrb, sizeof(*wrb)); @@ -470,7 +458,7 @@ static int be_xmit(struct sk_buff *skb, struct net_device *netdev) stopped = true; } - be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt); + be_txq_notify(adapter, txq->id, wrb_cnt); be_tx_stats_update(adapter, wrb_cnt, copied, stopped); return NETDEV_TX_OK; @@ -511,10 +499,10 @@ static void be_vid_config(struct net_device *netdev) ntags++; } } - be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle, + be_cmd_vlan_config(adapter, adapter->if_handle, vtag, ntags, 1, 0); } else { - be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle, + be_cmd_vlan_config(adapter, adapter->if_handle, NULL, 0, 1, 1); } } @@ -524,13 +512,12 @@ static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp) struct be_adapter *adapter = netdev_priv(netdev); struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; - struct be_ctrl_info *ctrl = &adapter->ctrl; - be_eq_notify(ctrl, rx_eq->q.id, false, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, false, false, 0); + be_eq_notify(adapter, rx_eq->q.id, false, false, 0); + be_eq_notify(adapter, tx_eq->q.id, false, false, 0); adapter->vlan_grp = grp; - be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); + be_eq_notify(adapter, rx_eq->q.id, true, false, 0); + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); } static void be_vlan_add_vid(struct net_device *netdev, u16 vid) @@ -554,47 +541,31 @@ static void be_vlan_rem_vid(struct net_device *netdev, u16 vid) be_vid_config(netdev); } -static void be_set_multicast_filter(struct net_device *netdev) +static void be_set_multicast_list(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct dev_mc_list *mc_ptr; - u8 mac_addr[32][ETH_ALEN]; - int i = 0; - if (netdev->flags & IFF_ALLMULTI) { - /* set BE in Multicast promiscuous */ - be_cmd_mcast_mac_set(&adapter->ctrl, - adapter->if_handle, NULL, 0, true); - return; + if (netdev->flags & IFF_PROMISC) { + be_cmd_promiscuous_config(adapter, adapter->port_num, 1); + adapter->promiscuous = true; + goto done; } - for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) { - memcpy(&mac_addr[i][0], mc_ptr->dmi_addr, ETH_ALEN); - if (++i >= 32) { - be_cmd_mcast_mac_set(&adapter->ctrl, - adapter->if_handle, &mac_addr[0][0], i, false); - i = 0; - } - + /* BE was previously in promiscous mode; disable it */ + if (adapter->promiscuous) { + adapter->promiscuous = false; + be_cmd_promiscuous_config(adapter, adapter->port_num, 0); } - if (i) { - /* reset the promiscuous mode also. */ - be_cmd_mcast_mac_set(&adapter->ctrl, - adapter->if_handle, &mac_addr[0][0], i, false); + if (netdev->flags & IFF_ALLMULTI) { + be_cmd_multicast_set(adapter, adapter->if_handle, NULL, 0); + goto done; } -} -static void be_set_multicast_list(struct net_device *netdev) -{ - struct be_adapter *adapter = netdev_priv(netdev); - - if (netdev->flags & IFF_PROMISC) { - be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 1); - } else { - be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 0); - be_set_multicast_filter(netdev); - } + be_cmd_multicast_set(adapter, adapter->if_handle, netdev->mc_list, + netdev->mc_count); +done: + return; } static void be_rx_rate_update(struct be_adapter *adapter) @@ -690,8 +661,8 @@ static void skb_fill_rx_data(struct be_adapter *adapter, { struct be_queue_info *rxq = &adapter->rx_obj.q; struct be_rx_page_info *page_info; - u16 rxq_idx, i, num_rcvd; - u32 pktsize, hdr_len, curr_frag_len; + u16 rxq_idx, i, num_rcvd, j; + u32 pktsize, hdr_len, curr_frag_len, size; u8 *start; rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); @@ -728,33 +699,45 @@ static void skb_fill_rx_data(struct be_adapter *adapter, if (pktsize <= rx_frag_size) { BUG_ON(num_rcvd != 1); - return; + goto done; } /* More frags present for this completion */ - pktsize -= curr_frag_len; /* account for above copied frag */ - for (i = 1; i < num_rcvd; i++) { + size = pktsize; + for (i = 1, j = 0; i < num_rcvd; i++) { + size -= curr_frag_len; index_inc(&rxq_idx, rxq->len); page_info = get_rx_page_info(adapter, rxq_idx); - curr_frag_len = min(pktsize, rx_frag_size); + curr_frag_len = min(size, rx_frag_size); + + /* Coalesce all frags from the same physical page in one slot */ + if (page_info->page_offset == 0) { + /* Fresh page */ + j++; + skb_shinfo(skb)->frags[j].page = page_info->page; + skb_shinfo(skb)->frags[j].page_offset = + page_info->page_offset; + skb_shinfo(skb)->frags[j].size = 0; + skb_shinfo(skb)->nr_frags++; + } else { + put_page(page_info->page); + } - skb_shinfo(skb)->frags[i].page = page_info->page; - skb_shinfo(skb)->frags[i].page_offset = page_info->page_offset; - skb_shinfo(skb)->frags[i].size = curr_frag_len; + skb_shinfo(skb)->frags[j].size += curr_frag_len; skb->len += curr_frag_len; skb->data_len += curr_frag_len; - skb_shinfo(skb)->nr_frags++; - pktsize -= curr_frag_len; memset(page_info, 0, sizeof(*page_info)); } + BUG_ON(j > MAX_SKB_FRAGS); +done: be_rx_stats_update(adapter, pktsize, num_rcvd); return; } -/* Process the RX completion indicated by rxcp when LRO is disabled */ +/* Process the RX completion indicated by rxcp when GRO is disabled */ static void be_rx_compl_process(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { @@ -801,40 +784,61 @@ static void be_rx_compl_process(struct be_adapter *adapter, return; } -/* Process the RX completion indicated by rxcp when LRO is enabled */ -static void be_rx_compl_process_lro(struct be_adapter *adapter, +/* Process the RX completion indicated by rxcp when GRO is enabled */ +static void be_rx_compl_process_gro(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { struct be_rx_page_info *page_info; - struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME]; + struct sk_buff *skb = NULL; struct be_queue_info *rxq = &adapter->rx_obj.q; + struct be_eq_obj *eq_obj = &adapter->rx_eq; u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len; - u16 i, rxq_idx = 0, vid; + u16 i, rxq_idx = 0, vid, j; num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp); pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp); vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp); rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp); + skb = napi_get_frags(&eq_obj->napi); + if (!skb) { + be_rx_compl_discard(adapter, rxcp); + return; + } + remaining = pkt_size; - for (i = 0; i < num_rcvd; i++) { + for (i = 0, j = -1; i < num_rcvd; i++) { page_info = get_rx_page_info(adapter, rxq_idx); curr_frag_len = min(remaining, rx_frag_size); - rx_frags[i].page = page_info->page; - rx_frags[i].page_offset = page_info->page_offset; - rx_frags[i].size = curr_frag_len; - remaining -= curr_frag_len; + /* Coalesce all frags from the same physical page in one slot */ + if (i == 0 || page_info->page_offset == 0) { + /* First frag or Fresh page */ + j++; + skb_shinfo(skb)->frags[j].page = page_info->page; + skb_shinfo(skb)->frags[j].page_offset = + page_info->page_offset; + skb_shinfo(skb)->frags[j].size = 0; + } else { + put_page(page_info->page); + } + skb_shinfo(skb)->frags[j].size += curr_frag_len; + remaining -= curr_frag_len; index_inc(&rxq_idx, rxq->len); - memset(page_info, 0, sizeof(*page_info)); } + BUG_ON(j > MAX_SKB_FRAGS); + + skb_shinfo(skb)->nr_frags = j + 1; + skb->len = pkt_size; + skb->data_len = pkt_size; + skb->truesize += pkt_size; + skb->ip_summed = CHECKSUM_UNNECESSARY; if (likely(!vlanf)) { - lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size, - pkt_size, NULL, 0); + napi_gro_frags(&eq_obj->napi); } else { vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp); vid = be16_to_cpu(vid); @@ -842,9 +846,7 @@ static void be_rx_compl_process_lro(struct be_adapter *adapter, if (!adapter->vlan_grp || adapter->num_vlans == 0) return; - lro_vlan_hwaccel_receive_frags(&adapter->rx_obj.lro_mgr, - rx_frags, pkt_size, pkt_size, adapter->vlan_grp, - vid, NULL, 0); + vlan_gro_frags(&eq_obj->napi, adapter->vlan_grp, vid); } be_rx_stats_update(adapter, pkt_size, num_rcvd); @@ -860,12 +862,19 @@ static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter) be_dws_le_to_cpu(rxcp, sizeof(*rxcp)); - rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; - queue_tail_inc(&adapter->rx_obj.cq); return rxcp; } +/* To reset the valid bit, we need to reset the whole word as + * when walking the queue the valid entries are little-endian + * and invalid entries are host endian + */ +static inline void be_rx_compl_reset(struct be_eth_rx_compl *rxcp) +{ + rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0; +} + static inline struct page *be_alloc_pages(u32 size) { gfp_t alloc_flags = GFP_ATOMIC; @@ -928,7 +937,7 @@ static void be_post_rx_frags(struct be_adapter *adapter) if (posted) { atomic_add(posted, &rxq->used); - be_rxq_notify(&adapter->ctrl, rxq->id, posted); + be_rxq_notify(adapter, rxq->id, posted); } else if (atomic_read(&rxq->used) == 0) { /* Let be_worker replenish when memory is available */ adapter->rx_post_starved = true; @@ -937,10 +946,8 @@ static void be_post_rx_frags(struct be_adapter *adapter) return; } -static struct be_eth_tx_compl * -be_tx_compl_get(struct be_adapter *adapter) +static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq) { - struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq); if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0) @@ -986,6 +993,56 @@ static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index) kfree_skb(sent_skb); } +static inline struct be_eq_entry *event_get(struct be_eq_obj *eq_obj) +{ + struct be_eq_entry *eqe = queue_tail_node(&eq_obj->q); + + if (!eqe->evt) + return NULL; + + eqe->evt = le32_to_cpu(eqe->evt); + queue_tail_inc(&eq_obj->q); + return eqe; +} + +static int event_handle(struct be_adapter *adapter, + struct be_eq_obj *eq_obj) +{ + struct be_eq_entry *eqe; + u16 num = 0; + + while ((eqe = event_get(eq_obj)) != NULL) { + eqe->evt = 0; + num++; + } + + /* Deal with any spurious interrupts that come + * without events + */ + be_eq_notify(adapter, eq_obj->q.id, true, true, num); + if (num) + napi_schedule(&eq_obj->napi); + + return num; +} + +/* Just read and notify events without processing them. + * Used at the time of destroying event queues */ +static void be_eq_clean(struct be_adapter *adapter, + struct be_eq_obj *eq_obj) +{ + struct be_eq_entry *eqe; + u16 num = 0; + + while ((eqe = event_get(eq_obj)) != NULL) { + eqe->evt = 0; + num++; + } + + if (num) + be_eq_notify(adapter, eq_obj->q.id, false, true, num); +} + static void be_rx_q_clean(struct be_adapter *adapter) { struct be_rx_page_info *page_info; @@ -997,12 +1054,13 @@ static void be_rx_q_clean(struct be_adapter *adapter) /* First cleanup pending rx completions */ while ((rxcp = be_rx_compl_get(adapter)) != NULL) { be_rx_compl_discard(adapter, rxcp); - be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1); + be_rx_compl_reset(rxcp); + be_cq_notify(adapter, rx_cq->id, true, 1); } /* Then free posted rx buffer that were not used */ tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len; - for (; tail != rxq->head; index_inc(&tail, rxq->len)) { + for (; atomic_read(&rxq->used) > 0; index_inc(&tail, rxq->len)) { page_info = get_rx_page_info(adapter, tail); put_page(page_info->page); memset(page_info, 0, sizeof(*page_info)); @@ -1010,21 +1068,86 @@ static void be_rx_q_clean(struct be_adapter *adapter) BUG_ON(atomic_read(&rxq->used)); } -static void be_tx_q_clean(struct be_adapter *adapter) +static void be_tx_compl_clean(struct be_adapter *adapter) { - struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list; - struct sk_buff *sent_skb; + struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_queue_info *txq = &adapter->tx_obj.q; - u16 last_index; - bool dummy_wrb; - - while (atomic_read(&txq->used)) { - sent_skb = sent_skbs[txq->tail]; - last_index = txq->tail; - index_adv(&last_index, - wrb_cnt_for_skb(sent_skb, &dummy_wrb) - 1, txq->len); - be_tx_compl_process(adapter, last_index); - } + struct be_eth_tx_compl *txcp; + u16 end_idx, cmpl = 0, timeo = 0; + + /* Wait for a max of 200ms for all the tx-completions to arrive. */ + do { + while ((txcp = be_tx_compl_get(tx_cq))) { + end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, + wrb_index, txcp); + be_tx_compl_process(adapter, end_idx); + cmpl++; + } + if (cmpl) { + be_cq_notify(adapter, tx_cq->id, false, cmpl); + cmpl = 0; + } + + if (atomic_read(&txq->used) == 0 || ++timeo > 200) + break; + + mdelay(1); + } while (true); + + if (atomic_read(&txq->used)) + dev_err(&adapter->pdev->dev, "%d pending tx-completions\n", + atomic_read(&txq->used)); +} + +static void be_mcc_queues_destroy(struct be_adapter *adapter) +{ + struct be_queue_info *q; + + q = &adapter->mcc_obj.q; + if (q->created) + be_cmd_q_destroy(adapter, q, QTYPE_MCCQ); + be_queue_free(adapter, q); + + q = &adapter->mcc_obj.cq; + if (q->created) + be_cmd_q_destroy(adapter, q, QTYPE_CQ); + be_queue_free(adapter, q); +} + +/* Must be called only after TX qs are created as MCC shares TX EQ */ +static int be_mcc_queues_create(struct be_adapter *adapter) +{ + struct be_queue_info *q, *cq; + + /* Alloc MCC compl queue */ + cq = &adapter->mcc_obj.cq; + if (be_queue_alloc(adapter, cq, MCC_CQ_LEN, + sizeof(struct be_mcc_compl))) + goto err; + + /* Ask BE to create MCC compl queue; share TX's eq */ + if (be_cmd_cq_create(adapter, cq, &adapter->tx_eq.q, false, true, 0)) + goto mcc_cq_free; + + /* Alloc MCC queue */ + q = &adapter->mcc_obj.q; + if (be_queue_alloc(adapter, q, MCC_Q_LEN, sizeof(struct be_mcc_wrb))) + goto mcc_cq_destroy; + + /* Ask BE to create MCC queue */ + if (be_cmd_mccq_create(adapter, q, cq)) + goto mcc_q_free; + + return 0; + +mcc_q_free: + be_queue_free(adapter, q); +mcc_cq_destroy: + be_cmd_q_destroy(adapter, cq, QTYPE_CQ); +mcc_cq_free: + be_queue_free(adapter, cq); +err: + return -1; } static void be_tx_queues_destroy(struct be_adapter *adapter) @@ -1033,21 +1156,20 @@ static void be_tx_queues_destroy(struct be_adapter *adapter) q = &adapter->tx_obj.q; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ); + be_cmd_q_destroy(adapter, q, QTYPE_TXQ); be_queue_free(adapter, q); q = &adapter->tx_obj.cq; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); + be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); - /* No more tx completions can be rcvd now; clean up if there are - * any pending completions or pending tx requests */ - be_tx_q_clean(adapter); + /* Clear any residual events */ + be_eq_clean(adapter, &adapter->tx_eq); q = &adapter->tx_eq.q; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); + be_cmd_q_destroy(adapter, q, QTYPE_EQ); be_queue_free(adapter, q); } @@ -1065,7 +1187,7 @@ static int be_tx_queues_create(struct be_adapter *adapter) return -1; /* Ask BE to create Tx Event queue */ - if (be_cmd_eq_create(&adapter->ctrl, eq, adapter->tx_eq.cur_eqd)) + if (be_cmd_eq_create(adapter, eq, adapter->tx_eq.cur_eqd)) goto tx_eq_free; /* Alloc TX eth compl queue */ cq = &adapter->tx_obj.cq; @@ -1074,7 +1196,7 @@ static int be_tx_queues_create(struct be_adapter *adapter) goto tx_eq_destroy; /* Ask BE to create Tx eth compl queue */ - if (be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3)) + if (be_cmd_cq_create(adapter, cq, eq, false, false, 3)) goto tx_cq_free; /* Alloc TX eth queue */ @@ -1083,18 +1205,18 @@ static int be_tx_queues_create(struct be_adapter *adapter) goto tx_cq_destroy; /* Ask BE to create Tx eth queue */ - if (be_cmd_txq_create(&adapter->ctrl, q, cq)) + if (be_cmd_txq_create(adapter, q, cq)) goto tx_q_free; return 0; tx_q_free: be_queue_free(adapter, q); tx_cq_destroy: - be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ); + be_cmd_q_destroy(adapter, cq, QTYPE_CQ); tx_cq_free: be_queue_free(adapter, cq); tx_eq_destroy: - be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ); + be_cmd_q_destroy(adapter, eq, QTYPE_EQ); tx_eq_free: be_queue_free(adapter, eq); return -1; @@ -1106,19 +1228,22 @@ static void be_rx_queues_destroy(struct be_adapter *adapter) q = &adapter->rx_obj.q; if (q->created) { - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_RXQ); + be_cmd_q_destroy(adapter, q, QTYPE_RXQ); be_rx_q_clean(adapter); } be_queue_free(adapter, q); q = &adapter->rx_obj.cq; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ); + be_cmd_q_destroy(adapter, q, QTYPE_CQ); be_queue_free(adapter, q); + /* Clear any residual events */ + be_eq_clean(adapter, &adapter->rx_eq); + q = &adapter->rx_eq.q; if (q->created) - be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ); + be_cmd_q_destroy(adapter, q, QTYPE_EQ); be_queue_free(adapter, q); } @@ -1127,7 +1252,6 @@ static int be_rx_queues_create(struct be_adapter *adapter) struct be_queue_info *eq, *q, *cq; int rc; - adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME; adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE; adapter->rx_eq.max_eqd = BE_MAX_EQD; adapter->rx_eq.min_eqd = 0; @@ -1142,7 +1266,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) return rc; /* Ask BE to create Rx Event queue */ - rc = be_cmd_eq_create(&adapter->ctrl, eq, adapter->rx_eq.cur_eqd); + rc = be_cmd_eq_create(adapter, eq, adapter->rx_eq.cur_eqd); if (rc) goto rx_eq_free; @@ -1154,7 +1278,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) goto rx_eq_destroy; /* Ask BE to create Rx eth compl queue */ - rc = be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3); + rc = be_cmd_cq_create(adapter, cq, eq, false, false, 3); if (rc) goto rx_cq_free; @@ -1165,7 +1289,7 @@ static int be_rx_queues_create(struct be_adapter *adapter) goto rx_cq_destroy; /* Ask BE to create Rx eth queue */ - rc = be_cmd_rxq_create(&adapter->ctrl, q, cq->id, rx_frag_size, + rc = be_cmd_rxq_create(adapter, q, cq->id, rx_frag_size, BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false); if (rc) goto rx_q_free; @@ -1174,80 +1298,51 @@ static int be_rx_queues_create(struct be_adapter *adapter) rx_q_free: be_queue_free(adapter, q); rx_cq_destroy: - be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ); + be_cmd_q_destroy(adapter, cq, QTYPE_CQ); rx_cq_free: be_queue_free(adapter, cq); rx_eq_destroy: - be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ); + be_cmd_q_destroy(adapter, eq, QTYPE_EQ); rx_eq_free: be_queue_free(adapter, eq); return rc; } -static bool event_get(struct be_eq_obj *eq_obj, u16 *rid) -{ - struct be_eq_entry *entry = queue_tail_node(&eq_obj->q); - u32 evt = entry->evt; - - if (!evt) - return false; - - evt = le32_to_cpu(evt); - *rid = (evt >> EQ_ENTRY_RES_ID_SHIFT) & EQ_ENTRY_RES_ID_MASK; - entry->evt = 0; - queue_tail_inc(&eq_obj->q); - return true; -} - -static int event_handle(struct be_ctrl_info *ctrl, - struct be_eq_obj *eq_obj) -{ - u16 rid = 0, num = 0; - - while (event_get(eq_obj, &rid)) - num++; - - /* We can see an interrupt and no event */ - be_eq_notify(ctrl, eq_obj->q.id, true, true, num); - if (num) - napi_schedule(&eq_obj->napi); - - return num; -} static irqreturn_t be_intx(int irq, void *dev) { struct be_adapter *adapter = dev; - struct be_ctrl_info *ctrl = &adapter->ctrl; - int rx, tx; + int isr; - tx = event_handle(ctrl, &adapter->tx_eq); - rx = event_handle(ctrl, &adapter->rx_eq); - - if (rx || tx) - return IRQ_HANDLED; - else + isr = ioread32(adapter->csr + CEV_ISR0_OFFSET + + be_pci_func(adapter) * CEV_ISR_SIZE); + if (!isr) return IRQ_NONE; + + event_handle(adapter, &adapter->tx_eq); + event_handle(adapter, &adapter->rx_eq); + + return IRQ_HANDLED; } static irqreturn_t be_msix_rx(int irq, void *dev) { struct be_adapter *adapter = dev; - event_handle(&adapter->ctrl, &adapter->rx_eq); + event_handle(adapter, &adapter->rx_eq); return IRQ_HANDLED; } -static irqreturn_t be_msix_tx(int irq, void *dev) +static irqreturn_t be_msix_tx_mcc(int irq, void *dev) { struct be_adapter *adapter = dev; - event_handle(&adapter->ctrl, &adapter->tx_eq); + event_handle(adapter, &adapter->tx_eq); return IRQ_HANDLED; } -static inline bool do_lro(struct be_adapter *adapter, +static inline bool do_gro(struct be_adapter *adapter, struct be_eth_rx_compl *rxcp) { int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp); @@ -1256,8 +1351,7 @@ static inline bool do_lro(struct be_adapter *adapter, if (err) drvr_stats(adapter)->be_rxcp_err++; - return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ? - false : true; + return (tcp_frame && !err) ? true : false; } int be_poll_rx(struct napi_struct *napi, int budget) @@ -1274,13 +1368,13 @@ int be_poll_rx(struct napi_struct *napi, int budget) if (!rxcp) break; - if (do_lro(adapter, rxcp)) - be_rx_compl_process_lro(adapter, rxcp); + if (do_gro(adapter, rxcp)) + be_rx_compl_process_gro(adapter, rxcp); else be_rx_compl_process(adapter, rxcp); - } - lro_flush_all(&adapter->rx_obj.lro_mgr); + be_rx_compl_reset(rxcp); + } /* Refill the queue */ if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM) @@ -1289,48 +1383,59 @@ int be_poll_rx(struct napi_struct *napi, int budget) /* All consumed */ if (work_done < budget) { napi_complete(napi); - be_cq_notify(&adapter->ctrl, rx_cq->id, true, work_done); + be_cq_notify(adapter, rx_cq->id, true, work_done); } else { /* More to be consumed; continue with interrupts disabled */ - be_cq_notify(&adapter->ctrl, rx_cq->id, false, work_done); + be_cq_notify(adapter, rx_cq->id, false, work_done); } return work_done; } -/* For TX we don't honour budget; consume everything */ -int be_poll_tx(struct napi_struct *napi, int budget) +void be_process_tx(struct be_adapter *adapter) { - struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); - struct be_adapter *adapter = - container_of(tx_eq, struct be_adapter, tx_eq); - struct be_tx_obj *tx_obj = &adapter->tx_obj; - struct be_queue_info *tx_cq = &tx_obj->cq; - struct be_queue_info *txq = &tx_obj->q; + struct be_queue_info *txq = &adapter->tx_obj.q; + struct be_queue_info *tx_cq = &adapter->tx_obj.cq; struct be_eth_tx_compl *txcp; u32 num_cmpl = 0; u16 end_idx; - while ((txcp = be_tx_compl_get(adapter))) { + while ((txcp = be_tx_compl_get(tx_cq))) { end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl, wrb_index, txcp); be_tx_compl_process(adapter, end_idx); num_cmpl++; } - /* As Tx wrbs have been freed up, wake up netdev queue if - * it was stopped due to lack of tx wrbs. - */ - if (netif_queue_stopped(adapter->netdev) && + if (num_cmpl) { + be_cq_notify(adapter, tx_cq->id, true, num_cmpl); + + /* As Tx wrbs have been freed up, wake up netdev queue if + * it was stopped due to lack of tx wrbs. + */ + if (netif_queue_stopped(adapter->netdev) && atomic_read(&txq->used) < txq->len / 2) { - netif_wake_queue(adapter->netdev); + netif_wake_queue(adapter->netdev); + } + + drvr_stats(adapter)->be_tx_events++; + drvr_stats(adapter)->be_tx_compl += num_cmpl; } +} + +/* As TX and MCC share the same EQ check for both TX and MCC completions. + * For TX/MCC we don't honour budget; consume everything + */ +static int be_poll_tx_mcc(struct napi_struct *napi, int budget) +{ + struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi); + struct be_adapter *adapter = + container_of(tx_eq, struct be_adapter, tx_eq); napi_complete(napi); - be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl); + be_process_tx(adapter); - drvr_stats(adapter)->be_tx_events++; - drvr_stats(adapter)->be_tx_compl += num_cmpl; + be_process_mcc(adapter); return 1; } @@ -1341,11 +1446,8 @@ static void be_worker(struct work_struct *work) container_of(work, struct be_adapter, work.work); int status; - /* Check link */ - be_link_status_update(adapter); - /* Get Stats */ - status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd); + status = be_cmd_get_stats(adapter, &adapter->stats.cmd); if (!status) netdev_stats_update(adapter); @@ -1379,8 +1481,7 @@ static void be_msix_enable(struct be_adapter *adapter) static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id) { - return adapter->msix_entries[eq_id - - 8 * adapter->ctrl.pci_func].vector; + return adapter->msix_entries[eq_id - 8 * be_pci_func(adapter)].vector; } static int be_msix_register(struct be_adapter *adapter) @@ -1392,7 +1493,7 @@ static int be_msix_register(struct be_adapter *adapter) sprintf(tx_eq->desc, "%s-tx", netdev->name); vec = be_msix_vec_get(adapter, tx_eq->q.id); - status = request_irq(vec, be_msix_tx, 0, tx_eq->desc, adapter); + status = request_irq(vec, be_msix_tx_mcc, 0, tx_eq->desc, adapter); if (status) goto err; @@ -1465,16 +1566,47 @@ done: static int be_open(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; + bool link_up; + int status; + + /* First time posting */ + be_post_rx_frags(adapter); + + napi_enable(&rx_eq->napi); + napi_enable(&tx_eq->napi); + + be_irq_register(adapter); + + be_intr_set(adapter, true); + + /* The evt queues are created in unarmed state; arm them */ + be_eq_notify(adapter, rx_eq->q.id, true, false, 0); + be_eq_notify(adapter, tx_eq->q.id, true, false, 0); + + /* Rx compl queue may be in unarmed state; rearm it */ + be_cq_notify(adapter, adapter->rx_obj.cq.id, true, 0); + + status = be_cmd_link_status_query(adapter, &link_up); + if (status) + return status; + be_link_status_update(adapter, link_up); + + schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); + return 0; +} + +static int be_setup(struct be_adapter *adapter) +{ + struct net_device *netdev = adapter->netdev; u32 if_flags; int status; if_flags = BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PROMISCUOUS | BE_IF_FLAGS_MCAST_PROMISCUOUS | BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_PASS_L3L4_ERRORS; - status = be_cmd_if_create(ctrl, if_flags, netdev->dev_addr, + status = be_cmd_if_create(adapter, if_flags, netdev->dev_addr, false/* pmac_invalid */, &adapter->if_handle, &adapter->pmac_id); if (status != 0) @@ -1482,7 +1614,7 @@ static int be_open(struct net_device *netdev) be_vid_config(netdev); - status = be_cmd_set_flow_control(ctrl, true, true); + status = be_cmd_set_flow_control(adapter, true, true); if (status != 0) goto if_destroy; @@ -1494,52 +1626,47 @@ static int be_open(struct net_device *netdev) if (status != 0) goto tx_qs_destroy; - /* First time posting */ - be_post_rx_frags(adapter); - - napi_enable(&rx_eq->napi); - napi_enable(&tx_eq->napi); - - be_irq_register(adapter); - - be_intr_set(ctrl, true); - - /* The evt queues are created in the unarmed state; arm them */ - be_eq_notify(ctrl, rx_eq->q.id, true, false, 0); - be_eq_notify(ctrl, tx_eq->q.id, true, false, 0); - - /* The compl queues are created in the unarmed state; arm them */ - be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); - be_cq_notify(ctrl, adapter->tx_obj.cq.id, true, 0); - - be_link_status_update(adapter); + status = be_mcc_queues_create(adapter); + if (status != 0) + goto rx_qs_destroy; - schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); return 0; +rx_qs_destroy: + be_rx_queues_destroy(adapter); tx_qs_destroy: be_tx_queues_destroy(adapter); if_destroy: - be_cmd_if_destroy(ctrl, adapter->if_handle); + be_cmd_if_destroy(adapter, adapter->if_handle); do_none: return status; } +static int be_clear(struct be_adapter *adapter) +{ + be_rx_queues_destroy(adapter); + be_tx_queues_destroy(adapter); + + be_cmd_if_destroy(adapter, adapter->if_handle); + + be_mcc_queues_destroy(adapter); + return 0; +} + static int be_close(struct net_device *netdev) { struct be_adapter *adapter = netdev_priv(netdev); - struct be_ctrl_info *ctrl = &adapter->ctrl; struct be_eq_obj *rx_eq = &adapter->rx_eq; struct be_eq_obj *tx_eq = &adapter->tx_eq; int vec; - cancel_delayed_work(&adapter->work); + cancel_delayed_work_sync(&adapter->work); netif_stop_queue(netdev); netif_carrier_off(netdev); - adapter->link.speed = PHY_LINK_SPEED_ZERO; + adapter->link_up = false; - be_intr_set(ctrl, false); + be_intr_set(adapter, false); if (adapter->msix_enabled) { vec = be_msix_vec_get(adapter, tx_eq->q.id); @@ -1554,64 +1681,14 @@ static int be_close(struct net_device *netdev) napi_disable(&rx_eq->napi); napi_disable(&tx_eq->napi); - be_rx_queues_destroy(adapter); - be_tx_queues_destroy(adapter); - - be_cmd_if_destroy(ctrl, adapter->if_handle); - return 0; -} - -static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, - void **ip_hdr, void **tcpudp_hdr, - u64 *hdr_flags, void *priv) -{ - struct ethhdr *eh; - struct vlan_ethhdr *veh; - struct iphdr *iph; - u8 *va = page_address(frag->page) + frag->page_offset; - unsigned long ll_hlen; - - prefetch(va); - eh = (struct ethhdr *)va; - *mac_hdr = eh; - ll_hlen = ETH_HLEN; - if (eh->h_proto != htons(ETH_P_IP)) { - if (eh->h_proto == htons(ETH_P_8021Q)) { - veh = (struct vlan_ethhdr *)va; - if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP)) - return -1; - - ll_hlen += VLAN_HLEN; - } else { - return -1; - } - } - *hdr_flags = LRO_IPV4; - iph = (struct iphdr *)(va + ll_hlen); - *ip_hdr = iph; - if (iph->protocol != IPPROTO_TCP) - return -1; - *hdr_flags |= LRO_TCP; - *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2); + /* Wait for all pending tx completions to arrive so that + * all tx skbs are freed. + */ + be_tx_compl_clean(adapter); return 0; } -static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev) -{ - struct net_lro_mgr *lro_mgr; - - lro_mgr = &adapter->rx_obj.lro_mgr; - lro_mgr->dev = netdev; - lro_mgr->features = LRO_F_NAPI; - lro_mgr->ip_summed = CHECKSUM_UNNECESSARY; - lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY; - lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS; - lro_mgr->lro_arr = adapter->rx_obj.lro_desc; - lro_mgr->get_frag_header = be_get_frag_header; - lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME; -} - static struct net_device_ops be_netdev_ops = { .ndo_open = be_open, .ndo_stop = be_close, @@ -1632,7 +1709,7 @@ static void be_netdev_init(struct net_device *netdev) netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO | NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM | - NETIF_F_IPV6_CSUM; + NETIF_F_IPV6_CSUM | NETIF_F_GRO; netdev->flags |= IFF_MULTICAST; @@ -1642,11 +1719,9 @@ static void be_netdev_init(struct net_device *netdev) SET_ETHTOOL_OPS(netdev, &be_ethtool_ops); - be_lro_init(adapter, netdev); - netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx, BE_NAPI_WEIGHT); - netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx, + netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx_mcc, BE_NAPI_WEIGHT); netif_carrier_off(netdev); @@ -1655,13 +1730,12 @@ static void be_netdev_init(struct net_device *netdev) static void be_unmap_pci_bars(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; - if (ctrl->csr) - iounmap(ctrl->csr); - if (ctrl->db) - iounmap(ctrl->db); - if (ctrl->pcicfg) - iounmap(ctrl->pcicfg); + if (adapter->csr) + iounmap(adapter->csr); + if (adapter->db) + iounmap(adapter->db); + if (adapter->pcicfg) + iounmap(adapter->pcicfg); } static int be_map_pci_bars(struct be_adapter *adapter) @@ -1672,19 +1746,19 @@ static int be_map_pci_bars(struct be_adapter *adapter) pci_resource_len(adapter->pdev, 2)); if (addr == NULL) return -ENOMEM; - adapter->ctrl.csr = addr; + adapter->csr = addr; addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4), 128 * 1024); if (addr == NULL) goto pci_map_err; - adapter->ctrl.db = addr; + adapter->db = addr; addr = ioremap_nocache(pci_resource_start(adapter->pdev, 1), pci_resource_len(adapter->pdev, 1)); if (addr == NULL) goto pci_map_err; - adapter->ctrl.pcicfg = addr; + adapter->pcicfg = addr; return 0; pci_map_err: @@ -1695,7 +1769,7 @@ pci_map_err: static void be_ctrl_cleanup(struct be_adapter *adapter) { - struct be_dma_mem *mem = &adapter->ctrl.mbox_mem_alloced; + struct be_dma_mem *mem = &adapter->mbox_mem_alloced; be_unmap_pci_bars(adapter); @@ -1704,14 +1778,11 @@ static void be_ctrl_cleanup(struct be_adapter *adapter) mem->va, mem->dma); } -/* Initialize the mbox required to send cmds to BE */ static int be_ctrl_init(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; - struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced; - struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem; + struct be_dma_mem *mbox_mem_alloc = &adapter->mbox_mem_alloced; + struct be_dma_mem *mbox_mem_align = &adapter->mbox_mem; int status; - u32 val; status = be_map_pci_bars(adapter); if (status) @@ -1728,11 +1799,10 @@ static int be_ctrl_init(struct be_adapter *adapter) mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16); mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16); memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox)); - spin_lock_init(&ctrl->cmd_lock); + spin_lock_init(&adapter->mbox_lock); + spin_lock_init(&adapter->mcc_lock); + spin_lock_init(&adapter->mcc_cq_lock); - val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); - ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & - MEMBAR_CTRL_INT_CTRL_PFUNC_MASK; return 0; } @@ -1766,6 +1836,8 @@ static void __devexit be_remove(struct pci_dev *pdev) unregister_netdev(adapter->netdev); + be_clear(adapter); + be_stats_cleanup(adapter); be_ctrl_cleanup(adapter); @@ -1784,18 +1856,17 @@ static void __devexit be_remove(struct pci_dev *pdev) static int be_hw_up(struct be_adapter *adapter) { - struct be_ctrl_info *ctrl = &adapter->ctrl; int status; - status = be_cmd_POST(ctrl); + status = be_cmd_POST(adapter); if (status) return status; - status = be_cmd_get_fw_ver(ctrl, adapter->fw_ver); + status = be_cmd_get_fw_ver(adapter, adapter->fw_ver); if (status) return status; - status = be_cmd_query_fw_cfg(ctrl, &adapter->port_num); + status = be_cmd_query_fw_cfg(adapter, &adapter->port_num); return status; } @@ -1805,7 +1876,6 @@ static int __devinit be_probe(struct pci_dev *pdev, int status = 0; struct be_adapter *adapter; struct net_device *netdev; - struct be_ctrl_info *ctrl; u8 mac[ETH_ALEN]; status = pci_enable_device(pdev); @@ -1840,11 +1910,14 @@ static int __devinit be_probe(struct pci_dev *pdev, } } - ctrl = &adapter->ctrl; status = be_ctrl_init(adapter); if (status) goto free_netdev; + status = be_cmd_reset_function(adapter); + if (status) + goto ctrl_clean; + status = be_stats_init(adapter); if (status) goto ctrl_clean; @@ -1853,7 +1926,7 @@ static int __devinit be_probe(struct pci_dev *pdev, if (status) goto stats_clean; - status = be_cmd_mac_addr_query(ctrl, mac, MAC_ADDRESS_TYPE_NETWORK, + status = be_cmd_mac_addr_query(adapter, mac, MAC_ADDRESS_TYPE_NETWORK, true /* permanent */, 0); if (status) goto stats_clean; @@ -1863,13 +1936,18 @@ static int __devinit be_probe(struct pci_dev *pdev, be_netdev_init(netdev); SET_NETDEV_DEV(netdev, &adapter->pdev->dev); + status = be_setup(adapter); + if (status) + goto stats_clean; status = register_netdev(netdev); if (status != 0) - goto stats_clean; + goto unsetup; dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num); return 0; +unsetup: + be_clear(adapter); stats_clean: be_stats_cleanup(adapter); ctrl_clean: @@ -1894,6 +1972,7 @@ static int be_suspend(struct pci_dev *pdev, pm_message_t state) if (netif_running(netdev)) { rtnl_lock(); be_close(netdev); + be_clear(adapter); rtnl_unlock(); } @@ -1920,6 +1999,7 @@ static int be_resume(struct pci_dev *pdev) if (netif_running(netdev)) { rtnl_lock(); + be_setup(adapter); be_open(netdev); rtnl_unlock(); } @@ -1945,12 +2025,6 @@ static int __init be_init_module(void) " Using 2048\n"); rx_frag_size = 2048; } - /* Ensure rx_frag_size is aligned to chache line */ - if (SKB_DATA_ALIGN(rx_frag_size) != rx_frag_size) { - printk(KERN_WARNING DRV_NAME - " : Bad module param rx_frag_size. Using 2048\n"); - rx_frag_size = 2048; - } return pci_register_driver(&be_driver); }