162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Linux network driver for QLogic BR-series Converged Network Adapter. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci/* 662306a36Sopenharmony_ci * Copyright (c) 2005-2014 Brocade Communications Systems, Inc. 762306a36Sopenharmony_ci * Copyright (c) 2014-2015 QLogic Corporation 862306a36Sopenharmony_ci * All rights reserved 962306a36Sopenharmony_ci * www.qlogic.com 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#include <linux/bitops.h> 1262306a36Sopenharmony_ci#include <linux/netdevice.h> 1362306a36Sopenharmony_ci#include <linux/skbuff.h> 1462306a36Sopenharmony_ci#include <linux/etherdevice.h> 1562306a36Sopenharmony_ci#include <linux/in.h> 1662306a36Sopenharmony_ci#include <linux/ethtool.h> 1762306a36Sopenharmony_ci#include <linux/if_vlan.h> 1862306a36Sopenharmony_ci#include <linux/if_ether.h> 1962306a36Sopenharmony_ci#include <linux/ip.h> 2062306a36Sopenharmony_ci#include <linux/prefetch.h> 2162306a36Sopenharmony_ci#include <linux/module.h> 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "bnad.h" 2462306a36Sopenharmony_ci#include "bna.h" 2562306a36Sopenharmony_ci#include "cna.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic DEFINE_MUTEX(bnad_fwimg_mutex); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* 3062306a36Sopenharmony_ci * Module params 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_cistatic uint bnad_msix_disable; 3362306a36Sopenharmony_cimodule_param(bnad_msix_disable, uint, 0444); 3462306a36Sopenharmony_ciMODULE_PARM_DESC(bnad_msix_disable, "Disable MSIX mode"); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic uint bnad_ioc_auto_recover = 1; 3762306a36Sopenharmony_cimodule_param(bnad_ioc_auto_recover, uint, 0444); 3862306a36Sopenharmony_ciMODULE_PARM_DESC(bnad_ioc_auto_recover, "Enable / Disable auto recovery"); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic uint bna_debugfs_enable = 1; 4162306a36Sopenharmony_cimodule_param(bna_debugfs_enable, uint, 0644); 4262306a36Sopenharmony_ciMODULE_PARM_DESC(bna_debugfs_enable, "Enables debugfs feature, default=1," 4362306a36Sopenharmony_ci " Range[false:0|true:1]"); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * Global variables 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_cistatic u32 bnad_rxqs_per_cq = 2; 4962306a36Sopenharmony_cistatic atomic_t bna_id; 5062306a36Sopenharmony_cistatic const u8 bnad_bcast_addr[] __aligned(2) = 5162306a36Sopenharmony_ci { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * Local MACROS 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_ci#define BNAD_GET_MBOX_IRQ(_bnad) \ 5762306a36Sopenharmony_ci (((_bnad)->cfg_flags & BNAD_CF_MSIX) ? \ 5862306a36Sopenharmony_ci ((_bnad)->msix_table[BNAD_MAILBOX_MSIX_INDEX].vector) : \ 5962306a36Sopenharmony_ci ((_bnad)->pcidev->irq)) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define BNAD_FILL_UNMAPQ_MEM_REQ(_res_info, _num, _size) \ 6262306a36Sopenharmony_cido { \ 6362306a36Sopenharmony_ci (_res_info)->res_type = BNA_RES_T_MEM; \ 6462306a36Sopenharmony_ci (_res_info)->res_u.mem_info.mem_type = BNA_MEM_T_KVA; \ 6562306a36Sopenharmony_ci (_res_info)->res_u.mem_info.num = (_num); \ 6662306a36Sopenharmony_ci (_res_info)->res_u.mem_info.len = (_size); \ 6762306a36Sopenharmony_ci} while (0) 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci/* 7062306a36Sopenharmony_ci * Reinitialize completions in CQ, once Rx is taken down 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_cistatic void 7362306a36Sopenharmony_cibnad_cq_cleanup(struct bnad *bnad, struct bna_ccb *ccb) 7462306a36Sopenharmony_ci{ 7562306a36Sopenharmony_ci struct bna_cq_entry *cmpl; 7662306a36Sopenharmony_ci int i; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci for (i = 0; i < ccb->q_depth; i++) { 7962306a36Sopenharmony_ci cmpl = &((struct bna_cq_entry *)ccb->sw_q)[i]; 8062306a36Sopenharmony_ci cmpl->valid = 0; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci} 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci/* Tx Datapath functions */ 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* Caller should ensure that the entry at unmap_q[index] is valid */ 8862306a36Sopenharmony_cistatic u32 8962306a36Sopenharmony_cibnad_tx_buff_unmap(struct bnad *bnad, 9062306a36Sopenharmony_ci struct bnad_tx_unmap *unmap_q, 9162306a36Sopenharmony_ci u32 q_depth, u32 index) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct bnad_tx_unmap *unmap; 9462306a36Sopenharmony_ci struct sk_buff *skb; 9562306a36Sopenharmony_ci int vector, nvecs; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci unmap = &unmap_q[index]; 9862306a36Sopenharmony_ci nvecs = unmap->nvecs; 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci skb = unmap->skb; 10162306a36Sopenharmony_ci unmap->skb = NULL; 10262306a36Sopenharmony_ci unmap->nvecs = 0; 10362306a36Sopenharmony_ci dma_unmap_single(&bnad->pcidev->dev, 10462306a36Sopenharmony_ci dma_unmap_addr(&unmap->vectors[0], dma_addr), 10562306a36Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 10662306a36Sopenharmony_ci dma_unmap_addr_set(&unmap->vectors[0], dma_addr, 0); 10762306a36Sopenharmony_ci nvecs--; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci vector = 0; 11062306a36Sopenharmony_ci while (nvecs) { 11162306a36Sopenharmony_ci vector++; 11262306a36Sopenharmony_ci if (vector == BFI_TX_MAX_VECTORS_PER_WI) { 11362306a36Sopenharmony_ci vector = 0; 11462306a36Sopenharmony_ci BNA_QE_INDX_INC(index, q_depth); 11562306a36Sopenharmony_ci unmap = &unmap_q[index]; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci dma_unmap_page(&bnad->pcidev->dev, 11962306a36Sopenharmony_ci dma_unmap_addr(&unmap->vectors[vector], dma_addr), 12062306a36Sopenharmony_ci dma_unmap_len(&unmap->vectors[vector], dma_len), 12162306a36Sopenharmony_ci DMA_TO_DEVICE); 12262306a36Sopenharmony_ci dma_unmap_addr_set(&unmap->vectors[vector], dma_addr, 0); 12362306a36Sopenharmony_ci nvecs--; 12462306a36Sopenharmony_ci } 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci BNA_QE_INDX_INC(index, q_depth); 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci return index; 12962306a36Sopenharmony_ci} 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* 13262306a36Sopenharmony_ci * Frees all pending Tx Bufs 13362306a36Sopenharmony_ci * At this point no activity is expected on the Q, 13462306a36Sopenharmony_ci * so DMA unmap & freeing is fine. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_cistatic void 13762306a36Sopenharmony_cibnad_txq_cleanup(struct bnad *bnad, struct bna_tcb *tcb) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct bnad_tx_unmap *unmap_q = tcb->unmap_q; 14062306a36Sopenharmony_ci struct sk_buff *skb; 14162306a36Sopenharmony_ci int i; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci for (i = 0; i < tcb->q_depth; i++) { 14462306a36Sopenharmony_ci skb = unmap_q[i].skb; 14562306a36Sopenharmony_ci if (!skb) 14662306a36Sopenharmony_ci continue; 14762306a36Sopenharmony_ci bnad_tx_buff_unmap(bnad, unmap_q, tcb->q_depth, i); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 15062306a36Sopenharmony_ci } 15162306a36Sopenharmony_ci} 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci/* 15462306a36Sopenharmony_ci * bnad_txcmpl_process : Frees the Tx bufs on Tx completion 15562306a36Sopenharmony_ci * Can be called in a) Interrupt context 15662306a36Sopenharmony_ci * b) Sending context 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_cistatic u32 15962306a36Sopenharmony_cibnad_txcmpl_process(struct bnad *bnad, struct bna_tcb *tcb) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci u32 sent_packets = 0, sent_bytes = 0; 16262306a36Sopenharmony_ci u32 wis, unmap_wis, hw_cons, cons, q_depth; 16362306a36Sopenharmony_ci struct bnad_tx_unmap *unmap_q = tcb->unmap_q; 16462306a36Sopenharmony_ci struct bnad_tx_unmap *unmap; 16562306a36Sopenharmony_ci struct sk_buff *skb; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci /* Just return if TX is stopped */ 16862306a36Sopenharmony_ci if (!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) 16962306a36Sopenharmony_ci return 0; 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci hw_cons = *(tcb->hw_consumer_index); 17262306a36Sopenharmony_ci rmb(); 17362306a36Sopenharmony_ci cons = tcb->consumer_index; 17462306a36Sopenharmony_ci q_depth = tcb->q_depth; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci wis = BNA_Q_INDEX_CHANGE(cons, hw_cons, q_depth); 17762306a36Sopenharmony_ci BUG_ON(!(wis <= BNA_QE_IN_USE_CNT(tcb, tcb->q_depth))); 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci while (wis) { 18062306a36Sopenharmony_ci unmap = &unmap_q[cons]; 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci skb = unmap->skb; 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci sent_packets++; 18562306a36Sopenharmony_ci sent_bytes += skb->len; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci unmap_wis = BNA_TXQ_WI_NEEDED(unmap->nvecs); 18862306a36Sopenharmony_ci wis -= unmap_wis; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci cons = bnad_tx_buff_unmap(bnad, unmap_q, q_depth, cons); 19162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci /* Update consumer pointers. */ 19562306a36Sopenharmony_ci tcb->consumer_index = hw_cons; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci tcb->txq->tx_packets += sent_packets; 19862306a36Sopenharmony_ci tcb->txq->tx_bytes += sent_bytes; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci return sent_packets; 20162306a36Sopenharmony_ci} 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_cistatic u32 20462306a36Sopenharmony_cibnad_tx_complete(struct bnad *bnad, struct bna_tcb *tcb) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct net_device *netdev = bnad->netdev; 20762306a36Sopenharmony_ci u32 sent = 0; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) 21062306a36Sopenharmony_ci return 0; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci sent = bnad_txcmpl_process(bnad, tcb); 21362306a36Sopenharmony_ci if (sent) { 21462306a36Sopenharmony_ci if (netif_queue_stopped(netdev) && 21562306a36Sopenharmony_ci netif_carrier_ok(netdev) && 21662306a36Sopenharmony_ci BNA_QE_FREE_CNT(tcb, tcb->q_depth) >= 21762306a36Sopenharmony_ci BNAD_NETIF_WAKE_THRESHOLD) { 21862306a36Sopenharmony_ci if (test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) { 21962306a36Sopenharmony_ci netif_wake_queue(netdev); 22062306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, netif_queue_wakeup); 22162306a36Sopenharmony_ci } 22262306a36Sopenharmony_ci } 22362306a36Sopenharmony_ci } 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) 22662306a36Sopenharmony_ci bna_ib_ack(tcb->i_dbell, sent); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci smp_mb__before_atomic(); 22962306a36Sopenharmony_ci clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci return sent; 23262306a36Sopenharmony_ci} 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci/* MSIX Tx Completion Handler */ 23562306a36Sopenharmony_cistatic irqreturn_t 23662306a36Sopenharmony_cibnad_msix_tx(int irq, void *data) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci struct bna_tcb *tcb = (struct bna_tcb *)data; 23962306a36Sopenharmony_ci struct bnad *bnad = tcb->bnad; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci bnad_tx_complete(bnad, tcb); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci return IRQ_HANDLED; 24462306a36Sopenharmony_ci} 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_cistatic inline void 24762306a36Sopenharmony_cibnad_rxq_alloc_uninit(struct bnad *bnad, struct bna_rcb *rcb) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci struct bnad_rx_unmap_q *unmap_q = rcb->unmap_q; 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci unmap_q->reuse_pi = -1; 25262306a36Sopenharmony_ci unmap_q->alloc_order = -1; 25362306a36Sopenharmony_ci unmap_q->map_size = 0; 25462306a36Sopenharmony_ci unmap_q->type = BNAD_RXBUF_NONE; 25562306a36Sopenharmony_ci} 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/* Default is page-based allocation. Multi-buffer support - TBD */ 25862306a36Sopenharmony_cistatic int 25962306a36Sopenharmony_cibnad_rxq_alloc_init(struct bnad *bnad, struct bna_rcb *rcb) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct bnad_rx_unmap_q *unmap_q = rcb->unmap_q; 26262306a36Sopenharmony_ci int order; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci bnad_rxq_alloc_uninit(bnad, rcb); 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci order = get_order(rcb->rxq->buffer_size); 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci unmap_q->type = BNAD_RXBUF_PAGE; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (bna_is_small_rxq(rcb->id)) { 27162306a36Sopenharmony_ci unmap_q->alloc_order = 0; 27262306a36Sopenharmony_ci unmap_q->map_size = rcb->rxq->buffer_size; 27362306a36Sopenharmony_ci } else { 27462306a36Sopenharmony_ci if (rcb->rxq->multi_buffer) { 27562306a36Sopenharmony_ci unmap_q->alloc_order = 0; 27662306a36Sopenharmony_ci unmap_q->map_size = rcb->rxq->buffer_size; 27762306a36Sopenharmony_ci unmap_q->type = BNAD_RXBUF_MULTI_BUFF; 27862306a36Sopenharmony_ci } else { 27962306a36Sopenharmony_ci unmap_q->alloc_order = order; 28062306a36Sopenharmony_ci unmap_q->map_size = 28162306a36Sopenharmony_ci (rcb->rxq->buffer_size > 2048) ? 28262306a36Sopenharmony_ci PAGE_SIZE << order : 2048; 28362306a36Sopenharmony_ci } 28462306a36Sopenharmony_ci } 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci BUG_ON((PAGE_SIZE << order) % unmap_q->map_size); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci return 0; 28962306a36Sopenharmony_ci} 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_cistatic inline void 29262306a36Sopenharmony_cibnad_rxq_cleanup_page(struct bnad *bnad, struct bnad_rx_unmap *unmap) 29362306a36Sopenharmony_ci{ 29462306a36Sopenharmony_ci if (!unmap->page) 29562306a36Sopenharmony_ci return; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci dma_unmap_page(&bnad->pcidev->dev, 29862306a36Sopenharmony_ci dma_unmap_addr(&unmap->vector, dma_addr), 29962306a36Sopenharmony_ci unmap->vector.len, DMA_FROM_DEVICE); 30062306a36Sopenharmony_ci put_page(unmap->page); 30162306a36Sopenharmony_ci unmap->page = NULL; 30262306a36Sopenharmony_ci dma_unmap_addr_set(&unmap->vector, dma_addr, 0); 30362306a36Sopenharmony_ci unmap->vector.len = 0; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic inline void 30762306a36Sopenharmony_cibnad_rxq_cleanup_skb(struct bnad *bnad, struct bnad_rx_unmap *unmap) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci if (!unmap->skb) 31062306a36Sopenharmony_ci return; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci dma_unmap_single(&bnad->pcidev->dev, 31362306a36Sopenharmony_ci dma_unmap_addr(&unmap->vector, dma_addr), 31462306a36Sopenharmony_ci unmap->vector.len, DMA_FROM_DEVICE); 31562306a36Sopenharmony_ci dev_kfree_skb_any(unmap->skb); 31662306a36Sopenharmony_ci unmap->skb = NULL; 31762306a36Sopenharmony_ci dma_unmap_addr_set(&unmap->vector, dma_addr, 0); 31862306a36Sopenharmony_ci unmap->vector.len = 0; 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic void 32262306a36Sopenharmony_cibnad_rxq_cleanup(struct bnad *bnad, struct bna_rcb *rcb) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct bnad_rx_unmap_q *unmap_q = rcb->unmap_q; 32562306a36Sopenharmony_ci int i; 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_ci for (i = 0; i < rcb->q_depth; i++) { 32862306a36Sopenharmony_ci struct bnad_rx_unmap *unmap = &unmap_q->unmap[i]; 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) 33162306a36Sopenharmony_ci bnad_rxq_cleanup_skb(bnad, unmap); 33262306a36Sopenharmony_ci else 33362306a36Sopenharmony_ci bnad_rxq_cleanup_page(bnad, unmap); 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci bnad_rxq_alloc_uninit(bnad, rcb); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic u32 33962306a36Sopenharmony_cibnad_rxq_refill_page(struct bnad *bnad, struct bna_rcb *rcb, u32 nalloc) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci u32 alloced, prod, q_depth; 34262306a36Sopenharmony_ci struct bnad_rx_unmap_q *unmap_q = rcb->unmap_q; 34362306a36Sopenharmony_ci struct bnad_rx_unmap *unmap, *prev; 34462306a36Sopenharmony_ci struct bna_rxq_entry *rxent; 34562306a36Sopenharmony_ci struct page *page; 34662306a36Sopenharmony_ci u32 page_offset, alloc_size; 34762306a36Sopenharmony_ci dma_addr_t dma_addr; 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci prod = rcb->producer_index; 35062306a36Sopenharmony_ci q_depth = rcb->q_depth; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci alloc_size = PAGE_SIZE << unmap_q->alloc_order; 35362306a36Sopenharmony_ci alloced = 0; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci while (nalloc--) { 35662306a36Sopenharmony_ci unmap = &unmap_q->unmap[prod]; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci if (unmap_q->reuse_pi < 0) { 35962306a36Sopenharmony_ci page = alloc_pages(GFP_ATOMIC | __GFP_COMP, 36062306a36Sopenharmony_ci unmap_q->alloc_order); 36162306a36Sopenharmony_ci page_offset = 0; 36262306a36Sopenharmony_ci } else { 36362306a36Sopenharmony_ci prev = &unmap_q->unmap[unmap_q->reuse_pi]; 36462306a36Sopenharmony_ci page = prev->page; 36562306a36Sopenharmony_ci page_offset = prev->page_offset + unmap_q->map_size; 36662306a36Sopenharmony_ci get_page(page); 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci if (unlikely(!page)) { 37062306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, rxbuf_alloc_failed); 37162306a36Sopenharmony_ci rcb->rxq->rxbuf_alloc_failed++; 37262306a36Sopenharmony_ci goto finishing; 37362306a36Sopenharmony_ci } 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci dma_addr = dma_map_page(&bnad->pcidev->dev, page, page_offset, 37662306a36Sopenharmony_ci unmap_q->map_size, DMA_FROM_DEVICE); 37762306a36Sopenharmony_ci if (dma_mapping_error(&bnad->pcidev->dev, dma_addr)) { 37862306a36Sopenharmony_ci put_page(page); 37962306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, rxbuf_map_failed); 38062306a36Sopenharmony_ci rcb->rxq->rxbuf_map_failed++; 38162306a36Sopenharmony_ci goto finishing; 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci unmap->page = page; 38562306a36Sopenharmony_ci unmap->page_offset = page_offset; 38662306a36Sopenharmony_ci dma_unmap_addr_set(&unmap->vector, dma_addr, dma_addr); 38762306a36Sopenharmony_ci unmap->vector.len = unmap_q->map_size; 38862306a36Sopenharmony_ci page_offset += unmap_q->map_size; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (page_offset < alloc_size) 39162306a36Sopenharmony_ci unmap_q->reuse_pi = prod; 39262306a36Sopenharmony_ci else 39362306a36Sopenharmony_ci unmap_q->reuse_pi = -1; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci rxent = &((struct bna_rxq_entry *)rcb->sw_q)[prod]; 39662306a36Sopenharmony_ci BNA_SET_DMA_ADDR(dma_addr, &rxent->host_addr); 39762306a36Sopenharmony_ci BNA_QE_INDX_INC(prod, q_depth); 39862306a36Sopenharmony_ci alloced++; 39962306a36Sopenharmony_ci } 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cifinishing: 40262306a36Sopenharmony_ci if (likely(alloced)) { 40362306a36Sopenharmony_ci rcb->producer_index = prod; 40462306a36Sopenharmony_ci smp_mb(); 40562306a36Sopenharmony_ci if (likely(test_bit(BNAD_RXQ_POST_OK, &rcb->flags))) 40662306a36Sopenharmony_ci bna_rxq_prod_indx_doorbell(rcb); 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci return alloced; 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic u32 41362306a36Sopenharmony_cibnad_rxq_refill_skb(struct bnad *bnad, struct bna_rcb *rcb, u32 nalloc) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci u32 alloced, prod, q_depth, buff_sz; 41662306a36Sopenharmony_ci struct bnad_rx_unmap_q *unmap_q = rcb->unmap_q; 41762306a36Sopenharmony_ci struct bnad_rx_unmap *unmap; 41862306a36Sopenharmony_ci struct bna_rxq_entry *rxent; 41962306a36Sopenharmony_ci struct sk_buff *skb; 42062306a36Sopenharmony_ci dma_addr_t dma_addr; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci buff_sz = rcb->rxq->buffer_size; 42362306a36Sopenharmony_ci prod = rcb->producer_index; 42462306a36Sopenharmony_ci q_depth = rcb->q_depth; 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci alloced = 0; 42762306a36Sopenharmony_ci while (nalloc--) { 42862306a36Sopenharmony_ci unmap = &unmap_q->unmap[prod]; 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci skb = netdev_alloc_skb_ip_align(bnad->netdev, buff_sz); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci if (unlikely(!skb)) { 43362306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, rxbuf_alloc_failed); 43462306a36Sopenharmony_ci rcb->rxq->rxbuf_alloc_failed++; 43562306a36Sopenharmony_ci goto finishing; 43662306a36Sopenharmony_ci } 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data, 43962306a36Sopenharmony_ci buff_sz, DMA_FROM_DEVICE); 44062306a36Sopenharmony_ci if (dma_mapping_error(&bnad->pcidev->dev, dma_addr)) { 44162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 44262306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, rxbuf_map_failed); 44362306a36Sopenharmony_ci rcb->rxq->rxbuf_map_failed++; 44462306a36Sopenharmony_ci goto finishing; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci unmap->skb = skb; 44862306a36Sopenharmony_ci dma_unmap_addr_set(&unmap->vector, dma_addr, dma_addr); 44962306a36Sopenharmony_ci unmap->vector.len = buff_sz; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci rxent = &((struct bna_rxq_entry *)rcb->sw_q)[prod]; 45262306a36Sopenharmony_ci BNA_SET_DMA_ADDR(dma_addr, &rxent->host_addr); 45362306a36Sopenharmony_ci BNA_QE_INDX_INC(prod, q_depth); 45462306a36Sopenharmony_ci alloced++; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_cifinishing: 45862306a36Sopenharmony_ci if (likely(alloced)) { 45962306a36Sopenharmony_ci rcb->producer_index = prod; 46062306a36Sopenharmony_ci smp_mb(); 46162306a36Sopenharmony_ci if (likely(test_bit(BNAD_RXQ_POST_OK, &rcb->flags))) 46262306a36Sopenharmony_ci bna_rxq_prod_indx_doorbell(rcb); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci return alloced; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic inline void 46962306a36Sopenharmony_cibnad_rxq_post(struct bnad *bnad, struct bna_rcb *rcb) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci struct bnad_rx_unmap_q *unmap_q = rcb->unmap_q; 47262306a36Sopenharmony_ci u32 to_alloc; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci to_alloc = BNA_QE_FREE_CNT(rcb, rcb->q_depth); 47562306a36Sopenharmony_ci if (!(to_alloc >> BNAD_RXQ_REFILL_THRESHOLD_SHIFT)) 47662306a36Sopenharmony_ci return; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) 47962306a36Sopenharmony_ci bnad_rxq_refill_skb(bnad, rcb, to_alloc); 48062306a36Sopenharmony_ci else 48162306a36Sopenharmony_ci bnad_rxq_refill_page(bnad, rcb, to_alloc); 48262306a36Sopenharmony_ci} 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci#define flags_cksum_prot_mask (BNA_CQ_EF_IPV4 | BNA_CQ_EF_L3_CKSUM_OK | \ 48562306a36Sopenharmony_ci BNA_CQ_EF_IPV6 | \ 48662306a36Sopenharmony_ci BNA_CQ_EF_TCP | BNA_CQ_EF_UDP | \ 48762306a36Sopenharmony_ci BNA_CQ_EF_L4_CKSUM_OK) 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci#define flags_tcp4 (BNA_CQ_EF_IPV4 | BNA_CQ_EF_L3_CKSUM_OK | \ 49062306a36Sopenharmony_ci BNA_CQ_EF_TCP | BNA_CQ_EF_L4_CKSUM_OK) 49162306a36Sopenharmony_ci#define flags_tcp6 (BNA_CQ_EF_IPV6 | \ 49262306a36Sopenharmony_ci BNA_CQ_EF_TCP | BNA_CQ_EF_L4_CKSUM_OK) 49362306a36Sopenharmony_ci#define flags_udp4 (BNA_CQ_EF_IPV4 | BNA_CQ_EF_L3_CKSUM_OK | \ 49462306a36Sopenharmony_ci BNA_CQ_EF_UDP | BNA_CQ_EF_L4_CKSUM_OK) 49562306a36Sopenharmony_ci#define flags_udp6 (BNA_CQ_EF_IPV6 | \ 49662306a36Sopenharmony_ci BNA_CQ_EF_UDP | BNA_CQ_EF_L4_CKSUM_OK) 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_cistatic void 49962306a36Sopenharmony_cibnad_cq_drop_packet(struct bnad *bnad, struct bna_rcb *rcb, 50062306a36Sopenharmony_ci u32 sop_ci, u32 nvecs) 50162306a36Sopenharmony_ci{ 50262306a36Sopenharmony_ci struct bnad_rx_unmap_q *unmap_q; 50362306a36Sopenharmony_ci struct bnad_rx_unmap *unmap; 50462306a36Sopenharmony_ci u32 ci, vec; 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci unmap_q = rcb->unmap_q; 50762306a36Sopenharmony_ci for (vec = 0, ci = sop_ci; vec < nvecs; vec++) { 50862306a36Sopenharmony_ci unmap = &unmap_q->unmap[ci]; 50962306a36Sopenharmony_ci BNA_QE_INDX_INC(ci, rcb->q_depth); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) 51262306a36Sopenharmony_ci bnad_rxq_cleanup_skb(bnad, unmap); 51362306a36Sopenharmony_ci else 51462306a36Sopenharmony_ci bnad_rxq_cleanup_page(bnad, unmap); 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic void 51962306a36Sopenharmony_cibnad_cq_setup_skb_frags(struct bna_ccb *ccb, struct sk_buff *skb, u32 nvecs) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct bna_rcb *rcb; 52262306a36Sopenharmony_ci struct bnad *bnad; 52362306a36Sopenharmony_ci struct bnad_rx_unmap_q *unmap_q; 52462306a36Sopenharmony_ci struct bna_cq_entry *cq, *cmpl; 52562306a36Sopenharmony_ci u32 ci, pi, totlen = 0; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci cq = ccb->sw_q; 52862306a36Sopenharmony_ci pi = ccb->producer_index; 52962306a36Sopenharmony_ci cmpl = &cq[pi]; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci rcb = bna_is_small_rxq(cmpl->rxq_id) ? ccb->rcb[1] : ccb->rcb[0]; 53262306a36Sopenharmony_ci unmap_q = rcb->unmap_q; 53362306a36Sopenharmony_ci bnad = rcb->bnad; 53462306a36Sopenharmony_ci ci = rcb->consumer_index; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* prefetch header */ 53762306a36Sopenharmony_ci prefetch(page_address(unmap_q->unmap[ci].page) + 53862306a36Sopenharmony_ci unmap_q->unmap[ci].page_offset); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci while (nvecs--) { 54162306a36Sopenharmony_ci struct bnad_rx_unmap *unmap; 54262306a36Sopenharmony_ci u32 len; 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci unmap = &unmap_q->unmap[ci]; 54562306a36Sopenharmony_ci BNA_QE_INDX_INC(ci, rcb->q_depth); 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci dma_unmap_page(&bnad->pcidev->dev, 54862306a36Sopenharmony_ci dma_unmap_addr(&unmap->vector, dma_addr), 54962306a36Sopenharmony_ci unmap->vector.len, DMA_FROM_DEVICE); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci len = ntohs(cmpl->length); 55262306a36Sopenharmony_ci skb->truesize += unmap->vector.len; 55362306a36Sopenharmony_ci totlen += len; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, 55662306a36Sopenharmony_ci unmap->page, unmap->page_offset, len); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci unmap->page = NULL; 55962306a36Sopenharmony_ci unmap->vector.len = 0; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci BNA_QE_INDX_INC(pi, ccb->q_depth); 56262306a36Sopenharmony_ci cmpl = &cq[pi]; 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci skb->len += totlen; 56662306a36Sopenharmony_ci skb->data_len += totlen; 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_cistatic inline void 57062306a36Sopenharmony_cibnad_cq_setup_skb(struct bnad *bnad, struct sk_buff *skb, 57162306a36Sopenharmony_ci struct bnad_rx_unmap *unmap, u32 len) 57262306a36Sopenharmony_ci{ 57362306a36Sopenharmony_ci prefetch(skb->data); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci dma_unmap_single(&bnad->pcidev->dev, 57662306a36Sopenharmony_ci dma_unmap_addr(&unmap->vector, dma_addr), 57762306a36Sopenharmony_ci unmap->vector.len, DMA_FROM_DEVICE); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci skb_put(skb, len); 58062306a36Sopenharmony_ci skb->protocol = eth_type_trans(skb, bnad->netdev); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci unmap->skb = NULL; 58362306a36Sopenharmony_ci unmap->vector.len = 0; 58462306a36Sopenharmony_ci} 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic u32 58762306a36Sopenharmony_cibnad_cq_process(struct bnad *bnad, struct bna_ccb *ccb, int budget) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci struct bna_cq_entry *cq, *cmpl, *next_cmpl; 59062306a36Sopenharmony_ci struct bna_rcb *rcb = NULL; 59162306a36Sopenharmony_ci struct bnad_rx_unmap_q *unmap_q; 59262306a36Sopenharmony_ci struct bnad_rx_unmap *unmap = NULL; 59362306a36Sopenharmony_ci struct sk_buff *skb = NULL; 59462306a36Sopenharmony_ci struct bna_pkt_rate *pkt_rt = &ccb->pkt_rate; 59562306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl = ccb->ctrl; 59662306a36Sopenharmony_ci u32 packets = 0, len = 0, totlen = 0; 59762306a36Sopenharmony_ci u32 pi, vec, sop_ci = 0, nvecs = 0; 59862306a36Sopenharmony_ci u32 flags, masked_flags; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci prefetch(bnad->netdev); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci cq = ccb->sw_q; 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci while (packets < budget) { 60562306a36Sopenharmony_ci cmpl = &cq[ccb->producer_index]; 60662306a36Sopenharmony_ci if (!cmpl->valid) 60762306a36Sopenharmony_ci break; 60862306a36Sopenharmony_ci /* The 'valid' field is set by the adapter, only after writing 60962306a36Sopenharmony_ci * the other fields of completion entry. Hence, do not load 61062306a36Sopenharmony_ci * other fields of completion entry *before* the 'valid' is 61162306a36Sopenharmony_ci * loaded. Adding the rmb() here prevents the compiler and/or 61262306a36Sopenharmony_ci * CPU from reordering the reads which would potentially result 61362306a36Sopenharmony_ci * in reading stale values in completion entry. 61462306a36Sopenharmony_ci */ 61562306a36Sopenharmony_ci rmb(); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci BNA_UPDATE_PKT_CNT(pkt_rt, ntohs(cmpl->length)); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (bna_is_small_rxq(cmpl->rxq_id)) 62062306a36Sopenharmony_ci rcb = ccb->rcb[1]; 62162306a36Sopenharmony_ci else 62262306a36Sopenharmony_ci rcb = ccb->rcb[0]; 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci unmap_q = rcb->unmap_q; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci /* start of packet ci */ 62762306a36Sopenharmony_ci sop_ci = rcb->consumer_index; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) { 63062306a36Sopenharmony_ci unmap = &unmap_q->unmap[sop_ci]; 63162306a36Sopenharmony_ci skb = unmap->skb; 63262306a36Sopenharmony_ci } else { 63362306a36Sopenharmony_ci skb = napi_get_frags(&rx_ctrl->napi); 63462306a36Sopenharmony_ci if (unlikely(!skb)) 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci prefetch(skb); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci flags = ntohl(cmpl->flags); 64062306a36Sopenharmony_ci len = ntohs(cmpl->length); 64162306a36Sopenharmony_ci totlen = len; 64262306a36Sopenharmony_ci nvecs = 1; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci /* Check all the completions for this frame. 64562306a36Sopenharmony_ci * busy-wait doesn't help much, break here. 64662306a36Sopenharmony_ci */ 64762306a36Sopenharmony_ci if (BNAD_RXBUF_IS_MULTI_BUFF(unmap_q->type) && 64862306a36Sopenharmony_ci (flags & BNA_CQ_EF_EOP) == 0) { 64962306a36Sopenharmony_ci pi = ccb->producer_index; 65062306a36Sopenharmony_ci do { 65162306a36Sopenharmony_ci BNA_QE_INDX_INC(pi, ccb->q_depth); 65262306a36Sopenharmony_ci next_cmpl = &cq[pi]; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci if (!next_cmpl->valid) 65562306a36Sopenharmony_ci break; 65662306a36Sopenharmony_ci /* The 'valid' field is set by the adapter, only 65762306a36Sopenharmony_ci * after writing the other fields of completion 65862306a36Sopenharmony_ci * entry. Hence, do not load other fields of 65962306a36Sopenharmony_ci * completion entry *before* the 'valid' is 66062306a36Sopenharmony_ci * loaded. Adding the rmb() here prevents the 66162306a36Sopenharmony_ci * compiler and/or CPU from reordering the reads 66262306a36Sopenharmony_ci * which would potentially result in reading 66362306a36Sopenharmony_ci * stale values in completion entry. 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_ci rmb(); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci len = ntohs(next_cmpl->length); 66862306a36Sopenharmony_ci flags = ntohl(next_cmpl->flags); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci nvecs++; 67162306a36Sopenharmony_ci totlen += len; 67262306a36Sopenharmony_ci } while ((flags & BNA_CQ_EF_EOP) == 0); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (!next_cmpl->valid) 67562306a36Sopenharmony_ci break; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci packets++; 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci /* TODO: BNA_CQ_EF_LOCAL ? */ 68062306a36Sopenharmony_ci if (unlikely(flags & (BNA_CQ_EF_MAC_ERROR | 68162306a36Sopenharmony_ci BNA_CQ_EF_FCS_ERROR | 68262306a36Sopenharmony_ci BNA_CQ_EF_TOO_LONG))) { 68362306a36Sopenharmony_ci bnad_cq_drop_packet(bnad, rcb, sop_ci, nvecs); 68462306a36Sopenharmony_ci rcb->rxq->rx_packets_with_error++; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci goto next; 68762306a36Sopenharmony_ci } 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) 69062306a36Sopenharmony_ci bnad_cq_setup_skb(bnad, skb, unmap, len); 69162306a36Sopenharmony_ci else 69262306a36Sopenharmony_ci bnad_cq_setup_skb_frags(ccb, skb, nvecs); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci rcb->rxq->rx_packets++; 69562306a36Sopenharmony_ci rcb->rxq->rx_bytes += totlen; 69662306a36Sopenharmony_ci ccb->bytes_per_intr += totlen; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci masked_flags = flags & flags_cksum_prot_mask; 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci if (likely 70162306a36Sopenharmony_ci ((bnad->netdev->features & NETIF_F_RXCSUM) && 70262306a36Sopenharmony_ci ((masked_flags == flags_tcp4) || 70362306a36Sopenharmony_ci (masked_flags == flags_udp4) || 70462306a36Sopenharmony_ci (masked_flags == flags_tcp6) || 70562306a36Sopenharmony_ci (masked_flags == flags_udp6)))) 70662306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 70762306a36Sopenharmony_ci else 70862306a36Sopenharmony_ci skb_checksum_none_assert(skb); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci if ((flags & BNA_CQ_EF_VLAN) && 71162306a36Sopenharmony_ci (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX)) 71262306a36Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(cmpl->vlan_tag)); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci if (BNAD_RXBUF_IS_SK_BUFF(unmap_q->type)) 71562306a36Sopenharmony_ci netif_receive_skb(skb); 71662306a36Sopenharmony_ci else 71762306a36Sopenharmony_ci napi_gro_frags(&rx_ctrl->napi); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_cinext: 72062306a36Sopenharmony_ci BNA_QE_INDX_ADD(rcb->consumer_index, nvecs, rcb->q_depth); 72162306a36Sopenharmony_ci for (vec = 0; vec < nvecs; vec++) { 72262306a36Sopenharmony_ci cmpl = &cq[ccb->producer_index]; 72362306a36Sopenharmony_ci cmpl->valid = 0; 72462306a36Sopenharmony_ci BNA_QE_INDX_INC(ccb->producer_index, ccb->q_depth); 72562306a36Sopenharmony_ci } 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci napi_gro_flush(&rx_ctrl->napi, false); 72962306a36Sopenharmony_ci if (likely(test_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags))) 73062306a36Sopenharmony_ci bna_ib_ack_disable_irq(ccb->i_dbell, packets); 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci bnad_rxq_post(bnad, ccb->rcb[0]); 73362306a36Sopenharmony_ci if (ccb->rcb[1]) 73462306a36Sopenharmony_ci bnad_rxq_post(bnad, ccb->rcb[1]); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci return packets; 73762306a36Sopenharmony_ci} 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_cistatic void 74062306a36Sopenharmony_cibnad_netif_rx_schedule_poll(struct bnad *bnad, struct bna_ccb *ccb) 74162306a36Sopenharmony_ci{ 74262306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl = (struct bnad_rx_ctrl *)(ccb->ctrl); 74362306a36Sopenharmony_ci struct napi_struct *napi = &rx_ctrl->napi; 74462306a36Sopenharmony_ci 74562306a36Sopenharmony_ci if (likely(napi_schedule_prep(napi))) { 74662306a36Sopenharmony_ci __napi_schedule(napi); 74762306a36Sopenharmony_ci rx_ctrl->rx_schedule++; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci} 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci/* MSIX Rx Path Handler */ 75262306a36Sopenharmony_cistatic irqreturn_t 75362306a36Sopenharmony_cibnad_msix_rx(int irq, void *data) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct bna_ccb *ccb = (struct bna_ccb *)data; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci if (ccb) { 75862306a36Sopenharmony_ci ((struct bnad_rx_ctrl *)ccb->ctrl)->rx_intr_ctr++; 75962306a36Sopenharmony_ci bnad_netif_rx_schedule_poll(ccb->bnad, ccb); 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci return IRQ_HANDLED; 76362306a36Sopenharmony_ci} 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci/* Interrupt handlers */ 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci/* Mbox Interrupt Handlers */ 76862306a36Sopenharmony_cistatic irqreturn_t 76962306a36Sopenharmony_cibnad_msix_mbox_handler(int irq, void *data) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci u32 intr_status; 77262306a36Sopenharmony_ci unsigned long flags; 77362306a36Sopenharmony_ci struct bnad *bnad = (struct bnad *)data; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 77662306a36Sopenharmony_ci if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))) { 77762306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 77862306a36Sopenharmony_ci return IRQ_HANDLED; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci bna_intr_status_get(&bnad->bna, intr_status); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci if (BNA_IS_MBOX_ERR_INTR(&bnad->bna, intr_status)) 78462306a36Sopenharmony_ci bna_mbox_handler(&bnad->bna, intr_status); 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci return IRQ_HANDLED; 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic irqreturn_t 79262306a36Sopenharmony_cibnad_isr(int irq, void *data) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci int i, j; 79562306a36Sopenharmony_ci u32 intr_status; 79662306a36Sopenharmony_ci unsigned long flags; 79762306a36Sopenharmony_ci struct bnad *bnad = (struct bnad *)data; 79862306a36Sopenharmony_ci struct bnad_rx_info *rx_info; 79962306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl; 80062306a36Sopenharmony_ci struct bna_tcb *tcb = NULL; 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 80362306a36Sopenharmony_ci if (unlikely(test_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags))) { 80462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 80562306a36Sopenharmony_ci return IRQ_NONE; 80662306a36Sopenharmony_ci } 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci bna_intr_status_get(&bnad->bna, intr_status); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci if (unlikely(!intr_status)) { 81162306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 81262306a36Sopenharmony_ci return IRQ_NONE; 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci if (BNA_IS_MBOX_ERR_INTR(&bnad->bna, intr_status)) 81662306a36Sopenharmony_ci bna_mbox_handler(&bnad->bna, intr_status); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (!BNA_IS_INTX_DATA_INTR(intr_status)) 82162306a36Sopenharmony_ci return IRQ_HANDLED; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci /* Process data interrupts */ 82462306a36Sopenharmony_ci /* Tx processing */ 82562306a36Sopenharmony_ci for (i = 0; i < bnad->num_tx; i++) { 82662306a36Sopenharmony_ci for (j = 0; j < bnad->num_txq_per_tx; j++) { 82762306a36Sopenharmony_ci tcb = bnad->tx_info[i].tcb[j]; 82862306a36Sopenharmony_ci if (tcb && test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)) 82962306a36Sopenharmony_ci bnad_tx_complete(bnad, bnad->tx_info[i].tcb[j]); 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci } 83262306a36Sopenharmony_ci /* Rx processing */ 83362306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 83462306a36Sopenharmony_ci rx_info = &bnad->rx_info[i]; 83562306a36Sopenharmony_ci if (!rx_info->rx) 83662306a36Sopenharmony_ci continue; 83762306a36Sopenharmony_ci for (j = 0; j < bnad->num_rxp_per_rx; j++) { 83862306a36Sopenharmony_ci rx_ctrl = &rx_info->rx_ctrl[j]; 83962306a36Sopenharmony_ci if (rx_ctrl->ccb) 84062306a36Sopenharmony_ci bnad_netif_rx_schedule_poll(bnad, 84162306a36Sopenharmony_ci rx_ctrl->ccb); 84262306a36Sopenharmony_ci } 84362306a36Sopenharmony_ci } 84462306a36Sopenharmony_ci return IRQ_HANDLED; 84562306a36Sopenharmony_ci} 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci/* 84862306a36Sopenharmony_ci * Called in interrupt / callback context 84962306a36Sopenharmony_ci * with bna_lock held, so cfg_flags access is OK 85062306a36Sopenharmony_ci */ 85162306a36Sopenharmony_cistatic void 85262306a36Sopenharmony_cibnad_enable_mbox_irq(struct bnad *bnad) 85362306a36Sopenharmony_ci{ 85462306a36Sopenharmony_ci clear_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, mbox_intr_enabled); 85762306a36Sopenharmony_ci} 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci/* 86062306a36Sopenharmony_ci * Called with bnad->bna_lock held b'cos of 86162306a36Sopenharmony_ci * bnad->cfg_flags access. 86262306a36Sopenharmony_ci */ 86362306a36Sopenharmony_cistatic void 86462306a36Sopenharmony_cibnad_disable_mbox_irq(struct bnad *bnad) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, mbox_intr_disabled); 86962306a36Sopenharmony_ci} 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_cistatic void 87262306a36Sopenharmony_cibnad_set_netdev_perm_addr(struct bnad *bnad) 87362306a36Sopenharmony_ci{ 87462306a36Sopenharmony_ci struct net_device *netdev = bnad->netdev; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci ether_addr_copy(netdev->perm_addr, bnad->perm_addr); 87762306a36Sopenharmony_ci if (is_zero_ether_addr(netdev->dev_addr)) 87862306a36Sopenharmony_ci eth_hw_addr_set(netdev, bnad->perm_addr); 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci/* Control Path Handlers */ 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci/* Callbacks */ 88462306a36Sopenharmony_civoid 88562306a36Sopenharmony_cibnad_cb_mbox_intr_enable(struct bnad *bnad) 88662306a36Sopenharmony_ci{ 88762306a36Sopenharmony_ci bnad_enable_mbox_irq(bnad); 88862306a36Sopenharmony_ci} 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_civoid 89162306a36Sopenharmony_cibnad_cb_mbox_intr_disable(struct bnad *bnad) 89262306a36Sopenharmony_ci{ 89362306a36Sopenharmony_ci bnad_disable_mbox_irq(bnad); 89462306a36Sopenharmony_ci} 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_civoid 89762306a36Sopenharmony_cibnad_cb_ioceth_ready(struct bnad *bnad) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci bnad->bnad_completions.ioc_comp_status = BNA_CB_SUCCESS; 90062306a36Sopenharmony_ci complete(&bnad->bnad_completions.ioc_comp); 90162306a36Sopenharmony_ci} 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_civoid 90462306a36Sopenharmony_cibnad_cb_ioceth_failed(struct bnad *bnad) 90562306a36Sopenharmony_ci{ 90662306a36Sopenharmony_ci bnad->bnad_completions.ioc_comp_status = BNA_CB_FAIL; 90762306a36Sopenharmony_ci complete(&bnad->bnad_completions.ioc_comp); 90862306a36Sopenharmony_ci} 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_civoid 91162306a36Sopenharmony_cibnad_cb_ioceth_disabled(struct bnad *bnad) 91262306a36Sopenharmony_ci{ 91362306a36Sopenharmony_ci bnad->bnad_completions.ioc_comp_status = BNA_CB_SUCCESS; 91462306a36Sopenharmony_ci complete(&bnad->bnad_completions.ioc_comp); 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistatic void 91862306a36Sopenharmony_cibnad_cb_enet_disabled(void *arg) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct bnad *bnad = (struct bnad *)arg; 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci netif_carrier_off(bnad->netdev); 92362306a36Sopenharmony_ci complete(&bnad->bnad_completions.enet_comp); 92462306a36Sopenharmony_ci} 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_civoid 92762306a36Sopenharmony_cibnad_cb_ethport_link_status(struct bnad *bnad, 92862306a36Sopenharmony_ci enum bna_link_status link_status) 92962306a36Sopenharmony_ci{ 93062306a36Sopenharmony_ci bool link_up = false; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci link_up = (link_status == BNA_LINK_UP) || (link_status == BNA_CEE_UP); 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci if (link_status == BNA_CEE_UP) { 93562306a36Sopenharmony_ci if (!test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) 93662306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, cee_toggle); 93762306a36Sopenharmony_ci set_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags); 93862306a36Sopenharmony_ci } else { 93962306a36Sopenharmony_ci if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) 94062306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, cee_toggle); 94162306a36Sopenharmony_ci clear_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags); 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (link_up) { 94562306a36Sopenharmony_ci if (!netif_carrier_ok(bnad->netdev)) { 94662306a36Sopenharmony_ci uint tx_id, tcb_id; 94762306a36Sopenharmony_ci netdev_info(bnad->netdev, "link up\n"); 94862306a36Sopenharmony_ci netif_carrier_on(bnad->netdev); 94962306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, link_toggle); 95062306a36Sopenharmony_ci for (tx_id = 0; tx_id < bnad->num_tx; tx_id++) { 95162306a36Sopenharmony_ci for (tcb_id = 0; tcb_id < bnad->num_txq_per_tx; 95262306a36Sopenharmony_ci tcb_id++) { 95362306a36Sopenharmony_ci struct bna_tcb *tcb = 95462306a36Sopenharmony_ci bnad->tx_info[tx_id].tcb[tcb_id]; 95562306a36Sopenharmony_ci u32 txq_id; 95662306a36Sopenharmony_ci if (!tcb) 95762306a36Sopenharmony_ci continue; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci txq_id = tcb->id; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (test_bit(BNAD_TXQ_TX_STARTED, 96262306a36Sopenharmony_ci &tcb->flags)) { 96362306a36Sopenharmony_ci /* 96462306a36Sopenharmony_ci * Force an immediate 96562306a36Sopenharmony_ci * Transmit Schedule */ 96662306a36Sopenharmony_ci netif_wake_subqueue( 96762306a36Sopenharmony_ci bnad->netdev, 96862306a36Sopenharmony_ci txq_id); 96962306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, 97062306a36Sopenharmony_ci netif_queue_wakeup); 97162306a36Sopenharmony_ci } else { 97262306a36Sopenharmony_ci netif_stop_subqueue( 97362306a36Sopenharmony_ci bnad->netdev, 97462306a36Sopenharmony_ci txq_id); 97562306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, 97662306a36Sopenharmony_ci netif_queue_stop); 97762306a36Sopenharmony_ci } 97862306a36Sopenharmony_ci } 97962306a36Sopenharmony_ci } 98062306a36Sopenharmony_ci } 98162306a36Sopenharmony_ci } else { 98262306a36Sopenharmony_ci if (netif_carrier_ok(bnad->netdev)) { 98362306a36Sopenharmony_ci netdev_info(bnad->netdev, "link down\n"); 98462306a36Sopenharmony_ci netif_carrier_off(bnad->netdev); 98562306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, link_toggle); 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci } 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic void 99162306a36Sopenharmony_cibnad_cb_tx_disabled(void *arg, struct bna_tx *tx) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci struct bnad *bnad = (struct bnad *)arg; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci complete(&bnad->bnad_completions.tx_comp); 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_cistatic void 99962306a36Sopenharmony_cibnad_cb_tcb_setup(struct bnad *bnad, struct bna_tcb *tcb) 100062306a36Sopenharmony_ci{ 100162306a36Sopenharmony_ci struct bnad_tx_info *tx_info = 100262306a36Sopenharmony_ci (struct bnad_tx_info *)tcb->txq->tx->priv; 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci tcb->priv = tcb; 100562306a36Sopenharmony_ci tx_info->tcb[tcb->id] = tcb; 100662306a36Sopenharmony_ci} 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_cistatic void 100962306a36Sopenharmony_cibnad_cb_tcb_destroy(struct bnad *bnad, struct bna_tcb *tcb) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci struct bnad_tx_info *tx_info = 101262306a36Sopenharmony_ci (struct bnad_tx_info *)tcb->txq->tx->priv; 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci tx_info->tcb[tcb->id] = NULL; 101562306a36Sopenharmony_ci tcb->priv = NULL; 101662306a36Sopenharmony_ci} 101762306a36Sopenharmony_ci 101862306a36Sopenharmony_cistatic void 101962306a36Sopenharmony_cibnad_cb_ccb_setup(struct bnad *bnad, struct bna_ccb *ccb) 102062306a36Sopenharmony_ci{ 102162306a36Sopenharmony_ci struct bnad_rx_info *rx_info = 102262306a36Sopenharmony_ci (struct bnad_rx_info *)ccb->cq->rx->priv; 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci rx_info->rx_ctrl[ccb->id].ccb = ccb; 102562306a36Sopenharmony_ci ccb->ctrl = &rx_info->rx_ctrl[ccb->id]; 102662306a36Sopenharmony_ci} 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_cistatic void 102962306a36Sopenharmony_cibnad_cb_ccb_destroy(struct bnad *bnad, struct bna_ccb *ccb) 103062306a36Sopenharmony_ci{ 103162306a36Sopenharmony_ci struct bnad_rx_info *rx_info = 103262306a36Sopenharmony_ci (struct bnad_rx_info *)ccb->cq->rx->priv; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci rx_info->rx_ctrl[ccb->id].ccb = NULL; 103562306a36Sopenharmony_ci} 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic void 103862306a36Sopenharmony_cibnad_cb_tx_stall(struct bnad *bnad, struct bna_tx *tx) 103962306a36Sopenharmony_ci{ 104062306a36Sopenharmony_ci struct bnad_tx_info *tx_info = tx->priv; 104162306a36Sopenharmony_ci struct bna_tcb *tcb; 104262306a36Sopenharmony_ci u32 txq_id; 104362306a36Sopenharmony_ci int i; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) { 104662306a36Sopenharmony_ci tcb = tx_info->tcb[i]; 104762306a36Sopenharmony_ci if (!tcb) 104862306a36Sopenharmony_ci continue; 104962306a36Sopenharmony_ci txq_id = tcb->id; 105062306a36Sopenharmony_ci clear_bit(BNAD_TXQ_TX_STARTED, &tcb->flags); 105162306a36Sopenharmony_ci netif_stop_subqueue(bnad->netdev, txq_id); 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci} 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_cistatic void 105662306a36Sopenharmony_cibnad_cb_tx_resume(struct bnad *bnad, struct bna_tx *tx) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci struct bnad_tx_info *tx_info = tx->priv; 105962306a36Sopenharmony_ci struct bna_tcb *tcb; 106062306a36Sopenharmony_ci u32 txq_id; 106162306a36Sopenharmony_ci int i; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) { 106462306a36Sopenharmony_ci tcb = tx_info->tcb[i]; 106562306a36Sopenharmony_ci if (!tcb) 106662306a36Sopenharmony_ci continue; 106762306a36Sopenharmony_ci txq_id = tcb->id; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci BUG_ON(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags)); 107062306a36Sopenharmony_ci set_bit(BNAD_TXQ_TX_STARTED, &tcb->flags); 107162306a36Sopenharmony_ci BUG_ON(*(tcb->hw_consumer_index) != 0); 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (netif_carrier_ok(bnad->netdev)) { 107462306a36Sopenharmony_ci netif_wake_subqueue(bnad->netdev, txq_id); 107562306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, netif_queue_wakeup); 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci } 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci /* 108062306a36Sopenharmony_ci * Workaround for first ioceth enable failure & we 108162306a36Sopenharmony_ci * get a 0 MAC address. We try to get the MAC address 108262306a36Sopenharmony_ci * again here. 108362306a36Sopenharmony_ci */ 108462306a36Sopenharmony_ci if (is_zero_ether_addr(bnad->perm_addr)) { 108562306a36Sopenharmony_ci bna_enet_perm_mac_get(&bnad->bna.enet, bnad->perm_addr); 108662306a36Sopenharmony_ci bnad_set_netdev_perm_addr(bnad); 108762306a36Sopenharmony_ci } 108862306a36Sopenharmony_ci} 108962306a36Sopenharmony_ci 109062306a36Sopenharmony_ci/* 109162306a36Sopenharmony_ci * Free all TxQs buffers and then notify TX_E_CLEANUP_DONE to Tx fsm. 109262306a36Sopenharmony_ci */ 109362306a36Sopenharmony_cistatic void 109462306a36Sopenharmony_cibnad_tx_cleanup(struct delayed_work *work) 109562306a36Sopenharmony_ci{ 109662306a36Sopenharmony_ci struct bnad_tx_info *tx_info = 109762306a36Sopenharmony_ci container_of(work, struct bnad_tx_info, tx_cleanup_work); 109862306a36Sopenharmony_ci struct bnad *bnad = NULL; 109962306a36Sopenharmony_ci struct bna_tcb *tcb; 110062306a36Sopenharmony_ci unsigned long flags; 110162306a36Sopenharmony_ci u32 i, pending = 0; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) { 110462306a36Sopenharmony_ci tcb = tx_info->tcb[i]; 110562306a36Sopenharmony_ci if (!tcb) 110662306a36Sopenharmony_ci continue; 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci bnad = tcb->bnad; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci if (test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) { 111162306a36Sopenharmony_ci pending++; 111262306a36Sopenharmony_ci continue; 111362306a36Sopenharmony_ci } 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci bnad_txq_cleanup(bnad, tcb); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci smp_mb__before_atomic(); 111862306a36Sopenharmony_ci clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); 111962306a36Sopenharmony_ci } 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci if (pending) { 112262306a36Sopenharmony_ci queue_delayed_work(bnad->work_q, &tx_info->tx_cleanup_work, 112362306a36Sopenharmony_ci msecs_to_jiffies(1)); 112462306a36Sopenharmony_ci return; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 112862306a36Sopenharmony_ci bna_tx_cleanup_complete(tx_info->tx); 112962306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 113062306a36Sopenharmony_ci} 113162306a36Sopenharmony_ci 113262306a36Sopenharmony_cistatic void 113362306a36Sopenharmony_cibnad_cb_tx_cleanup(struct bnad *bnad, struct bna_tx *tx) 113462306a36Sopenharmony_ci{ 113562306a36Sopenharmony_ci struct bnad_tx_info *tx_info = tx->priv; 113662306a36Sopenharmony_ci struct bna_tcb *tcb; 113762306a36Sopenharmony_ci int i; 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ci for (i = 0; i < BNAD_MAX_TXQ_PER_TX; i++) { 114062306a36Sopenharmony_ci tcb = tx_info->tcb[i]; 114162306a36Sopenharmony_ci if (!tcb) 114262306a36Sopenharmony_ci continue; 114362306a36Sopenharmony_ci } 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci queue_delayed_work(bnad->work_q, &tx_info->tx_cleanup_work, 0); 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic void 114962306a36Sopenharmony_cibnad_cb_rx_stall(struct bnad *bnad, struct bna_rx *rx) 115062306a36Sopenharmony_ci{ 115162306a36Sopenharmony_ci struct bnad_rx_info *rx_info = rx->priv; 115262306a36Sopenharmony_ci struct bna_ccb *ccb; 115362306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl; 115462306a36Sopenharmony_ci int i; 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci for (i = 0; i < BNAD_MAX_RXP_PER_RX; i++) { 115762306a36Sopenharmony_ci rx_ctrl = &rx_info->rx_ctrl[i]; 115862306a36Sopenharmony_ci ccb = rx_ctrl->ccb; 115962306a36Sopenharmony_ci if (!ccb) 116062306a36Sopenharmony_ci continue; 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci clear_bit(BNAD_RXQ_POST_OK, &ccb->rcb[0]->flags); 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci if (ccb->rcb[1]) 116562306a36Sopenharmony_ci clear_bit(BNAD_RXQ_POST_OK, &ccb->rcb[1]->flags); 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci} 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci/* 117062306a36Sopenharmony_ci * Free all RxQs buffers and then notify RX_E_CLEANUP_DONE to Rx fsm. 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_cistatic void 117362306a36Sopenharmony_cibnad_rx_cleanup(void *work) 117462306a36Sopenharmony_ci{ 117562306a36Sopenharmony_ci struct bnad_rx_info *rx_info = 117662306a36Sopenharmony_ci container_of(work, struct bnad_rx_info, rx_cleanup_work); 117762306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl; 117862306a36Sopenharmony_ci struct bnad *bnad = NULL; 117962306a36Sopenharmony_ci unsigned long flags; 118062306a36Sopenharmony_ci u32 i; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci for (i = 0; i < BNAD_MAX_RXP_PER_RX; i++) { 118362306a36Sopenharmony_ci rx_ctrl = &rx_info->rx_ctrl[i]; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci if (!rx_ctrl->ccb) 118662306a36Sopenharmony_ci continue; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci bnad = rx_ctrl->ccb->bnad; 118962306a36Sopenharmony_ci 119062306a36Sopenharmony_ci /* 119162306a36Sopenharmony_ci * Wait till the poll handler has exited 119262306a36Sopenharmony_ci * and nothing can be scheduled anymore 119362306a36Sopenharmony_ci */ 119462306a36Sopenharmony_ci napi_disable(&rx_ctrl->napi); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci bnad_cq_cleanup(bnad, rx_ctrl->ccb); 119762306a36Sopenharmony_ci bnad_rxq_cleanup(bnad, rx_ctrl->ccb->rcb[0]); 119862306a36Sopenharmony_ci if (rx_ctrl->ccb->rcb[1]) 119962306a36Sopenharmony_ci bnad_rxq_cleanup(bnad, rx_ctrl->ccb->rcb[1]); 120062306a36Sopenharmony_ci } 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 120362306a36Sopenharmony_ci bna_rx_cleanup_complete(rx_info->rx); 120462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 120562306a36Sopenharmony_ci} 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_cistatic void 120862306a36Sopenharmony_cibnad_cb_rx_cleanup(struct bnad *bnad, struct bna_rx *rx) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci struct bnad_rx_info *rx_info = rx->priv; 121162306a36Sopenharmony_ci struct bna_ccb *ccb; 121262306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl; 121362306a36Sopenharmony_ci int i; 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci for (i = 0; i < BNAD_MAX_RXP_PER_RX; i++) { 121662306a36Sopenharmony_ci rx_ctrl = &rx_info->rx_ctrl[i]; 121762306a36Sopenharmony_ci ccb = rx_ctrl->ccb; 121862306a36Sopenharmony_ci if (!ccb) 121962306a36Sopenharmony_ci continue; 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_ci clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[0]->flags); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (ccb->rcb[1]) 122462306a36Sopenharmony_ci clear_bit(BNAD_RXQ_STARTED, &ccb->rcb[1]->flags); 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci 122762306a36Sopenharmony_ci queue_work(bnad->work_q, &rx_info->rx_cleanup_work); 122862306a36Sopenharmony_ci} 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_cistatic void 123162306a36Sopenharmony_cibnad_cb_rx_post(struct bnad *bnad, struct bna_rx *rx) 123262306a36Sopenharmony_ci{ 123362306a36Sopenharmony_ci struct bnad_rx_info *rx_info = rx->priv; 123462306a36Sopenharmony_ci struct bna_ccb *ccb; 123562306a36Sopenharmony_ci struct bna_rcb *rcb; 123662306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl; 123762306a36Sopenharmony_ci int i, j; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci for (i = 0; i < BNAD_MAX_RXP_PER_RX; i++) { 124062306a36Sopenharmony_ci rx_ctrl = &rx_info->rx_ctrl[i]; 124162306a36Sopenharmony_ci ccb = rx_ctrl->ccb; 124262306a36Sopenharmony_ci if (!ccb) 124362306a36Sopenharmony_ci continue; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci napi_enable(&rx_ctrl->napi); 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci for (j = 0; j < BNAD_MAX_RXQ_PER_RXP; j++) { 124862306a36Sopenharmony_ci rcb = ccb->rcb[j]; 124962306a36Sopenharmony_ci if (!rcb) 125062306a36Sopenharmony_ci continue; 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_ci bnad_rxq_alloc_init(bnad, rcb); 125362306a36Sopenharmony_ci set_bit(BNAD_RXQ_STARTED, &rcb->flags); 125462306a36Sopenharmony_ci set_bit(BNAD_RXQ_POST_OK, &rcb->flags); 125562306a36Sopenharmony_ci bnad_rxq_post(bnad, rcb); 125662306a36Sopenharmony_ci } 125762306a36Sopenharmony_ci } 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic void 126162306a36Sopenharmony_cibnad_cb_rx_disabled(void *arg, struct bna_rx *rx) 126262306a36Sopenharmony_ci{ 126362306a36Sopenharmony_ci struct bnad *bnad = (struct bnad *)arg; 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci complete(&bnad->bnad_completions.rx_comp); 126662306a36Sopenharmony_ci} 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_cistatic void 126962306a36Sopenharmony_cibnad_cb_rx_mcast_add(struct bnad *bnad, struct bna_rx *rx) 127062306a36Sopenharmony_ci{ 127162306a36Sopenharmony_ci bnad->bnad_completions.mcast_comp_status = BNA_CB_SUCCESS; 127262306a36Sopenharmony_ci complete(&bnad->bnad_completions.mcast_comp); 127362306a36Sopenharmony_ci} 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_civoid 127662306a36Sopenharmony_cibnad_cb_stats_get(struct bnad *bnad, enum bna_cb_status status, 127762306a36Sopenharmony_ci struct bna_stats *stats) 127862306a36Sopenharmony_ci{ 127962306a36Sopenharmony_ci if (status == BNA_CB_SUCCESS) 128062306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, hw_stats_updates); 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci if (!netif_running(bnad->netdev) || 128362306a36Sopenharmony_ci !test_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags)) 128462306a36Sopenharmony_ci return; 128562306a36Sopenharmony_ci 128662306a36Sopenharmony_ci mod_timer(&bnad->stats_timer, 128762306a36Sopenharmony_ci jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ)); 128862306a36Sopenharmony_ci} 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_cistatic void 129162306a36Sopenharmony_cibnad_cb_enet_mtu_set(struct bnad *bnad) 129262306a36Sopenharmony_ci{ 129362306a36Sopenharmony_ci bnad->bnad_completions.mtu_comp_status = BNA_CB_SUCCESS; 129462306a36Sopenharmony_ci complete(&bnad->bnad_completions.mtu_comp); 129562306a36Sopenharmony_ci} 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_civoid 129862306a36Sopenharmony_cibnad_cb_completion(void *arg, enum bfa_status status) 129962306a36Sopenharmony_ci{ 130062306a36Sopenharmony_ci struct bnad_iocmd_comp *iocmd_comp = 130162306a36Sopenharmony_ci (struct bnad_iocmd_comp *)arg; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci iocmd_comp->comp_status = (u32) status; 130462306a36Sopenharmony_ci complete(&iocmd_comp->comp); 130562306a36Sopenharmony_ci} 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci/* Resource allocation, free functions */ 130862306a36Sopenharmony_ci 130962306a36Sopenharmony_cistatic void 131062306a36Sopenharmony_cibnad_mem_free(struct bnad *bnad, 131162306a36Sopenharmony_ci struct bna_mem_info *mem_info) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci int i; 131462306a36Sopenharmony_ci dma_addr_t dma_pa; 131562306a36Sopenharmony_ci 131662306a36Sopenharmony_ci if (mem_info->mdl == NULL) 131762306a36Sopenharmony_ci return; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci for (i = 0; i < mem_info->num; i++) { 132062306a36Sopenharmony_ci if (mem_info->mdl[i].kva != NULL) { 132162306a36Sopenharmony_ci if (mem_info->mem_type == BNA_MEM_T_DMA) { 132262306a36Sopenharmony_ci BNA_GET_DMA_ADDR(&(mem_info->mdl[i].dma), 132362306a36Sopenharmony_ci dma_pa); 132462306a36Sopenharmony_ci dma_free_coherent(&bnad->pcidev->dev, 132562306a36Sopenharmony_ci mem_info->mdl[i].len, 132662306a36Sopenharmony_ci mem_info->mdl[i].kva, dma_pa); 132762306a36Sopenharmony_ci } else 132862306a36Sopenharmony_ci kfree(mem_info->mdl[i].kva); 132962306a36Sopenharmony_ci } 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci kfree(mem_info->mdl); 133262306a36Sopenharmony_ci mem_info->mdl = NULL; 133362306a36Sopenharmony_ci} 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_cistatic int 133662306a36Sopenharmony_cibnad_mem_alloc(struct bnad *bnad, 133762306a36Sopenharmony_ci struct bna_mem_info *mem_info) 133862306a36Sopenharmony_ci{ 133962306a36Sopenharmony_ci int i; 134062306a36Sopenharmony_ci dma_addr_t dma_pa; 134162306a36Sopenharmony_ci 134262306a36Sopenharmony_ci if ((mem_info->num == 0) || (mem_info->len == 0)) { 134362306a36Sopenharmony_ci mem_info->mdl = NULL; 134462306a36Sopenharmony_ci return 0; 134562306a36Sopenharmony_ci } 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci mem_info->mdl = kcalloc(mem_info->num, sizeof(struct bna_mem_descr), 134862306a36Sopenharmony_ci GFP_KERNEL); 134962306a36Sopenharmony_ci if (mem_info->mdl == NULL) 135062306a36Sopenharmony_ci return -ENOMEM; 135162306a36Sopenharmony_ci 135262306a36Sopenharmony_ci if (mem_info->mem_type == BNA_MEM_T_DMA) { 135362306a36Sopenharmony_ci for (i = 0; i < mem_info->num; i++) { 135462306a36Sopenharmony_ci mem_info->mdl[i].len = mem_info->len; 135562306a36Sopenharmony_ci mem_info->mdl[i].kva = 135662306a36Sopenharmony_ci dma_alloc_coherent(&bnad->pcidev->dev, 135762306a36Sopenharmony_ci mem_info->len, &dma_pa, 135862306a36Sopenharmony_ci GFP_KERNEL); 135962306a36Sopenharmony_ci if (mem_info->mdl[i].kva == NULL) 136062306a36Sopenharmony_ci goto err_return; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci BNA_SET_DMA_ADDR(dma_pa, 136362306a36Sopenharmony_ci &(mem_info->mdl[i].dma)); 136462306a36Sopenharmony_ci } 136562306a36Sopenharmony_ci } else { 136662306a36Sopenharmony_ci for (i = 0; i < mem_info->num; i++) { 136762306a36Sopenharmony_ci mem_info->mdl[i].len = mem_info->len; 136862306a36Sopenharmony_ci mem_info->mdl[i].kva = kzalloc(mem_info->len, 136962306a36Sopenharmony_ci GFP_KERNEL); 137062306a36Sopenharmony_ci if (mem_info->mdl[i].kva == NULL) 137162306a36Sopenharmony_ci goto err_return; 137262306a36Sopenharmony_ci } 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci return 0; 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_cierr_return: 137862306a36Sopenharmony_ci bnad_mem_free(bnad, mem_info); 137962306a36Sopenharmony_ci return -ENOMEM; 138062306a36Sopenharmony_ci} 138162306a36Sopenharmony_ci 138262306a36Sopenharmony_ci/* Free IRQ for Mailbox */ 138362306a36Sopenharmony_cistatic void 138462306a36Sopenharmony_cibnad_mbox_irq_free(struct bnad *bnad) 138562306a36Sopenharmony_ci{ 138662306a36Sopenharmony_ci int irq; 138762306a36Sopenharmony_ci unsigned long flags; 138862306a36Sopenharmony_ci 138962306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 139062306a36Sopenharmony_ci bnad_disable_mbox_irq(bnad); 139162306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci irq = BNAD_GET_MBOX_IRQ(bnad); 139462306a36Sopenharmony_ci free_irq(irq, bnad); 139562306a36Sopenharmony_ci} 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci/* 139862306a36Sopenharmony_ci * Allocates IRQ for Mailbox, but keep it disabled 139962306a36Sopenharmony_ci * This will be enabled once we get the mbox enable callback 140062306a36Sopenharmony_ci * from bna 140162306a36Sopenharmony_ci */ 140262306a36Sopenharmony_cistatic int 140362306a36Sopenharmony_cibnad_mbox_irq_alloc(struct bnad *bnad) 140462306a36Sopenharmony_ci{ 140562306a36Sopenharmony_ci int err = 0; 140662306a36Sopenharmony_ci unsigned long irq_flags, flags; 140762306a36Sopenharmony_ci u32 irq; 140862306a36Sopenharmony_ci irq_handler_t irq_handler; 140962306a36Sopenharmony_ci 141062306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 141162306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_MSIX) { 141262306a36Sopenharmony_ci irq_handler = (irq_handler_t)bnad_msix_mbox_handler; 141362306a36Sopenharmony_ci irq = bnad->msix_table[BNAD_MAILBOX_MSIX_INDEX].vector; 141462306a36Sopenharmony_ci irq_flags = 0; 141562306a36Sopenharmony_ci } else { 141662306a36Sopenharmony_ci irq_handler = (irq_handler_t)bnad_isr; 141762306a36Sopenharmony_ci irq = bnad->pcidev->irq; 141862306a36Sopenharmony_ci irq_flags = IRQF_SHARED; 141962306a36Sopenharmony_ci } 142062306a36Sopenharmony_ci 142162306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 142262306a36Sopenharmony_ci sprintf(bnad->mbox_irq_name, "%s", BNAD_NAME); 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci /* 142562306a36Sopenharmony_ci * Set the Mbox IRQ disable flag, so that the IRQ handler 142662306a36Sopenharmony_ci * called from request_irq() for SHARED IRQs do not execute 142762306a36Sopenharmony_ci */ 142862306a36Sopenharmony_ci set_bit(BNAD_RF_MBOX_IRQ_DISABLED, &bnad->run_flags); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, mbox_intr_disabled); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci err = request_irq(irq, irq_handler, irq_flags, 143362306a36Sopenharmony_ci bnad->mbox_irq_name, bnad); 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci return err; 143662306a36Sopenharmony_ci} 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_cistatic void 143962306a36Sopenharmony_cibnad_txrx_irq_free(struct bnad *bnad, struct bna_intr_info *intr_info) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci kfree(intr_info->idl); 144262306a36Sopenharmony_ci intr_info->idl = NULL; 144362306a36Sopenharmony_ci} 144462306a36Sopenharmony_ci 144562306a36Sopenharmony_ci/* Allocates Interrupt Descriptor List for MSIX/INT-X vectors */ 144662306a36Sopenharmony_cistatic int 144762306a36Sopenharmony_cibnad_txrx_irq_alloc(struct bnad *bnad, enum bnad_intr_source src, 144862306a36Sopenharmony_ci u32 txrx_id, struct bna_intr_info *intr_info) 144962306a36Sopenharmony_ci{ 145062306a36Sopenharmony_ci int i, vector_start = 0; 145162306a36Sopenharmony_ci u32 cfg_flags; 145262306a36Sopenharmony_ci unsigned long flags; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 145562306a36Sopenharmony_ci cfg_flags = bnad->cfg_flags; 145662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci if (cfg_flags & BNAD_CF_MSIX) { 145962306a36Sopenharmony_ci intr_info->intr_type = BNA_INTR_T_MSIX; 146062306a36Sopenharmony_ci intr_info->idl = kcalloc(intr_info->num, 146162306a36Sopenharmony_ci sizeof(struct bna_intr_descr), 146262306a36Sopenharmony_ci GFP_KERNEL); 146362306a36Sopenharmony_ci if (!intr_info->idl) 146462306a36Sopenharmony_ci return -ENOMEM; 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci switch (src) { 146762306a36Sopenharmony_ci case BNAD_INTR_TX: 146862306a36Sopenharmony_ci vector_start = BNAD_MAILBOX_MSIX_VECTORS + txrx_id; 146962306a36Sopenharmony_ci break; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci case BNAD_INTR_RX: 147262306a36Sopenharmony_ci vector_start = BNAD_MAILBOX_MSIX_VECTORS + 147362306a36Sopenharmony_ci (bnad->num_tx * bnad->num_txq_per_tx) + 147462306a36Sopenharmony_ci txrx_id; 147562306a36Sopenharmony_ci break; 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci default: 147862306a36Sopenharmony_ci BUG(); 147962306a36Sopenharmony_ci } 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci for (i = 0; i < intr_info->num; i++) 148262306a36Sopenharmony_ci intr_info->idl[i].vector = vector_start + i; 148362306a36Sopenharmony_ci } else { 148462306a36Sopenharmony_ci intr_info->intr_type = BNA_INTR_T_INTX; 148562306a36Sopenharmony_ci intr_info->num = 1; 148662306a36Sopenharmony_ci intr_info->idl = kcalloc(intr_info->num, 148762306a36Sopenharmony_ci sizeof(struct bna_intr_descr), 148862306a36Sopenharmony_ci GFP_KERNEL); 148962306a36Sopenharmony_ci if (!intr_info->idl) 149062306a36Sopenharmony_ci return -ENOMEM; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_ci switch (src) { 149362306a36Sopenharmony_ci case BNAD_INTR_TX: 149462306a36Sopenharmony_ci intr_info->idl[0].vector = BNAD_INTX_TX_IB_BITMASK; 149562306a36Sopenharmony_ci break; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci case BNAD_INTR_RX: 149862306a36Sopenharmony_ci intr_info->idl[0].vector = BNAD_INTX_RX_IB_BITMASK; 149962306a36Sopenharmony_ci break; 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci return 0; 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci/* NOTE: Should be called for MSIX only 150662306a36Sopenharmony_ci * Unregisters Tx MSIX vector(s) from the kernel 150762306a36Sopenharmony_ci */ 150862306a36Sopenharmony_cistatic void 150962306a36Sopenharmony_cibnad_tx_msix_unregister(struct bnad *bnad, struct bnad_tx_info *tx_info, 151062306a36Sopenharmony_ci int num_txqs) 151162306a36Sopenharmony_ci{ 151262306a36Sopenharmony_ci int i; 151362306a36Sopenharmony_ci int vector_num; 151462306a36Sopenharmony_ci 151562306a36Sopenharmony_ci for (i = 0; i < num_txqs; i++) { 151662306a36Sopenharmony_ci if (tx_info->tcb[i] == NULL) 151762306a36Sopenharmony_ci continue; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci vector_num = tx_info->tcb[i]->intr_vector; 152062306a36Sopenharmony_ci free_irq(bnad->msix_table[vector_num].vector, tx_info->tcb[i]); 152162306a36Sopenharmony_ci } 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci/* NOTE: Should be called for MSIX only 152562306a36Sopenharmony_ci * Registers Tx MSIX vector(s) and ISR(s), cookie with the kernel 152662306a36Sopenharmony_ci */ 152762306a36Sopenharmony_cistatic int 152862306a36Sopenharmony_cibnad_tx_msix_register(struct bnad *bnad, struct bnad_tx_info *tx_info, 152962306a36Sopenharmony_ci u32 tx_id, int num_txqs) 153062306a36Sopenharmony_ci{ 153162306a36Sopenharmony_ci int i; 153262306a36Sopenharmony_ci int err; 153362306a36Sopenharmony_ci int vector_num; 153462306a36Sopenharmony_ci 153562306a36Sopenharmony_ci for (i = 0; i < num_txqs; i++) { 153662306a36Sopenharmony_ci vector_num = tx_info->tcb[i]->intr_vector; 153762306a36Sopenharmony_ci sprintf(tx_info->tcb[i]->name, "%s TXQ %d", bnad->netdev->name, 153862306a36Sopenharmony_ci tx_id + tx_info->tcb[i]->id); 153962306a36Sopenharmony_ci err = request_irq(bnad->msix_table[vector_num].vector, 154062306a36Sopenharmony_ci (irq_handler_t)bnad_msix_tx, 0, 154162306a36Sopenharmony_ci tx_info->tcb[i]->name, 154262306a36Sopenharmony_ci tx_info->tcb[i]); 154362306a36Sopenharmony_ci if (err) 154462306a36Sopenharmony_ci goto err_return; 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci return 0; 154862306a36Sopenharmony_ci 154962306a36Sopenharmony_cierr_return: 155062306a36Sopenharmony_ci if (i > 0) 155162306a36Sopenharmony_ci bnad_tx_msix_unregister(bnad, tx_info, (i - 1)); 155262306a36Sopenharmony_ci return -1; 155362306a36Sopenharmony_ci} 155462306a36Sopenharmony_ci 155562306a36Sopenharmony_ci/* NOTE: Should be called for MSIX only 155662306a36Sopenharmony_ci * Unregisters Rx MSIX vector(s) from the kernel 155762306a36Sopenharmony_ci */ 155862306a36Sopenharmony_cistatic void 155962306a36Sopenharmony_cibnad_rx_msix_unregister(struct bnad *bnad, struct bnad_rx_info *rx_info, 156062306a36Sopenharmony_ci int num_rxps) 156162306a36Sopenharmony_ci{ 156262306a36Sopenharmony_ci int i; 156362306a36Sopenharmony_ci int vector_num; 156462306a36Sopenharmony_ci 156562306a36Sopenharmony_ci for (i = 0; i < num_rxps; i++) { 156662306a36Sopenharmony_ci if (rx_info->rx_ctrl[i].ccb == NULL) 156762306a36Sopenharmony_ci continue; 156862306a36Sopenharmony_ci 156962306a36Sopenharmony_ci vector_num = rx_info->rx_ctrl[i].ccb->intr_vector; 157062306a36Sopenharmony_ci free_irq(bnad->msix_table[vector_num].vector, 157162306a36Sopenharmony_ci rx_info->rx_ctrl[i].ccb); 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci} 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci/* NOTE: Should be called for MSIX only 157662306a36Sopenharmony_ci * Registers Tx MSIX vector(s) and ISR(s), cookie with the kernel 157762306a36Sopenharmony_ci */ 157862306a36Sopenharmony_cistatic int 157962306a36Sopenharmony_cibnad_rx_msix_register(struct bnad *bnad, struct bnad_rx_info *rx_info, 158062306a36Sopenharmony_ci u32 rx_id, int num_rxps) 158162306a36Sopenharmony_ci{ 158262306a36Sopenharmony_ci int i; 158362306a36Sopenharmony_ci int err; 158462306a36Sopenharmony_ci int vector_num; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci for (i = 0; i < num_rxps; i++) { 158762306a36Sopenharmony_ci vector_num = rx_info->rx_ctrl[i].ccb->intr_vector; 158862306a36Sopenharmony_ci sprintf(rx_info->rx_ctrl[i].ccb->name, "%s CQ %d", 158962306a36Sopenharmony_ci bnad->netdev->name, 159062306a36Sopenharmony_ci rx_id + rx_info->rx_ctrl[i].ccb->id); 159162306a36Sopenharmony_ci err = request_irq(bnad->msix_table[vector_num].vector, 159262306a36Sopenharmony_ci (irq_handler_t)bnad_msix_rx, 0, 159362306a36Sopenharmony_ci rx_info->rx_ctrl[i].ccb->name, 159462306a36Sopenharmony_ci rx_info->rx_ctrl[i].ccb); 159562306a36Sopenharmony_ci if (err) 159662306a36Sopenharmony_ci goto err_return; 159762306a36Sopenharmony_ci } 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci return 0; 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_cierr_return: 160262306a36Sopenharmony_ci if (i > 0) 160362306a36Sopenharmony_ci bnad_rx_msix_unregister(bnad, rx_info, (i - 1)); 160462306a36Sopenharmony_ci return -1; 160562306a36Sopenharmony_ci} 160662306a36Sopenharmony_ci 160762306a36Sopenharmony_ci/* Free Tx object Resources */ 160862306a36Sopenharmony_cistatic void 160962306a36Sopenharmony_cibnad_tx_res_free(struct bnad *bnad, struct bna_res_info *res_info) 161062306a36Sopenharmony_ci{ 161162306a36Sopenharmony_ci int i; 161262306a36Sopenharmony_ci 161362306a36Sopenharmony_ci for (i = 0; i < BNA_TX_RES_T_MAX; i++) { 161462306a36Sopenharmony_ci if (res_info[i].res_type == BNA_RES_T_MEM) 161562306a36Sopenharmony_ci bnad_mem_free(bnad, &res_info[i].res_u.mem_info); 161662306a36Sopenharmony_ci else if (res_info[i].res_type == BNA_RES_T_INTR) 161762306a36Sopenharmony_ci bnad_txrx_irq_free(bnad, &res_info[i].res_u.intr_info); 161862306a36Sopenharmony_ci } 161962306a36Sopenharmony_ci} 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci/* Allocates memory and interrupt resources for Tx object */ 162262306a36Sopenharmony_cistatic int 162362306a36Sopenharmony_cibnad_tx_res_alloc(struct bnad *bnad, struct bna_res_info *res_info, 162462306a36Sopenharmony_ci u32 tx_id) 162562306a36Sopenharmony_ci{ 162662306a36Sopenharmony_ci int i, err = 0; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci for (i = 0; i < BNA_TX_RES_T_MAX; i++) { 162962306a36Sopenharmony_ci if (res_info[i].res_type == BNA_RES_T_MEM) 163062306a36Sopenharmony_ci err = bnad_mem_alloc(bnad, 163162306a36Sopenharmony_ci &res_info[i].res_u.mem_info); 163262306a36Sopenharmony_ci else if (res_info[i].res_type == BNA_RES_T_INTR) 163362306a36Sopenharmony_ci err = bnad_txrx_irq_alloc(bnad, BNAD_INTR_TX, tx_id, 163462306a36Sopenharmony_ci &res_info[i].res_u.intr_info); 163562306a36Sopenharmony_ci if (err) 163662306a36Sopenharmony_ci goto err_return; 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci return 0; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_cierr_return: 164162306a36Sopenharmony_ci bnad_tx_res_free(bnad, res_info); 164262306a36Sopenharmony_ci return err; 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci/* Free Rx object Resources */ 164662306a36Sopenharmony_cistatic void 164762306a36Sopenharmony_cibnad_rx_res_free(struct bnad *bnad, struct bna_res_info *res_info) 164862306a36Sopenharmony_ci{ 164962306a36Sopenharmony_ci int i; 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci for (i = 0; i < BNA_RX_RES_T_MAX; i++) { 165262306a36Sopenharmony_ci if (res_info[i].res_type == BNA_RES_T_MEM) 165362306a36Sopenharmony_ci bnad_mem_free(bnad, &res_info[i].res_u.mem_info); 165462306a36Sopenharmony_ci else if (res_info[i].res_type == BNA_RES_T_INTR) 165562306a36Sopenharmony_ci bnad_txrx_irq_free(bnad, &res_info[i].res_u.intr_info); 165662306a36Sopenharmony_ci } 165762306a36Sopenharmony_ci} 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci/* Allocates memory and interrupt resources for Rx object */ 166062306a36Sopenharmony_cistatic int 166162306a36Sopenharmony_cibnad_rx_res_alloc(struct bnad *bnad, struct bna_res_info *res_info, 166262306a36Sopenharmony_ci uint rx_id) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci int i, err = 0; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci /* All memory needs to be allocated before setup_ccbs */ 166762306a36Sopenharmony_ci for (i = 0; i < BNA_RX_RES_T_MAX; i++) { 166862306a36Sopenharmony_ci if (res_info[i].res_type == BNA_RES_T_MEM) 166962306a36Sopenharmony_ci err = bnad_mem_alloc(bnad, 167062306a36Sopenharmony_ci &res_info[i].res_u.mem_info); 167162306a36Sopenharmony_ci else if (res_info[i].res_type == BNA_RES_T_INTR) 167262306a36Sopenharmony_ci err = bnad_txrx_irq_alloc(bnad, BNAD_INTR_RX, rx_id, 167362306a36Sopenharmony_ci &res_info[i].res_u.intr_info); 167462306a36Sopenharmony_ci if (err) 167562306a36Sopenharmony_ci goto err_return; 167662306a36Sopenharmony_ci } 167762306a36Sopenharmony_ci return 0; 167862306a36Sopenharmony_ci 167962306a36Sopenharmony_cierr_return: 168062306a36Sopenharmony_ci bnad_rx_res_free(bnad, res_info); 168162306a36Sopenharmony_ci return err; 168262306a36Sopenharmony_ci} 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci/* Timer callbacks */ 168562306a36Sopenharmony_ci/* a) IOC timer */ 168662306a36Sopenharmony_cistatic void 168762306a36Sopenharmony_cibnad_ioc_timeout(struct timer_list *t) 168862306a36Sopenharmony_ci{ 168962306a36Sopenharmony_ci struct bnad *bnad = from_timer(bnad, t, bna.ioceth.ioc.ioc_timer); 169062306a36Sopenharmony_ci unsigned long flags; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 169362306a36Sopenharmony_ci bfa_nw_ioc_timeout(&bnad->bna.ioceth.ioc); 169462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 169562306a36Sopenharmony_ci} 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_cistatic void 169862306a36Sopenharmony_cibnad_ioc_hb_check(struct timer_list *t) 169962306a36Sopenharmony_ci{ 170062306a36Sopenharmony_ci struct bnad *bnad = from_timer(bnad, t, bna.ioceth.ioc.hb_timer); 170162306a36Sopenharmony_ci unsigned long flags; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 170462306a36Sopenharmony_ci bfa_nw_ioc_hb_check(&bnad->bna.ioceth.ioc); 170562306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_cistatic void 170962306a36Sopenharmony_cibnad_iocpf_timeout(struct timer_list *t) 171062306a36Sopenharmony_ci{ 171162306a36Sopenharmony_ci struct bnad *bnad = from_timer(bnad, t, bna.ioceth.ioc.iocpf_timer); 171262306a36Sopenharmony_ci unsigned long flags; 171362306a36Sopenharmony_ci 171462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 171562306a36Sopenharmony_ci bfa_nw_iocpf_timeout(&bnad->bna.ioceth.ioc); 171662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 171762306a36Sopenharmony_ci} 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_cistatic void 172062306a36Sopenharmony_cibnad_iocpf_sem_timeout(struct timer_list *t) 172162306a36Sopenharmony_ci{ 172262306a36Sopenharmony_ci struct bnad *bnad = from_timer(bnad, t, bna.ioceth.ioc.sem_timer); 172362306a36Sopenharmony_ci unsigned long flags; 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 172662306a36Sopenharmony_ci bfa_nw_iocpf_sem_timeout(&bnad->bna.ioceth.ioc); 172762306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 172862306a36Sopenharmony_ci} 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci/* 173162306a36Sopenharmony_ci * All timer routines use bnad->bna_lock to protect against 173262306a36Sopenharmony_ci * the following race, which may occur in case of no locking: 173362306a36Sopenharmony_ci * Time CPU m CPU n 173462306a36Sopenharmony_ci * 0 1 = test_bit 173562306a36Sopenharmony_ci * 1 clear_bit 173662306a36Sopenharmony_ci * 2 del_timer_sync 173762306a36Sopenharmony_ci * 3 mod_timer 173862306a36Sopenharmony_ci */ 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci/* b) Dynamic Interrupt Moderation Timer */ 174162306a36Sopenharmony_cistatic void 174262306a36Sopenharmony_cibnad_dim_timeout(struct timer_list *t) 174362306a36Sopenharmony_ci{ 174462306a36Sopenharmony_ci struct bnad *bnad = from_timer(bnad, t, dim_timer); 174562306a36Sopenharmony_ci struct bnad_rx_info *rx_info; 174662306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl; 174762306a36Sopenharmony_ci int i, j; 174862306a36Sopenharmony_ci unsigned long flags; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci if (!netif_carrier_ok(bnad->netdev)) 175162306a36Sopenharmony_ci return; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 175462306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 175562306a36Sopenharmony_ci rx_info = &bnad->rx_info[i]; 175662306a36Sopenharmony_ci if (!rx_info->rx) 175762306a36Sopenharmony_ci continue; 175862306a36Sopenharmony_ci for (j = 0; j < bnad->num_rxp_per_rx; j++) { 175962306a36Sopenharmony_ci rx_ctrl = &rx_info->rx_ctrl[j]; 176062306a36Sopenharmony_ci if (!rx_ctrl->ccb) 176162306a36Sopenharmony_ci continue; 176262306a36Sopenharmony_ci bna_rx_dim_update(rx_ctrl->ccb); 176362306a36Sopenharmony_ci } 176462306a36Sopenharmony_ci } 176562306a36Sopenharmony_ci 176662306a36Sopenharmony_ci /* Check for BNAD_CF_DIM_ENABLED, does not eliminate a race */ 176762306a36Sopenharmony_ci if (test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags)) 176862306a36Sopenharmony_ci mod_timer(&bnad->dim_timer, 176962306a36Sopenharmony_ci jiffies + msecs_to_jiffies(BNAD_DIM_TIMER_FREQ)); 177062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 177162306a36Sopenharmony_ci} 177262306a36Sopenharmony_ci 177362306a36Sopenharmony_ci/* c) Statistics Timer */ 177462306a36Sopenharmony_cistatic void 177562306a36Sopenharmony_cibnad_stats_timeout(struct timer_list *t) 177662306a36Sopenharmony_ci{ 177762306a36Sopenharmony_ci struct bnad *bnad = from_timer(bnad, t, stats_timer); 177862306a36Sopenharmony_ci unsigned long flags; 177962306a36Sopenharmony_ci 178062306a36Sopenharmony_ci if (!netif_running(bnad->netdev) || 178162306a36Sopenharmony_ci !test_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags)) 178262306a36Sopenharmony_ci return; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 178562306a36Sopenharmony_ci bna_hw_stats_get(&bnad->bna); 178662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 178762306a36Sopenharmony_ci} 178862306a36Sopenharmony_ci 178962306a36Sopenharmony_ci/* 179062306a36Sopenharmony_ci * Set up timer for DIM 179162306a36Sopenharmony_ci * Called with bnad->bna_lock held 179262306a36Sopenharmony_ci */ 179362306a36Sopenharmony_civoid 179462306a36Sopenharmony_cibnad_dim_timer_start(struct bnad *bnad) 179562306a36Sopenharmony_ci{ 179662306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED && 179762306a36Sopenharmony_ci !test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags)) { 179862306a36Sopenharmony_ci timer_setup(&bnad->dim_timer, bnad_dim_timeout, 0); 179962306a36Sopenharmony_ci set_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags); 180062306a36Sopenharmony_ci mod_timer(&bnad->dim_timer, 180162306a36Sopenharmony_ci jiffies + msecs_to_jiffies(BNAD_DIM_TIMER_FREQ)); 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci} 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci/* 180662306a36Sopenharmony_ci * Set up timer for statistics 180762306a36Sopenharmony_ci * Called with mutex_lock(&bnad->conf_mutex) held 180862306a36Sopenharmony_ci */ 180962306a36Sopenharmony_cistatic void 181062306a36Sopenharmony_cibnad_stats_timer_start(struct bnad *bnad) 181162306a36Sopenharmony_ci{ 181262306a36Sopenharmony_ci unsigned long flags; 181362306a36Sopenharmony_ci 181462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 181562306a36Sopenharmony_ci if (!test_and_set_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags)) { 181662306a36Sopenharmony_ci timer_setup(&bnad->stats_timer, bnad_stats_timeout, 0); 181762306a36Sopenharmony_ci mod_timer(&bnad->stats_timer, 181862306a36Sopenharmony_ci jiffies + msecs_to_jiffies(BNAD_STATS_TIMER_FREQ)); 181962306a36Sopenharmony_ci } 182062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 182162306a36Sopenharmony_ci} 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci/* 182462306a36Sopenharmony_ci * Stops the stats timer 182562306a36Sopenharmony_ci * Called with mutex_lock(&bnad->conf_mutex) held 182662306a36Sopenharmony_ci */ 182762306a36Sopenharmony_cistatic void 182862306a36Sopenharmony_cibnad_stats_timer_stop(struct bnad *bnad) 182962306a36Sopenharmony_ci{ 183062306a36Sopenharmony_ci int to_del = 0; 183162306a36Sopenharmony_ci unsigned long flags; 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 183462306a36Sopenharmony_ci if (test_and_clear_bit(BNAD_RF_STATS_TIMER_RUNNING, &bnad->run_flags)) 183562306a36Sopenharmony_ci to_del = 1; 183662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 183762306a36Sopenharmony_ci if (to_del) 183862306a36Sopenharmony_ci del_timer_sync(&bnad->stats_timer); 183962306a36Sopenharmony_ci} 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci/* Utilities */ 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_cistatic void 184462306a36Sopenharmony_cibnad_netdev_mc_list_get(struct net_device *netdev, u8 *mc_list) 184562306a36Sopenharmony_ci{ 184662306a36Sopenharmony_ci int i = 1; /* Index 0 has broadcast address */ 184762306a36Sopenharmony_ci struct netdev_hw_addr *mc_addr; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci netdev_for_each_mc_addr(mc_addr, netdev) { 185062306a36Sopenharmony_ci ether_addr_copy(&mc_list[i * ETH_ALEN], &mc_addr->addr[0]); 185162306a36Sopenharmony_ci i++; 185262306a36Sopenharmony_ci } 185362306a36Sopenharmony_ci} 185462306a36Sopenharmony_ci 185562306a36Sopenharmony_cistatic int 185662306a36Sopenharmony_cibnad_napi_poll_rx(struct napi_struct *napi, int budget) 185762306a36Sopenharmony_ci{ 185862306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl = 185962306a36Sopenharmony_ci container_of(napi, struct bnad_rx_ctrl, napi); 186062306a36Sopenharmony_ci struct bnad *bnad = rx_ctrl->bnad; 186162306a36Sopenharmony_ci int rcvd = 0; 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci rx_ctrl->rx_poll_ctr++; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci if (!netif_carrier_ok(bnad->netdev)) 186662306a36Sopenharmony_ci goto poll_exit; 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_ci rcvd = bnad_cq_process(bnad, rx_ctrl->ccb, budget); 186962306a36Sopenharmony_ci if (rcvd >= budget) 187062306a36Sopenharmony_ci return rcvd; 187162306a36Sopenharmony_ci 187262306a36Sopenharmony_cipoll_exit: 187362306a36Sopenharmony_ci napi_complete_done(napi, rcvd); 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci rx_ctrl->rx_complete++; 187662306a36Sopenharmony_ci 187762306a36Sopenharmony_ci if (rx_ctrl->ccb) 187862306a36Sopenharmony_ci bnad_enable_rx_irq_unsafe(rx_ctrl->ccb); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci return rcvd; 188162306a36Sopenharmony_ci} 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_cistatic void 188462306a36Sopenharmony_cibnad_napi_add(struct bnad *bnad, u32 rx_id) 188562306a36Sopenharmony_ci{ 188662306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl; 188762306a36Sopenharmony_ci int i; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci /* Initialize & enable NAPI */ 189062306a36Sopenharmony_ci for (i = 0; i < bnad->num_rxp_per_rx; i++) { 189162306a36Sopenharmony_ci rx_ctrl = &bnad->rx_info[rx_id].rx_ctrl[i]; 189262306a36Sopenharmony_ci netif_napi_add(bnad->netdev, &rx_ctrl->napi, 189362306a36Sopenharmony_ci bnad_napi_poll_rx); 189462306a36Sopenharmony_ci } 189562306a36Sopenharmony_ci} 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_cistatic void 189862306a36Sopenharmony_cibnad_napi_delete(struct bnad *bnad, u32 rx_id) 189962306a36Sopenharmony_ci{ 190062306a36Sopenharmony_ci int i; 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci /* First disable and then clean up */ 190362306a36Sopenharmony_ci for (i = 0; i < bnad->num_rxp_per_rx; i++) 190462306a36Sopenharmony_ci netif_napi_del(&bnad->rx_info[rx_id].rx_ctrl[i].napi); 190562306a36Sopenharmony_ci} 190662306a36Sopenharmony_ci 190762306a36Sopenharmony_ci/* Should be held with conf_lock held */ 190862306a36Sopenharmony_civoid 190962306a36Sopenharmony_cibnad_destroy_tx(struct bnad *bnad, u32 tx_id) 191062306a36Sopenharmony_ci{ 191162306a36Sopenharmony_ci struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id]; 191262306a36Sopenharmony_ci struct bna_res_info *res_info = &bnad->tx_res_info[tx_id].res_info[0]; 191362306a36Sopenharmony_ci unsigned long flags; 191462306a36Sopenharmony_ci 191562306a36Sopenharmony_ci if (!tx_info->tx) 191662306a36Sopenharmony_ci return; 191762306a36Sopenharmony_ci 191862306a36Sopenharmony_ci init_completion(&bnad->bnad_completions.tx_comp); 191962306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 192062306a36Sopenharmony_ci bna_tx_disable(tx_info->tx, BNA_HARD_CLEANUP, bnad_cb_tx_disabled); 192162306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 192262306a36Sopenharmony_ci wait_for_completion(&bnad->bnad_completions.tx_comp); 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_ci if (tx_info->tcb[0]->intr_type == BNA_INTR_T_MSIX) 192562306a36Sopenharmony_ci bnad_tx_msix_unregister(bnad, tx_info, 192662306a36Sopenharmony_ci bnad->num_txq_per_tx); 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 192962306a36Sopenharmony_ci bna_tx_destroy(tx_info->tx); 193062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci tx_info->tx = NULL; 193362306a36Sopenharmony_ci tx_info->tx_id = 0; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci bnad_tx_res_free(bnad, res_info); 193662306a36Sopenharmony_ci} 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci/* Should be held with conf_lock held */ 193962306a36Sopenharmony_ciint 194062306a36Sopenharmony_cibnad_setup_tx(struct bnad *bnad, u32 tx_id) 194162306a36Sopenharmony_ci{ 194262306a36Sopenharmony_ci int err; 194362306a36Sopenharmony_ci struct bnad_tx_info *tx_info = &bnad->tx_info[tx_id]; 194462306a36Sopenharmony_ci struct bna_res_info *res_info = &bnad->tx_res_info[tx_id].res_info[0]; 194562306a36Sopenharmony_ci struct bna_intr_info *intr_info = 194662306a36Sopenharmony_ci &res_info[BNA_TX_RES_INTR_T_TXCMPL].res_u.intr_info; 194762306a36Sopenharmony_ci struct bna_tx_config *tx_config = &bnad->tx_config[tx_id]; 194862306a36Sopenharmony_ci static const struct bna_tx_event_cbfn tx_cbfn = { 194962306a36Sopenharmony_ci .tcb_setup_cbfn = bnad_cb_tcb_setup, 195062306a36Sopenharmony_ci .tcb_destroy_cbfn = bnad_cb_tcb_destroy, 195162306a36Sopenharmony_ci .tx_stall_cbfn = bnad_cb_tx_stall, 195262306a36Sopenharmony_ci .tx_resume_cbfn = bnad_cb_tx_resume, 195362306a36Sopenharmony_ci .tx_cleanup_cbfn = bnad_cb_tx_cleanup, 195462306a36Sopenharmony_ci }; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci struct bna_tx *tx; 195762306a36Sopenharmony_ci unsigned long flags; 195862306a36Sopenharmony_ci 195962306a36Sopenharmony_ci tx_info->tx_id = tx_id; 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci /* Initialize the Tx object configuration */ 196262306a36Sopenharmony_ci tx_config->num_txq = bnad->num_txq_per_tx; 196362306a36Sopenharmony_ci tx_config->txq_depth = bnad->txq_depth; 196462306a36Sopenharmony_ci tx_config->tx_type = BNA_TX_T_REGULAR; 196562306a36Sopenharmony_ci tx_config->coalescing_timeo = bnad->tx_coalescing_timeo; 196662306a36Sopenharmony_ci 196762306a36Sopenharmony_ci /* Get BNA's resource requirement for one tx object */ 196862306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 196962306a36Sopenharmony_ci bna_tx_res_req(bnad->num_txq_per_tx, 197062306a36Sopenharmony_ci bnad->txq_depth, res_info); 197162306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci /* Fill Unmap Q memory requirements */ 197462306a36Sopenharmony_ci BNAD_FILL_UNMAPQ_MEM_REQ(&res_info[BNA_TX_RES_MEM_T_UNMAPQ], 197562306a36Sopenharmony_ci bnad->num_txq_per_tx, (sizeof(struct bnad_tx_unmap) * 197662306a36Sopenharmony_ci bnad->txq_depth)); 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci /* Allocate resources */ 197962306a36Sopenharmony_ci err = bnad_tx_res_alloc(bnad, res_info, tx_id); 198062306a36Sopenharmony_ci if (err) 198162306a36Sopenharmony_ci return err; 198262306a36Sopenharmony_ci 198362306a36Sopenharmony_ci /* Ask BNA to create one Tx object, supplying required resources */ 198462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 198562306a36Sopenharmony_ci tx = bna_tx_create(&bnad->bna, bnad, tx_config, &tx_cbfn, res_info, 198662306a36Sopenharmony_ci tx_info); 198762306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 198862306a36Sopenharmony_ci if (!tx) { 198962306a36Sopenharmony_ci err = -ENOMEM; 199062306a36Sopenharmony_ci goto err_return; 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci tx_info->tx = tx; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci INIT_DELAYED_WORK(&tx_info->tx_cleanup_work, 199562306a36Sopenharmony_ci (work_func_t)bnad_tx_cleanup); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci /* Register ISR for the Tx object */ 199862306a36Sopenharmony_ci if (intr_info->intr_type == BNA_INTR_T_MSIX) { 199962306a36Sopenharmony_ci err = bnad_tx_msix_register(bnad, tx_info, 200062306a36Sopenharmony_ci tx_id, bnad->num_txq_per_tx); 200162306a36Sopenharmony_ci if (err) 200262306a36Sopenharmony_ci goto cleanup_tx; 200362306a36Sopenharmony_ci } 200462306a36Sopenharmony_ci 200562306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 200662306a36Sopenharmony_ci bna_tx_enable(tx); 200762306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci return 0; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_cicleanup_tx: 201262306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 201362306a36Sopenharmony_ci bna_tx_destroy(tx_info->tx); 201462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 201562306a36Sopenharmony_ci tx_info->tx = NULL; 201662306a36Sopenharmony_ci tx_info->tx_id = 0; 201762306a36Sopenharmony_cierr_return: 201862306a36Sopenharmony_ci bnad_tx_res_free(bnad, res_info); 201962306a36Sopenharmony_ci return err; 202062306a36Sopenharmony_ci} 202162306a36Sopenharmony_ci 202262306a36Sopenharmony_ci/* Setup the rx config for bna_rx_create */ 202362306a36Sopenharmony_ci/* bnad decides the configuration */ 202462306a36Sopenharmony_cistatic void 202562306a36Sopenharmony_cibnad_init_rx_config(struct bnad *bnad, struct bna_rx_config *rx_config) 202662306a36Sopenharmony_ci{ 202762306a36Sopenharmony_ci memset(rx_config, 0, sizeof(*rx_config)); 202862306a36Sopenharmony_ci rx_config->rx_type = BNA_RX_T_REGULAR; 202962306a36Sopenharmony_ci rx_config->num_paths = bnad->num_rxp_per_rx; 203062306a36Sopenharmony_ci rx_config->coalescing_timeo = bnad->rx_coalescing_timeo; 203162306a36Sopenharmony_ci 203262306a36Sopenharmony_ci if (bnad->num_rxp_per_rx > 1) { 203362306a36Sopenharmony_ci rx_config->rss_status = BNA_STATUS_T_ENABLED; 203462306a36Sopenharmony_ci rx_config->rss_config.hash_type = 203562306a36Sopenharmony_ci (BFI_ENET_RSS_IPV6 | 203662306a36Sopenharmony_ci BFI_ENET_RSS_IPV6_TCP | 203762306a36Sopenharmony_ci BFI_ENET_RSS_IPV4 | 203862306a36Sopenharmony_ci BFI_ENET_RSS_IPV4_TCP); 203962306a36Sopenharmony_ci rx_config->rss_config.hash_mask = 204062306a36Sopenharmony_ci bnad->num_rxp_per_rx - 1; 204162306a36Sopenharmony_ci netdev_rss_key_fill(rx_config->rss_config.toeplitz_hash_key, 204262306a36Sopenharmony_ci sizeof(rx_config->rss_config.toeplitz_hash_key)); 204362306a36Sopenharmony_ci } else { 204462306a36Sopenharmony_ci rx_config->rss_status = BNA_STATUS_T_DISABLED; 204562306a36Sopenharmony_ci memset(&rx_config->rss_config, 0, 204662306a36Sopenharmony_ci sizeof(rx_config->rss_config)); 204762306a36Sopenharmony_ci } 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci rx_config->frame_size = BNAD_FRAME_SIZE(bnad->netdev->mtu); 205062306a36Sopenharmony_ci rx_config->q0_multi_buf = BNA_STATUS_T_DISABLED; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci /* BNA_RXP_SINGLE - one data-buffer queue 205362306a36Sopenharmony_ci * BNA_RXP_SLR - one small-buffer and one large-buffer queues 205462306a36Sopenharmony_ci * BNA_RXP_HDS - one header-buffer and one data-buffer queues 205562306a36Sopenharmony_ci */ 205662306a36Sopenharmony_ci /* TODO: configurable param for queue type */ 205762306a36Sopenharmony_ci rx_config->rxp_type = BNA_RXP_SLR; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci if (BNAD_PCI_DEV_IS_CAT2(bnad) && 206062306a36Sopenharmony_ci rx_config->frame_size > 4096) { 206162306a36Sopenharmony_ci /* though size_routing_enable is set in SLR, 206262306a36Sopenharmony_ci * small packets may get routed to same rxq. 206362306a36Sopenharmony_ci * set buf_size to 2048 instead of PAGE_SIZE. 206462306a36Sopenharmony_ci */ 206562306a36Sopenharmony_ci rx_config->q0_buf_size = 2048; 206662306a36Sopenharmony_ci /* this should be in multiples of 2 */ 206762306a36Sopenharmony_ci rx_config->q0_num_vecs = 4; 206862306a36Sopenharmony_ci rx_config->q0_depth = bnad->rxq_depth * rx_config->q0_num_vecs; 206962306a36Sopenharmony_ci rx_config->q0_multi_buf = BNA_STATUS_T_ENABLED; 207062306a36Sopenharmony_ci } else { 207162306a36Sopenharmony_ci rx_config->q0_buf_size = rx_config->frame_size; 207262306a36Sopenharmony_ci rx_config->q0_num_vecs = 1; 207362306a36Sopenharmony_ci rx_config->q0_depth = bnad->rxq_depth; 207462306a36Sopenharmony_ci } 207562306a36Sopenharmony_ci 207662306a36Sopenharmony_ci /* initialize for q1 for BNA_RXP_SLR/BNA_RXP_HDS */ 207762306a36Sopenharmony_ci if (rx_config->rxp_type == BNA_RXP_SLR) { 207862306a36Sopenharmony_ci rx_config->q1_depth = bnad->rxq_depth; 207962306a36Sopenharmony_ci rx_config->q1_buf_size = BFI_SMALL_RXBUF_SIZE; 208062306a36Sopenharmony_ci } 208162306a36Sopenharmony_ci 208262306a36Sopenharmony_ci rx_config->vlan_strip_status = 208362306a36Sopenharmony_ci (bnad->netdev->features & NETIF_F_HW_VLAN_CTAG_RX) ? 208462306a36Sopenharmony_ci BNA_STATUS_T_ENABLED : BNA_STATUS_T_DISABLED; 208562306a36Sopenharmony_ci} 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_cistatic void 208862306a36Sopenharmony_cibnad_rx_ctrl_init(struct bnad *bnad, u32 rx_id) 208962306a36Sopenharmony_ci{ 209062306a36Sopenharmony_ci struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id]; 209162306a36Sopenharmony_ci int i; 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_ci for (i = 0; i < bnad->num_rxp_per_rx; i++) 209462306a36Sopenharmony_ci rx_info->rx_ctrl[i].bnad = bnad; 209562306a36Sopenharmony_ci} 209662306a36Sopenharmony_ci 209762306a36Sopenharmony_ci/* Called with mutex_lock(&bnad->conf_mutex) held */ 209862306a36Sopenharmony_cistatic u32 209962306a36Sopenharmony_cibnad_reinit_rx(struct bnad *bnad) 210062306a36Sopenharmony_ci{ 210162306a36Sopenharmony_ci struct net_device *netdev = bnad->netdev; 210262306a36Sopenharmony_ci u32 err = 0, current_err = 0; 210362306a36Sopenharmony_ci u32 rx_id = 0, count = 0; 210462306a36Sopenharmony_ci unsigned long flags; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci /* destroy and create new rx objects */ 210762306a36Sopenharmony_ci for (rx_id = 0; rx_id < bnad->num_rx; rx_id++) { 210862306a36Sopenharmony_ci if (!bnad->rx_info[rx_id].rx) 210962306a36Sopenharmony_ci continue; 211062306a36Sopenharmony_ci bnad_destroy_rx(bnad, rx_id); 211162306a36Sopenharmony_ci } 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 211462306a36Sopenharmony_ci bna_enet_mtu_set(&bnad->bna.enet, 211562306a36Sopenharmony_ci BNAD_FRAME_SIZE(bnad->netdev->mtu), NULL); 211662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 211762306a36Sopenharmony_ci 211862306a36Sopenharmony_ci for (rx_id = 0; rx_id < bnad->num_rx; rx_id++) { 211962306a36Sopenharmony_ci count++; 212062306a36Sopenharmony_ci current_err = bnad_setup_rx(bnad, rx_id); 212162306a36Sopenharmony_ci if (current_err && !err) { 212262306a36Sopenharmony_ci err = current_err; 212362306a36Sopenharmony_ci netdev_err(netdev, "RXQ:%u setup failed\n", rx_id); 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci } 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci /* restore rx configuration */ 212862306a36Sopenharmony_ci if (bnad->rx_info[0].rx && !err) { 212962306a36Sopenharmony_ci bnad_restore_vlans(bnad, 0); 213062306a36Sopenharmony_ci bnad_enable_default_bcast(bnad); 213162306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 213262306a36Sopenharmony_ci bnad_mac_addr_set_locked(bnad, netdev->dev_addr); 213362306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 213462306a36Sopenharmony_ci bnad_set_rx_mode(netdev); 213562306a36Sopenharmony_ci } 213662306a36Sopenharmony_ci 213762306a36Sopenharmony_ci return count; 213862306a36Sopenharmony_ci} 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci/* Called with bnad_conf_lock() held */ 214162306a36Sopenharmony_civoid 214262306a36Sopenharmony_cibnad_destroy_rx(struct bnad *bnad, u32 rx_id) 214362306a36Sopenharmony_ci{ 214462306a36Sopenharmony_ci struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id]; 214562306a36Sopenharmony_ci struct bna_rx_config *rx_config = &bnad->rx_config[rx_id]; 214662306a36Sopenharmony_ci struct bna_res_info *res_info = &bnad->rx_res_info[rx_id].res_info[0]; 214762306a36Sopenharmony_ci unsigned long flags; 214862306a36Sopenharmony_ci int to_del = 0; 214962306a36Sopenharmony_ci 215062306a36Sopenharmony_ci if (!rx_info->rx) 215162306a36Sopenharmony_ci return; 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_ci if (0 == rx_id) { 215462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 215562306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED && 215662306a36Sopenharmony_ci test_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags)) { 215762306a36Sopenharmony_ci clear_bit(BNAD_RF_DIM_TIMER_RUNNING, &bnad->run_flags); 215862306a36Sopenharmony_ci to_del = 1; 215962306a36Sopenharmony_ci } 216062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 216162306a36Sopenharmony_ci if (to_del) 216262306a36Sopenharmony_ci del_timer_sync(&bnad->dim_timer); 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci init_completion(&bnad->bnad_completions.rx_comp); 216662306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 216762306a36Sopenharmony_ci bna_rx_disable(rx_info->rx, BNA_HARD_CLEANUP, bnad_cb_rx_disabled); 216862306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 216962306a36Sopenharmony_ci wait_for_completion(&bnad->bnad_completions.rx_comp); 217062306a36Sopenharmony_ci 217162306a36Sopenharmony_ci if (rx_info->rx_ctrl[0].ccb->intr_type == BNA_INTR_T_MSIX) 217262306a36Sopenharmony_ci bnad_rx_msix_unregister(bnad, rx_info, rx_config->num_paths); 217362306a36Sopenharmony_ci 217462306a36Sopenharmony_ci bnad_napi_delete(bnad, rx_id); 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 217762306a36Sopenharmony_ci bna_rx_destroy(rx_info->rx); 217862306a36Sopenharmony_ci 217962306a36Sopenharmony_ci rx_info->rx = NULL; 218062306a36Sopenharmony_ci rx_info->rx_id = 0; 218162306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 218262306a36Sopenharmony_ci 218362306a36Sopenharmony_ci bnad_rx_res_free(bnad, res_info); 218462306a36Sopenharmony_ci} 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci/* Called with mutex_lock(&bnad->conf_mutex) held */ 218762306a36Sopenharmony_ciint 218862306a36Sopenharmony_cibnad_setup_rx(struct bnad *bnad, u32 rx_id) 218962306a36Sopenharmony_ci{ 219062306a36Sopenharmony_ci int err; 219162306a36Sopenharmony_ci struct bnad_rx_info *rx_info = &bnad->rx_info[rx_id]; 219262306a36Sopenharmony_ci struct bna_res_info *res_info = &bnad->rx_res_info[rx_id].res_info[0]; 219362306a36Sopenharmony_ci struct bna_intr_info *intr_info = 219462306a36Sopenharmony_ci &res_info[BNA_RX_RES_T_INTR].res_u.intr_info; 219562306a36Sopenharmony_ci struct bna_rx_config *rx_config = &bnad->rx_config[rx_id]; 219662306a36Sopenharmony_ci static const struct bna_rx_event_cbfn rx_cbfn = { 219762306a36Sopenharmony_ci .rcb_setup_cbfn = NULL, 219862306a36Sopenharmony_ci .rcb_destroy_cbfn = NULL, 219962306a36Sopenharmony_ci .ccb_setup_cbfn = bnad_cb_ccb_setup, 220062306a36Sopenharmony_ci .ccb_destroy_cbfn = bnad_cb_ccb_destroy, 220162306a36Sopenharmony_ci .rx_stall_cbfn = bnad_cb_rx_stall, 220262306a36Sopenharmony_ci .rx_cleanup_cbfn = bnad_cb_rx_cleanup, 220362306a36Sopenharmony_ci .rx_post_cbfn = bnad_cb_rx_post, 220462306a36Sopenharmony_ci }; 220562306a36Sopenharmony_ci struct bna_rx *rx; 220662306a36Sopenharmony_ci unsigned long flags; 220762306a36Sopenharmony_ci 220862306a36Sopenharmony_ci rx_info->rx_id = rx_id; 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_ci /* Initialize the Rx object configuration */ 221162306a36Sopenharmony_ci bnad_init_rx_config(bnad, rx_config); 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci /* Get BNA's resource requirement for one Rx object */ 221462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 221562306a36Sopenharmony_ci bna_rx_res_req(rx_config, res_info); 221662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci /* Fill Unmap Q memory requirements */ 221962306a36Sopenharmony_ci BNAD_FILL_UNMAPQ_MEM_REQ(&res_info[BNA_RX_RES_MEM_T_UNMAPDQ], 222062306a36Sopenharmony_ci rx_config->num_paths, 222162306a36Sopenharmony_ci (rx_config->q0_depth * 222262306a36Sopenharmony_ci sizeof(struct bnad_rx_unmap)) + 222362306a36Sopenharmony_ci sizeof(struct bnad_rx_unmap_q)); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci if (rx_config->rxp_type != BNA_RXP_SINGLE) { 222662306a36Sopenharmony_ci BNAD_FILL_UNMAPQ_MEM_REQ(&res_info[BNA_RX_RES_MEM_T_UNMAPHQ], 222762306a36Sopenharmony_ci rx_config->num_paths, 222862306a36Sopenharmony_ci (rx_config->q1_depth * 222962306a36Sopenharmony_ci sizeof(struct bnad_rx_unmap) + 223062306a36Sopenharmony_ci sizeof(struct bnad_rx_unmap_q))); 223162306a36Sopenharmony_ci } 223262306a36Sopenharmony_ci /* Allocate resource */ 223362306a36Sopenharmony_ci err = bnad_rx_res_alloc(bnad, res_info, rx_id); 223462306a36Sopenharmony_ci if (err) 223562306a36Sopenharmony_ci return err; 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci bnad_rx_ctrl_init(bnad, rx_id); 223862306a36Sopenharmony_ci 223962306a36Sopenharmony_ci /* Ask BNA to create one Rx object, supplying required resources */ 224062306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 224162306a36Sopenharmony_ci rx = bna_rx_create(&bnad->bna, bnad, rx_config, &rx_cbfn, res_info, 224262306a36Sopenharmony_ci rx_info); 224362306a36Sopenharmony_ci if (!rx) { 224462306a36Sopenharmony_ci err = -ENOMEM; 224562306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 224662306a36Sopenharmony_ci goto err_return; 224762306a36Sopenharmony_ci } 224862306a36Sopenharmony_ci rx_info->rx = rx; 224962306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci INIT_WORK(&rx_info->rx_cleanup_work, 225262306a36Sopenharmony_ci (work_func_t)(bnad_rx_cleanup)); 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci /* 225562306a36Sopenharmony_ci * Init NAPI, so that state is set to NAPI_STATE_SCHED, 225662306a36Sopenharmony_ci * so that IRQ handler cannot schedule NAPI at this point. 225762306a36Sopenharmony_ci */ 225862306a36Sopenharmony_ci bnad_napi_add(bnad, rx_id); 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci /* Register ISR for the Rx object */ 226162306a36Sopenharmony_ci if (intr_info->intr_type == BNA_INTR_T_MSIX) { 226262306a36Sopenharmony_ci err = bnad_rx_msix_register(bnad, rx_info, rx_id, 226362306a36Sopenharmony_ci rx_config->num_paths); 226462306a36Sopenharmony_ci if (err) 226562306a36Sopenharmony_ci goto err_return; 226662306a36Sopenharmony_ci } 226762306a36Sopenharmony_ci 226862306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 226962306a36Sopenharmony_ci if (0 == rx_id) { 227062306a36Sopenharmony_ci /* Set up Dynamic Interrupt Moderation Vector */ 227162306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_DIM_ENABLED) 227262306a36Sopenharmony_ci bna_rx_dim_reconfig(&bnad->bna, bna_napi_dim_vector); 227362306a36Sopenharmony_ci 227462306a36Sopenharmony_ci /* Enable VLAN filtering only on the default Rx */ 227562306a36Sopenharmony_ci bna_rx_vlanfilter_enable(rx); 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci /* Start the DIM timer */ 227862306a36Sopenharmony_ci bnad_dim_timer_start(bnad); 227962306a36Sopenharmony_ci } 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci bna_rx_enable(rx); 228262306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci return 0; 228562306a36Sopenharmony_ci 228662306a36Sopenharmony_cierr_return: 228762306a36Sopenharmony_ci bnad_destroy_rx(bnad, rx_id); 228862306a36Sopenharmony_ci return err; 228962306a36Sopenharmony_ci} 229062306a36Sopenharmony_ci 229162306a36Sopenharmony_ci/* Called with conf_lock & bnad->bna_lock held */ 229262306a36Sopenharmony_civoid 229362306a36Sopenharmony_cibnad_tx_coalescing_timeo_set(struct bnad *bnad) 229462306a36Sopenharmony_ci{ 229562306a36Sopenharmony_ci struct bnad_tx_info *tx_info; 229662306a36Sopenharmony_ci 229762306a36Sopenharmony_ci tx_info = &bnad->tx_info[0]; 229862306a36Sopenharmony_ci if (!tx_info->tx) 229962306a36Sopenharmony_ci return; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci bna_tx_coalescing_timeo_set(tx_info->tx, bnad->tx_coalescing_timeo); 230262306a36Sopenharmony_ci} 230362306a36Sopenharmony_ci 230462306a36Sopenharmony_ci/* Called with conf_lock & bnad->bna_lock held */ 230562306a36Sopenharmony_civoid 230662306a36Sopenharmony_cibnad_rx_coalescing_timeo_set(struct bnad *bnad) 230762306a36Sopenharmony_ci{ 230862306a36Sopenharmony_ci struct bnad_rx_info *rx_info; 230962306a36Sopenharmony_ci int i; 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 231262306a36Sopenharmony_ci rx_info = &bnad->rx_info[i]; 231362306a36Sopenharmony_ci if (!rx_info->rx) 231462306a36Sopenharmony_ci continue; 231562306a36Sopenharmony_ci bna_rx_coalescing_timeo_set(rx_info->rx, 231662306a36Sopenharmony_ci bnad->rx_coalescing_timeo); 231762306a36Sopenharmony_ci } 231862306a36Sopenharmony_ci} 231962306a36Sopenharmony_ci 232062306a36Sopenharmony_ci/* 232162306a36Sopenharmony_ci * Called with bnad->bna_lock held 232262306a36Sopenharmony_ci */ 232362306a36Sopenharmony_ciint 232462306a36Sopenharmony_cibnad_mac_addr_set_locked(struct bnad *bnad, const u8 *mac_addr) 232562306a36Sopenharmony_ci{ 232662306a36Sopenharmony_ci int ret; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci if (!is_valid_ether_addr(mac_addr)) 232962306a36Sopenharmony_ci return -EADDRNOTAVAIL; 233062306a36Sopenharmony_ci 233162306a36Sopenharmony_ci /* If datapath is down, pretend everything went through */ 233262306a36Sopenharmony_ci if (!bnad->rx_info[0].rx) 233362306a36Sopenharmony_ci return 0; 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci ret = bna_rx_ucast_set(bnad->rx_info[0].rx, mac_addr); 233662306a36Sopenharmony_ci if (ret != BNA_CB_SUCCESS) 233762306a36Sopenharmony_ci return -EADDRNOTAVAIL; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci return 0; 234062306a36Sopenharmony_ci} 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci/* Should be called with conf_lock held */ 234362306a36Sopenharmony_ciint 234462306a36Sopenharmony_cibnad_enable_default_bcast(struct bnad *bnad) 234562306a36Sopenharmony_ci{ 234662306a36Sopenharmony_ci struct bnad_rx_info *rx_info = &bnad->rx_info[0]; 234762306a36Sopenharmony_ci int ret; 234862306a36Sopenharmony_ci unsigned long flags; 234962306a36Sopenharmony_ci 235062306a36Sopenharmony_ci init_completion(&bnad->bnad_completions.mcast_comp); 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 235362306a36Sopenharmony_ci ret = bna_rx_mcast_add(rx_info->rx, bnad_bcast_addr, 235462306a36Sopenharmony_ci bnad_cb_rx_mcast_add); 235562306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci if (ret == BNA_CB_SUCCESS) 235862306a36Sopenharmony_ci wait_for_completion(&bnad->bnad_completions.mcast_comp); 235962306a36Sopenharmony_ci else 236062306a36Sopenharmony_ci return -ENODEV; 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci if (bnad->bnad_completions.mcast_comp_status != BNA_CB_SUCCESS) 236362306a36Sopenharmony_ci return -ENODEV; 236462306a36Sopenharmony_ci 236562306a36Sopenharmony_ci return 0; 236662306a36Sopenharmony_ci} 236762306a36Sopenharmony_ci 236862306a36Sopenharmony_ci/* Called with mutex_lock(&bnad->conf_mutex) held */ 236962306a36Sopenharmony_civoid 237062306a36Sopenharmony_cibnad_restore_vlans(struct bnad *bnad, u32 rx_id) 237162306a36Sopenharmony_ci{ 237262306a36Sopenharmony_ci u16 vid; 237362306a36Sopenharmony_ci unsigned long flags; 237462306a36Sopenharmony_ci 237562306a36Sopenharmony_ci for_each_set_bit(vid, bnad->active_vlans, VLAN_N_VID) { 237662306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 237762306a36Sopenharmony_ci bna_rx_vlan_add(bnad->rx_info[rx_id].rx, vid); 237862306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 237962306a36Sopenharmony_ci } 238062306a36Sopenharmony_ci} 238162306a36Sopenharmony_ci 238262306a36Sopenharmony_ci/* Statistics utilities */ 238362306a36Sopenharmony_civoid 238462306a36Sopenharmony_cibnad_netdev_qstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats) 238562306a36Sopenharmony_ci{ 238662306a36Sopenharmony_ci int i, j; 238762306a36Sopenharmony_ci 238862306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 238962306a36Sopenharmony_ci for (j = 0; j < bnad->num_rxp_per_rx; j++) { 239062306a36Sopenharmony_ci if (bnad->rx_info[i].rx_ctrl[j].ccb) { 239162306a36Sopenharmony_ci stats->rx_packets += bnad->rx_info[i]. 239262306a36Sopenharmony_ci rx_ctrl[j].ccb->rcb[0]->rxq->rx_packets; 239362306a36Sopenharmony_ci stats->rx_bytes += bnad->rx_info[i]. 239462306a36Sopenharmony_ci rx_ctrl[j].ccb->rcb[0]->rxq->rx_bytes; 239562306a36Sopenharmony_ci if (bnad->rx_info[i].rx_ctrl[j].ccb->rcb[1] && 239662306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j].ccb-> 239762306a36Sopenharmony_ci rcb[1]->rxq) { 239862306a36Sopenharmony_ci stats->rx_packets += 239962306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j]. 240062306a36Sopenharmony_ci ccb->rcb[1]->rxq->rx_packets; 240162306a36Sopenharmony_ci stats->rx_bytes += 240262306a36Sopenharmony_ci bnad->rx_info[i].rx_ctrl[j]. 240362306a36Sopenharmony_ci ccb->rcb[1]->rxq->rx_bytes; 240462306a36Sopenharmony_ci } 240562306a36Sopenharmony_ci } 240662306a36Sopenharmony_ci } 240762306a36Sopenharmony_ci } 240862306a36Sopenharmony_ci for (i = 0; i < bnad->num_tx; i++) { 240962306a36Sopenharmony_ci for (j = 0; j < bnad->num_txq_per_tx; j++) { 241062306a36Sopenharmony_ci if (bnad->tx_info[i].tcb[j]) { 241162306a36Sopenharmony_ci stats->tx_packets += 241262306a36Sopenharmony_ci bnad->tx_info[i].tcb[j]->txq->tx_packets; 241362306a36Sopenharmony_ci stats->tx_bytes += 241462306a36Sopenharmony_ci bnad->tx_info[i].tcb[j]->txq->tx_bytes; 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci } 241862306a36Sopenharmony_ci} 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci/* 242162306a36Sopenharmony_ci * Must be called with the bna_lock held. 242262306a36Sopenharmony_ci */ 242362306a36Sopenharmony_civoid 242462306a36Sopenharmony_cibnad_netdev_hwstats_fill(struct bnad *bnad, struct rtnl_link_stats64 *stats) 242562306a36Sopenharmony_ci{ 242662306a36Sopenharmony_ci struct bfi_enet_stats_mac *mac_stats; 242762306a36Sopenharmony_ci u32 bmap; 242862306a36Sopenharmony_ci int i; 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci mac_stats = &bnad->stats.bna_stats->hw_stats.mac_stats; 243162306a36Sopenharmony_ci stats->rx_errors = 243262306a36Sopenharmony_ci mac_stats->rx_fcs_error + mac_stats->rx_alignment_error + 243362306a36Sopenharmony_ci mac_stats->rx_frame_length_error + mac_stats->rx_code_error + 243462306a36Sopenharmony_ci mac_stats->rx_undersize; 243562306a36Sopenharmony_ci stats->tx_errors = mac_stats->tx_fcs_error + 243662306a36Sopenharmony_ci mac_stats->tx_undersize; 243762306a36Sopenharmony_ci stats->rx_dropped = mac_stats->rx_drop; 243862306a36Sopenharmony_ci stats->tx_dropped = mac_stats->tx_drop; 243962306a36Sopenharmony_ci stats->multicast = mac_stats->rx_multicast; 244062306a36Sopenharmony_ci stats->collisions = mac_stats->tx_total_collision; 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci stats->rx_length_errors = mac_stats->rx_frame_length_error; 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci /* receive ring buffer overflow ?? */ 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci stats->rx_crc_errors = mac_stats->rx_fcs_error; 244762306a36Sopenharmony_ci stats->rx_frame_errors = mac_stats->rx_alignment_error; 244862306a36Sopenharmony_ci /* recv'r fifo overrun */ 244962306a36Sopenharmony_ci bmap = bna_rx_rid_mask(&bnad->bna); 245062306a36Sopenharmony_ci for (i = 0; bmap; i++) { 245162306a36Sopenharmony_ci if (bmap & 1) { 245262306a36Sopenharmony_ci stats->rx_fifo_errors += 245362306a36Sopenharmony_ci bnad->stats.bna_stats-> 245462306a36Sopenharmony_ci hw_stats.rxf_stats[i].frame_drops; 245562306a36Sopenharmony_ci break; 245662306a36Sopenharmony_ci } 245762306a36Sopenharmony_ci bmap >>= 1; 245862306a36Sopenharmony_ci } 245962306a36Sopenharmony_ci} 246062306a36Sopenharmony_ci 246162306a36Sopenharmony_cistatic void 246262306a36Sopenharmony_cibnad_mbox_irq_sync(struct bnad *bnad) 246362306a36Sopenharmony_ci{ 246462306a36Sopenharmony_ci u32 irq; 246562306a36Sopenharmony_ci unsigned long flags; 246662306a36Sopenharmony_ci 246762306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 246862306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_MSIX) 246962306a36Sopenharmony_ci irq = bnad->msix_table[BNAD_MAILBOX_MSIX_INDEX].vector; 247062306a36Sopenharmony_ci else 247162306a36Sopenharmony_ci irq = bnad->pcidev->irq; 247262306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci synchronize_irq(irq); 247562306a36Sopenharmony_ci} 247662306a36Sopenharmony_ci 247762306a36Sopenharmony_ci/* Utility used by bnad_start_xmit, for doing TSO */ 247862306a36Sopenharmony_cistatic int 247962306a36Sopenharmony_cibnad_tso_prepare(struct bnad *bnad, struct sk_buff *skb) 248062306a36Sopenharmony_ci{ 248162306a36Sopenharmony_ci int err; 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_ci err = skb_cow_head(skb, 0); 248462306a36Sopenharmony_ci if (err < 0) { 248562306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tso_err); 248662306a36Sopenharmony_ci return err; 248762306a36Sopenharmony_ci } 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci /* 249062306a36Sopenharmony_ci * For TSO, the TCP checksum field is seeded with pseudo-header sum 249162306a36Sopenharmony_ci * excluding the length field. 249262306a36Sopenharmony_ci */ 249362306a36Sopenharmony_ci if (vlan_get_protocol(skb) == htons(ETH_P_IP)) { 249462306a36Sopenharmony_ci struct iphdr *iph = ip_hdr(skb); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci /* Do we really need these? */ 249762306a36Sopenharmony_ci iph->tot_len = 0; 249862306a36Sopenharmony_ci iph->check = 0; 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci tcp_hdr(skb)->check = 250162306a36Sopenharmony_ci ~csum_tcpudp_magic(iph->saddr, iph->daddr, 0, 250262306a36Sopenharmony_ci IPPROTO_TCP, 0); 250362306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tso4); 250462306a36Sopenharmony_ci } else { 250562306a36Sopenharmony_ci tcp_v6_gso_csum_prep(skb); 250662306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tso6); 250762306a36Sopenharmony_ci } 250862306a36Sopenharmony_ci 250962306a36Sopenharmony_ci return 0; 251062306a36Sopenharmony_ci} 251162306a36Sopenharmony_ci 251262306a36Sopenharmony_ci/* 251362306a36Sopenharmony_ci * Initialize Q numbers depending on Rx Paths 251462306a36Sopenharmony_ci * Called with bnad->bna_lock held, because of cfg_flags 251562306a36Sopenharmony_ci * access. 251662306a36Sopenharmony_ci */ 251762306a36Sopenharmony_cistatic void 251862306a36Sopenharmony_cibnad_q_num_init(struct bnad *bnad) 251962306a36Sopenharmony_ci{ 252062306a36Sopenharmony_ci int rxps; 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci rxps = min((uint)num_online_cpus(), 252362306a36Sopenharmony_ci (uint)(BNAD_MAX_RX * BNAD_MAX_RXP_PER_RX)); 252462306a36Sopenharmony_ci 252562306a36Sopenharmony_ci if (!(bnad->cfg_flags & BNAD_CF_MSIX)) 252662306a36Sopenharmony_ci rxps = 1; /* INTx */ 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci bnad->num_rx = 1; 252962306a36Sopenharmony_ci bnad->num_tx = 1; 253062306a36Sopenharmony_ci bnad->num_rxp_per_rx = rxps; 253162306a36Sopenharmony_ci bnad->num_txq_per_tx = BNAD_TXQ_NUM; 253262306a36Sopenharmony_ci} 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci/* 253562306a36Sopenharmony_ci * Adjusts the Q numbers, given a number of msix vectors 253662306a36Sopenharmony_ci * Give preference to RSS as opposed to Tx priority Queues, 253762306a36Sopenharmony_ci * in such a case, just use 1 Tx Q 253862306a36Sopenharmony_ci * Called with bnad->bna_lock held b'cos of cfg_flags access 253962306a36Sopenharmony_ci */ 254062306a36Sopenharmony_cistatic void 254162306a36Sopenharmony_cibnad_q_num_adjust(struct bnad *bnad, int msix_vectors, int temp) 254262306a36Sopenharmony_ci{ 254362306a36Sopenharmony_ci bnad->num_txq_per_tx = 1; 254462306a36Sopenharmony_ci if ((msix_vectors >= (bnad->num_tx * bnad->num_txq_per_tx) + 254562306a36Sopenharmony_ci bnad_rxqs_per_cq + BNAD_MAILBOX_MSIX_VECTORS) && 254662306a36Sopenharmony_ci (bnad->cfg_flags & BNAD_CF_MSIX)) { 254762306a36Sopenharmony_ci bnad->num_rxp_per_rx = msix_vectors - 254862306a36Sopenharmony_ci (bnad->num_tx * bnad->num_txq_per_tx) - 254962306a36Sopenharmony_ci BNAD_MAILBOX_MSIX_VECTORS; 255062306a36Sopenharmony_ci } else 255162306a36Sopenharmony_ci bnad->num_rxp_per_rx = 1; 255262306a36Sopenharmony_ci} 255362306a36Sopenharmony_ci 255462306a36Sopenharmony_ci/* Enable / disable ioceth */ 255562306a36Sopenharmony_cistatic int 255662306a36Sopenharmony_cibnad_ioceth_disable(struct bnad *bnad) 255762306a36Sopenharmony_ci{ 255862306a36Sopenharmony_ci unsigned long flags; 255962306a36Sopenharmony_ci int err = 0; 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 256262306a36Sopenharmony_ci init_completion(&bnad->bnad_completions.ioc_comp); 256362306a36Sopenharmony_ci bna_ioceth_disable(&bnad->bna.ioceth, BNA_HARD_CLEANUP); 256462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 256562306a36Sopenharmony_ci 256662306a36Sopenharmony_ci wait_for_completion_timeout(&bnad->bnad_completions.ioc_comp, 256762306a36Sopenharmony_ci msecs_to_jiffies(BNAD_IOCETH_TIMEOUT)); 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci err = bnad->bnad_completions.ioc_comp_status; 257062306a36Sopenharmony_ci return err; 257162306a36Sopenharmony_ci} 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_cistatic int 257462306a36Sopenharmony_cibnad_ioceth_enable(struct bnad *bnad) 257562306a36Sopenharmony_ci{ 257662306a36Sopenharmony_ci int err = 0; 257762306a36Sopenharmony_ci unsigned long flags; 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 258062306a36Sopenharmony_ci init_completion(&bnad->bnad_completions.ioc_comp); 258162306a36Sopenharmony_ci bnad->bnad_completions.ioc_comp_status = BNA_CB_WAITING; 258262306a36Sopenharmony_ci bna_ioceth_enable(&bnad->bna.ioceth); 258362306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci wait_for_completion_timeout(&bnad->bnad_completions.ioc_comp, 258662306a36Sopenharmony_ci msecs_to_jiffies(BNAD_IOCETH_TIMEOUT)); 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_ci err = bnad->bnad_completions.ioc_comp_status; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci return err; 259162306a36Sopenharmony_ci} 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_ci/* Free BNA resources */ 259462306a36Sopenharmony_cistatic void 259562306a36Sopenharmony_cibnad_res_free(struct bnad *bnad, struct bna_res_info *res_info, 259662306a36Sopenharmony_ci u32 res_val_max) 259762306a36Sopenharmony_ci{ 259862306a36Sopenharmony_ci int i; 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci for (i = 0; i < res_val_max; i++) 260162306a36Sopenharmony_ci bnad_mem_free(bnad, &res_info[i].res_u.mem_info); 260262306a36Sopenharmony_ci} 260362306a36Sopenharmony_ci 260462306a36Sopenharmony_ci/* Allocates memory and interrupt resources for BNA */ 260562306a36Sopenharmony_cistatic int 260662306a36Sopenharmony_cibnad_res_alloc(struct bnad *bnad, struct bna_res_info *res_info, 260762306a36Sopenharmony_ci u32 res_val_max) 260862306a36Sopenharmony_ci{ 260962306a36Sopenharmony_ci int i, err; 261062306a36Sopenharmony_ci 261162306a36Sopenharmony_ci for (i = 0; i < res_val_max; i++) { 261262306a36Sopenharmony_ci err = bnad_mem_alloc(bnad, &res_info[i].res_u.mem_info); 261362306a36Sopenharmony_ci if (err) 261462306a36Sopenharmony_ci goto err_return; 261562306a36Sopenharmony_ci } 261662306a36Sopenharmony_ci return 0; 261762306a36Sopenharmony_ci 261862306a36Sopenharmony_cierr_return: 261962306a36Sopenharmony_ci bnad_res_free(bnad, res_info, res_val_max); 262062306a36Sopenharmony_ci return err; 262162306a36Sopenharmony_ci} 262262306a36Sopenharmony_ci 262362306a36Sopenharmony_ci/* Interrupt enable / disable */ 262462306a36Sopenharmony_cistatic void 262562306a36Sopenharmony_cibnad_enable_msix(struct bnad *bnad) 262662306a36Sopenharmony_ci{ 262762306a36Sopenharmony_ci int i, ret; 262862306a36Sopenharmony_ci unsigned long flags; 262962306a36Sopenharmony_ci 263062306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 263162306a36Sopenharmony_ci if (!(bnad->cfg_flags & BNAD_CF_MSIX)) { 263262306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 263362306a36Sopenharmony_ci return; 263462306a36Sopenharmony_ci } 263562306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 263662306a36Sopenharmony_ci 263762306a36Sopenharmony_ci if (bnad->msix_table) 263862306a36Sopenharmony_ci return; 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci bnad->msix_table = 264162306a36Sopenharmony_ci kcalloc(bnad->msix_num, sizeof(struct msix_entry), GFP_KERNEL); 264262306a36Sopenharmony_ci 264362306a36Sopenharmony_ci if (!bnad->msix_table) 264462306a36Sopenharmony_ci goto intx_mode; 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci for (i = 0; i < bnad->msix_num; i++) 264762306a36Sopenharmony_ci bnad->msix_table[i].entry = i; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci ret = pci_enable_msix_range(bnad->pcidev, bnad->msix_table, 265062306a36Sopenharmony_ci 1, bnad->msix_num); 265162306a36Sopenharmony_ci if (ret < 0) { 265262306a36Sopenharmony_ci goto intx_mode; 265362306a36Sopenharmony_ci } else if (ret < bnad->msix_num) { 265462306a36Sopenharmony_ci dev_warn(&bnad->pcidev->dev, 265562306a36Sopenharmony_ci "%d MSI-X vectors allocated < %d requested\n", 265662306a36Sopenharmony_ci ret, bnad->msix_num); 265762306a36Sopenharmony_ci 265862306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 265962306a36Sopenharmony_ci /* ret = #of vectors that we got */ 266062306a36Sopenharmony_ci bnad_q_num_adjust(bnad, (ret - BNAD_MAILBOX_MSIX_VECTORS) / 2, 266162306a36Sopenharmony_ci (ret - BNAD_MAILBOX_MSIX_VECTORS) / 2); 266262306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 266362306a36Sopenharmony_ci 266462306a36Sopenharmony_ci bnad->msix_num = BNAD_NUM_TXQ + BNAD_NUM_RXP + 266562306a36Sopenharmony_ci BNAD_MAILBOX_MSIX_VECTORS; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci if (bnad->msix_num > ret) { 266862306a36Sopenharmony_ci pci_disable_msix(bnad->pcidev); 266962306a36Sopenharmony_ci goto intx_mode; 267062306a36Sopenharmony_ci } 267162306a36Sopenharmony_ci } 267262306a36Sopenharmony_ci 267362306a36Sopenharmony_ci pci_intx(bnad->pcidev, 0); 267462306a36Sopenharmony_ci 267562306a36Sopenharmony_ci return; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ciintx_mode: 267862306a36Sopenharmony_ci dev_warn(&bnad->pcidev->dev, 267962306a36Sopenharmony_ci "MSI-X enable failed - operating in INTx mode\n"); 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci kfree(bnad->msix_table); 268262306a36Sopenharmony_ci bnad->msix_table = NULL; 268362306a36Sopenharmony_ci bnad->msix_num = 0; 268462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 268562306a36Sopenharmony_ci bnad->cfg_flags &= ~BNAD_CF_MSIX; 268662306a36Sopenharmony_ci bnad_q_num_init(bnad); 268762306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 268862306a36Sopenharmony_ci} 268962306a36Sopenharmony_ci 269062306a36Sopenharmony_cistatic void 269162306a36Sopenharmony_cibnad_disable_msix(struct bnad *bnad) 269262306a36Sopenharmony_ci{ 269362306a36Sopenharmony_ci u32 cfg_flags; 269462306a36Sopenharmony_ci unsigned long flags; 269562306a36Sopenharmony_ci 269662306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 269762306a36Sopenharmony_ci cfg_flags = bnad->cfg_flags; 269862306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_MSIX) 269962306a36Sopenharmony_ci bnad->cfg_flags &= ~BNAD_CF_MSIX; 270062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_ci if (cfg_flags & BNAD_CF_MSIX) { 270362306a36Sopenharmony_ci pci_disable_msix(bnad->pcidev); 270462306a36Sopenharmony_ci kfree(bnad->msix_table); 270562306a36Sopenharmony_ci bnad->msix_table = NULL; 270662306a36Sopenharmony_ci } 270762306a36Sopenharmony_ci} 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_ci/* Netdev entry points */ 271062306a36Sopenharmony_cistatic int 271162306a36Sopenharmony_cibnad_open(struct net_device *netdev) 271262306a36Sopenharmony_ci{ 271362306a36Sopenharmony_ci int err; 271462306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 271562306a36Sopenharmony_ci struct bna_pause_config pause_config; 271662306a36Sopenharmony_ci unsigned long flags; 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 271962306a36Sopenharmony_ci 272062306a36Sopenharmony_ci /* Tx */ 272162306a36Sopenharmony_ci err = bnad_setup_tx(bnad, 0); 272262306a36Sopenharmony_ci if (err) 272362306a36Sopenharmony_ci goto err_return; 272462306a36Sopenharmony_ci 272562306a36Sopenharmony_ci /* Rx */ 272662306a36Sopenharmony_ci err = bnad_setup_rx(bnad, 0); 272762306a36Sopenharmony_ci if (err) 272862306a36Sopenharmony_ci goto cleanup_tx; 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci /* Port */ 273162306a36Sopenharmony_ci pause_config.tx_pause = 0; 273262306a36Sopenharmony_ci pause_config.rx_pause = 0; 273362306a36Sopenharmony_ci 273462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 273562306a36Sopenharmony_ci bna_enet_mtu_set(&bnad->bna.enet, 273662306a36Sopenharmony_ci BNAD_FRAME_SIZE(bnad->netdev->mtu), NULL); 273762306a36Sopenharmony_ci bna_enet_pause_config(&bnad->bna.enet, &pause_config); 273862306a36Sopenharmony_ci bna_enet_enable(&bnad->bna.enet); 273962306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci /* Enable broadcast */ 274262306a36Sopenharmony_ci bnad_enable_default_bcast(bnad); 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci /* Restore VLANs, if any */ 274562306a36Sopenharmony_ci bnad_restore_vlans(bnad, 0); 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci /* Set the UCAST address */ 274862306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 274962306a36Sopenharmony_ci bnad_mac_addr_set_locked(bnad, netdev->dev_addr); 275062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 275162306a36Sopenharmony_ci 275262306a36Sopenharmony_ci /* Start the stats timer */ 275362306a36Sopenharmony_ci bnad_stats_timer_start(bnad); 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci return 0; 275862306a36Sopenharmony_ci 275962306a36Sopenharmony_cicleanup_tx: 276062306a36Sopenharmony_ci bnad_destroy_tx(bnad, 0); 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_cierr_return: 276362306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 276462306a36Sopenharmony_ci return err; 276562306a36Sopenharmony_ci} 276662306a36Sopenharmony_ci 276762306a36Sopenharmony_cistatic int 276862306a36Sopenharmony_cibnad_stop(struct net_device *netdev) 276962306a36Sopenharmony_ci{ 277062306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 277162306a36Sopenharmony_ci unsigned long flags; 277262306a36Sopenharmony_ci 277362306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci /* Stop the stats timer */ 277662306a36Sopenharmony_ci bnad_stats_timer_stop(bnad); 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ci init_completion(&bnad->bnad_completions.enet_comp); 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 278162306a36Sopenharmony_ci bna_enet_disable(&bnad->bna.enet, BNA_HARD_CLEANUP, 278262306a36Sopenharmony_ci bnad_cb_enet_disabled); 278362306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci wait_for_completion(&bnad->bnad_completions.enet_comp); 278662306a36Sopenharmony_ci 278762306a36Sopenharmony_ci bnad_destroy_tx(bnad, 0); 278862306a36Sopenharmony_ci bnad_destroy_rx(bnad, 0); 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci /* Synchronize mailbox IRQ */ 279162306a36Sopenharmony_ci bnad_mbox_irq_sync(bnad); 279262306a36Sopenharmony_ci 279362306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 279462306a36Sopenharmony_ci 279562306a36Sopenharmony_ci return 0; 279662306a36Sopenharmony_ci} 279762306a36Sopenharmony_ci 279862306a36Sopenharmony_ci/* TX */ 279962306a36Sopenharmony_ci/* Returns 0 for success */ 280062306a36Sopenharmony_cistatic int 280162306a36Sopenharmony_cibnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb, 280262306a36Sopenharmony_ci struct sk_buff *skb, struct bna_txq_entry *txqent) 280362306a36Sopenharmony_ci{ 280462306a36Sopenharmony_ci u16 flags = 0; 280562306a36Sopenharmony_ci u32 gso_size; 280662306a36Sopenharmony_ci u16 vlan_tag = 0; 280762306a36Sopenharmony_ci 280862306a36Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 280962306a36Sopenharmony_ci vlan_tag = (u16)skb_vlan_tag_get(skb); 281062306a36Sopenharmony_ci flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN); 281162306a36Sopenharmony_ci } 281262306a36Sopenharmony_ci if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) { 281362306a36Sopenharmony_ci vlan_tag = ((tcb->priority & 0x7) << VLAN_PRIO_SHIFT) 281462306a36Sopenharmony_ci | (vlan_tag & 0x1fff); 281562306a36Sopenharmony_ci flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN); 281662306a36Sopenharmony_ci } 281762306a36Sopenharmony_ci txqent->hdr.wi.vlan_tag = htons(vlan_tag); 281862306a36Sopenharmony_ci 281962306a36Sopenharmony_ci if (skb_is_gso(skb)) { 282062306a36Sopenharmony_ci gso_size = skb_shinfo(skb)->gso_size; 282162306a36Sopenharmony_ci if (unlikely(gso_size > bnad->netdev->mtu)) { 282262306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_mss_too_long); 282362306a36Sopenharmony_ci return -EINVAL; 282462306a36Sopenharmony_ci } 282562306a36Sopenharmony_ci if (unlikely((gso_size + skb_tcp_all_headers(skb)) >= skb->len)) { 282662306a36Sopenharmony_ci txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND); 282762306a36Sopenharmony_ci txqent->hdr.wi.lso_mss = 0; 282862306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_tso_too_short); 282962306a36Sopenharmony_ci } else { 283062306a36Sopenharmony_ci txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND_LSO); 283162306a36Sopenharmony_ci txqent->hdr.wi.lso_mss = htons(gso_size); 283262306a36Sopenharmony_ci } 283362306a36Sopenharmony_ci 283462306a36Sopenharmony_ci if (bnad_tso_prepare(bnad, skb)) { 283562306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_tso_prepare); 283662306a36Sopenharmony_ci return -EINVAL; 283762306a36Sopenharmony_ci } 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci flags |= (BNA_TXQ_WI_CF_IP_CKSUM | BNA_TXQ_WI_CF_TCP_CKSUM); 284062306a36Sopenharmony_ci txqent->hdr.wi.l4_hdr_size_n_offset = 284162306a36Sopenharmony_ci htons(BNA_TXQ_WI_L4_HDR_N_OFFSET( 284262306a36Sopenharmony_ci tcp_hdrlen(skb) >> 2, skb_transport_offset(skb))); 284362306a36Sopenharmony_ci } else { 284462306a36Sopenharmony_ci txqent->hdr.wi.opcode = htons(BNA_TXQ_WI_SEND); 284562306a36Sopenharmony_ci txqent->hdr.wi.lso_mss = 0; 284662306a36Sopenharmony_ci 284762306a36Sopenharmony_ci if (unlikely(skb->len > (bnad->netdev->mtu + VLAN_ETH_HLEN))) { 284862306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_non_tso_too_long); 284962306a36Sopenharmony_ci return -EINVAL; 285062306a36Sopenharmony_ci } 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci if (skb->ip_summed == CHECKSUM_PARTIAL) { 285362306a36Sopenharmony_ci __be16 net_proto = vlan_get_protocol(skb); 285462306a36Sopenharmony_ci u8 proto = 0; 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci if (net_proto == htons(ETH_P_IP)) 285762306a36Sopenharmony_ci proto = ip_hdr(skb)->protocol; 285862306a36Sopenharmony_ci#ifdef NETIF_F_IPV6_CSUM 285962306a36Sopenharmony_ci else if (net_proto == htons(ETH_P_IPV6)) { 286062306a36Sopenharmony_ci /* nexthdr may not be TCP immediately. */ 286162306a36Sopenharmony_ci proto = ipv6_hdr(skb)->nexthdr; 286262306a36Sopenharmony_ci } 286362306a36Sopenharmony_ci#endif 286462306a36Sopenharmony_ci if (proto == IPPROTO_TCP) { 286562306a36Sopenharmony_ci flags |= BNA_TXQ_WI_CF_TCP_CKSUM; 286662306a36Sopenharmony_ci txqent->hdr.wi.l4_hdr_size_n_offset = 286762306a36Sopenharmony_ci htons(BNA_TXQ_WI_L4_HDR_N_OFFSET 286862306a36Sopenharmony_ci (0, skb_transport_offset(skb))); 286962306a36Sopenharmony_ci 287062306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tcpcsum_offload); 287162306a36Sopenharmony_ci 287262306a36Sopenharmony_ci if (unlikely(skb_headlen(skb) < 287362306a36Sopenharmony_ci skb_tcp_all_headers(skb))) { 287462306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_tcp_hdr); 287562306a36Sopenharmony_ci return -EINVAL; 287662306a36Sopenharmony_ci } 287762306a36Sopenharmony_ci } else if (proto == IPPROTO_UDP) { 287862306a36Sopenharmony_ci flags |= BNA_TXQ_WI_CF_UDP_CKSUM; 287962306a36Sopenharmony_ci txqent->hdr.wi.l4_hdr_size_n_offset = 288062306a36Sopenharmony_ci htons(BNA_TXQ_WI_L4_HDR_N_OFFSET 288162306a36Sopenharmony_ci (0, skb_transport_offset(skb))); 288262306a36Sopenharmony_ci 288362306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, udpcsum_offload); 288462306a36Sopenharmony_ci if (unlikely(skb_headlen(skb) < 288562306a36Sopenharmony_ci skb_transport_offset(skb) + 288662306a36Sopenharmony_ci sizeof(struct udphdr))) { 288762306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_udp_hdr); 288862306a36Sopenharmony_ci return -EINVAL; 288962306a36Sopenharmony_ci } 289062306a36Sopenharmony_ci } else { 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_csum_err); 289362306a36Sopenharmony_ci return -EINVAL; 289462306a36Sopenharmony_ci } 289562306a36Sopenharmony_ci } else 289662306a36Sopenharmony_ci txqent->hdr.wi.l4_hdr_size_n_offset = 0; 289762306a36Sopenharmony_ci } 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_ci txqent->hdr.wi.flags = htons(flags); 290062306a36Sopenharmony_ci txqent->hdr.wi.frame_length = htonl(skb->len); 290162306a36Sopenharmony_ci 290262306a36Sopenharmony_ci return 0; 290362306a36Sopenharmony_ci} 290462306a36Sopenharmony_ci 290562306a36Sopenharmony_ci/* 290662306a36Sopenharmony_ci * bnad_start_xmit : Netdev entry point for Transmit 290762306a36Sopenharmony_ci * Called under lock held by net_device 290862306a36Sopenharmony_ci */ 290962306a36Sopenharmony_cistatic netdev_tx_t 291062306a36Sopenharmony_cibnad_start_xmit(struct sk_buff *skb, struct net_device *netdev) 291162306a36Sopenharmony_ci{ 291262306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 291362306a36Sopenharmony_ci u32 txq_id = 0; 291462306a36Sopenharmony_ci struct bna_tcb *tcb = NULL; 291562306a36Sopenharmony_ci struct bnad_tx_unmap *unmap_q, *unmap, *head_unmap; 291662306a36Sopenharmony_ci u32 prod, q_depth, vect_id; 291762306a36Sopenharmony_ci u32 wis, vectors, len; 291862306a36Sopenharmony_ci int i; 291962306a36Sopenharmony_ci dma_addr_t dma_addr; 292062306a36Sopenharmony_ci struct bna_txq_entry *txqent; 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci len = skb_headlen(skb); 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci /* Sanity checks for the skb */ 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci if (unlikely(skb->len <= ETH_HLEN)) { 292762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 292862306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_too_short); 292962306a36Sopenharmony_ci return NETDEV_TX_OK; 293062306a36Sopenharmony_ci } 293162306a36Sopenharmony_ci if (unlikely(len > BFI_TX_MAX_DATA_PER_VECTOR)) { 293262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 293362306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero); 293462306a36Sopenharmony_ci return NETDEV_TX_OK; 293562306a36Sopenharmony_ci } 293662306a36Sopenharmony_ci if (unlikely(len == 0)) { 293762306a36Sopenharmony_ci dev_kfree_skb_any(skb); 293862306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_headlen_zero); 293962306a36Sopenharmony_ci return NETDEV_TX_OK; 294062306a36Sopenharmony_ci } 294162306a36Sopenharmony_ci 294262306a36Sopenharmony_ci tcb = bnad->tx_info[0].tcb[txq_id]; 294362306a36Sopenharmony_ci 294462306a36Sopenharmony_ci /* 294562306a36Sopenharmony_ci * Takes care of the Tx that is scheduled between clearing the flag 294662306a36Sopenharmony_ci * and the netif_tx_stop_all_queues() call. 294762306a36Sopenharmony_ci */ 294862306a36Sopenharmony_ci if (unlikely(!tcb || !test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) { 294962306a36Sopenharmony_ci dev_kfree_skb_any(skb); 295062306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_stopping); 295162306a36Sopenharmony_ci return NETDEV_TX_OK; 295262306a36Sopenharmony_ci } 295362306a36Sopenharmony_ci 295462306a36Sopenharmony_ci q_depth = tcb->q_depth; 295562306a36Sopenharmony_ci prod = tcb->producer_index; 295662306a36Sopenharmony_ci unmap_q = tcb->unmap_q; 295762306a36Sopenharmony_ci 295862306a36Sopenharmony_ci vectors = 1 + skb_shinfo(skb)->nr_frags; 295962306a36Sopenharmony_ci wis = BNA_TXQ_WI_NEEDED(vectors); /* 4 vectors per work item */ 296062306a36Sopenharmony_ci 296162306a36Sopenharmony_ci if (unlikely(vectors > BFI_TX_MAX_VECTORS_PER_PKT)) { 296262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 296362306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_max_vectors); 296462306a36Sopenharmony_ci return NETDEV_TX_OK; 296562306a36Sopenharmony_ci } 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci /* Check for available TxQ resources */ 296862306a36Sopenharmony_ci if (unlikely(wis > BNA_QE_FREE_CNT(tcb, q_depth))) { 296962306a36Sopenharmony_ci if ((*tcb->hw_consumer_index != tcb->consumer_index) && 297062306a36Sopenharmony_ci !test_and_set_bit(BNAD_TXQ_FREE_SENT, &tcb->flags)) { 297162306a36Sopenharmony_ci u32 sent; 297262306a36Sopenharmony_ci sent = bnad_txcmpl_process(bnad, tcb); 297362306a36Sopenharmony_ci if (likely(test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) 297462306a36Sopenharmony_ci bna_ib_ack(tcb->i_dbell, sent); 297562306a36Sopenharmony_ci smp_mb__before_atomic(); 297662306a36Sopenharmony_ci clear_bit(BNAD_TXQ_FREE_SENT, &tcb->flags); 297762306a36Sopenharmony_ci } else { 297862306a36Sopenharmony_ci netif_stop_queue(netdev); 297962306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, netif_queue_stop); 298062306a36Sopenharmony_ci } 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci smp_mb(); 298362306a36Sopenharmony_ci /* 298462306a36Sopenharmony_ci * Check again to deal with race condition between 298562306a36Sopenharmony_ci * netif_stop_queue here, and netif_wake_queue in 298662306a36Sopenharmony_ci * interrupt handler which is not inside netif tx lock. 298762306a36Sopenharmony_ci */ 298862306a36Sopenharmony_ci if (likely(wis > BNA_QE_FREE_CNT(tcb, q_depth))) { 298962306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, netif_queue_stop); 299062306a36Sopenharmony_ci return NETDEV_TX_BUSY; 299162306a36Sopenharmony_ci } else { 299262306a36Sopenharmony_ci netif_wake_queue(netdev); 299362306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, netif_queue_wakeup); 299462306a36Sopenharmony_ci } 299562306a36Sopenharmony_ci } 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod]; 299862306a36Sopenharmony_ci head_unmap = &unmap_q[prod]; 299962306a36Sopenharmony_ci 300062306a36Sopenharmony_ci /* Program the opcode, flags, frame_len, num_vectors in WI */ 300162306a36Sopenharmony_ci if (bnad_txq_wi_prepare(bnad, tcb, skb, txqent)) { 300262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 300362306a36Sopenharmony_ci return NETDEV_TX_OK; 300462306a36Sopenharmony_ci } 300562306a36Sopenharmony_ci txqent->hdr.wi.reserved = 0; 300662306a36Sopenharmony_ci txqent->hdr.wi.num_vectors = vectors; 300762306a36Sopenharmony_ci 300862306a36Sopenharmony_ci head_unmap->skb = skb; 300962306a36Sopenharmony_ci head_unmap->nvecs = 0; 301062306a36Sopenharmony_ci 301162306a36Sopenharmony_ci /* Program the vectors */ 301262306a36Sopenharmony_ci unmap = head_unmap; 301362306a36Sopenharmony_ci dma_addr = dma_map_single(&bnad->pcidev->dev, skb->data, 301462306a36Sopenharmony_ci len, DMA_TO_DEVICE); 301562306a36Sopenharmony_ci if (dma_mapping_error(&bnad->pcidev->dev, dma_addr)) { 301662306a36Sopenharmony_ci dev_kfree_skb_any(skb); 301762306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_map_failed); 301862306a36Sopenharmony_ci return NETDEV_TX_OK; 301962306a36Sopenharmony_ci } 302062306a36Sopenharmony_ci BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[0].host_addr); 302162306a36Sopenharmony_ci txqent->vector[0].length = htons(len); 302262306a36Sopenharmony_ci dma_unmap_addr_set(&unmap->vectors[0], dma_addr, dma_addr); 302362306a36Sopenharmony_ci head_unmap->nvecs++; 302462306a36Sopenharmony_ci 302562306a36Sopenharmony_ci for (i = 0, vect_id = 0; i < vectors - 1; i++) { 302662306a36Sopenharmony_ci const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 302762306a36Sopenharmony_ci u32 size = skb_frag_size(frag); 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci if (unlikely(size == 0)) { 303062306a36Sopenharmony_ci /* Undo the changes starting at tcb->producer_index */ 303162306a36Sopenharmony_ci bnad_tx_buff_unmap(bnad, unmap_q, q_depth, 303262306a36Sopenharmony_ci tcb->producer_index); 303362306a36Sopenharmony_ci dev_kfree_skb_any(skb); 303462306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_frag_zero); 303562306a36Sopenharmony_ci return NETDEV_TX_OK; 303662306a36Sopenharmony_ci } 303762306a36Sopenharmony_ci 303862306a36Sopenharmony_ci len += size; 303962306a36Sopenharmony_ci 304062306a36Sopenharmony_ci vect_id++; 304162306a36Sopenharmony_ci if (vect_id == BFI_TX_MAX_VECTORS_PER_WI) { 304262306a36Sopenharmony_ci vect_id = 0; 304362306a36Sopenharmony_ci BNA_QE_INDX_INC(prod, q_depth); 304462306a36Sopenharmony_ci txqent = &((struct bna_txq_entry *)tcb->sw_q)[prod]; 304562306a36Sopenharmony_ci txqent->hdr.wi_ext.opcode = htons(BNA_TXQ_WI_EXTENSION); 304662306a36Sopenharmony_ci unmap = &unmap_q[prod]; 304762306a36Sopenharmony_ci } 304862306a36Sopenharmony_ci 304962306a36Sopenharmony_ci dma_addr = skb_frag_dma_map(&bnad->pcidev->dev, frag, 305062306a36Sopenharmony_ci 0, size, DMA_TO_DEVICE); 305162306a36Sopenharmony_ci if (dma_mapping_error(&bnad->pcidev->dev, dma_addr)) { 305262306a36Sopenharmony_ci /* Undo the changes starting at tcb->producer_index */ 305362306a36Sopenharmony_ci bnad_tx_buff_unmap(bnad, unmap_q, q_depth, 305462306a36Sopenharmony_ci tcb->producer_index); 305562306a36Sopenharmony_ci dev_kfree_skb_any(skb); 305662306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_map_failed); 305762306a36Sopenharmony_ci return NETDEV_TX_OK; 305862306a36Sopenharmony_ci } 305962306a36Sopenharmony_ci 306062306a36Sopenharmony_ci dma_unmap_len_set(&unmap->vectors[vect_id], dma_len, size); 306162306a36Sopenharmony_ci BNA_SET_DMA_ADDR(dma_addr, &txqent->vector[vect_id].host_addr); 306262306a36Sopenharmony_ci txqent->vector[vect_id].length = htons(size); 306362306a36Sopenharmony_ci dma_unmap_addr_set(&unmap->vectors[vect_id], dma_addr, 306462306a36Sopenharmony_ci dma_addr); 306562306a36Sopenharmony_ci head_unmap->nvecs++; 306662306a36Sopenharmony_ci } 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci if (unlikely(len != skb->len)) { 306962306a36Sopenharmony_ci /* Undo the changes starting at tcb->producer_index */ 307062306a36Sopenharmony_ci bnad_tx_buff_unmap(bnad, unmap_q, q_depth, tcb->producer_index); 307162306a36Sopenharmony_ci dev_kfree_skb_any(skb); 307262306a36Sopenharmony_ci BNAD_UPDATE_CTR(bnad, tx_skb_len_mismatch); 307362306a36Sopenharmony_ci return NETDEV_TX_OK; 307462306a36Sopenharmony_ci } 307562306a36Sopenharmony_ci 307662306a36Sopenharmony_ci BNA_QE_INDX_INC(prod, q_depth); 307762306a36Sopenharmony_ci tcb->producer_index = prod; 307862306a36Sopenharmony_ci 307962306a36Sopenharmony_ci wmb(); 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci if (unlikely(!test_bit(BNAD_TXQ_TX_STARTED, &tcb->flags))) 308262306a36Sopenharmony_ci return NETDEV_TX_OK; 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci skb_tx_timestamp(skb); 308562306a36Sopenharmony_ci 308662306a36Sopenharmony_ci bna_txq_prod_indx_doorbell(tcb); 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_ci return NETDEV_TX_OK; 308962306a36Sopenharmony_ci} 309062306a36Sopenharmony_ci 309162306a36Sopenharmony_ci/* 309262306a36Sopenharmony_ci * Used spin_lock to synchronize reading of stats structures, which 309362306a36Sopenharmony_ci * is written by BNA under the same lock. 309462306a36Sopenharmony_ci */ 309562306a36Sopenharmony_cistatic void 309662306a36Sopenharmony_cibnad_get_stats64(struct net_device *netdev, struct rtnl_link_stats64 *stats) 309762306a36Sopenharmony_ci{ 309862306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 309962306a36Sopenharmony_ci unsigned long flags; 310062306a36Sopenharmony_ci 310162306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci bnad_netdev_qstats_fill(bnad, stats); 310462306a36Sopenharmony_ci bnad_netdev_hwstats_fill(bnad, stats); 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 310762306a36Sopenharmony_ci} 310862306a36Sopenharmony_ci 310962306a36Sopenharmony_cistatic void 311062306a36Sopenharmony_cibnad_set_rx_ucast_fltr(struct bnad *bnad) 311162306a36Sopenharmony_ci{ 311262306a36Sopenharmony_ci struct net_device *netdev = bnad->netdev; 311362306a36Sopenharmony_ci int uc_count = netdev_uc_count(netdev); 311462306a36Sopenharmony_ci enum bna_cb_status ret; 311562306a36Sopenharmony_ci u8 *mac_list; 311662306a36Sopenharmony_ci struct netdev_hw_addr *ha; 311762306a36Sopenharmony_ci int entry; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci if (netdev_uc_empty(bnad->netdev)) { 312062306a36Sopenharmony_ci bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL); 312162306a36Sopenharmony_ci return; 312262306a36Sopenharmony_ci } 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci if (uc_count > bna_attr(&bnad->bna)->num_ucmac) 312562306a36Sopenharmony_ci goto mode_default; 312662306a36Sopenharmony_ci 312762306a36Sopenharmony_ci mac_list = kcalloc(ETH_ALEN, uc_count, GFP_ATOMIC); 312862306a36Sopenharmony_ci if (mac_list == NULL) 312962306a36Sopenharmony_ci goto mode_default; 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ci entry = 0; 313262306a36Sopenharmony_ci netdev_for_each_uc_addr(ha, netdev) { 313362306a36Sopenharmony_ci ether_addr_copy(&mac_list[entry * ETH_ALEN], &ha->addr[0]); 313462306a36Sopenharmony_ci entry++; 313562306a36Sopenharmony_ci } 313662306a36Sopenharmony_ci 313762306a36Sopenharmony_ci ret = bna_rx_ucast_listset(bnad->rx_info[0].rx, entry, mac_list); 313862306a36Sopenharmony_ci kfree(mac_list); 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci if (ret != BNA_CB_SUCCESS) 314162306a36Sopenharmony_ci goto mode_default; 314262306a36Sopenharmony_ci 314362306a36Sopenharmony_ci return; 314462306a36Sopenharmony_ci 314562306a36Sopenharmony_ci /* ucast packets not in UCAM are routed to default function */ 314662306a36Sopenharmony_cimode_default: 314762306a36Sopenharmony_ci bnad->cfg_flags |= BNAD_CF_DEFAULT; 314862306a36Sopenharmony_ci bna_rx_ucast_listset(bnad->rx_info[0].rx, 0, NULL); 314962306a36Sopenharmony_ci} 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_cistatic void 315262306a36Sopenharmony_cibnad_set_rx_mcast_fltr(struct bnad *bnad) 315362306a36Sopenharmony_ci{ 315462306a36Sopenharmony_ci struct net_device *netdev = bnad->netdev; 315562306a36Sopenharmony_ci int mc_count = netdev_mc_count(netdev); 315662306a36Sopenharmony_ci enum bna_cb_status ret; 315762306a36Sopenharmony_ci u8 *mac_list; 315862306a36Sopenharmony_ci 315962306a36Sopenharmony_ci if (netdev->flags & IFF_ALLMULTI) 316062306a36Sopenharmony_ci goto mode_allmulti; 316162306a36Sopenharmony_ci 316262306a36Sopenharmony_ci if (netdev_mc_empty(netdev)) 316362306a36Sopenharmony_ci return; 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci if (mc_count > bna_attr(&bnad->bna)->num_mcmac) 316662306a36Sopenharmony_ci goto mode_allmulti; 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci mac_list = kcalloc(mc_count + 1, ETH_ALEN, GFP_ATOMIC); 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci if (mac_list == NULL) 317162306a36Sopenharmony_ci goto mode_allmulti; 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci ether_addr_copy(&mac_list[0], &bnad_bcast_addr[0]); 317462306a36Sopenharmony_ci 317562306a36Sopenharmony_ci /* copy rest of the MCAST addresses */ 317662306a36Sopenharmony_ci bnad_netdev_mc_list_get(netdev, mac_list); 317762306a36Sopenharmony_ci ret = bna_rx_mcast_listset(bnad->rx_info[0].rx, mc_count + 1, mac_list); 317862306a36Sopenharmony_ci kfree(mac_list); 317962306a36Sopenharmony_ci 318062306a36Sopenharmony_ci if (ret != BNA_CB_SUCCESS) 318162306a36Sopenharmony_ci goto mode_allmulti; 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci return; 318462306a36Sopenharmony_ci 318562306a36Sopenharmony_cimode_allmulti: 318662306a36Sopenharmony_ci bnad->cfg_flags |= BNAD_CF_ALLMULTI; 318762306a36Sopenharmony_ci bna_rx_mcast_delall(bnad->rx_info[0].rx); 318862306a36Sopenharmony_ci} 318962306a36Sopenharmony_ci 319062306a36Sopenharmony_civoid 319162306a36Sopenharmony_cibnad_set_rx_mode(struct net_device *netdev) 319262306a36Sopenharmony_ci{ 319362306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 319462306a36Sopenharmony_ci enum bna_rxmode new_mode, mode_mask; 319562306a36Sopenharmony_ci unsigned long flags; 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 319862306a36Sopenharmony_ci 319962306a36Sopenharmony_ci if (bnad->rx_info[0].rx == NULL) { 320062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 320162306a36Sopenharmony_ci return; 320262306a36Sopenharmony_ci } 320362306a36Sopenharmony_ci 320462306a36Sopenharmony_ci /* clear bnad flags to update it with new settings */ 320562306a36Sopenharmony_ci bnad->cfg_flags &= ~(BNAD_CF_PROMISC | BNAD_CF_DEFAULT | 320662306a36Sopenharmony_ci BNAD_CF_ALLMULTI); 320762306a36Sopenharmony_ci 320862306a36Sopenharmony_ci new_mode = 0; 320962306a36Sopenharmony_ci if (netdev->flags & IFF_PROMISC) { 321062306a36Sopenharmony_ci new_mode |= BNAD_RXMODE_PROMISC_DEFAULT; 321162306a36Sopenharmony_ci bnad->cfg_flags |= BNAD_CF_PROMISC; 321262306a36Sopenharmony_ci } else { 321362306a36Sopenharmony_ci bnad_set_rx_mcast_fltr(bnad); 321462306a36Sopenharmony_ci 321562306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_ALLMULTI) 321662306a36Sopenharmony_ci new_mode |= BNA_RXMODE_ALLMULTI; 321762306a36Sopenharmony_ci 321862306a36Sopenharmony_ci bnad_set_rx_ucast_fltr(bnad); 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_ci if (bnad->cfg_flags & BNAD_CF_DEFAULT) 322162306a36Sopenharmony_ci new_mode |= BNA_RXMODE_DEFAULT; 322262306a36Sopenharmony_ci } 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci mode_mask = BNA_RXMODE_PROMISC | BNA_RXMODE_DEFAULT | 322562306a36Sopenharmony_ci BNA_RXMODE_ALLMULTI; 322662306a36Sopenharmony_ci bna_rx_mode_set(bnad->rx_info[0].rx, new_mode, mode_mask); 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 322962306a36Sopenharmony_ci} 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci/* 323262306a36Sopenharmony_ci * bna_lock is used to sync writes to netdev->addr 323362306a36Sopenharmony_ci * conf_lock cannot be used since this call may be made 323462306a36Sopenharmony_ci * in a non-blocking context. 323562306a36Sopenharmony_ci */ 323662306a36Sopenharmony_cistatic int 323762306a36Sopenharmony_cibnad_set_mac_address(struct net_device *netdev, void *addr) 323862306a36Sopenharmony_ci{ 323962306a36Sopenharmony_ci int err; 324062306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 324162306a36Sopenharmony_ci struct sockaddr *sa = (struct sockaddr *)addr; 324262306a36Sopenharmony_ci unsigned long flags; 324362306a36Sopenharmony_ci 324462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 324562306a36Sopenharmony_ci 324662306a36Sopenharmony_ci err = bnad_mac_addr_set_locked(bnad, sa->sa_data); 324762306a36Sopenharmony_ci if (!err) 324862306a36Sopenharmony_ci eth_hw_addr_set(netdev, sa->sa_data); 324962306a36Sopenharmony_ci 325062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 325162306a36Sopenharmony_ci 325262306a36Sopenharmony_ci return err; 325362306a36Sopenharmony_ci} 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_cistatic int 325662306a36Sopenharmony_cibnad_mtu_set(struct bnad *bnad, int frame_size) 325762306a36Sopenharmony_ci{ 325862306a36Sopenharmony_ci unsigned long flags; 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_ci init_completion(&bnad->bnad_completions.mtu_comp); 326162306a36Sopenharmony_ci 326262306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 326362306a36Sopenharmony_ci bna_enet_mtu_set(&bnad->bna.enet, frame_size, bnad_cb_enet_mtu_set); 326462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci wait_for_completion(&bnad->bnad_completions.mtu_comp); 326762306a36Sopenharmony_ci 326862306a36Sopenharmony_ci return bnad->bnad_completions.mtu_comp_status; 326962306a36Sopenharmony_ci} 327062306a36Sopenharmony_ci 327162306a36Sopenharmony_cistatic int 327262306a36Sopenharmony_cibnad_change_mtu(struct net_device *netdev, int new_mtu) 327362306a36Sopenharmony_ci{ 327462306a36Sopenharmony_ci int err, mtu; 327562306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 327662306a36Sopenharmony_ci u32 frame, new_frame; 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 327962306a36Sopenharmony_ci 328062306a36Sopenharmony_ci mtu = netdev->mtu; 328162306a36Sopenharmony_ci netdev->mtu = new_mtu; 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci frame = BNAD_FRAME_SIZE(mtu); 328462306a36Sopenharmony_ci new_frame = BNAD_FRAME_SIZE(new_mtu); 328562306a36Sopenharmony_ci 328662306a36Sopenharmony_ci /* check if multi-buffer needs to be enabled */ 328762306a36Sopenharmony_ci if (BNAD_PCI_DEV_IS_CAT2(bnad) && 328862306a36Sopenharmony_ci netif_running(bnad->netdev)) { 328962306a36Sopenharmony_ci /* only when transition is over 4K */ 329062306a36Sopenharmony_ci if ((frame <= 4096 && new_frame > 4096) || 329162306a36Sopenharmony_ci (frame > 4096 && new_frame <= 4096)) 329262306a36Sopenharmony_ci bnad_reinit_rx(bnad); 329362306a36Sopenharmony_ci } 329462306a36Sopenharmony_ci 329562306a36Sopenharmony_ci err = bnad_mtu_set(bnad, new_frame); 329662306a36Sopenharmony_ci if (err) 329762306a36Sopenharmony_ci err = -EBUSY; 329862306a36Sopenharmony_ci 329962306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 330062306a36Sopenharmony_ci return err; 330162306a36Sopenharmony_ci} 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_cistatic int 330462306a36Sopenharmony_cibnad_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid) 330562306a36Sopenharmony_ci{ 330662306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 330762306a36Sopenharmony_ci unsigned long flags; 330862306a36Sopenharmony_ci 330962306a36Sopenharmony_ci if (!bnad->rx_info[0].rx) 331062306a36Sopenharmony_ci return 0; 331162306a36Sopenharmony_ci 331262306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 331362306a36Sopenharmony_ci 331462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 331562306a36Sopenharmony_ci bna_rx_vlan_add(bnad->rx_info[0].rx, vid); 331662306a36Sopenharmony_ci set_bit(vid, bnad->active_vlans); 331762306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci return 0; 332262306a36Sopenharmony_ci} 332362306a36Sopenharmony_ci 332462306a36Sopenharmony_cistatic int 332562306a36Sopenharmony_cibnad_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid) 332662306a36Sopenharmony_ci{ 332762306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 332862306a36Sopenharmony_ci unsigned long flags; 332962306a36Sopenharmony_ci 333062306a36Sopenharmony_ci if (!bnad->rx_info[0].rx) 333162306a36Sopenharmony_ci return 0; 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 333462306a36Sopenharmony_ci 333562306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 333662306a36Sopenharmony_ci clear_bit(vid, bnad->active_vlans); 333762306a36Sopenharmony_ci bna_rx_vlan_del(bnad->rx_info[0].rx, vid); 333862306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 333962306a36Sopenharmony_ci 334062306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci return 0; 334362306a36Sopenharmony_ci} 334462306a36Sopenharmony_ci 334562306a36Sopenharmony_cistatic int bnad_set_features(struct net_device *dev, netdev_features_t features) 334662306a36Sopenharmony_ci{ 334762306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(dev); 334862306a36Sopenharmony_ci netdev_features_t changed = features ^ dev->features; 334962306a36Sopenharmony_ci 335062306a36Sopenharmony_ci if ((changed & NETIF_F_HW_VLAN_CTAG_RX) && netif_running(dev)) { 335162306a36Sopenharmony_ci unsigned long flags; 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 335462306a36Sopenharmony_ci 335562306a36Sopenharmony_ci if (features & NETIF_F_HW_VLAN_CTAG_RX) 335662306a36Sopenharmony_ci bna_rx_vlan_strip_enable(bnad->rx_info[0].rx); 335762306a36Sopenharmony_ci else 335862306a36Sopenharmony_ci bna_rx_vlan_strip_disable(bnad->rx_info[0].rx); 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 336162306a36Sopenharmony_ci } 336262306a36Sopenharmony_ci 336362306a36Sopenharmony_ci return 0; 336462306a36Sopenharmony_ci} 336562306a36Sopenharmony_ci 336662306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 336762306a36Sopenharmony_cistatic void 336862306a36Sopenharmony_cibnad_netpoll(struct net_device *netdev) 336962306a36Sopenharmony_ci{ 337062306a36Sopenharmony_ci struct bnad *bnad = netdev_priv(netdev); 337162306a36Sopenharmony_ci struct bnad_rx_info *rx_info; 337262306a36Sopenharmony_ci struct bnad_rx_ctrl *rx_ctrl; 337362306a36Sopenharmony_ci u32 curr_mask; 337462306a36Sopenharmony_ci int i, j; 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci if (!(bnad->cfg_flags & BNAD_CF_MSIX)) { 337762306a36Sopenharmony_ci bna_intx_disable(&bnad->bna, curr_mask); 337862306a36Sopenharmony_ci bnad_isr(bnad->pcidev->irq, netdev); 337962306a36Sopenharmony_ci bna_intx_enable(&bnad->bna, curr_mask); 338062306a36Sopenharmony_ci } else { 338162306a36Sopenharmony_ci /* 338262306a36Sopenharmony_ci * Tx processing may happen in sending context, so no need 338362306a36Sopenharmony_ci * to explicitly process completions here 338462306a36Sopenharmony_ci */ 338562306a36Sopenharmony_ci 338662306a36Sopenharmony_ci /* Rx processing */ 338762306a36Sopenharmony_ci for (i = 0; i < bnad->num_rx; i++) { 338862306a36Sopenharmony_ci rx_info = &bnad->rx_info[i]; 338962306a36Sopenharmony_ci if (!rx_info->rx) 339062306a36Sopenharmony_ci continue; 339162306a36Sopenharmony_ci for (j = 0; j < bnad->num_rxp_per_rx; j++) { 339262306a36Sopenharmony_ci rx_ctrl = &rx_info->rx_ctrl[j]; 339362306a36Sopenharmony_ci if (rx_ctrl->ccb) 339462306a36Sopenharmony_ci bnad_netif_rx_schedule_poll(bnad, 339562306a36Sopenharmony_ci rx_ctrl->ccb); 339662306a36Sopenharmony_ci } 339762306a36Sopenharmony_ci } 339862306a36Sopenharmony_ci } 339962306a36Sopenharmony_ci} 340062306a36Sopenharmony_ci#endif 340162306a36Sopenharmony_ci 340262306a36Sopenharmony_cistatic const struct net_device_ops bnad_netdev_ops = { 340362306a36Sopenharmony_ci .ndo_open = bnad_open, 340462306a36Sopenharmony_ci .ndo_stop = bnad_stop, 340562306a36Sopenharmony_ci .ndo_start_xmit = bnad_start_xmit, 340662306a36Sopenharmony_ci .ndo_get_stats64 = bnad_get_stats64, 340762306a36Sopenharmony_ci .ndo_set_rx_mode = bnad_set_rx_mode, 340862306a36Sopenharmony_ci .ndo_validate_addr = eth_validate_addr, 340962306a36Sopenharmony_ci .ndo_set_mac_address = bnad_set_mac_address, 341062306a36Sopenharmony_ci .ndo_change_mtu = bnad_change_mtu, 341162306a36Sopenharmony_ci .ndo_vlan_rx_add_vid = bnad_vlan_rx_add_vid, 341262306a36Sopenharmony_ci .ndo_vlan_rx_kill_vid = bnad_vlan_rx_kill_vid, 341362306a36Sopenharmony_ci .ndo_set_features = bnad_set_features, 341462306a36Sopenharmony_ci#ifdef CONFIG_NET_POLL_CONTROLLER 341562306a36Sopenharmony_ci .ndo_poll_controller = bnad_netpoll 341662306a36Sopenharmony_ci#endif 341762306a36Sopenharmony_ci}; 341862306a36Sopenharmony_ci 341962306a36Sopenharmony_cistatic void 342062306a36Sopenharmony_cibnad_netdev_init(struct bnad *bnad) 342162306a36Sopenharmony_ci{ 342262306a36Sopenharmony_ci struct net_device *netdev = bnad->netdev; 342362306a36Sopenharmony_ci 342462306a36Sopenharmony_ci netdev->hw_features = NETIF_F_SG | NETIF_F_RXCSUM | 342562306a36Sopenharmony_ci NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 342662306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_HW_VLAN_CTAG_TX | 342762306a36Sopenharmony_ci NETIF_F_HW_VLAN_CTAG_RX; 342862306a36Sopenharmony_ci 342962306a36Sopenharmony_ci netdev->vlan_features = NETIF_F_SG | NETIF_F_HIGHDMA | 343062306a36Sopenharmony_ci NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | 343162306a36Sopenharmony_ci NETIF_F_TSO | NETIF_F_TSO6; 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci netdev->features |= netdev->hw_features | NETIF_F_HW_VLAN_CTAG_FILTER | 343462306a36Sopenharmony_ci NETIF_F_HIGHDMA; 343562306a36Sopenharmony_ci 343662306a36Sopenharmony_ci netdev->mem_start = bnad->mmio_start; 343762306a36Sopenharmony_ci netdev->mem_end = bnad->mmio_start + bnad->mmio_len - 1; 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_ci /* MTU range: 46 - 9000 */ 344062306a36Sopenharmony_ci netdev->min_mtu = ETH_ZLEN - ETH_HLEN; 344162306a36Sopenharmony_ci netdev->max_mtu = BNAD_JUMBO_MTU; 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_ci netdev->netdev_ops = &bnad_netdev_ops; 344462306a36Sopenharmony_ci bnad_set_ethtool_ops(netdev); 344562306a36Sopenharmony_ci} 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_ci/* 344862306a36Sopenharmony_ci * 1. Initialize the bnad structure 344962306a36Sopenharmony_ci * 2. Setup netdev pointer in pci_dev 345062306a36Sopenharmony_ci * 3. Initialize no. of TxQ & CQs & MSIX vectors 345162306a36Sopenharmony_ci * 4. Initialize work queue. 345262306a36Sopenharmony_ci */ 345362306a36Sopenharmony_cistatic int 345462306a36Sopenharmony_cibnad_init(struct bnad *bnad, 345562306a36Sopenharmony_ci struct pci_dev *pdev, struct net_device *netdev) 345662306a36Sopenharmony_ci{ 345762306a36Sopenharmony_ci unsigned long flags; 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_ci SET_NETDEV_DEV(netdev, &pdev->dev); 346062306a36Sopenharmony_ci pci_set_drvdata(pdev, netdev); 346162306a36Sopenharmony_ci 346262306a36Sopenharmony_ci bnad->netdev = netdev; 346362306a36Sopenharmony_ci bnad->pcidev = pdev; 346462306a36Sopenharmony_ci bnad->mmio_start = pci_resource_start(pdev, 0); 346562306a36Sopenharmony_ci bnad->mmio_len = pci_resource_len(pdev, 0); 346662306a36Sopenharmony_ci bnad->bar0 = ioremap(bnad->mmio_start, bnad->mmio_len); 346762306a36Sopenharmony_ci if (!bnad->bar0) { 346862306a36Sopenharmony_ci dev_err(&pdev->dev, "ioremap for bar0 failed\n"); 346962306a36Sopenharmony_ci return -ENOMEM; 347062306a36Sopenharmony_ci } 347162306a36Sopenharmony_ci dev_info(&pdev->dev, "bar0 mapped to %p, len %llu\n", bnad->bar0, 347262306a36Sopenharmony_ci (unsigned long long) bnad->mmio_len); 347362306a36Sopenharmony_ci 347462306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 347562306a36Sopenharmony_ci if (!bnad_msix_disable) 347662306a36Sopenharmony_ci bnad->cfg_flags = BNAD_CF_MSIX; 347762306a36Sopenharmony_ci 347862306a36Sopenharmony_ci bnad->cfg_flags |= BNAD_CF_DIM_ENABLED; 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci bnad_q_num_init(bnad); 348162306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci bnad->msix_num = (bnad->num_tx * bnad->num_txq_per_tx) + 348462306a36Sopenharmony_ci (bnad->num_rx * bnad->num_rxp_per_rx) + 348562306a36Sopenharmony_ci BNAD_MAILBOX_MSIX_VECTORS; 348662306a36Sopenharmony_ci 348762306a36Sopenharmony_ci bnad->txq_depth = BNAD_TXQ_DEPTH; 348862306a36Sopenharmony_ci bnad->rxq_depth = BNAD_RXQ_DEPTH; 348962306a36Sopenharmony_ci 349062306a36Sopenharmony_ci bnad->tx_coalescing_timeo = BFI_TX_COALESCING_TIMEO; 349162306a36Sopenharmony_ci bnad->rx_coalescing_timeo = BFI_RX_COALESCING_TIMEO; 349262306a36Sopenharmony_ci 349362306a36Sopenharmony_ci sprintf(bnad->wq_name, "%s_wq_%d", BNAD_NAME, bnad->id); 349462306a36Sopenharmony_ci bnad->work_q = create_singlethread_workqueue(bnad->wq_name); 349562306a36Sopenharmony_ci if (!bnad->work_q) { 349662306a36Sopenharmony_ci iounmap(bnad->bar0); 349762306a36Sopenharmony_ci return -ENOMEM; 349862306a36Sopenharmony_ci } 349962306a36Sopenharmony_ci 350062306a36Sopenharmony_ci return 0; 350162306a36Sopenharmony_ci} 350262306a36Sopenharmony_ci 350362306a36Sopenharmony_ci/* 350462306a36Sopenharmony_ci * Must be called after bnad_pci_uninit() 350562306a36Sopenharmony_ci * so that iounmap() and pci_set_drvdata(NULL) 350662306a36Sopenharmony_ci * happens only after PCI uninitialization. 350762306a36Sopenharmony_ci */ 350862306a36Sopenharmony_cistatic void 350962306a36Sopenharmony_cibnad_uninit(struct bnad *bnad) 351062306a36Sopenharmony_ci{ 351162306a36Sopenharmony_ci if (bnad->work_q) { 351262306a36Sopenharmony_ci destroy_workqueue(bnad->work_q); 351362306a36Sopenharmony_ci bnad->work_q = NULL; 351462306a36Sopenharmony_ci } 351562306a36Sopenharmony_ci 351662306a36Sopenharmony_ci if (bnad->bar0) 351762306a36Sopenharmony_ci iounmap(bnad->bar0); 351862306a36Sopenharmony_ci} 351962306a36Sopenharmony_ci 352062306a36Sopenharmony_ci/* 352162306a36Sopenharmony_ci * Initialize locks 352262306a36Sopenharmony_ci a) Per ioceth mutes used for serializing configuration 352362306a36Sopenharmony_ci changes from OS interface 352462306a36Sopenharmony_ci b) spin lock used to protect bna state machine 352562306a36Sopenharmony_ci */ 352662306a36Sopenharmony_cistatic void 352762306a36Sopenharmony_cibnad_lock_init(struct bnad *bnad) 352862306a36Sopenharmony_ci{ 352962306a36Sopenharmony_ci spin_lock_init(&bnad->bna_lock); 353062306a36Sopenharmony_ci mutex_init(&bnad->conf_mutex); 353162306a36Sopenharmony_ci} 353262306a36Sopenharmony_ci 353362306a36Sopenharmony_cistatic void 353462306a36Sopenharmony_cibnad_lock_uninit(struct bnad *bnad) 353562306a36Sopenharmony_ci{ 353662306a36Sopenharmony_ci mutex_destroy(&bnad->conf_mutex); 353762306a36Sopenharmony_ci} 353862306a36Sopenharmony_ci 353962306a36Sopenharmony_ci/* PCI Initialization */ 354062306a36Sopenharmony_cistatic int 354162306a36Sopenharmony_cibnad_pci_init(struct bnad *bnad, struct pci_dev *pdev) 354262306a36Sopenharmony_ci{ 354362306a36Sopenharmony_ci int err; 354462306a36Sopenharmony_ci 354562306a36Sopenharmony_ci err = pci_enable_device(pdev); 354662306a36Sopenharmony_ci if (err) 354762306a36Sopenharmony_ci return err; 354862306a36Sopenharmony_ci err = pci_request_regions(pdev, BNAD_NAME); 354962306a36Sopenharmony_ci if (err) 355062306a36Sopenharmony_ci goto disable_device; 355162306a36Sopenharmony_ci err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 355262306a36Sopenharmony_ci if (err) 355362306a36Sopenharmony_ci goto release_regions; 355462306a36Sopenharmony_ci pci_set_master(pdev); 355562306a36Sopenharmony_ci return 0; 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_cirelease_regions: 355862306a36Sopenharmony_ci pci_release_regions(pdev); 355962306a36Sopenharmony_cidisable_device: 356062306a36Sopenharmony_ci pci_disable_device(pdev); 356162306a36Sopenharmony_ci 356262306a36Sopenharmony_ci return err; 356362306a36Sopenharmony_ci} 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_cistatic void 356662306a36Sopenharmony_cibnad_pci_uninit(struct pci_dev *pdev) 356762306a36Sopenharmony_ci{ 356862306a36Sopenharmony_ci pci_release_regions(pdev); 356962306a36Sopenharmony_ci pci_disable_device(pdev); 357062306a36Sopenharmony_ci} 357162306a36Sopenharmony_ci 357262306a36Sopenharmony_cistatic int 357362306a36Sopenharmony_cibnad_pci_probe(struct pci_dev *pdev, 357462306a36Sopenharmony_ci const struct pci_device_id *pcidev_id) 357562306a36Sopenharmony_ci{ 357662306a36Sopenharmony_ci int err; 357762306a36Sopenharmony_ci struct bnad *bnad; 357862306a36Sopenharmony_ci struct bna *bna; 357962306a36Sopenharmony_ci struct net_device *netdev; 358062306a36Sopenharmony_ci struct bfa_pcidev pcidev_info; 358162306a36Sopenharmony_ci unsigned long flags; 358262306a36Sopenharmony_ci 358362306a36Sopenharmony_ci mutex_lock(&bnad_fwimg_mutex); 358462306a36Sopenharmony_ci if (!cna_get_firmware_buf(pdev)) { 358562306a36Sopenharmony_ci mutex_unlock(&bnad_fwimg_mutex); 358662306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to load firmware image!\n"); 358762306a36Sopenharmony_ci return -ENODEV; 358862306a36Sopenharmony_ci } 358962306a36Sopenharmony_ci mutex_unlock(&bnad_fwimg_mutex); 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci /* 359262306a36Sopenharmony_ci * Allocates sizeof(struct net_device + struct bnad) 359362306a36Sopenharmony_ci * bnad = netdev->priv 359462306a36Sopenharmony_ci */ 359562306a36Sopenharmony_ci netdev = alloc_etherdev(sizeof(struct bnad)); 359662306a36Sopenharmony_ci if (!netdev) { 359762306a36Sopenharmony_ci err = -ENOMEM; 359862306a36Sopenharmony_ci return err; 359962306a36Sopenharmony_ci } 360062306a36Sopenharmony_ci bnad = netdev_priv(netdev); 360162306a36Sopenharmony_ci bnad_lock_init(bnad); 360262306a36Sopenharmony_ci bnad->id = atomic_inc_return(&bna_id) - 1; 360362306a36Sopenharmony_ci 360462306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 360562306a36Sopenharmony_ci /* PCI initialization */ 360662306a36Sopenharmony_ci err = bnad_pci_init(bnad, pdev); 360762306a36Sopenharmony_ci if (err) 360862306a36Sopenharmony_ci goto unlock_mutex; 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci /* 361162306a36Sopenharmony_ci * Initialize bnad structure 361262306a36Sopenharmony_ci * Setup relation between pci_dev & netdev 361362306a36Sopenharmony_ci */ 361462306a36Sopenharmony_ci err = bnad_init(bnad, pdev, netdev); 361562306a36Sopenharmony_ci if (err) 361662306a36Sopenharmony_ci goto pci_uninit; 361762306a36Sopenharmony_ci 361862306a36Sopenharmony_ci /* Initialize netdev structure, set up ethtool ops */ 361962306a36Sopenharmony_ci bnad_netdev_init(bnad); 362062306a36Sopenharmony_ci 362162306a36Sopenharmony_ci /* Set link to down state */ 362262306a36Sopenharmony_ci netif_carrier_off(netdev); 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci /* Setup the debugfs node for this bfad */ 362562306a36Sopenharmony_ci if (bna_debugfs_enable) 362662306a36Sopenharmony_ci bnad_debugfs_init(bnad); 362762306a36Sopenharmony_ci 362862306a36Sopenharmony_ci /* Get resource requirement form bna */ 362962306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 363062306a36Sopenharmony_ci bna_res_req(&bnad->res_info[0]); 363162306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 363262306a36Sopenharmony_ci 363362306a36Sopenharmony_ci /* Allocate resources from bna */ 363462306a36Sopenharmony_ci err = bnad_res_alloc(bnad, &bnad->res_info[0], BNA_RES_T_MAX); 363562306a36Sopenharmony_ci if (err) 363662306a36Sopenharmony_ci goto drv_uninit; 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci bna = &bnad->bna; 363962306a36Sopenharmony_ci 364062306a36Sopenharmony_ci /* Setup pcidev_info for bna_init() */ 364162306a36Sopenharmony_ci pcidev_info.pci_slot = PCI_SLOT(bnad->pcidev->devfn); 364262306a36Sopenharmony_ci pcidev_info.pci_func = PCI_FUNC(bnad->pcidev->devfn); 364362306a36Sopenharmony_ci pcidev_info.device_id = bnad->pcidev->device; 364462306a36Sopenharmony_ci pcidev_info.pci_bar_kva = bnad->bar0; 364562306a36Sopenharmony_ci 364662306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 364762306a36Sopenharmony_ci bna_init(bna, bnad, &pcidev_info, &bnad->res_info[0]); 364862306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 364962306a36Sopenharmony_ci 365062306a36Sopenharmony_ci bnad->stats.bna_stats = &bna->stats; 365162306a36Sopenharmony_ci 365262306a36Sopenharmony_ci bnad_enable_msix(bnad); 365362306a36Sopenharmony_ci err = bnad_mbox_irq_alloc(bnad); 365462306a36Sopenharmony_ci if (err) 365562306a36Sopenharmony_ci goto res_free; 365662306a36Sopenharmony_ci 365762306a36Sopenharmony_ci /* Set up timers */ 365862306a36Sopenharmony_ci timer_setup(&bnad->bna.ioceth.ioc.ioc_timer, bnad_ioc_timeout, 0); 365962306a36Sopenharmony_ci timer_setup(&bnad->bna.ioceth.ioc.hb_timer, bnad_ioc_hb_check, 0); 366062306a36Sopenharmony_ci timer_setup(&bnad->bna.ioceth.ioc.iocpf_timer, bnad_iocpf_timeout, 0); 366162306a36Sopenharmony_ci timer_setup(&bnad->bna.ioceth.ioc.sem_timer, bnad_iocpf_sem_timeout, 366262306a36Sopenharmony_ci 0); 366362306a36Sopenharmony_ci 366462306a36Sopenharmony_ci /* 366562306a36Sopenharmony_ci * Start the chip 366662306a36Sopenharmony_ci * If the call back comes with error, we bail out. 366762306a36Sopenharmony_ci * This is a catastrophic error. 366862306a36Sopenharmony_ci */ 366962306a36Sopenharmony_ci err = bnad_ioceth_enable(bnad); 367062306a36Sopenharmony_ci if (err) { 367162306a36Sopenharmony_ci dev_err(&pdev->dev, "initialization failed err=%d\n", err); 367262306a36Sopenharmony_ci goto probe_success; 367362306a36Sopenharmony_ci } 367462306a36Sopenharmony_ci 367562306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 367662306a36Sopenharmony_ci if (bna_num_txq_set(bna, BNAD_NUM_TXQ + 1) || 367762306a36Sopenharmony_ci bna_num_rxp_set(bna, BNAD_NUM_RXP + 1)) { 367862306a36Sopenharmony_ci bnad_q_num_adjust(bnad, bna_attr(bna)->num_txq - 1, 367962306a36Sopenharmony_ci bna_attr(bna)->num_rxp - 1); 368062306a36Sopenharmony_ci if (bna_num_txq_set(bna, BNAD_NUM_TXQ + 1) || 368162306a36Sopenharmony_ci bna_num_rxp_set(bna, BNAD_NUM_RXP + 1)) 368262306a36Sopenharmony_ci err = -EIO; 368362306a36Sopenharmony_ci } 368462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 368562306a36Sopenharmony_ci if (err) 368662306a36Sopenharmony_ci goto disable_ioceth; 368762306a36Sopenharmony_ci 368862306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 368962306a36Sopenharmony_ci bna_mod_res_req(&bnad->bna, &bnad->mod_res_info[0]); 369062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 369162306a36Sopenharmony_ci 369262306a36Sopenharmony_ci err = bnad_res_alloc(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX); 369362306a36Sopenharmony_ci if (err) { 369462306a36Sopenharmony_ci err = -EIO; 369562306a36Sopenharmony_ci goto disable_ioceth; 369662306a36Sopenharmony_ci } 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 369962306a36Sopenharmony_ci bna_mod_init(&bnad->bna, &bnad->mod_res_info[0]); 370062306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 370162306a36Sopenharmony_ci 370262306a36Sopenharmony_ci /* Get the burnt-in mac */ 370362306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 370462306a36Sopenharmony_ci bna_enet_perm_mac_get(&bna->enet, bnad->perm_addr); 370562306a36Sopenharmony_ci bnad_set_netdev_perm_addr(bnad); 370662306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci /* Finally, reguister with net_device layer */ 371162306a36Sopenharmony_ci err = register_netdev(netdev); 371262306a36Sopenharmony_ci if (err) { 371362306a36Sopenharmony_ci dev_err(&pdev->dev, "registering net device failed\n"); 371462306a36Sopenharmony_ci goto probe_uninit; 371562306a36Sopenharmony_ci } 371662306a36Sopenharmony_ci set_bit(BNAD_RF_NETDEV_REGISTERED, &bnad->run_flags); 371762306a36Sopenharmony_ci 371862306a36Sopenharmony_ci return 0; 371962306a36Sopenharmony_ci 372062306a36Sopenharmony_ciprobe_success: 372162306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 372262306a36Sopenharmony_ci return 0; 372362306a36Sopenharmony_ci 372462306a36Sopenharmony_ciprobe_uninit: 372562306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 372662306a36Sopenharmony_ci bnad_res_free(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX); 372762306a36Sopenharmony_cidisable_ioceth: 372862306a36Sopenharmony_ci bnad_ioceth_disable(bnad); 372962306a36Sopenharmony_ci del_timer_sync(&bnad->bna.ioceth.ioc.ioc_timer); 373062306a36Sopenharmony_ci del_timer_sync(&bnad->bna.ioceth.ioc.sem_timer); 373162306a36Sopenharmony_ci del_timer_sync(&bnad->bna.ioceth.ioc.hb_timer); 373262306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 373362306a36Sopenharmony_ci bna_uninit(bna); 373462306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 373562306a36Sopenharmony_ci bnad_mbox_irq_free(bnad); 373662306a36Sopenharmony_ci bnad_disable_msix(bnad); 373762306a36Sopenharmony_cires_free: 373862306a36Sopenharmony_ci bnad_res_free(bnad, &bnad->res_info[0], BNA_RES_T_MAX); 373962306a36Sopenharmony_cidrv_uninit: 374062306a36Sopenharmony_ci /* Remove the debugfs node for this bnad */ 374162306a36Sopenharmony_ci kfree(bnad->regdata); 374262306a36Sopenharmony_ci bnad_debugfs_uninit(bnad); 374362306a36Sopenharmony_ci bnad_uninit(bnad); 374462306a36Sopenharmony_cipci_uninit: 374562306a36Sopenharmony_ci bnad_pci_uninit(pdev); 374662306a36Sopenharmony_ciunlock_mutex: 374762306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 374862306a36Sopenharmony_ci bnad_lock_uninit(bnad); 374962306a36Sopenharmony_ci free_netdev(netdev); 375062306a36Sopenharmony_ci return err; 375162306a36Sopenharmony_ci} 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_cistatic void 375462306a36Sopenharmony_cibnad_pci_remove(struct pci_dev *pdev) 375562306a36Sopenharmony_ci{ 375662306a36Sopenharmony_ci struct net_device *netdev = pci_get_drvdata(pdev); 375762306a36Sopenharmony_ci struct bnad *bnad; 375862306a36Sopenharmony_ci struct bna *bna; 375962306a36Sopenharmony_ci unsigned long flags; 376062306a36Sopenharmony_ci 376162306a36Sopenharmony_ci if (!netdev) 376262306a36Sopenharmony_ci return; 376362306a36Sopenharmony_ci 376462306a36Sopenharmony_ci bnad = netdev_priv(netdev); 376562306a36Sopenharmony_ci bna = &bnad->bna; 376662306a36Sopenharmony_ci 376762306a36Sopenharmony_ci if (test_and_clear_bit(BNAD_RF_NETDEV_REGISTERED, &bnad->run_flags)) 376862306a36Sopenharmony_ci unregister_netdev(netdev); 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci mutex_lock(&bnad->conf_mutex); 377162306a36Sopenharmony_ci bnad_ioceth_disable(bnad); 377262306a36Sopenharmony_ci del_timer_sync(&bnad->bna.ioceth.ioc.ioc_timer); 377362306a36Sopenharmony_ci del_timer_sync(&bnad->bna.ioceth.ioc.sem_timer); 377462306a36Sopenharmony_ci del_timer_sync(&bnad->bna.ioceth.ioc.hb_timer); 377562306a36Sopenharmony_ci spin_lock_irqsave(&bnad->bna_lock, flags); 377662306a36Sopenharmony_ci bna_uninit(bna); 377762306a36Sopenharmony_ci spin_unlock_irqrestore(&bnad->bna_lock, flags); 377862306a36Sopenharmony_ci 377962306a36Sopenharmony_ci bnad_res_free(bnad, &bnad->mod_res_info[0], BNA_MOD_RES_T_MAX); 378062306a36Sopenharmony_ci bnad_res_free(bnad, &bnad->res_info[0], BNA_RES_T_MAX); 378162306a36Sopenharmony_ci bnad_mbox_irq_free(bnad); 378262306a36Sopenharmony_ci bnad_disable_msix(bnad); 378362306a36Sopenharmony_ci bnad_pci_uninit(pdev); 378462306a36Sopenharmony_ci mutex_unlock(&bnad->conf_mutex); 378562306a36Sopenharmony_ci bnad_lock_uninit(bnad); 378662306a36Sopenharmony_ci /* Remove the debugfs node for this bnad */ 378762306a36Sopenharmony_ci kfree(bnad->regdata); 378862306a36Sopenharmony_ci bnad_debugfs_uninit(bnad); 378962306a36Sopenharmony_ci bnad_uninit(bnad); 379062306a36Sopenharmony_ci free_netdev(netdev); 379162306a36Sopenharmony_ci} 379262306a36Sopenharmony_ci 379362306a36Sopenharmony_cistatic const struct pci_device_id bnad_pci_id_table[] = { 379462306a36Sopenharmony_ci { 379562306a36Sopenharmony_ci PCI_DEVICE(PCI_VENDOR_ID_BROCADE, 379662306a36Sopenharmony_ci PCI_DEVICE_ID_BROCADE_CT), 379762306a36Sopenharmony_ci .class = PCI_CLASS_NETWORK_ETHERNET << 8, 379862306a36Sopenharmony_ci .class_mask = 0xffff00 379962306a36Sopenharmony_ci }, 380062306a36Sopenharmony_ci { 380162306a36Sopenharmony_ci PCI_DEVICE(PCI_VENDOR_ID_BROCADE, 380262306a36Sopenharmony_ci BFA_PCI_DEVICE_ID_CT2), 380362306a36Sopenharmony_ci .class = PCI_CLASS_NETWORK_ETHERNET << 8, 380462306a36Sopenharmony_ci .class_mask = 0xffff00 380562306a36Sopenharmony_ci }, 380662306a36Sopenharmony_ci {0, }, 380762306a36Sopenharmony_ci}; 380862306a36Sopenharmony_ci 380962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(pci, bnad_pci_id_table); 381062306a36Sopenharmony_ci 381162306a36Sopenharmony_cistatic struct pci_driver bnad_pci_driver = { 381262306a36Sopenharmony_ci .name = BNAD_NAME, 381362306a36Sopenharmony_ci .id_table = bnad_pci_id_table, 381462306a36Sopenharmony_ci .probe = bnad_pci_probe, 381562306a36Sopenharmony_ci .remove = bnad_pci_remove, 381662306a36Sopenharmony_ci}; 381762306a36Sopenharmony_ci 381862306a36Sopenharmony_cistatic int __init 381962306a36Sopenharmony_cibnad_module_init(void) 382062306a36Sopenharmony_ci{ 382162306a36Sopenharmony_ci int err; 382262306a36Sopenharmony_ci 382362306a36Sopenharmony_ci bfa_nw_ioc_auto_recover(bnad_ioc_auto_recover); 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci err = pci_register_driver(&bnad_pci_driver); 382662306a36Sopenharmony_ci if (err < 0) { 382762306a36Sopenharmony_ci pr_err("bna: PCI driver registration failed err=%d\n", err); 382862306a36Sopenharmony_ci return err; 382962306a36Sopenharmony_ci } 383062306a36Sopenharmony_ci 383162306a36Sopenharmony_ci return 0; 383262306a36Sopenharmony_ci} 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_cistatic void __exit 383562306a36Sopenharmony_cibnad_module_exit(void) 383662306a36Sopenharmony_ci{ 383762306a36Sopenharmony_ci pci_unregister_driver(&bnad_pci_driver); 383862306a36Sopenharmony_ci release_firmware(bfi_fw); 383962306a36Sopenharmony_ci} 384062306a36Sopenharmony_ci 384162306a36Sopenharmony_cimodule_init(bnad_module_init); 384262306a36Sopenharmony_cimodule_exit(bnad_module_exit); 384362306a36Sopenharmony_ci 384462306a36Sopenharmony_ciMODULE_AUTHOR("Brocade"); 384562306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 384662306a36Sopenharmony_ciMODULE_DESCRIPTION("QLogic BR-series 10G PCIe Ethernet driver"); 384762306a36Sopenharmony_ciMODULE_FIRMWARE(CNA_FW_FILE_CT); 384862306a36Sopenharmony_ciMODULE_FIRMWARE(CNA_FW_FILE_CT2); 3849