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