162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 1999 - 2018 Intel Corporation. */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include "ixgbe.h" 562306a36Sopenharmony_ci#include <linux/if_ether.h> 662306a36Sopenharmony_ci#include <linux/gfp.h> 762306a36Sopenharmony_ci#include <linux/if_vlan.h> 862306a36Sopenharmony_ci#include <generated/utsrelease.h> 962306a36Sopenharmony_ci#include <scsi/scsi_cmnd.h> 1062306a36Sopenharmony_ci#include <scsi/scsi_device.h> 1162306a36Sopenharmony_ci#include <scsi/fc/fc_fs.h> 1262306a36Sopenharmony_ci#include <scsi/fc/fc_fcoe.h> 1362306a36Sopenharmony_ci#include <scsi/libfc.h> 1462306a36Sopenharmony_ci#include <scsi/libfcoe.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/** 1762306a36Sopenharmony_ci * ixgbe_fcoe_clear_ddp - clear the given ddp context 1862306a36Sopenharmony_ci * @ddp: ptr to the ixgbe_fcoe_ddp 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * Returns : none 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci */ 2362306a36Sopenharmony_cistatic inline void ixgbe_fcoe_clear_ddp(struct ixgbe_fcoe_ddp *ddp) 2462306a36Sopenharmony_ci{ 2562306a36Sopenharmony_ci ddp->len = 0; 2662306a36Sopenharmony_ci ddp->err = 1; 2762306a36Sopenharmony_ci ddp->udl = NULL; 2862306a36Sopenharmony_ci ddp->udp = 0UL; 2962306a36Sopenharmony_ci ddp->sgl = NULL; 3062306a36Sopenharmony_ci ddp->sgc = 0; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci/** 3462306a36Sopenharmony_ci * ixgbe_fcoe_ddp_put - free the ddp context for a given xid 3562306a36Sopenharmony_ci * @netdev: the corresponding net_device 3662306a36Sopenharmony_ci * @xid: the xid that corresponding ddp will be freed 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci * This is the implementation of net_device_ops.ndo_fcoe_ddp_done 3962306a36Sopenharmony_ci * and it is expected to be called by ULD, i.e., FCP layer of libfc 4062306a36Sopenharmony_ci * to release the corresponding ddp context when the I/O is done. 4162306a36Sopenharmony_ci * 4262306a36Sopenharmony_ci * Returns : data length already ddp-ed in bytes 4362306a36Sopenharmony_ci */ 4462306a36Sopenharmony_ciint ixgbe_fcoe_ddp_put(struct net_device *netdev, u16 xid) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci int len; 4762306a36Sopenharmony_ci struct ixgbe_fcoe *fcoe; 4862306a36Sopenharmony_ci struct ixgbe_adapter *adapter; 4962306a36Sopenharmony_ci struct ixgbe_fcoe_ddp *ddp; 5062306a36Sopenharmony_ci struct ixgbe_hw *hw; 5162306a36Sopenharmony_ci u32 fcbuff; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci if (!netdev) 5462306a36Sopenharmony_ci return 0; 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci if (xid >= netdev->fcoe_ddp_xid) 5762306a36Sopenharmony_ci return 0; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci adapter = netdev_priv(netdev); 6062306a36Sopenharmony_ci fcoe = &adapter->fcoe; 6162306a36Sopenharmony_ci ddp = &fcoe->ddp[xid]; 6262306a36Sopenharmony_ci if (!ddp->udl) 6362306a36Sopenharmony_ci return 0; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci hw = &adapter->hw; 6662306a36Sopenharmony_ci len = ddp->len; 6762306a36Sopenharmony_ci /* if no error then skip ddp context invalidation */ 6862306a36Sopenharmony_ci if (!ddp->err) 6962306a36Sopenharmony_ci goto skip_ddpinv; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (hw->mac.type == ixgbe_mac_X550) { 7262306a36Sopenharmony_ci /* X550 does not require DDP FCoE lock */ 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(0, xid), 0); 7562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(3, xid), 7662306a36Sopenharmony_ci (xid | IXGBE_FCFLTRW_WE)); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci /* program FCBUFF */ 7962306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(2, xid), 0); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci /* program FCDMARW */ 8262306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(3, xid), 8362306a36Sopenharmony_ci (xid | IXGBE_FCDMARW_WE)); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* read FCBUFF to check context invalidated */ 8662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(3, xid), 8762306a36Sopenharmony_ci (xid | IXGBE_FCDMARW_RE)); 8862306a36Sopenharmony_ci fcbuff = IXGBE_READ_REG(hw, IXGBE_FCDDC(2, xid)); 8962306a36Sopenharmony_ci } else { 9062306a36Sopenharmony_ci /* other hardware requires DDP FCoE lock */ 9162306a36Sopenharmony_ci spin_lock_bh(&fcoe->lock); 9262306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCFLT, 0); 9362306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCFLTRW, 9462306a36Sopenharmony_ci (xid | IXGBE_FCFLTRW_WE)); 9562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCBUFF, 0); 9662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, 9762306a36Sopenharmony_ci (xid | IXGBE_FCDMARW_WE)); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci /* guaranteed to be invalidated after 100us */ 10062306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, 10162306a36Sopenharmony_ci (xid | IXGBE_FCDMARW_RE)); 10262306a36Sopenharmony_ci fcbuff = IXGBE_READ_REG(hw, IXGBE_FCBUFF); 10362306a36Sopenharmony_ci spin_unlock_bh(&fcoe->lock); 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci if (fcbuff & IXGBE_FCBUFF_VALID) 10762306a36Sopenharmony_ci usleep_range(100, 150); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ciskip_ddpinv: 11062306a36Sopenharmony_ci if (ddp->sgl) 11162306a36Sopenharmony_ci dma_unmap_sg(&adapter->pdev->dev, ddp->sgl, ddp->sgc, 11262306a36Sopenharmony_ci DMA_FROM_DEVICE); 11362306a36Sopenharmony_ci if (ddp->pool) { 11462306a36Sopenharmony_ci dma_pool_free(ddp->pool, ddp->udl, ddp->udp); 11562306a36Sopenharmony_ci ddp->pool = NULL; 11662306a36Sopenharmony_ci } 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci ixgbe_fcoe_clear_ddp(ddp); 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci return len; 12162306a36Sopenharmony_ci} 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/** 12462306a36Sopenharmony_ci * ixgbe_fcoe_ddp_setup - called to set up ddp context 12562306a36Sopenharmony_ci * @netdev: the corresponding net_device 12662306a36Sopenharmony_ci * @xid: the exchange id requesting ddp 12762306a36Sopenharmony_ci * @sgl: the scatter-gather list for this request 12862306a36Sopenharmony_ci * @sgc: the number of scatter-gather items 12962306a36Sopenharmony_ci * @target_mode: 1 to setup target mode, 0 to setup initiator mode 13062306a36Sopenharmony_ci * 13162306a36Sopenharmony_ci * Returns : 1 for success and 0 for no ddp 13262306a36Sopenharmony_ci */ 13362306a36Sopenharmony_cistatic int ixgbe_fcoe_ddp_setup(struct net_device *netdev, u16 xid, 13462306a36Sopenharmony_ci struct scatterlist *sgl, unsigned int sgc, 13562306a36Sopenharmony_ci int target_mode) 13662306a36Sopenharmony_ci{ 13762306a36Sopenharmony_ci struct ixgbe_adapter *adapter; 13862306a36Sopenharmony_ci struct ixgbe_hw *hw; 13962306a36Sopenharmony_ci struct ixgbe_fcoe *fcoe; 14062306a36Sopenharmony_ci struct ixgbe_fcoe_ddp *ddp; 14162306a36Sopenharmony_ci struct ixgbe_fcoe_ddp_pool *ddp_pool; 14262306a36Sopenharmony_ci struct scatterlist *sg; 14362306a36Sopenharmony_ci unsigned int i, j, dmacount; 14462306a36Sopenharmony_ci unsigned int len; 14562306a36Sopenharmony_ci static const unsigned int bufflen = IXGBE_FCBUFF_MIN; 14662306a36Sopenharmony_ci unsigned int firstoff = 0; 14762306a36Sopenharmony_ci unsigned int lastsize; 14862306a36Sopenharmony_ci unsigned int thisoff = 0; 14962306a36Sopenharmony_ci unsigned int thislen = 0; 15062306a36Sopenharmony_ci u32 fcbuff, fcdmarw, fcfltrw, fcrxctl; 15162306a36Sopenharmony_ci dma_addr_t addr = 0; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci if (!netdev || !sgl) 15462306a36Sopenharmony_ci return 0; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci adapter = netdev_priv(netdev); 15762306a36Sopenharmony_ci if (xid >= netdev->fcoe_ddp_xid) { 15862306a36Sopenharmony_ci e_warn(drv, "xid=0x%x out-of-range\n", xid); 15962306a36Sopenharmony_ci return 0; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* no DDP if we are already down or resetting */ 16362306a36Sopenharmony_ci if (test_bit(__IXGBE_DOWN, &adapter->state) || 16462306a36Sopenharmony_ci test_bit(__IXGBE_RESETTING, &adapter->state)) 16562306a36Sopenharmony_ci return 0; 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci fcoe = &adapter->fcoe; 16862306a36Sopenharmony_ci ddp = &fcoe->ddp[xid]; 16962306a36Sopenharmony_ci if (ddp->sgl) { 17062306a36Sopenharmony_ci e_err(drv, "xid 0x%x w/ non-null sgl=%p nents=%d\n", 17162306a36Sopenharmony_ci xid, ddp->sgl, ddp->sgc); 17262306a36Sopenharmony_ci return 0; 17362306a36Sopenharmony_ci } 17462306a36Sopenharmony_ci ixgbe_fcoe_clear_ddp(ddp); 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci if (!fcoe->ddp_pool) { 17862306a36Sopenharmony_ci e_warn(drv, "No ddp_pool resources allocated\n"); 17962306a36Sopenharmony_ci return 0; 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci ddp_pool = per_cpu_ptr(fcoe->ddp_pool, get_cpu()); 18362306a36Sopenharmony_ci if (!ddp_pool->pool) { 18462306a36Sopenharmony_ci e_warn(drv, "xid=0x%x no ddp pool for fcoe\n", xid); 18562306a36Sopenharmony_ci goto out_noddp; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci /* setup dma from scsi command sgl */ 18962306a36Sopenharmony_ci dmacount = dma_map_sg(&adapter->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); 19062306a36Sopenharmony_ci if (dmacount == 0) { 19162306a36Sopenharmony_ci e_err(drv, "xid 0x%x DMA map error\n", xid); 19262306a36Sopenharmony_ci goto out_noddp; 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* alloc the udl from per cpu ddp pool */ 19662306a36Sopenharmony_ci ddp->udl = dma_pool_alloc(ddp_pool->pool, GFP_ATOMIC, &ddp->udp); 19762306a36Sopenharmony_ci if (!ddp->udl) { 19862306a36Sopenharmony_ci e_err(drv, "failed allocated ddp context\n"); 19962306a36Sopenharmony_ci goto out_noddp_unmap; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci ddp->pool = ddp_pool->pool; 20262306a36Sopenharmony_ci ddp->sgl = sgl; 20362306a36Sopenharmony_ci ddp->sgc = sgc; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci j = 0; 20662306a36Sopenharmony_ci for_each_sg(sgl, sg, dmacount, i) { 20762306a36Sopenharmony_ci addr = sg_dma_address(sg); 20862306a36Sopenharmony_ci len = sg_dma_len(sg); 20962306a36Sopenharmony_ci while (len) { 21062306a36Sopenharmony_ci /* max number of buffers allowed in one DDP context */ 21162306a36Sopenharmony_ci if (j >= IXGBE_BUFFCNT_MAX) { 21262306a36Sopenharmony_ci ddp_pool->noddp++; 21362306a36Sopenharmony_ci goto out_noddp_free; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci /* get the offset of length of current buffer */ 21762306a36Sopenharmony_ci thisoff = addr & ((dma_addr_t)bufflen - 1); 21862306a36Sopenharmony_ci thislen = min((bufflen - thisoff), len); 21962306a36Sopenharmony_ci /* 22062306a36Sopenharmony_ci * all but the 1st buffer (j == 0) 22162306a36Sopenharmony_ci * must be aligned on bufflen 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_ci if ((j != 0) && (thisoff)) 22462306a36Sopenharmony_ci goto out_noddp_free; 22562306a36Sopenharmony_ci /* 22662306a36Sopenharmony_ci * all but the last buffer 22762306a36Sopenharmony_ci * ((i == (dmacount - 1)) && (thislen == len)) 22862306a36Sopenharmony_ci * must end at bufflen 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_ci if (((i != (dmacount - 1)) || (thislen != len)) 23162306a36Sopenharmony_ci && ((thislen + thisoff) != bufflen)) 23262306a36Sopenharmony_ci goto out_noddp_free; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci ddp->udl[j] = (u64)(addr - thisoff); 23562306a36Sopenharmony_ci /* only the first buffer may have none-zero offset */ 23662306a36Sopenharmony_ci if (j == 0) 23762306a36Sopenharmony_ci firstoff = thisoff; 23862306a36Sopenharmony_ci len -= thislen; 23962306a36Sopenharmony_ci addr += thislen; 24062306a36Sopenharmony_ci j++; 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci } 24362306a36Sopenharmony_ci /* only the last buffer may have non-full bufflen */ 24462306a36Sopenharmony_ci lastsize = thisoff + thislen; 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci /* 24762306a36Sopenharmony_ci * lastsize can not be buffer len. 24862306a36Sopenharmony_ci * If it is then adding another buffer with lastsize = 1. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci if (lastsize == bufflen) { 25162306a36Sopenharmony_ci if (j >= IXGBE_BUFFCNT_MAX) { 25262306a36Sopenharmony_ci ddp_pool->noddp_ext_buff++; 25362306a36Sopenharmony_ci goto out_noddp_free; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci ddp->udl[j] = (u64)(fcoe->extra_ddp_buffer_dma); 25762306a36Sopenharmony_ci j++; 25862306a36Sopenharmony_ci lastsize = 1; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci put_cpu(); 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci fcbuff = (IXGBE_FCBUFF_4KB << IXGBE_FCBUFF_BUFFSIZE_SHIFT); 26362306a36Sopenharmony_ci fcbuff |= ((j & 0xff) << IXGBE_FCBUFF_BUFFCNT_SHIFT); 26462306a36Sopenharmony_ci fcbuff |= (firstoff << IXGBE_FCBUFF_OFFSET_SHIFT); 26562306a36Sopenharmony_ci /* Set WRCONTX bit to allow DDP for target */ 26662306a36Sopenharmony_ci if (target_mode) 26762306a36Sopenharmony_ci fcbuff |= (IXGBE_FCBUFF_WRCONTX); 26862306a36Sopenharmony_ci fcbuff |= (IXGBE_FCBUFF_VALID); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci fcdmarw = xid; 27162306a36Sopenharmony_ci fcdmarw |= IXGBE_FCDMARW_WE; 27262306a36Sopenharmony_ci fcdmarw |= (lastsize << IXGBE_FCDMARW_LASTSIZE_SHIFT); 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci fcfltrw = xid; 27562306a36Sopenharmony_ci fcfltrw |= IXGBE_FCFLTRW_WE; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* program DMA context */ 27862306a36Sopenharmony_ci hw = &adapter->hw; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* turn on last frame indication for target mode as FCP_RSPtarget is 28162306a36Sopenharmony_ci * supposed to send FCP_RSP when it is done. */ 28262306a36Sopenharmony_ci if (target_mode && !test_bit(__IXGBE_FCOE_TARGET, &fcoe->mode)) { 28362306a36Sopenharmony_ci set_bit(__IXGBE_FCOE_TARGET, &fcoe->mode); 28462306a36Sopenharmony_ci fcrxctl = IXGBE_READ_REG(hw, IXGBE_FCRXCTRL); 28562306a36Sopenharmony_ci fcrxctl |= IXGBE_FCRXCTRL_LASTSEQH; 28662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, fcrxctl); 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (hw->mac.type == ixgbe_mac_X550) { 29062306a36Sopenharmony_ci /* X550 does not require DDP lock */ 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(0, xid), 29362306a36Sopenharmony_ci ddp->udp & DMA_BIT_MASK(32)); 29462306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(1, xid), (u64)ddp->udp >> 32); 29562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(2, xid), fcbuff); 29662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDDC(3, xid), fcdmarw); 29762306a36Sopenharmony_ci /* program filter context */ 29862306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(0, xid), IXGBE_FCFLT_VALID); 29962306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(1, xid), 0); 30062306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDFC(3, xid), fcfltrw); 30162306a36Sopenharmony_ci } else { 30262306a36Sopenharmony_ci /* DDP lock for indirect DDP context access */ 30362306a36Sopenharmony_ci spin_lock_bh(&fcoe->lock); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCPTRL, ddp->udp & DMA_BIT_MASK(32)); 30662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCPTRH, (u64)ddp->udp >> 32); 30762306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCBUFF, fcbuff); 30862306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCDMARW, fcdmarw); 30962306a36Sopenharmony_ci /* program filter context */ 31062306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCPARAM, 0); 31162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCFLT, IXGBE_FCFLT_VALID); 31262306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCFLTRW, fcfltrw); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci spin_unlock_bh(&fcoe->lock); 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci return 1; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ciout_noddp_free: 32062306a36Sopenharmony_ci dma_pool_free(ddp->pool, ddp->udl, ddp->udp); 32162306a36Sopenharmony_ci ixgbe_fcoe_clear_ddp(ddp); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ciout_noddp_unmap: 32462306a36Sopenharmony_ci dma_unmap_sg(&adapter->pdev->dev, sgl, sgc, DMA_FROM_DEVICE); 32562306a36Sopenharmony_ciout_noddp: 32662306a36Sopenharmony_ci put_cpu(); 32762306a36Sopenharmony_ci return 0; 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci/** 33162306a36Sopenharmony_ci * ixgbe_fcoe_ddp_get - called to set up ddp context in initiator mode 33262306a36Sopenharmony_ci * @netdev: the corresponding net_device 33362306a36Sopenharmony_ci * @xid: the exchange id requesting ddp 33462306a36Sopenharmony_ci * @sgl: the scatter-gather list for this request 33562306a36Sopenharmony_ci * @sgc: the number of scatter-gather items 33662306a36Sopenharmony_ci * 33762306a36Sopenharmony_ci * This is the implementation of net_device_ops.ndo_fcoe_ddp_setup 33862306a36Sopenharmony_ci * and is expected to be called from ULD, e.g., FCP layer of libfc 33962306a36Sopenharmony_ci * to set up ddp for the corresponding xid of the given sglist for 34062306a36Sopenharmony_ci * the corresponding I/O. 34162306a36Sopenharmony_ci * 34262306a36Sopenharmony_ci * Returns : 1 for success and 0 for no ddp 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ciint ixgbe_fcoe_ddp_get(struct net_device *netdev, u16 xid, 34562306a36Sopenharmony_ci struct scatterlist *sgl, unsigned int sgc) 34662306a36Sopenharmony_ci{ 34762306a36Sopenharmony_ci return ixgbe_fcoe_ddp_setup(netdev, xid, sgl, sgc, 0); 34862306a36Sopenharmony_ci} 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci/** 35162306a36Sopenharmony_ci * ixgbe_fcoe_ddp_target - called to set up ddp context in target mode 35262306a36Sopenharmony_ci * @netdev: the corresponding net_device 35362306a36Sopenharmony_ci * @xid: the exchange id requesting ddp 35462306a36Sopenharmony_ci * @sgl: the scatter-gather list for this request 35562306a36Sopenharmony_ci * @sgc: the number of scatter-gather items 35662306a36Sopenharmony_ci * 35762306a36Sopenharmony_ci * This is the implementation of net_device_ops.ndo_fcoe_ddp_target 35862306a36Sopenharmony_ci * and is expected to be called from ULD, e.g., FCP layer of libfc 35962306a36Sopenharmony_ci * to set up ddp for the corresponding xid of the given sglist for 36062306a36Sopenharmony_ci * the corresponding I/O. The DDP in target mode is a write I/O request 36162306a36Sopenharmony_ci * from the initiator. 36262306a36Sopenharmony_ci * 36362306a36Sopenharmony_ci * Returns : 1 for success and 0 for no ddp 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_ciint ixgbe_fcoe_ddp_target(struct net_device *netdev, u16 xid, 36662306a36Sopenharmony_ci struct scatterlist *sgl, unsigned int sgc) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci return ixgbe_fcoe_ddp_setup(netdev, xid, sgl, sgc, 1); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci/** 37262306a36Sopenharmony_ci * ixgbe_fcoe_ddp - check ddp status and mark it done 37362306a36Sopenharmony_ci * @adapter: ixgbe adapter 37462306a36Sopenharmony_ci * @rx_desc: advanced rx descriptor 37562306a36Sopenharmony_ci * @skb: the skb holding the received data 37662306a36Sopenharmony_ci * 37762306a36Sopenharmony_ci * This checks ddp status. 37862306a36Sopenharmony_ci * 37962306a36Sopenharmony_ci * Returns : < 0 indicates an error or not a FCiE ddp, 0 indicates 38062306a36Sopenharmony_ci * not passing the skb to ULD, > 0 indicates is the length of data 38162306a36Sopenharmony_ci * being ddped. 38262306a36Sopenharmony_ci */ 38362306a36Sopenharmony_ciint ixgbe_fcoe_ddp(struct ixgbe_adapter *adapter, 38462306a36Sopenharmony_ci union ixgbe_adv_rx_desc *rx_desc, 38562306a36Sopenharmony_ci struct sk_buff *skb) 38662306a36Sopenharmony_ci{ 38762306a36Sopenharmony_ci int rc = -EINVAL; 38862306a36Sopenharmony_ci struct ixgbe_fcoe *fcoe; 38962306a36Sopenharmony_ci struct ixgbe_fcoe_ddp *ddp; 39062306a36Sopenharmony_ci struct fc_frame_header *fh; 39162306a36Sopenharmony_ci struct fcoe_crc_eof *crc; 39262306a36Sopenharmony_ci __le32 fcerr = ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_FCERR); 39362306a36Sopenharmony_ci __le32 ddp_err; 39462306a36Sopenharmony_ci int ddp_max; 39562306a36Sopenharmony_ci u32 fctl; 39662306a36Sopenharmony_ci u16 xid; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci if (fcerr == cpu_to_le32(IXGBE_FCERR_BADCRC)) 39962306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 40062306a36Sopenharmony_ci else 40162306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_UNNECESSARY; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (eth_hdr(skb)->h_proto == htons(ETH_P_8021Q)) 40462306a36Sopenharmony_ci fh = (struct fc_frame_header *)(skb->data + 40562306a36Sopenharmony_ci sizeof(struct vlan_hdr) + sizeof(struct fcoe_hdr)); 40662306a36Sopenharmony_ci else 40762306a36Sopenharmony_ci fh = (struct fc_frame_header *)(skb->data + 40862306a36Sopenharmony_ci sizeof(struct fcoe_hdr)); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci fctl = ntoh24(fh->fh_f_ctl); 41162306a36Sopenharmony_ci if (fctl & FC_FC_EX_CTX) 41262306a36Sopenharmony_ci xid = be16_to_cpu(fh->fh_ox_id); 41362306a36Sopenharmony_ci else 41462306a36Sopenharmony_ci xid = be16_to_cpu(fh->fh_rx_id); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci ddp_max = IXGBE_FCOE_DDP_MAX; 41762306a36Sopenharmony_ci /* X550 has different DDP Max limit */ 41862306a36Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) 41962306a36Sopenharmony_ci ddp_max = IXGBE_FCOE_DDP_MAX_X550; 42062306a36Sopenharmony_ci if (xid >= ddp_max) 42162306a36Sopenharmony_ci return -EINVAL; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci fcoe = &adapter->fcoe; 42462306a36Sopenharmony_ci ddp = &fcoe->ddp[xid]; 42562306a36Sopenharmony_ci if (!ddp->udl) 42662306a36Sopenharmony_ci return -EINVAL; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci ddp_err = ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_FCEOFE | 42962306a36Sopenharmony_ci IXGBE_RXDADV_ERR_FCERR); 43062306a36Sopenharmony_ci if (ddp_err) 43162306a36Sopenharmony_ci return -EINVAL; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci switch (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_STAT_FCSTAT)) { 43462306a36Sopenharmony_ci /* return 0 to bypass going to ULD for DDPed data */ 43562306a36Sopenharmony_ci case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_DDP): 43662306a36Sopenharmony_ci /* update length of DDPed data */ 43762306a36Sopenharmony_ci ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); 43862306a36Sopenharmony_ci rc = 0; 43962306a36Sopenharmony_ci break; 44062306a36Sopenharmony_ci /* unmap the sg list when FCPRSP is received */ 44162306a36Sopenharmony_ci case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_FCPRSP): 44262306a36Sopenharmony_ci dma_unmap_sg(&adapter->pdev->dev, ddp->sgl, 44362306a36Sopenharmony_ci ddp->sgc, DMA_FROM_DEVICE); 44462306a36Sopenharmony_ci ddp->err = (__force u32)ddp_err; 44562306a36Sopenharmony_ci ddp->sgl = NULL; 44662306a36Sopenharmony_ci ddp->sgc = 0; 44762306a36Sopenharmony_ci fallthrough; 44862306a36Sopenharmony_ci /* if DDP length is present pass it through to ULD */ 44962306a36Sopenharmony_ci case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NODDP): 45062306a36Sopenharmony_ci /* update length of DDPed data */ 45162306a36Sopenharmony_ci ddp->len = le32_to_cpu(rx_desc->wb.lower.hi_dword.rss); 45262306a36Sopenharmony_ci if (ddp->len) 45362306a36Sopenharmony_ci rc = ddp->len; 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci /* no match will return as an error */ 45662306a36Sopenharmony_ci case cpu_to_le32(IXGBE_RXDADV_STAT_FCSTAT_NOMTCH): 45762306a36Sopenharmony_ci default: 45862306a36Sopenharmony_ci break; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci /* In target mode, check the last data frame of the sequence. 46262306a36Sopenharmony_ci * For DDP in target mode, data is already DDPed but the header 46362306a36Sopenharmony_ci * indication of the last data frame ould allow is to tell if we 46462306a36Sopenharmony_ci * got all the data and the ULP can send FCP_RSP back, as this is 46562306a36Sopenharmony_ci * not a full fcoe frame, we fill the trailer here so it won't be 46662306a36Sopenharmony_ci * dropped by the ULP stack. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ci if ((fh->fh_r_ctl == FC_RCTL_DD_SOL_DATA) && 46962306a36Sopenharmony_ci (fctl & FC_FC_END_SEQ)) { 47062306a36Sopenharmony_ci skb_linearize(skb); 47162306a36Sopenharmony_ci crc = skb_put(skb, sizeof(*crc)); 47262306a36Sopenharmony_ci crc->fcoe_eof = FC_EOF_T; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci return rc; 47662306a36Sopenharmony_ci} 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci/** 47962306a36Sopenharmony_ci * ixgbe_fso - ixgbe FCoE Sequence Offload (FSO) 48062306a36Sopenharmony_ci * @tx_ring: tx desc ring 48162306a36Sopenharmony_ci * @first: first tx_buffer structure containing skb, tx_flags, and protocol 48262306a36Sopenharmony_ci * @hdr_len: hdr_len to be returned 48362306a36Sopenharmony_ci * 48462306a36Sopenharmony_ci * This sets up large send offload for FCoE 48562306a36Sopenharmony_ci * 48662306a36Sopenharmony_ci * Returns : 0 indicates success, < 0 for error 48762306a36Sopenharmony_ci */ 48862306a36Sopenharmony_ciint ixgbe_fso(struct ixgbe_ring *tx_ring, 48962306a36Sopenharmony_ci struct ixgbe_tx_buffer *first, 49062306a36Sopenharmony_ci u8 *hdr_len) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct sk_buff *skb = first->skb; 49362306a36Sopenharmony_ci struct fc_frame_header *fh; 49462306a36Sopenharmony_ci u32 vlan_macip_lens; 49562306a36Sopenharmony_ci u32 fcoe_sof_eof = 0; 49662306a36Sopenharmony_ci u32 mss_l4len_idx; 49762306a36Sopenharmony_ci u32 type_tucmd = IXGBE_ADVTXT_TUCMD_FCOE; 49862306a36Sopenharmony_ci u8 sof, eof; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci if (skb_is_gso(skb) && (skb_shinfo(skb)->gso_type != SKB_GSO_FCOE)) { 50162306a36Sopenharmony_ci dev_err(tx_ring->dev, "Wrong gso type %d:expecting SKB_GSO_FCOE\n", 50262306a36Sopenharmony_ci skb_shinfo(skb)->gso_type); 50362306a36Sopenharmony_ci return -EINVAL; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci /* resets the header to point fcoe/fc */ 50762306a36Sopenharmony_ci skb_set_network_header(skb, skb->mac_len); 50862306a36Sopenharmony_ci skb_set_transport_header(skb, skb->mac_len + 50962306a36Sopenharmony_ci sizeof(struct fcoe_hdr)); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* sets up SOF and ORIS */ 51262306a36Sopenharmony_ci sof = ((struct fcoe_hdr *)skb_network_header(skb))->fcoe_sof; 51362306a36Sopenharmony_ci switch (sof) { 51462306a36Sopenharmony_ci case FC_SOF_I2: 51562306a36Sopenharmony_ci fcoe_sof_eof = IXGBE_ADVTXD_FCOEF_ORIS; 51662306a36Sopenharmony_ci break; 51762306a36Sopenharmony_ci case FC_SOF_I3: 51862306a36Sopenharmony_ci fcoe_sof_eof = IXGBE_ADVTXD_FCOEF_SOF | 51962306a36Sopenharmony_ci IXGBE_ADVTXD_FCOEF_ORIS; 52062306a36Sopenharmony_ci break; 52162306a36Sopenharmony_ci case FC_SOF_N2: 52262306a36Sopenharmony_ci break; 52362306a36Sopenharmony_ci case FC_SOF_N3: 52462306a36Sopenharmony_ci fcoe_sof_eof = IXGBE_ADVTXD_FCOEF_SOF; 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci default: 52762306a36Sopenharmony_ci dev_warn(tx_ring->dev, "unknown sof = 0x%x\n", sof); 52862306a36Sopenharmony_ci return -EINVAL; 52962306a36Sopenharmony_ci } 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci /* the first byte of the last dword is EOF */ 53262306a36Sopenharmony_ci skb_copy_bits(skb, skb->len - 4, &eof, 1); 53362306a36Sopenharmony_ci /* sets up EOF and ORIE */ 53462306a36Sopenharmony_ci switch (eof) { 53562306a36Sopenharmony_ci case FC_EOF_N: 53662306a36Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N; 53762306a36Sopenharmony_ci break; 53862306a36Sopenharmony_ci case FC_EOF_T: 53962306a36Sopenharmony_ci /* lso needs ORIE */ 54062306a36Sopenharmony_ci if (skb_is_gso(skb)) 54162306a36Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_N | 54262306a36Sopenharmony_ci IXGBE_ADVTXD_FCOEF_ORIE; 54362306a36Sopenharmony_ci else 54462306a36Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_T; 54562306a36Sopenharmony_ci break; 54662306a36Sopenharmony_ci case FC_EOF_NI: 54762306a36Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_NI; 54862306a36Sopenharmony_ci break; 54962306a36Sopenharmony_ci case FC_EOF_A: 55062306a36Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_EOF_A; 55162306a36Sopenharmony_ci break; 55262306a36Sopenharmony_ci default: 55362306a36Sopenharmony_ci dev_warn(tx_ring->dev, "unknown eof = 0x%x\n", eof); 55462306a36Sopenharmony_ci return -EINVAL; 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci /* sets up PARINC indicating data offset */ 55862306a36Sopenharmony_ci fh = (struct fc_frame_header *)skb_transport_header(skb); 55962306a36Sopenharmony_ci if (fh->fh_f_ctl[2] & FC_FC_REL_OFF) 56062306a36Sopenharmony_ci fcoe_sof_eof |= IXGBE_ADVTXD_FCOEF_PARINC; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* include trailer in headlen as it is replicated per frame */ 56362306a36Sopenharmony_ci *hdr_len = sizeof(struct fcoe_crc_eof); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* hdr_len includes fc_hdr if FCoE LSO is enabled */ 56662306a36Sopenharmony_ci if (skb_is_gso(skb)) { 56762306a36Sopenharmony_ci *hdr_len += skb_transport_offset(skb) + 56862306a36Sopenharmony_ci sizeof(struct fc_frame_header); 56962306a36Sopenharmony_ci /* update gso_segs and bytecount */ 57062306a36Sopenharmony_ci first->gso_segs = DIV_ROUND_UP(skb->len - *hdr_len, 57162306a36Sopenharmony_ci skb_shinfo(skb)->gso_size); 57262306a36Sopenharmony_ci first->bytecount += (first->gso_segs - 1) * *hdr_len; 57362306a36Sopenharmony_ci first->tx_flags |= IXGBE_TX_FLAGS_TSO; 57462306a36Sopenharmony_ci /* Hardware expects L4T to be RSV for FCoE TSO */ 57562306a36Sopenharmony_ci type_tucmd |= IXGBE_ADVTXD_TUCMD_L4T_RSV; 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci /* set flag indicating FCOE to ixgbe_tx_map call */ 57962306a36Sopenharmony_ci first->tx_flags |= IXGBE_TX_FLAGS_FCOE | IXGBE_TX_FLAGS_CC; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci /* mss_l4len_id: use 0 for FSO as TSO, no need for L4LEN */ 58262306a36Sopenharmony_ci mss_l4len_idx = skb_shinfo(skb)->gso_size << IXGBE_ADVTXD_MSS_SHIFT; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* vlan_macip_lens: HEADLEN, MACLEN, VLAN tag */ 58562306a36Sopenharmony_ci vlan_macip_lens = skb_transport_offset(skb) + 58662306a36Sopenharmony_ci sizeof(struct fc_frame_header); 58762306a36Sopenharmony_ci vlan_macip_lens |= (skb_transport_offset(skb) - 4) 58862306a36Sopenharmony_ci << IXGBE_ADVTXD_MACLEN_SHIFT; 58962306a36Sopenharmony_ci vlan_macip_lens |= first->tx_flags & IXGBE_TX_FLAGS_VLAN_MASK; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* write context desc */ 59262306a36Sopenharmony_ci ixgbe_tx_ctxtdesc(tx_ring, vlan_macip_lens, fcoe_sof_eof, 59362306a36Sopenharmony_ci type_tucmd, mss_l4len_idx); 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci return 0; 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_cistatic void ixgbe_fcoe_dma_pool_free(struct ixgbe_fcoe *fcoe, unsigned int cpu) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci struct ixgbe_fcoe_ddp_pool *ddp_pool; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu); 60362306a36Sopenharmony_ci dma_pool_destroy(ddp_pool->pool); 60462306a36Sopenharmony_ci ddp_pool->pool = NULL; 60562306a36Sopenharmony_ci} 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_cistatic int ixgbe_fcoe_dma_pool_alloc(struct ixgbe_fcoe *fcoe, 60862306a36Sopenharmony_ci struct device *dev, 60962306a36Sopenharmony_ci unsigned int cpu) 61062306a36Sopenharmony_ci{ 61162306a36Sopenharmony_ci struct ixgbe_fcoe_ddp_pool *ddp_pool; 61262306a36Sopenharmony_ci struct dma_pool *pool; 61362306a36Sopenharmony_ci char pool_name[32]; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci snprintf(pool_name, 32, "ixgbe_fcoe_ddp_%u", cpu); 61662306a36Sopenharmony_ci 61762306a36Sopenharmony_ci pool = dma_pool_create(pool_name, dev, IXGBE_FCPTR_MAX, 61862306a36Sopenharmony_ci IXGBE_FCPTR_ALIGN, PAGE_SIZE); 61962306a36Sopenharmony_ci if (!pool) 62062306a36Sopenharmony_ci return -ENOMEM; 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci ddp_pool = per_cpu_ptr(fcoe->ddp_pool, cpu); 62362306a36Sopenharmony_ci ddp_pool->pool = pool; 62462306a36Sopenharmony_ci ddp_pool->noddp = 0; 62562306a36Sopenharmony_ci ddp_pool->noddp_ext_buff = 0; 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci return 0; 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci/** 63162306a36Sopenharmony_ci * ixgbe_configure_fcoe - configures registers for fcoe at start 63262306a36Sopenharmony_ci * @adapter: ptr to ixgbe adapter 63362306a36Sopenharmony_ci * 63462306a36Sopenharmony_ci * This sets up FCoE related registers 63562306a36Sopenharmony_ci * 63662306a36Sopenharmony_ci * Returns : none 63762306a36Sopenharmony_ci */ 63862306a36Sopenharmony_civoid ixgbe_configure_fcoe(struct ixgbe_adapter *adapter) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci struct ixgbe_ring_feature *fcoe = &adapter->ring_feature[RING_F_FCOE]; 64162306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 64262306a36Sopenharmony_ci int i, fcoe_q, fcoe_i, fcoe_q_h = 0; 64362306a36Sopenharmony_ci int fcreta_size; 64462306a36Sopenharmony_ci u32 etqf; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Minimal functionality for FCoE requires at least CRC offloads */ 64762306a36Sopenharmony_ci if (!(adapter->netdev->features & NETIF_F_FCOE_CRC)) 64862306a36Sopenharmony_ci return; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* Enable L2 EtherType filter for FCoE, needed for FCoE CRC and DDP */ 65162306a36Sopenharmony_ci etqf = ETH_P_FCOE | IXGBE_ETQF_FCOE | IXGBE_ETQF_FILTER_EN; 65262306a36Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { 65362306a36Sopenharmony_ci etqf |= IXGBE_ETQF_POOL_ENABLE; 65462306a36Sopenharmony_ci etqf |= VMDQ_P(0) << IXGBE_ETQF_POOL_SHIFT; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FCOE), etqf); 65762306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FCOE), 0); 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci /* leave registers un-configured if FCoE is disabled */ 66062306a36Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) 66162306a36Sopenharmony_ci return; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci /* Use one or more Rx queues for FCoE by redirection table */ 66462306a36Sopenharmony_ci fcreta_size = IXGBE_FCRETA_SIZE; 66562306a36Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) 66662306a36Sopenharmony_ci fcreta_size = IXGBE_FCRETA_SIZE_X550; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci for (i = 0; i < fcreta_size; i++) { 66962306a36Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) { 67062306a36Sopenharmony_ci int fcoe_i_h = fcoe->offset + ((i + fcreta_size) % 67162306a36Sopenharmony_ci fcoe->indices); 67262306a36Sopenharmony_ci fcoe_q_h = adapter->rx_ring[fcoe_i_h]->reg_idx; 67362306a36Sopenharmony_ci fcoe_q_h = (fcoe_q_h << IXGBE_FCRETA_ENTRY_HIGH_SHIFT) & 67462306a36Sopenharmony_ci IXGBE_FCRETA_ENTRY_HIGH_MASK; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci fcoe_i = fcoe->offset + (i % fcoe->indices); 67862306a36Sopenharmony_ci fcoe_i &= IXGBE_FCRETA_ENTRY_MASK; 67962306a36Sopenharmony_ci fcoe_q = adapter->rx_ring[fcoe_i]->reg_idx; 68062306a36Sopenharmony_ci fcoe_q |= fcoe_q_h; 68162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRETA(i), fcoe_q); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRECTL, IXGBE_FCRECTL_ENA); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* Enable L2 EtherType filter for FIP */ 68662306a36Sopenharmony_ci etqf = ETH_P_FIP | IXGBE_ETQF_FILTER_EN; 68762306a36Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) { 68862306a36Sopenharmony_ci etqf |= IXGBE_ETQF_POOL_ENABLE; 68962306a36Sopenharmony_ci etqf |= VMDQ_P(0) << IXGBE_ETQF_POOL_SHIFT; 69062306a36Sopenharmony_ci } 69162306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_FIP), etqf); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* Send FIP frames to the first FCoE queue */ 69462306a36Sopenharmony_ci fcoe_q = adapter->rx_ring[fcoe->offset]->reg_idx; 69562306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_ETQS(IXGBE_ETQF_FILTER_FIP), 69662306a36Sopenharmony_ci IXGBE_ETQS_QUEUE_EN | 69762306a36Sopenharmony_ci (fcoe_q << IXGBE_ETQS_RX_QUEUE_SHIFT)); 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci /* Configure FCoE Rx control */ 70062306a36Sopenharmony_ci IXGBE_WRITE_REG(hw, IXGBE_FCRXCTRL, 70162306a36Sopenharmony_ci IXGBE_FCRXCTRL_FCCRCBO | 70262306a36Sopenharmony_ci (FC_FCOE_VER << IXGBE_FCRXCTRL_FCOEVER_SHIFT)); 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci/** 70662306a36Sopenharmony_ci * ixgbe_free_fcoe_ddp_resources - release all fcoe ddp context resources 70762306a36Sopenharmony_ci * @adapter : ixgbe adapter 70862306a36Sopenharmony_ci * 70962306a36Sopenharmony_ci * Cleans up outstanding ddp context resources 71062306a36Sopenharmony_ci * 71162306a36Sopenharmony_ci * Returns : none 71262306a36Sopenharmony_ci */ 71362306a36Sopenharmony_civoid ixgbe_free_fcoe_ddp_resources(struct ixgbe_adapter *adapter) 71462306a36Sopenharmony_ci{ 71562306a36Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 71662306a36Sopenharmony_ci int cpu, i, ddp_max; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci /* do nothing if no DDP pools were allocated */ 71962306a36Sopenharmony_ci if (!fcoe->ddp_pool) 72062306a36Sopenharmony_ci return; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci ddp_max = IXGBE_FCOE_DDP_MAX; 72362306a36Sopenharmony_ci /* X550 has different DDP Max limit */ 72462306a36Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) 72562306a36Sopenharmony_ci ddp_max = IXGBE_FCOE_DDP_MAX_X550; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci for (i = 0; i < ddp_max; i++) 72862306a36Sopenharmony_ci ixgbe_fcoe_ddp_put(adapter->netdev, i); 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci for_each_possible_cpu(cpu) 73162306a36Sopenharmony_ci ixgbe_fcoe_dma_pool_free(fcoe, cpu); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci dma_unmap_single(&adapter->pdev->dev, 73462306a36Sopenharmony_ci fcoe->extra_ddp_buffer_dma, 73562306a36Sopenharmony_ci IXGBE_FCBUFF_MIN, 73662306a36Sopenharmony_ci DMA_FROM_DEVICE); 73762306a36Sopenharmony_ci kfree(fcoe->extra_ddp_buffer); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci fcoe->extra_ddp_buffer = NULL; 74062306a36Sopenharmony_ci fcoe->extra_ddp_buffer_dma = 0; 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci/** 74462306a36Sopenharmony_ci * ixgbe_setup_fcoe_ddp_resources - setup all fcoe ddp context resources 74562306a36Sopenharmony_ci * @adapter: ixgbe adapter 74662306a36Sopenharmony_ci * 74762306a36Sopenharmony_ci * Sets up ddp context resouces 74862306a36Sopenharmony_ci * 74962306a36Sopenharmony_ci * Returns : 0 indicates success or -EINVAL on failure 75062306a36Sopenharmony_ci */ 75162306a36Sopenharmony_ciint ixgbe_setup_fcoe_ddp_resources(struct ixgbe_adapter *adapter) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 75462306a36Sopenharmony_ci struct device *dev = &adapter->pdev->dev; 75562306a36Sopenharmony_ci void *buffer; 75662306a36Sopenharmony_ci dma_addr_t dma; 75762306a36Sopenharmony_ci unsigned int cpu; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci /* do nothing if no DDP pools were allocated */ 76062306a36Sopenharmony_ci if (!fcoe->ddp_pool) 76162306a36Sopenharmony_ci return 0; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci /* Extra buffer to be shared by all DDPs for HW work around */ 76462306a36Sopenharmony_ci buffer = kmalloc(IXGBE_FCBUFF_MIN, GFP_KERNEL); 76562306a36Sopenharmony_ci if (!buffer) 76662306a36Sopenharmony_ci return -ENOMEM; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci dma = dma_map_single(dev, buffer, IXGBE_FCBUFF_MIN, DMA_FROM_DEVICE); 76962306a36Sopenharmony_ci if (dma_mapping_error(dev, dma)) { 77062306a36Sopenharmony_ci e_err(drv, "failed to map extra DDP buffer\n"); 77162306a36Sopenharmony_ci kfree(buffer); 77262306a36Sopenharmony_ci return -ENOMEM; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci fcoe->extra_ddp_buffer = buffer; 77662306a36Sopenharmony_ci fcoe->extra_ddp_buffer_dma = dma; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci /* allocate pci pool for each cpu */ 77962306a36Sopenharmony_ci for_each_possible_cpu(cpu) { 78062306a36Sopenharmony_ci int err = ixgbe_fcoe_dma_pool_alloc(fcoe, dev, cpu); 78162306a36Sopenharmony_ci if (!err) 78262306a36Sopenharmony_ci continue; 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci e_err(drv, "failed to alloc DDP pool on cpu:%d\n", cpu); 78562306a36Sopenharmony_ci ixgbe_free_fcoe_ddp_resources(adapter); 78662306a36Sopenharmony_ci return -ENOMEM; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci return 0; 79062306a36Sopenharmony_ci} 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_cistatic int ixgbe_fcoe_ddp_enable(struct ixgbe_adapter *adapter) 79362306a36Sopenharmony_ci{ 79462306a36Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) 79762306a36Sopenharmony_ci return -EINVAL; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci fcoe->ddp_pool = alloc_percpu(struct ixgbe_fcoe_ddp_pool); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (!fcoe->ddp_pool) { 80262306a36Sopenharmony_ci e_err(drv, "failed to allocate percpu DDP resources\n"); 80362306a36Sopenharmony_ci return -ENOMEM; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci adapter->netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX - 1; 80762306a36Sopenharmony_ci /* X550 has different DDP Max limit */ 80862306a36Sopenharmony_ci if (adapter->hw.mac.type == ixgbe_mac_X550) 80962306a36Sopenharmony_ci adapter->netdev->fcoe_ddp_xid = IXGBE_FCOE_DDP_MAX_X550 - 1; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci return 0; 81262306a36Sopenharmony_ci} 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_cistatic void ixgbe_fcoe_ddp_disable(struct ixgbe_adapter *adapter) 81562306a36Sopenharmony_ci{ 81662306a36Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci adapter->netdev->fcoe_ddp_xid = 0; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci if (!fcoe->ddp_pool) 82162306a36Sopenharmony_ci return; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci free_percpu(fcoe->ddp_pool); 82462306a36Sopenharmony_ci fcoe->ddp_pool = NULL; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci/** 82862306a36Sopenharmony_ci * ixgbe_fcoe_enable - turn on FCoE offload feature 82962306a36Sopenharmony_ci * @netdev: the corresponding netdev 83062306a36Sopenharmony_ci * 83162306a36Sopenharmony_ci * Turns on FCoE offload feature in 82599. 83262306a36Sopenharmony_ci * 83362306a36Sopenharmony_ci * Returns : 0 indicates success or -EINVAL on failure 83462306a36Sopenharmony_ci */ 83562306a36Sopenharmony_ciint ixgbe_fcoe_enable(struct net_device *netdev) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 83862306a36Sopenharmony_ci struct ixgbe_fcoe *fcoe = &adapter->fcoe; 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci atomic_inc(&fcoe->refcnt); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_CAPABLE)) 84362306a36Sopenharmony_ci return -EINVAL; 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_FCOE_ENABLED) 84662306a36Sopenharmony_ci return -EINVAL; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci e_info(drv, "Enabling FCoE offload features.\n"); 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci if (adapter->flags & IXGBE_FLAG_SRIOV_ENABLED) 85162306a36Sopenharmony_ci e_warn(probe, "Enabling FCoE on PF will disable legacy VFs\n"); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (netif_running(netdev)) 85462306a36Sopenharmony_ci netdev->netdev_ops->ndo_stop(netdev); 85562306a36Sopenharmony_ci 85662306a36Sopenharmony_ci /* Allocate per CPU memory to track DDP pools */ 85762306a36Sopenharmony_ci ixgbe_fcoe_ddp_enable(adapter); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci /* enable FCoE and notify stack */ 86062306a36Sopenharmony_ci adapter->flags |= IXGBE_FLAG_FCOE_ENABLED; 86162306a36Sopenharmony_ci netdev->features |= NETIF_F_FCOE_MTU; 86262306a36Sopenharmony_ci netdev_features_change(netdev); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* release existing queues and reallocate them */ 86562306a36Sopenharmony_ci ixgbe_clear_interrupt_scheme(adapter); 86662306a36Sopenharmony_ci ixgbe_init_interrupt_scheme(adapter); 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci if (netif_running(netdev)) 86962306a36Sopenharmony_ci netdev->netdev_ops->ndo_open(netdev); 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci return 0; 87262306a36Sopenharmony_ci} 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci/** 87562306a36Sopenharmony_ci * ixgbe_fcoe_disable - turn off FCoE offload feature 87662306a36Sopenharmony_ci * @netdev: the corresponding netdev 87762306a36Sopenharmony_ci * 87862306a36Sopenharmony_ci * Turns off FCoE offload feature in 82599. 87962306a36Sopenharmony_ci * 88062306a36Sopenharmony_ci * Returns : 0 indicates success or -EINVAL on failure 88162306a36Sopenharmony_ci */ 88262306a36Sopenharmony_ciint ixgbe_fcoe_disable(struct net_device *netdev) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (!atomic_dec_and_test(&adapter->fcoe.refcnt)) 88762306a36Sopenharmony_ci return -EINVAL; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) 89062306a36Sopenharmony_ci return -EINVAL; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci e_info(drv, "Disabling FCoE offload features.\n"); 89362306a36Sopenharmony_ci if (netif_running(netdev)) 89462306a36Sopenharmony_ci netdev->netdev_ops->ndo_stop(netdev); 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci /* Free per CPU memory to track DDP pools */ 89762306a36Sopenharmony_ci ixgbe_fcoe_ddp_disable(adapter); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci /* disable FCoE and notify stack */ 90062306a36Sopenharmony_ci adapter->flags &= ~IXGBE_FLAG_FCOE_ENABLED; 90162306a36Sopenharmony_ci netdev->features &= ~NETIF_F_FCOE_MTU; 90262306a36Sopenharmony_ci 90362306a36Sopenharmony_ci netdev_features_change(netdev); 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci /* release existing queues and reallocate them */ 90662306a36Sopenharmony_ci ixgbe_clear_interrupt_scheme(adapter); 90762306a36Sopenharmony_ci ixgbe_init_interrupt_scheme(adapter); 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (netif_running(netdev)) 91062306a36Sopenharmony_ci netdev->netdev_ops->ndo_open(netdev); 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci return 0; 91362306a36Sopenharmony_ci} 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci/** 91662306a36Sopenharmony_ci * ixgbe_fcoe_get_wwn - get world wide name for the node or the port 91762306a36Sopenharmony_ci * @netdev : ixgbe adapter 91862306a36Sopenharmony_ci * @wwn : the world wide name 91962306a36Sopenharmony_ci * @type: the type of world wide name 92062306a36Sopenharmony_ci * 92162306a36Sopenharmony_ci * Returns the node or port world wide name if both the prefix and the san 92262306a36Sopenharmony_ci * mac address are valid, then the wwn is formed based on the NAA-2 for 92362306a36Sopenharmony_ci * IEEE Extended name identifier (ref. to T10 FC-LS Spec., Sec. 15.3). 92462306a36Sopenharmony_ci * 92562306a36Sopenharmony_ci * Returns : 0 on success 92662306a36Sopenharmony_ci */ 92762306a36Sopenharmony_ciint ixgbe_fcoe_get_wwn(struct net_device *netdev, u64 *wwn, int type) 92862306a36Sopenharmony_ci{ 92962306a36Sopenharmony_ci u16 prefix = 0xffff; 93062306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 93162306a36Sopenharmony_ci struct ixgbe_mac_info *mac = &adapter->hw.mac; 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci switch (type) { 93462306a36Sopenharmony_ci case NETDEV_FCOE_WWNN: 93562306a36Sopenharmony_ci prefix = mac->wwnn_prefix; 93662306a36Sopenharmony_ci break; 93762306a36Sopenharmony_ci case NETDEV_FCOE_WWPN: 93862306a36Sopenharmony_ci prefix = mac->wwpn_prefix; 93962306a36Sopenharmony_ci break; 94062306a36Sopenharmony_ci default: 94162306a36Sopenharmony_ci break; 94262306a36Sopenharmony_ci } 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if ((prefix != 0xffff) && 94562306a36Sopenharmony_ci is_valid_ether_addr(mac->san_addr)) { 94662306a36Sopenharmony_ci *wwn = ((u64) prefix << 48) | 94762306a36Sopenharmony_ci ((u64) mac->san_addr[0] << 40) | 94862306a36Sopenharmony_ci ((u64) mac->san_addr[1] << 32) | 94962306a36Sopenharmony_ci ((u64) mac->san_addr[2] << 24) | 95062306a36Sopenharmony_ci ((u64) mac->san_addr[3] << 16) | 95162306a36Sopenharmony_ci ((u64) mac->san_addr[4] << 8) | 95262306a36Sopenharmony_ci ((u64) mac->san_addr[5]); 95362306a36Sopenharmony_ci return 0; 95462306a36Sopenharmony_ci } 95562306a36Sopenharmony_ci return -EINVAL; 95662306a36Sopenharmony_ci} 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci/** 95962306a36Sopenharmony_ci * ixgbe_fcoe_get_hbainfo - get FCoE HBA information 96062306a36Sopenharmony_ci * @netdev : ixgbe adapter 96162306a36Sopenharmony_ci * @info : HBA information 96262306a36Sopenharmony_ci * 96362306a36Sopenharmony_ci * Returns ixgbe HBA information 96462306a36Sopenharmony_ci * 96562306a36Sopenharmony_ci * Returns : 0 on success 96662306a36Sopenharmony_ci */ 96762306a36Sopenharmony_ciint ixgbe_fcoe_get_hbainfo(struct net_device *netdev, 96862306a36Sopenharmony_ci struct netdev_fcoe_hbainfo *info) 96962306a36Sopenharmony_ci{ 97062306a36Sopenharmony_ci struct ixgbe_adapter *adapter = netdev_priv(netdev); 97162306a36Sopenharmony_ci struct ixgbe_hw *hw = &adapter->hw; 97262306a36Sopenharmony_ci u64 dsn; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if (!info) 97562306a36Sopenharmony_ci return -EINVAL; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci /* Don't return information on unsupported devices */ 97862306a36Sopenharmony_ci if (!(adapter->flags & IXGBE_FLAG_FCOE_ENABLED)) 97962306a36Sopenharmony_ci return -EINVAL; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* Manufacturer */ 98262306a36Sopenharmony_ci snprintf(info->manufacturer, sizeof(info->manufacturer), 98362306a36Sopenharmony_ci "Intel Corporation"); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci /* Serial Number */ 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci /* Get the PCI-e Device Serial Number Capability */ 98862306a36Sopenharmony_ci dsn = pci_get_dsn(adapter->pdev); 98962306a36Sopenharmony_ci if (dsn) 99062306a36Sopenharmony_ci snprintf(info->serial_number, sizeof(info->serial_number), 99162306a36Sopenharmony_ci "%016llX", dsn); 99262306a36Sopenharmony_ci else 99362306a36Sopenharmony_ci snprintf(info->serial_number, sizeof(info->serial_number), 99462306a36Sopenharmony_ci "Unknown"); 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci /* Hardware Version */ 99762306a36Sopenharmony_ci snprintf(info->hardware_version, 99862306a36Sopenharmony_ci sizeof(info->hardware_version), 99962306a36Sopenharmony_ci "Rev %d", hw->revision_id); 100062306a36Sopenharmony_ci /* Driver Name/Version */ 100162306a36Sopenharmony_ci snprintf(info->driver_version, 100262306a36Sopenharmony_ci sizeof(info->driver_version), 100362306a36Sopenharmony_ci "%s v%s", 100462306a36Sopenharmony_ci ixgbe_driver_name, 100562306a36Sopenharmony_ci UTS_RELEASE); 100662306a36Sopenharmony_ci /* Firmware Version */ 100762306a36Sopenharmony_ci strscpy(info->firmware_version, adapter->eeprom_id, 100862306a36Sopenharmony_ci sizeof(info->firmware_version)); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci /* Model */ 101162306a36Sopenharmony_ci if (hw->mac.type == ixgbe_mac_82599EB) { 101262306a36Sopenharmony_ci snprintf(info->model, 101362306a36Sopenharmony_ci sizeof(info->model), 101462306a36Sopenharmony_ci "Intel 82599"); 101562306a36Sopenharmony_ci } else if (hw->mac.type == ixgbe_mac_X550) { 101662306a36Sopenharmony_ci snprintf(info->model, 101762306a36Sopenharmony_ci sizeof(info->model), 101862306a36Sopenharmony_ci "Intel X550"); 101962306a36Sopenharmony_ci } else { 102062306a36Sopenharmony_ci snprintf(info->model, 102162306a36Sopenharmony_ci sizeof(info->model), 102262306a36Sopenharmony_ci "Intel X540"); 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* Model Description */ 102662306a36Sopenharmony_ci snprintf(info->model_description, 102762306a36Sopenharmony_ci sizeof(info->model_description), 102862306a36Sopenharmony_ci "%s", 102962306a36Sopenharmony_ci ixgbe_default_device_descr); 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci return 0; 103262306a36Sopenharmony_ci} 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci/** 103562306a36Sopenharmony_ci * ixgbe_fcoe_get_tc - get the current TC that fcoe is mapped to 103662306a36Sopenharmony_ci * @adapter: pointer to the device adapter structure 103762306a36Sopenharmony_ci * 103862306a36Sopenharmony_ci * Return : TC that FCoE is mapped to 103962306a36Sopenharmony_ci */ 104062306a36Sopenharmony_ciu8 ixgbe_fcoe_get_tc(struct ixgbe_adapter *adapter) 104162306a36Sopenharmony_ci{ 104262306a36Sopenharmony_ci#ifdef CONFIG_IXGBE_DCB 104362306a36Sopenharmony_ci return netdev_get_prio_tc_map(adapter->netdev, adapter->fcoe.up); 104462306a36Sopenharmony_ci#else 104562306a36Sopenharmony_ci return 0; 104662306a36Sopenharmony_ci#endif 104762306a36Sopenharmony_ci} 1048