18c2ecf20Sopenharmony_ci/* bnx2x_cmn.c: QLogic Everest network driver. 28c2ecf20Sopenharmony_ci * 38c2ecf20Sopenharmony_ci * Copyright (c) 2007-2013 Broadcom Corporation 48c2ecf20Sopenharmony_ci * Copyright (c) 2014 QLogic Corporation 58c2ecf20Sopenharmony_ci * All rights reserved 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * This program is free software; you can redistribute it and/or modify 88c2ecf20Sopenharmony_ci * it under the terms of the GNU General Public License as published by 98c2ecf20Sopenharmony_ci * the Free Software Foundation. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Maintained by: Ariel Elior <ariel.elior@qlogic.com> 128c2ecf20Sopenharmony_ci * Written by: Eliezer Tamir 138c2ecf20Sopenharmony_ci * Based on code from Michael Chan's bnx2 driver 148c2ecf20Sopenharmony_ci * UDP CSUM errata workaround by Arik Gendelman 158c2ecf20Sopenharmony_ci * Slowpath and fastpath rework by Vladislav Zolotarov 168c2ecf20Sopenharmony_ci * Statistics and Link management by Yitchak Gertner 178c2ecf20Sopenharmony_ci * 188c2ecf20Sopenharmony_ci */ 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#include <linux/etherdevice.h> 238c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 248c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 258c2ecf20Sopenharmony_ci#include <linux/ip.h> 268c2ecf20Sopenharmony_ci#include <linux/crash_dump.h> 278c2ecf20Sopenharmony_ci#include <net/tcp.h> 288c2ecf20Sopenharmony_ci#include <net/ipv6.h> 298c2ecf20Sopenharmony_ci#include <net/ip6_checksum.h> 308c2ecf20Sopenharmony_ci#include <linux/prefetch.h> 318c2ecf20Sopenharmony_ci#include "bnx2x_cmn.h" 328c2ecf20Sopenharmony_ci#include "bnx2x_init.h" 338c2ecf20Sopenharmony_ci#include "bnx2x_sp.h" 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_cistatic void bnx2x_free_fp_mem_cnic(struct bnx2x *bp); 368c2ecf20Sopenharmony_cistatic int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp); 378c2ecf20Sopenharmony_cistatic int bnx2x_alloc_fp_mem(struct bnx2x *bp); 388c2ecf20Sopenharmony_cistatic int bnx2x_poll(struct napi_struct *napi, int budget); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_cistatic void bnx2x_add_all_napi_cnic(struct bnx2x *bp) 418c2ecf20Sopenharmony_ci{ 428c2ecf20Sopenharmony_ci int i; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci /* Add NAPI objects */ 458c2ecf20Sopenharmony_ci for_each_rx_queue_cnic(bp, i) { 468c2ecf20Sopenharmony_ci netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), 478c2ecf20Sopenharmony_ci bnx2x_poll, NAPI_POLL_WEIGHT); 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci} 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic void bnx2x_add_all_napi(struct bnx2x *bp) 528c2ecf20Sopenharmony_ci{ 538c2ecf20Sopenharmony_ci int i; 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci /* Add NAPI objects */ 568c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) { 578c2ecf20Sopenharmony_ci netif_napi_add(bp->dev, &bnx2x_fp(bp, i, napi), 588c2ecf20Sopenharmony_ci bnx2x_poll, NAPI_POLL_WEIGHT); 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_cistatic int bnx2x_calc_num_queues(struct bnx2x *bp) 638c2ecf20Sopenharmony_ci{ 648c2ecf20Sopenharmony_ci int nq = bnx2x_num_queues ? : netif_get_num_default_rss_queues(); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* Reduce memory usage in kdump environment by using only one queue */ 678c2ecf20Sopenharmony_ci if (is_kdump_kernel()) 688c2ecf20Sopenharmony_ci nq = 1; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci nq = clamp(nq, 1, BNX2X_MAX_QUEUES(bp)); 718c2ecf20Sopenharmony_ci return nq; 728c2ecf20Sopenharmony_ci} 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/** 758c2ecf20Sopenharmony_ci * bnx2x_move_fp - move content of the fastpath structure. 768c2ecf20Sopenharmony_ci * 778c2ecf20Sopenharmony_ci * @bp: driver handle 788c2ecf20Sopenharmony_ci * @from: source FP index 798c2ecf20Sopenharmony_ci * @to: destination FP index 808c2ecf20Sopenharmony_ci * 818c2ecf20Sopenharmony_ci * Makes sure the contents of the bp->fp[to].napi is kept 828c2ecf20Sopenharmony_ci * intact. This is done by first copying the napi struct from 838c2ecf20Sopenharmony_ci * the target to the source, and then mem copying the entire 848c2ecf20Sopenharmony_ci * source onto the target. Update txdata pointers and related 858c2ecf20Sopenharmony_ci * content. 868c2ecf20Sopenharmony_ci */ 878c2ecf20Sopenharmony_cistatic inline void bnx2x_move_fp(struct bnx2x *bp, int from, int to) 888c2ecf20Sopenharmony_ci{ 898c2ecf20Sopenharmony_ci struct bnx2x_fastpath *from_fp = &bp->fp[from]; 908c2ecf20Sopenharmony_ci struct bnx2x_fastpath *to_fp = &bp->fp[to]; 918c2ecf20Sopenharmony_ci struct bnx2x_sp_objs *from_sp_objs = &bp->sp_objs[from]; 928c2ecf20Sopenharmony_ci struct bnx2x_sp_objs *to_sp_objs = &bp->sp_objs[to]; 938c2ecf20Sopenharmony_ci struct bnx2x_fp_stats *from_fp_stats = &bp->fp_stats[from]; 948c2ecf20Sopenharmony_ci struct bnx2x_fp_stats *to_fp_stats = &bp->fp_stats[to]; 958c2ecf20Sopenharmony_ci int old_max_eth_txqs, new_max_eth_txqs; 968c2ecf20Sopenharmony_ci int old_txdata_index = 0, new_txdata_index = 0; 978c2ecf20Sopenharmony_ci struct bnx2x_agg_info *old_tpa_info = to_fp->tpa_info; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* Copy the NAPI object as it has been already initialized */ 1008c2ecf20Sopenharmony_ci from_fp->napi = to_fp->napi; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci /* Move bnx2x_fastpath contents */ 1038c2ecf20Sopenharmony_ci memcpy(to_fp, from_fp, sizeof(*to_fp)); 1048c2ecf20Sopenharmony_ci to_fp->index = to; 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci /* Retain the tpa_info of the original `to' version as we don't want 1078c2ecf20Sopenharmony_ci * 2 FPs to contain the same tpa_info pointer. 1088c2ecf20Sopenharmony_ci */ 1098c2ecf20Sopenharmony_ci to_fp->tpa_info = old_tpa_info; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci /* move sp_objs contents as well, as their indices match fp ones */ 1128c2ecf20Sopenharmony_ci memcpy(to_sp_objs, from_sp_objs, sizeof(*to_sp_objs)); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* move fp_stats contents as well, as their indices match fp ones */ 1158c2ecf20Sopenharmony_ci memcpy(to_fp_stats, from_fp_stats, sizeof(*to_fp_stats)); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci /* Update txdata pointers in fp and move txdata content accordingly: 1188c2ecf20Sopenharmony_ci * Each fp consumes 'max_cos' txdata structures, so the index should be 1198c2ecf20Sopenharmony_ci * decremented by max_cos x delta. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci old_max_eth_txqs = BNX2X_NUM_ETH_QUEUES(bp) * (bp)->max_cos; 1238c2ecf20Sopenharmony_ci new_max_eth_txqs = (BNX2X_NUM_ETH_QUEUES(bp) - from + to) * 1248c2ecf20Sopenharmony_ci (bp)->max_cos; 1258c2ecf20Sopenharmony_ci if (from == FCOE_IDX(bp)) { 1268c2ecf20Sopenharmony_ci old_txdata_index = old_max_eth_txqs + FCOE_TXQ_IDX_OFFSET; 1278c2ecf20Sopenharmony_ci new_txdata_index = new_max_eth_txqs + FCOE_TXQ_IDX_OFFSET; 1288c2ecf20Sopenharmony_ci } 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci memcpy(&bp->bnx2x_txq[new_txdata_index], 1318c2ecf20Sopenharmony_ci &bp->bnx2x_txq[old_txdata_index], 1328c2ecf20Sopenharmony_ci sizeof(struct bnx2x_fp_txdata)); 1338c2ecf20Sopenharmony_ci to_fp->txdata_ptr[0] = &bp->bnx2x_txq[new_txdata_index]; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/** 1378c2ecf20Sopenharmony_ci * bnx2x_fill_fw_str - Fill buffer with FW version string. 1388c2ecf20Sopenharmony_ci * 1398c2ecf20Sopenharmony_ci * @bp: driver handle 1408c2ecf20Sopenharmony_ci * @buf: character buffer to fill with the fw name 1418c2ecf20Sopenharmony_ci * @buf_len: length of the above buffer 1428c2ecf20Sopenharmony_ci * 1438c2ecf20Sopenharmony_ci */ 1448c2ecf20Sopenharmony_civoid bnx2x_fill_fw_str(struct bnx2x *bp, char *buf, size_t buf_len) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 1478c2ecf20Sopenharmony_ci u8 phy_fw_ver[PHY_FW_VER_LEN]; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci phy_fw_ver[0] = '\0'; 1508c2ecf20Sopenharmony_ci bnx2x_get_ext_phy_fw_version(&bp->link_params, 1518c2ecf20Sopenharmony_ci phy_fw_ver, PHY_FW_VER_LEN); 1528c2ecf20Sopenharmony_ci strlcpy(buf, bp->fw_ver, buf_len); 1538c2ecf20Sopenharmony_ci snprintf(buf + strlen(bp->fw_ver), 32 - strlen(bp->fw_ver), 1548c2ecf20Sopenharmony_ci "bc %d.%d.%d%s%s", 1558c2ecf20Sopenharmony_ci (bp->common.bc_ver & 0xff0000) >> 16, 1568c2ecf20Sopenharmony_ci (bp->common.bc_ver & 0xff00) >> 8, 1578c2ecf20Sopenharmony_ci (bp->common.bc_ver & 0xff), 1588c2ecf20Sopenharmony_ci ((phy_fw_ver[0] != '\0') ? " phy " : ""), phy_fw_ver); 1598c2ecf20Sopenharmony_ci } else { 1608c2ecf20Sopenharmony_ci bnx2x_vf_fill_fw_str(bp, buf, buf_len); 1618c2ecf20Sopenharmony_ci } 1628c2ecf20Sopenharmony_ci} 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/** 1658c2ecf20Sopenharmony_ci * bnx2x_shrink_eth_fp - guarantees fastpath structures stay intact 1668c2ecf20Sopenharmony_ci * 1678c2ecf20Sopenharmony_ci * @bp: driver handle 1688c2ecf20Sopenharmony_ci * @delta: number of eth queues which were not allocated 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_cistatic void bnx2x_shrink_eth_fp(struct bnx2x *bp, int delta) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci int i, cos, old_eth_num = BNX2X_NUM_ETH_QUEUES(bp); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci /* Queue pointer cannot be re-set on an fp-basis, as moving pointer 1758c2ecf20Sopenharmony_ci * backward along the array could cause memory to be overridden 1768c2ecf20Sopenharmony_ci */ 1778c2ecf20Sopenharmony_ci for (cos = 1; cos < bp->max_cos; cos++) { 1788c2ecf20Sopenharmony_ci for (i = 0; i < old_eth_num - delta; i++) { 1798c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[i]; 1808c2ecf20Sopenharmony_ci int new_idx = cos * (old_eth_num - delta) + i; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci memcpy(&bp->bnx2x_txq[new_idx], fp->txdata_ptr[cos], 1838c2ecf20Sopenharmony_ci sizeof(struct bnx2x_fp_txdata)); 1848c2ecf20Sopenharmony_ci fp->txdata_ptr[cos] = &bp->bnx2x_txq[new_idx]; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ciint bnx2x_load_count[2][3] = { {0} }; /* per-path: 0-common, 1-port0, 2-port1 */ 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci/* free skb in the packet ring at pos idx 1928c2ecf20Sopenharmony_ci * return idx of last bd freed 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_cistatic u16 bnx2x_free_tx_pkt(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata, 1958c2ecf20Sopenharmony_ci u16 idx, unsigned int *pkts_compl, 1968c2ecf20Sopenharmony_ci unsigned int *bytes_compl) 1978c2ecf20Sopenharmony_ci{ 1988c2ecf20Sopenharmony_ci struct sw_tx_bd *tx_buf = &txdata->tx_buf_ring[idx]; 1998c2ecf20Sopenharmony_ci struct eth_tx_start_bd *tx_start_bd; 2008c2ecf20Sopenharmony_ci struct eth_tx_bd *tx_data_bd; 2018c2ecf20Sopenharmony_ci struct sk_buff *skb = tx_buf->skb; 2028c2ecf20Sopenharmony_ci u16 bd_idx = TX_BD(tx_buf->first_bd), new_cons; 2038c2ecf20Sopenharmony_ci int nbd; 2048c2ecf20Sopenharmony_ci u16 split_bd_len = 0; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci /* prefetch skb end pointer to speedup dev_kfree_skb() */ 2078c2ecf20Sopenharmony_ci prefetch(&skb->end); 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_DONE, "fp[%d]: pkt_idx %d buff @(%p)->skb %p\n", 2108c2ecf20Sopenharmony_ci txdata->txq_index, idx, tx_buf, skb); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci tx_start_bd = &txdata->tx_desc_ring[bd_idx].start_bd; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci nbd = le16_to_cpu(tx_start_bd->nbd) - 1; 2158c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 2168c2ecf20Sopenharmony_ci if ((nbd - 1) > (MAX_SKB_FRAGS + 2)) { 2178c2ecf20Sopenharmony_ci BNX2X_ERR("BAD nbd!\n"); 2188c2ecf20Sopenharmony_ci bnx2x_panic(); 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci#endif 2218c2ecf20Sopenharmony_ci new_cons = nbd + tx_buf->first_bd; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* Get the next bd */ 2248c2ecf20Sopenharmony_ci bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci /* Skip a parse bd... */ 2278c2ecf20Sopenharmony_ci --nbd; 2288c2ecf20Sopenharmony_ci bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (tx_buf->flags & BNX2X_HAS_SECOND_PBD) { 2318c2ecf20Sopenharmony_ci /* Skip second parse bd... */ 2328c2ecf20Sopenharmony_ci --nbd; 2338c2ecf20Sopenharmony_ci bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci /* TSO headers+data bds share a common mapping. See bnx2x_tx_split() */ 2378c2ecf20Sopenharmony_ci if (tx_buf->flags & BNX2X_TSO_SPLIT_BD) { 2388c2ecf20Sopenharmony_ci tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd; 2398c2ecf20Sopenharmony_ci split_bd_len = BD_UNMAP_LEN(tx_data_bd); 2408c2ecf20Sopenharmony_ci --nbd; 2418c2ecf20Sopenharmony_ci bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci /* unmap first bd */ 2458c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, BD_UNMAP_ADDR(tx_start_bd), 2468c2ecf20Sopenharmony_ci BD_UNMAP_LEN(tx_start_bd) + split_bd_len, 2478c2ecf20Sopenharmony_ci DMA_TO_DEVICE); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci /* now free frags */ 2508c2ecf20Sopenharmony_ci while (nbd > 0) { 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci tx_data_bd = &txdata->tx_desc_ring[bd_idx].reg_bd; 2538c2ecf20Sopenharmony_ci dma_unmap_page(&bp->pdev->dev, BD_UNMAP_ADDR(tx_data_bd), 2548c2ecf20Sopenharmony_ci BD_UNMAP_LEN(tx_data_bd), DMA_TO_DEVICE); 2558c2ecf20Sopenharmony_ci if (--nbd) 2568c2ecf20Sopenharmony_ci bd_idx = TX_BD(NEXT_TX_IDX(bd_idx)); 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* release skb */ 2608c2ecf20Sopenharmony_ci WARN_ON(!skb); 2618c2ecf20Sopenharmony_ci if (likely(skb)) { 2628c2ecf20Sopenharmony_ci (*pkts_compl)++; 2638c2ecf20Sopenharmony_ci (*bytes_compl) += skb->len; 2648c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci tx_buf->first_bd = 0; 2688c2ecf20Sopenharmony_ci tx_buf->skb = NULL; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci return new_cons; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ciint bnx2x_tx_int(struct bnx2x *bp, struct bnx2x_fp_txdata *txdata) 2748c2ecf20Sopenharmony_ci{ 2758c2ecf20Sopenharmony_ci struct netdev_queue *txq; 2768c2ecf20Sopenharmony_ci u16 hw_cons, sw_cons, bd_cons = txdata->tx_bd_cons; 2778c2ecf20Sopenharmony_ci unsigned int pkts_compl = 0, bytes_compl = 0; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 2808c2ecf20Sopenharmony_ci if (unlikely(bp->panic)) 2818c2ecf20Sopenharmony_ci return -1; 2828c2ecf20Sopenharmony_ci#endif 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci txq = netdev_get_tx_queue(bp->dev, txdata->txq_index); 2858c2ecf20Sopenharmony_ci hw_cons = le16_to_cpu(*txdata->tx_cons_sb); 2868c2ecf20Sopenharmony_ci sw_cons = txdata->tx_pkt_cons; 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci /* Ensure subsequent loads occur after hw_cons */ 2898c2ecf20Sopenharmony_ci smp_rmb(); 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci while (sw_cons != hw_cons) { 2928c2ecf20Sopenharmony_ci u16 pkt_cons; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci pkt_cons = TX_BD(sw_cons); 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_DONE, 2978c2ecf20Sopenharmony_ci "queue[%d]: hw_cons %u sw_cons %u pkt_cons %u\n", 2988c2ecf20Sopenharmony_ci txdata->txq_index, hw_cons, sw_cons, pkt_cons); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci bd_cons = bnx2x_free_tx_pkt(bp, txdata, pkt_cons, 3018c2ecf20Sopenharmony_ci &pkts_compl, &bytes_compl); 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci sw_cons++; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci netdev_tx_completed_queue(txq, pkts_compl, bytes_compl); 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci txdata->tx_pkt_cons = sw_cons; 3098c2ecf20Sopenharmony_ci txdata->tx_bd_cons = bd_cons; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci /* Need to make the tx_bd_cons update visible to start_xmit() 3128c2ecf20Sopenharmony_ci * before checking for netif_tx_queue_stopped(). Without the 3138c2ecf20Sopenharmony_ci * memory barrier, there is a small possibility that 3148c2ecf20Sopenharmony_ci * start_xmit() will miss it and cause the queue to be stopped 3158c2ecf20Sopenharmony_ci * forever. 3168c2ecf20Sopenharmony_ci * On the other hand we need an rmb() here to ensure the proper 3178c2ecf20Sopenharmony_ci * ordering of bit testing in the following 3188c2ecf20Sopenharmony_ci * netif_tx_queue_stopped(txq) call. 3198c2ecf20Sopenharmony_ci */ 3208c2ecf20Sopenharmony_ci smp_mb(); 3218c2ecf20Sopenharmony_ci 3228c2ecf20Sopenharmony_ci if (unlikely(netif_tx_queue_stopped(txq))) { 3238c2ecf20Sopenharmony_ci /* Taking tx_lock() is needed to prevent re-enabling the queue 3248c2ecf20Sopenharmony_ci * while it's empty. This could have happen if rx_action() gets 3258c2ecf20Sopenharmony_ci * suspended in bnx2x_tx_int() after the condition before 3268c2ecf20Sopenharmony_ci * netif_tx_wake_queue(), while tx_action (bnx2x_start_xmit()): 3278c2ecf20Sopenharmony_ci * 3288c2ecf20Sopenharmony_ci * stops the queue->sees fresh tx_bd_cons->releases the queue-> 3298c2ecf20Sopenharmony_ci * sends some packets consuming the whole queue again-> 3308c2ecf20Sopenharmony_ci * stops the queue 3318c2ecf20Sopenharmony_ci */ 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci __netif_tx_lock(txq, smp_processor_id()); 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if ((netif_tx_queue_stopped(txq)) && 3368c2ecf20Sopenharmony_ci (bp->state == BNX2X_STATE_OPEN) && 3378c2ecf20Sopenharmony_ci (bnx2x_tx_avail(bp, txdata) >= MAX_DESC_PER_TX_PKT)) 3388c2ecf20Sopenharmony_ci netif_tx_wake_queue(txq); 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci __netif_tx_unlock(txq); 3418c2ecf20Sopenharmony_ci } 3428c2ecf20Sopenharmony_ci return 0; 3438c2ecf20Sopenharmony_ci} 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_cistatic inline void bnx2x_update_last_max_sge(struct bnx2x_fastpath *fp, 3468c2ecf20Sopenharmony_ci u16 idx) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci u16 last_max = fp->last_max_sge; 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci if (SUB_S16(idx, last_max) > 0) 3518c2ecf20Sopenharmony_ci fp->last_max_sge = idx; 3528c2ecf20Sopenharmony_ci} 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_cistatic inline void bnx2x_update_sge_prod(struct bnx2x_fastpath *fp, 3558c2ecf20Sopenharmony_ci u16 sge_len, 3568c2ecf20Sopenharmony_ci struct eth_end_agg_rx_cqe *cqe) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct bnx2x *bp = fp->bp; 3598c2ecf20Sopenharmony_ci u16 last_max, last_elem, first_elem; 3608c2ecf20Sopenharmony_ci u16 delta = 0; 3618c2ecf20Sopenharmony_ci u16 i; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci if (!sge_len) 3648c2ecf20Sopenharmony_ci return; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci /* First mark all used pages */ 3678c2ecf20Sopenharmony_ci for (i = 0; i < sge_len; i++) 3688c2ecf20Sopenharmony_ci BIT_VEC64_CLEAR_BIT(fp->sge_mask, 3698c2ecf20Sopenharmony_ci RX_SGE(le16_to_cpu(cqe->sgl_or_raw_data.sgl[i]))); 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, "fp_cqe->sgl[%d] = %d\n", 3728c2ecf20Sopenharmony_ci sge_len - 1, le16_to_cpu(cqe->sgl_or_raw_data.sgl[sge_len - 1])); 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci /* Here we assume that the last SGE index is the biggest */ 3758c2ecf20Sopenharmony_ci prefetch((void *)(fp->sge_mask)); 3768c2ecf20Sopenharmony_ci bnx2x_update_last_max_sge(fp, 3778c2ecf20Sopenharmony_ci le16_to_cpu(cqe->sgl_or_raw_data.sgl[sge_len - 1])); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci last_max = RX_SGE(fp->last_max_sge); 3808c2ecf20Sopenharmony_ci last_elem = last_max >> BIT_VEC64_ELEM_SHIFT; 3818c2ecf20Sopenharmony_ci first_elem = RX_SGE(fp->rx_sge_prod) >> BIT_VEC64_ELEM_SHIFT; 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci /* If ring is not full */ 3848c2ecf20Sopenharmony_ci if (last_elem + 1 != first_elem) 3858c2ecf20Sopenharmony_ci last_elem++; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci /* Now update the prod */ 3888c2ecf20Sopenharmony_ci for (i = first_elem; i != last_elem; i = NEXT_SGE_MASK_ELEM(i)) { 3898c2ecf20Sopenharmony_ci if (likely(fp->sge_mask[i])) 3908c2ecf20Sopenharmony_ci break; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci fp->sge_mask[i] = BIT_VEC64_ELEM_ONE_MASK; 3938c2ecf20Sopenharmony_ci delta += BIT_VEC64_ELEM_SZ; 3948c2ecf20Sopenharmony_ci } 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci if (delta > 0) { 3978c2ecf20Sopenharmony_ci fp->rx_sge_prod += delta; 3988c2ecf20Sopenharmony_ci /* clear page-end entries */ 3998c2ecf20Sopenharmony_ci bnx2x_clear_sge_mask_next_elems(fp); 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, 4038c2ecf20Sopenharmony_ci "fp->last_max_sge = %d fp->rx_sge_prod = %d\n", 4048c2ecf20Sopenharmony_ci fp->last_max_sge, fp->rx_sge_prod); 4058c2ecf20Sopenharmony_ci} 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci/* Get Toeplitz hash value in the skb using the value from the 4088c2ecf20Sopenharmony_ci * CQE (calculated by HW). 4098c2ecf20Sopenharmony_ci */ 4108c2ecf20Sopenharmony_cistatic u32 bnx2x_get_rxhash(const struct bnx2x *bp, 4118c2ecf20Sopenharmony_ci const struct eth_fast_path_rx_cqe *cqe, 4128c2ecf20Sopenharmony_ci enum pkt_hash_types *rxhash_type) 4138c2ecf20Sopenharmony_ci{ 4148c2ecf20Sopenharmony_ci /* Get Toeplitz hash from CQE */ 4158c2ecf20Sopenharmony_ci if ((bp->dev->features & NETIF_F_RXHASH) && 4168c2ecf20Sopenharmony_ci (cqe->status_flags & ETH_FAST_PATH_RX_CQE_RSS_HASH_FLG)) { 4178c2ecf20Sopenharmony_ci enum eth_rss_hash_type htype; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci htype = cqe->status_flags & ETH_FAST_PATH_RX_CQE_RSS_HASH_TYPE; 4208c2ecf20Sopenharmony_ci *rxhash_type = ((htype == TCP_IPV4_HASH_TYPE) || 4218c2ecf20Sopenharmony_ci (htype == TCP_IPV6_HASH_TYPE)) ? 4228c2ecf20Sopenharmony_ci PKT_HASH_TYPE_L4 : PKT_HASH_TYPE_L3; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return le32_to_cpu(cqe->rss_hash_result); 4258c2ecf20Sopenharmony_ci } 4268c2ecf20Sopenharmony_ci *rxhash_type = PKT_HASH_TYPE_NONE; 4278c2ecf20Sopenharmony_ci return 0; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic void bnx2x_tpa_start(struct bnx2x_fastpath *fp, u16 queue, 4318c2ecf20Sopenharmony_ci u16 cons, u16 prod, 4328c2ecf20Sopenharmony_ci struct eth_fast_path_rx_cqe *cqe) 4338c2ecf20Sopenharmony_ci{ 4348c2ecf20Sopenharmony_ci struct bnx2x *bp = fp->bp; 4358c2ecf20Sopenharmony_ci struct sw_rx_bd *cons_rx_buf = &fp->rx_buf_ring[cons]; 4368c2ecf20Sopenharmony_ci struct sw_rx_bd *prod_rx_buf = &fp->rx_buf_ring[prod]; 4378c2ecf20Sopenharmony_ci struct eth_rx_bd *prod_bd = &fp->rx_desc_ring[prod]; 4388c2ecf20Sopenharmony_ci dma_addr_t mapping; 4398c2ecf20Sopenharmony_ci struct bnx2x_agg_info *tpa_info = &fp->tpa_info[queue]; 4408c2ecf20Sopenharmony_ci struct sw_rx_bd *first_buf = &tpa_info->first_buf; 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci /* print error if current state != stop */ 4438c2ecf20Sopenharmony_ci if (tpa_info->tpa_state != BNX2X_TPA_STOP) 4448c2ecf20Sopenharmony_ci BNX2X_ERR("start of bin not in stop [%d]\n", queue); 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci /* Try to map an empty data buffer from the aggregation info */ 4478c2ecf20Sopenharmony_ci mapping = dma_map_single(&bp->pdev->dev, 4488c2ecf20Sopenharmony_ci first_buf->data + NET_SKB_PAD, 4498c2ecf20Sopenharmony_ci fp->rx_buf_size, DMA_FROM_DEVICE); 4508c2ecf20Sopenharmony_ci /* 4518c2ecf20Sopenharmony_ci * ...if it fails - move the skb from the consumer to the producer 4528c2ecf20Sopenharmony_ci * and set the current aggregation state as ERROR to drop it 4538c2ecf20Sopenharmony_ci * when TPA_STOP arrives. 4548c2ecf20Sopenharmony_ci */ 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { 4578c2ecf20Sopenharmony_ci /* Move the BD from the consumer to the producer */ 4588c2ecf20Sopenharmony_ci bnx2x_reuse_rx_data(fp, cons, prod); 4598c2ecf20Sopenharmony_ci tpa_info->tpa_state = BNX2X_TPA_ERROR; 4608c2ecf20Sopenharmony_ci return; 4618c2ecf20Sopenharmony_ci } 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci /* move empty data from pool to prod */ 4648c2ecf20Sopenharmony_ci prod_rx_buf->data = first_buf->data; 4658c2ecf20Sopenharmony_ci dma_unmap_addr_set(prod_rx_buf, mapping, mapping); 4668c2ecf20Sopenharmony_ci /* point prod_bd to new data */ 4678c2ecf20Sopenharmony_ci prod_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); 4688c2ecf20Sopenharmony_ci prod_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci /* move partial skb from cons to pool (don't unmap yet) */ 4718c2ecf20Sopenharmony_ci *first_buf = *cons_rx_buf; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci /* mark bin state as START */ 4748c2ecf20Sopenharmony_ci tpa_info->parsing_flags = 4758c2ecf20Sopenharmony_ci le16_to_cpu(cqe->pars_flags.flags); 4768c2ecf20Sopenharmony_ci tpa_info->vlan_tag = le16_to_cpu(cqe->vlan_tag); 4778c2ecf20Sopenharmony_ci tpa_info->tpa_state = BNX2X_TPA_START; 4788c2ecf20Sopenharmony_ci tpa_info->len_on_bd = le16_to_cpu(cqe->len_on_bd); 4798c2ecf20Sopenharmony_ci tpa_info->placement_offset = cqe->placement_offset; 4808c2ecf20Sopenharmony_ci tpa_info->rxhash = bnx2x_get_rxhash(bp, cqe, &tpa_info->rxhash_type); 4818c2ecf20Sopenharmony_ci if (fp->mode == TPA_MODE_GRO) { 4828c2ecf20Sopenharmony_ci u16 gro_size = le16_to_cpu(cqe->pkt_len_or_gro_seg_len); 4838c2ecf20Sopenharmony_ci tpa_info->full_page = SGE_PAGES / gro_size * gro_size; 4848c2ecf20Sopenharmony_ci tpa_info->gro_size = gro_size; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 4888c2ecf20Sopenharmony_ci fp->tpa_queue_used |= (1 << queue); 4898c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, "fp->tpa_queue_used = 0x%llx\n", 4908c2ecf20Sopenharmony_ci fp->tpa_queue_used); 4918c2ecf20Sopenharmony_ci#endif 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci/* Timestamp option length allowed for TPA aggregation: 4958c2ecf20Sopenharmony_ci * 4968c2ecf20Sopenharmony_ci * nop nop kind length echo val 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_ci#define TPA_TSTAMP_OPT_LEN 12 4998c2ecf20Sopenharmony_ci/** 5008c2ecf20Sopenharmony_ci * bnx2x_set_gro_params - compute GRO values 5018c2ecf20Sopenharmony_ci * 5028c2ecf20Sopenharmony_ci * @skb: packet skb 5038c2ecf20Sopenharmony_ci * @parsing_flags: parsing flags from the START CQE 5048c2ecf20Sopenharmony_ci * @len_on_bd: total length of the first packet for the 5058c2ecf20Sopenharmony_ci * aggregation. 5068c2ecf20Sopenharmony_ci * @pkt_len: length of all segments 5078c2ecf20Sopenharmony_ci * @num_of_coalesced_segs: count of segments 5088c2ecf20Sopenharmony_ci * 5098c2ecf20Sopenharmony_ci * Approximate value of the MSS for this aggregation calculated using 5108c2ecf20Sopenharmony_ci * the first packet of it. 5118c2ecf20Sopenharmony_ci * Compute number of aggregated segments, and gso_type. 5128c2ecf20Sopenharmony_ci */ 5138c2ecf20Sopenharmony_cistatic void bnx2x_set_gro_params(struct sk_buff *skb, u16 parsing_flags, 5148c2ecf20Sopenharmony_ci u16 len_on_bd, unsigned int pkt_len, 5158c2ecf20Sopenharmony_ci u16 num_of_coalesced_segs) 5168c2ecf20Sopenharmony_ci{ 5178c2ecf20Sopenharmony_ci /* TPA aggregation won't have either IP options or TCP options 5188c2ecf20Sopenharmony_ci * other than timestamp or IPv6 extension headers. 5198c2ecf20Sopenharmony_ci */ 5208c2ecf20Sopenharmony_ci u16 hdrs_len = ETH_HLEN + sizeof(struct tcphdr); 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci if (GET_FLAG(parsing_flags, PARSING_FLAGS_OVER_ETHERNET_PROTOCOL) == 5238c2ecf20Sopenharmony_ci PRS_FLAG_OVERETH_IPV6) { 5248c2ecf20Sopenharmony_ci hdrs_len += sizeof(struct ipv6hdr); 5258c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6; 5268c2ecf20Sopenharmony_ci } else { 5278c2ecf20Sopenharmony_ci hdrs_len += sizeof(struct iphdr); 5288c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* Check if there was a TCP timestamp, if there is it's will 5328c2ecf20Sopenharmony_ci * always be 12 bytes length: nop nop kind length echo val. 5338c2ecf20Sopenharmony_ci * 5348c2ecf20Sopenharmony_ci * Otherwise FW would close the aggregation. 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_ci if (parsing_flags & PARSING_FLAGS_TIME_STAMP_EXIST_FLAG) 5378c2ecf20Sopenharmony_ci hdrs_len += TPA_TSTAMP_OPT_LEN; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_size = len_on_bd - hdrs_len; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci /* tcp_gro_complete() will copy NAPI_GRO_CB(skb)->count 5428c2ecf20Sopenharmony_ci * to skb_shinfo(skb)->gso_segs 5438c2ecf20Sopenharmony_ci */ 5448c2ecf20Sopenharmony_ci NAPI_GRO_CB(skb)->count = num_of_coalesced_segs; 5458c2ecf20Sopenharmony_ci} 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_cistatic int bnx2x_alloc_rx_sge(struct bnx2x *bp, struct bnx2x_fastpath *fp, 5488c2ecf20Sopenharmony_ci u16 index, gfp_t gfp_mask) 5498c2ecf20Sopenharmony_ci{ 5508c2ecf20Sopenharmony_ci struct sw_rx_page *sw_buf = &fp->rx_page_ring[index]; 5518c2ecf20Sopenharmony_ci struct eth_rx_sge *sge = &fp->rx_sge_ring[index]; 5528c2ecf20Sopenharmony_ci struct bnx2x_alloc_pool *pool = &fp->page_pool; 5538c2ecf20Sopenharmony_ci dma_addr_t mapping; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci if (!pool->page) { 5568c2ecf20Sopenharmony_ci pool->page = alloc_pages(gfp_mask, PAGES_PER_SGE_SHIFT); 5578c2ecf20Sopenharmony_ci if (unlikely(!pool->page)) 5588c2ecf20Sopenharmony_ci return -ENOMEM; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci pool->offset = 0; 5618c2ecf20Sopenharmony_ci } 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci mapping = dma_map_page(&bp->pdev->dev, pool->page, 5648c2ecf20Sopenharmony_ci pool->offset, SGE_PAGE_SIZE, DMA_FROM_DEVICE); 5658c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { 5668c2ecf20Sopenharmony_ci BNX2X_ERR("Can't map sge\n"); 5678c2ecf20Sopenharmony_ci return -ENOMEM; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci sw_buf->page = pool->page; 5718c2ecf20Sopenharmony_ci sw_buf->offset = pool->offset; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci dma_unmap_addr_set(sw_buf, mapping, mapping); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci sge->addr_hi = cpu_to_le32(U64_HI(mapping)); 5768c2ecf20Sopenharmony_ci sge->addr_lo = cpu_to_le32(U64_LO(mapping)); 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci pool->offset += SGE_PAGE_SIZE; 5798c2ecf20Sopenharmony_ci if (PAGE_SIZE - pool->offset >= SGE_PAGE_SIZE) 5808c2ecf20Sopenharmony_ci get_page(pool->page); 5818c2ecf20Sopenharmony_ci else 5828c2ecf20Sopenharmony_ci pool->page = NULL; 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic int bnx2x_fill_frag_skb(struct bnx2x *bp, struct bnx2x_fastpath *fp, 5878c2ecf20Sopenharmony_ci struct bnx2x_agg_info *tpa_info, 5888c2ecf20Sopenharmony_ci u16 pages, 5898c2ecf20Sopenharmony_ci struct sk_buff *skb, 5908c2ecf20Sopenharmony_ci struct eth_end_agg_rx_cqe *cqe, 5918c2ecf20Sopenharmony_ci u16 cqe_idx) 5928c2ecf20Sopenharmony_ci{ 5938c2ecf20Sopenharmony_ci struct sw_rx_page *rx_pg, old_rx_pg; 5948c2ecf20Sopenharmony_ci u32 i, frag_len, frag_size; 5958c2ecf20Sopenharmony_ci int err, j, frag_id = 0; 5968c2ecf20Sopenharmony_ci u16 len_on_bd = tpa_info->len_on_bd; 5978c2ecf20Sopenharmony_ci u16 full_page = 0, gro_size = 0; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci frag_size = le16_to_cpu(cqe->pkt_len) - len_on_bd; 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci if (fp->mode == TPA_MODE_GRO) { 6028c2ecf20Sopenharmony_ci gro_size = tpa_info->gro_size; 6038c2ecf20Sopenharmony_ci full_page = tpa_info->full_page; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci /* This is needed in order to enable forwarding support */ 6078c2ecf20Sopenharmony_ci if (frag_size) 6088c2ecf20Sopenharmony_ci bnx2x_set_gro_params(skb, tpa_info->parsing_flags, len_on_bd, 6098c2ecf20Sopenharmony_ci le16_to_cpu(cqe->pkt_len), 6108c2ecf20Sopenharmony_ci le16_to_cpu(cqe->num_of_coalesced_segs)); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 6138c2ecf20Sopenharmony_ci if (pages > min_t(u32, 8, MAX_SKB_FRAGS) * SGE_PAGES) { 6148c2ecf20Sopenharmony_ci BNX2X_ERR("SGL length is too long: %d. CQE index is %d\n", 6158c2ecf20Sopenharmony_ci pages, cqe_idx); 6168c2ecf20Sopenharmony_ci BNX2X_ERR("cqe->pkt_len = %d\n", cqe->pkt_len); 6178c2ecf20Sopenharmony_ci bnx2x_panic(); 6188c2ecf20Sopenharmony_ci return -EINVAL; 6198c2ecf20Sopenharmony_ci } 6208c2ecf20Sopenharmony_ci#endif 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci /* Run through the SGL and compose the fragmented skb */ 6238c2ecf20Sopenharmony_ci for (i = 0, j = 0; i < pages; i += PAGES_PER_SGE, j++) { 6248c2ecf20Sopenharmony_ci u16 sge_idx = RX_SGE(le16_to_cpu(cqe->sgl_or_raw_data.sgl[j])); 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci /* FW gives the indices of the SGE as if the ring is an array 6278c2ecf20Sopenharmony_ci (meaning that "next" element will consume 2 indices) */ 6288c2ecf20Sopenharmony_ci if (fp->mode == TPA_MODE_GRO) 6298c2ecf20Sopenharmony_ci frag_len = min_t(u32, frag_size, (u32)full_page); 6308c2ecf20Sopenharmony_ci else /* LRO */ 6318c2ecf20Sopenharmony_ci frag_len = min_t(u32, frag_size, (u32)SGE_PAGES); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci rx_pg = &fp->rx_page_ring[sge_idx]; 6348c2ecf20Sopenharmony_ci old_rx_pg = *rx_pg; 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci /* If we fail to allocate a substitute page, we simply stop 6378c2ecf20Sopenharmony_ci where we are and drop the whole packet */ 6388c2ecf20Sopenharmony_ci err = bnx2x_alloc_rx_sge(bp, fp, sge_idx, GFP_ATOMIC); 6398c2ecf20Sopenharmony_ci if (unlikely(err)) { 6408c2ecf20Sopenharmony_ci bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++; 6418c2ecf20Sopenharmony_ci return err; 6428c2ecf20Sopenharmony_ci } 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci dma_unmap_page(&bp->pdev->dev, 6458c2ecf20Sopenharmony_ci dma_unmap_addr(&old_rx_pg, mapping), 6468c2ecf20Sopenharmony_ci SGE_PAGE_SIZE, DMA_FROM_DEVICE); 6478c2ecf20Sopenharmony_ci /* Add one frag and update the appropriate fields in the skb */ 6488c2ecf20Sopenharmony_ci if (fp->mode == TPA_MODE_LRO) 6498c2ecf20Sopenharmony_ci skb_fill_page_desc(skb, j, old_rx_pg.page, 6508c2ecf20Sopenharmony_ci old_rx_pg.offset, frag_len); 6518c2ecf20Sopenharmony_ci else { /* GRO */ 6528c2ecf20Sopenharmony_ci int rem; 6538c2ecf20Sopenharmony_ci int offset = 0; 6548c2ecf20Sopenharmony_ci for (rem = frag_len; rem > 0; rem -= gro_size) { 6558c2ecf20Sopenharmony_ci int len = rem > gro_size ? gro_size : rem; 6568c2ecf20Sopenharmony_ci skb_fill_page_desc(skb, frag_id++, 6578c2ecf20Sopenharmony_ci old_rx_pg.page, 6588c2ecf20Sopenharmony_ci old_rx_pg.offset + offset, 6598c2ecf20Sopenharmony_ci len); 6608c2ecf20Sopenharmony_ci if (offset) 6618c2ecf20Sopenharmony_ci get_page(old_rx_pg.page); 6628c2ecf20Sopenharmony_ci offset += len; 6638c2ecf20Sopenharmony_ci } 6648c2ecf20Sopenharmony_ci } 6658c2ecf20Sopenharmony_ci 6668c2ecf20Sopenharmony_ci skb->data_len += frag_len; 6678c2ecf20Sopenharmony_ci skb->truesize += SGE_PAGES; 6688c2ecf20Sopenharmony_ci skb->len += frag_len; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci frag_size -= frag_len; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci return 0; 6748c2ecf20Sopenharmony_ci} 6758c2ecf20Sopenharmony_ci 6768c2ecf20Sopenharmony_cistatic void bnx2x_frag_free(const struct bnx2x_fastpath *fp, void *data) 6778c2ecf20Sopenharmony_ci{ 6788c2ecf20Sopenharmony_ci if (fp->rx_frag_size) 6798c2ecf20Sopenharmony_ci skb_free_frag(data); 6808c2ecf20Sopenharmony_ci else 6818c2ecf20Sopenharmony_ci kfree(data); 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic void *bnx2x_frag_alloc(const struct bnx2x_fastpath *fp, gfp_t gfp_mask) 6858c2ecf20Sopenharmony_ci{ 6868c2ecf20Sopenharmony_ci if (fp->rx_frag_size) { 6878c2ecf20Sopenharmony_ci /* GFP_KERNEL allocations are used only during initialization */ 6888c2ecf20Sopenharmony_ci if (unlikely(gfpflags_allow_blocking(gfp_mask))) 6898c2ecf20Sopenharmony_ci return (void *)__get_free_page(gfp_mask); 6908c2ecf20Sopenharmony_ci 6918c2ecf20Sopenharmony_ci return napi_alloc_frag(fp->rx_frag_size); 6928c2ecf20Sopenharmony_ci } 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci return kmalloc(fp->rx_buf_size + NET_SKB_PAD, gfp_mask); 6958c2ecf20Sopenharmony_ci} 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci#ifdef CONFIG_INET 6988c2ecf20Sopenharmony_cistatic void bnx2x_gro_ip_csum(struct bnx2x *bp, struct sk_buff *skb) 6998c2ecf20Sopenharmony_ci{ 7008c2ecf20Sopenharmony_ci const struct iphdr *iph = ip_hdr(skb); 7018c2ecf20Sopenharmony_ci struct tcphdr *th; 7028c2ecf20Sopenharmony_ci 7038c2ecf20Sopenharmony_ci skb_set_transport_header(skb, sizeof(struct iphdr)); 7048c2ecf20Sopenharmony_ci th = tcp_hdr(skb); 7058c2ecf20Sopenharmony_ci 7068c2ecf20Sopenharmony_ci th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb), 7078c2ecf20Sopenharmony_ci iph->saddr, iph->daddr, 0); 7088c2ecf20Sopenharmony_ci} 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_cistatic void bnx2x_gro_ipv6_csum(struct bnx2x *bp, struct sk_buff *skb) 7118c2ecf20Sopenharmony_ci{ 7128c2ecf20Sopenharmony_ci struct ipv6hdr *iph = ipv6_hdr(skb); 7138c2ecf20Sopenharmony_ci struct tcphdr *th; 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci skb_set_transport_header(skb, sizeof(struct ipv6hdr)); 7168c2ecf20Sopenharmony_ci th = tcp_hdr(skb); 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci th->check = ~tcp_v6_check(skb->len - skb_transport_offset(skb), 7198c2ecf20Sopenharmony_ci &iph->saddr, &iph->daddr, 0); 7208c2ecf20Sopenharmony_ci} 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_cistatic void bnx2x_gro_csum(struct bnx2x *bp, struct sk_buff *skb, 7238c2ecf20Sopenharmony_ci void (*gro_func)(struct bnx2x*, struct sk_buff*)) 7248c2ecf20Sopenharmony_ci{ 7258c2ecf20Sopenharmony_ci skb_reset_network_header(skb); 7268c2ecf20Sopenharmony_ci gro_func(bp, skb); 7278c2ecf20Sopenharmony_ci tcp_gro_complete(skb); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci#endif 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistatic void bnx2x_gro_receive(struct bnx2x *bp, struct bnx2x_fastpath *fp, 7328c2ecf20Sopenharmony_ci struct sk_buff *skb) 7338c2ecf20Sopenharmony_ci{ 7348c2ecf20Sopenharmony_ci#ifdef CONFIG_INET 7358c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->gso_size) { 7368c2ecf20Sopenharmony_ci switch (be16_to_cpu(skb->protocol)) { 7378c2ecf20Sopenharmony_ci case ETH_P_IP: 7388c2ecf20Sopenharmony_ci bnx2x_gro_csum(bp, skb, bnx2x_gro_ip_csum); 7398c2ecf20Sopenharmony_ci break; 7408c2ecf20Sopenharmony_ci case ETH_P_IPV6: 7418c2ecf20Sopenharmony_ci bnx2x_gro_csum(bp, skb, bnx2x_gro_ipv6_csum); 7428c2ecf20Sopenharmony_ci break; 7438c2ecf20Sopenharmony_ci default: 7448c2ecf20Sopenharmony_ci netdev_WARN_ONCE(bp->dev, 7458c2ecf20Sopenharmony_ci "Error: FW GRO supports only IPv4/IPv6, not 0x%04x\n", 7468c2ecf20Sopenharmony_ci be16_to_cpu(skb->protocol)); 7478c2ecf20Sopenharmony_ci } 7488c2ecf20Sopenharmony_ci } 7498c2ecf20Sopenharmony_ci#endif 7508c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, fp->rx_queue); 7518c2ecf20Sopenharmony_ci napi_gro_receive(&fp->napi, skb); 7528c2ecf20Sopenharmony_ci} 7538c2ecf20Sopenharmony_ci 7548c2ecf20Sopenharmony_cistatic void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, 7558c2ecf20Sopenharmony_ci struct bnx2x_agg_info *tpa_info, 7568c2ecf20Sopenharmony_ci u16 pages, 7578c2ecf20Sopenharmony_ci struct eth_end_agg_rx_cqe *cqe, 7588c2ecf20Sopenharmony_ci u16 cqe_idx) 7598c2ecf20Sopenharmony_ci{ 7608c2ecf20Sopenharmony_ci struct sw_rx_bd *rx_buf = &tpa_info->first_buf; 7618c2ecf20Sopenharmony_ci u8 pad = tpa_info->placement_offset; 7628c2ecf20Sopenharmony_ci u16 len = tpa_info->len_on_bd; 7638c2ecf20Sopenharmony_ci struct sk_buff *skb = NULL; 7648c2ecf20Sopenharmony_ci u8 *new_data, *data = rx_buf->data; 7658c2ecf20Sopenharmony_ci u8 old_tpa_state = tpa_info->tpa_state; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci tpa_info->tpa_state = BNX2X_TPA_STOP; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* If we there was an error during the handling of the TPA_START - 7708c2ecf20Sopenharmony_ci * drop this aggregation. 7718c2ecf20Sopenharmony_ci */ 7728c2ecf20Sopenharmony_ci if (old_tpa_state == BNX2X_TPA_ERROR) 7738c2ecf20Sopenharmony_ci goto drop; 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci /* Try to allocate the new data */ 7768c2ecf20Sopenharmony_ci new_data = bnx2x_frag_alloc(fp, GFP_ATOMIC); 7778c2ecf20Sopenharmony_ci /* Unmap skb in the pool anyway, as we are going to change 7788c2ecf20Sopenharmony_ci pool entry status to BNX2X_TPA_STOP even if new skb allocation 7798c2ecf20Sopenharmony_ci fails. */ 7808c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, dma_unmap_addr(rx_buf, mapping), 7818c2ecf20Sopenharmony_ci fp->rx_buf_size, DMA_FROM_DEVICE); 7828c2ecf20Sopenharmony_ci if (likely(new_data)) 7838c2ecf20Sopenharmony_ci skb = build_skb(data, fp->rx_frag_size); 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci if (likely(skb)) { 7868c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 7878c2ecf20Sopenharmony_ci if (pad + len > fp->rx_buf_size) { 7888c2ecf20Sopenharmony_ci BNX2X_ERR("skb_put is about to fail... pad %d len %d rx_buf_size %d\n", 7898c2ecf20Sopenharmony_ci pad, len, fp->rx_buf_size); 7908c2ecf20Sopenharmony_ci bnx2x_panic(); 7918c2ecf20Sopenharmony_ci bnx2x_frag_free(fp, new_data); 7928c2ecf20Sopenharmony_ci return; 7938c2ecf20Sopenharmony_ci } 7948c2ecf20Sopenharmony_ci#endif 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci skb_reserve(skb, pad + NET_SKB_PAD); 7978c2ecf20Sopenharmony_ci skb_put(skb, len); 7988c2ecf20Sopenharmony_ci skb_set_hash(skb, tpa_info->rxhash, tpa_info->rxhash_type); 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, bp->dev); 8018c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci if (!bnx2x_fill_frag_skb(bp, fp, tpa_info, pages, 8048c2ecf20Sopenharmony_ci skb, cqe, cqe_idx)) { 8058c2ecf20Sopenharmony_ci if (tpa_info->parsing_flags & PARSING_FLAGS_VLAN) 8068c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), tpa_info->vlan_tag); 8078c2ecf20Sopenharmony_ci bnx2x_gro_receive(bp, fp, skb); 8088c2ecf20Sopenharmony_ci } else { 8098c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, 8108c2ecf20Sopenharmony_ci "Failed to allocate new pages - dropping packet!\n"); 8118c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 8128c2ecf20Sopenharmony_ci } 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_ci /* put new data in bin */ 8158c2ecf20Sopenharmony_ci rx_buf->data = new_data; 8168c2ecf20Sopenharmony_ci 8178c2ecf20Sopenharmony_ci return; 8188c2ecf20Sopenharmony_ci } 8198c2ecf20Sopenharmony_ci if (new_data) 8208c2ecf20Sopenharmony_ci bnx2x_frag_free(fp, new_data); 8218c2ecf20Sopenharmony_cidrop: 8228c2ecf20Sopenharmony_ci /* drop the packet and keep the buffer in the bin */ 8238c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, 8248c2ecf20Sopenharmony_ci "Failed to allocate or map a new skb - dropping packet!\n"); 8258c2ecf20Sopenharmony_ci bnx2x_fp_stats(bp, fp)->eth_q_stats.rx_skb_alloc_failed++; 8268c2ecf20Sopenharmony_ci} 8278c2ecf20Sopenharmony_ci 8288c2ecf20Sopenharmony_cistatic int bnx2x_alloc_rx_data(struct bnx2x *bp, struct bnx2x_fastpath *fp, 8298c2ecf20Sopenharmony_ci u16 index, gfp_t gfp_mask) 8308c2ecf20Sopenharmony_ci{ 8318c2ecf20Sopenharmony_ci u8 *data; 8328c2ecf20Sopenharmony_ci struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[index]; 8338c2ecf20Sopenharmony_ci struct eth_rx_bd *rx_bd = &fp->rx_desc_ring[index]; 8348c2ecf20Sopenharmony_ci dma_addr_t mapping; 8358c2ecf20Sopenharmony_ci 8368c2ecf20Sopenharmony_ci data = bnx2x_frag_alloc(fp, gfp_mask); 8378c2ecf20Sopenharmony_ci if (unlikely(data == NULL)) 8388c2ecf20Sopenharmony_ci return -ENOMEM; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci mapping = dma_map_single(&bp->pdev->dev, data + NET_SKB_PAD, 8418c2ecf20Sopenharmony_ci fp->rx_buf_size, 8428c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 8438c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { 8448c2ecf20Sopenharmony_ci bnx2x_frag_free(fp, data); 8458c2ecf20Sopenharmony_ci BNX2X_ERR("Can't map rx data\n"); 8468c2ecf20Sopenharmony_ci return -ENOMEM; 8478c2ecf20Sopenharmony_ci } 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_ci rx_buf->data = data; 8508c2ecf20Sopenharmony_ci dma_unmap_addr_set(rx_buf, mapping, mapping); 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci rx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); 8538c2ecf20Sopenharmony_ci rx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci return 0; 8568c2ecf20Sopenharmony_ci} 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_cistatic 8598c2ecf20Sopenharmony_civoid bnx2x_csum_validate(struct sk_buff *skb, union eth_rx_cqe *cqe, 8608c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp, 8618c2ecf20Sopenharmony_ci struct bnx2x_eth_q_stats *qstats) 8628c2ecf20Sopenharmony_ci{ 8638c2ecf20Sopenharmony_ci /* Do nothing if no L4 csum validation was done. 8648c2ecf20Sopenharmony_ci * We do not check whether IP csum was validated. For IPv4 we assume 8658c2ecf20Sopenharmony_ci * that if the card got as far as validating the L4 csum, it also 8668c2ecf20Sopenharmony_ci * validated the IP csum. IPv6 has no IP csum. 8678c2ecf20Sopenharmony_ci */ 8688c2ecf20Sopenharmony_ci if (cqe->fast_path_cqe.status_flags & 8698c2ecf20Sopenharmony_ci ETH_FAST_PATH_RX_CQE_L4_XSUM_NO_VALIDATION_FLG) 8708c2ecf20Sopenharmony_ci return; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci /* If L4 validation was done, check if an error was found. */ 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci if (cqe->fast_path_cqe.type_error_flags & 8758c2ecf20Sopenharmony_ci (ETH_FAST_PATH_RX_CQE_IP_BAD_XSUM_FLG | 8768c2ecf20Sopenharmony_ci ETH_FAST_PATH_RX_CQE_L4_BAD_XSUM_FLG)) 8778c2ecf20Sopenharmony_ci qstats->hw_csum_err++; 8788c2ecf20Sopenharmony_ci else 8798c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 8808c2ecf20Sopenharmony_ci} 8818c2ecf20Sopenharmony_ci 8828c2ecf20Sopenharmony_cistatic int bnx2x_rx_int(struct bnx2x_fastpath *fp, int budget) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct bnx2x *bp = fp->bp; 8858c2ecf20Sopenharmony_ci u16 bd_cons, bd_prod, bd_prod_fw, comp_ring_cons; 8868c2ecf20Sopenharmony_ci u16 sw_comp_cons, sw_comp_prod; 8878c2ecf20Sopenharmony_ci int rx_pkt = 0; 8888c2ecf20Sopenharmony_ci union eth_rx_cqe *cqe; 8898c2ecf20Sopenharmony_ci struct eth_fast_path_rx_cqe *cqe_fp; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 8928c2ecf20Sopenharmony_ci if (unlikely(bp->panic)) 8938c2ecf20Sopenharmony_ci return 0; 8948c2ecf20Sopenharmony_ci#endif 8958c2ecf20Sopenharmony_ci if (budget <= 0) 8968c2ecf20Sopenharmony_ci return rx_pkt; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci bd_cons = fp->rx_bd_cons; 8998c2ecf20Sopenharmony_ci bd_prod = fp->rx_bd_prod; 9008c2ecf20Sopenharmony_ci bd_prod_fw = bd_prod; 9018c2ecf20Sopenharmony_ci sw_comp_cons = fp->rx_comp_cons; 9028c2ecf20Sopenharmony_ci sw_comp_prod = fp->rx_comp_prod; 9038c2ecf20Sopenharmony_ci 9048c2ecf20Sopenharmony_ci comp_ring_cons = RCQ_BD(sw_comp_cons); 9058c2ecf20Sopenharmony_ci cqe = &fp->rx_comp_ring[comp_ring_cons]; 9068c2ecf20Sopenharmony_ci cqe_fp = &cqe->fast_path_cqe; 9078c2ecf20Sopenharmony_ci 9088c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, 9098c2ecf20Sopenharmony_ci "queue[%d]: sw_comp_cons %u\n", fp->index, sw_comp_cons); 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci while (BNX2X_IS_CQE_COMPLETED(cqe_fp)) { 9128c2ecf20Sopenharmony_ci struct sw_rx_bd *rx_buf = NULL; 9138c2ecf20Sopenharmony_ci struct sk_buff *skb; 9148c2ecf20Sopenharmony_ci u8 cqe_fp_flags; 9158c2ecf20Sopenharmony_ci enum eth_rx_cqe_type cqe_fp_type; 9168c2ecf20Sopenharmony_ci u16 len, pad, queue; 9178c2ecf20Sopenharmony_ci u8 *data; 9188c2ecf20Sopenharmony_ci u32 rxhash; 9198c2ecf20Sopenharmony_ci enum pkt_hash_types rxhash_type; 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 9228c2ecf20Sopenharmony_ci if (unlikely(bp->panic)) 9238c2ecf20Sopenharmony_ci return 0; 9248c2ecf20Sopenharmony_ci#endif 9258c2ecf20Sopenharmony_ci 9268c2ecf20Sopenharmony_ci bd_prod = RX_BD(bd_prod); 9278c2ecf20Sopenharmony_ci bd_cons = RX_BD(bd_cons); 9288c2ecf20Sopenharmony_ci 9298c2ecf20Sopenharmony_ci /* A rmb() is required to ensure that the CQE is not read 9308c2ecf20Sopenharmony_ci * before it is written by the adapter DMA. PCI ordering 9318c2ecf20Sopenharmony_ci * rules will make sure the other fields are written before 9328c2ecf20Sopenharmony_ci * the marker at the end of struct eth_fast_path_rx_cqe 9338c2ecf20Sopenharmony_ci * but without rmb() a weakly ordered processor can process 9348c2ecf20Sopenharmony_ci * stale data. Without the barrier TPA state-machine might 9358c2ecf20Sopenharmony_ci * enter inconsistent state and kernel stack might be 9368c2ecf20Sopenharmony_ci * provided with incorrect packet description - these lead 9378c2ecf20Sopenharmony_ci * to various kernel crashed. 9388c2ecf20Sopenharmony_ci */ 9398c2ecf20Sopenharmony_ci rmb(); 9408c2ecf20Sopenharmony_ci 9418c2ecf20Sopenharmony_ci cqe_fp_flags = cqe_fp->type_error_flags; 9428c2ecf20Sopenharmony_ci cqe_fp_type = cqe_fp_flags & ETH_FAST_PATH_RX_CQE_TYPE; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, 9458c2ecf20Sopenharmony_ci "CQE type %x err %x status %x queue %x vlan %x len %u\n", 9468c2ecf20Sopenharmony_ci CQE_TYPE(cqe_fp_flags), 9478c2ecf20Sopenharmony_ci cqe_fp_flags, cqe_fp->status_flags, 9488c2ecf20Sopenharmony_ci le32_to_cpu(cqe_fp->rss_hash_result), 9498c2ecf20Sopenharmony_ci le16_to_cpu(cqe_fp->vlan_tag), 9508c2ecf20Sopenharmony_ci le16_to_cpu(cqe_fp->pkt_len_or_gro_seg_len)); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci /* is this a slowpath msg? */ 9538c2ecf20Sopenharmony_ci if (unlikely(CQE_TYPE_SLOW(cqe_fp_type))) { 9548c2ecf20Sopenharmony_ci bnx2x_sp_event(fp, cqe); 9558c2ecf20Sopenharmony_ci goto next_cqe; 9568c2ecf20Sopenharmony_ci } 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci rx_buf = &fp->rx_buf_ring[bd_cons]; 9598c2ecf20Sopenharmony_ci data = rx_buf->data; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (!CQE_TYPE_FAST(cqe_fp_type)) { 9628c2ecf20Sopenharmony_ci struct bnx2x_agg_info *tpa_info; 9638c2ecf20Sopenharmony_ci u16 frag_size, pages; 9648c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 9658c2ecf20Sopenharmony_ci /* sanity check */ 9668c2ecf20Sopenharmony_ci if (fp->mode == TPA_MODE_DISABLED && 9678c2ecf20Sopenharmony_ci (CQE_TYPE_START(cqe_fp_type) || 9688c2ecf20Sopenharmony_ci CQE_TYPE_STOP(cqe_fp_type))) 9698c2ecf20Sopenharmony_ci BNX2X_ERR("START/STOP packet while TPA disabled, type %x\n", 9708c2ecf20Sopenharmony_ci CQE_TYPE(cqe_fp_type)); 9718c2ecf20Sopenharmony_ci#endif 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_ci if (CQE_TYPE_START(cqe_fp_type)) { 9748c2ecf20Sopenharmony_ci u16 queue = cqe_fp->queue_index; 9758c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, 9768c2ecf20Sopenharmony_ci "calling tpa_start on queue %d\n", 9778c2ecf20Sopenharmony_ci queue); 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_ci bnx2x_tpa_start(fp, queue, 9808c2ecf20Sopenharmony_ci bd_cons, bd_prod, 9818c2ecf20Sopenharmony_ci cqe_fp); 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci goto next_rx; 9848c2ecf20Sopenharmony_ci } 9858c2ecf20Sopenharmony_ci queue = cqe->end_agg_cqe.queue_index; 9868c2ecf20Sopenharmony_ci tpa_info = &fp->tpa_info[queue]; 9878c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, 9888c2ecf20Sopenharmony_ci "calling tpa_stop on queue %d\n", 9898c2ecf20Sopenharmony_ci queue); 9908c2ecf20Sopenharmony_ci 9918c2ecf20Sopenharmony_ci frag_size = le16_to_cpu(cqe->end_agg_cqe.pkt_len) - 9928c2ecf20Sopenharmony_ci tpa_info->len_on_bd; 9938c2ecf20Sopenharmony_ci 9948c2ecf20Sopenharmony_ci if (fp->mode == TPA_MODE_GRO) 9958c2ecf20Sopenharmony_ci pages = (frag_size + tpa_info->full_page - 1) / 9968c2ecf20Sopenharmony_ci tpa_info->full_page; 9978c2ecf20Sopenharmony_ci else 9988c2ecf20Sopenharmony_ci pages = SGE_PAGE_ALIGN(frag_size) >> 9998c2ecf20Sopenharmony_ci SGE_PAGE_SHIFT; 10008c2ecf20Sopenharmony_ci 10018c2ecf20Sopenharmony_ci bnx2x_tpa_stop(bp, fp, tpa_info, pages, 10028c2ecf20Sopenharmony_ci &cqe->end_agg_cqe, comp_ring_cons); 10038c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 10048c2ecf20Sopenharmony_ci if (bp->panic) 10058c2ecf20Sopenharmony_ci return 0; 10068c2ecf20Sopenharmony_ci#endif 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci bnx2x_update_sge_prod(fp, pages, &cqe->end_agg_cqe); 10098c2ecf20Sopenharmony_ci goto next_cqe; 10108c2ecf20Sopenharmony_ci } 10118c2ecf20Sopenharmony_ci /* non TPA */ 10128c2ecf20Sopenharmony_ci len = le16_to_cpu(cqe_fp->pkt_len_or_gro_seg_len); 10138c2ecf20Sopenharmony_ci pad = cqe_fp->placement_offset; 10148c2ecf20Sopenharmony_ci dma_sync_single_for_cpu(&bp->pdev->dev, 10158c2ecf20Sopenharmony_ci dma_unmap_addr(rx_buf, mapping), 10168c2ecf20Sopenharmony_ci pad + RX_COPY_THRESH, 10178c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 10188c2ecf20Sopenharmony_ci pad += NET_SKB_PAD; 10198c2ecf20Sopenharmony_ci prefetch(data + pad); /* speedup eth_type_trans() */ 10208c2ecf20Sopenharmony_ci /* is this an error packet? */ 10218c2ecf20Sopenharmony_ci if (unlikely(cqe_fp_flags & ETH_RX_ERROR_FALGS)) { 10228c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS, 10238c2ecf20Sopenharmony_ci "ERROR flags %x rx packet %u\n", 10248c2ecf20Sopenharmony_ci cqe_fp_flags, sw_comp_cons); 10258c2ecf20Sopenharmony_ci bnx2x_fp_qstats(bp, fp)->rx_err_discard_pkt++; 10268c2ecf20Sopenharmony_ci goto reuse_rx; 10278c2ecf20Sopenharmony_ci } 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci /* Since we don't have a jumbo ring 10308c2ecf20Sopenharmony_ci * copy small packets if mtu > 1500 10318c2ecf20Sopenharmony_ci */ 10328c2ecf20Sopenharmony_ci if ((bp->dev->mtu > ETH_MAX_PACKET_SIZE) && 10338c2ecf20Sopenharmony_ci (len <= RX_COPY_THRESH)) { 10348c2ecf20Sopenharmony_ci skb = napi_alloc_skb(&fp->napi, len); 10358c2ecf20Sopenharmony_ci if (skb == NULL) { 10368c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS, 10378c2ecf20Sopenharmony_ci "ERROR packet dropped because of alloc failure\n"); 10388c2ecf20Sopenharmony_ci bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++; 10398c2ecf20Sopenharmony_ci goto reuse_rx; 10408c2ecf20Sopenharmony_ci } 10418c2ecf20Sopenharmony_ci memcpy(skb->data, data + pad, len); 10428c2ecf20Sopenharmony_ci bnx2x_reuse_rx_data(fp, bd_cons, bd_prod); 10438c2ecf20Sopenharmony_ci } else { 10448c2ecf20Sopenharmony_ci if (likely(bnx2x_alloc_rx_data(bp, fp, bd_prod, 10458c2ecf20Sopenharmony_ci GFP_ATOMIC) == 0)) { 10468c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, 10478c2ecf20Sopenharmony_ci dma_unmap_addr(rx_buf, mapping), 10488c2ecf20Sopenharmony_ci fp->rx_buf_size, 10498c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 10508c2ecf20Sopenharmony_ci skb = build_skb(data, fp->rx_frag_size); 10518c2ecf20Sopenharmony_ci if (unlikely(!skb)) { 10528c2ecf20Sopenharmony_ci bnx2x_frag_free(fp, data); 10538c2ecf20Sopenharmony_ci bnx2x_fp_qstats(bp, fp)-> 10548c2ecf20Sopenharmony_ci rx_skb_alloc_failed++; 10558c2ecf20Sopenharmony_ci goto next_rx; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci skb_reserve(skb, pad); 10588c2ecf20Sopenharmony_ci } else { 10598c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_ERR | NETIF_MSG_RX_STATUS, 10608c2ecf20Sopenharmony_ci "ERROR packet dropped because of alloc failure\n"); 10618c2ecf20Sopenharmony_ci bnx2x_fp_qstats(bp, fp)->rx_skb_alloc_failed++; 10628c2ecf20Sopenharmony_cireuse_rx: 10638c2ecf20Sopenharmony_ci bnx2x_reuse_rx_data(fp, bd_cons, bd_prod); 10648c2ecf20Sopenharmony_ci goto next_rx; 10658c2ecf20Sopenharmony_ci } 10668c2ecf20Sopenharmony_ci } 10678c2ecf20Sopenharmony_ci 10688c2ecf20Sopenharmony_ci skb_put(skb, len); 10698c2ecf20Sopenharmony_ci skb->protocol = eth_type_trans(skb, bp->dev); 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci /* Set Toeplitz hash for a none-LRO skb */ 10728c2ecf20Sopenharmony_ci rxhash = bnx2x_get_rxhash(bp, cqe_fp, &rxhash_type); 10738c2ecf20Sopenharmony_ci skb_set_hash(skb, rxhash, rxhash_type); 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci skb_checksum_none_assert(skb); 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci if (bp->dev->features & NETIF_F_RXCSUM) 10788c2ecf20Sopenharmony_ci bnx2x_csum_validate(skb, cqe, fp, 10798c2ecf20Sopenharmony_ci bnx2x_fp_qstats(bp, fp)); 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci skb_record_rx_queue(skb, fp->rx_queue); 10828c2ecf20Sopenharmony_ci 10838c2ecf20Sopenharmony_ci /* Check if this packet was timestamped */ 10848c2ecf20Sopenharmony_ci if (unlikely(cqe->fast_path_cqe.type_error_flags & 10858c2ecf20Sopenharmony_ci (1 << ETH_FAST_PATH_RX_CQE_PTP_PKT_SHIFT))) 10868c2ecf20Sopenharmony_ci bnx2x_set_rx_ts(bp, skb); 10878c2ecf20Sopenharmony_ci 10888c2ecf20Sopenharmony_ci if (le16_to_cpu(cqe_fp->pars_flags.flags) & 10898c2ecf20Sopenharmony_ci PARSING_FLAGS_VLAN) 10908c2ecf20Sopenharmony_ci __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), 10918c2ecf20Sopenharmony_ci le16_to_cpu(cqe_fp->vlan_tag)); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci napi_gro_receive(&fp->napi, skb); 10948c2ecf20Sopenharmony_cinext_rx: 10958c2ecf20Sopenharmony_ci rx_buf->data = NULL; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci bd_cons = NEXT_RX_IDX(bd_cons); 10988c2ecf20Sopenharmony_ci bd_prod = NEXT_RX_IDX(bd_prod); 10998c2ecf20Sopenharmony_ci bd_prod_fw = NEXT_RX_IDX(bd_prod_fw); 11008c2ecf20Sopenharmony_ci rx_pkt++; 11018c2ecf20Sopenharmony_cinext_cqe: 11028c2ecf20Sopenharmony_ci sw_comp_prod = NEXT_RCQ_IDX(sw_comp_prod); 11038c2ecf20Sopenharmony_ci sw_comp_cons = NEXT_RCQ_IDX(sw_comp_cons); 11048c2ecf20Sopenharmony_ci 11058c2ecf20Sopenharmony_ci /* mark CQE as free */ 11068c2ecf20Sopenharmony_ci BNX2X_SEED_CQE(cqe_fp); 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci if (rx_pkt == budget) 11098c2ecf20Sopenharmony_ci break; 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci comp_ring_cons = RCQ_BD(sw_comp_cons); 11128c2ecf20Sopenharmony_ci cqe = &fp->rx_comp_ring[comp_ring_cons]; 11138c2ecf20Sopenharmony_ci cqe_fp = &cqe->fast_path_cqe; 11148c2ecf20Sopenharmony_ci } /* while */ 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci fp->rx_bd_cons = bd_cons; 11178c2ecf20Sopenharmony_ci fp->rx_bd_prod = bd_prod_fw; 11188c2ecf20Sopenharmony_ci fp->rx_comp_cons = sw_comp_cons; 11198c2ecf20Sopenharmony_ci fp->rx_comp_prod = sw_comp_prod; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci /* Update producers */ 11228c2ecf20Sopenharmony_ci bnx2x_update_rx_prod(bp, fp, bd_prod_fw, sw_comp_prod, 11238c2ecf20Sopenharmony_ci fp->rx_sge_prod); 11248c2ecf20Sopenharmony_ci 11258c2ecf20Sopenharmony_ci return rx_pkt; 11268c2ecf20Sopenharmony_ci} 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = fp_cookie; 11318c2ecf20Sopenharmony_ci struct bnx2x *bp = fp->bp; 11328c2ecf20Sopenharmony_ci u8 cos; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci DP(NETIF_MSG_INTR, 11358c2ecf20Sopenharmony_ci "got an MSI-X interrupt on IDX:SB [fp %d fw_sd %d igusb %d]\n", 11368c2ecf20Sopenharmony_ci fp->index, fp->fw_sb_id, fp->igu_sb_id); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 0, IGU_INT_DISABLE, 0); 11398c2ecf20Sopenharmony_ci 11408c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 11418c2ecf20Sopenharmony_ci if (unlikely(bp->panic)) 11428c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11438c2ecf20Sopenharmony_ci#endif 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci /* Handle Rx and Tx according to MSI-X vector */ 11468c2ecf20Sopenharmony_ci for_each_cos_in_tx_queue(fp, cos) 11478c2ecf20Sopenharmony_ci prefetch(fp->txdata_ptr[cos]->tx_cons_sb); 11488c2ecf20Sopenharmony_ci 11498c2ecf20Sopenharmony_ci prefetch(&fp->sb_running_index[SM_RX_ID]); 11508c2ecf20Sopenharmony_ci napi_schedule_irqoff(&bnx2x_fp(bp, fp->index, napi)); 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_ci return IRQ_HANDLED; 11538c2ecf20Sopenharmony_ci} 11548c2ecf20Sopenharmony_ci 11558c2ecf20Sopenharmony_ci/* HW Lock for shared dual port PHYs */ 11568c2ecf20Sopenharmony_civoid bnx2x_acquire_phy_lock(struct bnx2x *bp) 11578c2ecf20Sopenharmony_ci{ 11588c2ecf20Sopenharmony_ci mutex_lock(&bp->port.phy_mutex); 11598c2ecf20Sopenharmony_ci 11608c2ecf20Sopenharmony_ci bnx2x_acquire_hw_lock(bp, HW_LOCK_RESOURCE_MDIO); 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_civoid bnx2x_release_phy_lock(struct bnx2x *bp) 11648c2ecf20Sopenharmony_ci{ 11658c2ecf20Sopenharmony_ci bnx2x_release_hw_lock(bp, HW_LOCK_RESOURCE_MDIO); 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_ci mutex_unlock(&bp->port.phy_mutex); 11688c2ecf20Sopenharmony_ci} 11698c2ecf20Sopenharmony_ci 11708c2ecf20Sopenharmony_ci/* calculates MF speed according to current linespeed and MF configuration */ 11718c2ecf20Sopenharmony_ciu16 bnx2x_get_mf_speed(struct bnx2x *bp) 11728c2ecf20Sopenharmony_ci{ 11738c2ecf20Sopenharmony_ci u16 line_speed = bp->link_vars.line_speed; 11748c2ecf20Sopenharmony_ci if (IS_MF(bp)) { 11758c2ecf20Sopenharmony_ci u16 maxCfg = bnx2x_extract_max_cfg(bp, 11768c2ecf20Sopenharmony_ci bp->mf_config[BP_VN(bp)]); 11778c2ecf20Sopenharmony_ci 11788c2ecf20Sopenharmony_ci /* Calculate the current MAX line speed limit for the MF 11798c2ecf20Sopenharmony_ci * devices 11808c2ecf20Sopenharmony_ci */ 11818c2ecf20Sopenharmony_ci if (IS_MF_PERCENT_BW(bp)) 11828c2ecf20Sopenharmony_ci line_speed = (line_speed * maxCfg) / 100; 11838c2ecf20Sopenharmony_ci else { /* SD mode */ 11848c2ecf20Sopenharmony_ci u16 vn_max_rate = maxCfg * 100; 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci if (vn_max_rate < line_speed) 11878c2ecf20Sopenharmony_ci line_speed = vn_max_rate; 11888c2ecf20Sopenharmony_ci } 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci return line_speed; 11928c2ecf20Sopenharmony_ci} 11938c2ecf20Sopenharmony_ci 11948c2ecf20Sopenharmony_ci/** 11958c2ecf20Sopenharmony_ci * bnx2x_fill_report_data - fill link report data to report 11968c2ecf20Sopenharmony_ci * 11978c2ecf20Sopenharmony_ci * @bp: driver handle 11988c2ecf20Sopenharmony_ci * @data: link state to update 11998c2ecf20Sopenharmony_ci * 12008c2ecf20Sopenharmony_ci * It uses a none-atomic bit operations because is called under the mutex. 12018c2ecf20Sopenharmony_ci */ 12028c2ecf20Sopenharmony_cistatic void bnx2x_fill_report_data(struct bnx2x *bp, 12038c2ecf20Sopenharmony_ci struct bnx2x_link_report_data *data) 12048c2ecf20Sopenharmony_ci{ 12058c2ecf20Sopenharmony_ci memset(data, 0, sizeof(*data)); 12068c2ecf20Sopenharmony_ci 12078c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 12088c2ecf20Sopenharmony_ci /* Fill the report data: effective line speed */ 12098c2ecf20Sopenharmony_ci data->line_speed = bnx2x_get_mf_speed(bp); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci /* Link is down */ 12128c2ecf20Sopenharmony_ci if (!bp->link_vars.link_up || (bp->flags & MF_FUNC_DIS)) 12138c2ecf20Sopenharmony_ci __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, 12148c2ecf20Sopenharmony_ci &data->link_report_flags); 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci if (!BNX2X_NUM_ETH_QUEUES(bp)) 12178c2ecf20Sopenharmony_ci __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, 12188c2ecf20Sopenharmony_ci &data->link_report_flags); 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci /* Full DUPLEX */ 12218c2ecf20Sopenharmony_ci if (bp->link_vars.duplex == DUPLEX_FULL) 12228c2ecf20Sopenharmony_ci __set_bit(BNX2X_LINK_REPORT_FD, 12238c2ecf20Sopenharmony_ci &data->link_report_flags); 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci /* Rx Flow Control is ON */ 12268c2ecf20Sopenharmony_ci if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) 12278c2ecf20Sopenharmony_ci __set_bit(BNX2X_LINK_REPORT_RX_FC_ON, 12288c2ecf20Sopenharmony_ci &data->link_report_flags); 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci /* Tx Flow Control is ON */ 12318c2ecf20Sopenharmony_ci if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) 12328c2ecf20Sopenharmony_ci __set_bit(BNX2X_LINK_REPORT_TX_FC_ON, 12338c2ecf20Sopenharmony_ci &data->link_report_flags); 12348c2ecf20Sopenharmony_ci } else { /* VF */ 12358c2ecf20Sopenharmony_ci *data = bp->vf_link_vars; 12368c2ecf20Sopenharmony_ci } 12378c2ecf20Sopenharmony_ci} 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci/** 12408c2ecf20Sopenharmony_ci * bnx2x_link_report - report link status to OS. 12418c2ecf20Sopenharmony_ci * 12428c2ecf20Sopenharmony_ci * @bp: driver handle 12438c2ecf20Sopenharmony_ci * 12448c2ecf20Sopenharmony_ci * Calls the __bnx2x_link_report() under the same locking scheme 12458c2ecf20Sopenharmony_ci * as a link/PHY state managing code to ensure a consistent link 12468c2ecf20Sopenharmony_ci * reporting. 12478c2ecf20Sopenharmony_ci */ 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_civoid bnx2x_link_report(struct bnx2x *bp) 12508c2ecf20Sopenharmony_ci{ 12518c2ecf20Sopenharmony_ci bnx2x_acquire_phy_lock(bp); 12528c2ecf20Sopenharmony_ci __bnx2x_link_report(bp); 12538c2ecf20Sopenharmony_ci bnx2x_release_phy_lock(bp); 12548c2ecf20Sopenharmony_ci} 12558c2ecf20Sopenharmony_ci 12568c2ecf20Sopenharmony_ci/** 12578c2ecf20Sopenharmony_ci * __bnx2x_link_report - report link status to OS. 12588c2ecf20Sopenharmony_ci * 12598c2ecf20Sopenharmony_ci * @bp: driver handle 12608c2ecf20Sopenharmony_ci * 12618c2ecf20Sopenharmony_ci * None atomic implementation. 12628c2ecf20Sopenharmony_ci * Should be called under the phy_lock. 12638c2ecf20Sopenharmony_ci */ 12648c2ecf20Sopenharmony_civoid __bnx2x_link_report(struct bnx2x *bp) 12658c2ecf20Sopenharmony_ci{ 12668c2ecf20Sopenharmony_ci struct bnx2x_link_report_data cur_data; 12678c2ecf20Sopenharmony_ci 12688c2ecf20Sopenharmony_ci if (bp->force_link_down) { 12698c2ecf20Sopenharmony_ci bp->link_vars.link_up = 0; 12708c2ecf20Sopenharmony_ci return; 12718c2ecf20Sopenharmony_ci } 12728c2ecf20Sopenharmony_ci 12738c2ecf20Sopenharmony_ci /* reread mf_cfg */ 12748c2ecf20Sopenharmony_ci if (IS_PF(bp) && !CHIP_IS_E1(bp)) 12758c2ecf20Sopenharmony_ci bnx2x_read_mf_cfg(bp); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci /* Read the current link report info */ 12788c2ecf20Sopenharmony_ci bnx2x_fill_report_data(bp, &cur_data); 12798c2ecf20Sopenharmony_ci 12808c2ecf20Sopenharmony_ci /* Don't report link down or exactly the same link status twice */ 12818c2ecf20Sopenharmony_ci if (!memcmp(&cur_data, &bp->last_reported_link, sizeof(cur_data)) || 12828c2ecf20Sopenharmony_ci (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, 12838c2ecf20Sopenharmony_ci &bp->last_reported_link.link_report_flags) && 12848c2ecf20Sopenharmony_ci test_bit(BNX2X_LINK_REPORT_LINK_DOWN, 12858c2ecf20Sopenharmony_ci &cur_data.link_report_flags))) 12868c2ecf20Sopenharmony_ci return; 12878c2ecf20Sopenharmony_ci 12888c2ecf20Sopenharmony_ci bp->link_cnt++; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci /* We are going to report a new link parameters now - 12918c2ecf20Sopenharmony_ci * remember the current data for the next time. 12928c2ecf20Sopenharmony_ci */ 12938c2ecf20Sopenharmony_ci memcpy(&bp->last_reported_link, &cur_data, sizeof(cur_data)); 12948c2ecf20Sopenharmony_ci 12958c2ecf20Sopenharmony_ci /* propagate status to VFs */ 12968c2ecf20Sopenharmony_ci if (IS_PF(bp)) 12978c2ecf20Sopenharmony_ci bnx2x_iov_link_update(bp); 12988c2ecf20Sopenharmony_ci 12998c2ecf20Sopenharmony_ci if (test_bit(BNX2X_LINK_REPORT_LINK_DOWN, 13008c2ecf20Sopenharmony_ci &cur_data.link_report_flags)) { 13018c2ecf20Sopenharmony_ci netif_carrier_off(bp->dev); 13028c2ecf20Sopenharmony_ci netdev_err(bp->dev, "NIC Link is Down\n"); 13038c2ecf20Sopenharmony_ci return; 13048c2ecf20Sopenharmony_ci } else { 13058c2ecf20Sopenharmony_ci const char *duplex; 13068c2ecf20Sopenharmony_ci const char *flow; 13078c2ecf20Sopenharmony_ci 13088c2ecf20Sopenharmony_ci netif_carrier_on(bp->dev); 13098c2ecf20Sopenharmony_ci 13108c2ecf20Sopenharmony_ci if (test_and_clear_bit(BNX2X_LINK_REPORT_FD, 13118c2ecf20Sopenharmony_ci &cur_data.link_report_flags)) 13128c2ecf20Sopenharmony_ci duplex = "full"; 13138c2ecf20Sopenharmony_ci else 13148c2ecf20Sopenharmony_ci duplex = "half"; 13158c2ecf20Sopenharmony_ci 13168c2ecf20Sopenharmony_ci /* Handle the FC at the end so that only these flags would be 13178c2ecf20Sopenharmony_ci * possibly set. This way we may easily check if there is no FC 13188c2ecf20Sopenharmony_ci * enabled. 13198c2ecf20Sopenharmony_ci */ 13208c2ecf20Sopenharmony_ci if (cur_data.link_report_flags) { 13218c2ecf20Sopenharmony_ci if (test_bit(BNX2X_LINK_REPORT_RX_FC_ON, 13228c2ecf20Sopenharmony_ci &cur_data.link_report_flags)) { 13238c2ecf20Sopenharmony_ci if (test_bit(BNX2X_LINK_REPORT_TX_FC_ON, 13248c2ecf20Sopenharmony_ci &cur_data.link_report_flags)) 13258c2ecf20Sopenharmony_ci flow = "ON - receive & transmit"; 13268c2ecf20Sopenharmony_ci else 13278c2ecf20Sopenharmony_ci flow = "ON - receive"; 13288c2ecf20Sopenharmony_ci } else { 13298c2ecf20Sopenharmony_ci flow = "ON - transmit"; 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci } else { 13328c2ecf20Sopenharmony_ci flow = "none"; 13338c2ecf20Sopenharmony_ci } 13348c2ecf20Sopenharmony_ci netdev_info(bp->dev, "NIC Link is Up, %d Mbps %s duplex, Flow control: %s\n", 13358c2ecf20Sopenharmony_ci cur_data.line_speed, duplex, flow); 13368c2ecf20Sopenharmony_ci } 13378c2ecf20Sopenharmony_ci} 13388c2ecf20Sopenharmony_ci 13398c2ecf20Sopenharmony_cistatic void bnx2x_set_next_page_sgl(struct bnx2x_fastpath *fp) 13408c2ecf20Sopenharmony_ci{ 13418c2ecf20Sopenharmony_ci int i; 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci for (i = 1; i <= NUM_RX_SGE_PAGES; i++) { 13448c2ecf20Sopenharmony_ci struct eth_rx_sge *sge; 13458c2ecf20Sopenharmony_ci 13468c2ecf20Sopenharmony_ci sge = &fp->rx_sge_ring[RX_SGE_CNT * i - 2]; 13478c2ecf20Sopenharmony_ci sge->addr_hi = 13488c2ecf20Sopenharmony_ci cpu_to_le32(U64_HI(fp->rx_sge_mapping + 13498c2ecf20Sopenharmony_ci BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES))); 13508c2ecf20Sopenharmony_ci 13518c2ecf20Sopenharmony_ci sge->addr_lo = 13528c2ecf20Sopenharmony_ci cpu_to_le32(U64_LO(fp->rx_sge_mapping + 13538c2ecf20Sopenharmony_ci BCM_PAGE_SIZE*(i % NUM_RX_SGE_PAGES))); 13548c2ecf20Sopenharmony_ci } 13558c2ecf20Sopenharmony_ci} 13568c2ecf20Sopenharmony_ci 13578c2ecf20Sopenharmony_cistatic void bnx2x_free_tpa_pool(struct bnx2x *bp, 13588c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp, int last) 13598c2ecf20Sopenharmony_ci{ 13608c2ecf20Sopenharmony_ci int i; 13618c2ecf20Sopenharmony_ci 13628c2ecf20Sopenharmony_ci for (i = 0; i < last; i++) { 13638c2ecf20Sopenharmony_ci struct bnx2x_agg_info *tpa_info = &fp->tpa_info[i]; 13648c2ecf20Sopenharmony_ci struct sw_rx_bd *first_buf = &tpa_info->first_buf; 13658c2ecf20Sopenharmony_ci u8 *data = first_buf->data; 13668c2ecf20Sopenharmony_ci 13678c2ecf20Sopenharmony_ci if (data == NULL) { 13688c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFDOWN, "tpa bin %d empty on free\n", i); 13698c2ecf20Sopenharmony_ci continue; 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci if (tpa_info->tpa_state == BNX2X_TPA_START) 13728c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, 13738c2ecf20Sopenharmony_ci dma_unmap_addr(first_buf, mapping), 13748c2ecf20Sopenharmony_ci fp->rx_buf_size, DMA_FROM_DEVICE); 13758c2ecf20Sopenharmony_ci bnx2x_frag_free(fp, data); 13768c2ecf20Sopenharmony_ci first_buf->data = NULL; 13778c2ecf20Sopenharmony_ci } 13788c2ecf20Sopenharmony_ci} 13798c2ecf20Sopenharmony_ci 13808c2ecf20Sopenharmony_civoid bnx2x_init_rx_rings_cnic(struct bnx2x *bp) 13818c2ecf20Sopenharmony_ci{ 13828c2ecf20Sopenharmony_ci int j; 13838c2ecf20Sopenharmony_ci 13848c2ecf20Sopenharmony_ci for_each_rx_queue_cnic(bp, j) { 13858c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[j]; 13868c2ecf20Sopenharmony_ci 13878c2ecf20Sopenharmony_ci fp->rx_bd_cons = 0; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci /* Activate BD ring */ 13908c2ecf20Sopenharmony_ci /* Warning! 13918c2ecf20Sopenharmony_ci * this will generate an interrupt (to the TSTORM) 13928c2ecf20Sopenharmony_ci * must only be done after chip is initialized 13938c2ecf20Sopenharmony_ci */ 13948c2ecf20Sopenharmony_ci bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, 13958c2ecf20Sopenharmony_ci fp->rx_sge_prod); 13968c2ecf20Sopenharmony_ci } 13978c2ecf20Sopenharmony_ci} 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_civoid bnx2x_init_rx_rings(struct bnx2x *bp) 14008c2ecf20Sopenharmony_ci{ 14018c2ecf20Sopenharmony_ci int func = BP_FUNC(bp); 14028c2ecf20Sopenharmony_ci u16 ring_prod; 14038c2ecf20Sopenharmony_ci int i, j; 14048c2ecf20Sopenharmony_ci 14058c2ecf20Sopenharmony_ci /* Allocate TPA resources */ 14068c2ecf20Sopenharmony_ci for_each_eth_queue(bp, j) { 14078c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[j]; 14088c2ecf20Sopenharmony_ci 14098c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, 14108c2ecf20Sopenharmony_ci "mtu %d rx_buf_size %d\n", bp->dev->mtu, fp->rx_buf_size); 14118c2ecf20Sopenharmony_ci 14128c2ecf20Sopenharmony_ci if (fp->mode != TPA_MODE_DISABLED) { 14138c2ecf20Sopenharmony_ci /* Fill the per-aggregation pool */ 14148c2ecf20Sopenharmony_ci for (i = 0; i < MAX_AGG_QS(bp); i++) { 14158c2ecf20Sopenharmony_ci struct bnx2x_agg_info *tpa_info = 14168c2ecf20Sopenharmony_ci &fp->tpa_info[i]; 14178c2ecf20Sopenharmony_ci struct sw_rx_bd *first_buf = 14188c2ecf20Sopenharmony_ci &tpa_info->first_buf; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci first_buf->data = 14218c2ecf20Sopenharmony_ci bnx2x_frag_alloc(fp, GFP_KERNEL); 14228c2ecf20Sopenharmony_ci if (!first_buf->data) { 14238c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to allocate TPA skb pool for queue[%d] - disabling TPA on this queue!\n", 14248c2ecf20Sopenharmony_ci j); 14258c2ecf20Sopenharmony_ci bnx2x_free_tpa_pool(bp, fp, i); 14268c2ecf20Sopenharmony_ci fp->mode = TPA_MODE_DISABLED; 14278c2ecf20Sopenharmony_ci break; 14288c2ecf20Sopenharmony_ci } 14298c2ecf20Sopenharmony_ci dma_unmap_addr_set(first_buf, mapping, 0); 14308c2ecf20Sopenharmony_ci tpa_info->tpa_state = BNX2X_TPA_STOP; 14318c2ecf20Sopenharmony_ci } 14328c2ecf20Sopenharmony_ci 14338c2ecf20Sopenharmony_ci /* "next page" elements initialization */ 14348c2ecf20Sopenharmony_ci bnx2x_set_next_page_sgl(fp); 14358c2ecf20Sopenharmony_ci 14368c2ecf20Sopenharmony_ci /* set SGEs bit mask */ 14378c2ecf20Sopenharmony_ci bnx2x_init_sge_ring_bit_mask(fp); 14388c2ecf20Sopenharmony_ci 14398c2ecf20Sopenharmony_ci /* Allocate SGEs and initialize the ring elements */ 14408c2ecf20Sopenharmony_ci for (i = 0, ring_prod = 0; 14418c2ecf20Sopenharmony_ci i < MAX_RX_SGE_CNT*NUM_RX_SGE_PAGES; i++) { 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci if (bnx2x_alloc_rx_sge(bp, fp, ring_prod, 14448c2ecf20Sopenharmony_ci GFP_KERNEL) < 0) { 14458c2ecf20Sopenharmony_ci BNX2X_ERR("was only able to allocate %d rx sges\n", 14468c2ecf20Sopenharmony_ci i); 14478c2ecf20Sopenharmony_ci BNX2X_ERR("disabling TPA for queue[%d]\n", 14488c2ecf20Sopenharmony_ci j); 14498c2ecf20Sopenharmony_ci /* Cleanup already allocated elements */ 14508c2ecf20Sopenharmony_ci bnx2x_free_rx_sge_range(bp, fp, 14518c2ecf20Sopenharmony_ci ring_prod); 14528c2ecf20Sopenharmony_ci bnx2x_free_tpa_pool(bp, fp, 14538c2ecf20Sopenharmony_ci MAX_AGG_QS(bp)); 14548c2ecf20Sopenharmony_ci fp->mode = TPA_MODE_DISABLED; 14558c2ecf20Sopenharmony_ci ring_prod = 0; 14568c2ecf20Sopenharmony_ci break; 14578c2ecf20Sopenharmony_ci } 14588c2ecf20Sopenharmony_ci ring_prod = NEXT_SGE_IDX(ring_prod); 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci fp->rx_sge_prod = ring_prod; 14628c2ecf20Sopenharmony_ci } 14638c2ecf20Sopenharmony_ci } 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci for_each_eth_queue(bp, j) { 14668c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[j]; 14678c2ecf20Sopenharmony_ci 14688c2ecf20Sopenharmony_ci fp->rx_bd_cons = 0; 14698c2ecf20Sopenharmony_ci 14708c2ecf20Sopenharmony_ci /* Activate BD ring */ 14718c2ecf20Sopenharmony_ci /* Warning! 14728c2ecf20Sopenharmony_ci * this will generate an interrupt (to the TSTORM) 14738c2ecf20Sopenharmony_ci * must only be done after chip is initialized 14748c2ecf20Sopenharmony_ci */ 14758c2ecf20Sopenharmony_ci bnx2x_update_rx_prod(bp, fp, fp->rx_bd_prod, fp->rx_comp_prod, 14768c2ecf20Sopenharmony_ci fp->rx_sge_prod); 14778c2ecf20Sopenharmony_ci 14788c2ecf20Sopenharmony_ci if (j != 0) 14798c2ecf20Sopenharmony_ci continue; 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_ci if (CHIP_IS_E1(bp)) { 14828c2ecf20Sopenharmony_ci REG_WR(bp, BAR_USTRORM_INTMEM + 14838c2ecf20Sopenharmony_ci USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func), 14848c2ecf20Sopenharmony_ci U64_LO(fp->rx_comp_mapping)); 14858c2ecf20Sopenharmony_ci REG_WR(bp, BAR_USTRORM_INTMEM + 14868c2ecf20Sopenharmony_ci USTORM_MEM_WORKAROUND_ADDRESS_OFFSET(func) + 4, 14878c2ecf20Sopenharmony_ci U64_HI(fp->rx_comp_mapping)); 14888c2ecf20Sopenharmony_ci } 14898c2ecf20Sopenharmony_ci } 14908c2ecf20Sopenharmony_ci} 14918c2ecf20Sopenharmony_ci 14928c2ecf20Sopenharmony_cistatic void bnx2x_free_tx_skbs_queue(struct bnx2x_fastpath *fp) 14938c2ecf20Sopenharmony_ci{ 14948c2ecf20Sopenharmony_ci u8 cos; 14958c2ecf20Sopenharmony_ci struct bnx2x *bp = fp->bp; 14968c2ecf20Sopenharmony_ci 14978c2ecf20Sopenharmony_ci for_each_cos_in_tx_queue(fp, cos) { 14988c2ecf20Sopenharmony_ci struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos]; 14998c2ecf20Sopenharmony_ci unsigned pkts_compl = 0, bytes_compl = 0; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci u16 sw_prod = txdata->tx_pkt_prod; 15028c2ecf20Sopenharmony_ci u16 sw_cons = txdata->tx_pkt_cons; 15038c2ecf20Sopenharmony_ci 15048c2ecf20Sopenharmony_ci while (sw_cons != sw_prod) { 15058c2ecf20Sopenharmony_ci bnx2x_free_tx_pkt(bp, txdata, TX_BD(sw_cons), 15068c2ecf20Sopenharmony_ci &pkts_compl, &bytes_compl); 15078c2ecf20Sopenharmony_ci sw_cons++; 15088c2ecf20Sopenharmony_ci } 15098c2ecf20Sopenharmony_ci 15108c2ecf20Sopenharmony_ci netdev_tx_reset_queue( 15118c2ecf20Sopenharmony_ci netdev_get_tx_queue(bp->dev, 15128c2ecf20Sopenharmony_ci txdata->txq_index)); 15138c2ecf20Sopenharmony_ci } 15148c2ecf20Sopenharmony_ci} 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_cistatic void bnx2x_free_tx_skbs_cnic(struct bnx2x *bp) 15178c2ecf20Sopenharmony_ci{ 15188c2ecf20Sopenharmony_ci int i; 15198c2ecf20Sopenharmony_ci 15208c2ecf20Sopenharmony_ci for_each_tx_queue_cnic(bp, i) { 15218c2ecf20Sopenharmony_ci bnx2x_free_tx_skbs_queue(&bp->fp[i]); 15228c2ecf20Sopenharmony_ci } 15238c2ecf20Sopenharmony_ci} 15248c2ecf20Sopenharmony_ci 15258c2ecf20Sopenharmony_cistatic void bnx2x_free_tx_skbs(struct bnx2x *bp) 15268c2ecf20Sopenharmony_ci{ 15278c2ecf20Sopenharmony_ci int i; 15288c2ecf20Sopenharmony_ci 15298c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) { 15308c2ecf20Sopenharmony_ci bnx2x_free_tx_skbs_queue(&bp->fp[i]); 15318c2ecf20Sopenharmony_ci } 15328c2ecf20Sopenharmony_ci} 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_cistatic void bnx2x_free_rx_bds(struct bnx2x_fastpath *fp) 15358c2ecf20Sopenharmony_ci{ 15368c2ecf20Sopenharmony_ci struct bnx2x *bp = fp->bp; 15378c2ecf20Sopenharmony_ci int i; 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci /* ring wasn't allocated */ 15408c2ecf20Sopenharmony_ci if (fp->rx_buf_ring == NULL) 15418c2ecf20Sopenharmony_ci return; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci for (i = 0; i < NUM_RX_BD; i++) { 15448c2ecf20Sopenharmony_ci struct sw_rx_bd *rx_buf = &fp->rx_buf_ring[i]; 15458c2ecf20Sopenharmony_ci u8 *data = rx_buf->data; 15468c2ecf20Sopenharmony_ci 15478c2ecf20Sopenharmony_ci if (data == NULL) 15488c2ecf20Sopenharmony_ci continue; 15498c2ecf20Sopenharmony_ci dma_unmap_single(&bp->pdev->dev, 15508c2ecf20Sopenharmony_ci dma_unmap_addr(rx_buf, mapping), 15518c2ecf20Sopenharmony_ci fp->rx_buf_size, DMA_FROM_DEVICE); 15528c2ecf20Sopenharmony_ci 15538c2ecf20Sopenharmony_ci rx_buf->data = NULL; 15548c2ecf20Sopenharmony_ci bnx2x_frag_free(fp, data); 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci} 15578c2ecf20Sopenharmony_ci 15588c2ecf20Sopenharmony_cistatic void bnx2x_free_rx_skbs_cnic(struct bnx2x *bp) 15598c2ecf20Sopenharmony_ci{ 15608c2ecf20Sopenharmony_ci int j; 15618c2ecf20Sopenharmony_ci 15628c2ecf20Sopenharmony_ci for_each_rx_queue_cnic(bp, j) { 15638c2ecf20Sopenharmony_ci bnx2x_free_rx_bds(&bp->fp[j]); 15648c2ecf20Sopenharmony_ci } 15658c2ecf20Sopenharmony_ci} 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_cistatic void bnx2x_free_rx_skbs(struct bnx2x *bp) 15688c2ecf20Sopenharmony_ci{ 15698c2ecf20Sopenharmony_ci int j; 15708c2ecf20Sopenharmony_ci 15718c2ecf20Sopenharmony_ci for_each_eth_queue(bp, j) { 15728c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[j]; 15738c2ecf20Sopenharmony_ci 15748c2ecf20Sopenharmony_ci bnx2x_free_rx_bds(fp); 15758c2ecf20Sopenharmony_ci 15768c2ecf20Sopenharmony_ci if (fp->mode != TPA_MODE_DISABLED) 15778c2ecf20Sopenharmony_ci bnx2x_free_tpa_pool(bp, fp, MAX_AGG_QS(bp)); 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_cistatic void bnx2x_free_skbs_cnic(struct bnx2x *bp) 15828c2ecf20Sopenharmony_ci{ 15838c2ecf20Sopenharmony_ci bnx2x_free_tx_skbs_cnic(bp); 15848c2ecf20Sopenharmony_ci bnx2x_free_rx_skbs_cnic(bp); 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_civoid bnx2x_free_skbs(struct bnx2x *bp) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci bnx2x_free_tx_skbs(bp); 15908c2ecf20Sopenharmony_ci bnx2x_free_rx_skbs(bp); 15918c2ecf20Sopenharmony_ci} 15928c2ecf20Sopenharmony_ci 15938c2ecf20Sopenharmony_civoid bnx2x_update_max_mf_config(struct bnx2x *bp, u32 value) 15948c2ecf20Sopenharmony_ci{ 15958c2ecf20Sopenharmony_ci /* load old values */ 15968c2ecf20Sopenharmony_ci u32 mf_cfg = bp->mf_config[BP_VN(bp)]; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci if (value != bnx2x_extract_max_cfg(bp, mf_cfg)) { 15998c2ecf20Sopenharmony_ci /* leave all but MAX value */ 16008c2ecf20Sopenharmony_ci mf_cfg &= ~FUNC_MF_CFG_MAX_BW_MASK; 16018c2ecf20Sopenharmony_ci 16028c2ecf20Sopenharmony_ci /* set new MAX value */ 16038c2ecf20Sopenharmony_ci mf_cfg |= (value << FUNC_MF_CFG_MAX_BW_SHIFT) 16048c2ecf20Sopenharmony_ci & FUNC_MF_CFG_MAX_BW_MASK; 16058c2ecf20Sopenharmony_ci 16068c2ecf20Sopenharmony_ci bnx2x_fw_command(bp, DRV_MSG_CODE_SET_MF_BW, mf_cfg); 16078c2ecf20Sopenharmony_ci } 16088c2ecf20Sopenharmony_ci} 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci/** 16118c2ecf20Sopenharmony_ci * bnx2x_free_msix_irqs - free previously requested MSI-X IRQ vectors 16128c2ecf20Sopenharmony_ci * 16138c2ecf20Sopenharmony_ci * @bp: driver handle 16148c2ecf20Sopenharmony_ci * @nvecs: number of vectors to be released 16158c2ecf20Sopenharmony_ci */ 16168c2ecf20Sopenharmony_cistatic void bnx2x_free_msix_irqs(struct bnx2x *bp, int nvecs) 16178c2ecf20Sopenharmony_ci{ 16188c2ecf20Sopenharmony_ci int i, offset = 0; 16198c2ecf20Sopenharmony_ci 16208c2ecf20Sopenharmony_ci if (nvecs == offset) 16218c2ecf20Sopenharmony_ci return; 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci /* VFs don't have a default SB */ 16248c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 16258c2ecf20Sopenharmony_ci free_irq(bp->msix_table[offset].vector, bp->dev); 16268c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n", 16278c2ecf20Sopenharmony_ci bp->msix_table[offset].vector); 16288c2ecf20Sopenharmony_ci offset++; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci 16318c2ecf20Sopenharmony_ci if (CNIC_SUPPORT(bp)) { 16328c2ecf20Sopenharmony_ci if (nvecs == offset) 16338c2ecf20Sopenharmony_ci return; 16348c2ecf20Sopenharmony_ci offset++; 16358c2ecf20Sopenharmony_ci } 16368c2ecf20Sopenharmony_ci 16378c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) { 16388c2ecf20Sopenharmony_ci if (nvecs == offset) 16398c2ecf20Sopenharmony_ci return; 16408c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq\n", 16418c2ecf20Sopenharmony_ci i, bp->msix_table[offset].vector); 16428c2ecf20Sopenharmony_ci 16438c2ecf20Sopenharmony_ci free_irq(bp->msix_table[offset++].vector, &bp->fp[i]); 16448c2ecf20Sopenharmony_ci } 16458c2ecf20Sopenharmony_ci} 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_civoid bnx2x_free_irq(struct bnx2x *bp) 16488c2ecf20Sopenharmony_ci{ 16498c2ecf20Sopenharmony_ci if (bp->flags & USING_MSIX_FLAG && 16508c2ecf20Sopenharmony_ci !(bp->flags & USING_SINGLE_MSIX_FLAG)) { 16518c2ecf20Sopenharmony_ci int nvecs = BNX2X_NUM_ETH_QUEUES(bp) + CNIC_SUPPORT(bp); 16528c2ecf20Sopenharmony_ci 16538c2ecf20Sopenharmony_ci /* vfs don't have a default status block */ 16548c2ecf20Sopenharmony_ci if (IS_PF(bp)) 16558c2ecf20Sopenharmony_ci nvecs++; 16568c2ecf20Sopenharmony_ci 16578c2ecf20Sopenharmony_ci bnx2x_free_msix_irqs(bp, nvecs); 16588c2ecf20Sopenharmony_ci } else { 16598c2ecf20Sopenharmony_ci free_irq(bp->dev->irq, bp->dev); 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci} 16628c2ecf20Sopenharmony_ci 16638c2ecf20Sopenharmony_ciint bnx2x_enable_msix(struct bnx2x *bp) 16648c2ecf20Sopenharmony_ci{ 16658c2ecf20Sopenharmony_ci int msix_vec = 0, i, rc; 16668c2ecf20Sopenharmony_ci 16678c2ecf20Sopenharmony_ci /* VFs don't have a default status block */ 16688c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 16698c2ecf20Sopenharmony_ci bp->msix_table[msix_vec].entry = msix_vec; 16708c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("msix_table[0].entry = %d (slowpath)\n", 16718c2ecf20Sopenharmony_ci bp->msix_table[0].entry); 16728c2ecf20Sopenharmony_ci msix_vec++; 16738c2ecf20Sopenharmony_ci } 16748c2ecf20Sopenharmony_ci 16758c2ecf20Sopenharmony_ci /* Cnic requires an msix vector for itself */ 16768c2ecf20Sopenharmony_ci if (CNIC_SUPPORT(bp)) { 16778c2ecf20Sopenharmony_ci bp->msix_table[msix_vec].entry = msix_vec; 16788c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("msix_table[%d].entry = %d (CNIC)\n", 16798c2ecf20Sopenharmony_ci msix_vec, bp->msix_table[msix_vec].entry); 16808c2ecf20Sopenharmony_ci msix_vec++; 16818c2ecf20Sopenharmony_ci } 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci /* We need separate vectors for ETH queues only (not FCoE) */ 16848c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) { 16858c2ecf20Sopenharmony_ci bp->msix_table[msix_vec].entry = msix_vec; 16868c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("msix_table[%d].entry = %d (fastpath #%u)\n", 16878c2ecf20Sopenharmony_ci msix_vec, msix_vec, i); 16888c2ecf20Sopenharmony_ci msix_vec++; 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "about to request enable msix with %d vectors\n", 16928c2ecf20Sopenharmony_ci msix_vec); 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0], 16958c2ecf20Sopenharmony_ci BNX2X_MIN_MSIX_VEC_CNT(bp), msix_vec); 16968c2ecf20Sopenharmony_ci /* 16978c2ecf20Sopenharmony_ci * reconfigure number of tx/rx queues according to available 16988c2ecf20Sopenharmony_ci * MSI-X vectors 16998c2ecf20Sopenharmony_ci */ 17008c2ecf20Sopenharmony_ci if (rc == -ENOSPC) { 17018c2ecf20Sopenharmony_ci /* Get by with single vector */ 17028c2ecf20Sopenharmony_ci rc = pci_enable_msix_range(bp->pdev, &bp->msix_table[0], 1, 1); 17038c2ecf20Sopenharmony_ci if (rc < 0) { 17048c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("Single MSI-X is not attainable rc %d\n", 17058c2ecf20Sopenharmony_ci rc); 17068c2ecf20Sopenharmony_ci goto no_msix; 17078c2ecf20Sopenharmony_ci } 17088c2ecf20Sopenharmony_ci 17098c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("Using single MSI-X vector\n"); 17108c2ecf20Sopenharmony_ci bp->flags |= USING_SINGLE_MSIX_FLAG; 17118c2ecf20Sopenharmony_ci 17128c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("set number of queues to 1\n"); 17138c2ecf20Sopenharmony_ci bp->num_ethernet_queues = 1; 17148c2ecf20Sopenharmony_ci bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues; 17158c2ecf20Sopenharmony_ci } else if (rc < 0) { 17168c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("MSI-X is not attainable rc %d\n", rc); 17178c2ecf20Sopenharmony_ci goto no_msix; 17188c2ecf20Sopenharmony_ci } else if (rc < msix_vec) { 17198c2ecf20Sopenharmony_ci /* how less vectors we will have? */ 17208c2ecf20Sopenharmony_ci int diff = msix_vec - rc; 17218c2ecf20Sopenharmony_ci 17228c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("Trying to use less MSI-X vectors: %d\n", rc); 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci /* 17258c2ecf20Sopenharmony_ci * decrease number of queues by number of unallocated entries 17268c2ecf20Sopenharmony_ci */ 17278c2ecf20Sopenharmony_ci bp->num_ethernet_queues -= diff; 17288c2ecf20Sopenharmony_ci bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues; 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("New queue configuration set: %d\n", 17318c2ecf20Sopenharmony_ci bp->num_queues); 17328c2ecf20Sopenharmony_ci } 17338c2ecf20Sopenharmony_ci 17348c2ecf20Sopenharmony_ci bp->flags |= USING_MSIX_FLAG; 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_ci return 0; 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_cino_msix: 17398c2ecf20Sopenharmony_ci /* fall to INTx if not enough memory */ 17408c2ecf20Sopenharmony_ci if (rc == -ENOMEM) 17418c2ecf20Sopenharmony_ci bp->flags |= DISABLE_MSI_FLAG; 17428c2ecf20Sopenharmony_ci 17438c2ecf20Sopenharmony_ci return rc; 17448c2ecf20Sopenharmony_ci} 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_cistatic int bnx2x_req_msix_irqs(struct bnx2x *bp) 17478c2ecf20Sopenharmony_ci{ 17488c2ecf20Sopenharmony_ci int i, rc, offset = 0; 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_ci /* no default status block for vf */ 17518c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 17528c2ecf20Sopenharmony_ci rc = request_irq(bp->msix_table[offset++].vector, 17538c2ecf20Sopenharmony_ci bnx2x_msix_sp_int, 0, 17548c2ecf20Sopenharmony_ci bp->dev->name, bp->dev); 17558c2ecf20Sopenharmony_ci if (rc) { 17568c2ecf20Sopenharmony_ci BNX2X_ERR("request sp irq failed\n"); 17578c2ecf20Sopenharmony_ci return -EBUSY; 17588c2ecf20Sopenharmony_ci } 17598c2ecf20Sopenharmony_ci } 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci if (CNIC_SUPPORT(bp)) 17628c2ecf20Sopenharmony_ci offset++; 17638c2ecf20Sopenharmony_ci 17648c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) { 17658c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[i]; 17668c2ecf20Sopenharmony_ci snprintf(fp->name, sizeof(fp->name), "%s-fp-%d", 17678c2ecf20Sopenharmony_ci bp->dev->name, i); 17688c2ecf20Sopenharmony_ci 17698c2ecf20Sopenharmony_ci rc = request_irq(bp->msix_table[offset].vector, 17708c2ecf20Sopenharmony_ci bnx2x_msix_fp_int, 0, fp->name, fp); 17718c2ecf20Sopenharmony_ci if (rc) { 17728c2ecf20Sopenharmony_ci BNX2X_ERR("request fp #%d irq (%d) failed rc %d\n", i, 17738c2ecf20Sopenharmony_ci bp->msix_table[offset].vector, rc); 17748c2ecf20Sopenharmony_ci bnx2x_free_msix_irqs(bp, offset); 17758c2ecf20Sopenharmony_ci return -EBUSY; 17768c2ecf20Sopenharmony_ci } 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci offset++; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci 17818c2ecf20Sopenharmony_ci i = BNX2X_NUM_ETH_QUEUES(bp); 17828c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 17838c2ecf20Sopenharmony_ci offset = 1 + CNIC_SUPPORT(bp); 17848c2ecf20Sopenharmony_ci netdev_info(bp->dev, 17858c2ecf20Sopenharmony_ci "using MSI-X IRQs: sp %d fp[%d] %d ... fp[%d] %d\n", 17868c2ecf20Sopenharmony_ci bp->msix_table[0].vector, 17878c2ecf20Sopenharmony_ci 0, bp->msix_table[offset].vector, 17888c2ecf20Sopenharmony_ci i - 1, bp->msix_table[offset + i - 1].vector); 17898c2ecf20Sopenharmony_ci } else { 17908c2ecf20Sopenharmony_ci offset = CNIC_SUPPORT(bp); 17918c2ecf20Sopenharmony_ci netdev_info(bp->dev, 17928c2ecf20Sopenharmony_ci "using MSI-X IRQs: fp[%d] %d ... fp[%d] %d\n", 17938c2ecf20Sopenharmony_ci 0, bp->msix_table[offset].vector, 17948c2ecf20Sopenharmony_ci i - 1, bp->msix_table[offset + i - 1].vector); 17958c2ecf20Sopenharmony_ci } 17968c2ecf20Sopenharmony_ci return 0; 17978c2ecf20Sopenharmony_ci} 17988c2ecf20Sopenharmony_ci 17998c2ecf20Sopenharmony_ciint bnx2x_enable_msi(struct bnx2x *bp) 18008c2ecf20Sopenharmony_ci{ 18018c2ecf20Sopenharmony_ci int rc; 18028c2ecf20Sopenharmony_ci 18038c2ecf20Sopenharmony_ci rc = pci_enable_msi(bp->pdev); 18048c2ecf20Sopenharmony_ci if (rc) { 18058c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("MSI is not attainable\n"); 18068c2ecf20Sopenharmony_ci return -1; 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ci bp->flags |= USING_MSI_FLAG; 18098c2ecf20Sopenharmony_ci 18108c2ecf20Sopenharmony_ci return 0; 18118c2ecf20Sopenharmony_ci} 18128c2ecf20Sopenharmony_ci 18138c2ecf20Sopenharmony_cistatic int bnx2x_req_irq(struct bnx2x *bp) 18148c2ecf20Sopenharmony_ci{ 18158c2ecf20Sopenharmony_ci unsigned long flags; 18168c2ecf20Sopenharmony_ci unsigned int irq; 18178c2ecf20Sopenharmony_ci 18188c2ecf20Sopenharmony_ci if (bp->flags & (USING_MSI_FLAG | USING_MSIX_FLAG)) 18198c2ecf20Sopenharmony_ci flags = 0; 18208c2ecf20Sopenharmony_ci else 18218c2ecf20Sopenharmony_ci flags = IRQF_SHARED; 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci if (bp->flags & USING_MSIX_FLAG) 18248c2ecf20Sopenharmony_ci irq = bp->msix_table[0].vector; 18258c2ecf20Sopenharmony_ci else 18268c2ecf20Sopenharmony_ci irq = bp->pdev->irq; 18278c2ecf20Sopenharmony_ci 18288c2ecf20Sopenharmony_ci return request_irq(irq, bnx2x_interrupt, flags, bp->dev->name, bp->dev); 18298c2ecf20Sopenharmony_ci} 18308c2ecf20Sopenharmony_ci 18318c2ecf20Sopenharmony_cistatic int bnx2x_setup_irqs(struct bnx2x *bp) 18328c2ecf20Sopenharmony_ci{ 18338c2ecf20Sopenharmony_ci int rc = 0; 18348c2ecf20Sopenharmony_ci if (bp->flags & USING_MSIX_FLAG && 18358c2ecf20Sopenharmony_ci !(bp->flags & USING_SINGLE_MSIX_FLAG)) { 18368c2ecf20Sopenharmony_ci rc = bnx2x_req_msix_irqs(bp); 18378c2ecf20Sopenharmony_ci if (rc) 18388c2ecf20Sopenharmony_ci return rc; 18398c2ecf20Sopenharmony_ci } else { 18408c2ecf20Sopenharmony_ci rc = bnx2x_req_irq(bp); 18418c2ecf20Sopenharmony_ci if (rc) { 18428c2ecf20Sopenharmony_ci BNX2X_ERR("IRQ request failed rc %d, aborting\n", rc); 18438c2ecf20Sopenharmony_ci return rc; 18448c2ecf20Sopenharmony_ci } 18458c2ecf20Sopenharmony_ci if (bp->flags & USING_MSI_FLAG) { 18468c2ecf20Sopenharmony_ci bp->dev->irq = bp->pdev->irq; 18478c2ecf20Sopenharmony_ci netdev_info(bp->dev, "using MSI IRQ %d\n", 18488c2ecf20Sopenharmony_ci bp->dev->irq); 18498c2ecf20Sopenharmony_ci } 18508c2ecf20Sopenharmony_ci if (bp->flags & USING_MSIX_FLAG) { 18518c2ecf20Sopenharmony_ci bp->dev->irq = bp->msix_table[0].vector; 18528c2ecf20Sopenharmony_ci netdev_info(bp->dev, "using MSIX IRQ %d\n", 18538c2ecf20Sopenharmony_ci bp->dev->irq); 18548c2ecf20Sopenharmony_ci } 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci return 0; 18588c2ecf20Sopenharmony_ci} 18598c2ecf20Sopenharmony_ci 18608c2ecf20Sopenharmony_cistatic void bnx2x_napi_enable_cnic(struct bnx2x *bp) 18618c2ecf20Sopenharmony_ci{ 18628c2ecf20Sopenharmony_ci int i; 18638c2ecf20Sopenharmony_ci 18648c2ecf20Sopenharmony_ci for_each_rx_queue_cnic(bp, i) { 18658c2ecf20Sopenharmony_ci napi_enable(&bnx2x_fp(bp, i, napi)); 18668c2ecf20Sopenharmony_ci } 18678c2ecf20Sopenharmony_ci} 18688c2ecf20Sopenharmony_ci 18698c2ecf20Sopenharmony_cistatic void bnx2x_napi_enable(struct bnx2x *bp) 18708c2ecf20Sopenharmony_ci{ 18718c2ecf20Sopenharmony_ci int i; 18728c2ecf20Sopenharmony_ci 18738c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) { 18748c2ecf20Sopenharmony_ci napi_enable(&bnx2x_fp(bp, i, napi)); 18758c2ecf20Sopenharmony_ci } 18768c2ecf20Sopenharmony_ci} 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_cistatic void bnx2x_napi_disable_cnic(struct bnx2x *bp) 18798c2ecf20Sopenharmony_ci{ 18808c2ecf20Sopenharmony_ci int i; 18818c2ecf20Sopenharmony_ci 18828c2ecf20Sopenharmony_ci for_each_rx_queue_cnic(bp, i) { 18838c2ecf20Sopenharmony_ci napi_disable(&bnx2x_fp(bp, i, napi)); 18848c2ecf20Sopenharmony_ci } 18858c2ecf20Sopenharmony_ci} 18868c2ecf20Sopenharmony_ci 18878c2ecf20Sopenharmony_cistatic void bnx2x_napi_disable(struct bnx2x *bp) 18888c2ecf20Sopenharmony_ci{ 18898c2ecf20Sopenharmony_ci int i; 18908c2ecf20Sopenharmony_ci 18918c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) { 18928c2ecf20Sopenharmony_ci napi_disable(&bnx2x_fp(bp, i, napi)); 18938c2ecf20Sopenharmony_ci } 18948c2ecf20Sopenharmony_ci} 18958c2ecf20Sopenharmony_ci 18968c2ecf20Sopenharmony_civoid bnx2x_netif_start(struct bnx2x *bp) 18978c2ecf20Sopenharmony_ci{ 18988c2ecf20Sopenharmony_ci if (netif_running(bp->dev)) { 18998c2ecf20Sopenharmony_ci bnx2x_napi_enable(bp); 19008c2ecf20Sopenharmony_ci if (CNIC_LOADED(bp)) 19018c2ecf20Sopenharmony_ci bnx2x_napi_enable_cnic(bp); 19028c2ecf20Sopenharmony_ci bnx2x_int_enable(bp); 19038c2ecf20Sopenharmony_ci if (bp->state == BNX2X_STATE_OPEN) 19048c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(bp->dev); 19058c2ecf20Sopenharmony_ci } 19068c2ecf20Sopenharmony_ci} 19078c2ecf20Sopenharmony_ci 19088c2ecf20Sopenharmony_civoid bnx2x_netif_stop(struct bnx2x *bp, int disable_hw) 19098c2ecf20Sopenharmony_ci{ 19108c2ecf20Sopenharmony_ci bnx2x_int_disable_sync(bp, disable_hw); 19118c2ecf20Sopenharmony_ci bnx2x_napi_disable(bp); 19128c2ecf20Sopenharmony_ci if (CNIC_LOADED(bp)) 19138c2ecf20Sopenharmony_ci bnx2x_napi_disable_cnic(bp); 19148c2ecf20Sopenharmony_ci} 19158c2ecf20Sopenharmony_ci 19168c2ecf20Sopenharmony_ciu16 bnx2x_select_queue(struct net_device *dev, struct sk_buff *skb, 19178c2ecf20Sopenharmony_ci struct net_device *sb_dev) 19188c2ecf20Sopenharmony_ci{ 19198c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_ci if (CNIC_LOADED(bp) && !NO_FCOE(bp)) { 19228c2ecf20Sopenharmony_ci struct ethhdr *hdr = (struct ethhdr *)skb->data; 19238c2ecf20Sopenharmony_ci u16 ether_type = ntohs(hdr->h_proto); 19248c2ecf20Sopenharmony_ci 19258c2ecf20Sopenharmony_ci /* Skip VLAN tag if present */ 19268c2ecf20Sopenharmony_ci if (ether_type == ETH_P_8021Q) { 19278c2ecf20Sopenharmony_ci struct vlan_ethhdr *vhdr = skb_vlan_eth_hdr(skb); 19288c2ecf20Sopenharmony_ci 19298c2ecf20Sopenharmony_ci ether_type = ntohs(vhdr->h_vlan_encapsulated_proto); 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci /* If ethertype is FCoE or FIP - use FCoE ring */ 19338c2ecf20Sopenharmony_ci if ((ether_type == ETH_P_FCOE) || (ether_type == ETH_P_FIP)) 19348c2ecf20Sopenharmony_ci return bnx2x_fcoe_tx(bp, txq_index); 19358c2ecf20Sopenharmony_ci } 19368c2ecf20Sopenharmony_ci 19378c2ecf20Sopenharmony_ci /* select a non-FCoE queue */ 19388c2ecf20Sopenharmony_ci return netdev_pick_tx(dev, skb, NULL) % 19398c2ecf20Sopenharmony_ci (BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos); 19408c2ecf20Sopenharmony_ci} 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_civoid bnx2x_set_num_queues(struct bnx2x *bp) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci /* RSS queues */ 19458c2ecf20Sopenharmony_ci bp->num_ethernet_queues = bnx2x_calc_num_queues(bp); 19468c2ecf20Sopenharmony_ci 19478c2ecf20Sopenharmony_ci /* override in STORAGE SD modes */ 19488c2ecf20Sopenharmony_ci if (IS_MF_STORAGE_ONLY(bp)) 19498c2ecf20Sopenharmony_ci bp->num_ethernet_queues = 1; 19508c2ecf20Sopenharmony_ci 19518c2ecf20Sopenharmony_ci /* Add special queues */ 19528c2ecf20Sopenharmony_ci bp->num_cnic_queues = CNIC_SUPPORT(bp); /* For FCOE */ 19538c2ecf20Sopenharmony_ci bp->num_queues = bp->num_ethernet_queues + bp->num_cnic_queues; 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("set number of queues to %d\n", bp->num_queues); 19568c2ecf20Sopenharmony_ci} 19578c2ecf20Sopenharmony_ci 19588c2ecf20Sopenharmony_ci/** 19598c2ecf20Sopenharmony_ci * bnx2x_set_real_num_queues - configure netdev->real_num_[tx,rx]_queues 19608c2ecf20Sopenharmony_ci * 19618c2ecf20Sopenharmony_ci * @bp: Driver handle 19628c2ecf20Sopenharmony_ci * @include_cnic: handle cnic case 19638c2ecf20Sopenharmony_ci * 19648c2ecf20Sopenharmony_ci * We currently support for at most 16 Tx queues for each CoS thus we will 19658c2ecf20Sopenharmony_ci * allocate a multiple of 16 for ETH L2 rings according to the value of the 19668c2ecf20Sopenharmony_ci * bp->max_cos. 19678c2ecf20Sopenharmony_ci * 19688c2ecf20Sopenharmony_ci * If there is an FCoE L2 queue the appropriate Tx queue will have the next 19698c2ecf20Sopenharmony_ci * index after all ETH L2 indices. 19708c2ecf20Sopenharmony_ci * 19718c2ecf20Sopenharmony_ci * If the actual number of Tx queues (for each CoS) is less than 16 then there 19728c2ecf20Sopenharmony_ci * will be the holes at the end of each group of 16 ETh L2 indices (0..15, 19738c2ecf20Sopenharmony_ci * 16..31,...) with indices that are not coupled with any real Tx queue. 19748c2ecf20Sopenharmony_ci * 19758c2ecf20Sopenharmony_ci * The proper configuration of skb->queue_mapping is handled by 19768c2ecf20Sopenharmony_ci * bnx2x_select_queue() and __skb_tx_hash(). 19778c2ecf20Sopenharmony_ci * 19788c2ecf20Sopenharmony_ci * bnx2x_setup_tc() takes care of the proper TC mappings so that __skb_tx_hash() 19798c2ecf20Sopenharmony_ci * will return a proper Tx index if TC is enabled (netdev->num_tc > 0). 19808c2ecf20Sopenharmony_ci */ 19818c2ecf20Sopenharmony_cistatic int bnx2x_set_real_num_queues(struct bnx2x *bp, int include_cnic) 19828c2ecf20Sopenharmony_ci{ 19838c2ecf20Sopenharmony_ci int rc, tx, rx; 19848c2ecf20Sopenharmony_ci 19858c2ecf20Sopenharmony_ci tx = BNX2X_NUM_ETH_QUEUES(bp) * bp->max_cos; 19868c2ecf20Sopenharmony_ci rx = BNX2X_NUM_ETH_QUEUES(bp); 19878c2ecf20Sopenharmony_ci 19888c2ecf20Sopenharmony_ci/* account for fcoe queue */ 19898c2ecf20Sopenharmony_ci if (include_cnic && !NO_FCOE(bp)) { 19908c2ecf20Sopenharmony_ci rx++; 19918c2ecf20Sopenharmony_ci tx++; 19928c2ecf20Sopenharmony_ci } 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci rc = netif_set_real_num_tx_queues(bp->dev, tx); 19958c2ecf20Sopenharmony_ci if (rc) { 19968c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to set real number of Tx queues: %d\n", rc); 19978c2ecf20Sopenharmony_ci return rc; 19988c2ecf20Sopenharmony_ci } 19998c2ecf20Sopenharmony_ci rc = netif_set_real_num_rx_queues(bp->dev, rx); 20008c2ecf20Sopenharmony_ci if (rc) { 20018c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to set real number of Rx queues: %d\n", rc); 20028c2ecf20Sopenharmony_ci return rc; 20038c2ecf20Sopenharmony_ci } 20048c2ecf20Sopenharmony_ci 20058c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "Setting real num queues to (tx, rx) (%d, %d)\n", 20068c2ecf20Sopenharmony_ci tx, rx); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci return rc; 20098c2ecf20Sopenharmony_ci} 20108c2ecf20Sopenharmony_ci 20118c2ecf20Sopenharmony_cistatic void bnx2x_set_rx_buf_size(struct bnx2x *bp) 20128c2ecf20Sopenharmony_ci{ 20138c2ecf20Sopenharmony_ci int i; 20148c2ecf20Sopenharmony_ci 20158c2ecf20Sopenharmony_ci for_each_queue(bp, i) { 20168c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[i]; 20178c2ecf20Sopenharmony_ci u32 mtu; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci /* Always use a mini-jumbo MTU for the FCoE L2 ring */ 20208c2ecf20Sopenharmony_ci if (IS_FCOE_IDX(i)) 20218c2ecf20Sopenharmony_ci /* 20228c2ecf20Sopenharmony_ci * Although there are no IP frames expected to arrive to 20238c2ecf20Sopenharmony_ci * this ring we still want to add an 20248c2ecf20Sopenharmony_ci * IP_HEADER_ALIGNMENT_PADDING to prevent a buffer 20258c2ecf20Sopenharmony_ci * overrun attack. 20268c2ecf20Sopenharmony_ci */ 20278c2ecf20Sopenharmony_ci mtu = BNX2X_FCOE_MINI_JUMBO_MTU; 20288c2ecf20Sopenharmony_ci else 20298c2ecf20Sopenharmony_ci mtu = bp->dev->mtu; 20308c2ecf20Sopenharmony_ci fp->rx_buf_size = BNX2X_FW_RX_ALIGN_START + 20318c2ecf20Sopenharmony_ci IP_HEADER_ALIGNMENT_PADDING + 20328c2ecf20Sopenharmony_ci ETH_OVERHEAD + 20338c2ecf20Sopenharmony_ci mtu + 20348c2ecf20Sopenharmony_ci BNX2X_FW_RX_ALIGN_END; 20358c2ecf20Sopenharmony_ci fp->rx_buf_size = SKB_DATA_ALIGN(fp->rx_buf_size); 20368c2ecf20Sopenharmony_ci /* Note : rx_buf_size doesn't take into account NET_SKB_PAD */ 20378c2ecf20Sopenharmony_ci if (fp->rx_buf_size + NET_SKB_PAD <= PAGE_SIZE) 20388c2ecf20Sopenharmony_ci fp->rx_frag_size = fp->rx_buf_size + NET_SKB_PAD; 20398c2ecf20Sopenharmony_ci else 20408c2ecf20Sopenharmony_ci fp->rx_frag_size = 0; 20418c2ecf20Sopenharmony_ci } 20428c2ecf20Sopenharmony_ci} 20438c2ecf20Sopenharmony_ci 20448c2ecf20Sopenharmony_cistatic int bnx2x_init_rss(struct bnx2x *bp) 20458c2ecf20Sopenharmony_ci{ 20468c2ecf20Sopenharmony_ci int i; 20478c2ecf20Sopenharmony_ci u8 num_eth_queues = BNX2X_NUM_ETH_QUEUES(bp); 20488c2ecf20Sopenharmony_ci 20498c2ecf20Sopenharmony_ci /* Prepare the initial contents for the indirection table if RSS is 20508c2ecf20Sopenharmony_ci * enabled 20518c2ecf20Sopenharmony_ci */ 20528c2ecf20Sopenharmony_ci for (i = 0; i < sizeof(bp->rss_conf_obj.ind_table); i++) 20538c2ecf20Sopenharmony_ci bp->rss_conf_obj.ind_table[i] = 20548c2ecf20Sopenharmony_ci bp->fp->cl_id + 20558c2ecf20Sopenharmony_ci ethtool_rxfh_indir_default(i, num_eth_queues); 20568c2ecf20Sopenharmony_ci 20578c2ecf20Sopenharmony_ci /* 20588c2ecf20Sopenharmony_ci * For 57710 and 57711 SEARCHER configuration (rss_keys) is 20598c2ecf20Sopenharmony_ci * per-port, so if explicit configuration is needed , do it only 20608c2ecf20Sopenharmony_ci * for a PMF. 20618c2ecf20Sopenharmony_ci * 20628c2ecf20Sopenharmony_ci * For 57712 and newer on the other hand it's a per-function 20638c2ecf20Sopenharmony_ci * configuration. 20648c2ecf20Sopenharmony_ci */ 20658c2ecf20Sopenharmony_ci return bnx2x_config_rss_eth(bp, bp->port.pmf || !CHIP_IS_E1x(bp)); 20668c2ecf20Sopenharmony_ci} 20678c2ecf20Sopenharmony_ci 20688c2ecf20Sopenharmony_ciint bnx2x_rss(struct bnx2x *bp, struct bnx2x_rss_config_obj *rss_obj, 20698c2ecf20Sopenharmony_ci bool config_hash, bool enable) 20708c2ecf20Sopenharmony_ci{ 20718c2ecf20Sopenharmony_ci struct bnx2x_config_rss_params params = {NULL}; 20728c2ecf20Sopenharmony_ci 20738c2ecf20Sopenharmony_ci /* Although RSS is meaningless when there is a single HW queue we 20748c2ecf20Sopenharmony_ci * still need it enabled in order to have HW Rx hash generated. 20758c2ecf20Sopenharmony_ci * 20768c2ecf20Sopenharmony_ci * if (!is_eth_multi(bp)) 20778c2ecf20Sopenharmony_ci * bp->multi_mode = ETH_RSS_MODE_DISABLED; 20788c2ecf20Sopenharmony_ci */ 20798c2ecf20Sopenharmony_ci 20808c2ecf20Sopenharmony_ci params.rss_obj = rss_obj; 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci __set_bit(RAMROD_COMP_WAIT, ¶ms.ramrod_flags); 20838c2ecf20Sopenharmony_ci 20848c2ecf20Sopenharmony_ci if (enable) { 20858c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_MODE_REGULAR, ¶ms.rss_flags); 20868c2ecf20Sopenharmony_ci 20878c2ecf20Sopenharmony_ci /* RSS configuration */ 20888c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_IPV4, ¶ms.rss_flags); 20898c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_IPV4_TCP, ¶ms.rss_flags); 20908c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_IPV6, ¶ms.rss_flags); 20918c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_IPV6_TCP, ¶ms.rss_flags); 20928c2ecf20Sopenharmony_ci if (rss_obj->udp_rss_v4) 20938c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_IPV4_UDP, ¶ms.rss_flags); 20948c2ecf20Sopenharmony_ci if (rss_obj->udp_rss_v6) 20958c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_IPV6_UDP, ¶ms.rss_flags); 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci if (!CHIP_IS_E1x(bp)) { 20988c2ecf20Sopenharmony_ci /* valid only for TUNN_MODE_VXLAN tunnel mode */ 20998c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_IPV4_VXLAN, ¶ms.rss_flags); 21008c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_IPV6_VXLAN, ¶ms.rss_flags); 21018c2ecf20Sopenharmony_ci 21028c2ecf20Sopenharmony_ci /* valid only for TUNN_MODE_GRE tunnel mode */ 21038c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_TUNN_INNER_HDRS, ¶ms.rss_flags); 21048c2ecf20Sopenharmony_ci } 21058c2ecf20Sopenharmony_ci } else { 21068c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_MODE_DISABLED, ¶ms.rss_flags); 21078c2ecf20Sopenharmony_ci } 21088c2ecf20Sopenharmony_ci 21098c2ecf20Sopenharmony_ci /* Hash bits */ 21108c2ecf20Sopenharmony_ci params.rss_result_mask = MULTI_MASK; 21118c2ecf20Sopenharmony_ci 21128c2ecf20Sopenharmony_ci memcpy(params.ind_table, rss_obj->ind_table, sizeof(params.ind_table)); 21138c2ecf20Sopenharmony_ci 21148c2ecf20Sopenharmony_ci if (config_hash) { 21158c2ecf20Sopenharmony_ci /* RSS keys */ 21168c2ecf20Sopenharmony_ci netdev_rss_key_fill(params.rss_key, T_ETH_RSS_KEY * 4); 21178c2ecf20Sopenharmony_ci __set_bit(BNX2X_RSS_SET_SRCH, ¶ms.rss_flags); 21188c2ecf20Sopenharmony_ci } 21198c2ecf20Sopenharmony_ci 21208c2ecf20Sopenharmony_ci if (IS_PF(bp)) 21218c2ecf20Sopenharmony_ci return bnx2x_config_rss(bp, ¶ms); 21228c2ecf20Sopenharmony_ci else 21238c2ecf20Sopenharmony_ci return bnx2x_vfpf_config_rss(bp, ¶ms); 21248c2ecf20Sopenharmony_ci} 21258c2ecf20Sopenharmony_ci 21268c2ecf20Sopenharmony_cistatic int bnx2x_init_hw(struct bnx2x *bp, u32 load_code) 21278c2ecf20Sopenharmony_ci{ 21288c2ecf20Sopenharmony_ci struct bnx2x_func_state_params func_params = {NULL}; 21298c2ecf20Sopenharmony_ci 21308c2ecf20Sopenharmony_ci /* Prepare parameters for function state transitions */ 21318c2ecf20Sopenharmony_ci __set_bit(RAMROD_COMP_WAIT, &func_params.ramrod_flags); 21328c2ecf20Sopenharmony_ci 21338c2ecf20Sopenharmony_ci func_params.f_obj = &bp->func_obj; 21348c2ecf20Sopenharmony_ci func_params.cmd = BNX2X_F_CMD_HW_INIT; 21358c2ecf20Sopenharmony_ci 21368c2ecf20Sopenharmony_ci func_params.params.hw_init.load_phase = load_code; 21378c2ecf20Sopenharmony_ci 21388c2ecf20Sopenharmony_ci return bnx2x_func_state_change(bp, &func_params); 21398c2ecf20Sopenharmony_ci} 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci/* 21428c2ecf20Sopenharmony_ci * Cleans the object that have internal lists without sending 21438c2ecf20Sopenharmony_ci * ramrods. Should be run when interrupts are disabled. 21448c2ecf20Sopenharmony_ci */ 21458c2ecf20Sopenharmony_civoid bnx2x_squeeze_objects(struct bnx2x *bp) 21468c2ecf20Sopenharmony_ci{ 21478c2ecf20Sopenharmony_ci int rc; 21488c2ecf20Sopenharmony_ci unsigned long ramrod_flags = 0, vlan_mac_flags = 0; 21498c2ecf20Sopenharmony_ci struct bnx2x_mcast_ramrod_params rparam = {NULL}; 21508c2ecf20Sopenharmony_ci struct bnx2x_vlan_mac_obj *mac_obj = &bp->sp_objs->mac_obj; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci /***************** Cleanup MACs' object first *************************/ 21538c2ecf20Sopenharmony_ci 21548c2ecf20Sopenharmony_ci /* Wait for completion of requested */ 21558c2ecf20Sopenharmony_ci __set_bit(RAMROD_COMP_WAIT, &ramrod_flags); 21568c2ecf20Sopenharmony_ci /* Perform a dry cleanup */ 21578c2ecf20Sopenharmony_ci __set_bit(RAMROD_DRV_CLR_ONLY, &ramrod_flags); 21588c2ecf20Sopenharmony_ci 21598c2ecf20Sopenharmony_ci /* Clean ETH primary MAC */ 21608c2ecf20Sopenharmony_ci __set_bit(BNX2X_ETH_MAC, &vlan_mac_flags); 21618c2ecf20Sopenharmony_ci rc = mac_obj->delete_all(bp, &bp->sp_objs->mac_obj, &vlan_mac_flags, 21628c2ecf20Sopenharmony_ci &ramrod_flags); 21638c2ecf20Sopenharmony_ci if (rc != 0) 21648c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to clean ETH MACs: %d\n", rc); 21658c2ecf20Sopenharmony_ci 21668c2ecf20Sopenharmony_ci /* Cleanup UC list */ 21678c2ecf20Sopenharmony_ci vlan_mac_flags = 0; 21688c2ecf20Sopenharmony_ci __set_bit(BNX2X_UC_LIST_MAC, &vlan_mac_flags); 21698c2ecf20Sopenharmony_ci rc = mac_obj->delete_all(bp, mac_obj, &vlan_mac_flags, 21708c2ecf20Sopenharmony_ci &ramrod_flags); 21718c2ecf20Sopenharmony_ci if (rc != 0) 21728c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to clean UC list MACs: %d\n", rc); 21738c2ecf20Sopenharmony_ci 21748c2ecf20Sopenharmony_ci /***************** Now clean mcast object *****************************/ 21758c2ecf20Sopenharmony_ci rparam.mcast_obj = &bp->mcast_obj; 21768c2ecf20Sopenharmony_ci __set_bit(RAMROD_DRV_CLR_ONLY, &rparam.ramrod_flags); 21778c2ecf20Sopenharmony_ci 21788c2ecf20Sopenharmony_ci /* Add a DEL command... - Since we're doing a driver cleanup only, 21798c2ecf20Sopenharmony_ci * we take a lock surrounding both the initial send and the CONTs, 21808c2ecf20Sopenharmony_ci * as we don't want a true completion to disrupt us in the middle. 21818c2ecf20Sopenharmony_ci */ 21828c2ecf20Sopenharmony_ci netif_addr_lock_bh(bp->dev); 21838c2ecf20Sopenharmony_ci rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_DEL); 21848c2ecf20Sopenharmony_ci if (rc < 0) 21858c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to add a new DEL command to a multi-cast object: %d\n", 21868c2ecf20Sopenharmony_ci rc); 21878c2ecf20Sopenharmony_ci 21888c2ecf20Sopenharmony_ci /* ...and wait until all pending commands are cleared */ 21898c2ecf20Sopenharmony_ci rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT); 21908c2ecf20Sopenharmony_ci while (rc != 0) { 21918c2ecf20Sopenharmony_ci if (rc < 0) { 21928c2ecf20Sopenharmony_ci BNX2X_ERR("Failed to clean multi-cast object: %d\n", 21938c2ecf20Sopenharmony_ci rc); 21948c2ecf20Sopenharmony_ci netif_addr_unlock_bh(bp->dev); 21958c2ecf20Sopenharmony_ci return; 21968c2ecf20Sopenharmony_ci } 21978c2ecf20Sopenharmony_ci 21988c2ecf20Sopenharmony_ci rc = bnx2x_config_mcast(bp, &rparam, BNX2X_MCAST_CMD_CONT); 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci netif_addr_unlock_bh(bp->dev); 22018c2ecf20Sopenharmony_ci} 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR 22048c2ecf20Sopenharmony_ci#define LOAD_ERROR_EXIT(bp, label) \ 22058c2ecf20Sopenharmony_ci do { \ 22068c2ecf20Sopenharmony_ci (bp)->state = BNX2X_STATE_ERROR; \ 22078c2ecf20Sopenharmony_ci goto label; \ 22088c2ecf20Sopenharmony_ci } while (0) 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci#define LOAD_ERROR_EXIT_CNIC(bp, label) \ 22118c2ecf20Sopenharmony_ci do { \ 22128c2ecf20Sopenharmony_ci bp->cnic_loaded = false; \ 22138c2ecf20Sopenharmony_ci goto label; \ 22148c2ecf20Sopenharmony_ci } while (0) 22158c2ecf20Sopenharmony_ci#else /*BNX2X_STOP_ON_ERROR*/ 22168c2ecf20Sopenharmony_ci#define LOAD_ERROR_EXIT(bp, label) \ 22178c2ecf20Sopenharmony_ci do { \ 22188c2ecf20Sopenharmony_ci (bp)->state = BNX2X_STATE_ERROR; \ 22198c2ecf20Sopenharmony_ci (bp)->panic = 1; \ 22208c2ecf20Sopenharmony_ci return -EBUSY; \ 22218c2ecf20Sopenharmony_ci } while (0) 22228c2ecf20Sopenharmony_ci#define LOAD_ERROR_EXIT_CNIC(bp, label) \ 22238c2ecf20Sopenharmony_ci do { \ 22248c2ecf20Sopenharmony_ci bp->cnic_loaded = false; \ 22258c2ecf20Sopenharmony_ci (bp)->panic = 1; \ 22268c2ecf20Sopenharmony_ci return -EBUSY; \ 22278c2ecf20Sopenharmony_ci } while (0) 22288c2ecf20Sopenharmony_ci#endif /*BNX2X_STOP_ON_ERROR*/ 22298c2ecf20Sopenharmony_ci 22308c2ecf20Sopenharmony_cistatic void bnx2x_free_fw_stats_mem(struct bnx2x *bp) 22318c2ecf20Sopenharmony_ci{ 22328c2ecf20Sopenharmony_ci BNX2X_PCI_FREE(bp->fw_stats, bp->fw_stats_mapping, 22338c2ecf20Sopenharmony_ci bp->fw_stats_data_sz + bp->fw_stats_req_sz); 22348c2ecf20Sopenharmony_ci return; 22358c2ecf20Sopenharmony_ci} 22368c2ecf20Sopenharmony_ci 22378c2ecf20Sopenharmony_cistatic int bnx2x_alloc_fw_stats_mem(struct bnx2x *bp) 22388c2ecf20Sopenharmony_ci{ 22398c2ecf20Sopenharmony_ci int num_groups, vf_headroom = 0; 22408c2ecf20Sopenharmony_ci int is_fcoe_stats = NO_FCOE(bp) ? 0 : 1; 22418c2ecf20Sopenharmony_ci 22428c2ecf20Sopenharmony_ci /* number of queues for statistics is number of eth queues + FCoE */ 22438c2ecf20Sopenharmony_ci u8 num_queue_stats = BNX2X_NUM_ETH_QUEUES(bp) + is_fcoe_stats; 22448c2ecf20Sopenharmony_ci 22458c2ecf20Sopenharmony_ci /* Total number of FW statistics requests = 22468c2ecf20Sopenharmony_ci * 1 for port stats + 1 for PF stats + potential 2 for FCoE (fcoe proper 22478c2ecf20Sopenharmony_ci * and fcoe l2 queue) stats + num of queues (which includes another 1 22488c2ecf20Sopenharmony_ci * for fcoe l2 queue if applicable) 22498c2ecf20Sopenharmony_ci */ 22508c2ecf20Sopenharmony_ci bp->fw_stats_num = 2 + is_fcoe_stats + num_queue_stats; 22518c2ecf20Sopenharmony_ci 22528c2ecf20Sopenharmony_ci /* vf stats appear in the request list, but their data is allocated by 22538c2ecf20Sopenharmony_ci * the VFs themselves. We don't include them in the bp->fw_stats_num as 22548c2ecf20Sopenharmony_ci * it is used to determine where to place the vf stats queries in the 22558c2ecf20Sopenharmony_ci * request struct 22568c2ecf20Sopenharmony_ci */ 22578c2ecf20Sopenharmony_ci if (IS_SRIOV(bp)) 22588c2ecf20Sopenharmony_ci vf_headroom = bnx2x_vf_headroom(bp); 22598c2ecf20Sopenharmony_ci 22608c2ecf20Sopenharmony_ci /* Request is built from stats_query_header and an array of 22618c2ecf20Sopenharmony_ci * stats_query_cmd_group each of which contains 22628c2ecf20Sopenharmony_ci * STATS_QUERY_CMD_COUNT rules. The real number or requests is 22638c2ecf20Sopenharmony_ci * configured in the stats_query_header. 22648c2ecf20Sopenharmony_ci */ 22658c2ecf20Sopenharmony_ci num_groups = 22668c2ecf20Sopenharmony_ci (((bp->fw_stats_num + vf_headroom) / STATS_QUERY_CMD_COUNT) + 22678c2ecf20Sopenharmony_ci (((bp->fw_stats_num + vf_headroom) % STATS_QUERY_CMD_COUNT) ? 22688c2ecf20Sopenharmony_ci 1 : 0)); 22698c2ecf20Sopenharmony_ci 22708c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "stats fw_stats_num %d, vf headroom %d, num_groups %d\n", 22718c2ecf20Sopenharmony_ci bp->fw_stats_num, vf_headroom, num_groups); 22728c2ecf20Sopenharmony_ci bp->fw_stats_req_sz = sizeof(struct stats_query_header) + 22738c2ecf20Sopenharmony_ci num_groups * sizeof(struct stats_query_cmd_group); 22748c2ecf20Sopenharmony_ci 22758c2ecf20Sopenharmony_ci /* Data for statistics requests + stats_counter 22768c2ecf20Sopenharmony_ci * stats_counter holds per-STORM counters that are incremented 22778c2ecf20Sopenharmony_ci * when STORM has finished with the current request. 22788c2ecf20Sopenharmony_ci * memory for FCoE offloaded statistics are counted anyway, 22798c2ecf20Sopenharmony_ci * even if they will not be sent. 22808c2ecf20Sopenharmony_ci * VF stats are not accounted for here as the data of VF stats is stored 22818c2ecf20Sopenharmony_ci * in memory allocated by the VF, not here. 22828c2ecf20Sopenharmony_ci */ 22838c2ecf20Sopenharmony_ci bp->fw_stats_data_sz = sizeof(struct per_port_stats) + 22848c2ecf20Sopenharmony_ci sizeof(struct per_pf_stats) + 22858c2ecf20Sopenharmony_ci sizeof(struct fcoe_statistics_params) + 22868c2ecf20Sopenharmony_ci sizeof(struct per_queue_stats) * num_queue_stats + 22878c2ecf20Sopenharmony_ci sizeof(struct stats_counter); 22888c2ecf20Sopenharmony_ci 22898c2ecf20Sopenharmony_ci bp->fw_stats = BNX2X_PCI_ALLOC(&bp->fw_stats_mapping, 22908c2ecf20Sopenharmony_ci bp->fw_stats_data_sz + bp->fw_stats_req_sz); 22918c2ecf20Sopenharmony_ci if (!bp->fw_stats) 22928c2ecf20Sopenharmony_ci goto alloc_mem_err; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci /* Set shortcuts */ 22958c2ecf20Sopenharmony_ci bp->fw_stats_req = (struct bnx2x_fw_stats_req *)bp->fw_stats; 22968c2ecf20Sopenharmony_ci bp->fw_stats_req_mapping = bp->fw_stats_mapping; 22978c2ecf20Sopenharmony_ci bp->fw_stats_data = (struct bnx2x_fw_stats_data *) 22988c2ecf20Sopenharmony_ci ((u8 *)bp->fw_stats + bp->fw_stats_req_sz); 22998c2ecf20Sopenharmony_ci bp->fw_stats_data_mapping = bp->fw_stats_mapping + 23008c2ecf20Sopenharmony_ci bp->fw_stats_req_sz; 23018c2ecf20Sopenharmony_ci 23028c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "statistics request base address set to %x %x\n", 23038c2ecf20Sopenharmony_ci U64_HI(bp->fw_stats_req_mapping), 23048c2ecf20Sopenharmony_ci U64_LO(bp->fw_stats_req_mapping)); 23058c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "statistics data base address set to %x %x\n", 23068c2ecf20Sopenharmony_ci U64_HI(bp->fw_stats_data_mapping), 23078c2ecf20Sopenharmony_ci U64_LO(bp->fw_stats_data_mapping)); 23088c2ecf20Sopenharmony_ci return 0; 23098c2ecf20Sopenharmony_ci 23108c2ecf20Sopenharmony_cialloc_mem_err: 23118c2ecf20Sopenharmony_ci bnx2x_free_fw_stats_mem(bp); 23128c2ecf20Sopenharmony_ci BNX2X_ERR("Can't allocate FW stats memory\n"); 23138c2ecf20Sopenharmony_ci return -ENOMEM; 23148c2ecf20Sopenharmony_ci} 23158c2ecf20Sopenharmony_ci 23168c2ecf20Sopenharmony_ci/* send load request to mcp and analyze response */ 23178c2ecf20Sopenharmony_cistatic int bnx2x_nic_load_request(struct bnx2x *bp, u32 *load_code) 23188c2ecf20Sopenharmony_ci{ 23198c2ecf20Sopenharmony_ci u32 param; 23208c2ecf20Sopenharmony_ci 23218c2ecf20Sopenharmony_ci /* init fw_seq */ 23228c2ecf20Sopenharmony_ci bp->fw_seq = 23238c2ecf20Sopenharmony_ci (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_mb_header) & 23248c2ecf20Sopenharmony_ci DRV_MSG_SEQ_NUMBER_MASK); 23258c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("fw_seq 0x%08x\n", bp->fw_seq); 23268c2ecf20Sopenharmony_ci 23278c2ecf20Sopenharmony_ci /* Get current FW pulse sequence */ 23288c2ecf20Sopenharmony_ci bp->fw_drv_pulse_wr_seq = 23298c2ecf20Sopenharmony_ci (SHMEM_RD(bp, func_mb[BP_FW_MB_IDX(bp)].drv_pulse_mb) & 23308c2ecf20Sopenharmony_ci DRV_PULSE_SEQ_MASK); 23318c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("drv_pulse 0x%x\n", bp->fw_drv_pulse_wr_seq); 23328c2ecf20Sopenharmony_ci 23338c2ecf20Sopenharmony_ci param = DRV_MSG_CODE_LOAD_REQ_WITH_LFA; 23348c2ecf20Sopenharmony_ci 23358c2ecf20Sopenharmony_ci if (IS_MF_SD(bp) && bnx2x_port_after_undi(bp)) 23368c2ecf20Sopenharmony_ci param |= DRV_MSG_CODE_LOAD_REQ_FORCE_LFA; 23378c2ecf20Sopenharmony_ci 23388c2ecf20Sopenharmony_ci /* load request */ 23398c2ecf20Sopenharmony_ci (*load_code) = bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_REQ, param); 23408c2ecf20Sopenharmony_ci 23418c2ecf20Sopenharmony_ci /* if mcp fails to respond we must abort */ 23428c2ecf20Sopenharmony_ci if (!(*load_code)) { 23438c2ecf20Sopenharmony_ci BNX2X_ERR("MCP response failure, aborting\n"); 23448c2ecf20Sopenharmony_ci return -EBUSY; 23458c2ecf20Sopenharmony_ci } 23468c2ecf20Sopenharmony_ci 23478c2ecf20Sopenharmony_ci /* If mcp refused (e.g. other port is in diagnostic mode) we 23488c2ecf20Sopenharmony_ci * must abort 23498c2ecf20Sopenharmony_ci */ 23508c2ecf20Sopenharmony_ci if ((*load_code) == FW_MSG_CODE_DRV_LOAD_REFUSED) { 23518c2ecf20Sopenharmony_ci BNX2X_ERR("MCP refused load request, aborting\n"); 23528c2ecf20Sopenharmony_ci return -EBUSY; 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci return 0; 23558c2ecf20Sopenharmony_ci} 23568c2ecf20Sopenharmony_ci 23578c2ecf20Sopenharmony_ci/* check whether another PF has already loaded FW to chip. In 23588c2ecf20Sopenharmony_ci * virtualized environments a pf from another VM may have already 23598c2ecf20Sopenharmony_ci * initialized the device including loading FW 23608c2ecf20Sopenharmony_ci */ 23618c2ecf20Sopenharmony_ciint bnx2x_compare_fw_ver(struct bnx2x *bp, u32 load_code, bool print_err) 23628c2ecf20Sopenharmony_ci{ 23638c2ecf20Sopenharmony_ci /* is another pf loaded on this engine? */ 23648c2ecf20Sopenharmony_ci if (load_code != FW_MSG_CODE_DRV_LOAD_COMMON_CHIP && 23658c2ecf20Sopenharmony_ci load_code != FW_MSG_CODE_DRV_LOAD_COMMON) { 23668c2ecf20Sopenharmony_ci u8 loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng; 23678c2ecf20Sopenharmony_ci u32 loaded_fw; 23688c2ecf20Sopenharmony_ci 23698c2ecf20Sopenharmony_ci /* read loaded FW from chip */ 23708c2ecf20Sopenharmony_ci loaded_fw = REG_RD(bp, XSEM_REG_PRAM); 23718c2ecf20Sopenharmony_ci 23728c2ecf20Sopenharmony_ci loaded_fw_major = loaded_fw & 0xff; 23738c2ecf20Sopenharmony_ci loaded_fw_minor = (loaded_fw >> 8) & 0xff; 23748c2ecf20Sopenharmony_ci loaded_fw_rev = (loaded_fw >> 16) & 0xff; 23758c2ecf20Sopenharmony_ci loaded_fw_eng = (loaded_fw >> 24) & 0xff; 23768c2ecf20Sopenharmony_ci 23778c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "loaded fw 0x%x major 0x%x minor 0x%x rev 0x%x eng 0x%x\n", 23788c2ecf20Sopenharmony_ci loaded_fw, loaded_fw_major, loaded_fw_minor, loaded_fw_rev, loaded_fw_eng); 23798c2ecf20Sopenharmony_ci 23808c2ecf20Sopenharmony_ci /* abort nic load if version mismatch */ 23818c2ecf20Sopenharmony_ci if (loaded_fw_major != BCM_5710_FW_MAJOR_VERSION || 23828c2ecf20Sopenharmony_ci loaded_fw_minor != BCM_5710_FW_MINOR_VERSION || 23838c2ecf20Sopenharmony_ci loaded_fw_eng != BCM_5710_FW_ENGINEERING_VERSION || 23848c2ecf20Sopenharmony_ci loaded_fw_rev < BCM_5710_FW_REVISION_VERSION_V15) { 23858c2ecf20Sopenharmony_ci if (print_err) 23868c2ecf20Sopenharmony_ci BNX2X_ERR("loaded FW incompatible. Aborting\n"); 23878c2ecf20Sopenharmony_ci else 23888c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("loaded FW incompatible, possibly due to MF UNDI\n"); 23898c2ecf20Sopenharmony_ci 23908c2ecf20Sopenharmony_ci return -EBUSY; 23918c2ecf20Sopenharmony_ci } 23928c2ecf20Sopenharmony_ci } 23938c2ecf20Sopenharmony_ci return 0; 23948c2ecf20Sopenharmony_ci} 23958c2ecf20Sopenharmony_ci 23968c2ecf20Sopenharmony_ci/* returns the "mcp load_code" according to global load_count array */ 23978c2ecf20Sopenharmony_cistatic int bnx2x_nic_load_no_mcp(struct bnx2x *bp, int port) 23988c2ecf20Sopenharmony_ci{ 23998c2ecf20Sopenharmony_ci int path = BP_PATH(bp); 24008c2ecf20Sopenharmony_ci 24018c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "NO MCP - load counts[%d] %d, %d, %d\n", 24028c2ecf20Sopenharmony_ci path, bnx2x_load_count[path][0], bnx2x_load_count[path][1], 24038c2ecf20Sopenharmony_ci bnx2x_load_count[path][2]); 24048c2ecf20Sopenharmony_ci bnx2x_load_count[path][0]++; 24058c2ecf20Sopenharmony_ci bnx2x_load_count[path][1 + port]++; 24068c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "NO MCP - new load counts[%d] %d, %d, %d\n", 24078c2ecf20Sopenharmony_ci path, bnx2x_load_count[path][0], bnx2x_load_count[path][1], 24088c2ecf20Sopenharmony_ci bnx2x_load_count[path][2]); 24098c2ecf20Sopenharmony_ci if (bnx2x_load_count[path][0] == 1) 24108c2ecf20Sopenharmony_ci return FW_MSG_CODE_DRV_LOAD_COMMON; 24118c2ecf20Sopenharmony_ci else if (bnx2x_load_count[path][1 + port] == 1) 24128c2ecf20Sopenharmony_ci return FW_MSG_CODE_DRV_LOAD_PORT; 24138c2ecf20Sopenharmony_ci else 24148c2ecf20Sopenharmony_ci return FW_MSG_CODE_DRV_LOAD_FUNCTION; 24158c2ecf20Sopenharmony_ci} 24168c2ecf20Sopenharmony_ci 24178c2ecf20Sopenharmony_ci/* mark PMF if applicable */ 24188c2ecf20Sopenharmony_cistatic void bnx2x_nic_load_pmf(struct bnx2x *bp, u32 load_code) 24198c2ecf20Sopenharmony_ci{ 24208c2ecf20Sopenharmony_ci if ((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) || 24218c2ecf20Sopenharmony_ci (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP) || 24228c2ecf20Sopenharmony_ci (load_code == FW_MSG_CODE_DRV_LOAD_PORT)) { 24238c2ecf20Sopenharmony_ci bp->port.pmf = 1; 24248c2ecf20Sopenharmony_ci /* We need the barrier to ensure the ordering between the 24258c2ecf20Sopenharmony_ci * writing to bp->port.pmf here and reading it from the 24268c2ecf20Sopenharmony_ci * bnx2x_periodic_task(). 24278c2ecf20Sopenharmony_ci */ 24288c2ecf20Sopenharmony_ci smp_mb(); 24298c2ecf20Sopenharmony_ci } else { 24308c2ecf20Sopenharmony_ci bp->port.pmf = 0; 24318c2ecf20Sopenharmony_ci } 24328c2ecf20Sopenharmony_ci 24338c2ecf20Sopenharmony_ci DP(NETIF_MSG_LINK, "pmf %d\n", bp->port.pmf); 24348c2ecf20Sopenharmony_ci} 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_cistatic void bnx2x_nic_load_afex_dcc(struct bnx2x *bp, int load_code) 24378c2ecf20Sopenharmony_ci{ 24388c2ecf20Sopenharmony_ci if (((load_code == FW_MSG_CODE_DRV_LOAD_COMMON) || 24398c2ecf20Sopenharmony_ci (load_code == FW_MSG_CODE_DRV_LOAD_COMMON_CHIP)) && 24408c2ecf20Sopenharmony_ci (bp->common.shmem2_base)) { 24418c2ecf20Sopenharmony_ci if (SHMEM2_HAS(bp, dcc_support)) 24428c2ecf20Sopenharmony_ci SHMEM2_WR(bp, dcc_support, 24438c2ecf20Sopenharmony_ci (SHMEM_DCC_SUPPORT_DISABLE_ENABLE_PF_TLV | 24448c2ecf20Sopenharmony_ci SHMEM_DCC_SUPPORT_BANDWIDTH_ALLOCATION_TLV)); 24458c2ecf20Sopenharmony_ci if (SHMEM2_HAS(bp, afex_driver_support)) 24468c2ecf20Sopenharmony_ci SHMEM2_WR(bp, afex_driver_support, 24478c2ecf20Sopenharmony_ci SHMEM_AFEX_SUPPORTED_VERSION_ONE); 24488c2ecf20Sopenharmony_ci } 24498c2ecf20Sopenharmony_ci 24508c2ecf20Sopenharmony_ci /* Set AFEX default VLAN tag to an invalid value */ 24518c2ecf20Sopenharmony_ci bp->afex_def_vlan_tag = -1; 24528c2ecf20Sopenharmony_ci} 24538c2ecf20Sopenharmony_ci 24548c2ecf20Sopenharmony_ci/** 24558c2ecf20Sopenharmony_ci * bnx2x_bz_fp - zero content of the fastpath structure. 24568c2ecf20Sopenharmony_ci * 24578c2ecf20Sopenharmony_ci * @bp: driver handle 24588c2ecf20Sopenharmony_ci * @index: fastpath index to be zeroed 24598c2ecf20Sopenharmony_ci * 24608c2ecf20Sopenharmony_ci * Makes sure the contents of the bp->fp[index].napi is kept 24618c2ecf20Sopenharmony_ci * intact. 24628c2ecf20Sopenharmony_ci */ 24638c2ecf20Sopenharmony_cistatic void bnx2x_bz_fp(struct bnx2x *bp, int index) 24648c2ecf20Sopenharmony_ci{ 24658c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[index]; 24668c2ecf20Sopenharmony_ci int cos; 24678c2ecf20Sopenharmony_ci struct napi_struct orig_napi = fp->napi; 24688c2ecf20Sopenharmony_ci struct bnx2x_agg_info *orig_tpa_info = fp->tpa_info; 24698c2ecf20Sopenharmony_ci 24708c2ecf20Sopenharmony_ci /* bzero bnx2x_fastpath contents */ 24718c2ecf20Sopenharmony_ci if (fp->tpa_info) 24728c2ecf20Sopenharmony_ci memset(fp->tpa_info, 0, ETH_MAX_AGGREGATION_QUEUES_E1H_E2 * 24738c2ecf20Sopenharmony_ci sizeof(struct bnx2x_agg_info)); 24748c2ecf20Sopenharmony_ci memset(fp, 0, sizeof(*fp)); 24758c2ecf20Sopenharmony_ci 24768c2ecf20Sopenharmony_ci /* Restore the NAPI object as it has been already initialized */ 24778c2ecf20Sopenharmony_ci fp->napi = orig_napi; 24788c2ecf20Sopenharmony_ci fp->tpa_info = orig_tpa_info; 24798c2ecf20Sopenharmony_ci fp->bp = bp; 24808c2ecf20Sopenharmony_ci fp->index = index; 24818c2ecf20Sopenharmony_ci if (IS_ETH_FP(fp)) 24828c2ecf20Sopenharmony_ci fp->max_cos = bp->max_cos; 24838c2ecf20Sopenharmony_ci else 24848c2ecf20Sopenharmony_ci /* Special queues support only one CoS */ 24858c2ecf20Sopenharmony_ci fp->max_cos = 1; 24868c2ecf20Sopenharmony_ci 24878c2ecf20Sopenharmony_ci /* Init txdata pointers */ 24888c2ecf20Sopenharmony_ci if (IS_FCOE_FP(fp)) 24898c2ecf20Sopenharmony_ci fp->txdata_ptr[0] = &bp->bnx2x_txq[FCOE_TXQ_IDX(bp)]; 24908c2ecf20Sopenharmony_ci if (IS_ETH_FP(fp)) 24918c2ecf20Sopenharmony_ci for_each_cos_in_tx_queue(fp, cos) 24928c2ecf20Sopenharmony_ci fp->txdata_ptr[cos] = &bp->bnx2x_txq[cos * 24938c2ecf20Sopenharmony_ci BNX2X_NUM_ETH_QUEUES(bp) + index]; 24948c2ecf20Sopenharmony_ci 24958c2ecf20Sopenharmony_ci /* set the tpa flag for each queue. The tpa flag determines the queue 24968c2ecf20Sopenharmony_ci * minimal size so it must be set prior to queue memory allocation 24978c2ecf20Sopenharmony_ci */ 24988c2ecf20Sopenharmony_ci if (bp->dev->features & NETIF_F_LRO) 24998c2ecf20Sopenharmony_ci fp->mode = TPA_MODE_LRO; 25008c2ecf20Sopenharmony_ci else if (bp->dev->features & NETIF_F_GRO_HW) 25018c2ecf20Sopenharmony_ci fp->mode = TPA_MODE_GRO; 25028c2ecf20Sopenharmony_ci else 25038c2ecf20Sopenharmony_ci fp->mode = TPA_MODE_DISABLED; 25048c2ecf20Sopenharmony_ci 25058c2ecf20Sopenharmony_ci /* We don't want TPA if it's disabled in bp 25068c2ecf20Sopenharmony_ci * or if this is an FCoE L2 ring. 25078c2ecf20Sopenharmony_ci */ 25088c2ecf20Sopenharmony_ci if (bp->disable_tpa || IS_FCOE_FP(fp)) 25098c2ecf20Sopenharmony_ci fp->mode = TPA_MODE_DISABLED; 25108c2ecf20Sopenharmony_ci} 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_civoid bnx2x_set_os_driver_state(struct bnx2x *bp, u32 state) 25138c2ecf20Sopenharmony_ci{ 25148c2ecf20Sopenharmony_ci u32 cur; 25158c2ecf20Sopenharmony_ci 25168c2ecf20Sopenharmony_ci if (!IS_MF_BD(bp) || !SHMEM2_HAS(bp, os_driver_state) || IS_VF(bp)) 25178c2ecf20Sopenharmony_ci return; 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci cur = SHMEM2_RD(bp, os_driver_state[BP_FW_MB_IDX(bp)]); 25208c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "Driver state %08x-->%08x\n", 25218c2ecf20Sopenharmony_ci cur, state); 25228c2ecf20Sopenharmony_ci 25238c2ecf20Sopenharmony_ci SHMEM2_WR(bp, os_driver_state[BP_FW_MB_IDX(bp)], state); 25248c2ecf20Sopenharmony_ci} 25258c2ecf20Sopenharmony_ci 25268c2ecf20Sopenharmony_ciint bnx2x_load_cnic(struct bnx2x *bp) 25278c2ecf20Sopenharmony_ci{ 25288c2ecf20Sopenharmony_ci int i, rc, port = BP_PORT(bp); 25298c2ecf20Sopenharmony_ci 25308c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "Starting CNIC-related load\n"); 25318c2ecf20Sopenharmony_ci 25328c2ecf20Sopenharmony_ci mutex_init(&bp->cnic_mutex); 25338c2ecf20Sopenharmony_ci 25348c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 25358c2ecf20Sopenharmony_ci rc = bnx2x_alloc_mem_cnic(bp); 25368c2ecf20Sopenharmony_ci if (rc) { 25378c2ecf20Sopenharmony_ci BNX2X_ERR("Unable to allocate bp memory for cnic\n"); 25388c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0); 25398c2ecf20Sopenharmony_ci } 25408c2ecf20Sopenharmony_ci } 25418c2ecf20Sopenharmony_ci 25428c2ecf20Sopenharmony_ci rc = bnx2x_alloc_fp_mem_cnic(bp); 25438c2ecf20Sopenharmony_ci if (rc) { 25448c2ecf20Sopenharmony_ci BNX2X_ERR("Unable to allocate memory for cnic fps\n"); 25458c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0); 25468c2ecf20Sopenharmony_ci } 25478c2ecf20Sopenharmony_ci 25488c2ecf20Sopenharmony_ci /* Update the number of queues with the cnic queues */ 25498c2ecf20Sopenharmony_ci rc = bnx2x_set_real_num_queues(bp, 1); 25508c2ecf20Sopenharmony_ci if (rc) { 25518c2ecf20Sopenharmony_ci BNX2X_ERR("Unable to set real_num_queues including cnic\n"); 25528c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic0); 25538c2ecf20Sopenharmony_ci } 25548c2ecf20Sopenharmony_ci 25558c2ecf20Sopenharmony_ci /* Add all CNIC NAPI objects */ 25568c2ecf20Sopenharmony_ci bnx2x_add_all_napi_cnic(bp); 25578c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "cnic napi added\n"); 25588c2ecf20Sopenharmony_ci bnx2x_napi_enable_cnic(bp); 25598c2ecf20Sopenharmony_ci 25608c2ecf20Sopenharmony_ci rc = bnx2x_init_hw_func_cnic(bp); 25618c2ecf20Sopenharmony_ci if (rc) 25628c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT_CNIC(bp, load_error_cnic1); 25638c2ecf20Sopenharmony_ci 25648c2ecf20Sopenharmony_ci bnx2x_nic_init_cnic(bp); 25658c2ecf20Sopenharmony_ci 25668c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 25678c2ecf20Sopenharmony_ci /* Enable Timer scan */ 25688c2ecf20Sopenharmony_ci REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 1); 25698c2ecf20Sopenharmony_ci 25708c2ecf20Sopenharmony_ci /* setup cnic queues */ 25718c2ecf20Sopenharmony_ci for_each_cnic_queue(bp, i) { 25728c2ecf20Sopenharmony_ci rc = bnx2x_setup_queue(bp, &bp->fp[i], 0); 25738c2ecf20Sopenharmony_ci if (rc) { 25748c2ecf20Sopenharmony_ci BNX2X_ERR("Queue setup failed\n"); 25758c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error_cnic2); 25768c2ecf20Sopenharmony_ci } 25778c2ecf20Sopenharmony_ci } 25788c2ecf20Sopenharmony_ci } 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci /* Initialize Rx filter. */ 25818c2ecf20Sopenharmony_ci bnx2x_set_rx_mode_inner(bp); 25828c2ecf20Sopenharmony_ci 25838c2ecf20Sopenharmony_ci /* re-read iscsi info */ 25848c2ecf20Sopenharmony_ci bnx2x_get_iscsi_info(bp); 25858c2ecf20Sopenharmony_ci bnx2x_setup_cnic_irq_info(bp); 25868c2ecf20Sopenharmony_ci bnx2x_setup_cnic_info(bp); 25878c2ecf20Sopenharmony_ci bp->cnic_loaded = true; 25888c2ecf20Sopenharmony_ci if (bp->state == BNX2X_STATE_OPEN) 25898c2ecf20Sopenharmony_ci bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD); 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "Ending successfully CNIC-related load\n"); 25928c2ecf20Sopenharmony_ci 25938c2ecf20Sopenharmony_ci return 0; 25948c2ecf20Sopenharmony_ci 25958c2ecf20Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR 25968c2ecf20Sopenharmony_ciload_error_cnic2: 25978c2ecf20Sopenharmony_ci /* Disable Timer scan */ 25988c2ecf20Sopenharmony_ci REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 0); 25998c2ecf20Sopenharmony_ci 26008c2ecf20Sopenharmony_ciload_error_cnic1: 26018c2ecf20Sopenharmony_ci bnx2x_napi_disable_cnic(bp); 26028c2ecf20Sopenharmony_ci /* Update the number of queues without the cnic queues */ 26038c2ecf20Sopenharmony_ci if (bnx2x_set_real_num_queues(bp, 0)) 26048c2ecf20Sopenharmony_ci BNX2X_ERR("Unable to set real_num_queues not including cnic\n"); 26058c2ecf20Sopenharmony_ciload_error_cnic0: 26068c2ecf20Sopenharmony_ci BNX2X_ERR("CNIC-related load failed\n"); 26078c2ecf20Sopenharmony_ci bnx2x_free_fp_mem_cnic(bp); 26088c2ecf20Sopenharmony_ci bnx2x_free_mem_cnic(bp); 26098c2ecf20Sopenharmony_ci return rc; 26108c2ecf20Sopenharmony_ci#endif /* ! BNX2X_STOP_ON_ERROR */ 26118c2ecf20Sopenharmony_ci} 26128c2ecf20Sopenharmony_ci 26138c2ecf20Sopenharmony_ci/* must be called with rtnl_lock */ 26148c2ecf20Sopenharmony_ciint bnx2x_nic_load(struct bnx2x *bp, int load_mode) 26158c2ecf20Sopenharmony_ci{ 26168c2ecf20Sopenharmony_ci int port = BP_PORT(bp); 26178c2ecf20Sopenharmony_ci int i, rc = 0, load_code = 0; 26188c2ecf20Sopenharmony_ci 26198c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "Starting NIC load\n"); 26208c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, 26218c2ecf20Sopenharmony_ci "CNIC is %s\n", CNIC_ENABLED(bp) ? "enabled" : "disabled"); 26228c2ecf20Sopenharmony_ci 26238c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 26248c2ecf20Sopenharmony_ci if (unlikely(bp->panic)) { 26258c2ecf20Sopenharmony_ci BNX2X_ERR("Can't load NIC when there is panic\n"); 26268c2ecf20Sopenharmony_ci return -EPERM; 26278c2ecf20Sopenharmony_ci } 26288c2ecf20Sopenharmony_ci#endif 26298c2ecf20Sopenharmony_ci 26308c2ecf20Sopenharmony_ci bp->state = BNX2X_STATE_OPENING_WAIT4_LOAD; 26318c2ecf20Sopenharmony_ci 26328c2ecf20Sopenharmony_ci /* zero the structure w/o any lock, before SP handler is initialized */ 26338c2ecf20Sopenharmony_ci memset(&bp->last_reported_link, 0, sizeof(bp->last_reported_link)); 26348c2ecf20Sopenharmony_ci __set_bit(BNX2X_LINK_REPORT_LINK_DOWN, 26358c2ecf20Sopenharmony_ci &bp->last_reported_link.link_report_flags); 26368c2ecf20Sopenharmony_ci 26378c2ecf20Sopenharmony_ci if (IS_PF(bp)) 26388c2ecf20Sopenharmony_ci /* must be called before memory allocation and HW init */ 26398c2ecf20Sopenharmony_ci bnx2x_ilt_set_info(bp); 26408c2ecf20Sopenharmony_ci 26418c2ecf20Sopenharmony_ci /* 26428c2ecf20Sopenharmony_ci * Zero fastpath structures preserving invariants like napi, which are 26438c2ecf20Sopenharmony_ci * allocated only once, fp index, max_cos, bp pointer. 26448c2ecf20Sopenharmony_ci * Also set fp->mode and txdata_ptr. 26458c2ecf20Sopenharmony_ci */ 26468c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "num queues: %d", bp->num_queues); 26478c2ecf20Sopenharmony_ci for_each_queue(bp, i) 26488c2ecf20Sopenharmony_ci bnx2x_bz_fp(bp, i); 26498c2ecf20Sopenharmony_ci memset(bp->bnx2x_txq, 0, (BNX2X_MAX_RSS_COUNT(bp) * BNX2X_MULTI_TX_COS + 26508c2ecf20Sopenharmony_ci bp->num_cnic_queues) * 26518c2ecf20Sopenharmony_ci sizeof(struct bnx2x_fp_txdata)); 26528c2ecf20Sopenharmony_ci 26538c2ecf20Sopenharmony_ci bp->fcoe_init = false; 26548c2ecf20Sopenharmony_ci 26558c2ecf20Sopenharmony_ci /* Set the receive queues buffer size */ 26568c2ecf20Sopenharmony_ci bnx2x_set_rx_buf_size(bp); 26578c2ecf20Sopenharmony_ci 26588c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 26598c2ecf20Sopenharmony_ci rc = bnx2x_alloc_mem(bp); 26608c2ecf20Sopenharmony_ci if (rc) { 26618c2ecf20Sopenharmony_ci BNX2X_ERR("Unable to allocate bp memory\n"); 26628c2ecf20Sopenharmony_ci return rc; 26638c2ecf20Sopenharmony_ci } 26648c2ecf20Sopenharmony_ci } 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci /* need to be done after alloc mem, since it's self adjusting to amount 26678c2ecf20Sopenharmony_ci * of memory available for RSS queues 26688c2ecf20Sopenharmony_ci */ 26698c2ecf20Sopenharmony_ci rc = bnx2x_alloc_fp_mem(bp); 26708c2ecf20Sopenharmony_ci if (rc) { 26718c2ecf20Sopenharmony_ci BNX2X_ERR("Unable to allocate memory for fps\n"); 26728c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error0); 26738c2ecf20Sopenharmony_ci } 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_ci /* Allocated memory for FW statistics */ 26768c2ecf20Sopenharmony_ci rc = bnx2x_alloc_fw_stats_mem(bp); 26778c2ecf20Sopenharmony_ci if (rc) 26788c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error0); 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci /* request pf to initialize status blocks */ 26818c2ecf20Sopenharmony_ci if (IS_VF(bp)) { 26828c2ecf20Sopenharmony_ci rc = bnx2x_vfpf_init(bp); 26838c2ecf20Sopenharmony_ci if (rc) 26848c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error0); 26858c2ecf20Sopenharmony_ci } 26868c2ecf20Sopenharmony_ci 26878c2ecf20Sopenharmony_ci /* As long as bnx2x_alloc_mem() may possibly update 26888c2ecf20Sopenharmony_ci * bp->num_queues, bnx2x_set_real_num_queues() should always 26898c2ecf20Sopenharmony_ci * come after it. At this stage cnic queues are not counted. 26908c2ecf20Sopenharmony_ci */ 26918c2ecf20Sopenharmony_ci rc = bnx2x_set_real_num_queues(bp, 0); 26928c2ecf20Sopenharmony_ci if (rc) { 26938c2ecf20Sopenharmony_ci BNX2X_ERR("Unable to set real_num_queues\n"); 26948c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error0); 26958c2ecf20Sopenharmony_ci } 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci /* configure multi cos mappings in kernel. 26988c2ecf20Sopenharmony_ci * this configuration may be overridden by a multi class queue 26998c2ecf20Sopenharmony_ci * discipline or by a dcbx negotiation result. 27008c2ecf20Sopenharmony_ci */ 27018c2ecf20Sopenharmony_ci bnx2x_setup_tc(bp->dev, bp->max_cos); 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci /* Add all NAPI objects */ 27048c2ecf20Sopenharmony_ci bnx2x_add_all_napi(bp); 27058c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "napi added\n"); 27068c2ecf20Sopenharmony_ci bnx2x_napi_enable(bp); 27078c2ecf20Sopenharmony_ci 27088c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 27098c2ecf20Sopenharmony_ci /* set pf load just before approaching the MCP */ 27108c2ecf20Sopenharmony_ci bnx2x_set_pf_load(bp); 27118c2ecf20Sopenharmony_ci 27128c2ecf20Sopenharmony_ci /* if mcp exists send load request and analyze response */ 27138c2ecf20Sopenharmony_ci if (!BP_NOMCP(bp)) { 27148c2ecf20Sopenharmony_ci /* attempt to load pf */ 27158c2ecf20Sopenharmony_ci rc = bnx2x_nic_load_request(bp, &load_code); 27168c2ecf20Sopenharmony_ci if (rc) 27178c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error1); 27188c2ecf20Sopenharmony_ci 27198c2ecf20Sopenharmony_ci /* what did mcp say? */ 27208c2ecf20Sopenharmony_ci rc = bnx2x_compare_fw_ver(bp, load_code, true); 27218c2ecf20Sopenharmony_ci if (rc) { 27228c2ecf20Sopenharmony_ci bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); 27238c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error2); 27248c2ecf20Sopenharmony_ci } 27258c2ecf20Sopenharmony_ci } else { 27268c2ecf20Sopenharmony_ci load_code = bnx2x_nic_load_no_mcp(bp, port); 27278c2ecf20Sopenharmony_ci } 27288c2ecf20Sopenharmony_ci 27298c2ecf20Sopenharmony_ci /* mark pmf if applicable */ 27308c2ecf20Sopenharmony_ci bnx2x_nic_load_pmf(bp, load_code); 27318c2ecf20Sopenharmony_ci 27328c2ecf20Sopenharmony_ci /* Init Function state controlling object */ 27338c2ecf20Sopenharmony_ci bnx2x__init_func_obj(bp); 27348c2ecf20Sopenharmony_ci 27358c2ecf20Sopenharmony_ci /* Initialize HW */ 27368c2ecf20Sopenharmony_ci rc = bnx2x_init_hw(bp, load_code); 27378c2ecf20Sopenharmony_ci if (rc) { 27388c2ecf20Sopenharmony_ci BNX2X_ERR("HW init failed, aborting\n"); 27398c2ecf20Sopenharmony_ci bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); 27408c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error2); 27418c2ecf20Sopenharmony_ci } 27428c2ecf20Sopenharmony_ci } 27438c2ecf20Sopenharmony_ci 27448c2ecf20Sopenharmony_ci bnx2x_pre_irq_nic_init(bp); 27458c2ecf20Sopenharmony_ci 27468c2ecf20Sopenharmony_ci /* Connect to IRQs */ 27478c2ecf20Sopenharmony_ci rc = bnx2x_setup_irqs(bp); 27488c2ecf20Sopenharmony_ci if (rc) { 27498c2ecf20Sopenharmony_ci BNX2X_ERR("setup irqs failed\n"); 27508c2ecf20Sopenharmony_ci if (IS_PF(bp)) 27518c2ecf20Sopenharmony_ci bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); 27528c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error2); 27538c2ecf20Sopenharmony_ci } 27548c2ecf20Sopenharmony_ci 27558c2ecf20Sopenharmony_ci /* Init per-function objects */ 27568c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 27578c2ecf20Sopenharmony_ci /* Setup NIC internals and enable interrupts */ 27588c2ecf20Sopenharmony_ci bnx2x_post_irq_nic_init(bp, load_code); 27598c2ecf20Sopenharmony_ci 27608c2ecf20Sopenharmony_ci bnx2x_init_bp_objs(bp); 27618c2ecf20Sopenharmony_ci bnx2x_iov_nic_init(bp); 27628c2ecf20Sopenharmony_ci 27638c2ecf20Sopenharmony_ci /* Set AFEX default VLAN tag to an invalid value */ 27648c2ecf20Sopenharmony_ci bp->afex_def_vlan_tag = -1; 27658c2ecf20Sopenharmony_ci bnx2x_nic_load_afex_dcc(bp, load_code); 27668c2ecf20Sopenharmony_ci bp->state = BNX2X_STATE_OPENING_WAIT4_PORT; 27678c2ecf20Sopenharmony_ci rc = bnx2x_func_start(bp); 27688c2ecf20Sopenharmony_ci if (rc) { 27698c2ecf20Sopenharmony_ci BNX2X_ERR("Function start failed!\n"); 27708c2ecf20Sopenharmony_ci bnx2x_fw_command(bp, DRV_MSG_CODE_LOAD_DONE, 0); 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error3); 27738c2ecf20Sopenharmony_ci } 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci /* Send LOAD_DONE command to MCP */ 27768c2ecf20Sopenharmony_ci if (!BP_NOMCP(bp)) { 27778c2ecf20Sopenharmony_ci load_code = bnx2x_fw_command(bp, 27788c2ecf20Sopenharmony_ci DRV_MSG_CODE_LOAD_DONE, 0); 27798c2ecf20Sopenharmony_ci if (!load_code) { 27808c2ecf20Sopenharmony_ci BNX2X_ERR("MCP response failure, aborting\n"); 27818c2ecf20Sopenharmony_ci rc = -EBUSY; 27828c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error3); 27838c2ecf20Sopenharmony_ci } 27848c2ecf20Sopenharmony_ci } 27858c2ecf20Sopenharmony_ci 27868c2ecf20Sopenharmony_ci /* initialize FW coalescing state machines in RAM */ 27878c2ecf20Sopenharmony_ci bnx2x_update_coalesce(bp); 27888c2ecf20Sopenharmony_ci } 27898c2ecf20Sopenharmony_ci 27908c2ecf20Sopenharmony_ci /* setup the leading queue */ 27918c2ecf20Sopenharmony_ci rc = bnx2x_setup_leading(bp); 27928c2ecf20Sopenharmony_ci if (rc) { 27938c2ecf20Sopenharmony_ci BNX2X_ERR("Setup leading failed!\n"); 27948c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error3); 27958c2ecf20Sopenharmony_ci } 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci /* set up the rest of the queues */ 27988c2ecf20Sopenharmony_ci for_each_nondefault_eth_queue(bp, i) { 27998c2ecf20Sopenharmony_ci if (IS_PF(bp)) 28008c2ecf20Sopenharmony_ci rc = bnx2x_setup_queue(bp, &bp->fp[i], false); 28018c2ecf20Sopenharmony_ci else /* VF */ 28028c2ecf20Sopenharmony_ci rc = bnx2x_vfpf_setup_q(bp, &bp->fp[i], false); 28038c2ecf20Sopenharmony_ci if (rc) { 28048c2ecf20Sopenharmony_ci BNX2X_ERR("Queue %d setup failed\n", i); 28058c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error3); 28068c2ecf20Sopenharmony_ci } 28078c2ecf20Sopenharmony_ci } 28088c2ecf20Sopenharmony_ci 28098c2ecf20Sopenharmony_ci /* setup rss */ 28108c2ecf20Sopenharmony_ci rc = bnx2x_init_rss(bp); 28118c2ecf20Sopenharmony_ci if (rc) { 28128c2ecf20Sopenharmony_ci BNX2X_ERR("PF RSS init failed\n"); 28138c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error3); 28148c2ecf20Sopenharmony_ci } 28158c2ecf20Sopenharmony_ci 28168c2ecf20Sopenharmony_ci /* Now when Clients are configured we are ready to work */ 28178c2ecf20Sopenharmony_ci bp->state = BNX2X_STATE_OPEN; 28188c2ecf20Sopenharmony_ci 28198c2ecf20Sopenharmony_ci /* Configure a ucast MAC */ 28208c2ecf20Sopenharmony_ci if (IS_PF(bp)) 28218c2ecf20Sopenharmony_ci rc = bnx2x_set_eth_mac(bp, true); 28228c2ecf20Sopenharmony_ci else /* vf */ 28238c2ecf20Sopenharmony_ci rc = bnx2x_vfpf_config_mac(bp, bp->dev->dev_addr, bp->fp->index, 28248c2ecf20Sopenharmony_ci true); 28258c2ecf20Sopenharmony_ci if (rc) { 28268c2ecf20Sopenharmony_ci BNX2X_ERR("Setting Ethernet MAC failed\n"); 28278c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error3); 28288c2ecf20Sopenharmony_ci } 28298c2ecf20Sopenharmony_ci 28308c2ecf20Sopenharmony_ci if (IS_PF(bp) && bp->pending_max) { 28318c2ecf20Sopenharmony_ci bnx2x_update_max_mf_config(bp, bp->pending_max); 28328c2ecf20Sopenharmony_ci bp->pending_max = 0; 28338c2ecf20Sopenharmony_ci } 28348c2ecf20Sopenharmony_ci 28358c2ecf20Sopenharmony_ci bp->force_link_down = false; 28368c2ecf20Sopenharmony_ci if (bp->port.pmf) { 28378c2ecf20Sopenharmony_ci rc = bnx2x_initial_phy_init(bp, load_mode); 28388c2ecf20Sopenharmony_ci if (rc) 28398c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error3); 28408c2ecf20Sopenharmony_ci } 28418c2ecf20Sopenharmony_ci bp->link_params.feature_config_flags &= ~FEATURE_CONFIG_BOOT_FROM_SAN; 28428c2ecf20Sopenharmony_ci 28438c2ecf20Sopenharmony_ci /* Start fast path */ 28448c2ecf20Sopenharmony_ci 28458c2ecf20Sopenharmony_ci /* Re-configure vlan filters */ 28468c2ecf20Sopenharmony_ci rc = bnx2x_vlan_reconfigure_vid(bp); 28478c2ecf20Sopenharmony_ci if (rc) 28488c2ecf20Sopenharmony_ci LOAD_ERROR_EXIT(bp, load_error3); 28498c2ecf20Sopenharmony_ci 28508c2ecf20Sopenharmony_ci /* Initialize Rx filter. */ 28518c2ecf20Sopenharmony_ci bnx2x_set_rx_mode_inner(bp); 28528c2ecf20Sopenharmony_ci 28538c2ecf20Sopenharmony_ci if (bp->flags & PTP_SUPPORTED) { 28548c2ecf20Sopenharmony_ci bnx2x_register_phc(bp); 28558c2ecf20Sopenharmony_ci bnx2x_init_ptp(bp); 28568c2ecf20Sopenharmony_ci bnx2x_configure_ptp_filters(bp); 28578c2ecf20Sopenharmony_ci } 28588c2ecf20Sopenharmony_ci /* Start Tx */ 28598c2ecf20Sopenharmony_ci switch (load_mode) { 28608c2ecf20Sopenharmony_ci case LOAD_NORMAL: 28618c2ecf20Sopenharmony_ci /* Tx queue should be only re-enabled */ 28628c2ecf20Sopenharmony_ci netif_tx_wake_all_queues(bp->dev); 28638c2ecf20Sopenharmony_ci break; 28648c2ecf20Sopenharmony_ci 28658c2ecf20Sopenharmony_ci case LOAD_OPEN: 28668c2ecf20Sopenharmony_ci netif_tx_start_all_queues(bp->dev); 28678c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 28688c2ecf20Sopenharmony_ci break; 28698c2ecf20Sopenharmony_ci 28708c2ecf20Sopenharmony_ci case LOAD_DIAG: 28718c2ecf20Sopenharmony_ci case LOAD_LOOPBACK_EXT: 28728c2ecf20Sopenharmony_ci bp->state = BNX2X_STATE_DIAG; 28738c2ecf20Sopenharmony_ci break; 28748c2ecf20Sopenharmony_ci 28758c2ecf20Sopenharmony_ci default: 28768c2ecf20Sopenharmony_ci break; 28778c2ecf20Sopenharmony_ci } 28788c2ecf20Sopenharmony_ci 28798c2ecf20Sopenharmony_ci if (bp->port.pmf) 28808c2ecf20Sopenharmony_ci bnx2x_update_drv_flags(bp, 1 << DRV_FLAGS_PORT_MASK, 0); 28818c2ecf20Sopenharmony_ci else 28828c2ecf20Sopenharmony_ci bnx2x__link_status_update(bp); 28838c2ecf20Sopenharmony_ci 28848c2ecf20Sopenharmony_ci /* start the timer */ 28858c2ecf20Sopenharmony_ci mod_timer(&bp->timer, jiffies + bp->current_interval); 28868c2ecf20Sopenharmony_ci 28878c2ecf20Sopenharmony_ci if (CNIC_ENABLED(bp)) 28888c2ecf20Sopenharmony_ci bnx2x_load_cnic(bp); 28898c2ecf20Sopenharmony_ci 28908c2ecf20Sopenharmony_ci if (IS_PF(bp)) 28918c2ecf20Sopenharmony_ci bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_GET_DRV_VERSION, 0); 28928c2ecf20Sopenharmony_ci 28938c2ecf20Sopenharmony_ci if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) { 28948c2ecf20Sopenharmony_ci /* mark driver is loaded in shmem2 */ 28958c2ecf20Sopenharmony_ci u32 val; 28968c2ecf20Sopenharmony_ci val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]); 28978c2ecf20Sopenharmony_ci val &= ~DRV_FLAGS_MTU_MASK; 28988c2ecf20Sopenharmony_ci val |= (bp->dev->mtu << DRV_FLAGS_MTU_SHIFT); 28998c2ecf20Sopenharmony_ci SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)], 29008c2ecf20Sopenharmony_ci val | DRV_FLAGS_CAPABILITIES_LOADED_SUPPORTED | 29018c2ecf20Sopenharmony_ci DRV_FLAGS_CAPABILITIES_LOADED_L2); 29028c2ecf20Sopenharmony_ci } 29038c2ecf20Sopenharmony_ci 29048c2ecf20Sopenharmony_ci /* Wait for all pending SP commands to complete */ 29058c2ecf20Sopenharmony_ci if (IS_PF(bp) && !bnx2x_wait_sp_comp(bp, ~0x0UL)) { 29068c2ecf20Sopenharmony_ci BNX2X_ERR("Timeout waiting for SP elements to complete\n"); 29078c2ecf20Sopenharmony_ci bnx2x_nic_unload(bp, UNLOAD_CLOSE, false); 29088c2ecf20Sopenharmony_ci return -EBUSY; 29098c2ecf20Sopenharmony_ci } 29108c2ecf20Sopenharmony_ci 29118c2ecf20Sopenharmony_ci /* Update driver data for On-Chip MFW dump. */ 29128c2ecf20Sopenharmony_ci if (IS_PF(bp)) 29138c2ecf20Sopenharmony_ci bnx2x_update_mfw_dump(bp); 29148c2ecf20Sopenharmony_ci 29158c2ecf20Sopenharmony_ci /* If PMF - send ADMIN DCBX msg to MFW to initiate DCBX FSM */ 29168c2ecf20Sopenharmony_ci if (bp->port.pmf && (bp->state != BNX2X_STATE_DIAG)) 29178c2ecf20Sopenharmony_ci bnx2x_dcbx_init(bp, false); 29188c2ecf20Sopenharmony_ci 29198c2ecf20Sopenharmony_ci if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) 29208c2ecf20Sopenharmony_ci bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_ACTIVE); 29218c2ecf20Sopenharmony_ci 29228c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "Ending successfully NIC load\n"); 29238c2ecf20Sopenharmony_ci 29248c2ecf20Sopenharmony_ci return 0; 29258c2ecf20Sopenharmony_ci 29268c2ecf20Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR 29278c2ecf20Sopenharmony_ciload_error3: 29288c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 29298c2ecf20Sopenharmony_ci bnx2x_int_disable_sync(bp, 1); 29308c2ecf20Sopenharmony_ci 29318c2ecf20Sopenharmony_ci /* Clean queueable objects */ 29328c2ecf20Sopenharmony_ci bnx2x_squeeze_objects(bp); 29338c2ecf20Sopenharmony_ci } 29348c2ecf20Sopenharmony_ci 29358c2ecf20Sopenharmony_ci /* Free SKBs, SGEs, TPA pool and driver internals */ 29368c2ecf20Sopenharmony_ci bnx2x_free_skbs(bp); 29378c2ecf20Sopenharmony_ci for_each_rx_queue(bp, i) 29388c2ecf20Sopenharmony_ci bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); 29398c2ecf20Sopenharmony_ci 29408c2ecf20Sopenharmony_ci /* Release IRQs */ 29418c2ecf20Sopenharmony_ci bnx2x_free_irq(bp); 29428c2ecf20Sopenharmony_ciload_error2: 29438c2ecf20Sopenharmony_ci if (IS_PF(bp) && !BP_NOMCP(bp)) { 29448c2ecf20Sopenharmony_ci bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_REQ_WOL_MCP, 0); 29458c2ecf20Sopenharmony_ci bnx2x_fw_command(bp, DRV_MSG_CODE_UNLOAD_DONE, 0); 29468c2ecf20Sopenharmony_ci } 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_ci bp->port.pmf = 0; 29498c2ecf20Sopenharmony_ciload_error1: 29508c2ecf20Sopenharmony_ci bnx2x_napi_disable(bp); 29518c2ecf20Sopenharmony_ci bnx2x_del_all_napi(bp); 29528c2ecf20Sopenharmony_ci 29538c2ecf20Sopenharmony_ci /* clear pf_load status, as it was already set */ 29548c2ecf20Sopenharmony_ci if (IS_PF(bp)) 29558c2ecf20Sopenharmony_ci bnx2x_clear_pf_load(bp); 29568c2ecf20Sopenharmony_ciload_error0: 29578c2ecf20Sopenharmony_ci bnx2x_free_fw_stats_mem(bp); 29588c2ecf20Sopenharmony_ci bnx2x_free_fp_mem(bp); 29598c2ecf20Sopenharmony_ci bnx2x_free_mem(bp); 29608c2ecf20Sopenharmony_ci 29618c2ecf20Sopenharmony_ci return rc; 29628c2ecf20Sopenharmony_ci#endif /* ! BNX2X_STOP_ON_ERROR */ 29638c2ecf20Sopenharmony_ci} 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ciint bnx2x_drain_tx_queues(struct bnx2x *bp) 29668c2ecf20Sopenharmony_ci{ 29678c2ecf20Sopenharmony_ci u8 rc = 0, cos, i; 29688c2ecf20Sopenharmony_ci 29698c2ecf20Sopenharmony_ci /* Wait until tx fastpath tasks complete */ 29708c2ecf20Sopenharmony_ci for_each_tx_queue(bp, i) { 29718c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[i]; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci for_each_cos_in_tx_queue(fp, cos) 29748c2ecf20Sopenharmony_ci rc = bnx2x_clean_tx_queue(bp, fp->txdata_ptr[cos]); 29758c2ecf20Sopenharmony_ci if (rc) 29768c2ecf20Sopenharmony_ci return rc; 29778c2ecf20Sopenharmony_ci } 29788c2ecf20Sopenharmony_ci return 0; 29798c2ecf20Sopenharmony_ci} 29808c2ecf20Sopenharmony_ci 29818c2ecf20Sopenharmony_ci/* must be called with rtnl_lock */ 29828c2ecf20Sopenharmony_ciint bnx2x_nic_unload(struct bnx2x *bp, int unload_mode, bool keep_link) 29838c2ecf20Sopenharmony_ci{ 29848c2ecf20Sopenharmony_ci int i; 29858c2ecf20Sopenharmony_ci bool global = false; 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "Starting NIC unload\n"); 29888c2ecf20Sopenharmony_ci 29898c2ecf20Sopenharmony_ci if (!IS_MF_SD_STORAGE_PERSONALITY_ONLY(bp)) 29908c2ecf20Sopenharmony_ci bnx2x_set_os_driver_state(bp, OS_DRIVER_STATE_DISABLED); 29918c2ecf20Sopenharmony_ci 29928c2ecf20Sopenharmony_ci /* mark driver is unloaded in shmem2 */ 29938c2ecf20Sopenharmony_ci if (IS_PF(bp) && SHMEM2_HAS(bp, drv_capabilities_flag)) { 29948c2ecf20Sopenharmony_ci u32 val; 29958c2ecf20Sopenharmony_ci val = SHMEM2_RD(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)]); 29968c2ecf20Sopenharmony_ci SHMEM2_WR(bp, drv_capabilities_flag[BP_FW_MB_IDX(bp)], 29978c2ecf20Sopenharmony_ci val & ~DRV_FLAGS_CAPABILITIES_LOADED_L2); 29988c2ecf20Sopenharmony_ci } 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci if (IS_PF(bp) && bp->recovery_state != BNX2X_RECOVERY_DONE && 30018c2ecf20Sopenharmony_ci (bp->state == BNX2X_STATE_CLOSED || 30028c2ecf20Sopenharmony_ci bp->state == BNX2X_STATE_ERROR)) { 30038c2ecf20Sopenharmony_ci /* We can get here if the driver has been unloaded 30048c2ecf20Sopenharmony_ci * during parity error recovery and is either waiting for a 30058c2ecf20Sopenharmony_ci * leader to complete or for other functions to unload and 30068c2ecf20Sopenharmony_ci * then ifdown has been issued. In this case we want to 30078c2ecf20Sopenharmony_ci * unload and let other functions to complete a recovery 30088c2ecf20Sopenharmony_ci * process. 30098c2ecf20Sopenharmony_ci */ 30108c2ecf20Sopenharmony_ci bp->recovery_state = BNX2X_RECOVERY_DONE; 30118c2ecf20Sopenharmony_ci bp->is_leader = 0; 30128c2ecf20Sopenharmony_ci bnx2x_release_leader_lock(bp); 30138c2ecf20Sopenharmony_ci smp_mb(); 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFDOWN, "Releasing a leadership...\n"); 30168c2ecf20Sopenharmony_ci BNX2X_ERR("Can't unload in closed or error state\n"); 30178c2ecf20Sopenharmony_ci return -EINVAL; 30188c2ecf20Sopenharmony_ci } 30198c2ecf20Sopenharmony_ci 30208c2ecf20Sopenharmony_ci /* Nothing to do during unload if previous bnx2x_nic_load() 30218c2ecf20Sopenharmony_ci * have not completed successfully - all resources are released. 30228c2ecf20Sopenharmony_ci * 30238c2ecf20Sopenharmony_ci * we can get here only after unsuccessful ndo_* callback, during which 30248c2ecf20Sopenharmony_ci * dev->IFF_UP flag is still on. 30258c2ecf20Sopenharmony_ci */ 30268c2ecf20Sopenharmony_ci if (bp->state == BNX2X_STATE_CLOSED || bp->state == BNX2X_STATE_ERROR) 30278c2ecf20Sopenharmony_ci return 0; 30288c2ecf20Sopenharmony_ci 30298c2ecf20Sopenharmony_ci /* It's important to set the bp->state to the value different from 30308c2ecf20Sopenharmony_ci * BNX2X_STATE_OPEN and only then stop the Tx. Otherwise bnx2x_tx_int() 30318c2ecf20Sopenharmony_ci * may restart the Tx from the NAPI context (see bnx2x_tx_int()). 30328c2ecf20Sopenharmony_ci */ 30338c2ecf20Sopenharmony_ci bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT; 30348c2ecf20Sopenharmony_ci smp_mb(); 30358c2ecf20Sopenharmony_ci 30368c2ecf20Sopenharmony_ci /* indicate to VFs that the PF is going down */ 30378c2ecf20Sopenharmony_ci bnx2x_iov_channel_down(bp); 30388c2ecf20Sopenharmony_ci 30398c2ecf20Sopenharmony_ci if (CNIC_LOADED(bp)) 30408c2ecf20Sopenharmony_ci bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD); 30418c2ecf20Sopenharmony_ci 30428c2ecf20Sopenharmony_ci /* Stop Tx */ 30438c2ecf20Sopenharmony_ci bnx2x_tx_disable(bp); 30448c2ecf20Sopenharmony_ci netdev_reset_tc(bp->dev); 30458c2ecf20Sopenharmony_ci 30468c2ecf20Sopenharmony_ci bp->rx_mode = BNX2X_RX_MODE_NONE; 30478c2ecf20Sopenharmony_ci 30488c2ecf20Sopenharmony_ci del_timer_sync(&bp->timer); 30498c2ecf20Sopenharmony_ci 30508c2ecf20Sopenharmony_ci if (IS_PF(bp) && !BP_NOMCP(bp)) { 30518c2ecf20Sopenharmony_ci /* Set ALWAYS_ALIVE bit in shmem */ 30528c2ecf20Sopenharmony_ci bp->fw_drv_pulse_wr_seq |= DRV_PULSE_ALWAYS_ALIVE; 30538c2ecf20Sopenharmony_ci bnx2x_drv_pulse(bp); 30548c2ecf20Sopenharmony_ci bnx2x_stats_handle(bp, STATS_EVENT_STOP); 30558c2ecf20Sopenharmony_ci bnx2x_save_statistics(bp); 30568c2ecf20Sopenharmony_ci } 30578c2ecf20Sopenharmony_ci 30588c2ecf20Sopenharmony_ci /* wait till consumers catch up with producers in all queues. 30598c2ecf20Sopenharmony_ci * If we're recovering, FW can't write to host so no reason 30608c2ecf20Sopenharmony_ci * to wait for the queues to complete all Tx. 30618c2ecf20Sopenharmony_ci */ 30628c2ecf20Sopenharmony_ci if (unload_mode != UNLOAD_RECOVERY) 30638c2ecf20Sopenharmony_ci bnx2x_drain_tx_queues(bp); 30648c2ecf20Sopenharmony_ci 30658c2ecf20Sopenharmony_ci /* if VF indicate to PF this function is going down (PF will delete sp 30668c2ecf20Sopenharmony_ci * elements and clear initializations 30678c2ecf20Sopenharmony_ci */ 30688c2ecf20Sopenharmony_ci if (IS_VF(bp)) { 30698c2ecf20Sopenharmony_ci bnx2x_clear_vlan_info(bp); 30708c2ecf20Sopenharmony_ci bnx2x_vfpf_close_vf(bp); 30718c2ecf20Sopenharmony_ci } else if (unload_mode != UNLOAD_RECOVERY) { 30728c2ecf20Sopenharmony_ci /* if this is a normal/close unload need to clean up chip*/ 30738c2ecf20Sopenharmony_ci bnx2x_chip_cleanup(bp, unload_mode, keep_link); 30748c2ecf20Sopenharmony_ci } else { 30758c2ecf20Sopenharmony_ci /* Send the UNLOAD_REQUEST to the MCP */ 30768c2ecf20Sopenharmony_ci bnx2x_send_unload_req(bp, unload_mode); 30778c2ecf20Sopenharmony_ci 30788c2ecf20Sopenharmony_ci /* Prevent transactions to host from the functions on the 30798c2ecf20Sopenharmony_ci * engine that doesn't reset global blocks in case of global 30808c2ecf20Sopenharmony_ci * attention once global blocks are reset and gates are opened 30818c2ecf20Sopenharmony_ci * (the engine which leader will perform the recovery 30828c2ecf20Sopenharmony_ci * last). 30838c2ecf20Sopenharmony_ci */ 30848c2ecf20Sopenharmony_ci if (!CHIP_IS_E1x(bp)) 30858c2ecf20Sopenharmony_ci bnx2x_pf_disable(bp); 30868c2ecf20Sopenharmony_ci 30878c2ecf20Sopenharmony_ci /* Disable HW interrupts, NAPI */ 30888c2ecf20Sopenharmony_ci bnx2x_netif_stop(bp, 1); 30898c2ecf20Sopenharmony_ci /* Delete all NAPI objects */ 30908c2ecf20Sopenharmony_ci bnx2x_del_all_napi(bp); 30918c2ecf20Sopenharmony_ci if (CNIC_LOADED(bp)) 30928c2ecf20Sopenharmony_ci bnx2x_del_all_napi_cnic(bp); 30938c2ecf20Sopenharmony_ci /* Release IRQs */ 30948c2ecf20Sopenharmony_ci bnx2x_free_irq(bp); 30958c2ecf20Sopenharmony_ci 30968c2ecf20Sopenharmony_ci /* Report UNLOAD_DONE to MCP */ 30978c2ecf20Sopenharmony_ci bnx2x_send_unload_done(bp, false); 30988c2ecf20Sopenharmony_ci } 30998c2ecf20Sopenharmony_ci 31008c2ecf20Sopenharmony_ci /* 31018c2ecf20Sopenharmony_ci * At this stage no more interrupts will arrive so we may safely clean 31028c2ecf20Sopenharmony_ci * the queueable objects here in case they failed to get cleaned so far. 31038c2ecf20Sopenharmony_ci */ 31048c2ecf20Sopenharmony_ci if (IS_PF(bp)) 31058c2ecf20Sopenharmony_ci bnx2x_squeeze_objects(bp); 31068c2ecf20Sopenharmony_ci 31078c2ecf20Sopenharmony_ci /* There should be no more pending SP commands at this stage */ 31088c2ecf20Sopenharmony_ci bp->sp_state = 0; 31098c2ecf20Sopenharmony_ci 31108c2ecf20Sopenharmony_ci bp->port.pmf = 0; 31118c2ecf20Sopenharmony_ci 31128c2ecf20Sopenharmony_ci /* clear pending work in rtnl task */ 31138c2ecf20Sopenharmony_ci bp->sp_rtnl_state = 0; 31148c2ecf20Sopenharmony_ci smp_mb(); 31158c2ecf20Sopenharmony_ci 31168c2ecf20Sopenharmony_ci /* Free SKBs, SGEs, TPA pool and driver internals */ 31178c2ecf20Sopenharmony_ci bnx2x_free_skbs(bp); 31188c2ecf20Sopenharmony_ci if (CNIC_LOADED(bp)) 31198c2ecf20Sopenharmony_ci bnx2x_free_skbs_cnic(bp); 31208c2ecf20Sopenharmony_ci for_each_rx_queue(bp, i) 31218c2ecf20Sopenharmony_ci bnx2x_free_rx_sge_range(bp, bp->fp + i, NUM_RX_SGE); 31228c2ecf20Sopenharmony_ci 31238c2ecf20Sopenharmony_ci bnx2x_free_fp_mem(bp); 31248c2ecf20Sopenharmony_ci if (CNIC_LOADED(bp)) 31258c2ecf20Sopenharmony_ci bnx2x_free_fp_mem_cnic(bp); 31268c2ecf20Sopenharmony_ci 31278c2ecf20Sopenharmony_ci if (IS_PF(bp)) { 31288c2ecf20Sopenharmony_ci if (CNIC_LOADED(bp)) 31298c2ecf20Sopenharmony_ci bnx2x_free_mem_cnic(bp); 31308c2ecf20Sopenharmony_ci } 31318c2ecf20Sopenharmony_ci bnx2x_free_mem(bp); 31328c2ecf20Sopenharmony_ci 31338c2ecf20Sopenharmony_ci bp->state = BNX2X_STATE_CLOSED; 31348c2ecf20Sopenharmony_ci bp->cnic_loaded = false; 31358c2ecf20Sopenharmony_ci 31368c2ecf20Sopenharmony_ci /* Clear driver version indication in shmem */ 31378c2ecf20Sopenharmony_ci if (IS_PF(bp) && !BP_NOMCP(bp)) 31388c2ecf20Sopenharmony_ci bnx2x_update_mng_version(bp); 31398c2ecf20Sopenharmony_ci 31408c2ecf20Sopenharmony_ci /* Check if there are pending parity attentions. If there are - set 31418c2ecf20Sopenharmony_ci * RECOVERY_IN_PROGRESS. 31428c2ecf20Sopenharmony_ci */ 31438c2ecf20Sopenharmony_ci if (IS_PF(bp) && bnx2x_chk_parity_attn(bp, &global, false)) { 31448c2ecf20Sopenharmony_ci bnx2x_set_reset_in_progress(bp); 31458c2ecf20Sopenharmony_ci 31468c2ecf20Sopenharmony_ci /* Set RESET_IS_GLOBAL if needed */ 31478c2ecf20Sopenharmony_ci if (global) 31488c2ecf20Sopenharmony_ci bnx2x_set_reset_global(bp); 31498c2ecf20Sopenharmony_ci } 31508c2ecf20Sopenharmony_ci 31518c2ecf20Sopenharmony_ci /* The last driver must disable a "close the gate" if there is no 31528c2ecf20Sopenharmony_ci * parity attention or "process kill" pending. 31538c2ecf20Sopenharmony_ci */ 31548c2ecf20Sopenharmony_ci if (IS_PF(bp) && 31558c2ecf20Sopenharmony_ci !bnx2x_clear_pf_load(bp) && 31568c2ecf20Sopenharmony_ci bnx2x_reset_is_done(bp, BP_PATH(bp))) 31578c2ecf20Sopenharmony_ci bnx2x_disable_close_the_gate(bp); 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, "Ending NIC unload\n"); 31608c2ecf20Sopenharmony_ci 31618c2ecf20Sopenharmony_ci return 0; 31628c2ecf20Sopenharmony_ci} 31638c2ecf20Sopenharmony_ci 31648c2ecf20Sopenharmony_ciint bnx2x_set_power_state(struct bnx2x *bp, pci_power_t state) 31658c2ecf20Sopenharmony_ci{ 31668c2ecf20Sopenharmony_ci u16 pmcsr; 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ci /* If there is no power capability, silently succeed */ 31698c2ecf20Sopenharmony_ci if (!bp->pdev->pm_cap) { 31708c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("No power capability. Breaking.\n"); 31718c2ecf20Sopenharmony_ci return 0; 31728c2ecf20Sopenharmony_ci } 31738c2ecf20Sopenharmony_ci 31748c2ecf20Sopenharmony_ci pci_read_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_CTRL, &pmcsr); 31758c2ecf20Sopenharmony_ci 31768c2ecf20Sopenharmony_ci switch (state) { 31778c2ecf20Sopenharmony_ci case PCI_D0: 31788c2ecf20Sopenharmony_ci pci_write_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_CTRL, 31798c2ecf20Sopenharmony_ci ((pmcsr & ~PCI_PM_CTRL_STATE_MASK) | 31808c2ecf20Sopenharmony_ci PCI_PM_CTRL_PME_STATUS)); 31818c2ecf20Sopenharmony_ci 31828c2ecf20Sopenharmony_ci if (pmcsr & PCI_PM_CTRL_STATE_MASK) 31838c2ecf20Sopenharmony_ci /* delay required during transition out of D3hot */ 31848c2ecf20Sopenharmony_ci msleep(20); 31858c2ecf20Sopenharmony_ci break; 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci case PCI_D3hot: 31888c2ecf20Sopenharmony_ci /* If there are other clients above don't 31898c2ecf20Sopenharmony_ci shut down the power */ 31908c2ecf20Sopenharmony_ci if (atomic_read(&bp->pdev->enable_cnt) != 1) 31918c2ecf20Sopenharmony_ci return 0; 31928c2ecf20Sopenharmony_ci /* Don't shut down the power for emulation and FPGA */ 31938c2ecf20Sopenharmony_ci if (CHIP_REV_IS_SLOW(bp)) 31948c2ecf20Sopenharmony_ci return 0; 31958c2ecf20Sopenharmony_ci 31968c2ecf20Sopenharmony_ci pmcsr &= ~PCI_PM_CTRL_STATE_MASK; 31978c2ecf20Sopenharmony_ci pmcsr |= 3; 31988c2ecf20Sopenharmony_ci 31998c2ecf20Sopenharmony_ci if (bp->wol) 32008c2ecf20Sopenharmony_ci pmcsr |= PCI_PM_CTRL_PME_ENABLE; 32018c2ecf20Sopenharmony_ci 32028c2ecf20Sopenharmony_ci pci_write_config_word(bp->pdev, bp->pdev->pm_cap + PCI_PM_CTRL, 32038c2ecf20Sopenharmony_ci pmcsr); 32048c2ecf20Sopenharmony_ci 32058c2ecf20Sopenharmony_ci /* No more memory access after this point until 32068c2ecf20Sopenharmony_ci * device is brought back to D0. 32078c2ecf20Sopenharmony_ci */ 32088c2ecf20Sopenharmony_ci break; 32098c2ecf20Sopenharmony_ci 32108c2ecf20Sopenharmony_ci default: 32118c2ecf20Sopenharmony_ci dev_err(&bp->pdev->dev, "Can't support state = %d\n", state); 32128c2ecf20Sopenharmony_ci return -EINVAL; 32138c2ecf20Sopenharmony_ci } 32148c2ecf20Sopenharmony_ci return 0; 32158c2ecf20Sopenharmony_ci} 32168c2ecf20Sopenharmony_ci 32178c2ecf20Sopenharmony_ci/* 32188c2ecf20Sopenharmony_ci * net_device service functions 32198c2ecf20Sopenharmony_ci */ 32208c2ecf20Sopenharmony_cistatic int bnx2x_poll(struct napi_struct *napi, int budget) 32218c2ecf20Sopenharmony_ci{ 32228c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = container_of(napi, struct bnx2x_fastpath, 32238c2ecf20Sopenharmony_ci napi); 32248c2ecf20Sopenharmony_ci struct bnx2x *bp = fp->bp; 32258c2ecf20Sopenharmony_ci int rx_work_done; 32268c2ecf20Sopenharmony_ci u8 cos; 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 32298c2ecf20Sopenharmony_ci if (unlikely(bp->panic)) { 32308c2ecf20Sopenharmony_ci napi_complete(napi); 32318c2ecf20Sopenharmony_ci return 0; 32328c2ecf20Sopenharmony_ci } 32338c2ecf20Sopenharmony_ci#endif 32348c2ecf20Sopenharmony_ci for_each_cos_in_tx_queue(fp, cos) 32358c2ecf20Sopenharmony_ci if (bnx2x_tx_queue_has_work(fp->txdata_ptr[cos])) 32368c2ecf20Sopenharmony_ci bnx2x_tx_int(bp, fp->txdata_ptr[cos]); 32378c2ecf20Sopenharmony_ci 32388c2ecf20Sopenharmony_ci rx_work_done = (bnx2x_has_rx_work(fp)) ? bnx2x_rx_int(fp, budget) : 0; 32398c2ecf20Sopenharmony_ci 32408c2ecf20Sopenharmony_ci if (rx_work_done < budget) { 32418c2ecf20Sopenharmony_ci /* No need to update SB for FCoE L2 ring as long as 32428c2ecf20Sopenharmony_ci * it's connected to the default SB and the SB 32438c2ecf20Sopenharmony_ci * has been updated when NAPI was scheduled. 32448c2ecf20Sopenharmony_ci */ 32458c2ecf20Sopenharmony_ci if (IS_FCOE_FP(fp)) { 32468c2ecf20Sopenharmony_ci napi_complete_done(napi, rx_work_done); 32478c2ecf20Sopenharmony_ci } else { 32488c2ecf20Sopenharmony_ci bnx2x_update_fpsb_idx(fp); 32498c2ecf20Sopenharmony_ci /* bnx2x_has_rx_work() reads the status block, 32508c2ecf20Sopenharmony_ci * thus we need to ensure that status block indices 32518c2ecf20Sopenharmony_ci * have been actually read (bnx2x_update_fpsb_idx) 32528c2ecf20Sopenharmony_ci * prior to this check (bnx2x_has_rx_work) so that 32538c2ecf20Sopenharmony_ci * we won't write the "newer" value of the status block 32548c2ecf20Sopenharmony_ci * to IGU (if there was a DMA right after 32558c2ecf20Sopenharmony_ci * bnx2x_has_rx_work and if there is no rmb, the memory 32568c2ecf20Sopenharmony_ci * reading (bnx2x_update_fpsb_idx) may be postponed 32578c2ecf20Sopenharmony_ci * to right before bnx2x_ack_sb). In this case there 32588c2ecf20Sopenharmony_ci * will never be another interrupt until there is 32598c2ecf20Sopenharmony_ci * another update of the status block, while there 32608c2ecf20Sopenharmony_ci * is still unhandled work. 32618c2ecf20Sopenharmony_ci */ 32628c2ecf20Sopenharmony_ci rmb(); 32638c2ecf20Sopenharmony_ci 32648c2ecf20Sopenharmony_ci if (!(bnx2x_has_rx_work(fp) || bnx2x_has_tx_work(fp))) { 32658c2ecf20Sopenharmony_ci if (napi_complete_done(napi, rx_work_done)) { 32668c2ecf20Sopenharmony_ci /* Re-enable interrupts */ 32678c2ecf20Sopenharmony_ci DP(NETIF_MSG_RX_STATUS, 32688c2ecf20Sopenharmony_ci "Update index to %d\n", fp->fp_hc_idx); 32698c2ecf20Sopenharmony_ci bnx2x_ack_sb(bp, fp->igu_sb_id, USTORM_ID, 32708c2ecf20Sopenharmony_ci le16_to_cpu(fp->fp_hc_idx), 32718c2ecf20Sopenharmony_ci IGU_INT_ENABLE, 1); 32728c2ecf20Sopenharmony_ci } 32738c2ecf20Sopenharmony_ci } else { 32748c2ecf20Sopenharmony_ci rx_work_done = budget; 32758c2ecf20Sopenharmony_ci } 32768c2ecf20Sopenharmony_ci } 32778c2ecf20Sopenharmony_ci } 32788c2ecf20Sopenharmony_ci 32798c2ecf20Sopenharmony_ci return rx_work_done; 32808c2ecf20Sopenharmony_ci} 32818c2ecf20Sopenharmony_ci 32828c2ecf20Sopenharmony_ci/* we split the first BD into headers and data BDs 32838c2ecf20Sopenharmony_ci * to ease the pain of our fellow microcode engineers 32848c2ecf20Sopenharmony_ci * we use one mapping for both BDs 32858c2ecf20Sopenharmony_ci */ 32868c2ecf20Sopenharmony_cistatic u16 bnx2x_tx_split(struct bnx2x *bp, 32878c2ecf20Sopenharmony_ci struct bnx2x_fp_txdata *txdata, 32888c2ecf20Sopenharmony_ci struct sw_tx_bd *tx_buf, 32898c2ecf20Sopenharmony_ci struct eth_tx_start_bd **tx_bd, u16 hlen, 32908c2ecf20Sopenharmony_ci u16 bd_prod) 32918c2ecf20Sopenharmony_ci{ 32928c2ecf20Sopenharmony_ci struct eth_tx_start_bd *h_tx_bd = *tx_bd; 32938c2ecf20Sopenharmony_ci struct eth_tx_bd *d_tx_bd; 32948c2ecf20Sopenharmony_ci dma_addr_t mapping; 32958c2ecf20Sopenharmony_ci int old_len = le16_to_cpu(h_tx_bd->nbytes); 32968c2ecf20Sopenharmony_ci 32978c2ecf20Sopenharmony_ci /* first fix first BD */ 32988c2ecf20Sopenharmony_ci h_tx_bd->nbytes = cpu_to_le16(hlen); 32998c2ecf20Sopenharmony_ci 33008c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, "TSO split header size is %d (%x:%x)\n", 33018c2ecf20Sopenharmony_ci h_tx_bd->nbytes, h_tx_bd->addr_hi, h_tx_bd->addr_lo); 33028c2ecf20Sopenharmony_ci 33038c2ecf20Sopenharmony_ci /* now get a new data BD 33048c2ecf20Sopenharmony_ci * (after the pbd) and fill it */ 33058c2ecf20Sopenharmony_ci bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); 33068c2ecf20Sopenharmony_ci d_tx_bd = &txdata->tx_desc_ring[bd_prod].reg_bd; 33078c2ecf20Sopenharmony_ci 33088c2ecf20Sopenharmony_ci mapping = HILO_U64(le32_to_cpu(h_tx_bd->addr_hi), 33098c2ecf20Sopenharmony_ci le32_to_cpu(h_tx_bd->addr_lo)) + hlen; 33108c2ecf20Sopenharmony_ci 33118c2ecf20Sopenharmony_ci d_tx_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); 33128c2ecf20Sopenharmony_ci d_tx_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); 33138c2ecf20Sopenharmony_ci d_tx_bd->nbytes = cpu_to_le16(old_len - hlen); 33148c2ecf20Sopenharmony_ci 33158c2ecf20Sopenharmony_ci /* this marks the BD as one that has no individual mapping */ 33168c2ecf20Sopenharmony_ci tx_buf->flags |= BNX2X_TSO_SPLIT_BD; 33178c2ecf20Sopenharmony_ci 33188c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 33198c2ecf20Sopenharmony_ci "TSO split data size is %d (%x:%x)\n", 33208c2ecf20Sopenharmony_ci d_tx_bd->nbytes, d_tx_bd->addr_hi, d_tx_bd->addr_lo); 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci /* update tx_bd */ 33238c2ecf20Sopenharmony_ci *tx_bd = (struct eth_tx_start_bd *)d_tx_bd; 33248c2ecf20Sopenharmony_ci 33258c2ecf20Sopenharmony_ci return bd_prod; 33268c2ecf20Sopenharmony_ci} 33278c2ecf20Sopenharmony_ci 33288c2ecf20Sopenharmony_ci#define bswab32(b32) ((__force __le32) swab32((__force __u32) (b32))) 33298c2ecf20Sopenharmony_ci#define bswab16(b16) ((__force __le16) swab16((__force __u16) (b16))) 33308c2ecf20Sopenharmony_cistatic __le16 bnx2x_csum_fix(unsigned char *t_header, u16 csum, s8 fix) 33318c2ecf20Sopenharmony_ci{ 33328c2ecf20Sopenharmony_ci __sum16 tsum = (__force __sum16) csum; 33338c2ecf20Sopenharmony_ci 33348c2ecf20Sopenharmony_ci if (fix > 0) 33358c2ecf20Sopenharmony_ci tsum = ~csum_fold(csum_sub((__force __wsum) csum, 33368c2ecf20Sopenharmony_ci csum_partial(t_header - fix, fix, 0))); 33378c2ecf20Sopenharmony_ci 33388c2ecf20Sopenharmony_ci else if (fix < 0) 33398c2ecf20Sopenharmony_ci tsum = ~csum_fold(csum_add((__force __wsum) csum, 33408c2ecf20Sopenharmony_ci csum_partial(t_header, -fix, 0))); 33418c2ecf20Sopenharmony_ci 33428c2ecf20Sopenharmony_ci return bswab16(tsum); 33438c2ecf20Sopenharmony_ci} 33448c2ecf20Sopenharmony_ci 33458c2ecf20Sopenharmony_cistatic u32 bnx2x_xmit_type(struct bnx2x *bp, struct sk_buff *skb) 33468c2ecf20Sopenharmony_ci{ 33478c2ecf20Sopenharmony_ci u32 rc; 33488c2ecf20Sopenharmony_ci __u8 prot = 0; 33498c2ecf20Sopenharmony_ci __be16 protocol; 33508c2ecf20Sopenharmony_ci 33518c2ecf20Sopenharmony_ci if (skb->ip_summed != CHECKSUM_PARTIAL) 33528c2ecf20Sopenharmony_ci return XMIT_PLAIN; 33538c2ecf20Sopenharmony_ci 33548c2ecf20Sopenharmony_ci protocol = vlan_get_protocol(skb); 33558c2ecf20Sopenharmony_ci if (protocol == htons(ETH_P_IPV6)) { 33568c2ecf20Sopenharmony_ci rc = XMIT_CSUM_V6; 33578c2ecf20Sopenharmony_ci prot = ipv6_hdr(skb)->nexthdr; 33588c2ecf20Sopenharmony_ci } else { 33598c2ecf20Sopenharmony_ci rc = XMIT_CSUM_V4; 33608c2ecf20Sopenharmony_ci prot = ip_hdr(skb)->protocol; 33618c2ecf20Sopenharmony_ci } 33628c2ecf20Sopenharmony_ci 33638c2ecf20Sopenharmony_ci if (!CHIP_IS_E1x(bp) && skb->encapsulation) { 33648c2ecf20Sopenharmony_ci if (inner_ip_hdr(skb)->version == 6) { 33658c2ecf20Sopenharmony_ci rc |= XMIT_CSUM_ENC_V6; 33668c2ecf20Sopenharmony_ci if (inner_ipv6_hdr(skb)->nexthdr == IPPROTO_TCP) 33678c2ecf20Sopenharmony_ci rc |= XMIT_CSUM_TCP; 33688c2ecf20Sopenharmony_ci } else { 33698c2ecf20Sopenharmony_ci rc |= XMIT_CSUM_ENC_V4; 33708c2ecf20Sopenharmony_ci if (inner_ip_hdr(skb)->protocol == IPPROTO_TCP) 33718c2ecf20Sopenharmony_ci rc |= XMIT_CSUM_TCP; 33728c2ecf20Sopenharmony_ci } 33738c2ecf20Sopenharmony_ci } 33748c2ecf20Sopenharmony_ci if (prot == IPPROTO_TCP) 33758c2ecf20Sopenharmony_ci rc |= XMIT_CSUM_TCP; 33768c2ecf20Sopenharmony_ci 33778c2ecf20Sopenharmony_ci if (skb_is_gso(skb)) { 33788c2ecf20Sopenharmony_ci if (skb_is_gso_v6(skb)) { 33798c2ecf20Sopenharmony_ci rc |= (XMIT_GSO_V6 | XMIT_CSUM_TCP); 33808c2ecf20Sopenharmony_ci if (rc & XMIT_CSUM_ENC) 33818c2ecf20Sopenharmony_ci rc |= XMIT_GSO_ENC_V6; 33828c2ecf20Sopenharmony_ci } else { 33838c2ecf20Sopenharmony_ci rc |= (XMIT_GSO_V4 | XMIT_CSUM_TCP); 33848c2ecf20Sopenharmony_ci if (rc & XMIT_CSUM_ENC) 33858c2ecf20Sopenharmony_ci rc |= XMIT_GSO_ENC_V4; 33868c2ecf20Sopenharmony_ci } 33878c2ecf20Sopenharmony_ci } 33888c2ecf20Sopenharmony_ci 33898c2ecf20Sopenharmony_ci return rc; 33908c2ecf20Sopenharmony_ci} 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci/* VXLAN: 4 = 1 (for linear data BD) + 3 (2 for PBD and last BD) */ 33938c2ecf20Sopenharmony_ci#define BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS 4 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci/* Regular: 3 = 1 (for linear data BD) + 2 (for PBD and last BD) */ 33968c2ecf20Sopenharmony_ci#define BNX2X_NUM_TSO_WIN_SUB_BDS 3 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ci#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - BDS_PER_TX_PKT) 33998c2ecf20Sopenharmony_ci/* check if packet requires linearization (packet is too fragmented) 34008c2ecf20Sopenharmony_ci no need to check fragmentation if page size > 8K (there will be no 34018c2ecf20Sopenharmony_ci violation to FW restrictions) */ 34028c2ecf20Sopenharmony_cistatic int bnx2x_pkt_req_lin(struct bnx2x *bp, struct sk_buff *skb, 34038c2ecf20Sopenharmony_ci u32 xmit_type) 34048c2ecf20Sopenharmony_ci{ 34058c2ecf20Sopenharmony_ci int first_bd_sz = 0, num_tso_win_sub = BNX2X_NUM_TSO_WIN_SUB_BDS; 34068c2ecf20Sopenharmony_ci int to_copy = 0, hlen = 0; 34078c2ecf20Sopenharmony_ci 34088c2ecf20Sopenharmony_ci if (xmit_type & XMIT_GSO_ENC) 34098c2ecf20Sopenharmony_ci num_tso_win_sub = BNX2X_NUM_VXLAN_TSO_WIN_SUB_BDS; 34108c2ecf20Sopenharmony_ci 34118c2ecf20Sopenharmony_ci if (skb_shinfo(skb)->nr_frags >= (MAX_FETCH_BD - num_tso_win_sub)) { 34128c2ecf20Sopenharmony_ci if (xmit_type & XMIT_GSO) { 34138c2ecf20Sopenharmony_ci unsigned short lso_mss = skb_shinfo(skb)->gso_size; 34148c2ecf20Sopenharmony_ci int wnd_size = MAX_FETCH_BD - num_tso_win_sub; 34158c2ecf20Sopenharmony_ci /* Number of windows to check */ 34168c2ecf20Sopenharmony_ci int num_wnds = skb_shinfo(skb)->nr_frags - wnd_size; 34178c2ecf20Sopenharmony_ci int wnd_idx = 0; 34188c2ecf20Sopenharmony_ci int frag_idx = 0; 34198c2ecf20Sopenharmony_ci u32 wnd_sum = 0; 34208c2ecf20Sopenharmony_ci 34218c2ecf20Sopenharmony_ci /* Headers length */ 34228c2ecf20Sopenharmony_ci if (xmit_type & XMIT_GSO_ENC) 34238c2ecf20Sopenharmony_ci hlen = (int)(skb_inner_transport_header(skb) - 34248c2ecf20Sopenharmony_ci skb->data) + 34258c2ecf20Sopenharmony_ci inner_tcp_hdrlen(skb); 34268c2ecf20Sopenharmony_ci else 34278c2ecf20Sopenharmony_ci hlen = (int)(skb_transport_header(skb) - 34288c2ecf20Sopenharmony_ci skb->data) + tcp_hdrlen(skb); 34298c2ecf20Sopenharmony_ci 34308c2ecf20Sopenharmony_ci /* Amount of data (w/o headers) on linear part of SKB*/ 34318c2ecf20Sopenharmony_ci first_bd_sz = skb_headlen(skb) - hlen; 34328c2ecf20Sopenharmony_ci 34338c2ecf20Sopenharmony_ci wnd_sum = first_bd_sz; 34348c2ecf20Sopenharmony_ci 34358c2ecf20Sopenharmony_ci /* Calculate the first sum - it's special */ 34368c2ecf20Sopenharmony_ci for (frag_idx = 0; frag_idx < wnd_size - 1; frag_idx++) 34378c2ecf20Sopenharmony_ci wnd_sum += 34388c2ecf20Sopenharmony_ci skb_frag_size(&skb_shinfo(skb)->frags[frag_idx]); 34398c2ecf20Sopenharmony_ci 34408c2ecf20Sopenharmony_ci /* If there was data on linear skb data - check it */ 34418c2ecf20Sopenharmony_ci if (first_bd_sz > 0) { 34428c2ecf20Sopenharmony_ci if (unlikely(wnd_sum < lso_mss)) { 34438c2ecf20Sopenharmony_ci to_copy = 1; 34448c2ecf20Sopenharmony_ci goto exit_lbl; 34458c2ecf20Sopenharmony_ci } 34468c2ecf20Sopenharmony_ci 34478c2ecf20Sopenharmony_ci wnd_sum -= first_bd_sz; 34488c2ecf20Sopenharmony_ci } 34498c2ecf20Sopenharmony_ci 34508c2ecf20Sopenharmony_ci /* Others are easier: run through the frag list and 34518c2ecf20Sopenharmony_ci check all windows */ 34528c2ecf20Sopenharmony_ci for (wnd_idx = 0; wnd_idx <= num_wnds; wnd_idx++) { 34538c2ecf20Sopenharmony_ci wnd_sum += 34548c2ecf20Sopenharmony_ci skb_frag_size(&skb_shinfo(skb)->frags[wnd_idx + wnd_size - 1]); 34558c2ecf20Sopenharmony_ci 34568c2ecf20Sopenharmony_ci if (unlikely(wnd_sum < lso_mss)) { 34578c2ecf20Sopenharmony_ci to_copy = 1; 34588c2ecf20Sopenharmony_ci break; 34598c2ecf20Sopenharmony_ci } 34608c2ecf20Sopenharmony_ci wnd_sum -= 34618c2ecf20Sopenharmony_ci skb_frag_size(&skb_shinfo(skb)->frags[wnd_idx]); 34628c2ecf20Sopenharmony_ci } 34638c2ecf20Sopenharmony_ci } else { 34648c2ecf20Sopenharmony_ci /* in non-LSO too fragmented packet should always 34658c2ecf20Sopenharmony_ci be linearized */ 34668c2ecf20Sopenharmony_ci to_copy = 1; 34678c2ecf20Sopenharmony_ci } 34688c2ecf20Sopenharmony_ci } 34698c2ecf20Sopenharmony_ci 34708c2ecf20Sopenharmony_ciexit_lbl: 34718c2ecf20Sopenharmony_ci if (unlikely(to_copy)) 34728c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 34738c2ecf20Sopenharmony_ci "Linearization IS REQUIRED for %s packet. num_frags %d hlen %d first_bd_sz %d\n", 34748c2ecf20Sopenharmony_ci (xmit_type & XMIT_GSO) ? "LSO" : "non-LSO", 34758c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags, hlen, first_bd_sz); 34768c2ecf20Sopenharmony_ci 34778c2ecf20Sopenharmony_ci return to_copy; 34788c2ecf20Sopenharmony_ci} 34798c2ecf20Sopenharmony_ci#endif 34808c2ecf20Sopenharmony_ci 34818c2ecf20Sopenharmony_ci/** 34828c2ecf20Sopenharmony_ci * bnx2x_set_pbd_gso - update PBD in GSO case. 34838c2ecf20Sopenharmony_ci * 34848c2ecf20Sopenharmony_ci * @skb: packet skb 34858c2ecf20Sopenharmony_ci * @pbd: parse BD 34868c2ecf20Sopenharmony_ci * @xmit_type: xmit flags 34878c2ecf20Sopenharmony_ci */ 34888c2ecf20Sopenharmony_cistatic void bnx2x_set_pbd_gso(struct sk_buff *skb, 34898c2ecf20Sopenharmony_ci struct eth_tx_parse_bd_e1x *pbd, 34908c2ecf20Sopenharmony_ci u32 xmit_type) 34918c2ecf20Sopenharmony_ci{ 34928c2ecf20Sopenharmony_ci pbd->lso_mss = cpu_to_le16(skb_shinfo(skb)->gso_size); 34938c2ecf20Sopenharmony_ci pbd->tcp_send_seq = bswab32(tcp_hdr(skb)->seq); 34948c2ecf20Sopenharmony_ci pbd->tcp_flags = pbd_tcp_flags(tcp_hdr(skb)); 34958c2ecf20Sopenharmony_ci 34968c2ecf20Sopenharmony_ci if (xmit_type & XMIT_GSO_V4) { 34978c2ecf20Sopenharmony_ci pbd->ip_id = bswab16(ip_hdr(skb)->id); 34988c2ecf20Sopenharmony_ci pbd->tcp_pseudo_csum = 34998c2ecf20Sopenharmony_ci bswab16(~csum_tcpudp_magic(ip_hdr(skb)->saddr, 35008c2ecf20Sopenharmony_ci ip_hdr(skb)->daddr, 35018c2ecf20Sopenharmony_ci 0, IPPROTO_TCP, 0)); 35028c2ecf20Sopenharmony_ci } else { 35038c2ecf20Sopenharmony_ci pbd->tcp_pseudo_csum = 35048c2ecf20Sopenharmony_ci bswab16(~csum_ipv6_magic(&ipv6_hdr(skb)->saddr, 35058c2ecf20Sopenharmony_ci &ipv6_hdr(skb)->daddr, 35068c2ecf20Sopenharmony_ci 0, IPPROTO_TCP, 0)); 35078c2ecf20Sopenharmony_ci } 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_ci pbd->global_data |= 35108c2ecf20Sopenharmony_ci cpu_to_le16(ETH_TX_PARSE_BD_E1X_PSEUDO_CS_WITHOUT_LEN); 35118c2ecf20Sopenharmony_ci} 35128c2ecf20Sopenharmony_ci 35138c2ecf20Sopenharmony_ci/** 35148c2ecf20Sopenharmony_ci * bnx2x_set_pbd_csum_enc - update PBD with checksum and return header length 35158c2ecf20Sopenharmony_ci * 35168c2ecf20Sopenharmony_ci * @bp: driver handle 35178c2ecf20Sopenharmony_ci * @skb: packet skb 35188c2ecf20Sopenharmony_ci * @parsing_data: data to be updated 35198c2ecf20Sopenharmony_ci * @xmit_type: xmit flags 35208c2ecf20Sopenharmony_ci * 35218c2ecf20Sopenharmony_ci * 57712/578xx related, when skb has encapsulation 35228c2ecf20Sopenharmony_ci */ 35238c2ecf20Sopenharmony_cistatic u8 bnx2x_set_pbd_csum_enc(struct bnx2x *bp, struct sk_buff *skb, 35248c2ecf20Sopenharmony_ci u32 *parsing_data, u32 xmit_type) 35258c2ecf20Sopenharmony_ci{ 35268c2ecf20Sopenharmony_ci *parsing_data |= 35278c2ecf20Sopenharmony_ci ((((u8 *)skb_inner_transport_header(skb) - skb->data) >> 1) << 35288c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W_SHIFT) & 35298c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W; 35308c2ecf20Sopenharmony_ci 35318c2ecf20Sopenharmony_ci if (xmit_type & XMIT_CSUM_TCP) { 35328c2ecf20Sopenharmony_ci *parsing_data |= ((inner_tcp_hdrlen(skb) / 4) << 35338c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & 35348c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; 35358c2ecf20Sopenharmony_ci 35368c2ecf20Sopenharmony_ci return skb_inner_transport_header(skb) + 35378c2ecf20Sopenharmony_ci inner_tcp_hdrlen(skb) - skb->data; 35388c2ecf20Sopenharmony_ci } 35398c2ecf20Sopenharmony_ci 35408c2ecf20Sopenharmony_ci /* We support checksum offload for TCP and UDP only. 35418c2ecf20Sopenharmony_ci * No need to pass the UDP header length - it's a constant. 35428c2ecf20Sopenharmony_ci */ 35438c2ecf20Sopenharmony_ci return skb_inner_transport_header(skb) + 35448c2ecf20Sopenharmony_ci sizeof(struct udphdr) - skb->data; 35458c2ecf20Sopenharmony_ci} 35468c2ecf20Sopenharmony_ci 35478c2ecf20Sopenharmony_ci/** 35488c2ecf20Sopenharmony_ci * bnx2x_set_pbd_csum_e2 - update PBD with checksum and return header length 35498c2ecf20Sopenharmony_ci * 35508c2ecf20Sopenharmony_ci * @bp: driver handle 35518c2ecf20Sopenharmony_ci * @skb: packet skb 35528c2ecf20Sopenharmony_ci * @parsing_data: data to be updated 35538c2ecf20Sopenharmony_ci * @xmit_type: xmit flags 35548c2ecf20Sopenharmony_ci * 35558c2ecf20Sopenharmony_ci * 57712/578xx related 35568c2ecf20Sopenharmony_ci */ 35578c2ecf20Sopenharmony_cistatic u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb, 35588c2ecf20Sopenharmony_ci u32 *parsing_data, u32 xmit_type) 35598c2ecf20Sopenharmony_ci{ 35608c2ecf20Sopenharmony_ci *parsing_data |= 35618c2ecf20Sopenharmony_ci ((((u8 *)skb_transport_header(skb) - skb->data) >> 1) << 35628c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W_SHIFT) & 35638c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_L4_HDR_START_OFFSET_W; 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_ci if (xmit_type & XMIT_CSUM_TCP) { 35668c2ecf20Sopenharmony_ci *parsing_data |= ((tcp_hdrlen(skb) / 4) << 35678c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) & 35688c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW; 35698c2ecf20Sopenharmony_ci 35708c2ecf20Sopenharmony_ci return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data; 35718c2ecf20Sopenharmony_ci } 35728c2ecf20Sopenharmony_ci /* We support checksum offload for TCP and UDP only. 35738c2ecf20Sopenharmony_ci * No need to pass the UDP header length - it's a constant. 35748c2ecf20Sopenharmony_ci */ 35758c2ecf20Sopenharmony_ci return skb_transport_header(skb) + sizeof(struct udphdr) - skb->data; 35768c2ecf20Sopenharmony_ci} 35778c2ecf20Sopenharmony_ci 35788c2ecf20Sopenharmony_ci/* set FW indication according to inner or outer protocols if tunneled */ 35798c2ecf20Sopenharmony_cistatic void bnx2x_set_sbd_csum(struct bnx2x *bp, struct sk_buff *skb, 35808c2ecf20Sopenharmony_ci struct eth_tx_start_bd *tx_start_bd, 35818c2ecf20Sopenharmony_ci u32 xmit_type) 35828c2ecf20Sopenharmony_ci{ 35838c2ecf20Sopenharmony_ci tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_L4_CSUM; 35848c2ecf20Sopenharmony_ci 35858c2ecf20Sopenharmony_ci if (xmit_type & (XMIT_CSUM_ENC_V6 | XMIT_CSUM_V6)) 35868c2ecf20Sopenharmony_ci tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IPV6; 35878c2ecf20Sopenharmony_ci 35888c2ecf20Sopenharmony_ci if (!(xmit_type & XMIT_CSUM_TCP)) 35898c2ecf20Sopenharmony_ci tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_IS_UDP; 35908c2ecf20Sopenharmony_ci} 35918c2ecf20Sopenharmony_ci 35928c2ecf20Sopenharmony_ci/** 35938c2ecf20Sopenharmony_ci * bnx2x_set_pbd_csum - update PBD with checksum and return header length 35948c2ecf20Sopenharmony_ci * 35958c2ecf20Sopenharmony_ci * @bp: driver handle 35968c2ecf20Sopenharmony_ci * @skb: packet skb 35978c2ecf20Sopenharmony_ci * @pbd: parse BD to be updated 35988c2ecf20Sopenharmony_ci * @xmit_type: xmit flags 35998c2ecf20Sopenharmony_ci */ 36008c2ecf20Sopenharmony_cistatic u8 bnx2x_set_pbd_csum(struct bnx2x *bp, struct sk_buff *skb, 36018c2ecf20Sopenharmony_ci struct eth_tx_parse_bd_e1x *pbd, 36028c2ecf20Sopenharmony_ci u32 xmit_type) 36038c2ecf20Sopenharmony_ci{ 36048c2ecf20Sopenharmony_ci u8 hlen = (skb_network_header(skb) - skb->data) >> 1; 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci /* for now NS flag is not used in Linux */ 36078c2ecf20Sopenharmony_ci pbd->global_data = 36088c2ecf20Sopenharmony_ci cpu_to_le16(hlen | 36098c2ecf20Sopenharmony_ci ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) << 36108c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E1X_LLC_SNAP_EN_SHIFT)); 36118c2ecf20Sopenharmony_ci 36128c2ecf20Sopenharmony_ci pbd->ip_hlen_w = (skb_transport_header(skb) - 36138c2ecf20Sopenharmony_ci skb_network_header(skb)) >> 1; 36148c2ecf20Sopenharmony_ci 36158c2ecf20Sopenharmony_ci hlen += pbd->ip_hlen_w; 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci /* We support checksum offload for TCP and UDP only */ 36188c2ecf20Sopenharmony_ci if (xmit_type & XMIT_CSUM_TCP) 36198c2ecf20Sopenharmony_ci hlen += tcp_hdrlen(skb) / 2; 36208c2ecf20Sopenharmony_ci else 36218c2ecf20Sopenharmony_ci hlen += sizeof(struct udphdr) / 2; 36228c2ecf20Sopenharmony_ci 36238c2ecf20Sopenharmony_ci pbd->total_hlen_w = cpu_to_le16(hlen); 36248c2ecf20Sopenharmony_ci hlen = hlen*2; 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_ci if (xmit_type & XMIT_CSUM_TCP) { 36278c2ecf20Sopenharmony_ci pbd->tcp_pseudo_csum = bswab16(tcp_hdr(skb)->check); 36288c2ecf20Sopenharmony_ci 36298c2ecf20Sopenharmony_ci } else { 36308c2ecf20Sopenharmony_ci s8 fix = SKB_CS_OFF(skb); /* signed! */ 36318c2ecf20Sopenharmony_ci 36328c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 36338c2ecf20Sopenharmony_ci "hlen %d fix %d csum before fix %x\n", 36348c2ecf20Sopenharmony_ci le16_to_cpu(pbd->total_hlen_w), fix, SKB_CS(skb)); 36358c2ecf20Sopenharmony_ci 36368c2ecf20Sopenharmony_ci /* HW bug: fixup the CSUM */ 36378c2ecf20Sopenharmony_ci pbd->tcp_pseudo_csum = 36388c2ecf20Sopenharmony_ci bnx2x_csum_fix(skb_transport_header(skb), 36398c2ecf20Sopenharmony_ci SKB_CS(skb), fix); 36408c2ecf20Sopenharmony_ci 36418c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, "csum after fix %x\n", 36428c2ecf20Sopenharmony_ci pbd->tcp_pseudo_csum); 36438c2ecf20Sopenharmony_ci } 36448c2ecf20Sopenharmony_ci 36458c2ecf20Sopenharmony_ci return hlen; 36468c2ecf20Sopenharmony_ci} 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_cistatic void bnx2x_update_pbds_gso_enc(struct sk_buff *skb, 36498c2ecf20Sopenharmony_ci struct eth_tx_parse_bd_e2 *pbd_e2, 36508c2ecf20Sopenharmony_ci struct eth_tx_parse_2nd_bd *pbd2, 36518c2ecf20Sopenharmony_ci u16 *global_data, 36528c2ecf20Sopenharmony_ci u32 xmit_type) 36538c2ecf20Sopenharmony_ci{ 36548c2ecf20Sopenharmony_ci u16 hlen_w = 0; 36558c2ecf20Sopenharmony_ci u8 outerip_off, outerip_len = 0; 36568c2ecf20Sopenharmony_ci 36578c2ecf20Sopenharmony_ci /* from outer IP to transport */ 36588c2ecf20Sopenharmony_ci hlen_w = (skb_inner_transport_header(skb) - 36598c2ecf20Sopenharmony_ci skb_network_header(skb)) >> 1; 36608c2ecf20Sopenharmony_ci 36618c2ecf20Sopenharmony_ci /* transport len */ 36628c2ecf20Sopenharmony_ci hlen_w += inner_tcp_hdrlen(skb) >> 1; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci pbd2->fw_ip_hdr_to_payload_w = hlen_w; 36658c2ecf20Sopenharmony_ci 36668c2ecf20Sopenharmony_ci /* outer IP header info */ 36678c2ecf20Sopenharmony_ci if (xmit_type & XMIT_CSUM_V4) { 36688c2ecf20Sopenharmony_ci struct iphdr *iph = ip_hdr(skb); 36698c2ecf20Sopenharmony_ci u32 csum = (__force u32)(~iph->check) - 36708c2ecf20Sopenharmony_ci (__force u32)iph->tot_len - 36718c2ecf20Sopenharmony_ci (__force u32)iph->frag_off; 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci outerip_len = iph->ihl << 1; 36748c2ecf20Sopenharmony_ci 36758c2ecf20Sopenharmony_ci pbd2->fw_ip_csum_wo_len_flags_frag = 36768c2ecf20Sopenharmony_ci bswab16(csum_fold((__force __wsum)csum)); 36778c2ecf20Sopenharmony_ci } else { 36788c2ecf20Sopenharmony_ci pbd2->fw_ip_hdr_to_payload_w = 36798c2ecf20Sopenharmony_ci hlen_w - ((sizeof(struct ipv6hdr)) >> 1); 36808c2ecf20Sopenharmony_ci pbd_e2->data.tunnel_data.flags |= 36818c2ecf20Sopenharmony_ci ETH_TUNNEL_DATA_IPV6_OUTER; 36828c2ecf20Sopenharmony_ci } 36838c2ecf20Sopenharmony_ci 36848c2ecf20Sopenharmony_ci pbd2->tcp_send_seq = bswab32(inner_tcp_hdr(skb)->seq); 36858c2ecf20Sopenharmony_ci 36868c2ecf20Sopenharmony_ci pbd2->tcp_flags = pbd_tcp_flags(inner_tcp_hdr(skb)); 36878c2ecf20Sopenharmony_ci 36888c2ecf20Sopenharmony_ci /* inner IP header info */ 36898c2ecf20Sopenharmony_ci if (xmit_type & XMIT_CSUM_ENC_V4) { 36908c2ecf20Sopenharmony_ci pbd2->hw_ip_id = bswab16(inner_ip_hdr(skb)->id); 36918c2ecf20Sopenharmony_ci 36928c2ecf20Sopenharmony_ci pbd_e2->data.tunnel_data.pseudo_csum = 36938c2ecf20Sopenharmony_ci bswab16(~csum_tcpudp_magic( 36948c2ecf20Sopenharmony_ci inner_ip_hdr(skb)->saddr, 36958c2ecf20Sopenharmony_ci inner_ip_hdr(skb)->daddr, 36968c2ecf20Sopenharmony_ci 0, IPPROTO_TCP, 0)); 36978c2ecf20Sopenharmony_ci } else { 36988c2ecf20Sopenharmony_ci pbd_e2->data.tunnel_data.pseudo_csum = 36998c2ecf20Sopenharmony_ci bswab16(~csum_ipv6_magic( 37008c2ecf20Sopenharmony_ci &inner_ipv6_hdr(skb)->saddr, 37018c2ecf20Sopenharmony_ci &inner_ipv6_hdr(skb)->daddr, 37028c2ecf20Sopenharmony_ci 0, IPPROTO_TCP, 0)); 37038c2ecf20Sopenharmony_ci } 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_ci outerip_off = (skb_network_header(skb) - skb->data) >> 1; 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_ci *global_data |= 37088c2ecf20Sopenharmony_ci outerip_off | 37098c2ecf20Sopenharmony_ci (outerip_len << 37108c2ecf20Sopenharmony_ci ETH_TX_PARSE_2ND_BD_IP_HDR_LEN_OUTER_W_SHIFT) | 37118c2ecf20Sopenharmony_ci ((skb->protocol == cpu_to_be16(ETH_P_8021Q)) << 37128c2ecf20Sopenharmony_ci ETH_TX_PARSE_2ND_BD_LLC_SNAP_EN_SHIFT); 37138c2ecf20Sopenharmony_ci 37148c2ecf20Sopenharmony_ci if (ip_hdr(skb)->protocol == IPPROTO_UDP) { 37158c2ecf20Sopenharmony_ci SET_FLAG(*global_data, ETH_TX_PARSE_2ND_BD_TUNNEL_UDP_EXIST, 1); 37168c2ecf20Sopenharmony_ci pbd2->tunnel_udp_hdr_start_w = skb_transport_offset(skb) >> 1; 37178c2ecf20Sopenharmony_ci } 37188c2ecf20Sopenharmony_ci} 37198c2ecf20Sopenharmony_ci 37208c2ecf20Sopenharmony_cistatic inline void bnx2x_set_ipv6_ext_e2(struct sk_buff *skb, u32 *parsing_data, 37218c2ecf20Sopenharmony_ci u32 xmit_type) 37228c2ecf20Sopenharmony_ci{ 37238c2ecf20Sopenharmony_ci struct ipv6hdr *ipv6; 37248c2ecf20Sopenharmony_ci 37258c2ecf20Sopenharmony_ci if (!(xmit_type & (XMIT_GSO_ENC_V6 | XMIT_GSO_V6))) 37268c2ecf20Sopenharmony_ci return; 37278c2ecf20Sopenharmony_ci 37288c2ecf20Sopenharmony_ci if (xmit_type & XMIT_GSO_ENC_V6) 37298c2ecf20Sopenharmony_ci ipv6 = inner_ipv6_hdr(skb); 37308c2ecf20Sopenharmony_ci else /* XMIT_GSO_V6 */ 37318c2ecf20Sopenharmony_ci ipv6 = ipv6_hdr(skb); 37328c2ecf20Sopenharmony_ci 37338c2ecf20Sopenharmony_ci if (ipv6->nexthdr == NEXTHDR_IPV6) 37348c2ecf20Sopenharmony_ci *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR; 37358c2ecf20Sopenharmony_ci} 37368c2ecf20Sopenharmony_ci 37378c2ecf20Sopenharmony_ci/* called with netif_tx_lock 37388c2ecf20Sopenharmony_ci * bnx2x_tx_int() runs without netif_tx_lock unless it needs to call 37398c2ecf20Sopenharmony_ci * netif_wake_queue() 37408c2ecf20Sopenharmony_ci */ 37418c2ecf20Sopenharmony_cinetdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev) 37428c2ecf20Sopenharmony_ci{ 37438c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 37448c2ecf20Sopenharmony_ci 37458c2ecf20Sopenharmony_ci struct netdev_queue *txq; 37468c2ecf20Sopenharmony_ci struct bnx2x_fp_txdata *txdata; 37478c2ecf20Sopenharmony_ci struct sw_tx_bd *tx_buf; 37488c2ecf20Sopenharmony_ci struct eth_tx_start_bd *tx_start_bd, *first_bd; 37498c2ecf20Sopenharmony_ci struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL; 37508c2ecf20Sopenharmony_ci struct eth_tx_parse_bd_e1x *pbd_e1x = NULL; 37518c2ecf20Sopenharmony_ci struct eth_tx_parse_bd_e2 *pbd_e2 = NULL; 37528c2ecf20Sopenharmony_ci struct eth_tx_parse_2nd_bd *pbd2 = NULL; 37538c2ecf20Sopenharmony_ci u32 pbd_e2_parsing_data = 0; 37548c2ecf20Sopenharmony_ci u16 pkt_prod, bd_prod; 37558c2ecf20Sopenharmony_ci int nbd, txq_index; 37568c2ecf20Sopenharmony_ci dma_addr_t mapping; 37578c2ecf20Sopenharmony_ci u32 xmit_type = bnx2x_xmit_type(bp, skb); 37588c2ecf20Sopenharmony_ci int i; 37598c2ecf20Sopenharmony_ci u8 hlen = 0; 37608c2ecf20Sopenharmony_ci __le16 pkt_size = 0; 37618c2ecf20Sopenharmony_ci struct ethhdr *eth; 37628c2ecf20Sopenharmony_ci u8 mac_type = UNICAST_ADDRESS; 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 37658c2ecf20Sopenharmony_ci if (unlikely(bp->panic)) 37668c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 37678c2ecf20Sopenharmony_ci#endif 37688c2ecf20Sopenharmony_ci 37698c2ecf20Sopenharmony_ci txq_index = skb_get_queue_mapping(skb); 37708c2ecf20Sopenharmony_ci txq = netdev_get_tx_queue(dev, txq_index); 37718c2ecf20Sopenharmony_ci 37728c2ecf20Sopenharmony_ci BUG_ON(txq_index >= MAX_ETH_TXQ_IDX(bp) + (CNIC_LOADED(bp) ? 1 : 0)); 37738c2ecf20Sopenharmony_ci 37748c2ecf20Sopenharmony_ci txdata = &bp->bnx2x_txq[txq_index]; 37758c2ecf20Sopenharmony_ci 37768c2ecf20Sopenharmony_ci /* enable this debug print to view the transmission queue being used 37778c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, "indices: txq %d, fp %d, txdata %d\n", 37788c2ecf20Sopenharmony_ci txq_index, fp_index, txdata_index); */ 37798c2ecf20Sopenharmony_ci 37808c2ecf20Sopenharmony_ci /* enable this debug print to view the transmission details 37818c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 37828c2ecf20Sopenharmony_ci "transmitting packet cid %d fp index %d txdata_index %d tx_data ptr %p fp pointer %p\n", 37838c2ecf20Sopenharmony_ci txdata->cid, fp_index, txdata_index, txdata, fp); */ 37848c2ecf20Sopenharmony_ci 37858c2ecf20Sopenharmony_ci if (unlikely(bnx2x_tx_avail(bp, txdata) < 37868c2ecf20Sopenharmony_ci skb_shinfo(skb)->nr_frags + 37878c2ecf20Sopenharmony_ci BDS_PER_TX_PKT + 37888c2ecf20Sopenharmony_ci NEXT_CNT_PER_TX_PKT(MAX_BDS_PER_TX_PKT))) { 37898c2ecf20Sopenharmony_ci /* Handle special storage cases separately */ 37908c2ecf20Sopenharmony_ci if (txdata->tx_ring_size == 0) { 37918c2ecf20Sopenharmony_ci struct bnx2x_eth_q_stats *q_stats = 37928c2ecf20Sopenharmony_ci bnx2x_fp_qstats(bp, txdata->parent_fp); 37938c2ecf20Sopenharmony_ci q_stats->driver_filtered_tx_pkt++; 37948c2ecf20Sopenharmony_ci dev_kfree_skb(skb); 37958c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 37968c2ecf20Sopenharmony_ci } 37978c2ecf20Sopenharmony_ci bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++; 37988c2ecf20Sopenharmony_ci netif_tx_stop_queue(txq); 37998c2ecf20Sopenharmony_ci BNX2X_ERR("BUG! Tx ring full when queue awake!\n"); 38008c2ecf20Sopenharmony_ci 38018c2ecf20Sopenharmony_ci return NETDEV_TX_BUSY; 38028c2ecf20Sopenharmony_ci } 38038c2ecf20Sopenharmony_ci 38048c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 38058c2ecf20Sopenharmony_ci "queue[%d]: SKB: summed %x protocol %x protocol(%x,%x) gso type %x xmit_type %x len %d\n", 38068c2ecf20Sopenharmony_ci txq_index, skb->ip_summed, skb->protocol, ipv6_hdr(skb)->nexthdr, 38078c2ecf20Sopenharmony_ci ip_hdr(skb)->protocol, skb_shinfo(skb)->gso_type, xmit_type, 38088c2ecf20Sopenharmony_ci skb->len); 38098c2ecf20Sopenharmony_ci 38108c2ecf20Sopenharmony_ci eth = (struct ethhdr *)skb->data; 38118c2ecf20Sopenharmony_ci 38128c2ecf20Sopenharmony_ci /* set flag according to packet type (UNICAST_ADDRESS is default)*/ 38138c2ecf20Sopenharmony_ci if (unlikely(is_multicast_ether_addr(eth->h_dest))) { 38148c2ecf20Sopenharmony_ci if (is_broadcast_ether_addr(eth->h_dest)) 38158c2ecf20Sopenharmony_ci mac_type = BROADCAST_ADDRESS; 38168c2ecf20Sopenharmony_ci else 38178c2ecf20Sopenharmony_ci mac_type = MULTICAST_ADDRESS; 38188c2ecf20Sopenharmony_ci } 38198c2ecf20Sopenharmony_ci 38208c2ecf20Sopenharmony_ci#if (MAX_SKB_FRAGS >= MAX_FETCH_BD - BDS_PER_TX_PKT) 38218c2ecf20Sopenharmony_ci /* First, check if we need to linearize the skb (due to FW 38228c2ecf20Sopenharmony_ci restrictions). No need to check fragmentation if page size > 8K 38238c2ecf20Sopenharmony_ci (there will be no violation to FW restrictions) */ 38248c2ecf20Sopenharmony_ci if (bnx2x_pkt_req_lin(bp, skb, xmit_type)) { 38258c2ecf20Sopenharmony_ci /* Statistics of linearization */ 38268c2ecf20Sopenharmony_ci bp->lin_cnt++; 38278c2ecf20Sopenharmony_ci if (skb_linearize(skb) != 0) { 38288c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 38298c2ecf20Sopenharmony_ci "SKB linearization failed - silently dropping this SKB\n"); 38308c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 38318c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 38328c2ecf20Sopenharmony_ci } 38338c2ecf20Sopenharmony_ci } 38348c2ecf20Sopenharmony_ci#endif 38358c2ecf20Sopenharmony_ci /* Map skb linear data for DMA */ 38368c2ecf20Sopenharmony_ci mapping = dma_map_single(&bp->pdev->dev, skb->data, 38378c2ecf20Sopenharmony_ci skb_headlen(skb), DMA_TO_DEVICE); 38388c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { 38398c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 38408c2ecf20Sopenharmony_ci "SKB mapping failed - silently dropping this SKB\n"); 38418c2ecf20Sopenharmony_ci dev_kfree_skb_any(skb); 38428c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 38438c2ecf20Sopenharmony_ci } 38448c2ecf20Sopenharmony_ci /* 38458c2ecf20Sopenharmony_ci Please read carefully. First we use one BD which we mark as start, 38468c2ecf20Sopenharmony_ci then we have a parsing info BD (used for TSO or xsum), 38478c2ecf20Sopenharmony_ci and only then we have the rest of the TSO BDs. 38488c2ecf20Sopenharmony_ci (don't forget to mark the last one as last, 38498c2ecf20Sopenharmony_ci and to unmap only AFTER you write to the BD ...) 38508c2ecf20Sopenharmony_ci And above all, all pdb sizes are in words - NOT DWORDS! 38518c2ecf20Sopenharmony_ci */ 38528c2ecf20Sopenharmony_ci 38538c2ecf20Sopenharmony_ci /* get current pkt produced now - advance it just before sending packet 38548c2ecf20Sopenharmony_ci * since mapping of pages may fail and cause packet to be dropped 38558c2ecf20Sopenharmony_ci */ 38568c2ecf20Sopenharmony_ci pkt_prod = txdata->tx_pkt_prod; 38578c2ecf20Sopenharmony_ci bd_prod = TX_BD(txdata->tx_bd_prod); 38588c2ecf20Sopenharmony_ci 38598c2ecf20Sopenharmony_ci /* get a tx_buf and first BD 38608c2ecf20Sopenharmony_ci * tx_start_bd may be changed during SPLIT, 38618c2ecf20Sopenharmony_ci * but first_bd will always stay first 38628c2ecf20Sopenharmony_ci */ 38638c2ecf20Sopenharmony_ci tx_buf = &txdata->tx_buf_ring[TX_BD(pkt_prod)]; 38648c2ecf20Sopenharmony_ci tx_start_bd = &txdata->tx_desc_ring[bd_prod].start_bd; 38658c2ecf20Sopenharmony_ci first_bd = tx_start_bd; 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_ci tx_start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD; 38688c2ecf20Sopenharmony_ci 38698c2ecf20Sopenharmony_ci if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) { 38708c2ecf20Sopenharmony_ci if (!(bp->flags & TX_TIMESTAMPING_EN)) { 38718c2ecf20Sopenharmony_ci bp->eth_stats.ptp_skip_tx_ts++; 38728c2ecf20Sopenharmony_ci BNX2X_ERR("Tx timestamping was not enabled, this packet will not be timestamped\n"); 38738c2ecf20Sopenharmony_ci } else if (bp->ptp_tx_skb) { 38748c2ecf20Sopenharmony_ci bp->eth_stats.ptp_skip_tx_ts++; 38758c2ecf20Sopenharmony_ci netdev_err_once(bp->dev, 38768c2ecf20Sopenharmony_ci "Device supports only a single outstanding packet to timestamp, this packet won't be timestamped\n"); 38778c2ecf20Sopenharmony_ci } else { 38788c2ecf20Sopenharmony_ci skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; 38798c2ecf20Sopenharmony_ci /* schedule check for Tx timestamp */ 38808c2ecf20Sopenharmony_ci bp->ptp_tx_skb = skb_get(skb); 38818c2ecf20Sopenharmony_ci bp->ptp_tx_start = jiffies; 38828c2ecf20Sopenharmony_ci schedule_work(&bp->ptp_task); 38838c2ecf20Sopenharmony_ci } 38848c2ecf20Sopenharmony_ci } 38858c2ecf20Sopenharmony_ci 38868c2ecf20Sopenharmony_ci /* header nbd: indirectly zero other flags! */ 38878c2ecf20Sopenharmony_ci tx_start_bd->general_data = 1 << ETH_TX_START_BD_HDR_NBDS_SHIFT; 38888c2ecf20Sopenharmony_ci 38898c2ecf20Sopenharmony_ci /* remember the first BD of the packet */ 38908c2ecf20Sopenharmony_ci tx_buf->first_bd = txdata->tx_bd_prod; 38918c2ecf20Sopenharmony_ci tx_buf->skb = skb; 38928c2ecf20Sopenharmony_ci tx_buf->flags = 0; 38938c2ecf20Sopenharmony_ci 38948c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 38958c2ecf20Sopenharmony_ci "sending pkt %u @%p next_idx %u bd %u @%p\n", 38968c2ecf20Sopenharmony_ci pkt_prod, tx_buf, txdata->tx_pkt_prod, bd_prod, tx_start_bd); 38978c2ecf20Sopenharmony_ci 38988c2ecf20Sopenharmony_ci if (skb_vlan_tag_present(skb)) { 38998c2ecf20Sopenharmony_ci tx_start_bd->vlan_or_ethertype = 39008c2ecf20Sopenharmony_ci cpu_to_le16(skb_vlan_tag_get(skb)); 39018c2ecf20Sopenharmony_ci tx_start_bd->bd_flags.as_bitfield |= 39028c2ecf20Sopenharmony_ci (X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT); 39038c2ecf20Sopenharmony_ci } else { 39048c2ecf20Sopenharmony_ci /* when transmitting in a vf, start bd must hold the ethertype 39058c2ecf20Sopenharmony_ci * for fw to enforce it 39068c2ecf20Sopenharmony_ci */ 39078c2ecf20Sopenharmony_ci u16 vlan_tci = 0; 39088c2ecf20Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR 39098c2ecf20Sopenharmony_ci if (IS_VF(bp)) { 39108c2ecf20Sopenharmony_ci#endif 39118c2ecf20Sopenharmony_ci /* Still need to consider inband vlan for enforced */ 39128c2ecf20Sopenharmony_ci if (__vlan_get_tag(skb, &vlan_tci)) { 39138c2ecf20Sopenharmony_ci tx_start_bd->vlan_or_ethertype = 39148c2ecf20Sopenharmony_ci cpu_to_le16(ntohs(eth->h_proto)); 39158c2ecf20Sopenharmony_ci } else { 39168c2ecf20Sopenharmony_ci tx_start_bd->bd_flags.as_bitfield |= 39178c2ecf20Sopenharmony_ci (X_ETH_INBAND_VLAN << 39188c2ecf20Sopenharmony_ci ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT); 39198c2ecf20Sopenharmony_ci tx_start_bd->vlan_or_ethertype = 39208c2ecf20Sopenharmony_ci cpu_to_le16(vlan_tci); 39218c2ecf20Sopenharmony_ci } 39228c2ecf20Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR 39238c2ecf20Sopenharmony_ci } else { 39248c2ecf20Sopenharmony_ci /* used by FW for packet accounting */ 39258c2ecf20Sopenharmony_ci tx_start_bd->vlan_or_ethertype = cpu_to_le16(pkt_prod); 39268c2ecf20Sopenharmony_ci } 39278c2ecf20Sopenharmony_ci#endif 39288c2ecf20Sopenharmony_ci } 39298c2ecf20Sopenharmony_ci 39308c2ecf20Sopenharmony_ci nbd = 2; /* start_bd + pbd + frags (updated when pages are mapped) */ 39318c2ecf20Sopenharmony_ci 39328c2ecf20Sopenharmony_ci /* turn on parsing and get a BD */ 39338c2ecf20Sopenharmony_ci bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); 39348c2ecf20Sopenharmony_ci 39358c2ecf20Sopenharmony_ci if (xmit_type & XMIT_CSUM) 39368c2ecf20Sopenharmony_ci bnx2x_set_sbd_csum(bp, skb, tx_start_bd, xmit_type); 39378c2ecf20Sopenharmony_ci 39388c2ecf20Sopenharmony_ci if (!CHIP_IS_E1x(bp)) { 39398c2ecf20Sopenharmony_ci pbd_e2 = &txdata->tx_desc_ring[bd_prod].parse_bd_e2; 39408c2ecf20Sopenharmony_ci memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2)); 39418c2ecf20Sopenharmony_ci 39428c2ecf20Sopenharmony_ci if (xmit_type & XMIT_CSUM_ENC) { 39438c2ecf20Sopenharmony_ci u16 global_data = 0; 39448c2ecf20Sopenharmony_ci 39458c2ecf20Sopenharmony_ci /* Set PBD in enc checksum offload case */ 39468c2ecf20Sopenharmony_ci hlen = bnx2x_set_pbd_csum_enc(bp, skb, 39478c2ecf20Sopenharmony_ci &pbd_e2_parsing_data, 39488c2ecf20Sopenharmony_ci xmit_type); 39498c2ecf20Sopenharmony_ci 39508c2ecf20Sopenharmony_ci /* turn on 2nd parsing and get a BD */ 39518c2ecf20Sopenharmony_ci bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); 39528c2ecf20Sopenharmony_ci 39538c2ecf20Sopenharmony_ci pbd2 = &txdata->tx_desc_ring[bd_prod].parse_2nd_bd; 39548c2ecf20Sopenharmony_ci 39558c2ecf20Sopenharmony_ci memset(pbd2, 0, sizeof(*pbd2)); 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_ci pbd_e2->data.tunnel_data.ip_hdr_start_inner_w = 39588c2ecf20Sopenharmony_ci (skb_inner_network_header(skb) - 39598c2ecf20Sopenharmony_ci skb->data) >> 1; 39608c2ecf20Sopenharmony_ci 39618c2ecf20Sopenharmony_ci if (xmit_type & XMIT_GSO_ENC) 39628c2ecf20Sopenharmony_ci bnx2x_update_pbds_gso_enc(skb, pbd_e2, pbd2, 39638c2ecf20Sopenharmony_ci &global_data, 39648c2ecf20Sopenharmony_ci xmit_type); 39658c2ecf20Sopenharmony_ci 39668c2ecf20Sopenharmony_ci pbd2->global_data = cpu_to_le16(global_data); 39678c2ecf20Sopenharmony_ci 39688c2ecf20Sopenharmony_ci /* add addition parse BD indication to start BD */ 39698c2ecf20Sopenharmony_ci SET_FLAG(tx_start_bd->general_data, 39708c2ecf20Sopenharmony_ci ETH_TX_START_BD_PARSE_NBDS, 1); 39718c2ecf20Sopenharmony_ci /* set encapsulation flag in start BD */ 39728c2ecf20Sopenharmony_ci SET_FLAG(tx_start_bd->general_data, 39738c2ecf20Sopenharmony_ci ETH_TX_START_BD_TUNNEL_EXIST, 1); 39748c2ecf20Sopenharmony_ci 39758c2ecf20Sopenharmony_ci tx_buf->flags |= BNX2X_HAS_SECOND_PBD; 39768c2ecf20Sopenharmony_ci 39778c2ecf20Sopenharmony_ci nbd++; 39788c2ecf20Sopenharmony_ci } else if (xmit_type & XMIT_CSUM) { 39798c2ecf20Sopenharmony_ci /* Set PBD in checksum offload case w/o encapsulation */ 39808c2ecf20Sopenharmony_ci hlen = bnx2x_set_pbd_csum_e2(bp, skb, 39818c2ecf20Sopenharmony_ci &pbd_e2_parsing_data, 39828c2ecf20Sopenharmony_ci xmit_type); 39838c2ecf20Sopenharmony_ci } 39848c2ecf20Sopenharmony_ci 39858c2ecf20Sopenharmony_ci bnx2x_set_ipv6_ext_e2(skb, &pbd_e2_parsing_data, xmit_type); 39868c2ecf20Sopenharmony_ci /* Add the macs to the parsing BD if this is a vf or if 39878c2ecf20Sopenharmony_ci * Tx Switching is enabled. 39888c2ecf20Sopenharmony_ci */ 39898c2ecf20Sopenharmony_ci if (IS_VF(bp)) { 39908c2ecf20Sopenharmony_ci /* override GRE parameters in BD */ 39918c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi, 39928c2ecf20Sopenharmony_ci &pbd_e2->data.mac_addr.src_mid, 39938c2ecf20Sopenharmony_ci &pbd_e2->data.mac_addr.src_lo, 39948c2ecf20Sopenharmony_ci eth->h_source); 39958c2ecf20Sopenharmony_ci 39968c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.dst_hi, 39978c2ecf20Sopenharmony_ci &pbd_e2->data.mac_addr.dst_mid, 39988c2ecf20Sopenharmony_ci &pbd_e2->data.mac_addr.dst_lo, 39998c2ecf20Sopenharmony_ci eth->h_dest); 40008c2ecf20Sopenharmony_ci } else { 40018c2ecf20Sopenharmony_ci if (bp->flags & TX_SWITCHING) 40028c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr( 40038c2ecf20Sopenharmony_ci &pbd_e2->data.mac_addr.dst_hi, 40048c2ecf20Sopenharmony_ci &pbd_e2->data.mac_addr.dst_mid, 40058c2ecf20Sopenharmony_ci &pbd_e2->data.mac_addr.dst_lo, 40068c2ecf20Sopenharmony_ci eth->h_dest); 40078c2ecf20Sopenharmony_ci#ifdef BNX2X_STOP_ON_ERROR 40088c2ecf20Sopenharmony_ci /* Enforce security is always set in Stop on Error - 40098c2ecf20Sopenharmony_ci * source mac should be present in the parsing BD 40108c2ecf20Sopenharmony_ci */ 40118c2ecf20Sopenharmony_ci bnx2x_set_fw_mac_addr(&pbd_e2->data.mac_addr.src_hi, 40128c2ecf20Sopenharmony_ci &pbd_e2->data.mac_addr.src_mid, 40138c2ecf20Sopenharmony_ci &pbd_e2->data.mac_addr.src_lo, 40148c2ecf20Sopenharmony_ci eth->h_source); 40158c2ecf20Sopenharmony_ci#endif 40168c2ecf20Sopenharmony_ci } 40178c2ecf20Sopenharmony_ci 40188c2ecf20Sopenharmony_ci SET_FLAG(pbd_e2_parsing_data, 40198c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_ETH_ADDR_TYPE, mac_type); 40208c2ecf20Sopenharmony_ci } else { 40218c2ecf20Sopenharmony_ci u16 global_data = 0; 40228c2ecf20Sopenharmony_ci pbd_e1x = &txdata->tx_desc_ring[bd_prod].parse_bd_e1x; 40238c2ecf20Sopenharmony_ci memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x)); 40248c2ecf20Sopenharmony_ci /* Set PBD in checksum offload case */ 40258c2ecf20Sopenharmony_ci if (xmit_type & XMIT_CSUM) 40268c2ecf20Sopenharmony_ci hlen = bnx2x_set_pbd_csum(bp, skb, pbd_e1x, xmit_type); 40278c2ecf20Sopenharmony_ci 40288c2ecf20Sopenharmony_ci SET_FLAG(global_data, 40298c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E1X_ETH_ADDR_TYPE, mac_type); 40308c2ecf20Sopenharmony_ci pbd_e1x->global_data |= cpu_to_le16(global_data); 40318c2ecf20Sopenharmony_ci } 40328c2ecf20Sopenharmony_ci 40338c2ecf20Sopenharmony_ci /* Setup the data pointer of the first BD of the packet */ 40348c2ecf20Sopenharmony_ci tx_start_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); 40358c2ecf20Sopenharmony_ci tx_start_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); 40368c2ecf20Sopenharmony_ci tx_start_bd->nbytes = cpu_to_le16(skb_headlen(skb)); 40378c2ecf20Sopenharmony_ci pkt_size = tx_start_bd->nbytes; 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 40408c2ecf20Sopenharmony_ci "first bd @%p addr (%x:%x) nbytes %d flags %x vlan %x\n", 40418c2ecf20Sopenharmony_ci tx_start_bd, tx_start_bd->addr_hi, tx_start_bd->addr_lo, 40428c2ecf20Sopenharmony_ci le16_to_cpu(tx_start_bd->nbytes), 40438c2ecf20Sopenharmony_ci tx_start_bd->bd_flags.as_bitfield, 40448c2ecf20Sopenharmony_ci le16_to_cpu(tx_start_bd->vlan_or_ethertype)); 40458c2ecf20Sopenharmony_ci 40468c2ecf20Sopenharmony_ci if (xmit_type & XMIT_GSO) { 40478c2ecf20Sopenharmony_ci 40488c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 40498c2ecf20Sopenharmony_ci "TSO packet len %d hlen %d total len %d tso size %d\n", 40508c2ecf20Sopenharmony_ci skb->len, hlen, skb_headlen(skb), 40518c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_size); 40528c2ecf20Sopenharmony_ci 40538c2ecf20Sopenharmony_ci tx_start_bd->bd_flags.as_bitfield |= ETH_TX_BD_FLAGS_SW_LSO; 40548c2ecf20Sopenharmony_ci 40558c2ecf20Sopenharmony_ci if (unlikely(skb_headlen(skb) > hlen)) { 40568c2ecf20Sopenharmony_ci nbd++; 40578c2ecf20Sopenharmony_ci bd_prod = bnx2x_tx_split(bp, txdata, tx_buf, 40588c2ecf20Sopenharmony_ci &tx_start_bd, hlen, 40598c2ecf20Sopenharmony_ci bd_prod); 40608c2ecf20Sopenharmony_ci } 40618c2ecf20Sopenharmony_ci if (!CHIP_IS_E1x(bp)) 40628c2ecf20Sopenharmony_ci pbd_e2_parsing_data |= 40638c2ecf20Sopenharmony_ci (skb_shinfo(skb)->gso_size << 40648c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) & 40658c2ecf20Sopenharmony_ci ETH_TX_PARSE_BD_E2_LSO_MSS; 40668c2ecf20Sopenharmony_ci else 40678c2ecf20Sopenharmony_ci bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type); 40688c2ecf20Sopenharmony_ci } 40698c2ecf20Sopenharmony_ci 40708c2ecf20Sopenharmony_ci /* Set the PBD's parsing_data field if not zero 40718c2ecf20Sopenharmony_ci * (for the chips newer than 57711). 40728c2ecf20Sopenharmony_ci */ 40738c2ecf20Sopenharmony_ci if (pbd_e2_parsing_data) 40748c2ecf20Sopenharmony_ci pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data); 40758c2ecf20Sopenharmony_ci 40768c2ecf20Sopenharmony_ci tx_data_bd = (struct eth_tx_bd *)tx_start_bd; 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci /* Handle fragmented skb */ 40798c2ecf20Sopenharmony_ci for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { 40808c2ecf20Sopenharmony_ci skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; 40818c2ecf20Sopenharmony_ci 40828c2ecf20Sopenharmony_ci mapping = skb_frag_dma_map(&bp->pdev->dev, frag, 0, 40838c2ecf20Sopenharmony_ci skb_frag_size(frag), DMA_TO_DEVICE); 40848c2ecf20Sopenharmony_ci if (unlikely(dma_mapping_error(&bp->pdev->dev, mapping))) { 40858c2ecf20Sopenharmony_ci unsigned int pkts_compl = 0, bytes_compl = 0; 40868c2ecf20Sopenharmony_ci 40878c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 40888c2ecf20Sopenharmony_ci "Unable to map page - dropping packet...\n"); 40898c2ecf20Sopenharmony_ci 40908c2ecf20Sopenharmony_ci /* we need unmap all buffers already mapped 40918c2ecf20Sopenharmony_ci * for this SKB; 40928c2ecf20Sopenharmony_ci * first_bd->nbd need to be properly updated 40938c2ecf20Sopenharmony_ci * before call to bnx2x_free_tx_pkt 40948c2ecf20Sopenharmony_ci */ 40958c2ecf20Sopenharmony_ci first_bd->nbd = cpu_to_le16(nbd); 40968c2ecf20Sopenharmony_ci bnx2x_free_tx_pkt(bp, txdata, 40978c2ecf20Sopenharmony_ci TX_BD(txdata->tx_pkt_prod), 40988c2ecf20Sopenharmony_ci &pkts_compl, &bytes_compl); 40998c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 41008c2ecf20Sopenharmony_ci } 41018c2ecf20Sopenharmony_ci 41028c2ecf20Sopenharmony_ci bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); 41038c2ecf20Sopenharmony_ci tx_data_bd = &txdata->tx_desc_ring[bd_prod].reg_bd; 41048c2ecf20Sopenharmony_ci if (total_pkt_bd == NULL) 41058c2ecf20Sopenharmony_ci total_pkt_bd = &txdata->tx_desc_ring[bd_prod].reg_bd; 41068c2ecf20Sopenharmony_ci 41078c2ecf20Sopenharmony_ci tx_data_bd->addr_hi = cpu_to_le32(U64_HI(mapping)); 41088c2ecf20Sopenharmony_ci tx_data_bd->addr_lo = cpu_to_le32(U64_LO(mapping)); 41098c2ecf20Sopenharmony_ci tx_data_bd->nbytes = cpu_to_le16(skb_frag_size(frag)); 41108c2ecf20Sopenharmony_ci le16_add_cpu(&pkt_size, skb_frag_size(frag)); 41118c2ecf20Sopenharmony_ci nbd++; 41128c2ecf20Sopenharmony_ci 41138c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 41148c2ecf20Sopenharmony_ci "frag %d bd @%p addr (%x:%x) nbytes %d\n", 41158c2ecf20Sopenharmony_ci i, tx_data_bd, tx_data_bd->addr_hi, tx_data_bd->addr_lo, 41168c2ecf20Sopenharmony_ci le16_to_cpu(tx_data_bd->nbytes)); 41178c2ecf20Sopenharmony_ci } 41188c2ecf20Sopenharmony_ci 41198c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, "last bd @%p\n", tx_data_bd); 41208c2ecf20Sopenharmony_ci 41218c2ecf20Sopenharmony_ci /* update with actual num BDs */ 41228c2ecf20Sopenharmony_ci first_bd->nbd = cpu_to_le16(nbd); 41238c2ecf20Sopenharmony_ci 41248c2ecf20Sopenharmony_ci bd_prod = TX_BD(NEXT_TX_IDX(bd_prod)); 41258c2ecf20Sopenharmony_ci 41268c2ecf20Sopenharmony_ci /* now send a tx doorbell, counting the next BD 41278c2ecf20Sopenharmony_ci * if the packet contains or ends with it 41288c2ecf20Sopenharmony_ci */ 41298c2ecf20Sopenharmony_ci if (TX_BD_POFF(bd_prod) < nbd) 41308c2ecf20Sopenharmony_ci nbd++; 41318c2ecf20Sopenharmony_ci 41328c2ecf20Sopenharmony_ci /* total_pkt_bytes should be set on the first data BD if 41338c2ecf20Sopenharmony_ci * it's not an LSO packet and there is more than one 41348c2ecf20Sopenharmony_ci * data BD. In this case pkt_size is limited by an MTU value. 41358c2ecf20Sopenharmony_ci * However we prefer to set it for an LSO packet (while we don't 41368c2ecf20Sopenharmony_ci * have to) in order to save some CPU cycles in a none-LSO 41378c2ecf20Sopenharmony_ci * case, when we much more care about them. 41388c2ecf20Sopenharmony_ci */ 41398c2ecf20Sopenharmony_ci if (total_pkt_bd != NULL) 41408c2ecf20Sopenharmony_ci total_pkt_bd->total_pkt_bytes = pkt_size; 41418c2ecf20Sopenharmony_ci 41428c2ecf20Sopenharmony_ci if (pbd_e1x) 41438c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 41448c2ecf20Sopenharmony_ci "PBD (E1X) @%p ip_data %x ip_hlen %u ip_id %u lso_mss %u tcp_flags %x xsum %x seq %u hlen %u\n", 41458c2ecf20Sopenharmony_ci pbd_e1x, pbd_e1x->global_data, pbd_e1x->ip_hlen_w, 41468c2ecf20Sopenharmony_ci pbd_e1x->ip_id, pbd_e1x->lso_mss, pbd_e1x->tcp_flags, 41478c2ecf20Sopenharmony_ci pbd_e1x->tcp_pseudo_csum, pbd_e1x->tcp_send_seq, 41488c2ecf20Sopenharmony_ci le16_to_cpu(pbd_e1x->total_hlen_w)); 41498c2ecf20Sopenharmony_ci if (pbd_e2) 41508c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, 41518c2ecf20Sopenharmony_ci "PBD (E2) @%p dst %x %x %x src %x %x %x parsing_data %x\n", 41528c2ecf20Sopenharmony_ci pbd_e2, 41538c2ecf20Sopenharmony_ci pbd_e2->data.mac_addr.dst_hi, 41548c2ecf20Sopenharmony_ci pbd_e2->data.mac_addr.dst_mid, 41558c2ecf20Sopenharmony_ci pbd_e2->data.mac_addr.dst_lo, 41568c2ecf20Sopenharmony_ci pbd_e2->data.mac_addr.src_hi, 41578c2ecf20Sopenharmony_ci pbd_e2->data.mac_addr.src_mid, 41588c2ecf20Sopenharmony_ci pbd_e2->data.mac_addr.src_lo, 41598c2ecf20Sopenharmony_ci pbd_e2->parsing_data); 41608c2ecf20Sopenharmony_ci DP(NETIF_MSG_TX_QUEUED, "doorbell: nbd %d bd %u\n", nbd, bd_prod); 41618c2ecf20Sopenharmony_ci 41628c2ecf20Sopenharmony_ci netdev_tx_sent_queue(txq, skb->len); 41638c2ecf20Sopenharmony_ci 41648c2ecf20Sopenharmony_ci skb_tx_timestamp(skb); 41658c2ecf20Sopenharmony_ci 41668c2ecf20Sopenharmony_ci txdata->tx_pkt_prod++; 41678c2ecf20Sopenharmony_ci /* 41688c2ecf20Sopenharmony_ci * Make sure that the BD data is updated before updating the producer 41698c2ecf20Sopenharmony_ci * since FW might read the BD right after the producer is updated. 41708c2ecf20Sopenharmony_ci * This is only applicable for weak-ordered memory model archs such 41718c2ecf20Sopenharmony_ci * as IA-64. The following barrier is also mandatory since FW will 41728c2ecf20Sopenharmony_ci * assumes packets must have BDs. 41738c2ecf20Sopenharmony_ci */ 41748c2ecf20Sopenharmony_ci wmb(); 41758c2ecf20Sopenharmony_ci 41768c2ecf20Sopenharmony_ci txdata->tx_db.data.prod += nbd; 41778c2ecf20Sopenharmony_ci /* make sure descriptor update is observed by HW */ 41788c2ecf20Sopenharmony_ci wmb(); 41798c2ecf20Sopenharmony_ci 41808c2ecf20Sopenharmony_ci DOORBELL_RELAXED(bp, txdata->cid, txdata->tx_db.raw); 41818c2ecf20Sopenharmony_ci 41828c2ecf20Sopenharmony_ci txdata->tx_bd_prod += nbd; 41838c2ecf20Sopenharmony_ci 41848c2ecf20Sopenharmony_ci if (unlikely(bnx2x_tx_avail(bp, txdata) < MAX_DESC_PER_TX_PKT)) { 41858c2ecf20Sopenharmony_ci netif_tx_stop_queue(txq); 41868c2ecf20Sopenharmony_ci 41878c2ecf20Sopenharmony_ci /* paired memory barrier is in bnx2x_tx_int(), we have to keep 41888c2ecf20Sopenharmony_ci * ordering of set_bit() in netif_tx_stop_queue() and read of 41898c2ecf20Sopenharmony_ci * fp->bd_tx_cons */ 41908c2ecf20Sopenharmony_ci smp_mb(); 41918c2ecf20Sopenharmony_ci 41928c2ecf20Sopenharmony_ci bnx2x_fp_qstats(bp, txdata->parent_fp)->driver_xoff++; 41938c2ecf20Sopenharmony_ci if (bnx2x_tx_avail(bp, txdata) >= MAX_DESC_PER_TX_PKT) 41948c2ecf20Sopenharmony_ci netif_tx_wake_queue(txq); 41958c2ecf20Sopenharmony_ci } 41968c2ecf20Sopenharmony_ci txdata->tx_pkt++; 41978c2ecf20Sopenharmony_ci 41988c2ecf20Sopenharmony_ci return NETDEV_TX_OK; 41998c2ecf20Sopenharmony_ci} 42008c2ecf20Sopenharmony_ci 42018c2ecf20Sopenharmony_civoid bnx2x_get_c2s_mapping(struct bnx2x *bp, u8 *c2s_map, u8 *c2s_default) 42028c2ecf20Sopenharmony_ci{ 42038c2ecf20Sopenharmony_ci int mfw_vn = BP_FW_MB_IDX(bp); 42048c2ecf20Sopenharmony_ci u32 tmp; 42058c2ecf20Sopenharmony_ci 42068c2ecf20Sopenharmony_ci /* If the shmem shouldn't affect configuration, reflect */ 42078c2ecf20Sopenharmony_ci if (!IS_MF_BD(bp)) { 42088c2ecf20Sopenharmony_ci int i; 42098c2ecf20Sopenharmony_ci 42108c2ecf20Sopenharmony_ci for (i = 0; i < BNX2X_MAX_PRIORITY; i++) 42118c2ecf20Sopenharmony_ci c2s_map[i] = i; 42128c2ecf20Sopenharmony_ci *c2s_default = 0; 42138c2ecf20Sopenharmony_ci 42148c2ecf20Sopenharmony_ci return; 42158c2ecf20Sopenharmony_ci } 42168c2ecf20Sopenharmony_ci 42178c2ecf20Sopenharmony_ci tmp = SHMEM2_RD(bp, c2s_pcp_map_lower[mfw_vn]); 42188c2ecf20Sopenharmony_ci tmp = (__force u32)be32_to_cpu((__force __be32)tmp); 42198c2ecf20Sopenharmony_ci c2s_map[0] = tmp & 0xff; 42208c2ecf20Sopenharmony_ci c2s_map[1] = (tmp >> 8) & 0xff; 42218c2ecf20Sopenharmony_ci c2s_map[2] = (tmp >> 16) & 0xff; 42228c2ecf20Sopenharmony_ci c2s_map[3] = (tmp >> 24) & 0xff; 42238c2ecf20Sopenharmony_ci 42248c2ecf20Sopenharmony_ci tmp = SHMEM2_RD(bp, c2s_pcp_map_upper[mfw_vn]); 42258c2ecf20Sopenharmony_ci tmp = (__force u32)be32_to_cpu((__force __be32)tmp); 42268c2ecf20Sopenharmony_ci c2s_map[4] = tmp & 0xff; 42278c2ecf20Sopenharmony_ci c2s_map[5] = (tmp >> 8) & 0xff; 42288c2ecf20Sopenharmony_ci c2s_map[6] = (tmp >> 16) & 0xff; 42298c2ecf20Sopenharmony_ci c2s_map[7] = (tmp >> 24) & 0xff; 42308c2ecf20Sopenharmony_ci 42318c2ecf20Sopenharmony_ci tmp = SHMEM2_RD(bp, c2s_pcp_map_default[mfw_vn]); 42328c2ecf20Sopenharmony_ci tmp = (__force u32)be32_to_cpu((__force __be32)tmp); 42338c2ecf20Sopenharmony_ci *c2s_default = (tmp >> (8 * mfw_vn)) & 0xff; 42348c2ecf20Sopenharmony_ci} 42358c2ecf20Sopenharmony_ci 42368c2ecf20Sopenharmony_ci/** 42378c2ecf20Sopenharmony_ci * bnx2x_setup_tc - routine to configure net_device for multi tc 42388c2ecf20Sopenharmony_ci * 42398c2ecf20Sopenharmony_ci * @dev: net device to configure 42408c2ecf20Sopenharmony_ci * @num_tc: number of traffic classes to enable 42418c2ecf20Sopenharmony_ci * 42428c2ecf20Sopenharmony_ci * callback connected to the ndo_setup_tc function pointer 42438c2ecf20Sopenharmony_ci */ 42448c2ecf20Sopenharmony_ciint bnx2x_setup_tc(struct net_device *dev, u8 num_tc) 42458c2ecf20Sopenharmony_ci{ 42468c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 42478c2ecf20Sopenharmony_ci u8 c2s_map[BNX2X_MAX_PRIORITY], c2s_def; 42488c2ecf20Sopenharmony_ci int cos, prio, count, offset; 42498c2ecf20Sopenharmony_ci 42508c2ecf20Sopenharmony_ci /* setup tc must be called under rtnl lock */ 42518c2ecf20Sopenharmony_ci ASSERT_RTNL(); 42528c2ecf20Sopenharmony_ci 42538c2ecf20Sopenharmony_ci /* no traffic classes requested. Aborting */ 42548c2ecf20Sopenharmony_ci if (!num_tc) { 42558c2ecf20Sopenharmony_ci netdev_reset_tc(dev); 42568c2ecf20Sopenharmony_ci return 0; 42578c2ecf20Sopenharmony_ci } 42588c2ecf20Sopenharmony_ci 42598c2ecf20Sopenharmony_ci /* requested to support too many traffic classes */ 42608c2ecf20Sopenharmony_ci if (num_tc > bp->max_cos) { 42618c2ecf20Sopenharmony_ci BNX2X_ERR("support for too many traffic classes requested: %d. Max supported is %d\n", 42628c2ecf20Sopenharmony_ci num_tc, bp->max_cos); 42638c2ecf20Sopenharmony_ci return -EINVAL; 42648c2ecf20Sopenharmony_ci } 42658c2ecf20Sopenharmony_ci 42668c2ecf20Sopenharmony_ci /* declare amount of supported traffic classes */ 42678c2ecf20Sopenharmony_ci if (netdev_set_num_tc(dev, num_tc)) { 42688c2ecf20Sopenharmony_ci BNX2X_ERR("failed to declare %d traffic classes\n", num_tc); 42698c2ecf20Sopenharmony_ci return -EINVAL; 42708c2ecf20Sopenharmony_ci } 42718c2ecf20Sopenharmony_ci 42728c2ecf20Sopenharmony_ci bnx2x_get_c2s_mapping(bp, c2s_map, &c2s_def); 42738c2ecf20Sopenharmony_ci 42748c2ecf20Sopenharmony_ci /* configure priority to traffic class mapping */ 42758c2ecf20Sopenharmony_ci for (prio = 0; prio < BNX2X_MAX_PRIORITY; prio++) { 42768c2ecf20Sopenharmony_ci int outer_prio = c2s_map[prio]; 42778c2ecf20Sopenharmony_ci 42788c2ecf20Sopenharmony_ci netdev_set_prio_tc_map(dev, prio, bp->prio_to_cos[outer_prio]); 42798c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP | NETIF_MSG_IFUP, 42808c2ecf20Sopenharmony_ci "mapping priority %d to tc %d\n", 42818c2ecf20Sopenharmony_ci outer_prio, bp->prio_to_cos[outer_prio]); 42828c2ecf20Sopenharmony_ci } 42838c2ecf20Sopenharmony_ci 42848c2ecf20Sopenharmony_ci /* Use this configuration to differentiate tc0 from other COSes 42858c2ecf20Sopenharmony_ci This can be used for ets or pfc, and save the effort of setting 42868c2ecf20Sopenharmony_ci up a multio class queue disc or negotiating DCBX with a switch 42878c2ecf20Sopenharmony_ci netdev_set_prio_tc_map(dev, 0, 0); 42888c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "mapping priority %d to tc %d\n", 0, 0); 42898c2ecf20Sopenharmony_ci for (prio = 1; prio < 16; prio++) { 42908c2ecf20Sopenharmony_ci netdev_set_prio_tc_map(dev, prio, 1); 42918c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "mapping priority %d to tc %d\n", prio, 1); 42928c2ecf20Sopenharmony_ci } */ 42938c2ecf20Sopenharmony_ci 42948c2ecf20Sopenharmony_ci /* configure traffic class to transmission queue mapping */ 42958c2ecf20Sopenharmony_ci for (cos = 0; cos < bp->max_cos; cos++) { 42968c2ecf20Sopenharmony_ci count = BNX2X_NUM_ETH_QUEUES(bp); 42978c2ecf20Sopenharmony_ci offset = cos * BNX2X_NUM_NON_CNIC_QUEUES(bp); 42988c2ecf20Sopenharmony_ci netdev_set_tc_queue(dev, cos, count, offset); 42998c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP | NETIF_MSG_IFUP, 43008c2ecf20Sopenharmony_ci "mapping tc %d to offset %d count %d\n", 43018c2ecf20Sopenharmony_ci cos, offset, count); 43028c2ecf20Sopenharmony_ci } 43038c2ecf20Sopenharmony_ci 43048c2ecf20Sopenharmony_ci return 0; 43058c2ecf20Sopenharmony_ci} 43068c2ecf20Sopenharmony_ci 43078c2ecf20Sopenharmony_ciint __bnx2x_setup_tc(struct net_device *dev, enum tc_setup_type type, 43088c2ecf20Sopenharmony_ci void *type_data) 43098c2ecf20Sopenharmony_ci{ 43108c2ecf20Sopenharmony_ci struct tc_mqprio_qopt *mqprio = type_data; 43118c2ecf20Sopenharmony_ci 43128c2ecf20Sopenharmony_ci if (type != TC_SETUP_QDISC_MQPRIO) 43138c2ecf20Sopenharmony_ci return -EOPNOTSUPP; 43148c2ecf20Sopenharmony_ci 43158c2ecf20Sopenharmony_ci mqprio->hw = TC_MQPRIO_HW_OFFLOAD_TCS; 43168c2ecf20Sopenharmony_ci 43178c2ecf20Sopenharmony_ci return bnx2x_setup_tc(dev, mqprio->num_tc); 43188c2ecf20Sopenharmony_ci} 43198c2ecf20Sopenharmony_ci 43208c2ecf20Sopenharmony_ci/* called with rtnl_lock */ 43218c2ecf20Sopenharmony_ciint bnx2x_change_mac_addr(struct net_device *dev, void *p) 43228c2ecf20Sopenharmony_ci{ 43238c2ecf20Sopenharmony_ci struct sockaddr *addr = p; 43248c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 43258c2ecf20Sopenharmony_ci int rc = 0; 43268c2ecf20Sopenharmony_ci 43278c2ecf20Sopenharmony_ci if (!is_valid_ether_addr(addr->sa_data)) { 43288c2ecf20Sopenharmony_ci BNX2X_ERR("Requested MAC address is not valid\n"); 43298c2ecf20Sopenharmony_ci return -EINVAL; 43308c2ecf20Sopenharmony_ci } 43318c2ecf20Sopenharmony_ci 43328c2ecf20Sopenharmony_ci if (IS_MF_STORAGE_ONLY(bp)) { 43338c2ecf20Sopenharmony_ci BNX2X_ERR("Can't change address on STORAGE ONLY function\n"); 43348c2ecf20Sopenharmony_ci return -EINVAL; 43358c2ecf20Sopenharmony_ci } 43368c2ecf20Sopenharmony_ci 43378c2ecf20Sopenharmony_ci if (netif_running(dev)) { 43388c2ecf20Sopenharmony_ci rc = bnx2x_set_eth_mac(bp, false); 43398c2ecf20Sopenharmony_ci if (rc) 43408c2ecf20Sopenharmony_ci return rc; 43418c2ecf20Sopenharmony_ci } 43428c2ecf20Sopenharmony_ci 43438c2ecf20Sopenharmony_ci memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); 43448c2ecf20Sopenharmony_ci 43458c2ecf20Sopenharmony_ci if (netif_running(dev)) 43468c2ecf20Sopenharmony_ci rc = bnx2x_set_eth_mac(bp, true); 43478c2ecf20Sopenharmony_ci 43488c2ecf20Sopenharmony_ci if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg)) 43498c2ecf20Sopenharmony_ci SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS); 43508c2ecf20Sopenharmony_ci 43518c2ecf20Sopenharmony_ci return rc; 43528c2ecf20Sopenharmony_ci} 43538c2ecf20Sopenharmony_ci 43548c2ecf20Sopenharmony_cistatic void bnx2x_free_fp_mem_at(struct bnx2x *bp, int fp_index) 43558c2ecf20Sopenharmony_ci{ 43568c2ecf20Sopenharmony_ci union host_hc_status_block *sb = &bnx2x_fp(bp, fp_index, status_blk); 43578c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[fp_index]; 43588c2ecf20Sopenharmony_ci u8 cos; 43598c2ecf20Sopenharmony_ci 43608c2ecf20Sopenharmony_ci /* Common */ 43618c2ecf20Sopenharmony_ci 43628c2ecf20Sopenharmony_ci if (IS_FCOE_IDX(fp_index)) { 43638c2ecf20Sopenharmony_ci memset(sb, 0, sizeof(union host_hc_status_block)); 43648c2ecf20Sopenharmony_ci fp->status_blk_mapping = 0; 43658c2ecf20Sopenharmony_ci } else { 43668c2ecf20Sopenharmony_ci /* status blocks */ 43678c2ecf20Sopenharmony_ci if (!CHIP_IS_E1x(bp)) 43688c2ecf20Sopenharmony_ci BNX2X_PCI_FREE(sb->e2_sb, 43698c2ecf20Sopenharmony_ci bnx2x_fp(bp, fp_index, 43708c2ecf20Sopenharmony_ci status_blk_mapping), 43718c2ecf20Sopenharmony_ci sizeof(struct host_hc_status_block_e2)); 43728c2ecf20Sopenharmony_ci else 43738c2ecf20Sopenharmony_ci BNX2X_PCI_FREE(sb->e1x_sb, 43748c2ecf20Sopenharmony_ci bnx2x_fp(bp, fp_index, 43758c2ecf20Sopenharmony_ci status_blk_mapping), 43768c2ecf20Sopenharmony_ci sizeof(struct host_hc_status_block_e1x)); 43778c2ecf20Sopenharmony_ci } 43788c2ecf20Sopenharmony_ci 43798c2ecf20Sopenharmony_ci /* Rx */ 43808c2ecf20Sopenharmony_ci if (!skip_rx_queue(bp, fp_index)) { 43818c2ecf20Sopenharmony_ci bnx2x_free_rx_bds(fp); 43828c2ecf20Sopenharmony_ci 43838c2ecf20Sopenharmony_ci /* fastpath rx rings: rx_buf rx_desc rx_comp */ 43848c2ecf20Sopenharmony_ci BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_buf_ring)); 43858c2ecf20Sopenharmony_ci BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_desc_ring), 43868c2ecf20Sopenharmony_ci bnx2x_fp(bp, fp_index, rx_desc_mapping), 43878c2ecf20Sopenharmony_ci sizeof(struct eth_rx_bd) * NUM_RX_BD); 43888c2ecf20Sopenharmony_ci 43898c2ecf20Sopenharmony_ci BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_comp_ring), 43908c2ecf20Sopenharmony_ci bnx2x_fp(bp, fp_index, rx_comp_mapping), 43918c2ecf20Sopenharmony_ci sizeof(struct eth_fast_path_rx_cqe) * 43928c2ecf20Sopenharmony_ci NUM_RCQ_BD); 43938c2ecf20Sopenharmony_ci 43948c2ecf20Sopenharmony_ci /* SGE ring */ 43958c2ecf20Sopenharmony_ci BNX2X_FREE(bnx2x_fp(bp, fp_index, rx_page_ring)); 43968c2ecf20Sopenharmony_ci BNX2X_PCI_FREE(bnx2x_fp(bp, fp_index, rx_sge_ring), 43978c2ecf20Sopenharmony_ci bnx2x_fp(bp, fp_index, rx_sge_mapping), 43988c2ecf20Sopenharmony_ci BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); 43998c2ecf20Sopenharmony_ci } 44008c2ecf20Sopenharmony_ci 44018c2ecf20Sopenharmony_ci /* Tx */ 44028c2ecf20Sopenharmony_ci if (!skip_tx_queue(bp, fp_index)) { 44038c2ecf20Sopenharmony_ci /* fastpath tx rings: tx_buf tx_desc */ 44048c2ecf20Sopenharmony_ci for_each_cos_in_tx_queue(fp, cos) { 44058c2ecf20Sopenharmony_ci struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos]; 44068c2ecf20Sopenharmony_ci 44078c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFDOWN, 44088c2ecf20Sopenharmony_ci "freeing tx memory of fp %d cos %d cid %d\n", 44098c2ecf20Sopenharmony_ci fp_index, cos, txdata->cid); 44108c2ecf20Sopenharmony_ci 44118c2ecf20Sopenharmony_ci BNX2X_FREE(txdata->tx_buf_ring); 44128c2ecf20Sopenharmony_ci BNX2X_PCI_FREE(txdata->tx_desc_ring, 44138c2ecf20Sopenharmony_ci txdata->tx_desc_mapping, 44148c2ecf20Sopenharmony_ci sizeof(union eth_tx_bd_types) * NUM_TX_BD); 44158c2ecf20Sopenharmony_ci } 44168c2ecf20Sopenharmony_ci } 44178c2ecf20Sopenharmony_ci /* end of fastpath */ 44188c2ecf20Sopenharmony_ci} 44198c2ecf20Sopenharmony_ci 44208c2ecf20Sopenharmony_cistatic void bnx2x_free_fp_mem_cnic(struct bnx2x *bp) 44218c2ecf20Sopenharmony_ci{ 44228c2ecf20Sopenharmony_ci int i; 44238c2ecf20Sopenharmony_ci for_each_cnic_queue(bp, i) 44248c2ecf20Sopenharmony_ci bnx2x_free_fp_mem_at(bp, i); 44258c2ecf20Sopenharmony_ci} 44268c2ecf20Sopenharmony_ci 44278c2ecf20Sopenharmony_civoid bnx2x_free_fp_mem(struct bnx2x *bp) 44288c2ecf20Sopenharmony_ci{ 44298c2ecf20Sopenharmony_ci int i; 44308c2ecf20Sopenharmony_ci for_each_eth_queue(bp, i) 44318c2ecf20Sopenharmony_ci bnx2x_free_fp_mem_at(bp, i); 44328c2ecf20Sopenharmony_ci} 44338c2ecf20Sopenharmony_ci 44348c2ecf20Sopenharmony_cistatic void set_sb_shortcuts(struct bnx2x *bp, int index) 44358c2ecf20Sopenharmony_ci{ 44368c2ecf20Sopenharmony_ci union host_hc_status_block status_blk = bnx2x_fp(bp, index, status_blk); 44378c2ecf20Sopenharmony_ci if (!CHIP_IS_E1x(bp)) { 44388c2ecf20Sopenharmony_ci bnx2x_fp(bp, index, sb_index_values) = 44398c2ecf20Sopenharmony_ci (__le16 *)status_blk.e2_sb->sb.index_values; 44408c2ecf20Sopenharmony_ci bnx2x_fp(bp, index, sb_running_index) = 44418c2ecf20Sopenharmony_ci (__le16 *)status_blk.e2_sb->sb.running_index; 44428c2ecf20Sopenharmony_ci } else { 44438c2ecf20Sopenharmony_ci bnx2x_fp(bp, index, sb_index_values) = 44448c2ecf20Sopenharmony_ci (__le16 *)status_blk.e1x_sb->sb.index_values; 44458c2ecf20Sopenharmony_ci bnx2x_fp(bp, index, sb_running_index) = 44468c2ecf20Sopenharmony_ci (__le16 *)status_blk.e1x_sb->sb.running_index; 44478c2ecf20Sopenharmony_ci } 44488c2ecf20Sopenharmony_ci} 44498c2ecf20Sopenharmony_ci 44508c2ecf20Sopenharmony_ci/* Returns the number of actually allocated BDs */ 44518c2ecf20Sopenharmony_cistatic int bnx2x_alloc_rx_bds(struct bnx2x_fastpath *fp, 44528c2ecf20Sopenharmony_ci int rx_ring_size) 44538c2ecf20Sopenharmony_ci{ 44548c2ecf20Sopenharmony_ci struct bnx2x *bp = fp->bp; 44558c2ecf20Sopenharmony_ci u16 ring_prod, cqe_ring_prod; 44568c2ecf20Sopenharmony_ci int i, failure_cnt = 0; 44578c2ecf20Sopenharmony_ci 44588c2ecf20Sopenharmony_ci fp->rx_comp_cons = 0; 44598c2ecf20Sopenharmony_ci cqe_ring_prod = ring_prod = 0; 44608c2ecf20Sopenharmony_ci 44618c2ecf20Sopenharmony_ci /* This routine is called only during fo init so 44628c2ecf20Sopenharmony_ci * fp->eth_q_stats.rx_skb_alloc_failed = 0 44638c2ecf20Sopenharmony_ci */ 44648c2ecf20Sopenharmony_ci for (i = 0; i < rx_ring_size; i++) { 44658c2ecf20Sopenharmony_ci if (bnx2x_alloc_rx_data(bp, fp, ring_prod, GFP_KERNEL) < 0) { 44668c2ecf20Sopenharmony_ci failure_cnt++; 44678c2ecf20Sopenharmony_ci continue; 44688c2ecf20Sopenharmony_ci } 44698c2ecf20Sopenharmony_ci ring_prod = NEXT_RX_IDX(ring_prod); 44708c2ecf20Sopenharmony_ci cqe_ring_prod = NEXT_RCQ_IDX(cqe_ring_prod); 44718c2ecf20Sopenharmony_ci WARN_ON(ring_prod <= (i - failure_cnt)); 44728c2ecf20Sopenharmony_ci } 44738c2ecf20Sopenharmony_ci 44748c2ecf20Sopenharmony_ci if (failure_cnt) 44758c2ecf20Sopenharmony_ci BNX2X_ERR("was only able to allocate %d rx skbs on queue[%d]\n", 44768c2ecf20Sopenharmony_ci i - failure_cnt, fp->index); 44778c2ecf20Sopenharmony_ci 44788c2ecf20Sopenharmony_ci fp->rx_bd_prod = ring_prod; 44798c2ecf20Sopenharmony_ci /* Limit the CQE producer by the CQE ring size */ 44808c2ecf20Sopenharmony_ci fp->rx_comp_prod = min_t(u16, NUM_RCQ_RINGS*RCQ_DESC_CNT, 44818c2ecf20Sopenharmony_ci cqe_ring_prod); 44828c2ecf20Sopenharmony_ci 44838c2ecf20Sopenharmony_ci bnx2x_fp_stats(bp, fp)->eth_q_stats.rx_skb_alloc_failed += failure_cnt; 44848c2ecf20Sopenharmony_ci 44858c2ecf20Sopenharmony_ci return i - failure_cnt; 44868c2ecf20Sopenharmony_ci} 44878c2ecf20Sopenharmony_ci 44888c2ecf20Sopenharmony_cistatic void bnx2x_set_next_page_rx_cq(struct bnx2x_fastpath *fp) 44898c2ecf20Sopenharmony_ci{ 44908c2ecf20Sopenharmony_ci int i; 44918c2ecf20Sopenharmony_ci 44928c2ecf20Sopenharmony_ci for (i = 1; i <= NUM_RCQ_RINGS; i++) { 44938c2ecf20Sopenharmony_ci struct eth_rx_cqe_next_page *nextpg; 44948c2ecf20Sopenharmony_ci 44958c2ecf20Sopenharmony_ci nextpg = (struct eth_rx_cqe_next_page *) 44968c2ecf20Sopenharmony_ci &fp->rx_comp_ring[RCQ_DESC_CNT * i - 1]; 44978c2ecf20Sopenharmony_ci nextpg->addr_hi = 44988c2ecf20Sopenharmony_ci cpu_to_le32(U64_HI(fp->rx_comp_mapping + 44998c2ecf20Sopenharmony_ci BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); 45008c2ecf20Sopenharmony_ci nextpg->addr_lo = 45018c2ecf20Sopenharmony_ci cpu_to_le32(U64_LO(fp->rx_comp_mapping + 45028c2ecf20Sopenharmony_ci BCM_PAGE_SIZE*(i % NUM_RCQ_RINGS))); 45038c2ecf20Sopenharmony_ci } 45048c2ecf20Sopenharmony_ci} 45058c2ecf20Sopenharmony_ci 45068c2ecf20Sopenharmony_cistatic int bnx2x_alloc_fp_mem_at(struct bnx2x *bp, int index) 45078c2ecf20Sopenharmony_ci{ 45088c2ecf20Sopenharmony_ci union host_hc_status_block *sb; 45098c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp = &bp->fp[index]; 45108c2ecf20Sopenharmony_ci int ring_size = 0; 45118c2ecf20Sopenharmony_ci u8 cos; 45128c2ecf20Sopenharmony_ci int rx_ring_size = 0; 45138c2ecf20Sopenharmony_ci 45148c2ecf20Sopenharmony_ci if (!bp->rx_ring_size && IS_MF_STORAGE_ONLY(bp)) { 45158c2ecf20Sopenharmony_ci rx_ring_size = MIN_RX_SIZE_NONTPA; 45168c2ecf20Sopenharmony_ci bp->rx_ring_size = rx_ring_size; 45178c2ecf20Sopenharmony_ci } else if (!bp->rx_ring_size) { 45188c2ecf20Sopenharmony_ci rx_ring_size = MAX_RX_AVAIL/BNX2X_NUM_RX_QUEUES(bp); 45198c2ecf20Sopenharmony_ci 45208c2ecf20Sopenharmony_ci if (CHIP_IS_E3(bp)) { 45218c2ecf20Sopenharmony_ci u32 cfg = SHMEM_RD(bp, 45228c2ecf20Sopenharmony_ci dev_info.port_hw_config[BP_PORT(bp)]. 45238c2ecf20Sopenharmony_ci default_cfg); 45248c2ecf20Sopenharmony_ci 45258c2ecf20Sopenharmony_ci /* Decrease ring size for 1G functions */ 45268c2ecf20Sopenharmony_ci if ((cfg & PORT_HW_CFG_NET_SERDES_IF_MASK) == 45278c2ecf20Sopenharmony_ci PORT_HW_CFG_NET_SERDES_IF_SGMII) 45288c2ecf20Sopenharmony_ci rx_ring_size /= 10; 45298c2ecf20Sopenharmony_ci } 45308c2ecf20Sopenharmony_ci 45318c2ecf20Sopenharmony_ci /* allocate at least number of buffers required by FW */ 45328c2ecf20Sopenharmony_ci rx_ring_size = max_t(int, bp->disable_tpa ? MIN_RX_SIZE_NONTPA : 45338c2ecf20Sopenharmony_ci MIN_RX_SIZE_TPA, rx_ring_size); 45348c2ecf20Sopenharmony_ci 45358c2ecf20Sopenharmony_ci bp->rx_ring_size = rx_ring_size; 45368c2ecf20Sopenharmony_ci } else /* if rx_ring_size specified - use it */ 45378c2ecf20Sopenharmony_ci rx_ring_size = bp->rx_ring_size; 45388c2ecf20Sopenharmony_ci 45398c2ecf20Sopenharmony_ci DP(BNX2X_MSG_SP, "calculated rx_ring_size %d\n", rx_ring_size); 45408c2ecf20Sopenharmony_ci 45418c2ecf20Sopenharmony_ci /* Common */ 45428c2ecf20Sopenharmony_ci sb = &bnx2x_fp(bp, index, status_blk); 45438c2ecf20Sopenharmony_ci 45448c2ecf20Sopenharmony_ci if (!IS_FCOE_IDX(index)) { 45458c2ecf20Sopenharmony_ci /* status blocks */ 45468c2ecf20Sopenharmony_ci if (!CHIP_IS_E1x(bp)) { 45478c2ecf20Sopenharmony_ci sb->e2_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping), 45488c2ecf20Sopenharmony_ci sizeof(struct host_hc_status_block_e2)); 45498c2ecf20Sopenharmony_ci if (!sb->e2_sb) 45508c2ecf20Sopenharmony_ci goto alloc_mem_err; 45518c2ecf20Sopenharmony_ci } else { 45528c2ecf20Sopenharmony_ci sb->e1x_sb = BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, status_blk_mapping), 45538c2ecf20Sopenharmony_ci sizeof(struct host_hc_status_block_e1x)); 45548c2ecf20Sopenharmony_ci if (!sb->e1x_sb) 45558c2ecf20Sopenharmony_ci goto alloc_mem_err; 45568c2ecf20Sopenharmony_ci } 45578c2ecf20Sopenharmony_ci } 45588c2ecf20Sopenharmony_ci 45598c2ecf20Sopenharmony_ci /* FCoE Queue uses Default SB and doesn't ACK the SB, thus no need to 45608c2ecf20Sopenharmony_ci * set shortcuts for it. 45618c2ecf20Sopenharmony_ci */ 45628c2ecf20Sopenharmony_ci if (!IS_FCOE_IDX(index)) 45638c2ecf20Sopenharmony_ci set_sb_shortcuts(bp, index); 45648c2ecf20Sopenharmony_ci 45658c2ecf20Sopenharmony_ci /* Tx */ 45668c2ecf20Sopenharmony_ci if (!skip_tx_queue(bp, index)) { 45678c2ecf20Sopenharmony_ci /* fastpath tx rings: tx_buf tx_desc */ 45688c2ecf20Sopenharmony_ci for_each_cos_in_tx_queue(fp, cos) { 45698c2ecf20Sopenharmony_ci struct bnx2x_fp_txdata *txdata = fp->txdata_ptr[cos]; 45708c2ecf20Sopenharmony_ci 45718c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, 45728c2ecf20Sopenharmony_ci "allocating tx memory of fp %d cos %d\n", 45738c2ecf20Sopenharmony_ci index, cos); 45748c2ecf20Sopenharmony_ci 45758c2ecf20Sopenharmony_ci txdata->tx_buf_ring = kcalloc(NUM_TX_BD, 45768c2ecf20Sopenharmony_ci sizeof(struct sw_tx_bd), 45778c2ecf20Sopenharmony_ci GFP_KERNEL); 45788c2ecf20Sopenharmony_ci if (!txdata->tx_buf_ring) 45798c2ecf20Sopenharmony_ci goto alloc_mem_err; 45808c2ecf20Sopenharmony_ci txdata->tx_desc_ring = BNX2X_PCI_ALLOC(&txdata->tx_desc_mapping, 45818c2ecf20Sopenharmony_ci sizeof(union eth_tx_bd_types) * NUM_TX_BD); 45828c2ecf20Sopenharmony_ci if (!txdata->tx_desc_ring) 45838c2ecf20Sopenharmony_ci goto alloc_mem_err; 45848c2ecf20Sopenharmony_ci } 45858c2ecf20Sopenharmony_ci } 45868c2ecf20Sopenharmony_ci 45878c2ecf20Sopenharmony_ci /* Rx */ 45888c2ecf20Sopenharmony_ci if (!skip_rx_queue(bp, index)) { 45898c2ecf20Sopenharmony_ci /* fastpath rx rings: rx_buf rx_desc rx_comp */ 45908c2ecf20Sopenharmony_ci bnx2x_fp(bp, index, rx_buf_ring) = 45918c2ecf20Sopenharmony_ci kcalloc(NUM_RX_BD, sizeof(struct sw_rx_bd), GFP_KERNEL); 45928c2ecf20Sopenharmony_ci if (!bnx2x_fp(bp, index, rx_buf_ring)) 45938c2ecf20Sopenharmony_ci goto alloc_mem_err; 45948c2ecf20Sopenharmony_ci bnx2x_fp(bp, index, rx_desc_ring) = 45958c2ecf20Sopenharmony_ci BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_desc_mapping), 45968c2ecf20Sopenharmony_ci sizeof(struct eth_rx_bd) * NUM_RX_BD); 45978c2ecf20Sopenharmony_ci if (!bnx2x_fp(bp, index, rx_desc_ring)) 45988c2ecf20Sopenharmony_ci goto alloc_mem_err; 45998c2ecf20Sopenharmony_ci 46008c2ecf20Sopenharmony_ci /* Seed all CQEs by 1s */ 46018c2ecf20Sopenharmony_ci bnx2x_fp(bp, index, rx_comp_ring) = 46028c2ecf20Sopenharmony_ci BNX2X_PCI_FALLOC(&bnx2x_fp(bp, index, rx_comp_mapping), 46038c2ecf20Sopenharmony_ci sizeof(struct eth_fast_path_rx_cqe) * NUM_RCQ_BD); 46048c2ecf20Sopenharmony_ci if (!bnx2x_fp(bp, index, rx_comp_ring)) 46058c2ecf20Sopenharmony_ci goto alloc_mem_err; 46068c2ecf20Sopenharmony_ci 46078c2ecf20Sopenharmony_ci /* SGE ring */ 46088c2ecf20Sopenharmony_ci bnx2x_fp(bp, index, rx_page_ring) = 46098c2ecf20Sopenharmony_ci kcalloc(NUM_RX_SGE, sizeof(struct sw_rx_page), 46108c2ecf20Sopenharmony_ci GFP_KERNEL); 46118c2ecf20Sopenharmony_ci if (!bnx2x_fp(bp, index, rx_page_ring)) 46128c2ecf20Sopenharmony_ci goto alloc_mem_err; 46138c2ecf20Sopenharmony_ci bnx2x_fp(bp, index, rx_sge_ring) = 46148c2ecf20Sopenharmony_ci BNX2X_PCI_ALLOC(&bnx2x_fp(bp, index, rx_sge_mapping), 46158c2ecf20Sopenharmony_ci BCM_PAGE_SIZE * NUM_RX_SGE_PAGES); 46168c2ecf20Sopenharmony_ci if (!bnx2x_fp(bp, index, rx_sge_ring)) 46178c2ecf20Sopenharmony_ci goto alloc_mem_err; 46188c2ecf20Sopenharmony_ci /* RX BD ring */ 46198c2ecf20Sopenharmony_ci bnx2x_set_next_page_rx_bd(fp); 46208c2ecf20Sopenharmony_ci 46218c2ecf20Sopenharmony_ci /* CQ ring */ 46228c2ecf20Sopenharmony_ci bnx2x_set_next_page_rx_cq(fp); 46238c2ecf20Sopenharmony_ci 46248c2ecf20Sopenharmony_ci /* BDs */ 46258c2ecf20Sopenharmony_ci ring_size = bnx2x_alloc_rx_bds(fp, rx_ring_size); 46268c2ecf20Sopenharmony_ci if (ring_size < rx_ring_size) 46278c2ecf20Sopenharmony_ci goto alloc_mem_err; 46288c2ecf20Sopenharmony_ci } 46298c2ecf20Sopenharmony_ci 46308c2ecf20Sopenharmony_ci return 0; 46318c2ecf20Sopenharmony_ci 46328c2ecf20Sopenharmony_ci/* handles low memory cases */ 46338c2ecf20Sopenharmony_cialloc_mem_err: 46348c2ecf20Sopenharmony_ci BNX2X_ERR("Unable to allocate full memory for queue %d (size %d)\n", 46358c2ecf20Sopenharmony_ci index, ring_size); 46368c2ecf20Sopenharmony_ci /* FW will drop all packets if queue is not big enough, 46378c2ecf20Sopenharmony_ci * In these cases we disable the queue 46388c2ecf20Sopenharmony_ci * Min size is different for OOO, TPA and non-TPA queues 46398c2ecf20Sopenharmony_ci */ 46408c2ecf20Sopenharmony_ci if (ring_size < (fp->mode == TPA_MODE_DISABLED ? 46418c2ecf20Sopenharmony_ci MIN_RX_SIZE_NONTPA : MIN_RX_SIZE_TPA)) { 46428c2ecf20Sopenharmony_ci /* release memory allocated for this queue */ 46438c2ecf20Sopenharmony_ci bnx2x_free_fp_mem_at(bp, index); 46448c2ecf20Sopenharmony_ci return -ENOMEM; 46458c2ecf20Sopenharmony_ci } 46468c2ecf20Sopenharmony_ci return 0; 46478c2ecf20Sopenharmony_ci} 46488c2ecf20Sopenharmony_ci 46498c2ecf20Sopenharmony_cistatic int bnx2x_alloc_fp_mem_cnic(struct bnx2x *bp) 46508c2ecf20Sopenharmony_ci{ 46518c2ecf20Sopenharmony_ci if (!NO_FCOE(bp)) 46528c2ecf20Sopenharmony_ci /* FCoE */ 46538c2ecf20Sopenharmony_ci if (bnx2x_alloc_fp_mem_at(bp, FCOE_IDX(bp))) 46548c2ecf20Sopenharmony_ci /* we will fail load process instead of mark 46558c2ecf20Sopenharmony_ci * NO_FCOE_FLAG 46568c2ecf20Sopenharmony_ci */ 46578c2ecf20Sopenharmony_ci return -ENOMEM; 46588c2ecf20Sopenharmony_ci 46598c2ecf20Sopenharmony_ci return 0; 46608c2ecf20Sopenharmony_ci} 46618c2ecf20Sopenharmony_ci 46628c2ecf20Sopenharmony_cistatic int bnx2x_alloc_fp_mem(struct bnx2x *bp) 46638c2ecf20Sopenharmony_ci{ 46648c2ecf20Sopenharmony_ci int i; 46658c2ecf20Sopenharmony_ci 46668c2ecf20Sopenharmony_ci /* 1. Allocate FP for leading - fatal if error 46678c2ecf20Sopenharmony_ci * 2. Allocate RSS - fix number of queues if error 46688c2ecf20Sopenharmony_ci */ 46698c2ecf20Sopenharmony_ci 46708c2ecf20Sopenharmony_ci /* leading */ 46718c2ecf20Sopenharmony_ci if (bnx2x_alloc_fp_mem_at(bp, 0)) 46728c2ecf20Sopenharmony_ci return -ENOMEM; 46738c2ecf20Sopenharmony_ci 46748c2ecf20Sopenharmony_ci /* RSS */ 46758c2ecf20Sopenharmony_ci for_each_nondefault_eth_queue(bp, i) 46768c2ecf20Sopenharmony_ci if (bnx2x_alloc_fp_mem_at(bp, i)) 46778c2ecf20Sopenharmony_ci break; 46788c2ecf20Sopenharmony_ci 46798c2ecf20Sopenharmony_ci /* handle memory failures */ 46808c2ecf20Sopenharmony_ci if (i != BNX2X_NUM_ETH_QUEUES(bp)) { 46818c2ecf20Sopenharmony_ci int delta = BNX2X_NUM_ETH_QUEUES(bp) - i; 46828c2ecf20Sopenharmony_ci 46838c2ecf20Sopenharmony_ci WARN_ON(delta < 0); 46848c2ecf20Sopenharmony_ci bnx2x_shrink_eth_fp(bp, delta); 46858c2ecf20Sopenharmony_ci if (CNIC_SUPPORT(bp)) 46868c2ecf20Sopenharmony_ci /* move non eth FPs next to last eth FP 46878c2ecf20Sopenharmony_ci * must be done in that order 46888c2ecf20Sopenharmony_ci * FCOE_IDX < FWD_IDX < OOO_IDX 46898c2ecf20Sopenharmony_ci */ 46908c2ecf20Sopenharmony_ci 46918c2ecf20Sopenharmony_ci /* move FCoE fp even NO_FCOE_FLAG is on */ 46928c2ecf20Sopenharmony_ci bnx2x_move_fp(bp, FCOE_IDX(bp), FCOE_IDX(bp) - delta); 46938c2ecf20Sopenharmony_ci bp->num_ethernet_queues -= delta; 46948c2ecf20Sopenharmony_ci bp->num_queues = bp->num_ethernet_queues + 46958c2ecf20Sopenharmony_ci bp->num_cnic_queues; 46968c2ecf20Sopenharmony_ci BNX2X_ERR("Adjusted num of queues from %d to %d\n", 46978c2ecf20Sopenharmony_ci bp->num_queues + delta, bp->num_queues); 46988c2ecf20Sopenharmony_ci } 46998c2ecf20Sopenharmony_ci 47008c2ecf20Sopenharmony_ci return 0; 47018c2ecf20Sopenharmony_ci} 47028c2ecf20Sopenharmony_ci 47038c2ecf20Sopenharmony_civoid bnx2x_free_mem_bp(struct bnx2x *bp) 47048c2ecf20Sopenharmony_ci{ 47058c2ecf20Sopenharmony_ci int i; 47068c2ecf20Sopenharmony_ci 47078c2ecf20Sopenharmony_ci for (i = 0; i < bp->fp_array_size; i++) 47088c2ecf20Sopenharmony_ci kfree(bp->fp[i].tpa_info); 47098c2ecf20Sopenharmony_ci kfree(bp->fp); 47108c2ecf20Sopenharmony_ci kfree(bp->sp_objs); 47118c2ecf20Sopenharmony_ci kfree(bp->fp_stats); 47128c2ecf20Sopenharmony_ci kfree(bp->bnx2x_txq); 47138c2ecf20Sopenharmony_ci kfree(bp->msix_table); 47148c2ecf20Sopenharmony_ci kfree(bp->ilt); 47158c2ecf20Sopenharmony_ci} 47168c2ecf20Sopenharmony_ci 47178c2ecf20Sopenharmony_ciint bnx2x_alloc_mem_bp(struct bnx2x *bp) 47188c2ecf20Sopenharmony_ci{ 47198c2ecf20Sopenharmony_ci struct bnx2x_fastpath *fp; 47208c2ecf20Sopenharmony_ci struct msix_entry *tbl; 47218c2ecf20Sopenharmony_ci struct bnx2x_ilt *ilt; 47228c2ecf20Sopenharmony_ci int msix_table_size = 0; 47238c2ecf20Sopenharmony_ci int fp_array_size, txq_array_size; 47248c2ecf20Sopenharmony_ci int i; 47258c2ecf20Sopenharmony_ci 47268c2ecf20Sopenharmony_ci /* 47278c2ecf20Sopenharmony_ci * The biggest MSI-X table we might need is as a maximum number of fast 47288c2ecf20Sopenharmony_ci * path IGU SBs plus default SB (for PF only). 47298c2ecf20Sopenharmony_ci */ 47308c2ecf20Sopenharmony_ci msix_table_size = bp->igu_sb_cnt; 47318c2ecf20Sopenharmony_ci if (IS_PF(bp)) 47328c2ecf20Sopenharmony_ci msix_table_size++; 47338c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("msix_table_size %d\n", msix_table_size); 47348c2ecf20Sopenharmony_ci 47358c2ecf20Sopenharmony_ci /* fp array: RSS plus CNIC related L2 queues */ 47368c2ecf20Sopenharmony_ci fp_array_size = BNX2X_MAX_RSS_COUNT(bp) + CNIC_SUPPORT(bp); 47378c2ecf20Sopenharmony_ci bp->fp_array_size = fp_array_size; 47388c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("fp_array_size %d\n", bp->fp_array_size); 47398c2ecf20Sopenharmony_ci 47408c2ecf20Sopenharmony_ci fp = kcalloc(bp->fp_array_size, sizeof(*fp), GFP_KERNEL); 47418c2ecf20Sopenharmony_ci if (!fp) 47428c2ecf20Sopenharmony_ci goto alloc_err; 47438c2ecf20Sopenharmony_ci for (i = 0; i < bp->fp_array_size; i++) { 47448c2ecf20Sopenharmony_ci fp[i].tpa_info = 47458c2ecf20Sopenharmony_ci kcalloc(ETH_MAX_AGGREGATION_QUEUES_E1H_E2, 47468c2ecf20Sopenharmony_ci sizeof(struct bnx2x_agg_info), GFP_KERNEL); 47478c2ecf20Sopenharmony_ci if (!(fp[i].tpa_info)) 47488c2ecf20Sopenharmony_ci goto alloc_err; 47498c2ecf20Sopenharmony_ci } 47508c2ecf20Sopenharmony_ci 47518c2ecf20Sopenharmony_ci bp->fp = fp; 47528c2ecf20Sopenharmony_ci 47538c2ecf20Sopenharmony_ci /* allocate sp objs */ 47548c2ecf20Sopenharmony_ci bp->sp_objs = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_sp_objs), 47558c2ecf20Sopenharmony_ci GFP_KERNEL); 47568c2ecf20Sopenharmony_ci if (!bp->sp_objs) 47578c2ecf20Sopenharmony_ci goto alloc_err; 47588c2ecf20Sopenharmony_ci 47598c2ecf20Sopenharmony_ci /* allocate fp_stats */ 47608c2ecf20Sopenharmony_ci bp->fp_stats = kcalloc(bp->fp_array_size, sizeof(struct bnx2x_fp_stats), 47618c2ecf20Sopenharmony_ci GFP_KERNEL); 47628c2ecf20Sopenharmony_ci if (!bp->fp_stats) 47638c2ecf20Sopenharmony_ci goto alloc_err; 47648c2ecf20Sopenharmony_ci 47658c2ecf20Sopenharmony_ci /* Allocate memory for the transmission queues array */ 47668c2ecf20Sopenharmony_ci txq_array_size = 47678c2ecf20Sopenharmony_ci BNX2X_MAX_RSS_COUNT(bp) * BNX2X_MULTI_TX_COS + CNIC_SUPPORT(bp); 47688c2ecf20Sopenharmony_ci BNX2X_DEV_INFO("txq_array_size %d", txq_array_size); 47698c2ecf20Sopenharmony_ci 47708c2ecf20Sopenharmony_ci bp->bnx2x_txq = kcalloc(txq_array_size, sizeof(struct bnx2x_fp_txdata), 47718c2ecf20Sopenharmony_ci GFP_KERNEL); 47728c2ecf20Sopenharmony_ci if (!bp->bnx2x_txq) 47738c2ecf20Sopenharmony_ci goto alloc_err; 47748c2ecf20Sopenharmony_ci 47758c2ecf20Sopenharmony_ci /* msix table */ 47768c2ecf20Sopenharmony_ci tbl = kcalloc(msix_table_size, sizeof(*tbl), GFP_KERNEL); 47778c2ecf20Sopenharmony_ci if (!tbl) 47788c2ecf20Sopenharmony_ci goto alloc_err; 47798c2ecf20Sopenharmony_ci bp->msix_table = tbl; 47808c2ecf20Sopenharmony_ci 47818c2ecf20Sopenharmony_ci /* ilt */ 47828c2ecf20Sopenharmony_ci ilt = kzalloc(sizeof(*ilt), GFP_KERNEL); 47838c2ecf20Sopenharmony_ci if (!ilt) 47848c2ecf20Sopenharmony_ci goto alloc_err; 47858c2ecf20Sopenharmony_ci bp->ilt = ilt; 47868c2ecf20Sopenharmony_ci 47878c2ecf20Sopenharmony_ci return 0; 47888c2ecf20Sopenharmony_cialloc_err: 47898c2ecf20Sopenharmony_ci bnx2x_free_mem_bp(bp); 47908c2ecf20Sopenharmony_ci return -ENOMEM; 47918c2ecf20Sopenharmony_ci} 47928c2ecf20Sopenharmony_ci 47938c2ecf20Sopenharmony_ciint bnx2x_reload_if_running(struct net_device *dev) 47948c2ecf20Sopenharmony_ci{ 47958c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 47968c2ecf20Sopenharmony_ci 47978c2ecf20Sopenharmony_ci if (unlikely(!netif_running(dev))) 47988c2ecf20Sopenharmony_ci return 0; 47998c2ecf20Sopenharmony_ci 48008c2ecf20Sopenharmony_ci bnx2x_nic_unload(bp, UNLOAD_NORMAL, true); 48018c2ecf20Sopenharmony_ci return bnx2x_nic_load(bp, LOAD_NORMAL); 48028c2ecf20Sopenharmony_ci} 48038c2ecf20Sopenharmony_ci 48048c2ecf20Sopenharmony_ciint bnx2x_get_cur_phy_idx(struct bnx2x *bp) 48058c2ecf20Sopenharmony_ci{ 48068c2ecf20Sopenharmony_ci u32 sel_phy_idx = 0; 48078c2ecf20Sopenharmony_ci if (bp->link_params.num_phys <= 1) 48088c2ecf20Sopenharmony_ci return INT_PHY; 48098c2ecf20Sopenharmony_ci 48108c2ecf20Sopenharmony_ci if (bp->link_vars.link_up) { 48118c2ecf20Sopenharmony_ci sel_phy_idx = EXT_PHY1; 48128c2ecf20Sopenharmony_ci /* In case link is SERDES, check if the EXT_PHY2 is the one */ 48138c2ecf20Sopenharmony_ci if ((bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) && 48148c2ecf20Sopenharmony_ci (bp->link_params.phy[EXT_PHY2].supported & SUPPORTED_FIBRE)) 48158c2ecf20Sopenharmony_ci sel_phy_idx = EXT_PHY2; 48168c2ecf20Sopenharmony_ci } else { 48178c2ecf20Sopenharmony_ci 48188c2ecf20Sopenharmony_ci switch (bnx2x_phy_selection(&bp->link_params)) { 48198c2ecf20Sopenharmony_ci case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT: 48208c2ecf20Sopenharmony_ci case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY: 48218c2ecf20Sopenharmony_ci case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY: 48228c2ecf20Sopenharmony_ci sel_phy_idx = EXT_PHY1; 48238c2ecf20Sopenharmony_ci break; 48248c2ecf20Sopenharmony_ci case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY: 48258c2ecf20Sopenharmony_ci case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY: 48268c2ecf20Sopenharmony_ci sel_phy_idx = EXT_PHY2; 48278c2ecf20Sopenharmony_ci break; 48288c2ecf20Sopenharmony_ci } 48298c2ecf20Sopenharmony_ci } 48308c2ecf20Sopenharmony_ci 48318c2ecf20Sopenharmony_ci return sel_phy_idx; 48328c2ecf20Sopenharmony_ci} 48338c2ecf20Sopenharmony_ciint bnx2x_get_link_cfg_idx(struct bnx2x *bp) 48348c2ecf20Sopenharmony_ci{ 48358c2ecf20Sopenharmony_ci u32 sel_phy_idx = bnx2x_get_cur_phy_idx(bp); 48368c2ecf20Sopenharmony_ci /* 48378c2ecf20Sopenharmony_ci * The selected activated PHY is always after swapping (in case PHY 48388c2ecf20Sopenharmony_ci * swapping is enabled). So when swapping is enabled, we need to reverse 48398c2ecf20Sopenharmony_ci * the configuration 48408c2ecf20Sopenharmony_ci */ 48418c2ecf20Sopenharmony_ci 48428c2ecf20Sopenharmony_ci if (bp->link_params.multi_phy_config & 48438c2ecf20Sopenharmony_ci PORT_HW_CFG_PHY_SWAPPED_ENABLED) { 48448c2ecf20Sopenharmony_ci if (sel_phy_idx == EXT_PHY1) 48458c2ecf20Sopenharmony_ci sel_phy_idx = EXT_PHY2; 48468c2ecf20Sopenharmony_ci else if (sel_phy_idx == EXT_PHY2) 48478c2ecf20Sopenharmony_ci sel_phy_idx = EXT_PHY1; 48488c2ecf20Sopenharmony_ci } 48498c2ecf20Sopenharmony_ci return LINK_CONFIG_IDX(sel_phy_idx); 48508c2ecf20Sopenharmony_ci} 48518c2ecf20Sopenharmony_ci 48528c2ecf20Sopenharmony_ci#ifdef NETDEV_FCOE_WWNN 48538c2ecf20Sopenharmony_ciint bnx2x_fcoe_get_wwn(struct net_device *dev, u64 *wwn, int type) 48548c2ecf20Sopenharmony_ci{ 48558c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 48568c2ecf20Sopenharmony_ci struct cnic_eth_dev *cp = &bp->cnic_eth_dev; 48578c2ecf20Sopenharmony_ci 48588c2ecf20Sopenharmony_ci switch (type) { 48598c2ecf20Sopenharmony_ci case NETDEV_FCOE_WWNN: 48608c2ecf20Sopenharmony_ci *wwn = HILO_U64(cp->fcoe_wwn_node_name_hi, 48618c2ecf20Sopenharmony_ci cp->fcoe_wwn_node_name_lo); 48628c2ecf20Sopenharmony_ci break; 48638c2ecf20Sopenharmony_ci case NETDEV_FCOE_WWPN: 48648c2ecf20Sopenharmony_ci *wwn = HILO_U64(cp->fcoe_wwn_port_name_hi, 48658c2ecf20Sopenharmony_ci cp->fcoe_wwn_port_name_lo); 48668c2ecf20Sopenharmony_ci break; 48678c2ecf20Sopenharmony_ci default: 48688c2ecf20Sopenharmony_ci BNX2X_ERR("Wrong WWN type requested - %d\n", type); 48698c2ecf20Sopenharmony_ci return -EINVAL; 48708c2ecf20Sopenharmony_ci } 48718c2ecf20Sopenharmony_ci 48728c2ecf20Sopenharmony_ci return 0; 48738c2ecf20Sopenharmony_ci} 48748c2ecf20Sopenharmony_ci#endif 48758c2ecf20Sopenharmony_ci 48768c2ecf20Sopenharmony_ci/* called with rtnl_lock */ 48778c2ecf20Sopenharmony_ciint bnx2x_change_mtu(struct net_device *dev, int new_mtu) 48788c2ecf20Sopenharmony_ci{ 48798c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 48808c2ecf20Sopenharmony_ci 48818c2ecf20Sopenharmony_ci if (pci_num_vf(bp->pdev)) { 48828c2ecf20Sopenharmony_ci DP(BNX2X_MSG_IOV, "VFs are enabled, can not change MTU\n"); 48838c2ecf20Sopenharmony_ci return -EPERM; 48848c2ecf20Sopenharmony_ci } 48858c2ecf20Sopenharmony_ci 48868c2ecf20Sopenharmony_ci if (bp->recovery_state != BNX2X_RECOVERY_DONE) { 48878c2ecf20Sopenharmony_ci BNX2X_ERR("Can't perform change MTU during parity recovery\n"); 48888c2ecf20Sopenharmony_ci return -EAGAIN; 48898c2ecf20Sopenharmony_ci } 48908c2ecf20Sopenharmony_ci 48918c2ecf20Sopenharmony_ci /* This does not race with packet allocation 48928c2ecf20Sopenharmony_ci * because the actual alloc size is 48938c2ecf20Sopenharmony_ci * only updated as part of load 48948c2ecf20Sopenharmony_ci */ 48958c2ecf20Sopenharmony_ci dev->mtu = new_mtu; 48968c2ecf20Sopenharmony_ci 48978c2ecf20Sopenharmony_ci if (!bnx2x_mtu_allows_gro(new_mtu)) 48988c2ecf20Sopenharmony_ci dev->features &= ~NETIF_F_GRO_HW; 48998c2ecf20Sopenharmony_ci 49008c2ecf20Sopenharmony_ci if (IS_PF(bp) && SHMEM2_HAS(bp, curr_cfg)) 49018c2ecf20Sopenharmony_ci SHMEM2_WR(bp, curr_cfg, CURR_CFG_MET_OS); 49028c2ecf20Sopenharmony_ci 49038c2ecf20Sopenharmony_ci return bnx2x_reload_if_running(dev); 49048c2ecf20Sopenharmony_ci} 49058c2ecf20Sopenharmony_ci 49068c2ecf20Sopenharmony_cinetdev_features_t bnx2x_fix_features(struct net_device *dev, 49078c2ecf20Sopenharmony_ci netdev_features_t features) 49088c2ecf20Sopenharmony_ci{ 49098c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 49108c2ecf20Sopenharmony_ci 49118c2ecf20Sopenharmony_ci if (pci_num_vf(bp->pdev)) { 49128c2ecf20Sopenharmony_ci netdev_features_t changed = dev->features ^ features; 49138c2ecf20Sopenharmony_ci 49148c2ecf20Sopenharmony_ci /* Revert the requested changes in features if they 49158c2ecf20Sopenharmony_ci * would require internal reload of PF in bnx2x_set_features(). 49168c2ecf20Sopenharmony_ci */ 49178c2ecf20Sopenharmony_ci if (!(features & NETIF_F_RXCSUM) && !bp->disable_tpa) { 49188c2ecf20Sopenharmony_ci features &= ~NETIF_F_RXCSUM; 49198c2ecf20Sopenharmony_ci features |= dev->features & NETIF_F_RXCSUM; 49208c2ecf20Sopenharmony_ci } 49218c2ecf20Sopenharmony_ci 49228c2ecf20Sopenharmony_ci if (changed & NETIF_F_LOOPBACK) { 49238c2ecf20Sopenharmony_ci features &= ~NETIF_F_LOOPBACK; 49248c2ecf20Sopenharmony_ci features |= dev->features & NETIF_F_LOOPBACK; 49258c2ecf20Sopenharmony_ci } 49268c2ecf20Sopenharmony_ci } 49278c2ecf20Sopenharmony_ci 49288c2ecf20Sopenharmony_ci /* TPA requires Rx CSUM offloading */ 49298c2ecf20Sopenharmony_ci if (!(features & NETIF_F_RXCSUM)) 49308c2ecf20Sopenharmony_ci features &= ~NETIF_F_LRO; 49318c2ecf20Sopenharmony_ci 49328c2ecf20Sopenharmony_ci if (!(features & NETIF_F_GRO) || !bnx2x_mtu_allows_gro(dev->mtu)) 49338c2ecf20Sopenharmony_ci features &= ~NETIF_F_GRO_HW; 49348c2ecf20Sopenharmony_ci if (features & NETIF_F_GRO_HW) 49358c2ecf20Sopenharmony_ci features &= ~NETIF_F_LRO; 49368c2ecf20Sopenharmony_ci 49378c2ecf20Sopenharmony_ci return features; 49388c2ecf20Sopenharmony_ci} 49398c2ecf20Sopenharmony_ci 49408c2ecf20Sopenharmony_ciint bnx2x_set_features(struct net_device *dev, netdev_features_t features) 49418c2ecf20Sopenharmony_ci{ 49428c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 49438c2ecf20Sopenharmony_ci netdev_features_t changes = features ^ dev->features; 49448c2ecf20Sopenharmony_ci bool bnx2x_reload = false; 49458c2ecf20Sopenharmony_ci int rc; 49468c2ecf20Sopenharmony_ci 49478c2ecf20Sopenharmony_ci /* VFs or non SRIOV PFs should be able to change loopback feature */ 49488c2ecf20Sopenharmony_ci if (!pci_num_vf(bp->pdev)) { 49498c2ecf20Sopenharmony_ci if (features & NETIF_F_LOOPBACK) { 49508c2ecf20Sopenharmony_ci if (bp->link_params.loopback_mode != LOOPBACK_BMAC) { 49518c2ecf20Sopenharmony_ci bp->link_params.loopback_mode = LOOPBACK_BMAC; 49528c2ecf20Sopenharmony_ci bnx2x_reload = true; 49538c2ecf20Sopenharmony_ci } 49548c2ecf20Sopenharmony_ci } else { 49558c2ecf20Sopenharmony_ci if (bp->link_params.loopback_mode != LOOPBACK_NONE) { 49568c2ecf20Sopenharmony_ci bp->link_params.loopback_mode = LOOPBACK_NONE; 49578c2ecf20Sopenharmony_ci bnx2x_reload = true; 49588c2ecf20Sopenharmony_ci } 49598c2ecf20Sopenharmony_ci } 49608c2ecf20Sopenharmony_ci } 49618c2ecf20Sopenharmony_ci 49628c2ecf20Sopenharmony_ci /* Don't care about GRO changes */ 49638c2ecf20Sopenharmony_ci changes &= ~NETIF_F_GRO; 49648c2ecf20Sopenharmony_ci 49658c2ecf20Sopenharmony_ci if (changes) 49668c2ecf20Sopenharmony_ci bnx2x_reload = true; 49678c2ecf20Sopenharmony_ci 49688c2ecf20Sopenharmony_ci if (bnx2x_reload) { 49698c2ecf20Sopenharmony_ci if (bp->recovery_state == BNX2X_RECOVERY_DONE) { 49708c2ecf20Sopenharmony_ci dev->features = features; 49718c2ecf20Sopenharmony_ci rc = bnx2x_reload_if_running(dev); 49728c2ecf20Sopenharmony_ci return rc ? rc : 1; 49738c2ecf20Sopenharmony_ci } 49748c2ecf20Sopenharmony_ci /* else: bnx2x_nic_load() will be called at end of recovery */ 49758c2ecf20Sopenharmony_ci } 49768c2ecf20Sopenharmony_ci 49778c2ecf20Sopenharmony_ci return 0; 49788c2ecf20Sopenharmony_ci} 49798c2ecf20Sopenharmony_ci 49808c2ecf20Sopenharmony_civoid bnx2x_tx_timeout(struct net_device *dev, unsigned int txqueue) 49818c2ecf20Sopenharmony_ci{ 49828c2ecf20Sopenharmony_ci struct bnx2x *bp = netdev_priv(dev); 49838c2ecf20Sopenharmony_ci 49848c2ecf20Sopenharmony_ci /* We want the information of the dump logged, 49858c2ecf20Sopenharmony_ci * but calling bnx2x_panic() would kill all chances of recovery. 49868c2ecf20Sopenharmony_ci */ 49878c2ecf20Sopenharmony_ci if (!bp->panic) 49888c2ecf20Sopenharmony_ci#ifndef BNX2X_STOP_ON_ERROR 49898c2ecf20Sopenharmony_ci bnx2x_panic_dump(bp, false); 49908c2ecf20Sopenharmony_ci#else 49918c2ecf20Sopenharmony_ci bnx2x_panic(); 49928c2ecf20Sopenharmony_ci#endif 49938c2ecf20Sopenharmony_ci 49948c2ecf20Sopenharmony_ci /* This allows the netif to be shutdown gracefully before resetting */ 49958c2ecf20Sopenharmony_ci bnx2x_schedule_sp_rtnl(bp, BNX2X_SP_RTNL_TX_TIMEOUT, 0); 49968c2ecf20Sopenharmony_ci} 49978c2ecf20Sopenharmony_ci 49988c2ecf20Sopenharmony_cistatic int __maybe_unused bnx2x_suspend(struct device *dev_d) 49998c2ecf20Sopenharmony_ci{ 50008c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_d); 50018c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 50028c2ecf20Sopenharmony_ci struct bnx2x *bp; 50038c2ecf20Sopenharmony_ci 50048c2ecf20Sopenharmony_ci if (!dev) { 50058c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n"); 50068c2ecf20Sopenharmony_ci return -ENODEV; 50078c2ecf20Sopenharmony_ci } 50088c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 50098c2ecf20Sopenharmony_ci 50108c2ecf20Sopenharmony_ci rtnl_lock(); 50118c2ecf20Sopenharmony_ci 50128c2ecf20Sopenharmony_ci if (!netif_running(dev)) { 50138c2ecf20Sopenharmony_ci rtnl_unlock(); 50148c2ecf20Sopenharmony_ci return 0; 50158c2ecf20Sopenharmony_ci } 50168c2ecf20Sopenharmony_ci 50178c2ecf20Sopenharmony_ci netif_device_detach(dev); 50188c2ecf20Sopenharmony_ci 50198c2ecf20Sopenharmony_ci bnx2x_nic_unload(bp, UNLOAD_CLOSE, false); 50208c2ecf20Sopenharmony_ci 50218c2ecf20Sopenharmony_ci rtnl_unlock(); 50228c2ecf20Sopenharmony_ci 50238c2ecf20Sopenharmony_ci return 0; 50248c2ecf20Sopenharmony_ci} 50258c2ecf20Sopenharmony_ci 50268c2ecf20Sopenharmony_cistatic int __maybe_unused bnx2x_resume(struct device *dev_d) 50278c2ecf20Sopenharmony_ci{ 50288c2ecf20Sopenharmony_ci struct pci_dev *pdev = to_pci_dev(dev_d); 50298c2ecf20Sopenharmony_ci struct net_device *dev = pci_get_drvdata(pdev); 50308c2ecf20Sopenharmony_ci struct bnx2x *bp; 50318c2ecf20Sopenharmony_ci int rc; 50328c2ecf20Sopenharmony_ci 50338c2ecf20Sopenharmony_ci if (!dev) { 50348c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "BAD net device from bnx2x_init_one\n"); 50358c2ecf20Sopenharmony_ci return -ENODEV; 50368c2ecf20Sopenharmony_ci } 50378c2ecf20Sopenharmony_ci bp = netdev_priv(dev); 50388c2ecf20Sopenharmony_ci 50398c2ecf20Sopenharmony_ci if (bp->recovery_state != BNX2X_RECOVERY_DONE) { 50408c2ecf20Sopenharmony_ci BNX2X_ERR("Handling parity error recovery. Try again later\n"); 50418c2ecf20Sopenharmony_ci return -EAGAIN; 50428c2ecf20Sopenharmony_ci } 50438c2ecf20Sopenharmony_ci 50448c2ecf20Sopenharmony_ci rtnl_lock(); 50458c2ecf20Sopenharmony_ci 50468c2ecf20Sopenharmony_ci if (!netif_running(dev)) { 50478c2ecf20Sopenharmony_ci rtnl_unlock(); 50488c2ecf20Sopenharmony_ci return 0; 50498c2ecf20Sopenharmony_ci } 50508c2ecf20Sopenharmony_ci 50518c2ecf20Sopenharmony_ci netif_device_attach(dev); 50528c2ecf20Sopenharmony_ci 50538c2ecf20Sopenharmony_ci rc = bnx2x_nic_load(bp, LOAD_OPEN); 50548c2ecf20Sopenharmony_ci 50558c2ecf20Sopenharmony_ci rtnl_unlock(); 50568c2ecf20Sopenharmony_ci 50578c2ecf20Sopenharmony_ci return rc; 50588c2ecf20Sopenharmony_ci} 50598c2ecf20Sopenharmony_ci 50608c2ecf20Sopenharmony_ciSIMPLE_DEV_PM_OPS(bnx2x_pm_ops, bnx2x_suspend, bnx2x_resume); 50618c2ecf20Sopenharmony_ci 50628c2ecf20Sopenharmony_civoid bnx2x_set_ctx_validation(struct bnx2x *bp, struct eth_context *cxt, 50638c2ecf20Sopenharmony_ci u32 cid) 50648c2ecf20Sopenharmony_ci{ 50658c2ecf20Sopenharmony_ci if (!cxt) { 50668c2ecf20Sopenharmony_ci BNX2X_ERR("bad context pointer %p\n", cxt); 50678c2ecf20Sopenharmony_ci return; 50688c2ecf20Sopenharmony_ci } 50698c2ecf20Sopenharmony_ci 50708c2ecf20Sopenharmony_ci /* ustorm cxt validation */ 50718c2ecf20Sopenharmony_ci cxt->ustorm_ag_context.cdu_usage = 50728c2ecf20Sopenharmony_ci CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, cid), 50738c2ecf20Sopenharmony_ci CDU_REGION_NUMBER_UCM_AG, ETH_CONNECTION_TYPE); 50748c2ecf20Sopenharmony_ci /* xcontext validation */ 50758c2ecf20Sopenharmony_ci cxt->xstorm_ag_context.cdu_reserved = 50768c2ecf20Sopenharmony_ci CDU_RSRVD_VALUE_TYPE_A(HW_CID(bp, cid), 50778c2ecf20Sopenharmony_ci CDU_REGION_NUMBER_XCM_AG, ETH_CONNECTION_TYPE); 50788c2ecf20Sopenharmony_ci} 50798c2ecf20Sopenharmony_ci 50808c2ecf20Sopenharmony_cistatic void storm_memset_hc_timeout(struct bnx2x *bp, u8 port, 50818c2ecf20Sopenharmony_ci u8 fw_sb_id, u8 sb_index, 50828c2ecf20Sopenharmony_ci u8 ticks) 50838c2ecf20Sopenharmony_ci{ 50848c2ecf20Sopenharmony_ci u32 addr = BAR_CSTRORM_INTMEM + 50858c2ecf20Sopenharmony_ci CSTORM_STATUS_BLOCK_DATA_TIMEOUT_OFFSET(fw_sb_id, sb_index); 50868c2ecf20Sopenharmony_ci REG_WR8(bp, addr, ticks); 50878c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, 50888c2ecf20Sopenharmony_ci "port %x fw_sb_id %d sb_index %d ticks %d\n", 50898c2ecf20Sopenharmony_ci port, fw_sb_id, sb_index, ticks); 50908c2ecf20Sopenharmony_ci} 50918c2ecf20Sopenharmony_ci 50928c2ecf20Sopenharmony_cistatic void storm_memset_hc_disable(struct bnx2x *bp, u8 port, 50938c2ecf20Sopenharmony_ci u16 fw_sb_id, u8 sb_index, 50948c2ecf20Sopenharmony_ci u8 disable) 50958c2ecf20Sopenharmony_ci{ 50968c2ecf20Sopenharmony_ci u32 enable_flag = disable ? 0 : (1 << HC_INDEX_DATA_HC_ENABLED_SHIFT); 50978c2ecf20Sopenharmony_ci u32 addr = BAR_CSTRORM_INTMEM + 50988c2ecf20Sopenharmony_ci CSTORM_STATUS_BLOCK_DATA_FLAGS_OFFSET(fw_sb_id, sb_index); 50998c2ecf20Sopenharmony_ci u8 flags = REG_RD8(bp, addr); 51008c2ecf20Sopenharmony_ci /* clear and set */ 51018c2ecf20Sopenharmony_ci flags &= ~HC_INDEX_DATA_HC_ENABLED; 51028c2ecf20Sopenharmony_ci flags |= enable_flag; 51038c2ecf20Sopenharmony_ci REG_WR8(bp, addr, flags); 51048c2ecf20Sopenharmony_ci DP(NETIF_MSG_IFUP, 51058c2ecf20Sopenharmony_ci "port %x fw_sb_id %d sb_index %d disable %d\n", 51068c2ecf20Sopenharmony_ci port, fw_sb_id, sb_index, disable); 51078c2ecf20Sopenharmony_ci} 51088c2ecf20Sopenharmony_ci 51098c2ecf20Sopenharmony_civoid bnx2x_update_coalesce_sb_index(struct bnx2x *bp, u8 fw_sb_id, 51108c2ecf20Sopenharmony_ci u8 sb_index, u8 disable, u16 usec) 51118c2ecf20Sopenharmony_ci{ 51128c2ecf20Sopenharmony_ci int port = BP_PORT(bp); 51138c2ecf20Sopenharmony_ci u8 ticks = usec / BNX2X_BTR; 51148c2ecf20Sopenharmony_ci 51158c2ecf20Sopenharmony_ci storm_memset_hc_timeout(bp, port, fw_sb_id, sb_index, ticks); 51168c2ecf20Sopenharmony_ci 51178c2ecf20Sopenharmony_ci disable = disable ? 1 : (usec ? 0 : 1); 51188c2ecf20Sopenharmony_ci storm_memset_hc_disable(bp, port, fw_sb_id, sb_index, disable); 51198c2ecf20Sopenharmony_ci} 51208c2ecf20Sopenharmony_ci 51218c2ecf20Sopenharmony_civoid bnx2x_schedule_sp_rtnl(struct bnx2x *bp, enum sp_rtnl_flag flag, 51228c2ecf20Sopenharmony_ci u32 verbose) 51238c2ecf20Sopenharmony_ci{ 51248c2ecf20Sopenharmony_ci smp_mb__before_atomic(); 51258c2ecf20Sopenharmony_ci set_bit(flag, &bp->sp_rtnl_state); 51268c2ecf20Sopenharmony_ci smp_mb__after_atomic(); 51278c2ecf20Sopenharmony_ci DP((BNX2X_MSG_SP | verbose), "Scheduling sp_rtnl task [Flag: %d]\n", 51288c2ecf20Sopenharmony_ci flag); 51298c2ecf20Sopenharmony_ci schedule_delayed_work(&bp->sp_rtnl_task, 0); 51308c2ecf20Sopenharmony_ci} 5131