18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 38c2ecf20Sopenharmony_ci 48c2ecf20Sopenharmony_ci#include "ixgbe.h" 58c2ecf20Sopenharmony_ci#include <linux/if_ether.h> 68c2ecf20Sopenharmony_ci#include <linux/gfp.h> 78c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 88c2ecf20Sopenharmony_ci#include <generated/utsrelease.h> 98c2ecf20Sopenharmony_ci#include <scsi/scsi_cmnd.h> 108c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h> 118c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fs.h> 128c2ecf20Sopenharmony_ci#include <scsi/fc/fc_fcoe.h> 138c2ecf20Sopenharmony_ci#include <scsi/libfc.h> 148c2ecf20Sopenharmony_ci#include <scsi/libfcoe.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci/** 178c2ecf20Sopenharmony_ci * ixgbe_fcoe_clear_ddp - clear the given ddp context 188c2ecf20Sopenharmony_ci * @ddp: ptr to the ixgbe_fcoe_ddp 198c2ecf20Sopenharmony_ci * 208c2ecf20Sopenharmony_ci * Returns : none 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci */ 238c2ecf20Sopenharmony_cistatic inline void ixgbe_fcoe_clear_ddp(struct ixgbe_fcoe_ddp *ddp) 248c2ecf20Sopenharmony_ci{ 258c2ecf20Sopenharmony_ci ddp->len = 0; 268c2ecf20Sopenharmony_ci ddp->err = 1; 278c2ecf20Sopenharmony_ci ddp->udl = NULL; 288c2ecf20Sopenharmony_ci ddp->udp = 0UL; 298c2ecf20Sopenharmony_ci ddp->sgl = NULL; 308c2ecf20Sopenharmony_ci ddp->sgc = 0; 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci/** 348c2ecf20Sopenharmony_ci * ixgbe_fcoe_ddp_put - free the ddp context for a given xid 358c2ecf20Sopenharmony_ci * @netdev: the corresponding net_device 368c2ecf20Sopenharmony_ci * @xid: the xid that corresponding ddp will be freed 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * This is the implementation of net_device_ops.ndo_fcoe_ddp_done 398c2ecf20Sopenharmony_ci * and it is expected to be called by ULD, i.e., FCP layer of libfc 408c2ecf20Sopenharmony_ci * to release the corresponding ddp context when the I/O is done. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Returns : data length already ddp-ed in bytes 438c2ecf20Sopenharmony_ci */ 448c2ecf20Sopenharmony_ciint ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci int len; 478c2ecf20Sopenharmony_ci struct ixgbe_fcoe *fcoe; 488c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter; 498c2ecf20Sopenharmony_ci struct ixgbe_fcoe_ddp *ddp; 508c2ecf20Sopenharmony_ci struct ixgbe_hw *hw; 518c2ecf20Sopenharmony_ci u32 fcbuff; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci if (!netdev) 548c2ecf20Sopenharmony_ci return 0; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (xid >= netdev->fcoe_ddp_xid) 578c2ecf20Sopenharmony_ci return 0; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci adapter = netdev_priv(netdev); 608c2ecf20Sopenharmony_ci fcoe = &adapter->fcoe; 618c2ecf20Sopenharmony_ci ddp = &fcoe->ddp[xid]; 628c2ecf20Sopenharmony_ci if (!ddp->udl) 638c2ecf20Sopenharmony_ci return 0; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci hw = &adapter->hw; 668c2ecf20Sopenharmony_ci len = ddp->len; 678c2ecf20Sopenharmony_ci /* if no error then skip ddp context invalidation */ 688c2ecf20Sopenharmony_ci if (!ddp->err) 698c2ecf20Sopenharmony_ci goto skip_ddpinv; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_X550) { 728c2ecf20Sopenharmony_ci /* X550 does not require DDP FCoE lock */ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(0, xid), 0); 758c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(3, xid), 768c2ecf20Sopenharmony_ci (xid | IXGBE_FCFLTRW_WE)); 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci /* program FCBUFF */ 798c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(2, xid), 0); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci /* program FCDMARW */ 828c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(3, xid), 838c2ecf20Sopenharmony_ci (xid | IXGBE_FCDMARW_WE)); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci /* read FCBUFF to check context invalidated */ 868c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(3, xid), 878c2ecf20Sopenharmony_ci (xid | IXGBE_FCDMARW_RE)); 888c2ecf20Sopenharmony_ci fcbuff = IXGBE_READ_REG(hw, IXGBE_FCDDC(2, xid)); 898c2ecf20Sopenharmony_ci } else { 908c2ecf20Sopenharmony_ci /* other hardware requires DDP FCoE lock */ 918c2ecf20Sopenharmony_ci spin_lock_bh(&fcoe->lock); 928c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCFLT, 0); 938c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCFLTRW, 948c2ecf20Sopenharmony_ci (xid | IXGBE_FCFLTRW_WE)); 958c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCBUFF, 0); 968c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, 978c2ecf20Sopenharmony_ci (xid | IXGBE_FCDMARW_WE)); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci /* guaranteed to be invalidated after 100us */ 1008c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, 1018c2ecf20Sopenharmony_ci (xid | IXGBE_FCDMARW_RE)); 1028c2ecf20Sopenharmony_ci fcbuff = IXGBE_READ_REG(hw, IXGBE_FCBUFF); 1038c2ecf20Sopenharmony_ci spin_unlock_bh(&fcoe->lock); 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (fcbuff & IXGBE_FCBUFF_VALID) 1078c2ecf20Sopenharmony_ci usleep_range(100, 150); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ciskip_ddpinv: 1108c2ecf20Sopenharmony_ci if (ddp->sgl) 1118c2ecf20Sopenharmony_ci dma_unmap_sg(&adapter->pdev->dev, ddp->sgl, ddp->sgc, 1128c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 1138c2ecf20Sopenharmony_ci if (ddp->pool) { 1148c2ecf20Sopenharmony_ci dma_pool_free(ddp->pool, ddp->udl, ddp->udp); 1158c2ecf20Sopenharmony_ci ddp->pool = NULL; 1168c2ecf20Sopenharmony_ci } 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci ixgbe_fcoe_clear_ddp(ddp); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci return len; 1218c2ecf20Sopenharmony_ci} 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci/** 1248c2ecf20Sopenharmony_ci * ixgbe_fcoe_ddp_setup - called to set up ddp context 1258c2ecf20Sopenharmony_ci * @netdev: the corresponding net_device 1268c2ecf20Sopenharmony_ci * @xid: the exchange id requesting ddp 1278c2ecf20Sopenharmony_ci * @sgl: the scatter-gather list for this request 1288c2ecf20Sopenharmony_ci * @sgc: the number of scatter-gather items 1298c2ecf20Sopenharmony_ci * @target_mode: 1 to setup target mode, 0 to setup initiator mode 1308c2ecf20Sopenharmony_ci * 1318c2ecf20Sopenharmony_ci * Returns : 1 for success and 0 for no ddp 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid, 1348c2ecf20Sopenharmony_ci struct scatterlist *sgl, unsigned int sgc, 1358c2ecf20Sopenharmony_ci int target_mode) 1368c2ecf20Sopenharmony_ci{ 1378c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter; 1388c2ecf20Sopenharmony_ci struct ixgbe_hw *hw; 1398c2ecf20Sopenharmony_ci struct ixgbe_fcoe *fcoe; 1408c2ecf20Sopenharmony_ci struct ixgbe_fcoe_ddp *ddp; 1418c2ecf20Sopenharmony_ci struct ixgbe_fcoe_ddp_pool *ddp_pool; 1428c2ecf20Sopenharmony_ci struct scatterlist *sg; 1438c2ecf20Sopenharmony_ci unsigned int i, j, dmacount; 1448c2ecf20Sopenharmony_ci unsigned int len; 1458c2ecf20Sopenharmony_ci static const unsigned int bufflen = IXGBE_FCBUFF_MIN; 1468c2ecf20Sopenharmony_ci unsigned int firstoff = 0; 1478c2ecf20Sopenharmony_ci unsigned int lastsize; 1488c2ecf20Sopenharmony_ci unsigned int thisoff = 0; 1498c2ecf20Sopenharmony_ci unsigned int thislen = 0; 1508c2ecf20Sopenharmony_ci u32 fcbuff, fcdmarw, fcfltrw, fcrxctl; 1518c2ecf20Sopenharmony_ci dma_addr_t addr = 0; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (!netdev || !sgl) 1548c2ecf20Sopenharmony_ci return 0; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci adapter = netdev_priv(netdev); 1578c2ecf20Sopenharmony_ci if (xid >= netdev->fcoe_ddp_xid) { 1588c2ecf20Sopenharmony_ci e_warn(drv, "xid=0x%x out-of-range\n", xid); 1598c2ecf20Sopenharmony_ci return 0; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci /* no DDP if we are already down or resetting */ 1638c2ecf20Sopenharmony_ci if (test_bit(__IXGBE_DOWN, &adapter->state) || 1648c2ecf20Sopenharmony_ci test_bit(__IXGBE_RESETTING, &adapter->state)) 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci fcoe = &adapter->fcoe; 1688c2ecf20Sopenharmony_ci ddp = &fcoe->ddp[xid]; 1698c2ecf20Sopenharmony_ci if (ddp->sgl) { 1708c2ecf20Sopenharmony_ci e_err(drv, "xid 0x%x w/ non-null sgl=%p nents=%d\n", 1718c2ecf20Sopenharmony_ci xid, ddp->sgl, ddp->sgc); 1728c2ecf20Sopenharmony_ci return 0; 1738c2ecf20Sopenharmony_ci } 1748c2ecf20Sopenharmony_ci ixgbe_fcoe_clear_ddp(ddp); 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci if (!fcoe->ddp_pool) { 1788c2ecf20Sopenharmony_ci e_warn(drv, "No ddp_pool resources allocated\n"); 1798c2ecf20Sopenharmony_ci return 0; 1808c2ecf20Sopenharmony_ci } 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci ddp_pool = per_cpu_ptr(fcoe->ddp_pool, get_cpu()); 1838c2ecf20Sopenharmony_ci if (!ddp_pool->pool) { 1848c2ecf20Sopenharmony_ci e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid); 1858c2ecf20Sopenharmony_ci goto out_noddp; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci /* setup dma from scsi command sgl */ 1898c2ecf20Sopenharmony_ci dmacount = dma_map_sg(&adapter->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); 1908c2ecf20Sopenharmony_ci if (dmacount == 0) { 1918c2ecf20Sopenharmony_ci e_err(drv, "xid 0x%x DMA map error\n", xid); 1928c2ecf20Sopenharmony_ci goto out_noddp; 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci /* alloc the udl from per cpu ddp pool */ 1968c2ecf20Sopenharmony_ci ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp); 1978c2ecf20Sopenharmony_ci if (!ddp->udl) { 1988c2ecf20Sopenharmony_ci e_err(drv, "failed allocated ddp context\n"); 1998c2ecf20Sopenharmony_ci goto out_noddp_unmap; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci ddp->pool = ddp_pool->pool; 2028c2ecf20Sopenharmony_ci ddp->sgl = sgl; 2038c2ecf20Sopenharmony_ci ddp->sgc = sgc; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci j = 0; 2068c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, dmacount, i) { 2078c2ecf20Sopenharmony_ci addr = sg_dma_address(sg); 2088c2ecf20Sopenharmony_ci len = sg_dma_len(sg); 2098c2ecf20Sopenharmony_ci while (len) { 2108c2ecf20Sopenharmony_ci /* max number of buffers allowed in one DDP context */ 2118c2ecf20Sopenharmony_ci if (j >= IXGBE_BUFFCNT_MAX) { 2128c2ecf20Sopenharmony_ci ddp_pool->noddp++; 2138c2ecf20Sopenharmony_ci goto out_noddp_free; 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci /* get the offset of length of current buffer */ 2178c2ecf20Sopenharmony_ci thisoff = addr & ((dma_addr_t)bufflen - 1); 2188c2ecf20Sopenharmony_ci thislen = min((bufflen - thisoff), len); 2198c2ecf20Sopenharmony_ci /* 2208c2ecf20Sopenharmony_ci * all but the 1st buffer (j == 0) 2218c2ecf20Sopenharmony_ci * must be aligned on bufflen 2228c2ecf20Sopenharmony_ci */ 2238c2ecf20Sopenharmony_ci if ((j != 0) && (thisoff)) 2248c2ecf20Sopenharmony_ci goto out_noddp_free; 2258c2ecf20Sopenharmony_ci /* 2268c2ecf20Sopenharmony_ci * all but the last buffer 2278c2ecf20Sopenharmony_ci * ((i == (dmacount - 1)) && (thislen == len)) 2288c2ecf20Sopenharmony_ci * must end at bufflen 2298c2ecf20Sopenharmony_ci */ 2308c2ecf20Sopenharmony_ci if (((i != (dmacount - 1)) || (thislen != len)) 2318c2ecf20Sopenharmony_ci && ((thislen + thisoff) != bufflen)) 2328c2ecf20Sopenharmony_ci goto out_noddp_free; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_ci ddp->udl[j] = (u64)(addr - thisoff); 2358c2ecf20Sopenharmony_ci /* only the first buffer may have none-zero offset */ 2368c2ecf20Sopenharmony_ci if (j == 0) 2378c2ecf20Sopenharmony_ci firstoff = thisoff; 2388c2ecf20Sopenharmony_ci len -= thislen; 2398c2ecf20Sopenharmony_ci addr += thislen; 2408c2ecf20Sopenharmony_ci j++; 2418c2ecf20Sopenharmony_ci } 2428c2ecf20Sopenharmony_ci } 2438c2ecf20Sopenharmony_ci /* only the last buffer may have non-full bufflen */ 2448c2ecf20Sopenharmony_ci lastsize = thisoff + thislen; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci /* 2478c2ecf20Sopenharmony_ci * lastsize can not be buffer len. 2488c2ecf20Sopenharmony_ci * If it is then adding another buffer with lastsize = 1. 2498c2ecf20Sopenharmony_ci */ 2508c2ecf20Sopenharmony_ci if (lastsize == bufflen) { 2518c2ecf20Sopenharmony_ci if (j >= IXGBE_BUFFCNT_MAX) { 2528c2ecf20Sopenharmony_ci ddp_pool->noddp_ext_buff++; 2538c2ecf20Sopenharmony_ci goto out_noddp_free; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma); 2578c2ecf20Sopenharmony_ci j++; 2588c2ecf20Sopenharmony_ci lastsize = 1; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci put_cpu(); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); 2638c2ecf20Sopenharmony_ci fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT); 2648c2ecf20Sopenharmony_ci fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); 2658c2ecf20Sopenharmony_ci /* Set WRCONTX bit to allow DDP for target */ 2668c2ecf20Sopenharmony_ci if (target_mode) 2678c2ecf20Sopenharmony_ci fcbuff |= (IXGBE_FCBUFF_WRCONTX); 2688c2ecf20Sopenharmony_ci fcbuff |= (IXGBE_FCBUFF_VALID); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci fcdmarw = xid; 2718c2ecf20Sopenharmony_ci fcdmarw |= IXGBE_FCDMARW_WE; 2728c2ecf20Sopenharmony_ci fcdmarw |= (lastsize << IXGBE_FCDMARW_LASTSIZE_SHIFT); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci fcfltrw = xid; 2758c2ecf20Sopenharmony_ci fcfltrw |= IXGBE_FCFLTRW_WE; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci /* program DMA context */ 2788c2ecf20Sopenharmony_ci hw = &adapter->hw; 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci /* turn on last frame indication for target mode as FCP_RSPtarget is 2818c2ecf20Sopenharmony_ci * supposed to send FCP_RSP when it is done. */ 2828c2ecf20Sopenharmony_ci if (target_mode && !test_bit(__IXGBE_FCOE_TARGET, &fcoe->mode)) { 2838c2ecf20Sopenharmony_ci set_bit(__IXGBE_FCOE_TARGET, &fcoe->mode); 2848c2ecf20Sopenharmony_ci fcrxctl = IXGBE_READ_REG(hw, IXGBE_FCRXCTRL); 2858c2ecf20Sopenharmony_ci fcrxctl |= IXGBE_FCRXCTRL_LASTSEQH; 2868c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, fcrxctl); 2878c2ecf20Sopenharmony_ci } 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_X550) { 2908c2ecf20Sopenharmony_ci /* X550 does not require DDP lock */ 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(0, xid), 2938c2ecf20Sopenharmony_ci ddp->udp & DMA_BIT_MASK(32)); 2948c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(1, xid), (u64)ddp->udp >> 32); 2958c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(2, xid), fcbuff); 2968c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(3, xid), fcdmarw); 2978c2ecf20Sopenharmony_ci /* program filter context */ 2988c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(0, xid), IXGBE_FCFLT_VALID); 2998c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(1, xid), 0); 3008c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(3, xid), fcfltrw); 3018c2ecf20Sopenharmony_ci } else { 3028c2ecf20Sopenharmony_ci /* DDP lock for indirect DDP context access */ 3038c2ecf20Sopenharmony_ci spin_lock_bh(&fcoe->lock); 3048c2ecf20Sopenharmony_ci 3058c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCPTRL, ddp->udp & DMA_BIT_MASK(32)); 3068c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCPTRH, (u64)ddp->udp >> 32); 3078c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCBUFF, fcbuff); 3088c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, fcdmarw); 3098c2ecf20Sopenharmony_ci /* program filter context */ 3108c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCPARAM, 0); 3118c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCFLT, IXGBE_FCFLT_VALID); 3128c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCFLTRW, fcfltrw); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci spin_unlock_bh(&fcoe->lock); 3158c2ecf20Sopenharmony_ci } 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci return 1; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ciout_noddp_free: 3208c2ecf20Sopenharmony_ci dma_pool_free(ddp->pool, ddp->udl, ddp->udp); 3218c2ecf20Sopenharmony_ci ixgbe_fcoe_clear_ddp(ddp); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ciout_noddp_unmap: 3248c2ecf20Sopenharmony_ci dma_unmap_sg(&adapter->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); 3258c2ecf20Sopenharmony_ciout_noddp: 3268c2ecf20Sopenharmony_ci put_cpu(); 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci/** 3318c2ecf20Sopenharmony_ci * ixgbe_fcoe_ddp_get - called to set up ddp context in initiator mode 3328c2ecf20Sopenharmony_ci * @netdev: the corresponding net_device 3338c2ecf20Sopenharmony_ci * @xid: the exchange id requesting ddp 3348c2ecf20Sopenharmony_ci * @sgl: the scatter-gather list for this request 3358c2ecf20Sopenharmony_ci * @sgc: the number of scatter-gather items 3368c2ecf20Sopenharmony_ci * 3378c2ecf20Sopenharmony_ci * This is the implementation of net_device_ops.ndo_fcoe_ddp_setup 3388c2ecf20Sopenharmony_ci * and is expected to be called from ULD, e.g., FCP layer of libfc 3398c2ecf20Sopenharmony_ci * to set up ddp for the corresponding xid of the given sglist for 3408c2ecf20Sopenharmony_ci * the corresponding I/O. 3418c2ecf20Sopenharmony_ci * 3428c2ecf20Sopenharmony_ci * Returns : 1 for success and 0 for no ddp 3438c2ecf20Sopenharmony_ci */ 3448c2ecf20Sopenharmony_ciint ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, 3458c2ecf20Sopenharmony_ci struct scatterlist *sgl, unsigned int sgc) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci return ixgbe_fcoe_ddp_setup(netdev, xid, sgl, sgc, 0); 3488c2ecf20Sopenharmony_ci} 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/** 3518c2ecf20Sopenharmony_ci * ixgbe_fcoe_ddp_target - called to set up ddp context in target mode 3528c2ecf20Sopenharmony_ci * @netdev: the corresponding net_device 3538c2ecf20Sopenharmony_ci * @xid: the exchange id requesting ddp 3548c2ecf20Sopenharmony_ci * @sgl: the scatter-gather list for this request 3558c2ecf20Sopenharmony_ci * @sgc: the number of scatter-gather items 3568c2ecf20Sopenharmony_ci * 3578c2ecf20Sopenharmony_ci * This is the implementation of net_device_ops.ndo_fcoe_ddp_target 3588c2ecf20Sopenharmony_ci * and is expected to be called from ULD, e.g., FCP layer of libfc 3598c2ecf20Sopenharmony_ci * to set up ddp for the corresponding xid of the given sglist for 3608c2ecf20Sopenharmony_ci * the corresponding I/O. The DDP in target mode is a write I/O request 3618c2ecf20Sopenharmony_ci * from the initiator. 3628c2ecf20Sopenharmony_ci * 3638c2ecf20Sopenharmony_ci * Returns : 1 for success and 0 for no ddp 3648c2ecf20Sopenharmony_ci */ 3658c2ecf20Sopenharmony_ciint ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid, 3668c2ecf20Sopenharmony_ci struct scatterlist *sgl, unsigned int sgc) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci return ixgbe_fcoe_ddp_setup(netdev, xid, sgl, sgc, 1); 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci/** 3728c2ecf20Sopenharmony_ci * ixgbe_fcoe_ddp - check ddp status and mark it done 3738c2ecf20Sopenharmony_ci * @adapter: ixgbe adapter 3748c2ecf20Sopenharmony_ci * @rx_desc: advanced rx descriptor 3758c2ecf20Sopenharmony_ci * @skb: the skb holding the received data 3768c2ecf20Sopenharmony_ci * 3778c2ecf20Sopenharmony_ci * This checks ddp status. 3788c2ecf20Sopenharmony_ci * 3798c2ecf20Sopenharmony_ci * Returns : < 0 indicates an error or not a FCiE ddp, 0 indicates 3808c2ecf20Sopenharmony_ci * not passing the skb to ULD, > 0 indicates is the length of data 3818c2ecf20Sopenharmony_ci * being ddped. 3828c2ecf20Sopenharmony_ci */ 3838c2ecf20Sopenharmony_ciint ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, 3848c2ecf20Sopenharmony_ci union ixgbe_adv_rx_desc *rx_desc, 3858c2ecf20Sopenharmony_ci struct sk_buff *skb) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci int rc = -EINVAL; 3888c2ecf20Sopenharmony_ci struct ixgbe_fcoe *fcoe; 3898c2ecf20Sopenharmony_ci struct ixgbe_fcoe_ddp *ddp; 3908c2ecf20Sopenharmony_ci struct fc_frame_header *fh; 3918c2ecf20Sopenharmony_ci struct fcoe_crc_eof *crc; 3928c2ecf20Sopenharmony_ci __le32 fcerr = ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_FCERR); 3938c2ecf20Sopenharmony_ci __le32 ddp_err; 3948c2ecf20Sopenharmony_ci int ddp_max; 3958c2ecf20Sopenharmony_ci u32 fctl; 3968c2ecf20Sopenharmony_ci u16 xid; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (fcerr == cpu_to_le32(IXGBE_FCERR_BADCRC)) 3998c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 4008c2ecf20Sopenharmony_ci else 4018c2ecf20Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q)) 4048c2ecf20Sopenharmony_ci fh = (struct fc_frame_header *)(skb->data + 4058c2ecf20Sopenharmony_ci sizeof(struct vlan_hdr) + sizeof(struct fcoe_hdr)); 4068c2ecf20Sopenharmony_ci else 4078c2ecf20Sopenharmony_ci fh = (struct fc_frame_header *)(skb->data + 4088c2ecf20Sopenharmony_ci sizeof(struct fcoe_hdr)); 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci fctl = ntoh24(fh->fh_f_ctl); 4118c2ecf20Sopenharmony_ci if (fctl & FC_FC_EX_CTX) 4128c2ecf20Sopenharmony_ci xid = be16_to_cpu(fh->fh_ox_id); 4138c2ecf20Sopenharmony_ci else 4148c2ecf20Sopenharmony_ci xid = be16_to_cpu(fh->fh_rx_id); 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci ddp_max = IXGBE_FCOE_DDP_MAX; 4178c2ecf20Sopenharmony_ci /* X550 has different DDP Max limit */ 4188c2ecf20Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) 4198c2ecf20Sopenharmony_ci ddp_max = IXGBE_FCOE_DDP_MAX_X550; 4208c2ecf20Sopenharmony_ci if (xid >= ddp_max) 4218c2ecf20Sopenharmony_ci return -EINVAL; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci fcoe = &adapter->fcoe; 4248c2ecf20Sopenharmony_ci ddp = &fcoe->ddp[xid]; 4258c2ecf20Sopenharmony_ci if (!ddp->udl) 4268c2ecf20Sopenharmony_ci return -EINVAL; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci ddp_err = ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_FCEOFE | 4298c2ecf20Sopenharmony_ci IXGBE_RXDADV_ERR_FCERR); 4308c2ecf20Sopenharmony_ci if (ddp_err) 4318c2ecf20Sopenharmony_ci return -EINVAL; 4328c2ecf20Sopenharmony_ci 4338c2ecf20Sopenharmony_ci switch (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_FCSTAT)) { 4348c2ecf20Sopenharmony_ci /* return 0 to bypass going to ULD for DDPed data */ 4358c2ecf20Sopenharmony_ci case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_DDP): 4368c2ecf20Sopenharmony_ci /* update length of DDPed data */ 4378c2ecf20Sopenharmony_ci ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); 4388c2ecf20Sopenharmony_ci rc = 0; 4398c2ecf20Sopenharmony_ci break; 4408c2ecf20Sopenharmony_ci /* unmap the sg list when FCPRSP is received */ 4418c2ecf20Sopenharmony_ci case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_FCPRSP): 4428c2ecf20Sopenharmony_ci dma_unmap_sg(&adapter->pdev->dev, ddp->sgl, 4438c2ecf20Sopenharmony_ci ddp->sgc, DMA_FROM_DEVICE); 4448c2ecf20Sopenharmony_ci ddp->err = (__force u32)ddp_err; 4458c2ecf20Sopenharmony_ci ddp->sgl = NULL; 4468c2ecf20Sopenharmony_ci ddp->sgc = 0; 4478c2ecf20Sopenharmony_ci fallthrough; 4488c2ecf20Sopenharmony_ci /* if DDP length is present pass it through to ULD */ 4498c2ecf20Sopenharmony_ci case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NODDP): 4508c2ecf20Sopenharmony_ci /* update length of DDPed data */ 4518c2ecf20Sopenharmony_ci ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); 4528c2ecf20Sopenharmony_ci if (ddp->len) 4538c2ecf20Sopenharmony_ci rc = ddp->len; 4548c2ecf20Sopenharmony_ci break; 4558c2ecf20Sopenharmony_ci /* no match will return as an error */ 4568c2ecf20Sopenharmony_ci case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NOMTCH): 4578c2ecf20Sopenharmony_ci default: 4588c2ecf20Sopenharmony_ci break; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* In target mode, check the last data frame of the sequence. 4628c2ecf20Sopenharmony_ci * For DDP in target mode, data is already DDPed but the header 4638c2ecf20Sopenharmony_ci * indication of the last data frame ould allow is to tell if we 4648c2ecf20Sopenharmony_ci * got all the data and the ULP can send FCP_RSP back, as this is 4658c2ecf20Sopenharmony_ci * not a full fcoe frame, we fill the trailer here so it won't be 4668c2ecf20Sopenharmony_ci * dropped by the ULP stack. 4678c2ecf20Sopenharmony_ci */ 4688c2ecf20Sopenharmony_ci if ((fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA) && 4698c2ecf20Sopenharmony_ci (fctl & FC_FC_END_SEQ)) { 4708c2ecf20Sopenharmony_ci skb_linearize(skb); 4718c2ecf20Sopenharmony_ci crc = skb_put(skb, sizeof(*crc)); 4728c2ecf20Sopenharmony_ci crc->fcoe_eof = FC_EOF_T; 4738c2ecf20Sopenharmony_ci } 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci return rc; 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci/** 4798c2ecf20Sopenharmony_ci * ixgbe_fso - ixgbe FCoE Sequence Offload (FSO) 4808c2ecf20Sopenharmony_ci * @tx_ring: tx desc ring 4818c2ecf20Sopenharmony_ci * @first: first tx_buffer structure containing skb, tx_flags, and protocol 4828c2ecf20Sopenharmony_ci * @hdr_len: hdr_len to be returned 4838c2ecf20Sopenharmony_ci * 4848c2ecf20Sopenharmony_ci * This sets up large send offload for FCoE 4858c2ecf20Sopenharmony_ci * 4868c2ecf20Sopenharmony_ci * Returns : 0 indicates success, < 0 for error 4878c2ecf20Sopenharmony_ci */ 4888c2ecf20Sopenharmony_ciint ixgbe_fso(struct ixgbe_ring *tx_ring, 4898c2ecf20Sopenharmony_ci struct ixgbe_tx_buffer *first, 4908c2ecf20Sopenharmony_ci u8 *hdr_len) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct sk_buff *skb = first->skb; 4938c2ecf20Sopenharmony_ci struct fc_frame_header *fh; 4948c2ecf20Sopenharmony_ci u32 vlan_macip_lens; 4958c2ecf20Sopenharmony_ci u32 fcoe_sof_eof = 0; 4968c2ecf20Sopenharmony_ci u32 mss_l4len_idx; 4978c2ecf20Sopenharmony_ci u32 type_tucmd = IXGBE_ADVTXT_TUCMD_FCOE; 4988c2ecf20Sopenharmony_ci u8 sof, eof; 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) { 5018c2ecf20Sopenharmony_ci dev_err(tx_ring->dev, "Wrong gso type %d:expecting SKB_GSO_FCOE\n", 5028c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_type); 5038c2ecf20Sopenharmony_ci return -EINVAL; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci /* resets the header to point fcoe/fc */ 5078c2ecf20Sopenharmony_ci skb_set_network_header(skb, skb->mac_len); 5088c2ecf20Sopenharmony_ci skb_set_transport_header(skb, skb->mac_len + 5098c2ecf20Sopenharmony_ci sizeof(struct fcoe_hdr)); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci /* sets up SOF and ORIS */ 5128c2ecf20Sopenharmony_ci sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof; 5138c2ecf20Sopenharmony_ci switch (sof) { 5148c2ecf20Sopenharmony_ci case FC_SOF_I2: 5158c2ecf20Sopenharmony_ci fcoe_sof_eof = IXGBE_ADVTXD_FCOEF_ORIS; 5168c2ecf20Sopenharmony_ci break; 5178c2ecf20Sopenharmony_ci case FC_SOF_I3: 5188c2ecf20Sopenharmony_ci fcoe_sof_eof = IXGBE_ADVTXD_FCOEF_SOF | 5198c2ecf20Sopenharmony_ci IXGBE_ADVTXD_FCOEF_ORIS; 5208c2ecf20Sopenharmony_ci break; 5218c2ecf20Sopenharmony_ci case FC_SOF_N2: 5228c2ecf20Sopenharmony_ci break; 5238c2ecf20Sopenharmony_ci case FC_SOF_N3: 5248c2ecf20Sopenharmony_ci fcoe_sof_eof = IXGBE_ADVTXD_FCOEF_SOF; 5258c2ecf20Sopenharmony_ci break; 5268c2ecf20Sopenharmony_ci default: 5278c2ecf20Sopenharmony_ci dev_warn(tx_ring->dev, "unknown sof = 0x%x\n", sof); 5288c2ecf20Sopenharmony_ci return -EINVAL; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* the first byte of the last dword is EOF */ 5328c2ecf20Sopenharmony_ci skb_copy_bits(skb, skb->len - 4, &eof, 1); 5338c2ecf20Sopenharmony_ci /* sets up EOF and ORIE */ 5348c2ecf20Sopenharmony_ci switch (eof) { 5358c2ecf20Sopenharmony_ci case FC_EOF_N: 5368c2ecf20Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N; 5378c2ecf20Sopenharmony_ci break; 5388c2ecf20Sopenharmony_ci case FC_EOF_T: 5398c2ecf20Sopenharmony_ci /* lso needs ORIE */ 5408c2ecf20Sopenharmony_ci if (skb_is_gso(skb)) 5418c2ecf20Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N | 5428c2ecf20Sopenharmony_ci IXGBE_ADVTXD_FCOEF_ORIE; 5438c2ecf20Sopenharmony_ci else 5448c2ecf20Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_T; 5458c2ecf20Sopenharmony_ci break; 5468c2ecf20Sopenharmony_ci case FC_EOF_NI: 5478c2ecf20Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_NI; 5488c2ecf20Sopenharmony_ci break; 5498c2ecf20Sopenharmony_ci case FC_EOF_A: 5508c2ecf20Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_A; 5518c2ecf20Sopenharmony_ci break; 5528c2ecf20Sopenharmony_ci default: 5538c2ecf20Sopenharmony_ci dev_warn(tx_ring->dev, "unknown eof = 0x%x\n", eof); 5548c2ecf20Sopenharmony_ci return -EINVAL; 5558c2ecf20Sopenharmony_ci } 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci /* sets up PARINC indicating data offset */ 5588c2ecf20Sopenharmony_ci fh = (struct fc_frame_header *)skb_transport_header(skb); 5598c2ecf20Sopenharmony_ci if (fh->fh_f_ctl[2] & FC_FC_REL_OFF) 5608c2ecf20Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_PARINC; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* include trailer in headlen as it is replicated per frame */ 5638c2ecf20Sopenharmony_ci *hdr_len = sizeof(struct fcoe_crc_eof); 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci /* hdr_len includes fc_hdr if FCoE LSO is enabled */ 5668c2ecf20Sopenharmony_ci if (skb_is_gso(skb)) { 5678c2ecf20Sopenharmony_ci *hdr_len += skb_transport_offset(skb) + 5688c2ecf20Sopenharmony_ci sizeof(struct fc_frame_header); 5698c2ecf20Sopenharmony_ci /* update gso_segs and bytecount */ 5708c2ecf20Sopenharmony_ci first->gso_segs = DIV_ROUND_UP(skb->len - *hdr_len, 5718c2ecf20Sopenharmony_ci skb_shinfo(skb)->gso_size); 5728c2ecf20Sopenharmony_ci first->bytecount += (first->gso_segs - 1) * *hdr_len; 5738c2ecf20Sopenharmony_ci first->tx_flags |= IXGBE_TX_FLAGS_TSO; 5748c2ecf20Sopenharmony_ci /* Hardware expects L4T to be RSV for FCoE TSO */ 5758c2ecf20Sopenharmony_ci type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_RSV; 5768c2ecf20Sopenharmony_ci } 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci /* set flag indicating FCOE to ixgbe_tx_map call */ 5798c2ecf20Sopenharmony_ci first->tx_flags |= IXGBE_TX_FLAGS_FCOE | IXGBE_TX_FLAGS_CC; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci /* mss_l4len_id: use 0 for FSO as TSO, no need for L4LEN */ 5828c2ecf20Sopenharmony_ci mss_l4len_idx = skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ci /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */ 5858c2ecf20Sopenharmony_ci vlan_macip_lens = skb_transport_offset(skb) + 5868c2ecf20Sopenharmony_ci sizeof(struct fc_frame_header); 5878c2ecf20Sopenharmony_ci vlan_macip_lens |= (skb_transport_offset(skb) - 4) 5888c2ecf20Sopenharmony_ci << IXGBE_ADVTXD_MACLEN_SHIFT; 5898c2ecf20Sopenharmony_ci vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK; 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci /* write context desc */ 5928c2ecf20Sopenharmony_ci ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, fcoe_sof_eof, 5938c2ecf20Sopenharmony_ci type_tucmd, mss_l4len_idx); 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci return 0; 5968c2ecf20Sopenharmony_ci} 5978c2ecf20Sopenharmony_ci 5988c2ecf20Sopenharmony_cistatic void ixgbe_fcoe_dma_pool_free(struct ixgbe_fcoe *fcoe, unsigned int cpu) 5998c2ecf20Sopenharmony_ci{ 6008c2ecf20Sopenharmony_ci struct ixgbe_fcoe_ddp_pool *ddp_pool; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu); 6038c2ecf20Sopenharmony_ci dma_pool_destroy(ddp_pool->pool); 6048c2ecf20Sopenharmony_ci ddp_pool->pool = NULL; 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistatic int ixgbe_fcoe_dma_pool_alloc(struct ixgbe_fcoe *fcoe, 6088c2ecf20Sopenharmony_ci struct device *dev, 6098c2ecf20Sopenharmony_ci unsigned int cpu) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct ixgbe_fcoe_ddp_pool *ddp_pool; 6128c2ecf20Sopenharmony_ci struct dma_pool *pool; 6138c2ecf20Sopenharmony_ci char pool_name[32]; 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%u", cpu); 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_ci pool = dma_pool_create(pool_name, dev, IXGBE_FCPTR_MAX, 6188c2ecf20Sopenharmony_ci IXGBE_FCPTR_ALIGN, PAGE_SIZE); 6198c2ecf20Sopenharmony_ci if (!pool) 6208c2ecf20Sopenharmony_ci return -ENOMEM; 6218c2ecf20Sopenharmony_ci 6228c2ecf20Sopenharmony_ci ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu); 6238c2ecf20Sopenharmony_ci ddp_pool->pool = pool; 6248c2ecf20Sopenharmony_ci ddp_pool->noddp = 0; 6258c2ecf20Sopenharmony_ci ddp_pool->noddp_ext_buff = 0; 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci return 0; 6288c2ecf20Sopenharmony_ci} 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci/** 6318c2ecf20Sopenharmony_ci * ixgbe_configure_fcoe - configures registers for fcoe at start 6328c2ecf20Sopenharmony_ci * @adapter: ptr to ixgbe adapter 6338c2ecf20Sopenharmony_ci * 6348c2ecf20Sopenharmony_ci * This sets up FCoE related registers 6358c2ecf20Sopenharmony_ci * 6368c2ecf20Sopenharmony_ci * Returns : none 6378c2ecf20Sopenharmony_ci */ 6388c2ecf20Sopenharmony_civoid ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) 6398c2ecf20Sopenharmony_ci{ 6408c2ecf20Sopenharmony_ci struct ixgbe_ring_feature *fcoe = &adapter->ring_feature[RING_F_FCOE]; 6418c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 6428c2ecf20Sopenharmony_ci int i, fcoe_q, fcoe_i, fcoe_q_h = 0; 6438c2ecf20Sopenharmony_ci int fcreta_size; 6448c2ecf20Sopenharmony_ci u32 etqf; 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci /* Minimal functionality for FCoE requires at least CRC offloads */ 6478c2ecf20Sopenharmony_ci if (!(adapter->netdev->features & NETIF_F_FCOE_CRC)) 6488c2ecf20Sopenharmony_ci return; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci /* Enable L2 EtherType filter for FCoE, needed for FCoE CRC and DDP */ 6518c2ecf20Sopenharmony_ci etqf = ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN; 6528c2ecf20Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { 6538c2ecf20Sopenharmony_ci etqf |= IXGBE_ETQF_POOL_ENABLE; 6548c2ecf20Sopenharmony_ci etqf |= VMDQ_P(0) << IXGBE_ETQF_POOL_SHIFT; 6558c2ecf20Sopenharmony_ci } 6568c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), etqf); 6578c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci /* leave registers un-configured if FCoE is disabled */ 6608c2ecf20Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) 6618c2ecf20Sopenharmony_ci return; 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ci /* Use one or more Rx queues for FCoE by redirection table */ 6648c2ecf20Sopenharmony_ci fcreta_size = IXGBE_FCRETA_SIZE; 6658c2ecf20Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) 6668c2ecf20Sopenharmony_ci fcreta_size = IXGBE_FCRETA_SIZE_X550; 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_ci for (i = 0; i < fcreta_size; i++) { 6698c2ecf20Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) { 6708c2ecf20Sopenharmony_ci int fcoe_i_h = fcoe->offset + ((i + fcreta_size) % 6718c2ecf20Sopenharmony_ci fcoe->indices); 6728c2ecf20Sopenharmony_ci fcoe_q_h = adapter->rx_ring[fcoe_i_h]->reg_idx; 6738c2ecf20Sopenharmony_ci fcoe_q_h = (fcoe_q_h << IXGBE_FCRETA_ENTRY_HIGH_SHIFT) & 6748c2ecf20Sopenharmony_ci IXGBE_FCRETA_ENTRY_HIGH_MASK; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci fcoe_i = fcoe->offset + (i % fcoe->indices); 6788c2ecf20Sopenharmony_ci fcoe_i &= IXGBE_FCRETA_ENTRY_MASK; 6798c2ecf20Sopenharmony_ci fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; 6808c2ecf20Sopenharmony_ci fcoe_q |= fcoe_q_h; 6818c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRETA(i), fcoe_q); 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA); 6848c2ecf20Sopenharmony_ci 6858c2ecf20Sopenharmony_ci /* Enable L2 EtherType filter for FIP */ 6868c2ecf20Sopenharmony_ci etqf = ETH_P_FIP | IXGBE_ETQF_FILTER_EN; 6878c2ecf20Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { 6888c2ecf20Sopenharmony_ci etqf |= IXGBE_ETQF_POOL_ENABLE; 6898c2ecf20Sopenharmony_ci etqf |= VMDQ_P(0) << IXGBE_ETQF_POOL_SHIFT; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FIP), etqf); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci /* Send FIP frames to the first FCoE queue */ 6948c2ecf20Sopenharmony_ci fcoe_q = adapter->rx_ring[fcoe->offset]->reg_idx; 6958c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP), 6968c2ecf20Sopenharmony_ci IXGBE_ETQS_QUEUE_EN | 6978c2ecf20Sopenharmony_ci (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci /* Configure FCoE Rx control */ 7008c2ecf20Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, 7018c2ecf20Sopenharmony_ci IXGBE_FCRXCTRL_FCCRCBO | 7028c2ecf20Sopenharmony_ci (FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT)); 7038c2ecf20Sopenharmony_ci} 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci/** 7068c2ecf20Sopenharmony_ci * ixgbe_free_fcoe_ddp_resources - release all fcoe ddp context resources 7078c2ecf20Sopenharmony_ci * @adapter : ixgbe adapter 7088c2ecf20Sopenharmony_ci * 7098c2ecf20Sopenharmony_ci * Cleans up outstanding ddp context resources 7108c2ecf20Sopenharmony_ci * 7118c2ecf20Sopenharmony_ci * Returns : none 7128c2ecf20Sopenharmony_ci */ 7138c2ecf20Sopenharmony_civoid ixgbe_free_fcoe_ddp_resources(struct ixgbe_adapter *adapter) 7148c2ecf20Sopenharmony_ci{ 7158c2ecf20Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 7168c2ecf20Sopenharmony_ci int cpu, i, ddp_max; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* do nothing if no DDP pools were allocated */ 7198c2ecf20Sopenharmony_ci if (!fcoe->ddp_pool) 7208c2ecf20Sopenharmony_ci return; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci ddp_max = IXGBE_FCOE_DDP_MAX; 7238c2ecf20Sopenharmony_ci /* X550 has different DDP Max limit */ 7248c2ecf20Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) 7258c2ecf20Sopenharmony_ci ddp_max = IXGBE_FCOE_DDP_MAX_X550; 7268c2ecf20Sopenharmony_ci 7278c2ecf20Sopenharmony_ci for (i = 0; i < ddp_max; i++) 7288c2ecf20Sopenharmony_ci ixgbe_fcoe_ddp_put(adapter->netdev, i); 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) 7318c2ecf20Sopenharmony_ci ixgbe_fcoe_dma_pool_free(fcoe, cpu); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci dma_unmap_single(&adapter->pdev->dev, 7348c2ecf20Sopenharmony_ci fcoe->extra_ddp_buffer_dma, 7358c2ecf20Sopenharmony_ci IXGBE_FCBUFF_MIN, 7368c2ecf20Sopenharmony_ci DMA_FROM_DEVICE); 7378c2ecf20Sopenharmony_ci kfree(fcoe->extra_ddp_buffer); 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci fcoe->extra_ddp_buffer = NULL; 7408c2ecf20Sopenharmony_ci fcoe->extra_ddp_buffer_dma = 0; 7418c2ecf20Sopenharmony_ci} 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci/** 7448c2ecf20Sopenharmony_ci * ixgbe_setup_fcoe_ddp_resources - setup all fcoe ddp context resources 7458c2ecf20Sopenharmony_ci * @adapter: ixgbe adapter 7468c2ecf20Sopenharmony_ci * 7478c2ecf20Sopenharmony_ci * Sets up ddp context resouces 7488c2ecf20Sopenharmony_ci * 7498c2ecf20Sopenharmony_ci * Returns : 0 indicates success or -EINVAL on failure 7508c2ecf20Sopenharmony_ci */ 7518c2ecf20Sopenharmony_ciint ixgbe_setup_fcoe_ddp_resources(struct ixgbe_adapter *adapter) 7528c2ecf20Sopenharmony_ci{ 7538c2ecf20Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 7548c2ecf20Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 7558c2ecf20Sopenharmony_ci void *buffer; 7568c2ecf20Sopenharmony_ci dma_addr_t dma; 7578c2ecf20Sopenharmony_ci unsigned int cpu; 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* do nothing if no DDP pools were allocated */ 7608c2ecf20Sopenharmony_ci if (!fcoe->ddp_pool) 7618c2ecf20Sopenharmony_ci return 0; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci /* Extra buffer to be shared by all DDPs for HW work around */ 7648c2ecf20Sopenharmony_ci buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_KERNEL); 7658c2ecf20Sopenharmony_ci if (!buffer) 7668c2ecf20Sopenharmony_ci return -ENOMEM; 7678c2ecf20Sopenharmony_ci 7688c2ecf20Sopenharmony_ci dma = dma_map_single(dev, buffer, IXGBE_FCBUFF_MIN, DMA_FROM_DEVICE); 7698c2ecf20Sopenharmony_ci if (dma_mapping_error(dev, dma)) { 7708c2ecf20Sopenharmony_ci e_err(drv, "failed to map extra DDP buffer\n"); 7718c2ecf20Sopenharmony_ci kfree(buffer); 7728c2ecf20Sopenharmony_ci return -ENOMEM; 7738c2ecf20Sopenharmony_ci } 7748c2ecf20Sopenharmony_ci 7758c2ecf20Sopenharmony_ci fcoe->extra_ddp_buffer = buffer; 7768c2ecf20Sopenharmony_ci fcoe->extra_ddp_buffer_dma = dma; 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci /* allocate pci pool for each cpu */ 7798c2ecf20Sopenharmony_ci for_each_possible_cpu(cpu) { 7808c2ecf20Sopenharmony_ci int err = ixgbe_fcoe_dma_pool_alloc(fcoe, dev, cpu); 7818c2ecf20Sopenharmony_ci if (!err) 7828c2ecf20Sopenharmony_ci continue; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci e_err(drv, "failed to alloc DDP pool on cpu:%d\n", cpu); 7858c2ecf20Sopenharmony_ci ixgbe_free_fcoe_ddp_resources(adapter); 7868c2ecf20Sopenharmony_ci return -ENOMEM; 7878c2ecf20Sopenharmony_ci } 7888c2ecf20Sopenharmony_ci 7898c2ecf20Sopenharmony_ci return 0; 7908c2ecf20Sopenharmony_ci} 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic int ixgbe_fcoe_ddp_enable(struct ixgbe_adapter *adapter) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) 7978c2ecf20Sopenharmony_ci return -EINVAL; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci fcoe->ddp_pool = alloc_percpu(struct ixgbe_fcoe_ddp_pool); 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci if (!fcoe->ddp_pool) { 8028c2ecf20Sopenharmony_ci e_err(drv, "failed to allocate percpu DDP resources\n"); 8038c2ecf20Sopenharmony_ci return -ENOMEM; 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_ci adapter->netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; 8078c2ecf20Sopenharmony_ci /* X550 has different DDP Max limit */ 8088c2ecf20Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) 8098c2ecf20Sopenharmony_ci adapter->netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX_X550 - 1; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci return 0; 8128c2ecf20Sopenharmony_ci} 8138c2ecf20Sopenharmony_ci 8148c2ecf20Sopenharmony_cistatic void ixgbe_fcoe_ddp_disable(struct ixgbe_adapter *adapter) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_ci adapter->netdev->fcoe_ddp_xid = 0; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci if (!fcoe->ddp_pool) 8218c2ecf20Sopenharmony_ci return; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci free_percpu(fcoe->ddp_pool); 8248c2ecf20Sopenharmony_ci fcoe->ddp_pool = NULL; 8258c2ecf20Sopenharmony_ci} 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci/** 8288c2ecf20Sopenharmony_ci * ixgbe_fcoe_enable - turn on FCoE offload feature 8298c2ecf20Sopenharmony_ci * @netdev: the corresponding netdev 8308c2ecf20Sopenharmony_ci * 8318c2ecf20Sopenharmony_ci * Turns on FCoE offload feature in 82599. 8328c2ecf20Sopenharmony_ci * 8338c2ecf20Sopenharmony_ci * Returns : 0 indicates success or -EINVAL on failure 8348c2ecf20Sopenharmony_ci */ 8358c2ecf20Sopenharmony_ciint ixgbe_fcoe_enable(struct net_device *netdev) 8368c2ecf20Sopenharmony_ci{ 8378c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 8388c2ecf20Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci atomic_inc(&fcoe->refcnt); 8418c2ecf20Sopenharmony_ci 8428c2ecf20Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) 8438c2ecf20Sopenharmony_ci return -EINVAL; 8448c2ecf20Sopenharmony_ci 8458c2ecf20Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) 8468c2ecf20Sopenharmony_ci return -EINVAL; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci e_info(drv, "Enabling FCoE offload features.\n"); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) 8518c2ecf20Sopenharmony_ci e_warn(probe, "Enabling FCoE on PF will disable legacy VFs\n"); 8528c2ecf20Sopenharmony_ci 8538c2ecf20Sopenharmony_ci if (netif_running(netdev)) 8548c2ecf20Sopenharmony_ci netdev->netdev_ops->ndo_stop(netdev); 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci /* Allocate per CPU memory to track DDP pools */ 8578c2ecf20Sopenharmony_ci ixgbe_fcoe_ddp_enable(adapter); 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci /* enable FCoE and notify stack */ 8608c2ecf20Sopenharmony_ci adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; 8618c2ecf20Sopenharmony_ci netdev->features |= NETIF_F_FCOE_MTU; 8628c2ecf20Sopenharmony_ci netdev_features_change(netdev); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci /* release existing queues and reallocate them */ 8658c2ecf20Sopenharmony_ci ixgbe_clear_interrupt_scheme(adapter); 8668c2ecf20Sopenharmony_ci ixgbe_init_interrupt_scheme(adapter); 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci if (netif_running(netdev)) 8698c2ecf20Sopenharmony_ci netdev->netdev_ops->ndo_open(netdev); 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci return 0; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci/** 8758c2ecf20Sopenharmony_ci * ixgbe_fcoe_disable - turn off FCoE offload feature 8768c2ecf20Sopenharmony_ci * @netdev: the corresponding netdev 8778c2ecf20Sopenharmony_ci * 8788c2ecf20Sopenharmony_ci * Turns off FCoE offload feature in 82599. 8798c2ecf20Sopenharmony_ci * 8808c2ecf20Sopenharmony_ci * Returns : 0 indicates success or -EINVAL on failure 8818c2ecf20Sopenharmony_ci */ 8828c2ecf20Sopenharmony_ciint ixgbe_fcoe_disable(struct net_device *netdev) 8838c2ecf20Sopenharmony_ci{ 8848c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci if (!atomic_dec_and_test(&adapter->fcoe.refcnt)) 8878c2ecf20Sopenharmony_ci return -EINVAL; 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) 8908c2ecf20Sopenharmony_ci return -EINVAL; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci e_info(drv, "Disabling FCoE offload features.\n"); 8938c2ecf20Sopenharmony_ci if (netif_running(netdev)) 8948c2ecf20Sopenharmony_ci netdev->netdev_ops->ndo_stop(netdev); 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci /* Free per CPU memory to track DDP pools */ 8978c2ecf20Sopenharmony_ci ixgbe_fcoe_ddp_disable(adapter); 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci /* disable FCoE and notify stack */ 9008c2ecf20Sopenharmony_ci adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; 9018c2ecf20Sopenharmony_ci netdev->features &= ~NETIF_F_FCOE_MTU; 9028c2ecf20Sopenharmony_ci 9038c2ecf20Sopenharmony_ci netdev_features_change(netdev); 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci /* release existing queues and reallocate them */ 9068c2ecf20Sopenharmony_ci ixgbe_clear_interrupt_scheme(adapter); 9078c2ecf20Sopenharmony_ci ixgbe_init_interrupt_scheme(adapter); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci if (netif_running(netdev)) 9108c2ecf20Sopenharmony_ci netdev->netdev_ops->ndo_open(netdev); 9118c2ecf20Sopenharmony_ci 9128c2ecf20Sopenharmony_ci return 0; 9138c2ecf20Sopenharmony_ci} 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci/** 9168c2ecf20Sopenharmony_ci * ixgbe_fcoe_get_wwn - get world wide name for the node or the port 9178c2ecf20Sopenharmony_ci * @netdev : ixgbe adapter 9188c2ecf20Sopenharmony_ci * @wwn : the world wide name 9198c2ecf20Sopenharmony_ci * @type: the type of world wide name 9208c2ecf20Sopenharmony_ci * 9218c2ecf20Sopenharmony_ci * Returns the node or port world wide name if both the prefix and the san 9228c2ecf20Sopenharmony_ci * mac address are valid, then the wwn is formed based on the NAA-2 for 9238c2ecf20Sopenharmony_ci * IEEE Extended name identifier (ref. to T10 FC-LS Spec., Sec. 15.3). 9248c2ecf20Sopenharmony_ci * 9258c2ecf20Sopenharmony_ci * Returns : 0 on success 9268c2ecf20Sopenharmony_ci */ 9278c2ecf20Sopenharmony_ciint ixgbe_fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type) 9288c2ecf20Sopenharmony_ci{ 9298c2ecf20Sopenharmony_ci u16 prefix = 0xffff; 9308c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 9318c2ecf20Sopenharmony_ci struct ixgbe_mac_info *mac = &adapter->hw.mac; 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_ci switch (type) { 9348c2ecf20Sopenharmony_ci case NETDEV_FCOE_WWNN: 9358c2ecf20Sopenharmony_ci prefix = mac->wwnn_prefix; 9368c2ecf20Sopenharmony_ci break; 9378c2ecf20Sopenharmony_ci case NETDEV_FCOE_WWPN: 9388c2ecf20Sopenharmony_ci prefix = mac->wwpn_prefix; 9398c2ecf20Sopenharmony_ci break; 9408c2ecf20Sopenharmony_ci default: 9418c2ecf20Sopenharmony_ci break; 9428c2ecf20Sopenharmony_ci } 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci if ((prefix != 0xffff) && 9458c2ecf20Sopenharmony_ci is_valid_ether_addr(mac->san_addr)) { 9468c2ecf20Sopenharmony_ci *wwn = ((u64) prefix << 48) | 9478c2ecf20Sopenharmony_ci ((u64) mac->san_addr[0] << 40) | 9488c2ecf20Sopenharmony_ci ((u64) mac->san_addr[1] << 32) | 9498c2ecf20Sopenharmony_ci ((u64) mac->san_addr[2] << 24) | 9508c2ecf20Sopenharmony_ci ((u64) mac->san_addr[3] << 16) | 9518c2ecf20Sopenharmony_ci ((u64) mac->san_addr[4] << 8) | 9528c2ecf20Sopenharmony_ci ((u64) mac->san_addr[5]); 9538c2ecf20Sopenharmony_ci return 0; 9548c2ecf20Sopenharmony_ci } 9558c2ecf20Sopenharmony_ci return -EINVAL; 9568c2ecf20Sopenharmony_ci} 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci/** 9598c2ecf20Sopenharmony_ci * ixgbe_fcoe_get_hbainfo - get FCoE HBA information 9608c2ecf20Sopenharmony_ci * @netdev : ixgbe adapter 9618c2ecf20Sopenharmony_ci * @info : HBA information 9628c2ecf20Sopenharmony_ci * 9638c2ecf20Sopenharmony_ci * Returns ixgbe HBA information 9648c2ecf20Sopenharmony_ci * 9658c2ecf20Sopenharmony_ci * Returns : 0 on success 9668c2ecf20Sopenharmony_ci */ 9678c2ecf20Sopenharmony_ciint ixgbe_fcoe_get_hbainfo(struct net_device *netdev, 9688c2ecf20Sopenharmony_ci struct netdev_fcoe_hbainfo *info) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 9718c2ecf20Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 9728c2ecf20Sopenharmony_ci u64 dsn; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci if (!info) 9758c2ecf20Sopenharmony_ci return -EINVAL; 9768c2ecf20Sopenharmony_ci 9778c2ecf20Sopenharmony_ci /* Don't return information on unsupported devices */ 9788c2ecf20Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) 9798c2ecf20Sopenharmony_ci return -EINVAL; 9808c2ecf20Sopenharmony_ci 9818c2ecf20Sopenharmony_ci /* Manufacturer */ 9828c2ecf20Sopenharmony_ci snprintf(info->manufacturer, sizeof(info->manufacturer), 9838c2ecf20Sopenharmony_ci "Intel Corporation"); 9848c2ecf20Sopenharmony_ci 9858c2ecf20Sopenharmony_ci /* Serial Number */ 9868c2ecf20Sopenharmony_ci 9878c2ecf20Sopenharmony_ci /* Get the PCI-e Device Serial Number Capability */ 9888c2ecf20Sopenharmony_ci dsn = pci_get_dsn(adapter->pdev); 9898c2ecf20Sopenharmony_ci if (dsn) 9908c2ecf20Sopenharmony_ci snprintf(info->serial_number, sizeof(info->serial_number), 9918c2ecf20Sopenharmony_ci "%016llX", dsn); 9928c2ecf20Sopenharmony_ci else 9938c2ecf20Sopenharmony_ci snprintf(info->serial_number, sizeof(info->serial_number), 9948c2ecf20Sopenharmony_ci "Unknown"); 9958c2ecf20Sopenharmony_ci 9968c2ecf20Sopenharmony_ci /* Hardware Version */ 9978c2ecf20Sopenharmony_ci snprintf(info->hardware_version, 9988c2ecf20Sopenharmony_ci sizeof(info->hardware_version), 9998c2ecf20Sopenharmony_ci "Rev %d", hw->revision_id); 10008c2ecf20Sopenharmony_ci /* Driver Name/Version */ 10018c2ecf20Sopenharmony_ci snprintf(info->driver_version, 10028c2ecf20Sopenharmony_ci sizeof(info->driver_version), 10038c2ecf20Sopenharmony_ci "%s v%s", 10048c2ecf20Sopenharmony_ci ixgbe_driver_name, 10058c2ecf20Sopenharmony_ci UTS_RELEASE); 10068c2ecf20Sopenharmony_ci /* Firmware Version */ 10078c2ecf20Sopenharmony_ci strlcpy(info->firmware_version, adapter->eeprom_id, 10088c2ecf20Sopenharmony_ci sizeof(info->firmware_version)); 10098c2ecf20Sopenharmony_ci 10108c2ecf20Sopenharmony_ci /* Model */ 10118c2ecf20Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82599EB) { 10128c2ecf20Sopenharmony_ci snprintf(info->model, 10138c2ecf20Sopenharmony_ci sizeof(info->model), 10148c2ecf20Sopenharmony_ci "Intel 82599"); 10158c2ecf20Sopenharmony_ci } else if (hw->mac.type == ixgbe_mac_X550) { 10168c2ecf20Sopenharmony_ci snprintf(info->model, 10178c2ecf20Sopenharmony_ci sizeof(info->model), 10188c2ecf20Sopenharmony_ci "Intel X550"); 10198c2ecf20Sopenharmony_ci } else { 10208c2ecf20Sopenharmony_ci snprintf(info->model, 10218c2ecf20Sopenharmony_ci sizeof(info->model), 10228c2ecf20Sopenharmony_ci "Intel X540"); 10238c2ecf20Sopenharmony_ci } 10248c2ecf20Sopenharmony_ci 10258c2ecf20Sopenharmony_ci /* Model Description */ 10268c2ecf20Sopenharmony_ci snprintf(info->model_description, 10278c2ecf20Sopenharmony_ci sizeof(info->model_description), 10288c2ecf20Sopenharmony_ci "%s", 10298c2ecf20Sopenharmony_ci ixgbe_default_device_descr); 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_ci return 0; 10328c2ecf20Sopenharmony_ci} 10338c2ecf20Sopenharmony_ci 10348c2ecf20Sopenharmony_ci/** 10358c2ecf20Sopenharmony_ci * ixgbe_fcoe_get_tc - get the current TC that fcoe is mapped to 10368c2ecf20Sopenharmony_ci * @adapter: pointer to the device adapter structure 10378c2ecf20Sopenharmony_ci * 10388c2ecf20Sopenharmony_ci * Return : TC that FCoE is mapped to 10398c2ecf20Sopenharmony_ci */ 10408c2ecf20Sopenharmony_ciu8 ixgbe_fcoe_get_tc(struct ixgbe_adapter *adapter) 10418c2ecf20Sopenharmony_ci{ 10428c2ecf20Sopenharmony_ci#ifdef CONFIG_IXGBE_DCB 10438c2ecf20Sopenharmony_ci return netdev_get_prio_tc_map(adapter->netdev, adapter->fcoe.up); 10448c2ecf20Sopenharmony_ci#else 10458c2ecf20Sopenharmony_ci return 0; 10468c2ecf20Sopenharmony_ci#endif 10478c2ecf20Sopenharmony_ci} 1048