* [PATCH RESEND net-next 2/5] sctp: reduce indent level in sctp_sf_shut_8_4_5
From: Marcelo Ricardo Leitner @ 2016-12-28 11:26 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Vlad Yasevich, Neil Horman
In-Reply-To: <cover.1482924092.git.marcelo.leitner@gmail.com>
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/sm_statefuns.c | 58 ++++++++++++++++++++++++-------------------------
1 file changed, 28 insertions(+), 30 deletions(-)
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 32587b1f84e729221965e270607fea7ef93a7430..a95915ef9dbabad30f6171f77b26feab61752f36 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -3501,45 +3501,43 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(struct net *net,
struct sctp_chunk *shut;
packet = sctp_ootb_pkt_new(net, asoc, chunk);
+ if (!packet)
+ return SCTP_DISPOSITION_NOMEM;
- if (packet) {
- /* Make an SHUTDOWN_COMPLETE.
- * The T bit will be set if the asoc is NULL.
- */
- shut = sctp_make_shutdown_complete(asoc, chunk);
- if (!shut) {
- sctp_ootb_pkt_free(packet);
- return SCTP_DISPOSITION_NOMEM;
- }
-
- /* Reflect vtag if T-Bit is set */
- if (sctp_test_T_bit(shut))
- packet->vtag = ntohl(chunk->sctp_hdr->vtag);
+ /* Make an SHUTDOWN_COMPLETE.
+ * The T bit will be set if the asoc is NULL.
+ */
+ shut = sctp_make_shutdown_complete(asoc, chunk);
+ if (!shut) {
+ sctp_ootb_pkt_free(packet);
+ return SCTP_DISPOSITION_NOMEM;
+ }
- /* Set the skb to the belonging sock for accounting. */
- shut->skb->sk = ep->base.sk;
+ /* Reflect vtag if T-Bit is set */
+ if (sctp_test_T_bit(shut))
+ packet->vtag = ntohl(chunk->sctp_hdr->vtag);
- sctp_packet_append_chunk(packet, shut);
+ /* Set the skb to the belonging sock for accounting. */
+ shut->skb->sk = ep->base.sk;
- sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
- SCTP_PACKET(packet));
+ sctp_packet_append_chunk(packet, shut);
- SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
+ sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
+ SCTP_PACKET(packet));
- /* If the chunk length is invalid, we don't want to process
- * the reset of the packet.
- */
- if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
- return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+ SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
- /* We need to discard the rest of the packet to prevent
- * potential bomming attacks from additional bundled chunks.
- * This is documented in SCTP Threats ID.
- */
+ /* If the chunk length is invalid, we don't want to process
+ * the reset of the packet.
+ */
+ if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
- }
- return SCTP_DISPOSITION_NOMEM;
+ /* We need to discard the rest of the packet to prevent
+ * potential bomming attacks from additional bundled chunks.
+ * This is documented in SCTP Threats ID.
+ */
+ return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
}
/*
--
2.9.3
^ permalink raw reply related
* [PATCH RESEND net-next 1/5] sctp: reduce indent level at sctp_sf_tabort_8_4_8
From: Marcelo Ricardo Leitner @ 2016-12-28 11:26 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Vlad Yasevich, Neil Horman
In-Reply-To: <cover.1482924092.git.marcelo.leitner@gmail.com>
Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
---
net/sctp/sm_statefuns.c | 44 +++++++++++++++++++++-----------------------
1 file changed, 21 insertions(+), 23 deletions(-)
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index 8ec20a64a3f8055a0c3576627c5ec5dad7e99ca8..32587b1f84e729221965e270607fea7ef93a7430 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -3237,36 +3237,34 @@ static sctp_disposition_t sctp_sf_tabort_8_4_8(struct net *net,
struct sctp_chunk *abort;
packet = sctp_ootb_pkt_new(net, asoc, chunk);
+ if (!packet)
+ return SCTP_DISPOSITION_NOMEM;
- if (packet) {
- /* Make an ABORT. The T bit will be set if the asoc
- * is NULL.
- */
- abort = sctp_make_abort(asoc, chunk, 0);
- if (!abort) {
- sctp_ootb_pkt_free(packet);
- return SCTP_DISPOSITION_NOMEM;
- }
+ /* Make an ABORT. The T bit will be set if the asoc
+ * is NULL.
+ */
+ abort = sctp_make_abort(asoc, chunk, 0);
+ if (!abort) {
+ sctp_ootb_pkt_free(packet);
+ return SCTP_DISPOSITION_NOMEM;
+ }
- /* Reflect vtag if T-Bit is set */
- if (sctp_test_T_bit(abort))
- packet->vtag = ntohl(chunk->sctp_hdr->vtag);
+ /* Reflect vtag if T-Bit is set */
+ if (sctp_test_T_bit(abort))
+ packet->vtag = ntohl(chunk->sctp_hdr->vtag);
- /* Set the skb to the belonging sock for accounting. */
- abort->skb->sk = ep->base.sk;
+ /* Set the skb to the belonging sock for accounting. */
+ abort->skb->sk = ep->base.sk;
- sctp_packet_append_chunk(packet, abort);
+ sctp_packet_append_chunk(packet, abort);
- sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
- SCTP_PACKET(packet));
-
- SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
+ sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
+ SCTP_PACKET(packet));
- sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
- return SCTP_DISPOSITION_CONSUME;
- }
+ SCTP_INC_STATS(net, SCTP_MIB_OUTCTRLCHUNKS);
- return SCTP_DISPOSITION_NOMEM;
+ sctp_sf_pdiscard(net, ep, asoc, type, arg, commands);
+ return SCTP_DISPOSITION_CONSUME;
}
/*
--
2.9.3
^ permalink raw reply related
* [PATCH RESEND net-next 0/5] SCTP cleanups
From: Marcelo Ricardo Leitner @ 2016-12-28 11:26 UTC (permalink / raw)
To: netdev; +Cc: linux-sctp, Vlad Yasevich, Neil Horman
Some cleanups/simplifications I've been collecting.
Resending now with net-next open.
Marcelo Ricardo Leitner (5):
sctp: reduce indent level at sctp_sf_tabort_8_4_8
sctp: reduce indent level in sctp_sf_shut_8_4_5
sctp: simplify addr copy
sctp: remove return value from sctp_packet_init/config
sctp: sctp_chunk_length_valid should return bool
include/net/sctp/structs.h | 7 ++-
net/sctp/ipv6.c | 16 +++---
net/sctp/output.c | 14 ++----
net/sctp/protocol.c | 18 +++----
net/sctp/sm_statefuns.c | 122 ++++++++++++++++++++++-----------------------
5 files changed, 81 insertions(+), 96 deletions(-)
--
2.9.3
^ permalink raw reply
* [PATCH v3] stmmac: enable rx queues
From: Joao Pinto @ 2016-12-28 11:15 UTC (permalink / raw)
To: davem; +Cc: netdev, Joao Pinto
When the hardware is synthesized with multiple queues, all queues are
disabled for default. This patch adds the rx queues configuration.
This patch was successfully tested in a Synopsys QoS Reference design.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
---
changes v2 -> v3 (Seraphin Bonnaffe):
- GMAC_RX_QUEUE_CLEAR macro simplified
changes v1 -> v2 (Niklas Cassel and Seraphin Bonnaffe):
- Instead of using number of DMA channels, lets use number of queues
- Create 2 flavors of RX queue enable Macros: AV and DCB (AV by default)
- Make sure that the RX queue related bits are cleared before setting
- Check if rx_queue_enable is available before executing
drivers/net/ethernet/stmicro/stmmac/common.h | 5 +++++
drivers/net/ethernet/stmicro/stmmac/dwmac4.h | 8 ++++++++
drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c | 12 ++++++++++++
drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c | 5 +++++
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 22 ++++++++++++++++++++++
5 files changed, 52 insertions(+)
diff --git a/drivers/net/ethernet/stmicro/stmmac/common.h b/drivers/net/ethernet/stmicro/stmmac/common.h
index b13a144..6c96291 100644
--- a/drivers/net/ethernet/stmicro/stmmac/common.h
+++ b/drivers/net/ethernet/stmicro/stmmac/common.h
@@ -323,6 +323,9 @@ struct dma_features {
/* TX and RX number of channels */
unsigned int number_rx_channel;
unsigned int number_tx_channel;
+ /* TX and RX number of queues */
+ unsigned int number_rx_queues;
+ unsigned int number_tx_queues;
/* Alternate (enhanced) DESC mode */
unsigned int enh_desc;
};
@@ -454,6 +457,8 @@ struct stmmac_ops {
void (*core_init)(struct mac_device_info *hw, int mtu);
/* Enable and verify that the IPC module is supported */
int (*rx_ipc)(struct mac_device_info *hw);
+ /* Enable RX Queues */
+ void (*rx_queue_enable)(struct mac_device_info *hw, u32 queue);
/* Dump MAC registers */
void (*dump_regs)(struct mac_device_info *hw);
/* Handle extra events on specific interrupts hw dependent */
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
index 3e8d4fe..b524598 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4.h
@@ -22,6 +22,7 @@
#define GMAC_HASH_TAB_32_63 0x00000014
#define GMAC_RX_FLOW_CTRL 0x00000090
#define GMAC_QX_TX_FLOW_CTRL(x) (0x70 + x * 4)
+#define GMAC_RXQ_CTRL0 0x000000a0
#define GMAC_INT_STATUS 0x000000b0
#define GMAC_INT_EN 0x000000b4
#define GMAC_PCS_BASE 0x000000e0
@@ -44,6 +45,11 @@
#define GMAC_MAX_PERFECT_ADDRESSES 128
+/* MAC RX Queue Enable */
+#define GMAC_RX_QUEUE_CLEAR(queue) ~(GENMASK(1, 0) << ((queue) * 2))
+#define GMAC_RX_AV_QUEUE_ENABLE(queue) BIT((queue) * 2)
+#define GMAC_RX_DCB_QUEUE_ENABLE(queue) BIT(((queue) * 2) + 1)
+
/* MAC Flow Control RX */
#define GMAC_RX_FLOW_CTRL_RFE BIT(0)
@@ -133,6 +139,8 @@ enum power_event {
/* MAC HW features2 bitmap */
#define GMAC_HW_FEAT_TXCHCNT GENMASK(21, 18)
#define GMAC_HW_FEAT_RXCHCNT GENMASK(15, 12)
+#define GMAC_HW_FEAT_TXQCNT GENMASK(9, 6)
+#define GMAC_HW_FEAT_RXQCNT GENMASK(3, 0)
/* MAC HW ADDR regs */
#define GMAC_HI_DCS GENMASK(18, 16)
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
index eaed7cb..ecfbf57 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_core.c
@@ -59,6 +59,17 @@ static void dwmac4_core_init(struct mac_device_info *hw, int mtu)
writel(value, ioaddr + GMAC_INT_EN);
}
+static void dwmac4_rx_queue_enable(struct mac_device_info *hw, u32 queue)
+{
+ void __iomem *ioaddr = hw->pcsr;
+ u32 value = readl(ioaddr + GMAC_RXQ_CTRL0);
+
+ value &= GMAC_RX_QUEUE_CLEAR(queue);
+ value |= GMAC_RX_AV_QUEUE_ENABLE(queue);
+
+ writel(value, ioaddr + GMAC_RXQ_CTRL0);
+}
+
static void dwmac4_dump_regs(struct mac_device_info *hw)
{
void __iomem *ioaddr = hw->pcsr;
@@ -392,6 +403,7 @@ static void dwmac4_debug(void __iomem *ioaddr, struct stmmac_extra_stats *x)
static const struct stmmac_ops dwmac4_ops = {
.core_init = dwmac4_core_init,
.rx_ipc = dwmac4_rx_ipc_enable,
+ .rx_queue_enable = dwmac4_rx_queue_enable,
.dump_regs = dwmac4_dump_regs,
.host_irq_status = dwmac4_irq_status,
.flow_ctrl = dwmac4_flow_ctrl,
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
index 8196ab5..377d1b4 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac4_dma.c
@@ -303,6 +303,11 @@ static void dwmac4_get_hw_feature(void __iomem *ioaddr,
((hw_cap & GMAC_HW_FEAT_RXCHCNT) >> 12) + 1;
dma_cap->number_tx_channel =
((hw_cap & GMAC_HW_FEAT_TXCHCNT) >> 18) + 1;
+ /* TX and RX number of queues */
+ dma_cap->number_rx_queues =
+ ((hw_cap & GMAC_HW_FEAT_RXQCNT) >> 0) + 1;
+ dma_cap->number_tx_queues =
+ ((hw_cap & GMAC_HW_FEAT_TXQCNT) >> 6) + 1;
/* IEEE 1588-2002 */
dma_cap->time_stamp = 0;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 3e40578..bc9cff9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1271,6 +1271,24 @@ static void free_dma_desc_resources(struct stmmac_priv *priv)
}
/**
+ * stmmac_mac_enable_rx_queues - Enable MAC rx queues
+ * @priv: driver private structure
+ * Description: It is used for enabling the rx queues in the MAC
+ */
+static void stmmac_mac_enable_rx_queues(struct stmmac_priv *priv)
+{
+ int rx_count = priv->dma_cap.number_rx_queues;
+ int queue = 0;
+
+ /* If GMAC does not have multiqueues, then this is not necessary*/
+ if (rx_count == 1)
+ return;
+
+ for (queue = 0; queue < rx_count; queue++)
+ priv->hw->mac->rx_queue_enable(priv->hw, queue);
+}
+
+/**
* stmmac_dma_operation_mode - HW DMA operation mode
* @priv: driver private structure
* Description: it is used for configuring the DMA operation mode register in
@@ -1691,6 +1709,10 @@ static int stmmac_hw_setup(struct net_device *dev, bool init_ptp)
/* Initialize the MAC Core */
priv->hw->mac->core_init(priv->hw, dev->mtu);
+ /* Initialize MAC RX Queues */
+ if (priv->hw->mac->rx_queue_enable)
+ stmmac_mac_enable_rx_queues(priv);
+
ret = priv->hw->mac->rx_ipc(priv->hw);
if (!ret) {
netdev_warn(priv->dev, "RX IPC Checksum Offload disabled\n");
--
2.9.3
^ permalink raw reply related
* Re: George's crazy full state idea (Re: HalfSipHash Acceptable Usage)
From: George Spelvin @ 2016-12-28 10:04 UTC (permalink / raw)
To: daniel, hannes, linux
Cc: ak, davem, David.Laight, ebiggers3, eric.dumazet, Jason,
kernel-hardening, linux-crypto, linux-kernel, luto, netdev, tom,
tytso, vegard.nossum
In-Reply-To: <1482902602.2234.1.camel@stressinduktion.org>
Hannes Frederic Sowa wrote:
> We call extract_crng when we run out of batched entropy and reseed. How
> often we call down to extract_crng depends on how much entropy we
> extracted by calls to get_random_int/long, so the number of calls into
> those functions matter.
>
> In extract_crng we have a timer which reseeds every 300s the CPRNG and
> either uses completely new entropy from the CRNG or calls down into the
> CPRNG while also doing backtracing protection (which feeds chacha's
> block size / 2 back into chacha, if I read the code correctly, thus
> 1024 bits, which should be enough).
In the current code, _extract_crng checks to see if more than 300 s
have elapsed since last time it was reseeded, and if so, reseeds with
fresh entropy.
In addition, on every read (or get_random_bytes), if the request leaves
enough ranfom bits in the last ChaCha block, it feeds back 256 bits
(the ChaCha block size is 16*32 = 512 bits) for anti-backtracking.
If the last read happened to not fit under that limit (size % 512 >
256), *and* there are no calls for RNG output for a long time, there is
no upper limit to how long the old ChaCha key can hang around.
> On Fri, 2016-12-23 at 20:17 -0500, George Spelvin wrote:
>> For example, two mix-backs of 64 bits gives you 65 bit security, not 128.
>> (Because each mixback can be guessed and verified separately.)
> Exactly, but the full reseed after running out of entropy is strong
> enough to not be defeated by your argumentation. Neither the reseed
> from the CRNG.
Yes, I was just reacting to your original statement:
>>>>> couldn't we simply use 8 bytes of the 64 byte
>>>>> return block to feed it directly back into the state chacha?
It's not the idea that's bad, just the proposed quantity.
>> If you want that, I have a pile of patches to prandom I really
>> should push upstream. Shall I refresh them and send them to you?
> I would like to have a look at them in the new year, certainly! I can
> also take care about the core prandom patches, but don't know if I have
> time to submit the others to the different subsystems.
>
> Maybe, if David would be okay with that, we can submit all patches
> through his tree, as he is also the dedicated maintainer for prandom.
Amazing, thank you very much! They're just minor cleanups, nothing
too exciting. I'll put it in the queue to make sure they're up to
date.
^ permalink raw reply
* [PATCH 1/2] ipv4: Namespaceify tcp_tw_recycle and tcp_max_tw_buckets knob
From: Haishuang Yan @ 2016-12-28 9:52 UTC (permalink / raw)
To: David S. Miller, Alexey Kuznetsov, James Morris, Nikolay Borisov
Cc: netdev, linux-kernel, Haishuang Yan
Different namespace application might require fast recycling
TIME-WAIT sockets independently of the host.
Signed-off-by: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
---
include/net/inet_timewait_sock.h | 13 +------------
include/net/netns/ipv4.h | 11 +++++++++++
include/net/tcp.h | 1 -
net/ipv4/af_inet.c | 2 --
net/ipv4/inet_timewait_sock.c | 3 +--
net/ipv4/proc.c | 2 +-
net/ipv4/sysctl_net_ipv4.c | 28 ++++++++++++++--------------
net/ipv4/tcp.c | 3 ++-
net/ipv4/tcp_input.c | 2 +-
net/ipv4/tcp_ipv4.c | 12 ++++++++----
net/ipv4/tcp_minisocks.c | 14 +++++---------
net/ipv6/tcp_ipv6.c | 7 ++++---
12 files changed, 48 insertions(+), 50 deletions(-)
diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h
index c9b3eb7..6a75d67 100644
--- a/include/net/inet_timewait_sock.h
+++ b/include/net/inet_timewait_sock.h
@@ -29,16 +29,6 @@
#include <linux/atomic.h>
-struct inet_hashinfo;
-
-struct inet_timewait_death_row {
- atomic_t tw_count;
-
- struct inet_hashinfo *hashinfo ____cacheline_aligned_in_smp;
- int sysctl_tw_recycle;
- int sysctl_max_tw_buckets;
-};
-
struct inet_bind_bucket;
/*
@@ -125,8 +115,7 @@ static inline void inet_twsk_reschedule(struct inet_timewait_sock *tw, int timeo
void inet_twsk_deschedule_put(struct inet_timewait_sock *tw);
-void inet_twsk_purge(struct inet_hashinfo *hashinfo,
- struct inet_timewait_death_row *twdr, int family);
+void inet_twsk_purge(struct inet_hashinfo *hashinfo, int family);
static inline
struct net *twsk_net(const struct inet_timewait_sock *twsk)
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 0378e88..99becaf 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -27,6 +27,16 @@ struct ping_group_range {
kgid_t range[2];
};
+struct inet_hashinfo;
+
+struct inet_timewait_death_row {
+ atomic_t tw_count;
+
+ struct inet_hashinfo *hashinfo ____cacheline_aligned_in_smp;
+ int sysctl_tw_recycle;
+ int sysctl_max_tw_buckets;
+};
+
struct netns_ipv4 {
#ifdef CONFIG_SYSCTL
struct ctl_table_header *forw_hdr;
@@ -111,6 +121,7 @@ struct netns_ipv4 {
int sysctl_tcp_fin_timeout;
unsigned int sysctl_tcp_notsent_lowat;
int sysctl_tcp_tw_reuse;
+ struct inet_timewait_death_row tcp_death_row;
int sysctl_igmp_max_memberships;
int sysctl_igmp_max_msf;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 6061963..1da0aa7 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -231,7 +231,6 @@ void tcp_time_wait(struct sock *sk, int state, int timeo);
*/
#define TFO_SERVER_WO_SOCKOPT1 0x400
-extern struct inet_timewait_death_row tcp_death_row;
/* sysctl variables for tcp */
extern int sysctl_tcp_timestamps;
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 1830e6f..29b1dd9 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1831,8 +1831,6 @@ static int __init inet_init(void)
ip_init();
- tcp_v4_init();
-
/* Setup TCP slab cache for open requests. */
tcp_init();
diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c
index ddcd56c..f8aff2c 100644
--- a/net/ipv4/inet_timewait_sock.c
+++ b/net/ipv4/inet_timewait_sock.c
@@ -257,8 +257,7 @@ void __inet_twsk_schedule(struct inet_timewait_sock *tw, int timeo, bool rearm)
}
EXPORT_SYMBOL_GPL(__inet_twsk_schedule);
-void inet_twsk_purge(struct inet_hashinfo *hashinfo,
- struct inet_timewait_death_row *twdr, int family)
+void inet_twsk_purge(struct inet_hashinfo *hashinfo, int family)
{
struct inet_timewait_sock *tw;
struct sock *sk;
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index 7143ca1..0247ca0 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -65,7 +65,7 @@ static int sockstat_seq_show(struct seq_file *seq, void *v)
socket_seq_show(seq);
seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %ld\n",
sock_prot_inuse_get(net, &tcp_prot), orphans,
- atomic_read(&tcp_death_row.tw_count), sockets,
+ atomic_read(&net->ipv4.tcp_death_row.tw_count), sockets,
proto_memory_allocated(&tcp_prot));
seq_printf(seq, "UDP: inuse %d mem %ld\n",
sock_prot_inuse_get(net, &udp_prot),
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 22cbd61..66f8f1b 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -290,13 +290,6 @@ static struct ctl_table ipv4_table[] = {
.proc_handler = proc_dointvec
},
{
- .procname = "tcp_max_tw_buckets",
- .data = &tcp_death_row.sysctl_max_tw_buckets,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {
.procname = "tcp_fastopen",
.data = &sysctl_tcp_fastopen,
.maxlen = sizeof(int),
@@ -310,13 +303,6 @@ static struct ctl_table ipv4_table[] = {
.proc_handler = proc_tcp_fastopen_key,
},
{
- .procname = "tcp_tw_recycle",
- .data = &tcp_death_row.sysctl_tw_recycle,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {
.procname = "tcp_abort_on_overflow",
.data = &sysctl_tcp_abort_on_overflow,
.maxlen = sizeof(int),
@@ -960,6 +946,20 @@ static struct ctl_table ipv4_net_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec
},
+ {
+ .procname = "tcp_max_tw_buckets",
+ .data = &init_net.ipv4.tcp_death_row.sysctl_max_tw_buckets,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
+ .procname = "tcp_tw_recycle",
+ .data = &init_net.ipv4.tcp_death_row.sysctl_tw_recycle,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
#ifdef CONFIG_IP_ROUTE_MULTIPATH
{
.procname = "fib_multipath_use_neigh",
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 1ef3165..91938c9 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3334,6 +3334,7 @@ void __init tcp_init(void)
percpu_counter_init(&tcp_sockets_allocated, 0, GFP_KERNEL);
percpu_counter_init(&tcp_orphan_count, 0, GFP_KERNEL);
+ inet_hashinfo_init(&tcp_hashinfo);
tcp_hashinfo.bind_bucket_cachep =
kmem_cache_create("tcp_bind_bucket",
sizeof(struct inet_bind_bucket), 0,
@@ -3378,7 +3379,6 @@ void __init tcp_init(void)
cnt = tcp_hashinfo.ehash_mask + 1;
- tcp_death_row.sysctl_max_tw_buckets = cnt / 2;
sysctl_tcp_max_orphans = cnt / 2;
sysctl_max_syn_backlog = max(128, cnt / 256);
@@ -3399,6 +3399,7 @@ void __init tcp_init(void)
pr_info("Hash tables configured (established %u bind %u)\n",
tcp_hashinfo.ehash_mask + 1, tcp_hashinfo.bhash_size);
+ tcp_v4_init();
tcp_metrics_init();
BUG_ON(tcp_register_congestion_control(&tcp_reno) != 0);
tcp_tasklet_init();
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 6c79075..c614802 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6363,7 +6363,7 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
* timewait bucket, so that all the necessary checks
* are made in the function processing timewait state.
*/
- if (tcp_death_row.sysctl_tw_recycle) {
+ if (net->ipv4.tcp_death_row.sysctl_tw_recycle) {
bool strict;
dst = af_ops->route_req(sk, &fl, req, &strict);
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index fe9da4f..56b5f49 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -146,6 +146,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
struct rtable *rt;
int err;
struct ip_options_rcu *inet_opt;
+ struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
if (addr_len < sizeof(struct sockaddr_in))
return -EINVAL;
@@ -196,7 +197,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
tp->write_seq = 0;
}
- if (tcp_death_row.sysctl_tw_recycle &&
+ if (tcp_death_row->sysctl_tw_recycle &&
!tp->rx_opt.ts_recent_stamp && fl4->daddr == daddr)
tcp_fetch_timewait_stamp(sk, &rt->dst);
@@ -215,7 +216,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
* complete initialization after this.
*/
tcp_set_state(sk, TCP_SYN_SENT);
- err = inet_hash_connect(&tcp_death_row, sk);
+ err = inet_hash_connect(tcp_death_row, sk);
if (err)
goto failure;
@@ -2457,6 +2458,10 @@ static int __net_init tcp_sk_init(struct net *net)
net->ipv4.sysctl_tcp_notsent_lowat = UINT_MAX;
net->ipv4.sysctl_tcp_tw_reuse = 0;
+ net->ipv4.tcp_death_row.sysctl_tw_recycle = 0;
+ net->ipv4.tcp_death_row.sysctl_max_tw_buckets = (tcp_hashinfo.ehash_mask + 1) / 2;
+ net->ipv4.tcp_death_row.hashinfo = &tcp_hashinfo;
+
return 0;
fail:
tcp_sk_exit(net);
@@ -2466,7 +2471,7 @@ static int __net_init tcp_sk_init(struct net *net)
static void __net_exit tcp_sk_exit_batch(struct list_head *net_exit_list)
{
- inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET);
+ inet_twsk_purge(&tcp_hashinfo, AF_INET);
}
static struct pernet_operations __net_initdata tcp_sk_ops = {
@@ -2477,7 +2482,6 @@ static struct pernet_operations __net_initdata tcp_sk_ops = {
void __init tcp_v4_init(void)
{
- inet_hashinfo_init(&tcp_hashinfo);
if (register_pernet_subsys(&tcp_sk_ops))
panic("Failed to create the TCP control socket.\n");
}
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 28ce5ee..06fde26 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -29,12 +29,6 @@
int sysctl_tcp_abort_on_overflow __read_mostly;
-struct inet_timewait_death_row tcp_death_row = {
- .sysctl_max_tw_buckets = NR_FILE * 2,
- .hashinfo = &tcp_hashinfo,
-};
-EXPORT_SYMBOL_GPL(tcp_death_row);
-
static bool tcp_in_window(u32 seq, u32 end_seq, u32 s_win, u32 e_win)
{
if (seq == s_win)
@@ -100,6 +94,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
struct tcp_options_received tmp_opt;
struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
bool paws_reject = false;
+ struct inet_timewait_death_row *tcp_death_row = &sock_net((struct sock*)tw)->ipv4.tcp_death_row;
tmp_opt.saw_tstamp = 0;
if (th->doff > (sizeof(*th) >> 2) && tcptw->tw_ts_recent_stamp) {
@@ -153,7 +148,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
tcptw->tw_ts_recent = tmp_opt.rcv_tsval;
}
- if (tcp_death_row.sysctl_tw_recycle &&
+ if (tcp_death_row->sysctl_tw_recycle &&
tcptw->tw_ts_recent_stamp &&
tcp_tw_remember_stamp(tw))
inet_twsk_reschedule(tw, tw->tw_timeout);
@@ -264,11 +259,12 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
const struct tcp_sock *tp = tcp_sk(sk);
struct inet_timewait_sock *tw;
bool recycle_ok = false;
+ struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
- if (tcp_death_row.sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
+ if (tcp_death_row->sysctl_tw_recycle && tp->rx_opt.ts_recent_stamp)
recycle_ok = tcp_remember_stamp(sk);
- tw = inet_twsk_alloc(sk, &tcp_death_row, state);
+ tw = inet_twsk_alloc(sk, tcp_death_row, state);
if (tw) {
struct tcp_timewait_sock *tcptw = tcp_twsk((struct sock *)tw);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 73bc8fc6..a4cdf6a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -123,6 +123,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
struct dst_entry *dst;
int addr_type;
int err;
+ struct inet_timewait_death_row *tcp_death_row = &sock_net(sk)->ipv4.tcp_death_row;
if (addr_len < SIN6_LEN_RFC2133)
return -EINVAL;
@@ -258,7 +259,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
sk->sk_gso_type = SKB_GSO_TCPV6;
ip6_dst_store(sk, dst, NULL, NULL);
- if (tcp_death_row.sysctl_tw_recycle &&
+ if (tcp_death_row->sysctl_tw_recycle &&
!tp->rx_opt.ts_recent_stamp &&
ipv6_addr_equal(&fl6.daddr, &sk->sk_v6_daddr))
tcp_fetch_timewait_stamp(sk, dst);
@@ -273,7 +274,7 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
inet->inet_dport = usin->sin6_port;
tcp_set_state(sk, TCP_SYN_SENT);
- err = inet6_hash_connect(&tcp_death_row, sk);
+ err = inet6_hash_connect(tcp_death_row, sk);
if (err)
goto late_failure;
@@ -1948,7 +1949,7 @@ static void __net_exit tcpv6_net_exit(struct net *net)
static void __net_exit tcpv6_net_exit_batch(struct list_head *net_exit_list)
{
- inet_twsk_purge(&tcp_hashinfo, &tcp_death_row, AF_INET6);
+ inet_twsk_purge(&tcp_hashinfo, AF_INET6);
}
static struct pernet_operations tcpv6_net_ops = {
--
2.5.0
^ permalink raw reply related
* [PATCH 2/2] ipv4: Namespaceify tcp_max_syn_backlog knob
From: Haishuang Yan @ 2016-12-28 9:52 UTC (permalink / raw)
To: David S. Miller, Alexey Kuznetsov, James Morris, Nikolay Borisov
Cc: netdev, linux-kernel, Haishuang Yan
In-Reply-To: <1482918753-1235-1-git-send-email-yanhaishuang@cmss.chinamobile.com>
Different namespace application might require different maximal
number of remembered connection requests.
Signed-off-by: Haishuang Yan <yanhaishuang@cmss.chinamobile.com>
---
include/net/netns/ipv4.h | 1 +
include/net/request_sock.h | 4 +---
net/core/request_sock.c | 2 --
net/ipv4/sysctl_net_ipv4.c | 14 +++++++-------
net/ipv4/tcp.c | 2 --
net/ipv4/tcp_input.c | 4 ++--
net/ipv4/tcp_ipv4.c | 7 +++++--
7 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index 99becaf..96b15a2 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -122,6 +122,7 @@ struct netns_ipv4 {
unsigned int sysctl_tcp_notsent_lowat;
int sysctl_tcp_tw_reuse;
struct inet_timewait_death_row tcp_death_row;
+ int sysctl_max_syn_backlog;
int sysctl_igmp_max_memberships;
int sysctl_igmp_max_msf;
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index 6ebe13e..a12a5d2 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -1,7 +1,7 @@
/*
* NET Generic infrastructure for Network protocols.
*
- * Definitions for request_sock
+ * Definitions for request_sock
*
* Authors: Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
@@ -123,8 +123,6 @@ static inline void reqsk_put(struct request_sock *req)
reqsk_free(req);
}
-extern int sysctl_max_syn_backlog;
-
/*
* For a TCP Fast Open listener -
* lock - protects the access to all the reqsk, which is co-owned by
diff --git a/net/core/request_sock.c b/net/core/request_sock.c
index 5d26056..9b8727c 100644
--- a/net/core/request_sock.c
+++ b/net/core/request_sock.c
@@ -34,8 +34,6 @@
* and it will increase in proportion to the memory of machine.
* Note : Dont forget somaxconn that may limit backlog too.
*/
-int sysctl_max_syn_backlog = 256;
-EXPORT_SYMBOL(sysctl_max_syn_backlog);
void reqsk_queue_alloc(struct request_sock_queue *queue)
{
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 66f8f1b..134d8e1 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -324,13 +324,6 @@ static struct ctl_table ipv4_table[] = {
.proc_handler = proc_dointvec
},
{
- .procname = "tcp_max_syn_backlog",
- .data = &sysctl_max_syn_backlog,
- .maxlen = sizeof(int),
- .mode = 0644,
- .proc_handler = proc_dointvec
- },
- {
.procname = "inet_peer_threshold",
.data = &inet_peer_threshold,
.maxlen = sizeof(int),
@@ -960,6 +953,13 @@ static struct ctl_table ipv4_net_table[] = {
.mode = 0644,
.proc_handler = proc_dointvec
},
+ {
+ .procname = "tcp_max_syn_backlog",
+ .data = &init_net.ipv4.sysctl_max_syn_backlog,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
#ifdef CONFIG_IP_ROUTE_MULTIPATH
{
.procname = "fib_multipath_use_neigh",
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 91938c9..f0637a9 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -3378,9 +3378,7 @@ void __init tcp_init(void)
cnt = tcp_hashinfo.ehash_mask + 1;
-
sysctl_tcp_max_orphans = cnt / 2;
- sysctl_max_syn_backlog = max(128, cnt / 256);
tcp_init_mem();
/* Set per-socket limits to no more than 1/128 the pressure threshold */
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index c614802..ec6d843 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -6377,8 +6377,8 @@ int tcp_conn_request(struct request_sock_ops *rsk_ops,
}
/* Kill the following clause, if you dislike this way. */
else if (!net->ipv4.sysctl_tcp_syncookies &&
- (sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
- (sysctl_max_syn_backlog >> 2)) &&
+ (net->ipv4.sysctl_max_syn_backlog - inet_csk_reqsk_queue_len(sk) <
+ (net->ipv4.sysctl_max_syn_backlog >> 2)) &&
!tcp_peer_is_proven(req, dst, false,
tmp_opt.saw_tstamp)) {
/* Without syncookies last quarter of
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 56b5f49..7e4be4f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -2419,7 +2419,7 @@ static void __net_exit tcp_sk_exit(struct net *net)
static int __net_init tcp_sk_init(struct net *net)
{
- int res, cpu;
+ int res, cpu, cnt;
net->ipv4.tcp_sk = alloc_percpu(struct sock *);
if (!net->ipv4.tcp_sk)
@@ -2458,10 +2458,13 @@ static int __net_init tcp_sk_init(struct net *net)
net->ipv4.sysctl_tcp_notsent_lowat = UINT_MAX;
net->ipv4.sysctl_tcp_tw_reuse = 0;
+ cnt = tcp_hashinfo.ehash_mask + 1;
net->ipv4.tcp_death_row.sysctl_tw_recycle = 0;
- net->ipv4.tcp_death_row.sysctl_max_tw_buckets = (tcp_hashinfo.ehash_mask + 1) / 2;
+ net->ipv4.tcp_death_row.sysctl_max_tw_buckets = (cnt + 1) / 2;
net->ipv4.tcp_death_row.hashinfo = &tcp_hashinfo;
+ net->ipv4.sysctl_max_syn_backlog = max(128, cnt / 256);
+
return 0;
fail:
tcp_sk_exit(net);
--
2.5.0
^ permalink raw reply related
* [PATCH v3] net: dev_weight: TX/RX orthogonality
From: Matthias Tafelmeier @ 2016-12-28 9:42 UTC (permalink / raw)
To: netdev; +Cc: hagen, fw, edumazet, daniel
In-Reply-To: <20161227164758.GA10870@localhost.localdomain>
Oftenly, introducing side effects on packet processing on the other half
of the stack by adjusting one of TX/RX via sysctl is not desirable.
There are cases of demand for asymmetric, orthogonal configurability.
This holds true especially for nodes where RPS for RFS usage on top is
configured and therefore use the 'old dev_weight'. This is quite a
common base configuration setup nowadays, even with NICs of superior processing
support (e.g. aRFS).
A good example use case are nodes acting as noSQL data bases with a
large number of tiny requests and rather fewer but large packets as responses.
It's affordable to have large budget and rx dev_weights for the
requests. But as a side effect having this large a number on TX
processed in one run can overwhelm drivers.
This patch therefore introduces an independent configurability via sysctl to
userland.
---
Documentation/sysctl/net.txt | 21 +++++++++++++++++++++
include/linux/netdevice.h | 2 ++
net/core/dev.c | 4 +++-
net/core/sysctl_net_core.c | 14 ++++++++++++++
net/sched/sch_generic.c | 2 +-
5 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/Documentation/sysctl/net.txt b/Documentation/sysctl/net.txt
index f0480f7..53cef32 100644
--- a/Documentation/sysctl/net.txt
+++ b/Documentation/sysctl/net.txt
@@ -61,6 +61,27 @@ The maximum number of packets that kernel can handle on a NAPI interrupt,
it's a Per-CPU variable.
Default: 64
+dev_weight_rx_bias
+--------------
+
+RPS (e.g. RFS, aRFS) processing is competing with the registered NAPI poll function
+of the driver for the per softirq cycle netdev_budget. This parameter influences
+the proportion of the configured netdev_budget that is spent on RPS based packet
+processing during RX softirq cycles. It is further meant for making current
+dev_weight adaptable for asymmetric CPU needs on RX/TX side of the network stack.
+(see dev_weight_tx_bias) It is effective on a per CPU basis. Determination is based
+on dev_weight and is calculated multiplicative (dev_weight * dev_weight_rx_bias).
+Default: 1
+
+dev_weight_tx_bias
+--------------
+
+Scales the maximum number of packets that can be processed during a TX softirq cycle.
+Effective on a per CPU basis. Allows scaling of current dev_weight for asymmetric
+net stack processing needs. Be careful to avoid making TX softirq processing a CPU hog.
+Calculation is based on dev_weight (dev_weight * dev_weight_tx_bias).
+Default: 1
+
default_qdisc
--------------
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 994f742..46b4b66 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -3795,6 +3795,8 @@ void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
extern int netdev_max_backlog;
extern int netdev_tstamp_prequeue;
extern int weight_p;
+extern int dev_weight_rx_bias;
+extern int dev_weight_tx_bias;
bool netdev_has_upper_dev(struct net_device *dev, struct net_device *upper_dev);
struct net_device *netdev_upper_get_next_dev_rcu(struct net_device *dev,
diff --git a/net/core/dev.c b/net/core/dev.c
index 8db5a0b..7ce1736 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -3428,6 +3428,8 @@ EXPORT_SYMBOL(netdev_max_backlog);
int netdev_tstamp_prequeue __read_mostly = 1;
int netdev_budget __read_mostly = 300;
int weight_p __read_mostly = 64; /* old backlog weight */
+int dev_weight_rx_bias __read_mostly = 1; /* bias for backlog weight */
+int dev_weight_tx_bias __read_mostly = 1; /* bias for output_queue quota */
/* Called with irq disabled */
static inline void ____napi_schedule(struct softnet_data *sd,
@@ -4833,7 +4835,7 @@ static int process_backlog(struct napi_struct *napi, int quota)
net_rps_action_and_irq_enable(sd);
}
- napi->weight = weight_p;
+ napi->weight = weight_p * dev_weight_rx_bias;
while (again) {
struct sk_buff *skb;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 2a46e40..2197388 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -276,6 +276,20 @@ static struct ctl_table net_core_table[] = {
.proc_handler = proc_dointvec
},
{
+ .procname = "dev_weight_rx_bias",
+ .data = &dev_weight_rx_bias,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
+ .procname = "dev_weight_tx_bias",
+ .data = &dev_weight_tx_bias,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec
+ },
+ {
.procname = "netdev_max_backlog",
.data = &netdev_max_backlog,
.maxlen = sizeof(int),
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 6eb9c8e..19374ef 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -247,7 +247,7 @@ static inline int qdisc_restart(struct Qdisc *q, int *packets)
void __qdisc_run(struct Qdisc *q)
{
- int quota = weight_p;
+ int quota = weight_p * dev_weight_tx_bias;
int packets;
while (qdisc_restart(q, &packets)) {
--
2.7.4
^ permalink raw reply related
* Re: [PATCH RFC 5/5] qedf: Add FIP request handling
From: Hannes Reinecke @ 2016-12-28 9:11 UTC (permalink / raw)
To: Dupuis, Chad, martin.petersen-QHcLZuEGTsvQT0dZR+AlfA
Cc: fcoe-devel-s9riP+hp16TNLxjTenLetw, netdev-u79uwXL29TY76Z2rM5mHXA,
yuval.mintz-YGCgFSpz5w/QT0dZR+AlfA,
linux-scsi-u79uwXL29TY76Z2rM5mHXA,
QLogic-Storage-Upstream-YGCgFSpz5w/QT0dZR+AlfA
In-Reply-To: <1482520628-24207-6-git-send-email-chad.dupuis-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
On 12/23/2016 08:17 PM, Dupuis, Chad wrote:
> From: "Dupuis, Chad" <chad.dupuis-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>
> This patch adds handling for FIP requests and responses that are handled by
> the driver itself and not by libfcoe.
>
> Signed-off-by: Nilesh Javali <nilesh.javali-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Manish Rangankar <manish.rangankar-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Saurav Kashyap <saurav.kashyap-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Chad Dupuis <chad.dupuis-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> ---
> drivers/scsi/qedf/qedf_fip.c | 267 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 267 insertions(+)
> create mode 100644 drivers/scsi/qedf/qedf_fip.c
>
> diff --git a/drivers/scsi/qedf/qedf_fip.c b/drivers/scsi/qedf/qedf_fip.c
> new file mode 100644
> index 0000000..4f185c6
> --- /dev/null
> +++ b/drivers/scsi/qedf/qedf_fip.c
> @@ -0,0 +1,267 @@
> +/*
> + * QLogic FCoE Offload Driver
> + * Copyright (c) 2016 Cavium Inc.
> + *
> + * This software is available under the terms of the GNU General Public License
> + * (GPL) Version 2, available from the file COPYING in the main directory of
> + * this source tree.
> + */
> +#include <linux/if_ether.h>
> +#include <linux/if_vlan.h>
> +#include "qedf.h"
> +
> +extern const struct qed_fcoe_ops *qed_ops;
> +/*
> + * FIP VLAN functions that will eventually move to libfcoe.
> + */
> +
> +void qedf_fcoe_send_vlan_req(struct qedf_ctx *qedf)
> +{
> + struct sk_buff *skb;
> + char *eth_fr;
> + int fr_len;
> + struct fip_vlan *vlan;
> +#define MY_FIP_ALL_FCF_MACS ((__u8[6]) { 1, 0x10, 0x18, 1, 0, 2 })
> + static u8 my_fcoe_all_fcfs[ETH_ALEN] = MY_FIP_ALL_FCF_MACS;
Do you support VN2VN, too?
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare-l3A5Bk7waGM@public.gmane.org +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
^ permalink raw reply
* Re: [Open-FCoE] [PATCH RFC 4/5] qedf: Add offload ELS request handling.
From: Hannes Reinecke @ 2016-12-28 9:10 UTC (permalink / raw)
To: Dupuis, Chad, martin.petersen
Cc: fcoe-devel, netdev, QLogic-Storage-Upstream, linux-scsi,
yuval.mintz
In-Reply-To: <1482520628-24207-5-git-send-email-chad.dupuis@cavium.com>
On 12/23/2016 08:17 PM, Dupuis, Chad wrote:
> From: "Dupuis, Chad" <chad.dupuis@cavium.com>
>
> This patch adds support for ELS requests that are handled by the firmware for
> offloaded sessions.
>
> Signed-off-by: Nilesh Javali <nilesh.javali@cavium.com>
> Signed-off-by: Manish Rangankar <manish.rangankar@cavium.com>
> Signed-off-by: Saurav Kashyap <saurav.kashyap@cavium.com>
> Signed-off-by: Chad Dupuis <chad.dupuis@cavium.com>
> ---
> drivers/scsi/qedf/qedf_els.c | 984 +++++++++++++++++++++++++++++++++++++++++++
> 1 file changed, 984 insertions(+)
> create mode 100644 drivers/scsi/qedf/qedf_els.c
>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
^ permalink raw reply
* Re: [PATCH RFC 3/5] qedf: Add offloaded I/O request functions.
From: Hannes Reinecke @ 2016-12-28 9:08 UTC (permalink / raw)
To: Dupuis, Chad, martin.petersen-QHcLZuEGTsvQT0dZR+AlfA
Cc: fcoe-devel-s9riP+hp16TNLxjTenLetw, netdev-u79uwXL29TY76Z2rM5mHXA,
yuval.mintz-YGCgFSpz5w/QT0dZR+AlfA,
linux-scsi-u79uwXL29TY76Z2rM5mHXA,
QLogic-Storage-Upstream-YGCgFSpz5w/QT0dZR+AlfA
In-Reply-To: <1482520628-24207-4-git-send-email-chad.dupuis-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
On 12/23/2016 08:17 PM, Dupuis, Chad wrote:
> From: "Dupuis, Chad" <chad.dupuis-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
>
> This patch adds various I/O requests types that are handled in firmware:
>
> - Normal I/O requests
> - ABTS requests
> - Cleanup requests
> - Task management requests
>
> It also contains:
>
> - I/O request initialization
> - Firmware completion handling
>
> Signed-off-by: Nilesh Javali <nilesh.javali-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Manish Rangankar <manish.rangankar-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Saurav Kashyap <saurav.kashyap-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Chad Dupuis <chad.dupuis-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> ---
> drivers/scsi/qedf/qedf_hsi.h | 427 ++++++++
> drivers/scsi/qedf/qedf_io.c | 2303 ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 2730 insertions(+)
> create mode 100644 drivers/scsi/qedf/qedf_hsi.h
> create mode 100644 drivers/scsi/qedf/qedf_io.c
>
[ .. ]
> +static int qedf_execute_tmf(struct qedf_rport *fcport, struct scsi_cmnd *sc_cmd,
> + uint8_t tm_flags)
> +{
> + struct qedf_ioreq *io_req;
> + struct qedf_mp_req *tm_req;
> + struct fcoe_task_context *task;
> + struct fc_frame_header *fc_hdr;
> + struct fcp_cmnd *fcp_cmnd;
> + struct qedf_ctx *qedf = fcport->qedf;
> + int rc = 0;
> + uint16_t xid;
> + uint32_t sid, did;
> + int tmo = 0;
> + unsigned long flags;
> +
> + if (!sc_cmd) {
> + QEDF_ERR(&(qedf->dbg_ctx), "invalid arg\n");
> + return FAILED;
> + }
> +
> + if (!(test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags))) {
> + QEDF_ERR(&(qedf->dbg_ctx), "fcport not offloaded\n");
> + rc = FAILED;
> + return FAILED;
> + }
> +
> + scsi_block_requests(qedf->lport->host);
> +
Typically, EH commands will be executed after the scsi host is stopped
and no commands are outstanding.
So there's no point in issuing 'scsi_block_requests()' here.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare-l3A5Bk7waGM@public.gmane.org +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
^ permalink raw reply
* Re: [Open-FCoE] [PATCH RFC 2/5] qedf: Add QLogic FastLinQ offload FCoE driver framework.
From: Hannes Reinecke @ 2016-12-28 9:00 UTC (permalink / raw)
To: Dupuis, Chad, martin.petersen
Cc: fcoe-devel, netdev, QLogic-Storage-Upstream, linux-scsi,
yuval.mintz
In-Reply-To: <1482520628-24207-3-git-send-email-chad.dupuis@cavium.com>
On 12/23/2016 08:17 PM, Dupuis, Chad wrote:
> From: "Dupuis, Chad" <chad.dupuis@cavium.com>
>
> The QLogic FastLinQ Driver for FCoE (qedf) is the FCoE specific module
> for 41000 Series Converged Network Adapters by QLogic.
>
> This patch consists of following changes:
> - MAINTAINERS Makefile and Kconfig changes for qedf
> - PCI driver registration
> - libfc/fcoe host level initialization
> - SCSI host template initialization and callbacks
> - Debugfs and log level infrastructure
> - Link handling
> - Firmware interface structures
> - QED core module initialization
> - Light L2 interface callbacks
>
> Signed-off-by: Nilesh Javali <nilesh.javali@cavium.com>
> Signed-off-by: Manish Rangankar <manish.rangankar@cavium.com>
> Signed-off-by: Saurav Kashyap <saurav.kashyap@cavium.com>
> Signed-off-by: Chad Dupuis <chad.dupuis@cavium.com>
> ---
> MAINTAINERS | 6 +
> drivers/scsi/Kconfig | 1 +
> drivers/scsi/qedf/Kconfig | 11 +
> drivers/scsi/qedf/Makefile | 5 +
> drivers/scsi/qedf/qedf.h | 555 ++++++
> drivers/scsi/qedf/qedf_attr.c | 165 ++
> drivers/scsi/qedf/qedf_dbg.c | 192 +++
> drivers/scsi/qedf/qedf_dbg.h | 153 ++
> drivers/scsi/qedf/qedf_debugfs.c | 472 +++++
> drivers/scsi/qedf/qedf_main.c | 3519 ++++++++++++++++++++++++++++++++++++++
> drivers/scsi/qedf/qedf_version.h | 15 +
> 11 files changed, 5094 insertions(+)
> create mode 100644 drivers/scsi/qedf/Kconfig
> create mode 100644 drivers/scsi/qedf/Makefile
> create mode 100644 drivers/scsi/qedf/qedf.h
> create mode 100644 drivers/scsi/qedf/qedf_attr.c
> create mode 100644 drivers/scsi/qedf/qedf_dbg.c
> create mode 100644 drivers/scsi/qedf/qedf_dbg.h
> create mode 100644 drivers/scsi/qedf/qedf_debugfs.c
> create mode 100644 drivers/scsi/qedf/qedf_main.c
> create mode 100644 drivers/scsi/qedf/qedf_version.h
>
[ .. ]
> +/* Returns true if we have a valid vlan, false otherwise */
> +static bool qedf_initiate_fipvlan_req(struct qedf_ctx *qedf)
> +{
> + int rc;
> +
> + if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) {
> + QEDF_ERR(&(qedf->dbg_ctx), "Link not up.\n");
> + return false;
> + }
> +
> + while (qedf->fipvlan_retries--) {
> + if (qedf->vlan_id > 0)
> + return true;
Some weird FCoE bridges (most notably HP VirtualConnect) return a VLAN
ID of '0'. Shouldn't you rather test for '>= 0' here?
[ .. ]
> +
> +static void qedf_flogi_resp(struct fc_seq *seq, struct fc_frame *fp,
> + void *arg)
> +{
> + struct fc_exch *exch = fc_seq_exch(seq);
> + struct fc_lport *lport = exch->lp;
> + struct qedf_ctx *qedf = lport_priv(lport);
> +
> + if (!qedf) {
> + QEDF_ERR(NULL, "qedf is NULL.\n");
> + return;
> + }
> +
> + /*
> + * If ERR_PTR is set then don't try to stat anything as it will cause
> + * a crash when we access fp.
> + */
> + if (fp == ERR_PTR(-FC_EX_TIMEOUT) ||
> + fp == ERR_PTR(-FC_EX_CLOSED)) {
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_ELS,
> + "fp has ERR_PTR() set.\n");
> + goto skip_stat;
> + }
Please use
if (IS_ERR(fp)) {
here instead of checking for individual error codes; if 'fp' has a
different error value you'll continue with an invalid fp from here on.
[ .. ]
> +/**
> + * qedf_xmit - qedf FCoE frame transmit function
> + *
> + */
> +static int qedf_xmit(struct fc_lport *lport, struct fc_frame *fp)
> +{
> + struct fc_lport *base_lport;
> + struct qedf_ctx *qedf;
> + struct ethhdr *eh;
> + struct fcoe_crc_eof *cp;
> + struct sk_buff *skb;
> + struct fc_frame_header *fh;
> + struct fcoe_hdr *hp;
> + u8 sof, eof;
> + u32 crc;
> + unsigned int hlen, tlen, elen;
> + int wlen;
> + struct fc_stats *stats;
> + struct fc_lport *tmp_lport;
> + struct fc_lport *vn_port = NULL;
> + struct qedf_rport *fcport;
> + int rc;
> + u16 vlan_tci = 0;
> + unsigned long flags;
> +
> + qedf = (struct qedf_ctx *)lport_priv(lport);
> +
> + fh = fc_frame_header_get(fp);
> + skb = fp_skb(fp);
> +
> + /* Filter out traffic to other NPIV ports on the same host */
> + if (lport->vport)
> + base_lport = shost_priv(vport_to_shost(lport->vport));
> + else
> + base_lport = lport;
> +
> + /* Flag if the destination is the base port */
> + if (base_lport->port_id == ntoh24(fh->fh_d_id)) {
> + vn_port = base_lport;
> + } else {
> + /* Got through the list of vports attached to the base_lport
> + * and see if we have a match with the destination address.
> + */
> + list_for_each_entry(tmp_lport, &base_lport->vports, list) {
> + if (tmp_lport->port_id == ntoh24(fh->fh_d_id)) {
> + vn_port = tmp_lport;
> + break;
> + }
> + }
> + }
> + if (vn_port && ntoh24(fh->fh_d_id) != FC_FID_FLOGI) {
> + struct fc_rport_priv *rdata = NULL;
> +
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2,
> + "Dropping FCoE frame to %06x.\n", ntoh24(fh->fh_d_id));
> + kfree_skb(skb);
> + rdata = fc_rport_lookup(lport, ntoh24(fh->fh_d_id));
> + if (rdata)
> + rdata->retries = lport->max_rport_retry_count;
> + return -EINVAL;
> + }
> + /* End NPIV filtering */
> +
> + if (!qedf->ctlr.sel_fcf) {
> + kfree_skb(skb);
> + return 0;
> + }
> +
> + if (!test_bit(QEDF_LL2_STARTED, &qedf->flags)) {
> + QEDF_WARN(&(qedf->dbg_ctx), "LL2 not started\n");
> + kfree_skb(skb);
> + return 0;
> + }
> +
> + if (atomic_read(&qedf->link_state) != QEDF_LINK_UP) {
> + QEDF_WARN(&(qedf->dbg_ctx), "qedf link down\n");
> + kfree_skb(skb);
> + return 0;
> + }
> +
> + if (unlikely(fh->fh_r_ctl == FC_RCTL_ELS_REQ)) {
> + if (fcoe_ctlr_els_send(&qedf->ctlr, lport, skb))
> + return 0;
> + }
> +
> + /* Check to see if this needs to be sent on an offloaded session */
> + spin_lock_irqsave(&qedf->hba_lock, flags);
> + fcport = qedf_fcport_lookup(qedf, ntoh24(fh->fh_d_id));
> + spin_unlock_irqrestore(&qedf->hba_lock, flags);
> +
Really sad, having to take a spinlock here to get to the session.
Can't you use RCU for rport lookup?
That would save you the spinlock here ...
> + if (fcport && test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) {
> + rc = qedf_xmit_l2_frame(fcport, fp);
> + /*
> + * If the frame was successfully sent over the middle path
> + * then do not try to also send it over the LL2 path
> + */
> + if (rc)
> + return 0;
> + }
> +
> + sof = fr_sof(fp);
> + eof = fr_eof(fp);
> +
> + elen = sizeof(struct ethhdr);
> + hlen = sizeof(struct fcoe_hdr);
> + tlen = sizeof(struct fcoe_crc_eof);
> + wlen = (skb->len - tlen + sizeof(crc)) / FCOE_WORD_TO_BYTE;
> +
> + skb->ip_summed = CHECKSUM_NONE;
> + crc = fcoe_fc_crc(fp);
> +
> + /* copy port crc and eof to the skb buff */
> + if (skb_is_nonlinear(skb)) {
> + skb_frag_t *frag;
> +
> + if (qedf_get_paged_crc_eof(skb, tlen)) {
> + kfree_skb(skb);
> + return -ENOMEM;
> + }
> + frag = &skb_shinfo(skb)->frags[skb_shinfo(skb)->nr_frags - 1];
> + cp = kmap_atomic(skb_frag_page(frag)) + frag->page_offset;
> + } else {
> + cp = (struct fcoe_crc_eof *)skb_put(skb, tlen);
> + }
> +
> + memset(cp, 0, sizeof(*cp));
> + cp->fcoe_eof = eof;
> + cp->fcoe_crc32 = cpu_to_le32(~crc);
> + if (skb_is_nonlinear(skb)) {
> + kunmap_atomic(cp);
> + cp = NULL;
> + }
> +
> +
> + /* adjust skb network/transport offsets to match mac/fcoe/port */
> + skb_push(skb, elen + hlen);
> + skb_reset_mac_header(skb);
> + skb_reset_network_header(skb);
> + skb->mac_len = elen;
> + skb->protocol = htons(ETH_P_FCOE);
> +
> + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), qedf->vlan_id);
> +
> + /* fill up mac and fcoe headers */
> + eh = eth_hdr(skb);
> + eh->h_proto = htons(ETH_P_FCOE);
> + if (qedf->ctlr.map_dest)
> + fc_fcoe_set_mac(eh->h_dest, fh->fh_d_id);
> + else
> + /* insert GW address */
> + ether_addr_copy(eh->h_dest, qedf->ctlr.dest_addr);
> +
> + /* Set the source MAC address */
> + fc_fcoe_set_mac(eh->h_source, fh->fh_s_id);
> +
> + hp = (struct fcoe_hdr *)(eh + 1);
> + memset(hp, 0, sizeof(*hp));
> + if (FC_FCOE_VER)
> + FC_FCOE_ENCAPS_VER(hp, FC_FCOE_VER);
> + hp->fcoe_sof = sof;
> +
> + /*update tx stats */
> + stats = per_cpu_ptr(lport->stats, get_cpu());
> + stats->TxFrames++;
> + stats->TxWords += wlen;
> + put_cpu();
> +
> + /* Get VLAN ID from skb for printing purposes */
> + __vlan_hwaccel_get_tag(skb, &vlan_tci);
> +
> + /* send down to lld */
> + fr_dev(fp) = lport;
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_LL2, "FCoE frame send: "
> + "src=%06x dest=%06x r_ctl=%x type=%x vlan=%04x.\n",
> + ntoh24(fh->fh_s_id), ntoh24(fh->fh_d_id), fh->fh_r_ctl, fh->fh_type,
> + vlan_tci);
> + if (qedf_dump_frames)
> + print_hex_dump(KERN_WARNING, "fcoe: ", DUMP_PREFIX_OFFSET, 16,
> + 1, skb->data, skb->len, false);
> + qed_ops->ll2->start_xmit(qedf->cdev, skb);
> +
> + return 0;
> +}
> +
> +static int qedf_alloc_sq(struct qedf_ctx *qedf, struct qedf_rport *fcport)
> +{
> + int rval = 0;
> + u32 *pbl;
> + dma_addr_t page;
> + int num_pages;
> +
> + /* Calculate appropriate queue and PBL sizes */
> + fcport->sq_mem_size = SQ_NUM_ENTRIES * sizeof(struct fcoe_wqe);
> + fcport->sq_mem_size = ALIGN(fcport->sq_mem_size, QEDF_PAGE_SIZE);
> + fcport->sq_pbl_size = (fcport->sq_mem_size / QEDF_PAGE_SIZE) *
> + sizeof(void *);
> + fcport->sq_pbl_size = fcport->sq_pbl_size + QEDF_PAGE_SIZE;
> +
> + fcport->sq = dma_alloc_coherent(&qedf->pdev->dev, fcport->sq_mem_size,
> + &fcport->sq_dma, GFP_KERNEL);
> + if (!fcport->sq) {
> + QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate send "
> + "queue.\n");
> + rval = 1;
> + goto out;
> + }
> + memset(fcport->sq, 0, fcport->sq_mem_size);
> +
> + fcport->sq_pbl = dma_alloc_coherent(&qedf->pdev->dev,
> + fcport->sq_pbl_size, &fcport->sq_pbl_dma, GFP_KERNEL);
> + if (!fcport->sq_pbl) {
> + QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate send "
> + "queue PBL.\n");
> + rval = 1;
> + goto out_free_sq;
> + }
> + memset(fcport->sq_pbl, 0, fcport->sq_pbl_size);
> +
> + /* Create PBL */
> + num_pages = fcport->sq_mem_size / QEDF_PAGE_SIZE;
> + page = fcport->sq_dma;
> + pbl = (u32 *)fcport->sq_pbl;
> +
> + while (num_pages--) {
> + *pbl = U64_LO(page);
> + pbl++;
> + *pbl = U64_HI(page);
> + pbl++;
> + page += QEDF_PAGE_SIZE;
> + }
> +
> + return rval;
> +
> +out_free_sq:
> + dma_free_coherent(&qedf->pdev->dev, fcport->sq_mem_size, fcport->sq,
> + fcport->sq_dma);
> +out:
> + return rval;
> +}
> +
> +static void qedf_free_sq(struct qedf_ctx *qedf, struct qedf_rport *fcport)
> +{
> + if (fcport->sq_pbl)
> + dma_free_coherent(&qedf->pdev->dev, fcport->sq_pbl_size,
> + fcport->sq_pbl, fcport->sq_pbl_dma);
> + if (fcport->sq)
> + dma_free_coherent(&qedf->pdev->dev, fcport->sq_mem_size,
> + fcport->sq, fcport->sq_dma);
> +}
> +
> +/*
> + * Allocate a cookie into the qedf_ctx rport list. Assumes the hba lock
> + * is held on entry.
> + */
> +static int qedf_alloc_conn_id(struct qedf_ctx *qedf, struct qedf_rport *fcport)
> +{
> + int i;
> +
> + for (i = 0; i < QEDF_MAX_SESSIONS; i++) {
> + qedf->curr_conn_id++;
> + if (qedf->curr_conn_id == QEDF_MAX_SESSIONS)
> + qedf->curr_conn_id = 0;
> + if (qedf->fcports[qedf->curr_conn_id] == NULL) {
> + qedf->fcports[qedf->curr_conn_id] = fcport;
> + fcport->conn_id = qedf->curr_conn_id;
> + break;
> + }
> + }
> + if (i == QEDF_MAX_SESSIONS)
> + return -1;
> + else
> + return 0;
> +}
> +
Have you looked at the 'sbitmap' code for conn_id allocation?
Should be giving you the same results, but you won't need to use a
spinlock ...
> +static int qedf_offload_connection(struct qedf_ctx *qedf,
> + struct qedf_rport *fcport)
> +{
> + struct qed_fcoe_params_offload conn_info;
> + u32 port_id;
> + u8 lport_src_id[3];
> + int rval;
> + uint16_t total_sqe = (fcport->sq_mem_size / sizeof(struct fcoe_wqe));
> +
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN, "Offloading connection "
> + "portid=%06x.\n", fcport->rdata->ids.port_id);
> + rval = qed_ops->acquire_conn(qedf->cdev, &fcport->handle,
> + &fcport->fw_cid, &fcport->p_doorbell);
> + if (rval) {
> + QEDF_WARN(&(qedf->dbg_ctx), "Could not acquire connection "
> + "for portid=%06x.\n", fcport->rdata->ids.port_id);
> + rval = 1; /* For some reason qed returns 0 on failure here */
> + goto out;
> + }
> +
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN, "portid=%06x "
> + "fw_cid=%08x handle=%d.\n", fcport->rdata->ids.port_id,
> + fcport->fw_cid, fcport->handle);
> +
> + memset(&conn_info, 0, sizeof(struct qed_fcoe_params_offload));
> +
> + /* Fill in the offload connection info */
> + conn_info.sq_pbl_addr = fcport->sq_pbl_dma;
> +
> + conn_info.sq_curr_page_addr = (dma_addr_t)(*(u64 *)fcport->sq_pbl);
> + conn_info.sq_next_page_addr =
> + (dma_addr_t)(*(u64 *)(fcport->sq_pbl + 8));
> +
> + /* Need to use our FCoE MAC for the offload session */
> + port_id = fc_host_port_id(qedf->lport->host);
> + lport_src_id[2] = (port_id & 0x000000FF);
> + lport_src_id[1] = (port_id & 0x0000FF00) >> 8;
> + lport_src_id[0] = (port_id & 0x00FF0000) >> 16;
> + fc_fcoe_set_mac(conn_info.src_mac, lport_src_id);
> +
> + ether_addr_copy(conn_info.dst_mac, qedf->ctlr.dest_addr);
> +
> + conn_info.tx_max_fc_pay_len = fcport->rdata->maxframe_size;
> + conn_info.e_d_tov_timer_val = qedf->lport->e_d_tov / 20;
> + conn_info.rec_tov_timer_val = 3; /* I think this is what E3 was */
> + conn_info.rx_max_fc_pay_len = fcport->rdata->maxframe_size;
> +
> + /* Set VLAN data */
> + conn_info.vlan_tag = qedf->vlan_id <<
> + FCOE_CONN_OFFLOAD_RAMROD_DATA_VLAN_ID_SHIFT;
> + conn_info.vlan_tag |=
> + qedf_default_prio << FCOE_CONN_OFFLOAD_RAMROD_DATA_PRIORITY_SHIFT;
> + conn_info.flags |= (FCOE_CONN_OFFLOAD_RAMROD_DATA_B_VLAN_FLAG_MASK <<
> + FCOE_CONN_OFFLOAD_RAMROD_DATA_B_VLAN_FLAG_SHIFT);
> +
> + /* Set host port source id */
> + port_id = fc_host_port_id(qedf->lport->host);
> + fcport->sid = port_id;
> + conn_info.s_id.addr_hi = (port_id & 0x000000FF);
> + conn_info.s_id.addr_mid = (port_id & 0x0000FF00) >> 8;
> + conn_info.s_id.addr_lo = (port_id & 0x00FF0000) >> 16;
> +
> + conn_info.max_conc_seqs_c3 = fcport->rdata->max_seq;
> +
> + /* Set remote port destination id */
> + port_id = fcport->rdata->rport->port_id;
> + conn_info.d_id.addr_hi = (port_id & 0x000000FF);
> + conn_info.d_id.addr_mid = (port_id & 0x0000FF00) >> 8;
> + conn_info.d_id.addr_lo = (port_id & 0x00FF0000) >> 16;
> +
> + conn_info.def_q_idx = 0; /* Default index for send queue? */
> +
> + /* Set FC-TAPE specific flags if needed */
> + if (fcport->dev_type == QEDF_RPORT_TYPE_TAPE) {
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN,
> + "Enable CONF, REC for portid=%06x.\n",
> + fcport->rdata->ids.port_id);
> + conn_info.flags |= 1 <<
> + FCOE_CONN_OFFLOAD_RAMROD_DATA_B_CONF_REQ_SHIFT;
> + conn_info.flags |=
> + ((fcport->rdata->sp_features & FC_SP_FT_SEQC) ? 1 : 0) <<
> + FCOE_CONN_OFFLOAD_RAMROD_DATA_B_REC_VALID_SHIFT;
> + }
> +
> + rval = qed_ops->offload_conn(qedf->cdev, fcport->handle, &conn_info);
> + if (rval) {
> + QEDF_WARN(&(qedf->dbg_ctx), "Could not offload connection "
> + "for portid=%06x.\n", fcport->rdata->ids.port_id);
> + goto out_free_conn;
> + } else
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN, "Offload "
> + "succeeded portid=%06x total_sqe=%d.\n",
> + fcport->rdata->ids.port_id, total_sqe);
> +
> + spin_lock_init(&fcport->rport_lock);
> + atomic_set(&fcport->free_sqes, total_sqe);
> + return 0;
> +out_free_conn:
> + qed_ops->release_conn(qedf->cdev, fcport->handle);
> +out:
> + return rval;
> +}
> +
> +#define QEDF_TERM_BUFF_SIZE 10
> +static void qedf_upload_connection(struct qedf_ctx *qedf,
> + struct qedf_rport *fcport)
> +{
> + void *term_params;
> + dma_addr_t term_params_dma;
> +
> + /* Term params needs to be a DMA coherent buffer as qed shared the
> + * physical DMA address with the firmware. The buffer may be used in
> + * the receive path so we may eventually have to move this.
> + */
> + term_params = dma_alloc_coherent(&qedf->pdev->dev, QEDF_TERM_BUFF_SIZE,
> + &term_params_dma, GFP_KERNEL);
> +
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN, "Uploading connection "
> + "port_id=%06x.\n", fcport->rdata->ids.port_id);
> +
> + qed_ops->destroy_conn(qedf->cdev, fcport->handle, term_params_dma);
> + qed_ops->release_conn(qedf->cdev, fcport->handle);
> +
> + dma_free_coherent(&qedf->pdev->dev, QEDF_TERM_BUFF_SIZE, term_params,
> + term_params_dma);
> +}
> +
> +static void qedf_cleanup_fcport(struct qedf_ctx *qedf,
> + struct qedf_rport *fcport)
> +{
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_CONN, "Clearing conn_id=%u "
> + "for portid=%06x.\n", fcport->conn_id,
> + fcport->rdata->ids.port_id);
> +
> + /* Flush any remaining i/o's before we upload the connection */
> + qedf_flush_active_ios(fcport, -1);
> +
> + spin_lock(&qedf->hba_lock);
> + qedf->fcports[fcport->conn_id] = NULL;
> + fcport->conn_id = -1;
> + spin_unlock(&qedf->hba_lock);
> +
> + if (test_and_clear_bit(QEDF_RPORT_SESSION_READY, &fcport->flags))
> + qedf_upload_connection(qedf, fcport);
> + qedf_free_sq(qedf, fcport);
> + fcport->rdata = NULL;
> + fcport->qedf = NULL;
> +}
> +
> +/**
> + * This event_callback is called after successful completion of libfc
> + * initiated target login. qedf can proceed with initiating the session
> + * establishment.
> + */
> +static void qedf_rport_event_handler(struct fc_lport *lport,
> + struct fc_rport_priv *rdata,
> + enum fc_rport_event event)
> +{
> + struct qedf_ctx *qedf = lport_priv(lport);
> + struct fc_rport *rport = rdata->rport;
> + struct fc_rport_libfc_priv *rp;
> + struct qedf_rport *fcport;
> + u32 port_id;
> + int rval;
> +
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC, "event = %d, "
> + "port_id = 0x%x\n", event, rdata->ids.port_id);
> +
> + switch (event) {
> + case RPORT_EV_READY:
> + if (!rport) {
> + QEDF_WARN(&(qedf->dbg_ctx), "rport is NULL.\n");
> + break;
> + }
> +
> + rp = rport->dd_data;
> + fcport = (struct qedf_rport *)&rp[1];
> + fcport->qedf = qedf;
> +
> + /*
> + * Don't try to offload the session again. Can happen when we
> + * get an ADISC
> + */
> + if (test_bit(QEDF_RPORT_SESSION_READY, &fcport->flags)) {
> + QEDF_WARN(&(qedf->dbg_ctx), "Session already "
> + "offloaded, portid=0x%x.\n",
> + rdata->ids.port_id);
> + return;
> + }
> +
> + /*
> + * Set the connection id to -1 so we know if we ever assigned
> + * one to the fcport.
> + */
> + fcport->conn_id = -1;
> +
> + if (rport->port_id == FC_FID_DIR_SERV) {
> + /*
> + * qedf_rport structure doesn't exist for
> + * directory server.
> + * We should not come here, as lport will
> + * take care of fabric login
> + */
> + QEDF_WARN(&(qedf->dbg_ctx), "rport struct does not "
> + "exist for dir server port_id=%x\n",
> + rdata->ids.port_id);
> + break;
> + }
> +
> + if (rdata->spp_type != FC_TYPE_FCP) {
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
> + "Not offlading since since spp type isn't FCP\n");
> + break;
> + }
> + if (!(rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET)) {
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
> + "Not FCP target so not offloading\n");
> + break;
> + }
> +
> + spin_lock(&qedf->hba_lock);
> + rval = qedf_alloc_conn_id(qedf, fcport);
> + spin_unlock(&qedf->hba_lock);
> +
> + if (rval) {
> + QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate "
> + "conn_id for port %06x.\n",
> + rdata->ids.port_id);
> + break;
> + }
> +
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
> + "Assigned conn_id=%u to port_id=%06x.\n",
> + fcport->conn_id, rdata->ids.port_id);
> +
> + fcport->rdata = rdata;
> + fcport->rport = rport;
> +
> + rval = qedf_alloc_sq(qedf, fcport);
> + if (rval) {
> + qedf_cleanup_fcport(qedf, fcport);
> + break;
> + }
> +
> + /* Set device type */
> + if (rdata->flags & FC_RP_FLAGS_RETRY &&
> + rdata->ids.roles & FC_RPORT_ROLE_FCP_TARGET &&
> + !(rdata->ids.roles & FC_RPORT_ROLE_FCP_INITIATOR)) {
> + fcport->dev_type = QEDF_RPORT_TYPE_TAPE;
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
> + "portid=%06x is a TAPE device.\n",
> + rdata->ids.port_id);
> + } else {
> + fcport->dev_type = QEDF_RPORT_TYPE_DISK;
> + }
> +
> + rval = qedf_offload_connection(qedf, fcport);
> + if (rval) {
> + qedf_cleanup_fcport(qedf, fcport);
> + break;
> + }
> +
> + /*
> + * Set the session ready bit to let everyone know that this
> + * connection is ready for I/O
> + */
> + set_bit(QEDF_RPORT_SESSION_READY, &fcport->flags);
> + atomic_inc(&qedf->num_offloads);
> +
> + break;
> + case RPORT_EV_LOGO:
> + case RPORT_EV_FAILED:
> + case RPORT_EV_STOP:
> + port_id = rdata->ids.port_id;
> + if (port_id == FC_FID_DIR_SERV)
> + break;
> +
> + if (!rport) {
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_DISC,
> + "port_id=%x - rport notcreated Yet!!\n", port_id);
> + break;
> + }
> + rp = rport->dd_data;
> + /*
> + * Perform session upload. Note that rdata->peers is already
> + * removed from disc->rports list before we get this event.
> + */
> + fcport = (struct qedf_rport *)&rp[1];
> +
> + /*
> + * Only free the conn_id if this fcport was initialized with
> + * one.
> + */
> + if (fcport->conn_id > -1) {
> + set_bit(QEDF_RPORT_UPLOADING_CONNECTION, &fcport->flags);
> + qedf_cleanup_fcport(qedf, fcport);
> + clear_bit(QEDF_RPORT_UPLOADING_CONNECTION,
> + &fcport->flags);
> + atomic_dec(&qedf->num_offloads);
> + }
> +
> + break;
> +
> + case RPORT_EV_NONE:
> + break;
> + }
> +}
> +
> +static void qedf_abort_io(struct fc_lport *lport)
> +{
> + /* NO-OP but need to fill in the template */
> +}
> +
> +static void qedf_fcp_cleanup(struct fc_lport *lport)
> +{
> + /*
> + * NO-OP but need to fill in template to prevent a NULL
> + * function pointer dereference during link down. I/Os
> + * will be flushed when port is uploaded.
> + */
> +}
> +
> +static struct libfc_function_template qedf_lport_template = {
> + .frame_send = qedf_xmit,
> + .fcp_abort_io = qedf_abort_io,
> + .fcp_cleanup = qedf_fcp_cleanup,
> + .rport_event_callback = qedf_rport_event_handler,
> + .elsct_send = qedf_elsct_send,
> +};
> +
> +static void qedf_fcoe_ctlr_setup(struct qedf_ctx *qedf)
> +{
> + fcoe_ctlr_init(&qedf->ctlr, FIP_ST_AUTO);
> +
> + qedf->ctlr.send = qedf_fip_send;
> + qedf->ctlr.update_mac = qedf_update_src_mac;
> + qedf->ctlr.get_src_addr = qedf_get_src_mac;
> + ether_addr_copy(qedf->ctlr.ctl_src_addr, qedf->mac);
> +}
> +
> +static int qedf_lport_setup(struct qedf_ctx *qedf)
> +{
> + struct fc_lport *lport = qedf->lport;
> +
> + lport->link_up = 0;
> + lport->max_retry_count = QEDF_FLOGI_RETRY_CNT;
> + lport->max_rport_retry_count = QEDF_RPORT_RETRY_CNT;
> + lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
> + FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
> + lport->boot_time = jiffies;
> + lport->e_d_tov = 2 * 1000;
> + lport->r_a_tov = 10 * 1000;
> +
> + /* Set NPIV support */
> + lport->does_npiv = 1;
> + fc_host_max_npiv_vports(lport->host) = QEDF_MAX_NPIV;
> +
> + fc_set_wwnn(lport, qedf->wwnn);
> + fc_set_wwpn(lport, qedf->wwpn);
> +
> + fcoe_libfc_config(lport, &qedf->ctlr, &qedf_lport_template, 0);
> +
> + /* Allocate the exchange manager */
> + fc_exch_mgr_alloc(lport, FC_CLASS_3, qedf->max_scsi_xid + 1,
> + qedf->max_els_xid, NULL);
> +
> + if (fc_lport_init_stats(lport))
> + return -ENOMEM;
> +
> + /* Finish lport config */
> + fc_lport_config(lport);
> +
> + /* Set max frame size */
> + fc_set_mfs(lport, QEDF_MFS);
> + fc_host_maxframe_size(lport->host) = lport->mfs;
> +
> + /* Set default dev_loss_tmo based on module parameter */
> + fc_host_dev_loss_tmo(lport->host) = qedf_dev_loss_tmo;
> +
> + /* Set symbolic node name */
> + snprintf(fc_host_symbolic_name(lport->host), 256,
> + "QLogic %s v%s", QEDF_MODULE_NAME, QEDF_VERSION);
> +
> + return 0;
> +}
> +
> +/*
> + * NPIV functions
> + */
> +
> +static int qedf_vport_libfc_config(struct fc_vport *vport,
> + struct fc_lport *lport)
> +{
> + lport->link_up = 0;
> + lport->qfull = 0;
> + lport->max_retry_count = QEDF_FLOGI_RETRY_CNT;
> + lport->max_rport_retry_count = QEDF_RPORT_RETRY_CNT;
> + lport->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS |
> + FCP_SPPF_RETRY | FCP_SPPF_CONF_COMPL);
> + lport->boot_time = jiffies;
> + lport->e_d_tov = 2 * 1000;
> + lport->r_a_tov = 10 * 1000;
> + lport->does_npiv = 1; /* Temporary until we add NPIV support */
> +
> + /* Allocate stats for vport */
> + if (fc_lport_init_stats(lport))
> + return -ENOMEM;
> +
> + /* Finish lport config */
> + fc_lport_config(lport);
> +
> + /* offload related configuration */
> + lport->crc_offload = 0;
> + lport->seq_offload = 0;
> + lport->lro_enabled = 0;
> + lport->lro_xid = 0;
> + lport->lso_max = 0;
> +
> + return 0;
> +}
> +
> +static int qedf_vport_create(struct fc_vport *vport, bool disabled)
> +{
> + struct Scsi_Host *shost = vport_to_shost(vport);
> + struct fc_lport *n_port = shost_priv(shost);
> + struct fc_lport *vn_port;
> + struct qedf_ctx *base_qedf = lport_priv(n_port);
> + struct qedf_ctx *vport_qedf;
> + int i;
> +
> + char buf[32];
> + int rc = 0;
> +
> + rc = fcoe_validate_vport_create(vport);
> + if (rc) {
> + fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf));
> + QEDF_WARN(&(base_qedf->dbg_ctx), "Failed to create vport, "
> + "WWPN (0x%s) already exists.\n", buf);
> + goto err1;
> + }
> +
> + if (atomic_read(&base_qedf->link_state) != QEDF_LINK_UP) {
> + QEDF_WARN(&(base_qedf->dbg_ctx), "Cannot create vport "
> + "because link is not up.\n");
> + rc = -EIO;
> + goto err1;
> + }
> +
> + vn_port = libfc_vport_create(vport, sizeof(struct qedf_ctx));
> + if (!vn_port) {
> + QEDF_WARN(&(base_qedf->dbg_ctx), "Could not create lport "
> + "for vport.\n");
> + rc = -ENOMEM;
> + goto err1;
> + }
> +
> + fcoe_wwn_to_str(vport->port_name, buf, sizeof(buf));
> + QEDF_ERR(&(base_qedf->dbg_ctx), "Creating NPIV port, WWPN=%s.\n",
> + buf);
> +
> + /* Copy some fields from base_qedf */
> + vport_qedf = lport_priv(vn_port);
> + memcpy(vport_qedf, base_qedf, sizeof(struct qedf_ctx));
> +
> + /* Set qedf data specific to this vport */
> + vport_qedf->lport = vn_port;
> + /* Use same hba_lock as base_qedf */
> + vport_qedf->hba_lock = base_qedf->hba_lock;
> + /* Purge any fcport info from base_qedf */
> + for (i = 0; i < QEDF_MAX_SESSIONS; i++)
> + vport_qedf->fcports[i] = NULL;
> + vport_qedf->pdev = base_qedf->pdev;
> + vport_qedf->cmd_mgr = base_qedf->cmd_mgr;
> + init_completion(&vport_qedf->flogi_compl);
> +
> + rc = qedf_vport_libfc_config(vport, vn_port);
> + if (rc) {
> + QEDF_ERR(&(base_qedf->dbg_ctx), "Could not allocate memory "
> + "for lport stats.\n");
> + goto err2;
> + }
> +
> + fc_set_wwnn(vn_port, vport->node_name);
> + fc_set_wwpn(vn_port, vport->port_name);
> + vport_qedf->wwnn = vn_port->wwnn;
> + vport_qedf->wwpn = vn_port->wwpn;
> +
> + vn_port->host->transportt = qedf_fc_vport_transport_template;
> + vn_port->host->can_queue = QEDF_MAX_ELS_XID;
> + vn_port->host->max_lun = qedf_max_lun;
> + vn_port->host->sg_tablesize = QEDF_MAX_BDS_PER_CMD;
> + vn_port->host->max_cmd_len = QEDF_MAX_CDB_LEN;
> +
> + rc = scsi_add_host(vn_port->host, &vport->dev);
> + if (rc) {
> + QEDF_WARN(&(base_qedf->dbg_ctx), "Error adding Scsi_Host.\n");
> + goto err2;
> + }
> +
> + /* Set default dev_loss_tmo based on module parameter */
> + fc_host_dev_loss_tmo(vn_port->host) = qedf_dev_loss_tmo;
> +
> + /* Init libfc stuffs */
> + memcpy(&vn_port->tt, &qedf_lport_template,
> + sizeof(qedf_lport_template));
> + fc_exch_init(vn_port);
> + fc_elsct_init(vn_port);
> + fc_lport_init(vn_port);
> + fc_disc_init(vn_port);
> + fc_disc_config(vn_port, vn_port);
> +
> +
> + /* Allocate the exchange manager */
> + shost = vport_to_shost(vport);
> + n_port = shost_priv(shost);
> + fc_exch_mgr_list_clone(n_port, vn_port);
> +
> + /* Set max frame size */
> + fc_set_mfs(vn_port, QEDF_MFS);
> +
> + fc_host_port_type(vn_port->host) = FC_PORTTYPE_UNKNOWN;
> +
> + if (disabled) {
> + fc_vport_set_state(vport, FC_VPORT_DISABLED);
> + } else {
> + vn_port->boot_time = jiffies;
> + fc_fabric_login(vn_port);
> + fc_vport_setlink(vn_port);
> + }
> +
> + QEDF_INFO(&(base_qedf->dbg_ctx), QEDF_LOG_NPIV, "vn_port=%p.\n",
> + vn_port);
> +
> + /* Set up debug context for vport */
> + vport_qedf->dbg_ctx.host_no = vn_port->host->host_no;
> + vport_qedf->dbg_ctx.pdev = base_qedf->pdev;
> +
> +err2:
> + scsi_host_put(vn_port->host);
> +err1:
> + return rc;
> +}
> +
> +static int qedf_vport_destroy(struct fc_vport *vport)
> +{
> + struct Scsi_Host *shost = vport_to_shost(vport);
> + struct fc_lport *n_port = shost_priv(shost);
> + struct fc_lport *vn_port = vport->dd_data;
> +
> + mutex_lock(&n_port->lp_mutex);
> + list_del(&vn_port->list);
> + mutex_unlock(&n_port->lp_mutex);
> +
> + fc_fabric_logoff(vn_port);
> + fc_lport_destroy(vn_port);
> +
> + /* Detach from scsi-ml */
> + fc_remove_host(vn_port->host);
> + scsi_remove_host(vn_port->host);
> +
> + /*
> + * Only try to release the exchange manager if the vn_port
> + * configuration is complete.
> + */
> + if (vn_port->state == LPORT_ST_READY)
> + fc_exch_mgr_free(vn_port);
> +
> + /* Free memory used by statistical counters */
> + fc_lport_free_stats(vn_port);
> +
> + /* Release Scsi_Host */
> + if (vn_port->host)
> + scsi_host_put(vn_port->host);
> +
> + return 0;
> +}
> +
> +static int qedf_vport_disable(struct fc_vport *vport, bool disable)
> +{
> + struct fc_lport *lport = vport->dd_data;
> +
> + if (disable) {
> + fc_vport_set_state(vport, FC_VPORT_DISABLED);
> + fc_fabric_logoff(lport);
> + } else {
> + lport->boot_time = jiffies;
> + fc_fabric_login(lport);
> + fc_vport_setlink(lport);
> + }
> + return 0;
> +}
> +
> +/*
> + * During removal we need to wait for all the vports associated with a port
> + * to be destroyed so we avoid a race condition where libfc is still trying
> + * to reap vports while the driver remove function has already reaped the
> + * driver contexts associated with the physical port.
> + */
> +static void qedf_wait_for_vport_destroy(struct qedf_ctx *qedf)
> +{
> + struct fc_host_attrs *fc_host = shost_to_fc_host(qedf->lport->host);
> +
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_NPIV,
> + "Entered.\n");
> + while (fc_host->npiv_vports_inuse > 0) {
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_NPIV,
> + "Waiting for all vports to be reaped.\n");
> + msleep(1000);
> + }
> +}
> +
> +/**
> + * qedf_fcoe_reset - Resets the fcoe
> + *
> + * @shost: shost the reset is from
> + *
> + * Returns: always 0
> + */
> +static int qedf_fcoe_reset(struct Scsi_Host *shost)
> +{
> + struct fc_lport *lport = shost_priv(shost);
> +
> + fc_fabric_logoff(lport);
> + fc_fabric_login(lport);
> + return 0;
> +}
> +
> +static struct fc_host_statistics *qedf_fc_get_host_stats(struct Scsi_Host
> + *shost)
> +{
> + struct fc_host_statistics *qedf_stats;
> + struct fc_lport *lport = shost_priv(shost);
> + struct qedf_ctx *qedf = lport_priv(lport);
> + struct qed_fcoe_stats *fw_fcoe_stats;
> +
> + qedf_stats = fc_get_host_stats(shost);
> +
> + /* We don't collect offload stats for specific NPIV ports */
> + if (lport->vport)
> + goto out;
> +
> + fw_fcoe_stats = kmalloc(sizeof(struct qed_fcoe_stats), GFP_KERNEL);
> + if (!fw_fcoe_stats) {
> + QEDF_ERR(&(qedf->dbg_ctx), "Could not allocate memory for "
> + "fw_fcoe_stats.\n");
> + goto out;
> + }
> +
> + /* Query firmware for offload stats */
> + qed_ops->get_stats(qedf->cdev, fw_fcoe_stats);
> +
> + /*
> + * The expectation is that we add our offload stats to the stats
> + * being maintained by libfc each time the fc_get_host_status callback
> + * is invoked. The additions are not carried over for each call to
> + * the fc_get_host_stats callback.
> + */
> + qedf_stats->tx_frames += fw_fcoe_stats->fcoe_tx_data_pkt_cnt +
> + fw_fcoe_stats->fcoe_tx_xfer_pkt_cnt +
> + fw_fcoe_stats->fcoe_tx_other_pkt_cnt;
> + qedf_stats->rx_frames += fw_fcoe_stats->fcoe_rx_data_pkt_cnt +
> + fw_fcoe_stats->fcoe_rx_xfer_pkt_cnt +
> + fw_fcoe_stats->fcoe_rx_other_pkt_cnt;
> + qedf_stats->fcp_input_megabytes += fw_fcoe_stats->fcoe_rx_byte_cnt /
> + 1000000;
> + qedf_stats->fcp_output_megabytes += fw_fcoe_stats->fcoe_tx_byte_cnt /
> + 1000000;
> + qedf_stats->rx_words += fw_fcoe_stats->fcoe_rx_byte_cnt / 4;
> + qedf_stats->tx_words += fw_fcoe_stats->fcoe_tx_byte_cnt / 4;
> + qedf_stats->invalid_crc_count +=
> + fw_fcoe_stats->fcoe_silent_drop_pkt_crc_error_cnt;
> + qedf_stats->dumped_frames =
> + fw_fcoe_stats->fcoe_silent_drop_total_pkt_cnt;
> + qedf_stats->error_frames +=
> + fw_fcoe_stats->fcoe_silent_drop_total_pkt_cnt;
> + qedf_stats->fcp_input_requests += qedf->input_requests;
> + qedf_stats->fcp_output_requests += qedf->output_requests;
> + qedf_stats->fcp_control_requests += qedf->control_requests;
> + qedf_stats->fcp_packet_aborts += qedf->packet_aborts;
> + qedf_stats->fcp_frame_alloc_failures += qedf->alloc_failures;
> +
> + kfree(fw_fcoe_stats);
> +out:
> + return qedf_stats;
> +}
> +
> +static struct fc_function_template qedf_fc_transport_fn = {
> + .show_host_node_name = 1,
> + .show_host_port_name = 1,
> + .show_host_supported_classes = 1,
> + .show_host_supported_fc4s = 1,
> + .show_host_active_fc4s = 1,
> + .show_host_maxframe_size = 1,
> +
> + .show_host_port_id = 1,
> + .show_host_supported_speeds = 1,
> + .get_host_speed = fc_get_host_speed,
> + .show_host_speed = 1,
> + .show_host_port_type = 1,
> + .get_host_port_state = fc_get_host_port_state,
> + .show_host_port_state = 1,
> + .show_host_symbolic_name = 1,
> +
> + /*
> + * Tell FC transport to allocate enough space to store the backpointer
> + * for the associate qedf_rport struct.
> + */
> + .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) +
> + sizeof(struct qedf_rport)),
> + .show_rport_maxframe_size = 1,
> + .show_rport_supported_classes = 1,
> + .show_host_fabric_name = 1,
> + .show_starget_node_name = 1,
> + .show_starget_port_name = 1,
> + .show_starget_port_id = 1,
> + .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo,
> + .show_rport_dev_loss_tmo = 1,
> + .get_fc_host_stats = qedf_fc_get_host_stats,
> + .issue_fc_host_lip = qedf_fcoe_reset,
> + .vport_create = qedf_vport_create,
> + .vport_delete = qedf_vport_destroy,
> + .vport_disable = qedf_vport_disable,
> + .bsg_request = fc_lport_bsg_request,
> +};
> +
> +static struct fc_function_template qedf_fc_vport_transport_fn = {
> + .show_host_node_name = 1,
> + .show_host_port_name = 1,
> + .show_host_supported_classes = 1,
> + .show_host_supported_fc4s = 1,
> + .show_host_active_fc4s = 1,
> + .show_host_maxframe_size = 1,
> + .show_host_port_id = 1,
> + .show_host_supported_speeds = 1,
> + .get_host_speed = fc_get_host_speed,
> + .show_host_speed = 1,
> + .show_host_port_type = 1,
> + .get_host_port_state = fc_get_host_port_state,
> + .show_host_port_state = 1,
> + .show_host_symbolic_name = 1,
> + .dd_fcrport_size = (sizeof(struct fc_rport_libfc_priv) +
> + sizeof(struct qedf_rport)),
> + .show_rport_maxframe_size = 1,
> + .show_rport_supported_classes = 1,
> + .show_host_fabric_name = 1,
> + .show_starget_node_name = 1,
> + .show_starget_port_name = 1,
> + .show_starget_port_id = 1,
> + .set_rport_dev_loss_tmo = fc_set_rport_loss_tmo,
> + .show_rport_dev_loss_tmo = 1,
> + .get_fc_host_stats = fc_get_host_stats,
> + .issue_fc_host_lip = qedf_fcoe_reset,
> + .bsg_request = fc_lport_bsg_request,
> +};
> +
> +static bool qedf_fp_has_work(struct qedf_fastpath *fp)
> +{
> + struct qedf_ctx *qedf = fp->qedf;
> + struct global_queue *que;
> + struct qed_sb_info *sb_info = fp->sb_info;
> + struct status_block *sb = sb_info->sb_virt;
> + u16 prod_idx;
> +
> + /* Get the pointer to the global CQ this completion is on */
> + que = qedf->global_queues[fp->sb_id];
> +
> + rmb();
> +
> + /* Get the current firmware producer index */
> + prod_idx = sb->pi_array[QEDF_FCOE_PARAMS_GL_RQ_PI];
> +
> + return (que->cq_prod_idx != prod_idx);
> +}
> +
> +/*
> + * Interrupt handler code.
> + */
> +
> +/* Process completion queue and copy CQE contents for deferred processesing
> + *
> + * Return true if we should wake the I/O thread, false if not.
> + */
> +static bool qedf_process_completions(struct qedf_fastpath *fp)
> +{
> + struct qedf_ctx *qedf = fp->qedf;
> + struct qed_sb_info *sb_info = fp->sb_info;
> + struct status_block *sb = sb_info->sb_virt;
> + struct global_queue *que;
> + u16 prod_idx;
> + struct fcoe_cqe *cqe;
> + struct qedf_io_work *work;
> + unsigned long flags;
> + int num_handled = 0;
> + unsigned int cpu;
> + struct qedf_ioreq *io_req = NULL;
> + struct qedf_percpu_iothread_s *iothread;
> + u16 xid;
> + u16 new_cqes;
> + u32 comp_type;
> +
> + /* Get the current firmware producer index */
> + prod_idx = sb->pi_array[QEDF_FCOE_PARAMS_GL_RQ_PI];
> +
> + /* Get the pointer to the global CQ this completion is on */
> + que = qedf->global_queues[fp->sb_id];
> +
> + /* Calculate the amount of new elements since last processing */
> + new_cqes = (prod_idx >= que->cq_prod_idx) ?
> + (prod_idx - que->cq_prod_idx) :
> + 0x10000 - que->cq_prod_idx + prod_idx;
> +
> + /* Save producer index */
> + que->cq_prod_idx = prod_idx;
> +
> + while (new_cqes) {
> + fp->completions++;
> + num_handled++;
> + cqe = &que->cq[que->cq_cons_idx];
> +
> + comp_type = (cqe->cqe_data >> FCOE_CQE_CQE_TYPE_SHIFT) &
> + FCOE_CQE_CQE_TYPE_MASK;
> +
> + /*
> + * Process unsolicited CQEs directly in the interrupt handler
> + * sine we need the fastpath ID
> + */
> + if (comp_type == FCOE_UNSOLIC_CQE_TYPE) {
> + QEDF_INFO(&(qedf->dbg_ctx), QEDF_LOG_UNSOL,
> + "Unsolicated CQE.\n");
> + qedf_process_unsol_compl(qedf, fp->sb_id, cqe);
> + /*
> + * Don't add a work list item. Increment consumer
> + * consumer index and move on.
> + */
> + goto inc_idx;
> + }
> +
> + xid = cqe->cqe_data & FCOE_CQE_TASK_ID_MASK;
> + io_req = &qedf->cmd_mgr->cmds[xid];
> +
> + /*
> + * Figure out which percpu thread we should queue this I/O
> + * on.
> + */
> + if (!io_req)
> + /* If there is not io_req assocated with this CQE
> + * just queue it on CPU 0
> + */
> + cpu = 0;
> + else {
> + cpu = io_req->cpu;
> + io_req->int_cpu = smp_processor_id();
> + }
> +
> + work = mempool_alloc(qedf->io_mempool, GFP_ATOMIC);
> + if (!work) {
> + QEDF_WARN(&(qedf->dbg_ctx), "Could not allocate "
> + "work for I/O completion.\n");
> + continue;
> + }
> + memset(work, 0, sizeof(struct qedf_io_work));
> +
> + INIT_LIST_HEAD(&work->list);
> +
> + /* Copy contents of CQE for deferred processing */
> + memcpy(&work->cqe, cqe, sizeof(struct fcoe_cqe));
> +
> + work->qedf = fp->qedf;
> + work->fp = NULL; /* Only used for unsolicited frames */
> +
> + iothread = &per_cpu(qedf_percpu_iothreads, cpu);
> + spin_lock_irqsave(&iothread->work_lock, flags);
> + list_add_tail(&work->list, &iothread->work_list);
> + spin_unlock_irqrestore(&iothread->work_lock, flags);
> + wake_up_process(iothread->iothread);
> +
> +inc_idx:
> + que->cq_cons_idx++;
> + if (que->cq_cons_idx == fp->cq_num_entries)
> + que->cq_cons_idx = 0;
> + new_cqes--;
> + }
> +
> + return true;
> +}
> +
> +
> +/* MSI-X fastpath handler code */
> +static irqreturn_t qedf_msix_handler(int irq, void *dev_id)
> +{
> + struct qedf_fastpath *fp = dev_id;
> +
> + if (!fp) {
> + QEDF_ERR(NULL, "fp is null.\n");
> + return IRQ_HANDLED;
> + }
> + if (!fp->sb_info) {
> + QEDF_ERR(NULL, "fp->sb_info in null.");
> + return IRQ_HANDLED;
> + }
> +
> + /*
> + * Disable interrupts for this status block while we process new
> + * completions
> + */
> + qed_sb_ack(fp->sb_info, IGU_INT_DISABLE, 0 /*do not update*/);
> +
> + while (1) {
> + qedf_process_completions(fp);
> +
> + if (qedf_fp_has_work(fp) == 0) {
> + /* Update the sb information */
> + qed_sb_update_sb_idx(fp->sb_info);
> + rmb();
> +
> + if (qedf_fp_has_work(fp) == 0) {
> + /* Re-enable interrupts */
> + qed_sb_ack(fp->sb_info, IGU_INT_ENABLE, 1);
> + return IRQ_HANDLED;
> + }
> + }
> + }
> +
> + /* Do we ever want to break out of above loop? */
> + return IRQ_HANDLED;
> +}
> +
> +/* simd handler for MSI/INTa */
> +static void qedf_simd_int_handler(void *cookie)
> +{
> + /* Cookie is qedf_ctx struct */
> + struct qedf_ctx *qedf = (struct qedf_ctx *)cookie;
> +
> + QEDF_WARN(&(qedf->dbg_ctx), "qedf=%p.\n", qedf);
> +}
> +
> +#define QEDF_SIMD_HANDLER_NUM 0
> +static void qedf_sync_free_irqs(struct qedf_ctx *qedf)
> +{
> + int i;
> +
> + if (qedf->int_info.msix_cnt) {
> + for (i = 0; i < qedf->int_info.used_cnt; i++) {
> + synchronize_irq(qedf->int_info.msix[i].vector);
> + irq_set_affinity_hint(qedf->int_info.msix[i].vector,
> + NULL);
> + irq_set_affinity_notifier(qedf->int_info.msix[i].vector,
> + NULL);
> + free_irq(qedf->int_info.msix[i].vector,
> + &qedf->fp_array[i]);
> + }
> + } else
> + qed_ops->common->simd_handler_clean(qedf->cdev,
> + QEDF_SIMD_HANDLER_NUM);
> +
> + qedf->int_info.used_cnt = 0;
> + qed_ops->common->set_fp_int(qedf->cdev, 0);
> +}
> +
> +static int qedf_request_msix_irq(struct qedf_ctx *qedf)
> +{
> + int i, rc, cpu;
> +
> + cpu = cpumask_first(cpu_online_mask);
> + for (i = 0; i < qedf->num_queues; i++) {
> + rc = request_irq(qedf->int_info.msix[i].vector,
> + qedf_msix_handler, 0, "qedf", &qedf->fp_array[i]);
> +
> + if (rc) {
> + QEDF_WARN(&(qedf->dbg_ctx), "request_irq failed.\n");
> + qedf_sync_free_irqs(qedf);
> + return rc;
> + }
> +
> + qedf->int_info.used_cnt++;
> + rc = irq_set_affinity_hint(qedf->int_info.msix[i].vector,
> + get_cpu_mask(cpu));
> + cpu = cpumask_next(cpu, cpu_online_mask);
> + }
> +
> + return 0;
> +}
> +
Please use the irq allocation routines from hch here.
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare@suse.de +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
^ permalink raw reply
* [PATCH net-next RESEND 1/1] driver: ipvlan: Remove unnecessary ipvlan NULL check in ipvlan_count_rx
From: fgao @ 2016-12-28 8:47 UTC (permalink / raw)
To: davem, maheshb, edumazet, netdev, gfree.wind; +Cc: Gao Feng
From: Gao Feng <fgao@ikuai8.com>
There are three functions which would invoke the ipvlan_count_rx. They
are ipvlan_process_multicast, ipvlan_rcv_frame, and ipvlan_nf_input.
The former two functions already use the ipvlan directly before
ipvlan_count_rx, and ipvlan_nf_input gets the ipvlan from
ipvl_addr->master, it is not possible to be NULL too.
So the ipvlan pointer check is unnecessary in ipvlan_count_rx.
Signed-off-by: Gao Feng <fgao@ikuai8.com>
---
It is sent again because the last email is sent during net-next closed
drivers/net/ipvlan/ipvlan_core.c | 3 ---
1 file changed, 3 deletions(-)
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index b4e9907..082f9f1 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -19,9 +19,6 @@ void ipvlan_init_secret(void)
static void ipvlan_count_rx(const struct ipvl_dev *ipvlan,
unsigned int len, bool success, bool mcast)
{
- if (!ipvlan)
- return;
-
if (likely(success)) {
struct ipvl_pcpu_stats *pcptr;
--
1.9.1
^ permalink raw reply related
* [PATCH net-next RESEND 1/1] driver: ipvlan: Define common functions to decrease duplicated codes used to add or del IP address
From: fgao @ 2016-12-28 8:46 UTC (permalink / raw)
To: davem, maheshb, edumazet, netdev, gfree.wind; +Cc: Gao Feng
From: Gao Feng <fgao@ikuai8.com>
There are some duplicated codes in ipvlan_add_addr6/4 and
ipvlan_del_addr6/4. Now define two common functions ipvlan_add_addr
and ipvlan_del_addr to decrease the duplicated codes.
It could be helful to maintain the codes.
Signed-off-by: Gao Feng <fgao@ikuai8.com>
---
It is sent again because the first email is sent during net-next closing.
drivers/net/ipvlan/ipvlan_main.c | 68 +++++++++++++++++-----------------------
1 file changed, 29 insertions(+), 39 deletions(-)
diff --git a/drivers/net/ipvlan/ipvlan_main.c b/drivers/net/ipvlan/ipvlan_main.c
index 693ec5b..5874d30 100644
--- a/drivers/net/ipvlan/ipvlan_main.c
+++ b/drivers/net/ipvlan/ipvlan_main.c
@@ -669,23 +669,22 @@ static int ipvlan_device_event(struct notifier_block *unused,
return NOTIFY_DONE;
}
-static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
+static int ipvlan_add_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
{
struct ipvl_addr *addr;
- if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) {
- netif_err(ipvlan, ifup, ipvlan->dev,
- "Failed to add IPv6=%pI6c addr for %s intf\n",
- ip6_addr, ipvlan->dev->name);
- return -EINVAL;
- }
addr = kzalloc(sizeof(struct ipvl_addr), GFP_ATOMIC);
if (!addr)
return -ENOMEM;
addr->master = ipvlan;
- memcpy(&addr->ip6addr, ip6_addr, sizeof(struct in6_addr));
- addr->atype = IPVL_IPV6;
+ if (is_v6) {
+ memcpy(&addr->ip6addr, iaddr, sizeof(struct in6_addr));
+ addr->atype = IPVL_IPV6;
+ } else {
+ memcpy(&addr->ip4addr, iaddr, sizeof(struct in_addr));
+ addr->atype = IPVL_IPV4;
+ }
list_add_tail(&addr->anode, &ipvlan->addrs);
/* If the interface is not up, the address will be added to the hash
@@ -697,11 +696,11 @@ static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
return 0;
}
-static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
+static void ipvlan_del_addr(struct ipvl_dev *ipvlan, void *iaddr, bool is_v6)
{
struct ipvl_addr *addr;
- addr = ipvlan_find_addr(ipvlan, ip6_addr, true);
+ addr = ipvlan_find_addr(ipvlan, iaddr, is_v6);
if (!addr)
return;
@@ -712,6 +711,23 @@ static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
return;
}
+static int ipvlan_add_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
+{
+ if (ipvlan_addr_busy(ipvlan->port, ip6_addr, true)) {
+ netif_err(ipvlan, ifup, ipvlan->dev,
+ "Failed to add IPv6=%pI6c addr for %s intf\n",
+ ip6_addr, ipvlan->dev->name);
+ return -EINVAL;
+ }
+
+ return ipvlan_add_addr(ipvlan, ip6_addr, true);
+}
+
+static void ipvlan_del_addr6(struct ipvl_dev *ipvlan, struct in6_addr *ip6_addr)
+{
+ return ipvlan_del_addr(ipvlan, ip6_addr, true);
+}
+
static int ipvlan_addr6_event(struct notifier_block *unused,
unsigned long event, void *ptr)
{
@@ -745,45 +761,19 @@ static int ipvlan_addr6_event(struct notifier_block *unused,
static int ipvlan_add_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
{
- struct ipvl_addr *addr;
-
if (ipvlan_addr_busy(ipvlan->port, ip4_addr, false)) {
netif_err(ipvlan, ifup, ipvlan->dev,
"Failed to add IPv4=%pI4 on %s intf.\n",
ip4_addr, ipvlan->dev->name);
return -EINVAL;
}
- addr = kzalloc(sizeof(struct ipvl_addr), GFP_KERNEL);
- if (!addr)
- return -ENOMEM;
-
- addr->master = ipvlan;
- memcpy(&addr->ip4addr, ip4_addr, sizeof(struct in_addr));
- addr->atype = IPVL_IPV4;
- list_add_tail(&addr->anode, &ipvlan->addrs);
-
- /* If the interface is not up, the address will be added to the hash
- * list by ipvlan_open.
- */
- if (netif_running(ipvlan->dev))
- ipvlan_ht_addr_add(ipvlan, addr);
- return 0;
+ return ipvlan_add_addr(ipvlan, ip4_addr, false);
}
static void ipvlan_del_addr4(struct ipvl_dev *ipvlan, struct in_addr *ip4_addr)
{
- struct ipvl_addr *addr;
-
- addr = ipvlan_find_addr(ipvlan, ip4_addr, false);
- if (!addr)
- return;
-
- ipvlan_ht_addr_del(addr);
- list_del(&addr->anode);
- kfree_rcu(addr, rcu);
-
- return;
+ return ipvlan_del_addr(ipvlan, ip4_addr, false);
}
static int ipvlan_addr4_event(struct notifier_block *unused,
--
1.9.1
^ permalink raw reply related
* Re: [PATCH RFC net-next 1/5] qed: Add support for hardware offloaded FCoE.
From: Hannes Reinecke @ 2016-12-28 8:41 UTC (permalink / raw)
To: Dupuis, Chad, martin.petersen-QHcLZuEGTsvQT0dZR+AlfA
Cc: fcoe-devel-s9riP+hp16TNLxjTenLetw, netdev-u79uwXL29TY76Z2rM5mHXA,
yuval.mintz-YGCgFSpz5w/QT0dZR+AlfA,
linux-scsi-u79uwXL29TY76Z2rM5mHXA,
QLogic-Storage-Upstream-YGCgFSpz5w/QT0dZR+AlfA
In-Reply-To: <1482520628-24207-2-git-send-email-chad.dupuis-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
On 12/23/2016 08:17 PM, Dupuis, Chad wrote:
> From: Arun Easi <arun.easi-h88ZbnxC6KDQT0dZR+AlfA@public.gmane.org>
>
> This adds the backbone required for the various HW initalizations
> which are necessary for the FCoE driver (qedf) for QLogic FastLinQ
> 4xxxx line of adapters - FW notification, resource initializations, etc.
>
> Signed-off-by: Arun Easi <arun.easi-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> Signed-off-by: Yuval Mintz <yuval.mintz-YGCgFSpz5w/QT0dZR+AlfA@public.gmane.org>
> ---
> drivers/net/ethernet/qlogic/Kconfig | 3 +
> drivers/net/ethernet/qlogic/qed/Makefile | 1 +
> drivers/net/ethernet/qlogic/qed/qed.h | 11 +
> drivers/net/ethernet/qlogic/qed/qed_cxt.c | 98 ++-
> drivers/net/ethernet/qlogic/qed/qed_cxt.h | 3 +
> drivers/net/ethernet/qlogic/qed/qed_dcbx.c | 11 +
> drivers/net/ethernet/qlogic/qed/qed_dcbx.h | 1 +
> drivers/net/ethernet/qlogic/qed/qed_dev.c | 205 ++++-
> drivers/net/ethernet/qlogic/qed/qed_dev_api.h | 42 +
> drivers/net/ethernet/qlogic/qed/qed_fcoe.c | 990 ++++++++++++++++++++++
> drivers/net/ethernet/qlogic/qed/qed_fcoe.h | 52 ++
> drivers/net/ethernet/qlogic/qed/qed_hsi.h | 781 ++++++++++++++++-
> drivers/net/ethernet/qlogic/qed/qed_hw.c | 3 +
> drivers/net/ethernet/qlogic/qed/qed_ll2.c | 25 +
> drivers/net/ethernet/qlogic/qed/qed_ll2.h | 2 +-
> drivers/net/ethernet/qlogic/qed/qed_main.c | 7 +
> drivers/net/ethernet/qlogic/qed/qed_mcp.c | 3 +
> drivers/net/ethernet/qlogic/qed/qed_mcp.h | 1 +
> drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 8 +
> drivers/net/ethernet/qlogic/qed/qed_sp.h | 4 +
> drivers/net/ethernet/qlogic/qed/qed_sp_commands.c | 3 +
> include/linux/qed/common_hsi.h | 10 +-
> include/linux/qed/fcoe_common.h | 715 ++++++++++++++++
> include/linux/qed/qed_fcoe_if.h | 145 ++++
> include/linux/qed/qed_if.h | 39 +
> 25 files changed, 3152 insertions(+), 11 deletions(-)
> create mode 100644 drivers/net/ethernet/qlogic/qed/qed_fcoe.c
> create mode 100644 drivers/net/ethernet/qlogic/qed/qed_fcoe.h
> create mode 100644 include/linux/qed/fcoe_common.h
> create mode 100644 include/linux/qed/qed_fcoe_if.h
>
> diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
> index 3cfd105..737b303 100644
> --- a/drivers/net/ethernet/qlogic/Kconfig
> +++ b/drivers/net/ethernet/qlogic/Kconfig
> @@ -113,4 +113,7 @@ config QED_RDMA
> config QED_ISCSI
> bool
>
> +config QED_FCOE
> + bool
> +
> endif # NET_VENDOR_QLOGIC
> diff --git a/drivers/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile
> index 729e437..e234083 100644
> --- a/drivers/net/ethernet/qlogic/qed/Makefile
> +++ b/drivers/net/ethernet/qlogic/qed/Makefile
> @@ -7,3 +7,4 @@ qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
> qed-$(CONFIG_QED_LL2) += qed_ll2.o
> qed-$(CONFIG_QED_RDMA) += qed_roce.o
> qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o qed_ooo.o
> +qed-$(CONFIG_QED_FCOE) += qed_fcoe.o
> diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
> index 44c184e..cbb4ebc 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed.h
> @@ -36,6 +36,7 @@
> #define QED_WFQ_UNIT 100
>
> #define ISCSI_BDQ_ID(_port_id) (_port_id)
> +#define FCOE_BDQ_ID(_port_id) ((_port_id) + 2)
> #define QED_WID_SIZE (1024)
> #define QED_PF_DEMS_SIZE (4)
>
> @@ -143,6 +144,7 @@ struct qed_tunn_update_params {
> */
> enum qed_pci_personality {
> QED_PCI_ETH,
> + QED_PCI_FCOE,
> QED_PCI_ISCSI,
> QED_PCI_ETH_ROCE,
> QED_PCI_DEFAULT /* default in shmem */
> @@ -180,6 +182,7 @@ enum QED_FEATURE {
> QED_VF,
> QED_RDMA_CNQ,
> QED_VF_L2_QUE,
> + QED_FCOE_CQ,
> QED_MAX_FEATURES,
> };
>
> @@ -197,6 +200,7 @@ enum QED_PORT_MODE {
>
> enum qed_dev_cap {
> QED_DEV_CAP_ETH,
> + QED_DEV_CAP_FCOE,
> QED_DEV_CAP_ISCSI,
> QED_DEV_CAP_ROCE,
> };
> @@ -231,6 +235,10 @@ struct qed_hw_info {
> u32 part_num[4];
>
> unsigned char hw_mac_addr[ETH_ALEN];
> + u64 node_wwn;
> + u64 port_wwn;
> +
> + u16 num_fcoe_conns;
>
> struct qed_igu_info *p_igu_info;
>
> @@ -386,6 +394,7 @@ struct qed_hwfn {
> struct qed_ooo_info *p_ooo_info;
> struct qed_rdma_info *p_rdma_info;
> struct qed_iscsi_info *p_iscsi_info;
> + struct qed_fcoe_info *p_fcoe_info;
> struct qed_pf_params pf_params;
>
> bool b_rdma_enabled_in_prs;
> @@ -594,11 +603,13 @@ struct qed_dev {
>
> u8 protocol;
> #define IS_QED_ETH_IF(cdev) ((cdev)->protocol == QED_PROTOCOL_ETH)
> +#define IS_QED_FCOE_IF(cdev) ((cdev)->protocol == QED_PROTOCOL_FCOE)
>
> /* Callbacks to protocol driver */
> union {
> struct qed_common_cb_ops *common;
> struct qed_eth_cb_ops *eth;
> + struct qed_fcoe_cb_ops *fcoe;
> struct qed_iscsi_cb_ops *iscsi;
> } protocol_ops;
> void *ops_cookie;
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.c b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
> index 0c42c24..749bff4 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.c
> @@ -66,12 +66,14 @@
> struct core_conn_context core_ctx;
> struct eth_conn_context eth_ctx;
> struct iscsi_conn_context iscsi_ctx;
> + struct fcoe_conn_context fcoe_ctx;
> struct roce_conn_context roce_ctx;
> };
>
> -/* TYPE-0 task context - iSCSI */
> +/* TYPE-0 task context - iSCSI, FCOE */
> union type0_task_context {
> struct iscsi_task_context iscsi_ctx;
> + struct fcoe_task_context fcoe_ctx;
> };
>
> /* TYPE-1 task context - ROCE */
> @@ -216,15 +218,22 @@ struct qed_cxt_mngr {
> static bool src_proto(enum protocol_type type)
> {
> return type == PROTOCOLID_ISCSI ||
> + type == PROTOCOLID_FCOE ||
> type == PROTOCOLID_ROCE;
> }
>
> static bool tm_cid_proto(enum protocol_type type)
> {
> return type == PROTOCOLID_ISCSI ||
> + type == PROTOCOLID_FCOE ||
> type == PROTOCOLID_ROCE;
> }
>
> +static bool tm_tid_proto(enum protocol_type type)
> +{
> + return type == PROTOCOLID_FCOE;
> +}
> +
> /* counts the iids for the CDU/CDUC ILT client configuration */
> struct qed_cdu_iids {
> u32 pf_cids;
> @@ -283,6 +292,22 @@ static void qed_cxt_tm_iids(struct qed_cxt_mngr *p_mngr,
> iids->pf_cids += p_cfg->cid_count;
> iids->per_vf_cids += p_cfg->cids_per_vf;
> }
> +
> + if (tm_tid_proto(i)) {
> + struct qed_tid_seg *segs = p_cfg->tid_seg;
> +
> + /* for each segment there is at most one
> + * protocol for which count is not 0.
> + */
> + for (j = 0; j < NUM_TASK_PF_SEGMENTS; j++)
> + iids->pf_tids[j] += segs[j].count;
> +
> + /* The last array elelment is for the VFs. As for PF
> + * segments there can be only one protocol for
> + * which this value is not 0.
> + */
> + iids->per_vf_tids += segs[NUM_TASK_PF_SEGMENTS].count;
> + }
> }
>
> iids->pf_cids = roundup(iids->pf_cids, TM_ALIGN);
> @@ -1670,9 +1695,42 @@ static void qed_tm_init_pf(struct qed_hwfn *p_hwfn)
> /* @@@TBD how to enable the scan for the VFs */
> }
>
> +static void qed_prs_init_common(struct qed_hwfn *p_hwfn)
> +{
> + if ((p_hwfn->hw_info.personality == QED_PCI_FCOE) &&
> + p_hwfn->pf_params.fcoe_pf_params.is_target)
> + STORE_RT_REG(p_hwfn,
> + PRS_REG_SEARCH_RESP_INITIATOR_TYPE_RT_OFFSET, 0);
> +}
> +
> +static void qed_prs_init_pf(struct qed_hwfn *p_hwfn)
> +{
> + struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
> + struct qed_conn_type_cfg *p_fcoe;
> + struct qed_tid_seg *p_tid;
> +
> + p_fcoe = &p_mngr->conn_cfg[PROTOCOLID_FCOE];
> +
> + /* If FCoE is active set the MAX OX_ID (tid) in the Parser */
> + if (!p_fcoe->cid_count)
> + return;
> +
> + p_tid = &p_fcoe->tid_seg[QED_CXT_FCOE_TID_SEG];
> + if (p_hwfn->pf_params.fcoe_pf_params.is_target) {
> + STORE_RT_REG_AGG(p_hwfn,
> + PRS_REG_TASK_ID_MAX_TARGET_PF_RT_OFFSET,
> + p_tid->count);
> + } else {
> + STORE_RT_REG_AGG(p_hwfn,
> + PRS_REG_TASK_ID_MAX_INITIATOR_PF_RT_OFFSET,
> + p_tid->count);
> + }
> +}
> +
> void qed_cxt_hw_init_common(struct qed_hwfn *p_hwfn)
> {
> qed_cdu_init_common(p_hwfn);
> + qed_prs_init_common(p_hwfn);
> }
>
> void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn)
> @@ -1684,6 +1742,7 @@ void qed_cxt_hw_init_pf(struct qed_hwfn *p_hwfn)
> qed_ilt_init_pf(p_hwfn);
> qed_src_init_pf(p_hwfn);
> qed_tm_init_pf(p_hwfn);
> + qed_prs_init_pf(p_hwfn);
> }
>
> int qed_cxt_acquire_cid(struct qed_hwfn *p_hwfn,
> @@ -1861,6 +1920,27 @@ int qed_cxt_set_pf_params(struct qed_hwfn *p_hwfn)
> p_params->num_cons, 1);
> break;
> }
> + case QED_PCI_FCOE:
> + {
> + struct qed_fcoe_pf_params *p_params;
> +
> + p_params = &p_hwfn->pf_params.fcoe_pf_params;
> +
> + if (p_params->num_cons && p_params->num_tasks) {
> + qed_cxt_set_proto_cid_count(p_hwfn,
> + PROTOCOLID_FCOE,
> + p_params->num_cons,
> + 0);
> +
> + qed_cxt_set_proto_tid_count(p_hwfn, PROTOCOLID_FCOE,
> + QED_CXT_FCOE_TID_SEG, 0,
> + p_params->num_tasks, true);
> + } else {
> + DP_INFO(p_hwfn->cdev,
> + "Fcoe personality used without setting params!\n");
> + }
> + break;
> + }
> case QED_PCI_ISCSI:
> {
> struct qed_iscsi_pf_params *p_params;
> @@ -1903,6 +1983,10 @@ int qed_cxt_get_tid_mem_info(struct qed_hwfn *p_hwfn,
>
> /* Verify the personality */
> switch (p_hwfn->hw_info.personality) {
> + case QED_PCI_FCOE:
> + proto = PROTOCOLID_FCOE;
> + seg = QED_CXT_FCOE_TID_SEG;
> + break;
> case QED_PCI_ISCSI:
> proto = PROTOCOLID_ISCSI;
> seg = QED_CXT_ISCSI_TID_SEG;
> @@ -2191,15 +2275,19 @@ int qed_cxt_get_task_ctx(struct qed_hwfn *p_hwfn,
> {
> struct qed_cxt_mngr *p_mngr = p_hwfn->p_cxt_mngr;
> struct qed_ilt_client_cfg *p_cli;
> - struct qed_ilt_cli_blk *p_seg;
> struct qed_tid_seg *p_seg_info;
> - u32 proto, seg;
> - u32 total_lines;
> - u32 tid_size, ilt_idx;
> + struct qed_ilt_cli_blk *p_seg;
> u32 num_tids_per_block;
> + u32 tid_size, ilt_idx;
> + u32 total_lines;
> + u32 proto, seg;
>
> /* Verify the personality */
> switch (p_hwfn->hw_info.personality) {
> + case QED_PCI_FCOE:
> + proto = PROTOCOLID_FCOE;
> + seg = QED_CXT_FCOE_TID_SEG;
> + break;
> case QED_PCI_ISCSI:
> proto = PROTOCOLID_ISCSI;
> seg = QED_CXT_ISCSI_TID_SEG;
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_cxt.h b/drivers/net/ethernet/qlogic/qed/qed_cxt.h
> index 2b8bdaa..b45d9b0 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_cxt.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_cxt.h
> @@ -67,6 +67,7 @@ int qed_cxt_get_tid_mem_info(struct qed_hwfn *p_hwfn,
>
> #define QED_CXT_ISCSI_TID_SEG PROTOCOLID_ISCSI
> #define QED_CXT_ROCE_TID_SEG PROTOCOLID_ROCE
> +#define QED_CXT_FCOE_TID_SEG PROTOCOLID_FCOE
> enum qed_cxt_elem_type {
> QED_ELEM_CXT,
> QED_ELEM_SRQ,
> @@ -180,4 +181,6 @@ u32 qed_cxt_get_proto_cid_start(struct qed_hwfn *p_hwfn,
>
> #define QED_CTX_WORKING_MEM 0
> #define QED_CTX_FL_MEM 1
> +int qed_cxt_get_task_ctx(struct qed_hwfn *p_hwfn,
> + u32 tid, u8 ctx_type, void **task_ctx);
> #endif
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
> index a4789a9..965fe20 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.c
> @@ -840,6 +840,15 @@ static int qed_dcbx_read_mib(struct qed_hwfn *p_hwfn,
> return rc;
> }
>
> +void qed_dcbx_aen(struct qed_hwfn *hwfn, u32 mib_type)
> +{
> + struct qed_common_cb_ops *op = hwfn->cdev->protocol_ops.common;
> + void *cookie = hwfn->cdev->ops_cookie;
> +
> + if (cookie && op->dcbx_aen)
> + op->dcbx_aen(cookie, &hwfn->p_dcbx_info->get, mib_type);
> +}
> +
> /* Read updated MIB.
> * Reconfigure QM and invoke PF update ramrod command if operational MIB
> * change is detected.
> @@ -866,6 +875,8 @@ static int qed_dcbx_read_mib(struct qed_hwfn *p_hwfn,
> qed_sp_pf_update(p_hwfn);
> }
> }
> + qed_dcbx_get_params(p_hwfn, p_ptt, &p_hwfn->p_dcbx_info->get, type);
> + qed_dcbx_aen(p_hwfn, type);
>
> return rc;
> }
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_dcbx.h b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h
> index 9ba6816..511113c 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_dcbx.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_dcbx.h
> @@ -75,6 +75,7 @@ struct qed_dcbx_info {
> struct dcbx_mib remote;
> #ifdef CONFIG_DCB
> struct qed_dcbx_set set;
> + struct qed_dcbx_get get;
> #endif
> u8 dcbx_cap;
> };
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
> index 3b22500..4218ddf 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
> @@ -25,6 +25,7 @@
> #include "qed_cxt.h"
> #include "qed_dcbx.h"
> #include "qed_dev_api.h"
> +#include "qed_fcoe.h"
> #include "qed_hsi.h"
> #include "qed_hw.h"
> #include "qed_init_ops.h"
> @@ -148,6 +149,9 @@ void qed_resc_free(struct qed_dev *cdev)
> #ifdef CONFIG_QED_LL2
> qed_ll2_free(p_hwfn, p_hwfn->p_ll2_info);
> #endif
> + if (p_hwfn->hw_info.personality == QED_PCI_FCOE)
> + qed_fcoe_free(p_hwfn, p_hwfn->p_fcoe_info);
> +
> if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
> qed_iscsi_free(p_hwfn, p_hwfn->p_iscsi_info);
> qed_ooo_free(p_hwfn, p_hwfn->p_ooo_info);
> @@ -409,6 +413,7 @@ int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
> int qed_resc_alloc(struct qed_dev *cdev)
> {
> struct qed_iscsi_info *p_iscsi_info;
> + struct qed_fcoe_info *p_fcoe_info;
> struct qed_ooo_info *p_ooo_info;
> #ifdef CONFIG_QED_LL2
> struct qed_ll2_info *p_ll2_info;
> @@ -515,6 +520,14 @@ int qed_resc_alloc(struct qed_dev *cdev)
> p_hwfn->p_ll2_info = p_ll2_info;
> }
> #endif
> +
> + if (p_hwfn->hw_info.personality == QED_PCI_FCOE) {
> + p_fcoe_info = qed_fcoe_alloc(p_hwfn);
> + if (!p_fcoe_info)
> + goto alloc_no_mem;
> + p_hwfn->p_fcoe_info = p_fcoe_info;
> + }
> +
> if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
> p_iscsi_info = qed_iscsi_alloc(p_hwfn);
> if (!p_iscsi_info)
> @@ -578,6 +591,9 @@ void qed_resc_setup(struct qed_dev *cdev)
> if (p_hwfn->using_ll2)
> qed_ll2_setup(p_hwfn, p_hwfn->p_ll2_info);
> #endif
> + if (p_hwfn->hw_info.personality == QED_PCI_FCOE)
> + qed_fcoe_setup(p_hwfn, p_hwfn->p_fcoe_info);
> +
> if (p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
> qed_iscsi_setup(p_hwfn, p_hwfn->p_iscsi_info);
> qed_ooo_setup(p_hwfn, p_hwfn->p_ooo_info);
> @@ -970,7 +986,8 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
> /* Protocl Configuration */
> STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_TCP_RT_OFFSET,
> (p_hwfn->hw_info.personality == QED_PCI_ISCSI) ? 1 : 0);
> - STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_FCOE_RT_OFFSET, 0);
> + STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_FCOE_RT_OFFSET,
> + (p_hwfn->hw_info.personality == QED_PCI_FCOE) ? 1 : 0);
> STORE_RT_REG(p_hwfn, PRS_REG_SEARCH_ROCE_RT_OFFSET, 0);
>
> /* Cleanup chip from previous driver if such remains exist */
> @@ -1002,8 +1019,16 @@ static int qed_hw_init_pf(struct qed_hwfn *p_hwfn,
> /* send function start command */
> rc = qed_sp_pf_start(p_hwfn, p_tunn, p_hwfn->cdev->mf_mode,
> allow_npar_tx_switch);
> - if (rc)
> + if (rc) {
> DP_NOTICE(p_hwfn, "Function start ramrod failed\n");
> + return rc;
> + }
> + if (p_hwfn->hw_info.personality == QED_PCI_FCOE) {
> + qed_wr(p_hwfn, p_ptt, PRS_REG_SEARCH_TAG1, BIT(2));
> + qed_wr(p_hwfn, p_ptt,
> + PRS_REG_PKT_LEN_STAT_TAGS_NOT_COUNTED_FIRST,
> + 0x100);
> + }
> }
> return rc;
> }
> @@ -1763,8 +1788,8 @@ static int qed_hw_get_resc(struct qed_hwfn *p_hwfn)
>
> static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
> {
> - u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, core_cfg;
> u32 port_cfg_addr, link_temp, nvm_cfg_addr, device_capabilities;
> + u32 nvm_cfg1_offset, mf_mode, addr, generic_cont0, core_cfg;
> struct qed_mcp_link_params *link;
>
> /* Read global nvm_cfg address */
> @@ -1910,6 +1935,9 @@ static int qed_hw_get_nvm_info(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
> if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET)
> __set_bit(QED_DEV_CAP_ETH,
> &p_hwfn->hw_info.device_capabilities);
> + if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_FCOE)
> + __set_bit(QED_DEV_CAP_FCOE,
> + &p_hwfn->hw_info.device_capabilities);
> if (device_capabilities & NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ISCSI)
> __set_bit(QED_DEV_CAP_ISCSI,
> &p_hwfn->hw_info.device_capabilities);
> @@ -2647,6 +2675,177 @@ void qed_llh_remove_mac_filter(struct qed_hwfn *p_hwfn,
> DP_NOTICE(p_hwfn, "Tried to remove a non-configured filter\n");
> }
>
> +int
> +qed_llh_add_protocol_filter(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + u16 source_port_or_eth_type,
> + u16 dest_port, enum qed_llh_port_filter_type_t type)
> +{
> + u32 high = 0, low = 0, en;
> + int i;
> +
> + if (!(IS_MF_SI(p_hwfn) || IS_MF_DEFAULT(p_hwfn)))
> + return 0;
> +
> + switch (type) {
> + case QED_LLH_FILTER_ETHERTYPE:
> + high = source_port_or_eth_type;
> + break;
> + case QED_LLH_FILTER_TCP_SRC_PORT:
> + case QED_LLH_FILTER_UDP_SRC_PORT:
> + low = source_port_or_eth_type << 16;
> + break;
> + case QED_LLH_FILTER_TCP_DEST_PORT:
> + case QED_LLH_FILTER_UDP_DEST_PORT:
> + low = dest_port;
> + break;
> + case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
> + case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
> + low = (source_port_or_eth_type << 16) | dest_port;
> + break;
> + default:
> + DP_NOTICE(p_hwfn,
> + "Non valid LLH protocol filter type %d\n", type);
> + return -EINVAL;
> + }
> + /* Find a free entry and utilize it */
> + for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
> + en = qed_rd(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32));
> + if (en)
> + continue;
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_VALUE +
> + 2 * i * sizeof(u32), low);
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_VALUE +
> + (2 * i + 1) * sizeof(u32), high);
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32), 1);
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE +
> + i * sizeof(u32), 1 << type);
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 1);
> + break;
> + }
> + if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE) {
> + DP_NOTICE(p_hwfn,
> + "Failed to find an empty LLH filter to utilize\n");
> + return -EINVAL;
> + }
> + switch (type) {
> + case QED_LLH_FILTER_ETHERTYPE:
> + DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
> + "ETH type %x is added at %d\n",
> + source_port_or_eth_type, i);
> + break;
> + case QED_LLH_FILTER_TCP_SRC_PORT:
> + DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
> + "TCP src port %x is added at %d\n",
> + source_port_or_eth_type, i);
> + break;
> + case QED_LLH_FILTER_UDP_SRC_PORT:
> + DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
> + "UDP src port %x is added at %d\n",
> + source_port_or_eth_type, i);
> + break;
> + case QED_LLH_FILTER_TCP_DEST_PORT:
> + DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
> + "TCP dst port %x is added at %d\n", dest_port, i);
> + break;
> + case QED_LLH_FILTER_UDP_DEST_PORT:
> + DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
> + "UDP dst port %x is added at %d\n", dest_port, i);
> + break;
> + case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
> + DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
> + "TCP src/dst ports %x/%x are added at %d\n",
> + source_port_or_eth_type, dest_port, i);
> + break;
> + case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
> + DP_VERBOSE(p_hwfn, NETIF_MSG_HW,
> + "UDP src/dst ports %x/%x are added at %d\n",
> + source_port_or_eth_type, dest_port, i);
> + break;
> + }
> + return 0;
> +}
> +
> +void
> +qed_llh_remove_protocol_filter(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + u16 source_port_or_eth_type,
> + u16 dest_port,
> + enum qed_llh_port_filter_type_t type)
> +{
> + u32 high = 0, low = 0;
> + int i;
> +
> + if (!(IS_MF_SI(p_hwfn) || IS_MF_DEFAULT(p_hwfn)))
> + return;
> +
> + switch (type) {
> + case QED_LLH_FILTER_ETHERTYPE:
> + high = source_port_or_eth_type;
> + break;
> + case QED_LLH_FILTER_TCP_SRC_PORT:
> + case QED_LLH_FILTER_UDP_SRC_PORT:
> + low = source_port_or_eth_type << 16;
> + break;
> + case QED_LLH_FILTER_TCP_DEST_PORT:
> + case QED_LLH_FILTER_UDP_DEST_PORT:
> + low = dest_port;
> + break;
> + case QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT:
> + case QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT:
> + low = (source_port_or_eth_type << 16) | dest_port;
> + break;
> + default:
> + DP_NOTICE(p_hwfn,
> + "Non valid LLH protocol filter type %d\n", type);
> + return;
> + }
> +
> + for (i = 0; i < NIG_REG_LLH_FUNC_FILTER_EN_SIZE; i++) {
> + if (!qed_rd(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32)))
> + continue;
> + if (!qed_rd(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32)))
> + continue;
> + if (!(qed_rd(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE +
> + i * sizeof(u32)) & BIT(type)))
> + continue;
> + if (qed_rd(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_VALUE +
> + 2 * i * sizeof(u32)) != low)
> + continue;
> + if (qed_rd(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_VALUE +
> + (2 * i + 1) * sizeof(u32)) != high)
> + continue;
> +
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_EN + i * sizeof(u32), 0);
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_MODE + i * sizeof(u32), 0);
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_PROTOCOL_TYPE +
> + i * sizeof(u32), 0);
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_VALUE + 2 * i * sizeof(u32), 0);
> + qed_wr(p_hwfn, p_ptt,
> + NIG_REG_LLH_FUNC_FILTER_VALUE +
> + (2 * i + 1) * sizeof(u32), 0);
> + break;
> + }
> +
> + if (i >= NIG_REG_LLH_FUNC_FILTER_EN_SIZE)
> + DP_NOTICE(p_hwfn, "Tried to remove a non-configured filter\n");
> +}
> +
> static int qed_set_coalesce(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt,
> u32 hw_addr, void *p_eth_qzone,
> size_t eth_qzone_size, u8 timeset)
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h
> index b6711c1..e3affbc 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_dev_api.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_dev_api.h
> @@ -329,6 +329,48 @@ int qed_llh_add_mac_filter(struct qed_hwfn *p_hwfn,
> void qed_llh_remove_mac_filter(struct qed_hwfn *p_hwfn,
> struct qed_ptt *p_ptt, u8 *p_filter);
>
> +enum qed_llh_port_filter_type_t {
> + QED_LLH_FILTER_ETHERTYPE,
> + QED_LLH_FILTER_TCP_SRC_PORT,
> + QED_LLH_FILTER_TCP_DEST_PORT,
> + QED_LLH_FILTER_TCP_SRC_AND_DEST_PORT,
> + QED_LLH_FILTER_UDP_SRC_PORT,
> + QED_LLH_FILTER_UDP_DEST_PORT,
> + QED_LLH_FILTER_UDP_SRC_AND_DEST_PORT
> +};
> +
> +/**
> + * @brief qed_llh_add_protocol_filter - configures a protocol filter in llh
> + *
> + * @param p_hwfn
> + * @param p_ptt
> + * @param source_port_or_eth_type - source port or ethertype to add
> + * @param dest_port - destination port to add
> + * @param type - type of filters and comparing
> + */
> +int
> +qed_llh_add_protocol_filter(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + u16 source_port_or_eth_type,
> + u16 dest_port,
> + enum qed_llh_port_filter_type_t type);
> +
> +/**
> + * @brief qed_llh_remove_protocol_filter - remove a protocol filter in llh
> + *
> + * @param p_hwfn
> + * @param p_ptt
> + * @param source_port_or_eth_type - source port or ethertype to add
> + * @param dest_port - destination port to add
> + * @param type - type of filters and comparing
> + */
> +void
> +qed_llh_remove_protocol_filter(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + u16 source_port_or_eth_type,
> + u16 dest_port,
> + enum qed_llh_port_filter_type_t type);
> +
> /**
> * *@brief Cleanup of previous driver remains prior to load
> *
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.c b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c
> new file mode 100644
> index 0000000..5118fcaf
> --- /dev/null
> +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.c
> @@ -0,0 +1,990 @@
> +/* QLogic qed NIC Driver
> + * Copyright (c) 2016 QLogic Corporation
> + *
> + * This software is available under the terms of the GNU General Public License
> + * (GPL) Version 2, available from the file COPYING in the main directory of
> + * this source tree.
> + */
> +
> +#include <linux/types.h>
> +#include <asm/byteorder.h>
> +#include <asm/param.h>
> +#include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/log2.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/stddef.h>
> +#include <linux/string.h>
> +#include <linux/version.h>
> +#include <linux/workqueue.h>
> +#include <linux/errno.h>
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#define __PREVENT_DUMP_MEM_ARR__
> +#define __PREVENT_PXP_GLOBAL_WIN__
> +#include "qed.h"
> +#include "qed_cxt.h"
> +#include "qed_dev_api.h"
> +#include "qed_fcoe.h"
> +#include "qed_hsi.h"
> +#include "qed_hw.h"
> +#include "qed_int.h"
> +#include "qed_ll2.h"
> +#include "qed_mcp.h"
> +#include "qed_reg_addr.h"
> +#include "qed_sp.h"
> +#include "qed_sriov.h"
> +#include <linux/qed/qed_fcoe_if.h>
> +
> +struct qed_fcoe_conn {
> + struct list_head list_entry;
> + bool free_on_delete;
> +
> + u16 conn_id;
> + u32 icid;
> + u32 fw_cid;
> + u8 layer_code;
> +
> + dma_addr_t sq_pbl_addr;
> + dma_addr_t sq_curr_page_addr;
> + dma_addr_t sq_next_page_addr;
> + dma_addr_t xferq_pbl_addr;
> + void *xferq_pbl_addr_virt_addr;
> + dma_addr_t xferq_addr[4];
> + void *xferq_addr_virt_addr[4];
> + dma_addr_t confq_pbl_addr;
> + void *confq_pbl_addr_virt_addr;
> + dma_addr_t confq_addr[2];
> + void *confq_addr_virt_addr[2];
> +
> + dma_addr_t terminate_params;
> +
> + u16 dst_mac_addr_lo;
> + u16 dst_mac_addr_mid;
> + u16 dst_mac_addr_hi;
> + u16 src_mac_addr_lo;
> + u16 src_mac_addr_mid;
> + u16 src_mac_addr_hi;
> +
> + u16 tx_max_fc_pay_len;
> + u16 e_d_tov_timer_val;
> + u16 rec_tov_timer_val;
> + u16 rx_max_fc_pay_len;
> + u16 vlan_tag;
> + u16 physical_q0;
> +
> + struct fc_addr_nw s_id;
> + u8 max_conc_seqs_c3;
> + struct fc_addr_nw d_id;
> + u8 flags;
> + u8 def_q_idx;
> +};
> +
> +static int
> +qed_sp_fcoe_func_start(struct qed_hwfn *p_hwfn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr)
> +{
> + struct qed_fcoe_pf_params *fcoe_pf_params = NULL;
> + struct fcoe_init_ramrod_params *p_ramrod = NULL;
> + struct fcoe_conn_context *p_cxt = NULL;
> + struct qed_spq_entry *p_ent = NULL;
> + struct fcoe_init_func_ramrod_data *p_data;
> + int rc = 0;
> + struct qed_sp_init_data init_data;
> + struct qed_cxt_info cxt_info;
> + u32 dummy_cid;
> + u16 tmp;
> + u8 i;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = qed_spq_get_cid(p_hwfn);
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + FCOE_RAMROD_CMD_ID_INIT_FUNC,
> + PROTOCOLID_FCOE, &init_data);
> + if (rc)
> + return rc;
> +
> + p_ramrod = &p_ent->ramrod.fcoe_init;
> + p_data = &p_ramrod->init_ramrod_data;
> + fcoe_pf_params = &p_hwfn->pf_params.fcoe_pf_params;
> +
> + p_data->mtu = cpu_to_le16(fcoe_pf_params->mtu);
> + tmp = cpu_to_le16(fcoe_pf_params->sq_num_pbl_pages);
> + p_data->sq_num_pages_in_pbl = tmp;
> +
> + rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_FCOE, &dummy_cid);
> + if (rc)
> + return rc;
> +
> + cxt_info.iid = dummy_cid;
> + rc = qed_cxt_get_cid_info(p_hwfn, &cxt_info);
> + if (rc) {
> + DP_NOTICE(p_hwfn, "Cannot find context info for dummy cid=%d\n",
> + dummy_cid);
> + return rc;
> + }
> + p_cxt = cxt_info.p_cxt;
> + SET_FIELD(p_cxt->tstorm_ag_context.flags3,
> + TSTORM_FCOE_CONN_AG_CTX_DUMMY_TIMER_CF_EN, 1);
> +
> + fcoe_pf_params->dummy_icid = (u16)dummy_cid;
> +
> + tmp = cpu_to_le16(fcoe_pf_params->num_tasks);
> + p_data->func_params.num_tasks = tmp;
> + p_data->func_params.log_page_size = fcoe_pf_params->log_page_size;
> + p_data->func_params.debug_mode = fcoe_pf_params->debug_mode;
> +
> + DMA_REGPAIR_LE(p_data->q_params.glbl_q_params_addr,
> + fcoe_pf_params->glbl_q_params_addr);
> +
> + tmp = cpu_to_le16(fcoe_pf_params->cq_num_entries);
> + p_data->q_params.cq_num_entries = tmp;
> +
> + tmp = cpu_to_le16(fcoe_pf_params->cmdq_num_entries);
> + p_data->q_params.cmdq_num_entries = tmp;
> +
> + tmp = fcoe_pf_params->num_cqs;
> + p_data->q_params.num_queues = (u8)tmp;
> +
> + tmp = (u16)p_hwfn->hw_info.resc_start[QED_CMDQS_CQS];
> + p_data->q_params.queue_relative_offset = (u8)tmp;
> +
> + for (i = 0; i < fcoe_pf_params->num_cqs; i++) {
> + tmp = cpu_to_le16(p_hwfn->sbs_info[i]->igu_sb_id);
> + p_data->q_params.cq_cmdq_sb_num_arr[i] = tmp;
> + }
> +
> + p_data->q_params.cq_sb_pi = fcoe_pf_params->gl_rq_pi;
> + p_data->q_params.cmdq_sb_pi = fcoe_pf_params->gl_cmd_pi;
> +
> + p_data->q_params.bdq_resource_id = FCOE_BDQ_ID(p_hwfn->port_id);
> +
> + DMA_REGPAIR_LE(p_data->q_params.bdq_pbl_base_address[BDQ_ID_RQ],
> + fcoe_pf_params->bdq_pbl_base_addr[BDQ_ID_RQ]);
> + p_data->q_params.bdq_pbl_num_entries[BDQ_ID_RQ] =
> + fcoe_pf_params->bdq_pbl_num_entries[BDQ_ID_RQ];
> + tmp = fcoe_pf_params->bdq_xoff_threshold[BDQ_ID_RQ];
> + p_data->q_params.bdq_xoff_threshold[BDQ_ID_RQ] = cpu_to_le16(tmp);
> + tmp = fcoe_pf_params->bdq_xon_threshold[BDQ_ID_RQ];
> + p_data->q_params.bdq_xon_threshold[BDQ_ID_RQ] = cpu_to_le16(tmp);
> +
> + DMA_REGPAIR_LE(p_data->q_params.bdq_pbl_base_address[BDQ_ID_IMM_DATA],
> + fcoe_pf_params->bdq_pbl_base_addr[BDQ_ID_IMM_DATA]);
> + p_data->q_params.bdq_pbl_num_entries[BDQ_ID_IMM_DATA] =
> + fcoe_pf_params->bdq_pbl_num_entries[BDQ_ID_IMM_DATA];
> + tmp = fcoe_pf_params->bdq_xoff_threshold[BDQ_ID_IMM_DATA];
> + p_data->q_params.bdq_xoff_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(tmp);
> + tmp = fcoe_pf_params->bdq_xon_threshold[BDQ_ID_IMM_DATA];
> + p_data->q_params.bdq_xon_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(tmp);
> + tmp = fcoe_pf_params->rq_buffer_size;
> + p_data->q_params.rq_buffer_size = cpu_to_le16(tmp);
> +
> + if (fcoe_pf_params->is_target) {
> + SET_FIELD(p_data->q_params.q_validity,
> + SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1);
> + if (p_data->q_params.bdq_pbl_num_entries[BDQ_ID_IMM_DATA])
> + SET_FIELD(p_data->q_params.q_validity,
> + SCSI_INIT_FUNC_QUEUES_IMM_DATA_VALID, 1);
> + SET_FIELD(p_data->q_params.q_validity,
> + SCSI_INIT_FUNC_QUEUES_CMD_VALID, 1);
> + } else {
> + SET_FIELD(p_data->q_params.q_validity,
> + SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1);
> + }
> +
> + rc = qed_spq_post(p_hwfn, p_ent, NULL);
> +
> + return rc;
> +}
> +
> +static int
> +qed_sp_fcoe_conn_offload(struct qed_hwfn *p_hwfn,
> + struct qed_fcoe_conn *p_conn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr)
> +{
> + struct fcoe_conn_offload_ramrod_params *p_ramrod = NULL;
> + struct fcoe_conn_offload_ramrod_data *p_data;
> + struct qed_spq_entry *p_ent = NULL;
> + struct qed_sp_init_data init_data;
> + u16 pq_id = 0, tmp;
> + int rc;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = p_conn->icid;
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + FCOE_RAMROD_CMD_ID_OFFLOAD_CONN,
> + PROTOCOLID_FCOE, &init_data);
> + if (rc)
> + return rc;
> +
> + p_ramrod = &p_ent->ramrod.fcoe_conn_ofld;
> + p_data = &p_ramrod->offload_ramrod_data;
> +
> + /* Transmission PQ is the first of the PF */
> + pq_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_FCOE, NULL);
> + p_conn->physical_q0 = cpu_to_le16(pq_id);
> + p_data->physical_q0 = cpu_to_le16(pq_id);
> +
> + p_data->conn_id = cpu_to_le16(p_conn->conn_id);
> + DMA_REGPAIR_LE(p_data->sq_pbl_addr, p_conn->sq_pbl_addr);
> + DMA_REGPAIR_LE(p_data->sq_curr_page_addr, p_conn->sq_curr_page_addr);
> + DMA_REGPAIR_LE(p_data->sq_next_page_addr, p_conn->sq_next_page_addr);
> + DMA_REGPAIR_LE(p_data->xferq_pbl_addr, p_conn->xferq_pbl_addr);
> + DMA_REGPAIR_LE(p_data->xferq_curr_page_addr, p_conn->xferq_addr[0]);
> + DMA_REGPAIR_LE(p_data->xferq_next_page_addr, p_conn->xferq_addr[1]);
> +
> + DMA_REGPAIR_LE(p_data->respq_pbl_addr, p_conn->confq_pbl_addr);
> + DMA_REGPAIR_LE(p_data->respq_curr_page_addr, p_conn->confq_addr[0]);
> + DMA_REGPAIR_LE(p_data->respq_next_page_addr, p_conn->confq_addr[1]);
> +
> + p_data->dst_mac_addr_lo = cpu_to_le16(p_conn->dst_mac_addr_lo);
> + p_data->dst_mac_addr_mid = cpu_to_le16(p_conn->dst_mac_addr_mid);
> + p_data->dst_mac_addr_hi = cpu_to_le16(p_conn->dst_mac_addr_hi);
> + p_data->src_mac_addr_lo = cpu_to_le16(p_conn->src_mac_addr_lo);
> + p_data->src_mac_addr_mid = cpu_to_le16(p_conn->src_mac_addr_mid);
> + p_data->src_mac_addr_hi = cpu_to_le16(p_conn->src_mac_addr_hi);
> +
> + tmp = cpu_to_le16(p_conn->tx_max_fc_pay_len);
> + p_data->tx_max_fc_pay_len = tmp;
> + tmp = cpu_to_le16(p_conn->e_d_tov_timer_val);
> + p_data->e_d_tov_timer_val = tmp;
> + tmp = cpu_to_le16(p_conn->rec_tov_timer_val);
> + p_data->rec_rr_tov_timer_val = tmp;
> + tmp = cpu_to_le16(p_conn->rx_max_fc_pay_len);
> + p_data->rx_max_fc_pay_len = tmp;
> +
> + p_data->vlan_tag = cpu_to_le16(p_conn->vlan_tag);
> + p_data->s_id.addr_hi = p_conn->s_id.addr_hi;
> + p_data->s_id.addr_mid = p_conn->s_id.addr_mid;
> + p_data->s_id.addr_lo = p_conn->s_id.addr_lo;
> + p_data->max_conc_seqs_c3 = p_conn->max_conc_seqs_c3;
> + p_data->d_id.addr_hi = p_conn->d_id.addr_hi;
> + p_data->d_id.addr_mid = p_conn->d_id.addr_mid;
> + p_data->d_id.addr_lo = p_conn->d_id.addr_lo;
> + p_data->flags = p_conn->flags;
> + p_data->def_q_idx = p_conn->def_q_idx;
> +
> + return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int
> +qed_sp_fcoe_conn_destroy(struct qed_hwfn *p_hwfn,
> + struct qed_fcoe_conn *p_conn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr)
> +{
> + struct fcoe_conn_terminate_ramrod_params *p_ramrod = NULL;
> + struct qed_spq_entry *p_ent = NULL;
> + struct qed_sp_init_data init_data;
> + int rc = 0;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = p_conn->icid;
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + FCOE_RAMROD_CMD_ID_TERMINATE_CONN,
> + PROTOCOLID_FCOE, &init_data);
> + if (rc)
> + return rc;
> +
> + p_ramrod = &p_ent->ramrod.fcoe_conn_terminate;
> + DMA_REGPAIR_LE(p_ramrod->terminate_ramrod_data.terminate_params_addr,
> + p_conn->terminate_params);
> +
> + return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int
> +qed_sp_fcoe_func_stop(struct qed_hwfn *p_hwfn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr)
> +{
> + struct qed_ptt *p_ptt = p_hwfn->p_main_ptt;
> + struct qed_spq_entry *p_ent = NULL;
> + struct qed_sp_init_data init_data;
> + u32 active_segs = 0;
> + int rc = 0;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = p_hwfn->pf_params.fcoe_pf_params.dummy_icid;
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + FCOE_RAMROD_CMD_ID_DESTROY_FUNC,
> + PROTOCOLID_FCOE, &init_data);
> + if (rc)
> + return rc;
> +
> + active_segs = qed_rd(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK);
> + active_segs &= ~BIT(QED_CXT_FCOE_TID_SEG);
> + qed_wr(p_hwfn, p_ptt, TM_REG_PF_ENABLE_TASK, active_segs);
> +
> + return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int
> +qed_fcoe_allocate_connection(struct qed_hwfn *p_hwfn,
> + struct qed_fcoe_conn **p_out_conn)
> +{
> + struct qed_fcoe_conn *p_conn = NULL;
> + void *p_addr;
> + u32 i;
> +
> + spin_lock_bh(&p_hwfn->p_fcoe_info->lock);
> + if (!list_empty(&p_hwfn->p_fcoe_info->free_list))
> + p_conn =
> + list_first_entry(&p_hwfn->p_fcoe_info->free_list,
> + struct qed_fcoe_conn, list_entry);
> + if (p_conn) {
> + list_del(&p_conn->list_entry);
> + spin_unlock_bh(&p_hwfn->p_fcoe_info->lock);
> + *p_out_conn = p_conn;
> + return 0;
> + }
> + spin_unlock_bh(&p_hwfn->p_fcoe_info->lock);
> +
> + p_conn = kzalloc(sizeof(*p_conn), GFP_KERNEL);
> + if (!p_conn)
> + return -ENOMEM;
> +
> + p_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + &p_conn->xferq_pbl_addr, GFP_KERNEL);
> + if (!p_addr)
> + goto nomem_pbl_xferq;
> + p_conn->xferq_pbl_addr_virt_addr = p_addr;
> +
> + for (i = 0; i < ARRAY_SIZE(p_conn->xferq_addr); i++) {
> + p_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + &p_conn->xferq_addr[i], GFP_KERNEL);
> + if (!p_addr)
> + goto nomem_xferq;
> + p_conn->xferq_addr_virt_addr[i] = p_addr;
> +
> + p_addr = p_conn->xferq_pbl_addr_virt_addr;
> + ((dma_addr_t *)p_addr)[i] = p_conn->xferq_addr[i];
> + }
> +
> + p_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + &p_conn->confq_pbl_addr, GFP_KERNEL);
> + if (!p_addr)
> + goto nomem_xferq;
> + p_conn->confq_pbl_addr_virt_addr = p_addr;
> +
> + for (i = 0; i < ARRAY_SIZE(p_conn->confq_addr); i++) {
> + p_addr = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + &p_conn->confq_addr[i], GFP_KERNEL);
> + if (!p_addr)
> + goto nomem_confq;
> + p_conn->confq_addr_virt_addr[i] = p_addr;
> +
> + p_addr = p_conn->confq_pbl_addr_virt_addr;
> + ((dma_addr_t *)p_addr)[i] = p_conn->confq_addr[i];
> + }
> +
> + p_conn->free_on_delete = true;
> + *p_out_conn = p_conn;
> + return 0;
> +
> +nomem_confq:
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + p_conn->confq_pbl_addr_virt_addr,
> + p_conn->confq_pbl_addr);
> + for (i = 0; i < ARRAY_SIZE(p_conn->confq_addr); i++)
> + if (p_conn->confq_addr_virt_addr[i])
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + p_conn->confq_addr_virt_addr[i],
> + p_conn->confq_addr[i]);
> +nomem_xferq:
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + p_conn->xferq_pbl_addr_virt_addr,
> + p_conn->xferq_pbl_addr);
> + for (i = 0; i < ARRAY_SIZE(p_conn->xferq_addr); i++)
> + if (p_conn->xferq_addr_virt_addr[i])
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + p_conn->xferq_addr_virt_addr[i],
> + p_conn->xferq_addr[i]);
> +nomem_pbl_xferq:
> + kfree(p_conn);
> + return -ENOMEM;
> +}
> +
> +static void qed_fcoe_free_connection(struct qed_hwfn *p_hwfn,
> + struct qed_fcoe_conn *p_conn)
> +{
> + u32 i;
> +
> + if (!p_conn)
> + return;
> +
> + if (p_conn->confq_pbl_addr_virt_addr)
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + p_conn->confq_pbl_addr_virt_addr,
> + p_conn->confq_pbl_addr);
> +
> + for (i = 0; i < ARRAY_SIZE(p_conn->confq_addr); i++) {
> + if (!p_conn->confq_addr_virt_addr[i])
> + continue;
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + p_conn->confq_addr_virt_addr[i],
> + p_conn->confq_addr[i]);
> + }
> +
> + if (p_conn->xferq_pbl_addr_virt_addr)
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + p_conn->xferq_pbl_addr_virt_addr,
> + p_conn->xferq_pbl_addr);
> +
> + for (i = 0; i < ARRAY_SIZE(p_conn->xferq_addr); i++) {
> + if (!p_conn->xferq_addr_virt_addr[i])
> + continue;
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + QED_CHAIN_PAGE_SIZE,
> + p_conn->xferq_addr_virt_addr[i],
> + p_conn->xferq_addr[i]);
> + }
> + kfree(p_conn);
> +}
> +
> +static void __iomem *qed_fcoe_get_db_addr(struct qed_hwfn *p_hwfn, u32 cid)
> +{
> + return (u8 __iomem *)p_hwfn->doorbells +
> + qed_db_addr(cid, DQ_DEMS_LEGACY);
> +}
> +
> +static void __iomem *qed_fcoe_get_primary_bdq_prod(struct qed_hwfn *p_hwfn,
> + u8 bdq_id)
> +{
> + u8 bdq_function_id = FCOE_BDQ_ID(p_hwfn->port_id);
> +
> + return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_MSDM_RAM +
> + MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id, bdq_id);
> +}
> +
> +static void __iomem *qed_fcoe_get_secondary_bdq_prod(struct qed_hwfn *p_hwfn,
> + u8 bdq_id)
> +{
> + u8 bdq_function_id = FCOE_BDQ_ID(p_hwfn->port_id);
> +
> + return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_TSDM_RAM +
> + TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id, bdq_id);
> +}
> +
> +struct qed_fcoe_info *qed_fcoe_alloc(struct qed_hwfn *p_hwfn)
> +{
> + struct qed_fcoe_info *p_fcoe_info;
> +
> + /* Allocate LL2's set struct */
> + p_fcoe_info = kzalloc(sizeof(*p_fcoe_info), GFP_KERNEL);
> + if (!p_fcoe_info) {
> + DP_NOTICE(p_hwfn, "Failed to allocate qed_fcoe_info'\n");
> + return NULL;
> + }
> + INIT_LIST_HEAD(&p_fcoe_info->free_list);
> + return p_fcoe_info;
> +}
> +
> +void qed_fcoe_setup(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info)
> +{
> + struct fcoe_task_context *p_task_ctx = NULL;
> + int rc;
> + u32 i;
> +
> + spin_lock_init(&p_fcoe_info->lock);
> + for (i = 0; i < p_hwfn->pf_params.fcoe_pf_params.num_tasks; i++) {
> + rc = qed_cxt_get_task_ctx(p_hwfn, i,
> + QED_CTX_WORKING_MEM,
> + (void **)&p_task_ctx);
> + if (rc)
> + continue;
> +
> + memset(p_task_ctx, 0, sizeof(struct fcoe_task_context));
> + SET_FIELD(p_task_ctx->timer_context.logical_client_0,
> + TIMERS_CONTEXT_VALIDLC0, 1);
> + SET_FIELD(p_task_ctx->timer_context.logical_client_1,
> + TIMERS_CONTEXT_VALIDLC1, 1);
> + SET_FIELD(p_task_ctx->tstorm_ag_context.flags0,
> + TSTORM_FCOE_TASK_AG_CTX_CONNECTION_TYPE, 1);
> + }
> +}
> +
> +void qed_fcoe_free(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info)
> +{
> + struct qed_fcoe_conn *p_conn = NULL;
> +
> + if (!p_fcoe_info)
> + return;
> +
> + while (!list_empty(&p_fcoe_info->free_list)) {
> + p_conn = list_first_entry(&p_fcoe_info->free_list,
> + struct qed_fcoe_conn, list_entry);
> + if (!p_conn)
> + break;
> + list_del(&p_conn->list_entry);
> + qed_fcoe_free_connection(p_hwfn, p_conn);
> + }
> +
> + kfree(p_fcoe_info);
> +}
> +
> +static int
> +qed_fcoe_acquire_connection(struct qed_hwfn *p_hwfn,
> + struct qed_fcoe_conn *p_in_conn,
> + struct qed_fcoe_conn **p_out_conn)
> +{
> + struct qed_fcoe_conn *p_conn = NULL;
> + int rc = 0;
> + u32 icid;
> +
> + spin_lock_bh(&p_hwfn->p_fcoe_info->lock);
> + rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_FCOE, &icid);
> + spin_unlock_bh(&p_hwfn->p_fcoe_info->lock);
> + if (rc)
> + return rc;
> +
> + /* Use input connection [if provided] or allocate a new one */
> + if (p_in_conn) {
> + p_conn = p_in_conn;
> + } else {
> + rc = qed_fcoe_allocate_connection(p_hwfn, &p_conn);
> + if (rc) {
> + spin_lock_bh(&p_hwfn->p_fcoe_info->lock);
> + qed_cxt_release_cid(p_hwfn, icid);
> + spin_unlock_bh(&p_hwfn->p_fcoe_info->lock);
> + return rc;
> + }
> + }
> +
> + p_conn->icid = icid;
> + p_conn->fw_cid = (p_hwfn->hw_info.opaque_fid << 16) | icid;
> + *p_out_conn = p_conn;
> +
> + return rc;
> +}
> +
> +static void qed_fcoe_release_connection(struct qed_hwfn *p_hwfn,
> + struct qed_fcoe_conn *p_conn)
> +{
> + spin_lock_bh(&p_hwfn->p_fcoe_info->lock);
> + list_add_tail(&p_conn->list_entry, &p_hwfn->p_fcoe_info->free_list);
> + qed_cxt_release_cid(p_hwfn, p_conn->icid);
> + spin_unlock_bh(&p_hwfn->p_fcoe_info->lock);
> +}
> +
> +static void _qed_fcoe_get_tstats(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + struct qed_fcoe_stats *p_stats)
> +{
> + struct fcoe_rx_stat tstats;
> + u32 tstats_addr;
> +
> + memset(&tstats, 0, sizeof(tstats));
> + tstats_addr = BAR0_MAP_REG_TSDM_RAM +
> + TSTORM_FCOE_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
> + qed_memcpy_from(p_hwfn, p_ptt, &tstats, tstats_addr, sizeof(tstats));
> +
> + p_stats->fcoe_rx_byte_cnt = HILO_64_REGPAIR(tstats.fcoe_rx_byte_cnt);
> + p_stats->fcoe_rx_data_pkt_cnt =
> + HILO_64_REGPAIR(tstats.fcoe_rx_data_pkt_cnt);
> + p_stats->fcoe_rx_xfer_pkt_cnt =
> + HILO_64_REGPAIR(tstats.fcoe_rx_xfer_pkt_cnt);
> + p_stats->fcoe_rx_other_pkt_cnt =
> + HILO_64_REGPAIR(tstats.fcoe_rx_other_pkt_cnt);
> +
> + p_stats->fcoe_silent_drop_pkt_cmdq_full_cnt =
> + le32_to_cpu(tstats.fcoe_silent_drop_pkt_cmdq_full_cnt);
> + p_stats->fcoe_silent_drop_pkt_rq_full_cnt =
> + le32_to_cpu(tstats.fcoe_silent_drop_pkt_rq_full_cnt);
> + p_stats->fcoe_silent_drop_pkt_crc_error_cnt =
> + le32_to_cpu(tstats.fcoe_silent_drop_pkt_crc_error_cnt);
> + p_stats->fcoe_silent_drop_pkt_task_invalid_cnt =
> + le32_to_cpu(tstats.fcoe_silent_drop_pkt_task_invalid_cnt);
> + p_stats->fcoe_silent_drop_total_pkt_cnt =
> + le32_to_cpu(tstats.fcoe_silent_drop_total_pkt_cnt);
> +}
> +
> +static void _qed_fcoe_get_pstats(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + struct qed_fcoe_stats *p_stats)
> +{
> + struct fcoe_tx_stat pstats;
> + u32 pstats_addr;
> +
> + memset(&pstats, 0, sizeof(pstats));
> + pstats_addr = BAR0_MAP_REG_PSDM_RAM +
> + PSTORM_FCOE_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
> + qed_memcpy_from(p_hwfn, p_ptt, &pstats, pstats_addr, sizeof(pstats));
> +
> + p_stats->fcoe_tx_byte_cnt = HILO_64_REGPAIR(pstats.fcoe_tx_byte_cnt);
> + p_stats->fcoe_tx_data_pkt_cnt =
> + HILO_64_REGPAIR(pstats.fcoe_tx_data_pkt_cnt);
> + p_stats->fcoe_tx_xfer_pkt_cnt =
> + HILO_64_REGPAIR(pstats.fcoe_tx_xfer_pkt_cnt);
> + p_stats->fcoe_tx_other_pkt_cnt =
> + HILO_64_REGPAIR(pstats.fcoe_tx_other_pkt_cnt);
> +}
> +
> +static int qed_fcoe_get_stats(struct qed_hwfn *p_hwfn,
> + struct qed_fcoe_stats *p_stats)
> +{
> + struct qed_ptt *p_ptt;
> +
> + memset(p_stats, 0, sizeof(*p_stats));
> +
> + p_ptt = qed_ptt_acquire(p_hwfn);
> +
> + if (!p_ptt) {
> + DP_ERR(p_hwfn, "Failed to acquire ptt\n");
> + return -EINVAL;
> + }
> +
> + _qed_fcoe_get_tstats(p_hwfn, p_ptt, p_stats);
> + _qed_fcoe_get_pstats(p_hwfn, p_ptt, p_stats);
> +
> + qed_ptt_release(p_hwfn, p_ptt);
> +
> + return 0;
> +}
> +
> +struct qed_hash_fcoe_con {
> + struct hlist_node node;
> + struct qed_fcoe_conn *con;
> +};
> +
> +static int qed_fill_fcoe_dev_info(struct qed_dev *cdev,
> + struct qed_dev_fcoe_info *info)
> +{
> + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
> + int rc;
> +
> + memset(info, 0, sizeof(*info));
> + rc = qed_fill_dev_info(cdev, &info->common);
> +
> + info->primary_dbq_rq_addr =
> + qed_fcoe_get_primary_bdq_prod(hwfn, BDQ_ID_RQ);
> + info->secondary_bdq_rq_addr =
> + qed_fcoe_get_secondary_bdq_prod(hwfn, BDQ_ID_RQ);
> +
> + return rc;
> +}
> +
> +static void qed_register_fcoe_ops(struct qed_dev *cdev,
> + struct qed_fcoe_cb_ops *ops, void *cookie)
> +{
> + cdev->protocol_ops.fcoe = ops;
> + cdev->ops_cookie = cookie;
> +}
> +
> +static struct qed_hash_fcoe_con *qed_fcoe_get_hash(struct qed_dev *cdev,
> + u32 handle)
> +{
> + struct qed_hash_fcoe_con *hash_con = NULL;
> +
> + if (!(cdev->flags & QED_FLAG_STORAGE_STARTED))
> + return NULL;
> +
> + hash_for_each_possible(cdev->connections, hash_con, node, handle) {
> + if (hash_con->con->icid == handle)
> + break;
> + }
> +
> + if (!hash_con || (hash_con->con->icid != handle))
> + return NULL;
> +
> + return hash_con;
> +}
> +
> +static int qed_fcoe_stop(struct qed_dev *cdev)
> +{
> + int rc;
> +
> + if (!(cdev->flags & QED_FLAG_STORAGE_STARTED)) {
> + DP_NOTICE(cdev, "fcoe already stopped\n");
> + return 0;
> + }
> +
> + if (!hash_empty(cdev->connections)) {
> + DP_NOTICE(cdev,
> + "Can't stop fcoe - not all connections were returned\n");
> + return -EINVAL;
> + }
> +
> + /* Stop the fcoe */
> + rc = qed_sp_fcoe_func_stop(QED_LEADING_HWFN(cdev),
> + QED_SPQ_MODE_EBLOCK, NULL);
> + cdev->flags &= ~QED_FLAG_STORAGE_STARTED;
> +
> + return rc;
> +}
> +
> +static int qed_fcoe_start(struct qed_dev *cdev, struct qed_fcoe_tid *tasks)
> +{
> + int rc;
> +
> + if (cdev->flags & QED_FLAG_STORAGE_STARTED) {
> + DP_NOTICE(cdev, "fcoe already started;\n");
> + return 0;
> + }
> +
> + rc = qed_sp_fcoe_func_start(QED_LEADING_HWFN(cdev),
> + QED_SPQ_MODE_EBLOCK, NULL);
> + if (rc) {
> + DP_NOTICE(cdev, "Failed to start fcoe\n");
> + return rc;
> + }
> +
> + cdev->flags |= QED_FLAG_STORAGE_STARTED;
> + hash_init(cdev->connections);
> +
> + if (tasks) {
> + struct qed_tid_mem *tid_info = kzalloc(sizeof(*tid_info),
> + GFP_ATOMIC);
> +
> + if (!tid_info) {
> + DP_NOTICE(cdev,
> + "Failed to allocate tasks information\n");
> + qed_fcoe_stop(cdev);
> + return -ENOMEM;
> + }
> +
> + rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev), tid_info);
> + if (rc) {
> + DP_NOTICE(cdev, "Failed to gather task information\n");
> + qed_fcoe_stop(cdev);
> + kfree(tid_info);
> + return rc;
> + }
> +
> + /* Fill task information */
> + tasks->size = tid_info->tid_size;
> + tasks->num_tids_per_block = tid_info->num_tids_per_block;
> + memcpy(tasks->blocks, tid_info->blocks,
> + MAX_TID_BLOCKS_FCOE * sizeof(u8 *));
> +
> + kfree(tid_info);
> + }
> +
> + return 0;
> +}
> +
> +static int qed_fcoe_acquire_conn(struct qed_dev *cdev,
> + u32 *handle,
> + u32 *fw_cid, void __iomem **p_doorbell)
> +{
> + struct qed_hash_fcoe_con *hash_con;
> + int rc;
> +
> + /* Allocate a hashed connection */
> + hash_con = kzalloc(sizeof(*hash_con), GFP_KERNEL);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to allocate hashed connection\n");
> + return -ENOMEM;
> + }
> +
> + /* Acquire the connection */
> + rc = qed_fcoe_acquire_connection(QED_LEADING_HWFN(cdev), NULL,
> + &hash_con->con);
> + if (rc) {
> + DP_NOTICE(cdev, "Failed to acquire Connection\n");
> + kfree(hash_con);
> + return rc;
> + }
> +
> + /* Added the connection to hash table */
> + *handle = hash_con->con->icid;
> + *fw_cid = hash_con->con->fw_cid;
> + hash_add(cdev->connections, &hash_con->node, *handle);
> +
> + if (p_doorbell)
> + *p_doorbell = qed_fcoe_get_db_addr(QED_LEADING_HWFN(cdev),
> + *handle);
> +
> + return 0;
> +}
> +
> +static int qed_fcoe_release_conn(struct qed_dev *cdev, u32 handle)
> +{
> + struct qed_hash_fcoe_con *hash_con;
> +
> + hash_con = qed_fcoe_get_hash(cdev, handle);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> + handle);
> + return -EINVAL;
> + }
> +
> + hlist_del(&hash_con->node);
> + qed_fcoe_release_connection(QED_LEADING_HWFN(cdev), hash_con->con);
> + kfree(hash_con);
> +
> + return 0;
> +}
> +
> +static int qed_fcoe_offload_conn(struct qed_dev *cdev,
> + u32 handle,
> + struct qed_fcoe_params_offload *conn_info)
> +{
> + struct qed_hash_fcoe_con *hash_con;
> + struct qed_fcoe_conn *con;
> +
> + hash_con = qed_fcoe_get_hash(cdev, handle);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> + handle);
> + return -EINVAL;
> + }
> +
> + /* Update the connection with information from the params */
> + con = hash_con->con;
> +
> + con->sq_pbl_addr = conn_info->sq_pbl_addr;
> + con->sq_curr_page_addr = conn_info->sq_curr_page_addr;
> + con->sq_next_page_addr = conn_info->sq_next_page_addr;
> + con->tx_max_fc_pay_len = conn_info->tx_max_fc_pay_len;
> + con->e_d_tov_timer_val = conn_info->e_d_tov_timer_val;
> + con->rec_tov_timer_val = conn_info->rec_tov_timer_val;
> + con->rx_max_fc_pay_len = conn_info->rx_max_fc_pay_len;
> + con->vlan_tag = conn_info->vlan_tag;
> + con->max_conc_seqs_c3 = conn_info->max_conc_seqs_c3;
> + con->flags = conn_info->flags;
> + con->def_q_idx = conn_info->def_q_idx;
> +
> + con->src_mac_addr_hi = (conn_info->src_mac[5] << 8) |
> + conn_info->src_mac[4];
> + con->src_mac_addr_mid = (conn_info->src_mac[3] << 8) |
> + conn_info->src_mac[2];
> + con->src_mac_addr_lo = (conn_info->src_mac[1] << 8) |
> + conn_info->src_mac[0];
> + con->dst_mac_addr_hi = (conn_info->dst_mac[5] << 8) |
> + conn_info->dst_mac[4];
> + con->dst_mac_addr_mid = (conn_info->dst_mac[3] << 8) |
> + conn_info->dst_mac[2];
> + con->dst_mac_addr_lo = (conn_info->dst_mac[1] << 8) |
> + conn_info->dst_mac[0];
> +
> + con->s_id.addr_hi = conn_info->s_id.addr_hi;
> + con->s_id.addr_mid = conn_info->s_id.addr_mid;
> + con->s_id.addr_lo = conn_info->s_id.addr_lo;
> + con->d_id.addr_hi = conn_info->d_id.addr_hi;
> + con->d_id.addr_mid = conn_info->d_id.addr_mid;
> + con->d_id.addr_lo = conn_info->d_id.addr_lo;
> +
> + return qed_sp_fcoe_conn_offload(QED_LEADING_HWFN(cdev), con,
> + QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_fcoe_destroy_conn(struct qed_dev *cdev,
> + u32 handle, dma_addr_t terminate_params)
> +{
> + struct qed_hash_fcoe_con *hash_con;
> + struct qed_fcoe_conn *con;
> +
> + hash_con = qed_fcoe_get_hash(cdev, handle);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> + handle);
> + return -EINVAL;
> + }
> +
> + /* Update the connection with information from the params */
> + con = hash_con->con;
> + con->terminate_params = terminate_params;
> +
> + return qed_sp_fcoe_conn_destroy(QED_LEADING_HWFN(cdev), con,
> + QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_fcoe_stats(struct qed_dev *cdev, struct qed_fcoe_stats *stats)
> +{
> + return qed_fcoe_get_stats(QED_LEADING_HWFN(cdev), stats);
> +}
> +
> +void qed_get_protocol_stats_fcoe(struct qed_dev *cdev,
> + struct qed_mcp_fcoe_stats *stats)
> +{
> + struct qed_fcoe_stats proto_stats;
> +
> + /* Retrieve FW statistics */
> + memset(&proto_stats, 0, sizeof(proto_stats));
> + if (qed_fcoe_stats(cdev, &proto_stats)) {
> + DP_VERBOSE(cdev, QED_MSG_STORAGE,
> + "Failed to collect FCoE statistics\n");
> + return;
> + }
> +
> + /* Translate FW statistics into struct */
> + stats->rx_pkts = proto_stats.fcoe_rx_data_pkt_cnt +
> + proto_stats.fcoe_rx_xfer_pkt_cnt +
> + proto_stats.fcoe_rx_other_pkt_cnt;
> + stats->tx_pkts = proto_stats.fcoe_tx_data_pkt_cnt +
> + proto_stats.fcoe_tx_xfer_pkt_cnt +
> + proto_stats.fcoe_tx_other_pkt_cnt;
> + stats->fcs_err = proto_stats.fcoe_silent_drop_pkt_crc_error_cnt;
> +
> + /* Request protocol driver to fill-in the rest */
> + if (cdev->protocol_ops.fcoe && cdev->ops_cookie) {
> + struct qed_fcoe_cb_ops *ops = cdev->protocol_ops.fcoe;
> + void *cookie = cdev->ops_cookie;
> +
> + if (ops->get_login_failures)
> + stats->login_failure = ops->get_login_failures(cookie);
> + }
> +}
> +
> +static const struct qed_fcoe_ops qed_fcoe_ops_pass = {
> + .common = &qed_common_ops_pass,
> + .ll2 = &qed_ll2_ops_pass,
> + .fill_dev_info = &qed_fill_fcoe_dev_info,
> + .start = &qed_fcoe_start,
> + .stop = &qed_fcoe_stop,
> + .register_ops = &qed_register_fcoe_ops,
> + .acquire_conn = &qed_fcoe_acquire_conn,
> + .release_conn = &qed_fcoe_release_conn,
> + .offload_conn = &qed_fcoe_offload_conn,
> + .destroy_conn = &qed_fcoe_destroy_conn,
> + .get_stats = &qed_fcoe_stats,
> +};
> +
> +const struct qed_fcoe_ops *qed_get_fcoe_ops(void)
> +{
> + return &qed_fcoe_ops_pass;
> +}
> +EXPORT_SYMBOL(qed_get_fcoe_ops);
> +
> +void qed_put_fcoe_ops(void)
> +{
> +}
> +EXPORT_SYMBOL(qed_put_fcoe_ops);
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_fcoe.h b/drivers/net/ethernet/qlogic/qed/qed_fcoe.h
> new file mode 100644
> index 0000000..72a3643
> --- /dev/null
> +++ b/drivers/net/ethernet/qlogic/qed/qed_fcoe.h
> @@ -0,0 +1,52 @@
> +/* QLogic qed NIC Driver
> + * Copyright (c) 2016 QLogic Corporation
> + *
> + * This software is available under the terms of the GNU General Public License
> + * (GPL) Version 2, available from the file COPYING in the main directory of
> + * this source tree.
> + */
> +
> +#ifndef _QED_FCOE_H
> +#define _QED_FCOE_H
> +#include <linux/types.h>
> +#include <linux/list.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/qed/qed_fcoe_if.h>
> +#include <linux/qed/qed_chain.h>
> +#include "qed.h"
> +#include "qed_hsi.h"
> +#include "qed_mcp.h"
> +#include "qed_sp.h"
> +
> +struct qed_fcoe_info {
> + spinlock_t lock; /* Connection resources. */
> + struct list_head free_list;
> +};
> +
> +#if IS_ENABLED(CONFIG_QED_FCOE)
> +struct qed_fcoe_info *qed_fcoe_alloc(struct qed_hwfn *p_hwfn);
> +
> +void qed_fcoe_setup(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info);
> +
> +void qed_fcoe_free(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info);
> +void qed_get_protocol_stats_fcoe(struct qed_dev *cdev,
> + struct qed_mcp_fcoe_stats *stats);
> +#else /* CONFIG_QED_FCOE */
> +static inline struct qed_fcoe_info *
> +qed_fcoe_alloc(struct qed_hwfn *p_hwfn) { return NULL; }
> +static inline void
> +qed_fcoe_setup(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) {}
> +static inline void
> +qed_fcoe_free(struct qed_hwfn *p_hwfn, struct qed_fcoe_info *p_fcoe_info) {}
> +static inline void
> +qed_get_protocol_stats_fcoe(struct qed_dev *cdev,
> + struct qed_mcp_fcoe_stats *stats) {}
> +#endif /* CONFIG_QED_FCOE */
> +
> +#ifdef CONFIG_QED_LL2
> +extern const struct qed_common_ops qed_common_ops_pass;
> +extern const struct qed_ll2_ops qed_ll2_ops_pass;
> +#endif
> +
> +#endif /* _QED_FCOE_H */
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_hsi.h b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
> index 785ab03..a10f55e 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_hsi.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_hsi.h
> @@ -19,10 +19,12 @@
> #include <linux/qed/common_hsi.h>
> #include <linux/qed/storage_common.h>
> #include <linux/qed/tcp_common.h>
> +#include <linux/qed/fcoe_common.h>
> #include <linux/qed/eth_common.h>
> #include <linux/qed/iscsi_common.h>
> #include <linux/qed/rdma_common.h>
> #include <linux/qed/roce_common.h>
> +#include <linux/qed/qed_fcoe_if.h>
>
> struct qed_hwfn;
> struct qed_ptt;
> @@ -913,7 +915,7 @@ struct mstorm_vf_zone {
> enum personality_type {
> BAD_PERSONALITY_TYP,
> PERSONALITY_ISCSI,
> - PERSONALITY_RESERVED2,
> + PERSONALITY_FCOE,
> PERSONALITY_RDMA_AND_ETH,
> PERSONALITY_RESERVED3,
> PERSONALITY_CORE,
> @@ -3449,6 +3451,10 @@ void qed_set_geneve_enable(struct qed_hwfn *p_hwfn,
> #define TSTORM_RDMA_QUEUE_STAT_OFFSET(rdma_stat_counter_id) \
> (IRO[46].base + ((rdma_stat_counter_id) * IRO[46].m1))
> #define TSTORM_RDMA_QUEUE_STAT_SIZE (IRO[46].size)
> +#define TSTORM_FCOE_RX_STATS_OFFSET(pf_id) \
> + (IRO[43].base + ((pf_id) * IRO[43].m1))
> +#define PSTORM_FCOE_TX_STATS_OFFSET(pf_id) \
> + (IRO[44].base + ((pf_id) * IRO[44].m1))
>
> static const struct iro iro_arr[47] = {
> {0x0, 0x0, 0x0, 0x0, 0x8},
> @@ -7383,6 +7389,769 @@ struct ystorm_roce_resp_conn_ag_ctx {
> __le32 reg3;
> };
>
> +struct ystorm_fcoe_conn_st_ctx {
> + u8 func_mode;
> + u8 cos;
> + u8 conf_version;
> + u8 eth_hdr_size;
> + __le16 stat_ram_addr;
> + __le16 mtu;
> + __le16 max_fc_payload_len;
> + __le16 tx_max_fc_pay_len;
> + u8 fcp_cmd_size;
> + u8 fcp_rsp_size;
> + __le16 mss;
> + struct regpair reserved;
> + u8 protection_info_flags;
> +#define YSTORM_FCOE_CONN_ST_CTX_SUPPORT_PROTECTION_MASK 0x1
> +#define YSTORM_FCOE_CONN_ST_CTX_SUPPORT_PROTECTION_SHIFT 0
> +#define YSTORM_FCOE_CONN_ST_CTX_VALID_MASK 0x1
> +#define YSTORM_FCOE_CONN_ST_CTX_VALID_SHIFT 1
> +#define YSTORM_FCOE_CONN_ST_CTX_RESERVED1_MASK 0x3F
> +#define YSTORM_FCOE_CONN_ST_CTX_RESERVED1_SHIFT 2
> + u8 dst_protection_per_mss;
> + u8 src_protection_per_mss;
> + u8 ptu_log_page_size;
> + u8 flags;
> +#define YSTORM_FCOE_CONN_ST_CTX_INNER_VLAN_FLAG_MASK 0x1
> +#define YSTORM_FCOE_CONN_ST_CTX_INNER_VLAN_FLAG_SHIFT 0
> +#define YSTORM_FCOE_CONN_ST_CTX_OUTER_VLAN_FLAG_MASK 0x1
> +#define YSTORM_FCOE_CONN_ST_CTX_OUTER_VLAN_FLAG_SHIFT 1
> +#define YSTORM_FCOE_CONN_ST_CTX_RSRV_MASK 0x3F
> +#define YSTORM_FCOE_CONN_ST_CTX_RSRV_SHIFT 2
> + u8 fcp_xfer_size;
> + u8 reserved3[2];
> +};
> +
> +struct fcoe_vlan_fields {
> + __le16 fields;
> +#define FCOE_VLAN_FIELDS_VID_MASK 0xFFF
> +#define FCOE_VLAN_FIELDS_VID_SHIFT 0
> +#define FCOE_VLAN_FIELDS_CLI_MASK 0x1
> +#define FCOE_VLAN_FIELDS_CLI_SHIFT 12
> +#define FCOE_VLAN_FIELDS_PRI_MASK 0x7
> +#define FCOE_VLAN_FIELDS_PRI_SHIFT 13
> +};
> +
> +union fcoe_vlan_field_union {
> + struct fcoe_vlan_fields fields;
> + __le16 val;
> +};
> +
> +union fcoe_vlan_vif_field_union {
> + union fcoe_vlan_field_union vlan;
> + __le16 vif;
> +};
> +
> +struct pstorm_fcoe_eth_context_section {
> + u8 remote_addr_3;
> + u8 remote_addr_2;
> + u8 remote_addr_1;
> + u8 remote_addr_0;
> + u8 local_addr_1;
> + u8 local_addr_0;
> + u8 remote_addr_5;
> + u8 remote_addr_4;
> + u8 local_addr_5;
> + u8 local_addr_4;
> + u8 local_addr_3;
> + u8 local_addr_2;
> + union fcoe_vlan_vif_field_union vif_outer_vlan;
> + __le16 vif_outer_eth_type;
> + union fcoe_vlan_vif_field_union inner_vlan;
> + __le16 inner_eth_type;
> +};
> +
> +struct pstorm_fcoe_conn_st_ctx {
> + u8 func_mode;
> + u8 cos;
> + u8 conf_version;
> + u8 rsrv;
> + __le16 stat_ram_addr;
> + __le16 mss;
> + struct regpair abts_cleanup_addr;
> + struct pstorm_fcoe_eth_context_section eth;
> + u8 sid_2;
> + u8 sid_1;
> + u8 sid_0;
> + u8 flags;
> +#define PSTORM_FCOE_CONN_ST_CTX_VNTAG_VLAN_MASK 0x1
> +#define PSTORM_FCOE_CONN_ST_CTX_VNTAG_VLAN_SHIFT 0
> +#define PSTORM_FCOE_CONN_ST_CTX_SUPPORT_REC_RR_TOV_MASK 0x1
> +#define PSTORM_FCOE_CONN_ST_CTX_SUPPORT_REC_RR_TOV_SHIFT 1
> +#define PSTORM_FCOE_CONN_ST_CTX_INNER_VLAN_FLAG_MASK 0x1
> +#define PSTORM_FCOE_CONN_ST_CTX_INNER_VLAN_FLAG_SHIFT 2
> +#define PSTORM_FCOE_CONN_ST_CTX_OUTER_VLAN_FLAG_MASK 0x1
> +#define PSTORM_FCOE_CONN_ST_CTX_OUTER_VLAN_FLAG_SHIFT 3
> +#define PSTORM_FCOE_CONN_ST_CTX_RESERVED_MASK 0xF
> +#define PSTORM_FCOE_CONN_ST_CTX_RESERVED_SHIFT 4
> + u8 did_2;
> + u8 did_1;
> + u8 did_0;
> + u8 src_mac_index;
> + __le16 rec_rr_tov_val;
> + u8 q_relative_offset;
> + u8 reserved1;
> +};
> +
> +struct xstorm_fcoe_conn_st_ctx {
> + u8 func_mode;
> + u8 src_mac_index;
> + u8 conf_version;
> + u8 cached_wqes_avail;
> + __le16 stat_ram_addr;
> + u8 flags;
> +#define XSTORM_FCOE_CONN_ST_CTX_SQ_DEFERRED_MASK 0x1
> +#define XSTORM_FCOE_CONN_ST_CTX_SQ_DEFERRED_SHIFT 0
> +#define XSTORM_FCOE_CONN_ST_CTX_INNER_VLAN_FLAG_MASK 0x1
> +#define XSTORM_FCOE_CONN_ST_CTX_INNER_VLAN_FLAG_SHIFT 1
> +#define XSTORM_FCOE_CONN_ST_CTX_INNER_VLAN_FLAG_ORIG_MASK 0x1
> +#define XSTORM_FCOE_CONN_ST_CTX_INNER_VLAN_FLAG_ORIG_SHIFT 2
> +#define XSTORM_FCOE_CONN_ST_CTX_LAST_QUEUE_HANDLED_MASK 0x3
> +#define XSTORM_FCOE_CONN_ST_CTX_LAST_QUEUE_HANDLED_SHIFT 3
> +#define XSTORM_FCOE_CONN_ST_CTX_RSRV_MASK 0x7
> +#define XSTORM_FCOE_CONN_ST_CTX_RSRV_SHIFT 5
> + u8 cached_wqes_offset;
> + u8 reserved2;
> + u8 eth_hdr_size;
> + u8 seq_id;
> + u8 max_conc_seqs;
> + __le16 num_pages_in_pbl;
> + __le16 reserved;
> + struct regpair sq_pbl_addr;
> + struct regpair sq_curr_page_addr;
> + struct regpair sq_next_page_addr;
> + struct regpair xferq_pbl_addr;
> + struct regpair xferq_curr_page_addr;
> + struct regpair xferq_next_page_addr;
> + struct regpair respq_pbl_addr;
> + struct regpair respq_curr_page_addr;
> + struct regpair respq_next_page_addr;
> + __le16 mtu;
> + __le16 tx_max_fc_pay_len;
> + __le16 max_fc_payload_len;
> + __le16 min_frame_size;
> + __le16 sq_pbl_next_index;
> + __le16 respq_pbl_next_index;
> + u8 fcp_cmd_byte_credit;
> + u8 fcp_rsp_byte_credit;
> + __le16 protection_info;
> +#define XSTORM_FCOE_CONN_ST_CTX_PROTECTION_PERF_MASK 0x1
> +#define XSTORM_FCOE_CONN_ST_CTX_PROTECTION_PERF_SHIFT 0
> +#define XSTORM_FCOE_CONN_ST_CTX_SUPPORT_PROTECTION_MASK 0x1
> +#define XSTORM_FCOE_CONN_ST_CTX_SUPPORT_PROTECTION_SHIFT 1
> +#define XSTORM_FCOE_CONN_ST_CTX_VALID_MASK 0x1
> +#define XSTORM_FCOE_CONN_ST_CTX_VALID_SHIFT 2
> +#define XSTORM_FCOE_CONN_ST_CTX_FRAME_PROT_ALIGNED_MASK 0x1
> +#define XSTORM_FCOE_CONN_ST_CTX_FRAME_PROT_ALIGNED_SHIFT 3
> +#define XSTORM_FCOE_CONN_ST_CTX_RESERVED3_MASK 0xF
> +#define XSTORM_FCOE_CONN_ST_CTX_RESERVED3_SHIFT 4
> +#define XSTORM_FCOE_CONN_ST_CTX_DST_PROTECTION_PER_MSS_MASK 0xFF
> +#define XSTORM_FCOE_CONN_ST_CTX_DST_PROTECTION_PER_MSS_SHIFT 8
> + __le16 xferq_pbl_next_index;
> + __le16 page_size;
> + u8 mid_seq;
> + u8 fcp_xfer_byte_credit;
> + u8 reserved1[2];
> + struct fcoe_wqe cached_wqes[16];
> +};
> +
> +struct xstorm_fcoe_conn_ag_ctx {
> + u8 reserved0;
> + u8 fcoe_state;
> + u8 flags0;
> +#define XSTORM_FCOE_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED1_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED1_SHIFT 1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED2_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED2_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_EXIST_IN_QM3_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_EXIST_IN_QM3_SHIFT 3
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED3_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED3_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED4_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED4_SHIFT 5
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED5_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED5_SHIFT 6
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED6_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED6_SHIFT 7
> + u8 flags1;
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED7_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED7_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED8_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED8_SHIFT 1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED9_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED9_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT11_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT11_SHIFT 3
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT12_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT12_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT13_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT13_SHIFT 5
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT14_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT14_SHIFT 6
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT15_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT15_SHIFT 7
> + u8 flags2;
> +#define XSTORM_FCOE_CONN_AG_CTX_CF0_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF0_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_CF1_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF1_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_CF2_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF2_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_CF3_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF3_SHIFT 6
> + u8 flags3;
> +#define XSTORM_FCOE_CONN_AG_CTX_CF4_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF4_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_CF5_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF5_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_CF6_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF6_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_CF7_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF7_SHIFT 6
> + u8 flags4;
> +#define XSTORM_FCOE_CONN_AG_CTX_CF8_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF8_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_CF9_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF9_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_CF10_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF10_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_CF11_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF11_SHIFT 6
> + u8 flags5;
> +#define XSTORM_FCOE_CONN_AG_CTX_CF12_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF12_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_CF13_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF13_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_CF14_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF14_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_CF15_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF15_SHIFT 6
> + u8 flags6;
> +#define XSTORM_FCOE_CONN_AG_CTX_CF16_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF16_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_CF17_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF17_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_CF18_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF18_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_DQ_CF_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_DQ_CF_SHIFT 6
> + u8 flags7;
> +#define XSTORM_FCOE_CONN_AG_CTX_FLUSH_Q0_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_FLUSH_Q0_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED10_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED10_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_SLOW_PATH_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_SLOW_PATH_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_CF0EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF0EN_SHIFT 6
> +#define XSTORM_FCOE_CONN_AG_CTX_CF1EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF1EN_SHIFT 7
> + u8 flags8;
> +#define XSTORM_FCOE_CONN_AG_CTX_CF2EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF2EN_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_CF3EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF3EN_SHIFT 1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF4EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF4EN_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_CF5EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF5EN_SHIFT 3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF6EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF6EN_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_CF7EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF7EN_SHIFT 5
> +#define XSTORM_FCOE_CONN_AG_CTX_CF8EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF8EN_SHIFT 6
> +#define XSTORM_FCOE_CONN_AG_CTX_CF9EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF9EN_SHIFT 7
> + u8 flags9;
> +#define XSTORM_FCOE_CONN_AG_CTX_CF10EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF10EN_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_CF11EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF11EN_SHIFT 1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF12EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF12EN_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_CF13EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF13EN_SHIFT 3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF14EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF14EN_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_CF15EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF15EN_SHIFT 5
> +#define XSTORM_FCOE_CONN_AG_CTX_CF16EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF16EN_SHIFT 6
> +#define XSTORM_FCOE_CONN_AG_CTX_CF17EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF17EN_SHIFT 7
> + u8 flags10;
> +#define XSTORM_FCOE_CONN_AG_CTX_CF18EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF18EN_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_DQ_CF_EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_DQ_CF_EN_SHIFT 1
> +#define XSTORM_FCOE_CONN_AG_CTX_FLUSH_Q0_EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_FLUSH_Q0_EN_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED11_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED11_SHIFT 3
> +#define XSTORM_FCOE_CONN_AG_CTX_SLOW_PATH_EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_SLOW_PATH_EN_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_CF23EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_CF23EN_SHIFT 5
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED12_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED12_SHIFT 6
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED13_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED13_SHIFT 7
> + u8 flags11;
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED14_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED14_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED15_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED15_SHIFT 1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED16_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESERVED16_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE5EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE5EN_SHIFT 3
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE6EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE6EN_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE7EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE7EN_SHIFT 5
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED1_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED1_SHIFT 6
> +#define XSTORM_FCOE_CONN_AG_CTX_XFERQ_DECISION_EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_XFERQ_DECISION_EN_SHIFT 7
> + u8 flags12;
> +#define XSTORM_FCOE_CONN_AG_CTX_SQ_DECISION_EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_SQ_DECISION_EN_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE11EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE11EN_SHIFT 1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED2_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED2_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED3_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED3_SHIFT 3
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE14EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE14EN_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE15EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE15EN_SHIFT 5
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE16EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE16EN_SHIFT 6
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE17EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE17EN_SHIFT 7
> + u8 flags13;
> +#define XSTORM_FCOE_CONN_AG_CTX_RESPQ_DECISION_EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RESPQ_DECISION_EN_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE19EN_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_RULE19EN_SHIFT 1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED4_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED4_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED5_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED5_SHIFT 3
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED6_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED6_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED7_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED7_SHIFT 5
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED8_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED8_SHIFT 6
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED9_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_A0_RESERVED9_SHIFT 7
> + u8 flags14;
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT16_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT16_SHIFT 0
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT17_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT17_SHIFT 1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT18_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT18_SHIFT 2
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT19_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT19_SHIFT 3
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT20_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT20_SHIFT 4
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT21_MASK 0x1
> +#define XSTORM_FCOE_CONN_AG_CTX_BIT21_SHIFT 5
> +#define XSTORM_FCOE_CONN_AG_CTX_CF23_MASK 0x3
> +#define XSTORM_FCOE_CONN_AG_CTX_CF23_SHIFT 6
> + u8 byte2;
> + __le16 physical_q0;
> + __le16 word1;
> + __le16 word2;
> + __le16 sq_cons;
> + __le16 sq_prod;
> + __le16 xferq_prod;
> + __le16 xferq_cons;
> + u8 byte3;
> + u8 byte4;
> + u8 byte5;
> + u8 byte6;
> + __le32 remain_io;
> + __le32 reg1;
> + __le32 reg2;
> + __le32 reg3;
> + __le32 reg4;
> + __le32 reg5;
> + __le32 reg6;
> + __le16 respq_prod;
> + __le16 respq_cons;
> + __le16 word9;
> + __le16 word10;
> + __le32 reg7;
> + __le32 reg8;
> +};
> +
> +struct ustorm_fcoe_conn_st_ctx {
> + struct regpair respq_pbl_addr;
> + __le16 num_pages_in_pbl;
> + u8 ptu_log_page_size;
> + u8 log_page_size;
> + __le16 respq_prod;
> + u8 reserved[2];
> +};
> +
> +struct tstorm_fcoe_conn_ag_ctx {
> + u8 reserved0;
> + u8 fcoe_state;
> + u8 flags0;
> +#define TSTORM_FCOE_CONN_AG_CTX_EXIST_IN_QM0_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_EXIST_IN_QM0_SHIFT 0
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT1_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT1_SHIFT 1
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT2_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT2_SHIFT 2
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT3_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT3_SHIFT 3
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT4_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT4_SHIFT 4
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT5_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_BIT5_SHIFT 5
> +#define TSTORM_FCOE_CONN_AG_CTX_DUMMY_TIMER_CF_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_DUMMY_TIMER_CF_SHIFT 6
> + u8 flags1;
> +#define TSTORM_FCOE_CONN_AG_CTX_FLUSH_Q0_CF_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_FLUSH_Q0_CF_SHIFT 0
> +#define TSTORM_FCOE_CONN_AG_CTX_CF2_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_CF2_SHIFT 2
> +#define TSTORM_FCOE_CONN_AG_CTX_TIMER_STOP_ALL_CF_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_TIMER_STOP_ALL_CF_SHIFT 4
> +#define TSTORM_FCOE_CONN_AG_CTX_CF4_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_CF4_SHIFT 6
> + u8 flags2;
> +#define TSTORM_FCOE_CONN_AG_CTX_CF5_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_CF5_SHIFT 0
> +#define TSTORM_FCOE_CONN_AG_CTX_CF6_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_CF6_SHIFT 2
> +#define TSTORM_FCOE_CONN_AG_CTX_CF7_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_CF7_SHIFT 4
> +#define TSTORM_FCOE_CONN_AG_CTX_CF8_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_CF8_SHIFT 6
> + u8 flags3;
> +#define TSTORM_FCOE_CONN_AG_CTX_CF9_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_CF9_SHIFT 0
> +#define TSTORM_FCOE_CONN_AG_CTX_CF10_MASK 0x3
> +#define TSTORM_FCOE_CONN_AG_CTX_CF10_SHIFT 2
> +#define TSTORM_FCOE_CONN_AG_CTX_DUMMY_TIMER_CF_EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_DUMMY_TIMER_CF_EN_SHIFT 4
> +#define TSTORM_FCOE_CONN_AG_CTX_FLUSH_Q0_CF_EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_FLUSH_Q0_CF_EN_SHIFT 5
> +#define TSTORM_FCOE_CONN_AG_CTX_CF2EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_CF2EN_SHIFT 6
> +#define TSTORM_FCOE_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_TIMER_STOP_ALL_CF_EN_SHIFT 7
> + u8 flags4;
> +#define TSTORM_FCOE_CONN_AG_CTX_CF4EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_CF4EN_SHIFT 0
> +#define TSTORM_FCOE_CONN_AG_CTX_CF5EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_CF5EN_SHIFT 1
> +#define TSTORM_FCOE_CONN_AG_CTX_CF6EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_CF6EN_SHIFT 2
> +#define TSTORM_FCOE_CONN_AG_CTX_CF7EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_CF7EN_SHIFT 3
> +#define TSTORM_FCOE_CONN_AG_CTX_CF8EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_CF8EN_SHIFT 4
> +#define TSTORM_FCOE_CONN_AG_CTX_CF9EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_CF9EN_SHIFT 5
> +#define TSTORM_FCOE_CONN_AG_CTX_CF10EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_CF10EN_SHIFT 6
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE0EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE0EN_SHIFT 7
> + u8 flags5;
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE1EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE1EN_SHIFT 0
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE2EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE2EN_SHIFT 1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE3EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE3EN_SHIFT 2
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE4EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE4EN_SHIFT 3
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE5EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE5EN_SHIFT 4
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE6EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE6EN_SHIFT 5
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE7EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE7EN_SHIFT 6
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE8EN_MASK 0x1
> +#define TSTORM_FCOE_CONN_AG_CTX_RULE8EN_SHIFT 7
> + __le32 reg0;
> + __le32 reg1;
> +};
> +
> +struct ustorm_fcoe_conn_ag_ctx {
> + u8 byte0;
> + u8 byte1;
> + u8 flags0;
> +#define USTORM_FCOE_CONN_AG_CTX_BIT0_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_BIT0_SHIFT 0
> +#define USTORM_FCOE_CONN_AG_CTX_BIT1_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_BIT1_SHIFT 1
> +#define USTORM_FCOE_CONN_AG_CTX_CF0_MASK 0x3
> +#define USTORM_FCOE_CONN_AG_CTX_CF0_SHIFT 2
> +#define USTORM_FCOE_CONN_AG_CTX_CF1_MASK 0x3
> +#define USTORM_FCOE_CONN_AG_CTX_CF1_SHIFT 4
> +#define USTORM_FCOE_CONN_AG_CTX_CF2_MASK 0x3
> +#define USTORM_FCOE_CONN_AG_CTX_CF2_SHIFT 6
> + u8 flags1;
> +#define USTORM_FCOE_CONN_AG_CTX_CF3_MASK 0x3
> +#define USTORM_FCOE_CONN_AG_CTX_CF3_SHIFT 0
> +#define USTORM_FCOE_CONN_AG_CTX_CF4_MASK 0x3
> +#define USTORM_FCOE_CONN_AG_CTX_CF4_SHIFT 2
> +#define USTORM_FCOE_CONN_AG_CTX_CF5_MASK 0x3
> +#define USTORM_FCOE_CONN_AG_CTX_CF5_SHIFT 4
> +#define USTORM_FCOE_CONN_AG_CTX_CF6_MASK 0x3
> +#define USTORM_FCOE_CONN_AG_CTX_CF6_SHIFT 6
> + u8 flags2;
> +#define USTORM_FCOE_CONN_AG_CTX_CF0EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_CF0EN_SHIFT 0
> +#define USTORM_FCOE_CONN_AG_CTX_CF1EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_CF1EN_SHIFT 1
> +#define USTORM_FCOE_CONN_AG_CTX_CF2EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_CF2EN_SHIFT 2
> +#define USTORM_FCOE_CONN_AG_CTX_CF3EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_CF3EN_SHIFT 3
> +#define USTORM_FCOE_CONN_AG_CTX_CF4EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_CF4EN_SHIFT 4
> +#define USTORM_FCOE_CONN_AG_CTX_CF5EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_CF5EN_SHIFT 5
> +#define USTORM_FCOE_CONN_AG_CTX_CF6EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_CF6EN_SHIFT 6
> +#define USTORM_FCOE_CONN_AG_CTX_RULE0EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE0EN_SHIFT 7
> + u8 flags3;
> +#define USTORM_FCOE_CONN_AG_CTX_RULE1EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE1EN_SHIFT 0
> +#define USTORM_FCOE_CONN_AG_CTX_RULE2EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE2EN_SHIFT 1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE3EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE3EN_SHIFT 2
> +#define USTORM_FCOE_CONN_AG_CTX_RULE4EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE4EN_SHIFT 3
> +#define USTORM_FCOE_CONN_AG_CTX_RULE5EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE5EN_SHIFT 4
> +#define USTORM_FCOE_CONN_AG_CTX_RULE6EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE6EN_SHIFT 5
> +#define USTORM_FCOE_CONN_AG_CTX_RULE7EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE7EN_SHIFT 6
> +#define USTORM_FCOE_CONN_AG_CTX_RULE8EN_MASK 0x1
> +#define USTORM_FCOE_CONN_AG_CTX_RULE8EN_SHIFT 7
> + u8 byte2;
> + u8 byte3;
> + __le16 word0;
> + __le16 word1;
> + __le32 reg0;
> + __le32 reg1;
> + __le32 reg2;
> + __le32 reg3;
> + __le16 word2;
> + __le16 word3;
> +};
> +
> +struct tstorm_fcoe_conn_st_ctx {
> + __le16 stat_ram_addr;
> + __le16 rx_max_fc_payload_len;
> + __le16 e_d_tov_val;
> + u8 flags;
> +#define TSTORM_FCOE_CONN_ST_CTX_INC_SEQ_CNT_MASK 0x1
> +#define TSTORM_FCOE_CONN_ST_CTX_INC_SEQ_CNT_SHIFT 0
> +#define TSTORM_FCOE_CONN_ST_CTX_SUPPORT_CONF_MASK 0x1
> +#define TSTORM_FCOE_CONN_ST_CTX_SUPPORT_CONF_SHIFT 1
> +#define TSTORM_FCOE_CONN_ST_CTX_DEF_Q_IDX_MASK 0x3F
> +#define TSTORM_FCOE_CONN_ST_CTX_DEF_Q_IDX_SHIFT 2
> + u8 timers_cleanup_invocation_cnt;
> + __le32 reserved1[2];
> + __le32 dst_mac_address_bytes0to3;
> + __le16 dst_mac_address_bytes4to5;
> + __le16 ramrod_echo;
> + u8 flags1;
> +#define TSTORM_FCOE_CONN_ST_CTX_MODE_MASK 0x3
> +#define TSTORM_FCOE_CONN_ST_CTX_MODE_SHIFT 0
> +#define TSTORM_FCOE_CONN_ST_CTX_RESERVED_MASK 0x3F
> +#define TSTORM_FCOE_CONN_ST_CTX_RESERVED_SHIFT 2
> + u8 q_relative_offset;
> + u8 bdq_resource_id;
> + u8 reserved0[5];
> +};
> +
> +struct mstorm_fcoe_conn_ag_ctx {
> + u8 byte0;
> + u8 byte1;
> + u8 flags0;
> +#define MSTORM_FCOE_CONN_AG_CTX_BIT0_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_BIT0_SHIFT 0
> +#define MSTORM_FCOE_CONN_AG_CTX_BIT1_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_BIT1_SHIFT 1
> +#define MSTORM_FCOE_CONN_AG_CTX_CF0_MASK 0x3
> +#define MSTORM_FCOE_CONN_AG_CTX_CF0_SHIFT 2
> +#define MSTORM_FCOE_CONN_AG_CTX_CF1_MASK 0x3
> +#define MSTORM_FCOE_CONN_AG_CTX_CF1_SHIFT 4
> +#define MSTORM_FCOE_CONN_AG_CTX_CF2_MASK 0x3
> +#define MSTORM_FCOE_CONN_AG_CTX_CF2_SHIFT 6
> + u8 flags1;
> +#define MSTORM_FCOE_CONN_AG_CTX_CF0EN_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_CF0EN_SHIFT 0
> +#define MSTORM_FCOE_CONN_AG_CTX_CF1EN_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_CF1EN_SHIFT 1
> +#define MSTORM_FCOE_CONN_AG_CTX_CF2EN_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_CF2EN_SHIFT 2
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE0EN_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE0EN_SHIFT 3
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE1EN_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE1EN_SHIFT 4
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE2EN_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE2EN_SHIFT 5
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE3EN_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE3EN_SHIFT 6
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE4EN_MASK 0x1
> +#define MSTORM_FCOE_CONN_AG_CTX_RULE4EN_SHIFT 7
> + __le16 word0;
> + __le16 word1;
> + __le32 reg0;
> + __le32 reg1;
> +};
> +
> +struct fcoe_mstorm_fcoe_conn_st_ctx_fp {
> + __le16 xfer_prod;
> + __le16 reserved1;
> + u8 protection_info;
> +#define FCOE_MSTORM_FCOE_CONN_ST_CTX_FP_SUPPORT_PROTECTION_MASK 0x1
> +#define FCOE_MSTORM_FCOE_CONN_ST_CTX_FP_SUPPORT_PROTECTION_SHIFT 0
> +#define FCOE_MSTORM_FCOE_CONN_ST_CTX_FP_VALID_MASK 0x1
> +#define FCOE_MSTORM_FCOE_CONN_ST_CTX_FP_VALID_SHIFT 1
> +#define FCOE_MSTORM_FCOE_CONN_ST_CTX_FP_RESERVED0_MASK 0x3F
> +#define FCOE_MSTORM_FCOE_CONN_ST_CTX_FP_RESERVED0_SHIFT 2
> + u8 q_relative_offset;
> + u8 reserved2[2];
> +};
> +
> +struct fcoe_mstorm_fcoe_conn_st_ctx_non_fp {
> + __le16 conn_id;
> + __le16 stat_ram_addr;
> + __le16 num_pages_in_pbl;
> + u8 ptu_log_page_size;
> + u8 log_page_size;
> + __le16 unsolicited_cq_count;
> + __le16 cmdq_count;
> + u8 bdq_resource_id;
> + u8 reserved0[3];
> + struct regpair xferq_pbl_addr;
> + struct regpair reserved1;
> + struct regpair reserved2[3];
> +};
> +
> +struct mstorm_fcoe_conn_st_ctx {
> + struct fcoe_mstorm_fcoe_conn_st_ctx_fp fp;
> + struct fcoe_mstorm_fcoe_conn_st_ctx_non_fp non_fp;
> +};
> +
> +struct fcoe_conn_context {
> + struct ystorm_fcoe_conn_st_ctx ystorm_st_context;
> + struct pstorm_fcoe_conn_st_ctx pstorm_st_context;
> + struct regpair pstorm_st_padding[2];
> + struct xstorm_fcoe_conn_st_ctx xstorm_st_context;
> + struct xstorm_fcoe_conn_ag_ctx xstorm_ag_context;
> + struct regpair xstorm_ag_padding[6];
> + struct ustorm_fcoe_conn_st_ctx ustorm_st_context;
> + struct regpair ustorm_st_padding[2];
> + struct tstorm_fcoe_conn_ag_ctx tstorm_ag_context;
> + struct regpair tstorm_ag_padding[2];
> + struct timers_context timer_context;
> + struct ustorm_fcoe_conn_ag_ctx ustorm_ag_context;
> + struct tstorm_fcoe_conn_st_ctx tstorm_st_context;
> + struct mstorm_fcoe_conn_ag_ctx mstorm_ag_context;
> + struct mstorm_fcoe_conn_st_ctx mstorm_st_context;
> +};
> +
> +struct fcoe_conn_offload_ramrod_params {
> + struct fcoe_conn_offload_ramrod_data offload_ramrod_data;
> +};
> +
> +struct fcoe_conn_terminate_ramrod_params {
> + struct fcoe_conn_terminate_ramrod_data terminate_ramrod_data;
> +};
> +
> +enum fcoe_event_type {
> + FCOE_EVENT_INIT_FUNC,
> + FCOE_EVENT_DESTROY_FUNC,
> + FCOE_EVENT_STAT_FUNC,
> + FCOE_EVENT_OFFLOAD_CONN,
> + FCOE_EVENT_TERMINATE_CONN,
> + FCOE_EVENT_ERROR,
> + MAX_FCOE_EVENT_TYPE
> +};
> +
> +struct fcoe_init_ramrod_params {
> + struct fcoe_init_func_ramrod_data init_ramrod_data;
> +};
> +
> +enum fcoe_ramrod_cmd_id {
> + FCOE_RAMROD_CMD_ID_INIT_FUNC,
> + FCOE_RAMROD_CMD_ID_DESTROY_FUNC,
> + FCOE_RAMROD_CMD_ID_STAT_FUNC,
> + FCOE_RAMROD_CMD_ID_OFFLOAD_CONN,
> + FCOE_RAMROD_CMD_ID_TERMINATE_CONN,
> + MAX_FCOE_RAMROD_CMD_ID
> +};
> +
> +struct fcoe_stat_ramrod_params {
> + struct fcoe_stat_ramrod_data stat_ramrod_data;
> +};
> +
> +struct ystorm_fcoe_conn_ag_ctx {
> + u8 byte0;
> + u8 byte1;
> + u8 flags0;
> +#define YSTORM_FCOE_CONN_AG_CTX_BIT0_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_BIT0_SHIFT 0
> +#define YSTORM_FCOE_CONN_AG_CTX_BIT1_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_BIT1_SHIFT 1
> +#define YSTORM_FCOE_CONN_AG_CTX_CF0_MASK 0x3
> +#define YSTORM_FCOE_CONN_AG_CTX_CF0_SHIFT 2
> +#define YSTORM_FCOE_CONN_AG_CTX_CF1_MASK 0x3
> +#define YSTORM_FCOE_CONN_AG_CTX_CF1_SHIFT 4
> +#define YSTORM_FCOE_CONN_AG_CTX_CF2_MASK 0x3
> +#define YSTORM_FCOE_CONN_AG_CTX_CF2_SHIFT 6
> + u8 flags1;
> +#define YSTORM_FCOE_CONN_AG_CTX_CF0EN_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_CF0EN_SHIFT 0
> +#define YSTORM_FCOE_CONN_AG_CTX_CF1EN_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_CF1EN_SHIFT 1
> +#define YSTORM_FCOE_CONN_AG_CTX_CF2EN_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_CF2EN_SHIFT 2
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE0EN_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE0EN_SHIFT 3
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE1EN_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE1EN_SHIFT 4
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE2EN_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE2EN_SHIFT 5
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE3EN_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE3EN_SHIFT 6
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE4EN_MASK 0x1
> +#define YSTORM_FCOE_CONN_AG_CTX_RULE4EN_SHIFT 7
> + u8 byte2;
> + u8 byte3;
> + __le16 word0;
> + __le32 reg0;
> + __le32 reg1;
> + __le16 word1;
> + __le16 word2;
> + __le16 word3;
> + __le16 word4;
> + __le32 reg2;
> + __le32 reg3;
> +};
> +
> struct ystorm_iscsi_conn_st_ctx {
> __le32 reserved[4];
> };
> @@ -8411,6 +9180,7 @@ struct public_func {
> #define FUNC_MF_CFG_PROTOCOL_SHIFT 4
> #define FUNC_MF_CFG_PROTOCOL_ETHERNET 0x00000000
> #define FUNC_MF_CFG_PROTOCOL_ISCSI 0x00000010
> +#define FUNC_MF_CFG_PROTOCOL_FCOE 0x00000020
> #define FUNC_MF_CFG_PROTOCOL_ROCE 0x00000030
> #define FUNC_MF_CFG_PROTOCOL_MAX 0x00000030
>
> @@ -8505,6 +9275,13 @@ struct lan_stats_stc {
> u32 rserved;
> };
>
> +struct fcoe_stats_stc {
> + u64 rx_pkts;
> + u64 tx_pkts;
> + u32 fcs_err;
> + u32 login_failure;
> +};
> +
> struct ocbb_data_stc {
> u32 ocbb_host_addr;
> u32 ocsd_host_addr;
> @@ -8578,6 +9355,7 @@ struct resource_info {
> struct drv_version_stc drv_version;
>
> struct lan_stats_stc lan_stats;
> + struct fcoe_stats_stc fcoe_stats;
> struct ocbb_data_stc ocbb_info;
> struct temperature_status_stc temp_info;
> struct resource_info resource;
> @@ -8881,6 +9659,7 @@ struct nvm_cfg1_glob {
> u32 misc_sig;
> u32 device_capabilities;
> #define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ETHERNET 0x1
> +#define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_FCOE 0x2
> #define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ISCSI 0x4
> #define NVM_CFG1_GLOB_DEVICE_CAPABILITIES_ROCE 0x8
> u32 power_dissipated;
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_hw.c b/drivers/net/ethernet/qlogic/qed/qed_hw.c
> index 6e4fae9..25b17ac 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_hw.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_hw.c
> @@ -817,6 +817,9 @@ u16 qed_get_qm_pq(struct qed_hwfn *p_hwfn,
> if (pq_id > p_hwfn->qm_info.num_pf_rls)
> pq_id = p_hwfn->qm_info.offload_pq;
> break;
> + case PROTOCOLID_FCOE:
> + pq_id = p_hwfn->qm_info.offload_pq;
> + break;
> default:
> pq_id = 0;
> }
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> index 8e5cb76..ab68455 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> @@ -1111,6 +1111,9 @@ static int qed_sp_ll2_tx_queue_start(struct qed_hwfn *p_hwfn,
> p_ramrod->qm_pq_id = cpu_to_le16(pq_id);
>
> switch (conn_type) {
> + case QED_LL2_TYPE_FCOE:
> + p_ramrod->conn_type = PROTOCOLID_FCOE;
> + break;
> case QED_LL2_TYPE_ISCSI:
> case QED_LL2_TYPE_ISCSI_OOO:
> p_ramrod->conn_type = PROTOCOLID_ISCSI;
> @@ -1447,6 +1450,15 @@ int qed_ll2_establish_connection(struct qed_hwfn *p_hwfn, u8 connection_handle)
>
> qed_ll2_establish_connection_ooo(p_hwfn, p_ll2_conn);
>
> + if (p_ll2_conn->conn_type == QED_LL2_TYPE_FCOE) {
> + qed_llh_add_protocol_filter(p_hwfn, p_hwfn->p_main_ptt,
> + 0x8906, 0,
> + QED_LLH_FILTER_ETHERTYPE);
> + qed_llh_add_protocol_filter(p_hwfn, p_hwfn->p_main_ptt,
> + 0x8914, 0,
> + QED_LLH_FILTER_ETHERTYPE);
> + }
> +
> return rc;
> }
>
> @@ -1820,6 +1832,15 @@ int qed_ll2_terminate_connection(struct qed_hwfn *p_hwfn, u8 connection_handle)
> if (p_ll2_conn->conn_type == QED_LL2_TYPE_ISCSI_OOO)
> qed_ooo_release_all_isles(p_hwfn, p_hwfn->p_ooo_info);
>
> + if (p_ll2_conn->conn_type == QED_LL2_TYPE_FCOE) {
> + qed_llh_remove_protocol_filter(p_hwfn, p_hwfn->p_main_ptt,
> + 0x8906, 0,
> + QED_LLH_FILTER_ETHERTYPE);
> + qed_llh_remove_protocol_filter(p_hwfn, p_hwfn->p_main_ptt,
> + 0x8914, 0,
> + QED_LLH_FILTER_ETHERTYPE);
> + }
> +
> return rc;
> }
>
> @@ -2028,6 +2049,10 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
> }
>
> switch (QED_LEADING_HWFN(cdev)->hw_info.personality) {
> + case QED_PCI_FCOE:
> + conn_type = QED_LL2_TYPE_FCOE;
> + gsi_enable = 0;
> + break;
> case QED_PCI_ISCSI:
> conn_type = QED_LL2_TYPE_ISCSI;
> gsi_enable = 0;
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.h b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
> index 6625a3a..cee357b 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.h
> @@ -31,7 +31,7 @@ enum qed_ll2_roce_flavor_type {
> };
>
> enum qed_ll2_conn_type {
> - QED_LL2_TYPE_RESERVED,
> + QED_LL2_TYPE_FCOE,
> QED_LL2_TYPE_ISCSI,
> QED_LL2_TYPE_TEST,
> QED_LL2_TYPE_ISCSI_OOO,
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
> index aeb98d8..4401147 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_main.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
> @@ -29,9 +29,11 @@
> #include "qed_sp.h"
> #include "qed_dev_api.h"
> #include "qed_ll2.h"
> +#include "qed_fcoe.h"
> #include "qed_mcp.h"
> #include "qed_hw.h"
> #include "qed_selftest.h"
> +#include "qed_debug.h"
>
> #define QED_ROCE_QPS (8192)
> #define QED_ROCE_DPIS (8)
> @@ -1553,6 +1555,8 @@ static int qed_update_mtu(struct qed_dev *cdev, u16 mtu)
> .sb_release = &qed_sb_release,
> .simd_handler_config = &qed_simd_handler_config,
> .simd_handler_clean = &qed_simd_handler_clean,
> + .dbg_grc = &qed_dbg_grc,
> + .dbg_grc_size = &qed_dbg_grc_size,
> .can_link_change = &qed_can_link_change,
> .set_link = &qed_set_link,
> .get_link = &qed_get_current_link,
> @@ -1586,6 +1590,9 @@ void qed_get_protocol_stats(struct qed_dev *cdev,
> stats->lan_stats.ucast_tx_pkts = eth_stats.tx_ucast_pkts;
> stats->lan_stats.fcs_err = -1;
> break;
> + case QED_MCP_FCOE_STATS:
> + qed_get_protocol_stats_fcoe(cdev, &stats->fcoe_stats);
> + break;
> default:
> DP_ERR(cdev, "Invalid protocol type = %d\n", type);
> return;
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.c b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
> index 6dd3ce4..f8a467e 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.c
> @@ -1104,6 +1104,9 @@ int qed_mcp_get_media_type(struct qed_dev *cdev, u32 *p_media_type)
> case FUNC_MF_CFG_PROTOCOL_ISCSI:
> *p_proto = QED_PCI_ISCSI;
> break;
> + case FUNC_MF_CFG_PROTOCOL_FCOE:
> + *p_proto = QED_PCI_FCOE;
> + break;
> case FUNC_MF_CFG_PROTOCOL_ROCE:
> DP_NOTICE(p_hwfn, "RoCE personality is not a valid value!\n");
> /* Fallthrough */
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> index 407a2c1..863b9dd 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> @@ -13,6 +13,7 @@
> #include <linux/delay.h>
> #include <linux/slab.h>
> #include <linux/spinlock.h>
> +#include <linux/qed/qed_fcoe_if.h>
> #include "qed_hsi.h"
>
> struct qed_mcp_link_speed_params {
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> index 9754420..4890652 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> @@ -86,6 +86,8 @@
> 0x1e80000UL
> #define NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF \
> 0x5011f4UL
> +#define PRS_REG_SEARCH_RESP_INITIATOR_TYPE \
> + 0x1f0164UL
> #define PRS_REG_SEARCH_TCP \
> 0x1f0400UL
> #define PRS_REG_SEARCH_UDP \
> @@ -96,6 +98,12 @@
> 0x1f040cUL
> #define PRS_REG_SEARCH_OPENFLOW \
> 0x1f0434UL
> +#define PRS_REG_SEARCH_TAG1 \
> + 0x1f0444UL
> +#define PRS_REG_PKT_LEN_STAT_TAGS_NOT_COUNTED_FIRST \
> + 0x1f0a0cUL
> +#define PRS_REG_SEARCH_TCP_FIRST_FRAG \
> + 0x1f0410UL
> #define TM_REG_PF_ENABLE_CONN \
> 0x2c043cUL
> #define TM_REG_PF_ENABLE_TASK \
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp.h b/drivers/net/ethernet/qlogic/qed/qed_sp.h
> index 9c897bc..72454c9 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_sp.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_sp.h
> @@ -85,6 +85,10 @@ int qed_eth_cqe_completion(struct qed_hwfn *p_hwfn,
> struct rdma_srq_destroy_ramrod_data rdma_destroy_srq;
> struct rdma_srq_modify_ramrod_data rdma_modify_srq;
> struct roce_init_func_ramrod_data roce_init_func;
> + struct fcoe_init_ramrod_params fcoe_init;
> + struct fcoe_conn_offload_ramrod_params fcoe_conn_ofld;
> + struct fcoe_conn_terminate_ramrod_params fcoe_conn_terminate;
> + struct fcoe_stat_ramrod_params fcoe_stat;
>
> struct iscsi_slow_path_hdr iscsi_empty;
> struct iscsi_init_ramrod_params iscsi_init;
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
> index a39ef2e..8b5489b 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_sp_commands.c
> @@ -362,6 +362,9 @@ int qed_sp_pf_start(struct qed_hwfn *p_hwfn,
> case QED_PCI_ETH:
> p_ramrod->personality = PERSONALITY_ETH;
> break;
> + case QED_PCI_FCOE:
> + p_ramrod->personality = PERSONALITY_FCOE;
> + break;
> case QED_PCI_ISCSI:
> p_ramrod->personality = PERSONALITY_ISCSI;
> break;
> diff --git a/include/linux/qed/common_hsi.h b/include/linux/qed/common_hsi.h
> index 734deb0..729a882 100644
> --- a/include/linux/qed/common_hsi.h
> +++ b/include/linux/qed/common_hsi.h
> @@ -37,6 +37,7 @@
> #define COMMON_QUEUE_ENTRY_MAX_BYTE_SIZE 64
>
> #define ISCSI_CDU_TASK_SEG_TYPE 0
> +#define FCOE_CDU_TASK_SEG_TYPE 0
> #define RDMA_CDU_TASK_SEG_TYPE 1
>
> #define FW_ASSERT_GENERAL_ATTN_IDX 32
> @@ -180,6 +181,9 @@
> #define DQ_XCM_ETH_TX_BD_CONS_CMD DQ_XCM_AGG_VAL_SEL_WORD3
> #define DQ_XCM_ETH_TX_BD_PROD_CMD DQ_XCM_AGG_VAL_SEL_WORD4
> #define DQ_XCM_ETH_GO_TO_BD_CONS_CMD DQ_XCM_AGG_VAL_SEL_WORD5
> +#define DQ_XCM_FCOE_SQ_CONS_CMD DQ_XCM_AGG_VAL_SEL_WORD3
> +#define DQ_XCM_FCOE_SQ_PROD_CMD DQ_XCM_AGG_VAL_SEL_WORD4
> +#define DQ_XCM_FCOE_X_FERQ_PROD_CMD DQ_XCM_AGG_VAL_SEL_WORD5
> #define DQ_XCM_ISCSI_SQ_CONS_CMD DQ_XCM_AGG_VAL_SEL_WORD3
> #define DQ_XCM_ISCSI_SQ_PROD_CMD DQ_XCM_AGG_VAL_SEL_WORD4
> #define DQ_XCM_ISCSI_MORE_TO_SEND_SEQ_CMD DQ_XCM_AGG_VAL_SEL_REG3
> @@ -236,6 +240,7 @@
> #define DQ_XCM_ETH_TERMINATE_CMD BIT(DQ_XCM_AGG_FLG_SHIFT_CF19)
> #define DQ_XCM_ETH_SLOW_PATH_CMD BIT(DQ_XCM_AGG_FLG_SHIFT_CF22)
> #define DQ_XCM_ETH_TPH_EN_CMD BIT(DQ_XCM_AGG_FLG_SHIFT_CF23)
> +#define DQ_XCM_FCOE_SLOW_PATH_CMD BIT(DQ_XCM_AGG_FLG_SHIFT_CF22)
> #define DQ_XCM_ISCSI_DQ_FLUSH_CMD BIT(DQ_XCM_AGG_FLG_SHIFT_CF19)
> #define DQ_XCM_ISCSI_SLOW_PATH_CMD BIT(DQ_XCM_AGG_FLG_SHIFT_CF22)
> #define DQ_XCM_ISCSI_PROC_ONLY_CLEANUP_CMD BIT(DQ_XCM_AGG_FLG_SHIFT_CF23)
> @@ -266,6 +271,9 @@
> #define DQ_TCM_AGG_FLG_SHIFT_CF6 6
> #define DQ_TCM_AGG_FLG_SHIFT_CF7 7
> /* TCM agg counter flag selection (FW) */
> +#define DQ_TCM_FCOE_FLUSH_Q0_CMD BIT(DQ_TCM_AGG_FLG_SHIFT_CF1)
> +#define DQ_TCM_FCOE_DUMMY_TIMER_CMD BIT(DQ_TCM_AGG_FLG_SHIFT_CF2)
> +#define DQ_TCM_FCOE_TIMER_STOP_ALL_CMD BIT(DQ_TCM_AGG_FLG_SHIFT_CF3)
> #define DQ_TCM_ISCSI_FLUSH_Q0_CMD BIT(DQ_TCM_AGG_FLG_SHIFT_CF1)
> #define DQ_TCM_ISCSI_TIMER_STOP_ALL_CMD BIT(DQ_TCM_AGG_FLG_SHIFT_CF3)
>
> @@ -703,7 +711,7 @@ enum mf_mode {
> /* Per-protocol connection types */
> enum protocol_type {
> PROTOCOLID_ISCSI,
> - PROTOCOLID_RESERVED2,
> + PROTOCOLID_FCOE,
> PROTOCOLID_ROCE,
> PROTOCOLID_CORE,
> PROTOCOLID_ETH,
> diff --git a/include/linux/qed/fcoe_common.h b/include/linux/qed/fcoe_common.h
> new file mode 100644
> index 0000000..2e417a4
> --- /dev/null
> +++ b/include/linux/qed/fcoe_common.h
> @@ -0,0 +1,715 @@
> +/* QLogic qed NIC Driver
> + * Copyright (c) 2015 QLogic Corporation
> + *
> + * This software is available under the terms of the GNU General Public License
> + * (GPL) Version 2, available from the file COPYING in the main directory of
> + * this source tree.
> + */
> +
> +#ifndef __FCOE_COMMON__
> +#define __FCOE_COMMON__
> +/*********************/
> +/* FCOE FW CONSTANTS */
> +/*********************/
> +
> +#define FC_ABTS_REPLY_MAX_PAYLOAD_LEN 12
> +#define FCOE_MAX_SIZE_FCP_DATA_SUPER (8600)
> +
> +struct fcoe_abts_pkt {
> + __le32 abts_rsp_fc_payload_lo;
> + __le16 abts_rsp_rx_id;
> + u8 abts_rsp_rctl;
> + u8 reserved2;
> +};
> +
> +/* FCoE additional WQE (Sq/XferQ) information */
> +union fcoe_additional_info_union {
> + __le32 previous_tid;
> + __le32 parent_tid;
> + __le32 burst_length;
> + __le32 seq_rec_updated_offset;
> +};
> +
> +struct fcoe_exp_ro {
> + __le32 data_offset;
> + __le32 reserved;
> +};
> +
> +union fcoe_cleanup_addr_exp_ro_union {
> + struct regpair abts_rsp_fc_payload_hi;
> + struct fcoe_exp_ro exp_ro;
> +};
> +
> +/* FCoE Ramrod Command IDs */
> +enum fcoe_completion_status {
> + FCOE_COMPLETION_STATUS_SUCCESS,
> + FCOE_COMPLETION_STATUS_FCOE_VER_ERR,
> + FCOE_COMPLETION_STATUS_SRC_MAC_ADD_ARR_ERR,
> + MAX_FCOE_COMPLETION_STATUS
> +};
> +
> +struct fc_addr_nw {
> + u8 addr_lo;
> + u8 addr_mid;
> + u8 addr_hi;
> +};
> +
> +/* FCoE connection offload */
> +struct fcoe_conn_offload_ramrod_data {
> + struct regpair sq_pbl_addr;
> + struct regpair sq_curr_page_addr;
> + struct regpair sq_next_page_addr;
> + struct regpair xferq_pbl_addr;
> + struct regpair xferq_curr_page_addr;
> + struct regpair xferq_next_page_addr;
> + struct regpair respq_pbl_addr;
> + struct regpair respq_curr_page_addr;
> + struct regpair respq_next_page_addr;
> + __le16 dst_mac_addr_lo;
> + __le16 dst_mac_addr_mid;
> + __le16 dst_mac_addr_hi;
> + __le16 src_mac_addr_lo;
> + __le16 src_mac_addr_mid;
> + __le16 src_mac_addr_hi;
> + __le16 tx_max_fc_pay_len;
> + __le16 e_d_tov_timer_val;
> + __le16 rx_max_fc_pay_len;
> + __le16 vlan_tag;
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_VLAN_ID_MASK 0xFFF
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_VLAN_ID_SHIFT 0
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_CFI_MASK 0x1
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_CFI_SHIFT 12
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_PRIORITY_MASK 0x7
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_PRIORITY_SHIFT 13
> + __le16 physical_q0;
> + __le16 rec_rr_tov_timer_val;
> + struct fc_addr_nw s_id;
> + u8 max_conc_seqs_c3;
> + struct fc_addr_nw d_id;
> + u8 flags;
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_B_CONT_INCR_SEQ_CNT_MASK 0x1
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_B_CONT_INCR_SEQ_CNT_SHIFT 0
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_B_CONF_REQ_MASK 0x1
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_B_CONF_REQ_SHIFT 1
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_B_REC_VALID_MASK 0x1
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_B_REC_VALID_SHIFT 2
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_B_VLAN_FLAG_MASK 0x1
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_B_VLAN_FLAG_SHIFT 3
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_MODE_MASK 0x3
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_MODE_SHIFT 4
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_RESERVED0_MASK 0x3
> +#define FCOE_CONN_OFFLOAD_RAMROD_DATA_RESERVED0_SHIFT 6
> + __le16 conn_id;
> + u8 def_q_idx;
> + u8 reserved[5];
> +};
> +
> +/* FCoE terminate connection request */
> +struct fcoe_conn_terminate_ramrod_data {
> + struct regpair terminate_params_addr;
> +};
> +
> +struct fcoe_fast_sgl_ctx {
> + struct regpair sgl_start_addr;
> + __le32 sgl_byte_offset;
> + __le16 task_reuse_cnt;
> + __le16 init_offset_in_first_sge;
> +};
> +
> +struct fcoe_slow_sgl_ctx {
> + struct regpair base_sgl_addr;
> + __le16 curr_sge_off;
> + __le16 remainder_num_sges;
> + __le16 curr_sgl_index;
> + __le16 reserved;
> +};
> +
> +struct fcoe_sge {
> + struct regpair sge_addr;
> + __le16 size;
> + __le16 reserved0;
> + u8 reserved1[3];
> + u8 is_valid_sge;
> +};
> +
> +union fcoe_data_desc_ctx {
> + struct fcoe_fast_sgl_ctx fast;
> + struct fcoe_slow_sgl_ctx slow;
> + struct fcoe_sge single_sge;
> +};
> +
> +union fcoe_dix_desc_ctx {
> + struct fcoe_slow_sgl_ctx dix_sgl;
> + struct fcoe_sge cached_dix_sge;
> +};
> +
> +struct fcoe_fcp_cmd_payload {
> + __le32 opaque[8];
> +};
> +
> +struct fcoe_fcp_rsp_payload {
> + __le32 opaque[6];
> +};
> +
> +struct fcoe_fcp_xfer_payload {
> + __le32 opaque[3];
> +};
> +
> +/* FCoE firmware function init */
> +struct fcoe_init_func_ramrod_data {
> + struct scsi_init_func_params func_params;
> + struct scsi_init_func_queues q_params;
> + __le16 mtu;
> + __le16 sq_num_pages_in_pbl;
> + __le32 reserved;
> +};
> +
> +/* FCoE: Mode of the connection: Target or Initiator or both */
> +enum fcoe_mode_type {
> + FCOE_INITIATOR_MODE = 0x0,
> + FCOE_TARGET_MODE = 0x1,
> + FCOE_BOTH_OR_NOT_CHOSEN = 0x3,
> + MAX_FCOE_MODE_TYPE
> +};
> +
> +struct fcoe_mstorm_fcoe_task_st_ctx_fp {
> + __le16 flags;
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_FP_RSRV0_MASK 0x7FFF
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_FP_RSRV0_SHIFT 0
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_FP_MP_INCLUDE_FC_HEADER_MASK 0x1
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_FP_MP_INCLUDE_FC_HEADER_SHIFT 15
> + __le16 difDataResidue;
> + __le16 parent_id;
> + __le16 single_sge_saved_offset;
> + __le32 data_2_trns_rem;
> + __le32 offset_in_io;
> + union fcoe_dix_desc_ctx dix_desc;
> + union fcoe_data_desc_ctx data_desc;
> +};
> +
> +struct fcoe_mstorm_fcoe_task_st_ctx_non_fp {
> + __le16 flags;
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_HOST_INTERFACE_MASK 0x3
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_HOST_INTERFACE_SHIFT 0
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_DIF_TO_PEER_MASK 0x1
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_DIF_TO_PEER_SHIFT 2
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_VALIDATE_DIX_APP_TAG_MASK 0x1
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_VALIDATE_DIX_APP_TAG_SHIFT 3
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_INTERVAL_SIZE_LOG_MASK 0xF
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_INTERVAL_SIZE_LOG_SHIFT 4
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_DIX_BLOCK_SIZE_MASK 0x3
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_DIX_BLOCK_SIZE_SHIFT 8
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_RESERVED_MASK 0x1
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_RESERVED_SHIFT 10
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_HAS_FIRST_PACKET_ARRIVED_MASK 0x1
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_HAS_FIRST_PACKET_ARRIVED_SHIFT 11
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_VALIDATE_DIX_REF_TAG_MASK 0x1
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_VALIDATE_DIX_REF_TAG_SHIFT 12
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_DIX_CACHED_SGE_FLG_MASK 0x1
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_DIX_CACHED_SGE_FLG_SHIFT 13
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_OFFSET_IN_IO_VALID_MASK 0x1
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_OFFSET_IN_IO_VALID_SHIFT 14
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_DIF_SUPPORTED_MASK 0x1
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_DIF_SUPPORTED_SHIFT 15
> + u8 tx_rx_sgl_mode;
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_TX_SGL_MODE_MASK 0x7
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_TX_SGL_MODE_SHIFT 0
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_RX_SGL_MODE_MASK 0x7
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_RX_SGL_MODE_SHIFT 3
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_RSRV1_MASK 0x3
> +#define FCOE_MSTORM_FCOE_TASK_ST_CTX_NON_FP_RSRV1_SHIFT 6
> + u8 rsrv2;
> + __le32 num_prm_zero_read;
> + struct regpair rsp_buf_addr;
> +};
> +
> +struct fcoe_rx_stat {
> + struct regpair fcoe_rx_byte_cnt;
> + struct regpair fcoe_rx_data_pkt_cnt;
> + struct regpair fcoe_rx_xfer_pkt_cnt;
> + struct regpair fcoe_rx_other_pkt_cnt;
> + __le32 fcoe_silent_drop_pkt_cmdq_full_cnt;
> + __le32 fcoe_silent_drop_pkt_rq_full_cnt;
> + __le32 fcoe_silent_drop_pkt_crc_error_cnt;
> + __le32 fcoe_silent_drop_pkt_task_invalid_cnt;
> + __le32 fcoe_silent_drop_total_pkt_cnt;
> + __le32 rsrv;
> +};
> +
> +enum fcoe_sgl_mode {
> + FCOE_SLOW_SGL,
> + FCOE_SINGLE_FAST_SGE,
> + FCOE_2_FAST_SGE,
> + FCOE_3_FAST_SGE,
> + FCOE_4_FAST_SGE,
> + FCOE_MUL_FAST_SGES,
> + MAX_FCOE_SGL_MODE
> +};
> +
> +struct fcoe_stat_ramrod_data {
> + struct regpair stat_params_addr;
> +};
> +
> +struct protection_info_ctx {
> + __le16 flags;
> +#define PROTECTION_INFO_CTX_HOST_INTERFACE_MASK 0x3
> +#define PROTECTION_INFO_CTX_HOST_INTERFACE_SHIFT 0
> +#define PROTECTION_INFO_CTX_DIF_TO_PEER_MASK 0x1
> +#define PROTECTION_INFO_CTX_DIF_TO_PEER_SHIFT 2
> +#define PROTECTION_INFO_CTX_VALIDATE_DIX_APP_TAG_MASK 0x1
> +#define PROTECTION_INFO_CTX_VALIDATE_DIX_APP_TAG_SHIFT 3
> +#define PROTECTION_INFO_CTX_INTERVAL_SIZE_LOG_MASK 0xF
> +#define PROTECTION_INFO_CTX_INTERVAL_SIZE_LOG_SHIFT 4
> +#define PROTECTION_INFO_CTX_VALIDATE_DIX_REF_TAG_MASK 0x1
> +#define PROTECTION_INFO_CTX_VALIDATE_DIX_REF_TAG_SHIFT 8
> +#define PROTECTION_INFO_CTX_RESERVED0_MASK 0x7F
> +#define PROTECTION_INFO_CTX_RESERVED0_SHIFT 9
> + u8 dix_block_size;
> + u8 dst_size;
> +};
> +
> +union protection_info_union_ctx {
> + struct protection_info_ctx info;
> + __le32 value;
> +};
> +
> +struct fcp_rsp_payload_padded {
> + struct fcoe_fcp_rsp_payload rsp_payload;
> + __le32 reserved[2];
> +};
> +
> +struct fcp_xfer_payload_padded {
> + struct fcoe_fcp_xfer_payload xfer_payload;
> + __le32 reserved[5];
> +};
> +
> +struct fcoe_tx_data_params {
> + __le32 data_offset;
> + __le32 offset_in_io;
> + u8 flags;
> +#define FCOE_TX_DATA_PARAMS_OFFSET_IN_IO_VALID_MASK 0x1
> +#define FCOE_TX_DATA_PARAMS_OFFSET_IN_IO_VALID_SHIFT 0
> +#define FCOE_TX_DATA_PARAMS_DROP_DATA_MASK 0x1
> +#define FCOE_TX_DATA_PARAMS_DROP_DATA_SHIFT 1
> +#define FCOE_TX_DATA_PARAMS_AFTER_SEQ_REC_MASK 0x1
> +#define FCOE_TX_DATA_PARAMS_AFTER_SEQ_REC_SHIFT 2
> +#define FCOE_TX_DATA_PARAMS_RESERVED0_MASK 0x1F
> +#define FCOE_TX_DATA_PARAMS_RESERVED0_SHIFT 3
> + u8 dif_residual;
> + __le16 seq_cnt;
> + __le16 single_sge_saved_offset;
> + __le16 next_dif_offset;
> + __le16 seq_id;
> + __le16 reserved3;
> +};
> +
> +struct fcoe_tx_mid_path_params {
> + __le32 parameter;
> + u8 r_ctl;
> + u8 type;
> + u8 cs_ctl;
> + u8 df_ctl;
> + __le16 rx_id;
> + __le16 ox_id;
> +};
> +
> +struct fcoe_tx_params {
> + struct fcoe_tx_data_params data;
> + struct fcoe_tx_mid_path_params mid_path;
> +};
> +
> +union fcoe_tx_info_union_ctx {
> + struct fcoe_fcp_cmd_payload fcp_cmd_payload;
> + struct fcp_rsp_payload_padded fcp_rsp_payload;
> + struct fcp_xfer_payload_padded fcp_xfer_payload;
> + struct fcoe_tx_params tx_params;
> +};
> +
> +struct ystorm_fcoe_task_st_ctx {
> + u8 task_type;
> + u8 sgl_mode;
> +#define YSTORM_FCOE_TASK_ST_CTX_TX_SGL_MODE_MASK 0x7
> +#define YSTORM_FCOE_TASK_ST_CTX_TX_SGL_MODE_SHIFT 0
> +#define YSTORM_FCOE_TASK_ST_CTX_RSRV_MASK 0x1F
> +#define YSTORM_FCOE_TASK_ST_CTX_RSRV_SHIFT 3
> + u8 cached_dix_sge;
> + u8 expect_first_xfer;
> + __le32 num_pbf_zero_write;
> + union protection_info_union_ctx protection_info_union;
> + __le32 data_2_trns_rem;
> + union fcoe_tx_info_union_ctx tx_info_union;
> + union fcoe_dix_desc_ctx dix_desc;
> + union fcoe_data_desc_ctx data_desc;
> + __le16 ox_id;
> + __le16 rx_id;
> + __le32 task_rety_identifier;
> + __le32 reserved1[2];
> +};
> +
> +struct ystorm_fcoe_task_ag_ctx {
> + u8 byte0;
> + u8 byte1;
> + __le16 word0;
> + u8 flags0;
> +#define YSTORM_FCOE_TASK_AG_CTX_NIBBLE0_MASK 0xF
> +#define YSTORM_FCOE_TASK_AG_CTX_NIBBLE0_SHIFT 0
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT0_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT0_SHIFT 4
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT1_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT1_SHIFT 5
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT2_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT2_SHIFT 6
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT3_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT3_SHIFT 7
> + u8 flags1;
> +#define YSTORM_FCOE_TASK_AG_CTX_CF0_MASK 0x3
> +#define YSTORM_FCOE_TASK_AG_CTX_CF0_SHIFT 0
> +#define YSTORM_FCOE_TASK_AG_CTX_CF1_MASK 0x3
> +#define YSTORM_FCOE_TASK_AG_CTX_CF1_SHIFT 2
> +#define YSTORM_FCOE_TASK_AG_CTX_CF2SPECIAL_MASK 0x3
> +#define YSTORM_FCOE_TASK_AG_CTX_CF2SPECIAL_SHIFT 4
> +#define YSTORM_FCOE_TASK_AG_CTX_CF0EN_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_CF0EN_SHIFT 6
> +#define YSTORM_FCOE_TASK_AG_CTX_CF1EN_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_CF1EN_SHIFT 7
> + u8 flags2;
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT4_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_BIT4_SHIFT 0
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE0EN_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE0EN_SHIFT 1
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE1EN_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE1EN_SHIFT 2
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE2EN_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE2EN_SHIFT 3
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE3EN_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE3EN_SHIFT 4
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE4EN_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE4EN_SHIFT 5
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE5EN_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE5EN_SHIFT 6
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE6EN_MASK 0x1
> +#define YSTORM_FCOE_TASK_AG_CTX_RULE6EN_SHIFT 7
> + u8 byte2;
> + __le32 reg0;
> + u8 byte3;
> + u8 byte4;
> + __le16 rx_id;
> + __le16 word2;
> + __le16 word3;
> + __le16 word4;
> + __le16 word5;
> + __le32 reg1;
> + __le32 reg2;
> +};
> +
> +struct tstorm_fcoe_task_ag_ctx {
> + u8 reserved;
> + u8 byte1;
> + __le16 icid;
> + u8 flags0;
> +#define TSTORM_FCOE_TASK_AG_CTX_CONNECTION_TYPE_MASK 0xF
> +#define TSTORM_FCOE_TASK_AG_CTX_CONNECTION_TYPE_SHIFT 0
> +#define TSTORM_FCOE_TASK_AG_CTX_EXIST_IN_QM0_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_EXIST_IN_QM0_SHIFT 4
> +#define TSTORM_FCOE_TASK_AG_CTX_BIT1_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_BIT1_SHIFT 5
> +#define TSTORM_FCOE_TASK_AG_CTX_WAIT_ABTS_RSP_F_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_WAIT_ABTS_RSP_F_SHIFT 6
> +#define TSTORM_FCOE_TASK_AG_CTX_VALID_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_VALID_SHIFT 7
> + u8 flags1;
> +#define TSTORM_FCOE_TASK_AG_CTX_FALSE_RR_TOV_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_FALSE_RR_TOV_SHIFT 0
> +#define TSTORM_FCOE_TASK_AG_CTX_BIT5_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_BIT5_SHIFT 1
> +#define TSTORM_FCOE_TASK_AG_CTX_REC_RR_TOV_CF_MASK 0x3
> +#define TSTORM_FCOE_TASK_AG_CTX_REC_RR_TOV_CF_SHIFT 2
> +#define TSTORM_FCOE_TASK_AG_CTX_ED_TOV_CF_MASK 0x3
> +#define TSTORM_FCOE_TASK_AG_CTX_ED_TOV_CF_SHIFT 4
> +#define TSTORM_FCOE_TASK_AG_CTX_CF2_MASK 0x3
> +#define TSTORM_FCOE_TASK_AG_CTX_CF2_SHIFT 6
> + u8 flags2;
> +#define TSTORM_FCOE_TASK_AG_CTX_TIMER_STOP_ALL_MASK 0x3
> +#define TSTORM_FCOE_TASK_AG_CTX_TIMER_STOP_ALL_SHIFT 0
> +#define TSTORM_FCOE_TASK_AG_CTX_EX_CLEANUP_CF_MASK 0x3
> +#define TSTORM_FCOE_TASK_AG_CTX_EX_CLEANUP_CF_SHIFT 2
> +#define TSTORM_FCOE_TASK_AG_CTX_SEQ_INIT_CF_MASK 0x3
> +#define TSTORM_FCOE_TASK_AG_CTX_SEQ_INIT_CF_SHIFT 4
> +#define TSTORM_FCOE_TASK_AG_CTX_SEQ_RECOVERY_CF_MASK 0x3
> +#define TSTORM_FCOE_TASK_AG_CTX_SEQ_RECOVERY_CF_SHIFT 6
> + u8 flags3;
> +#define TSTORM_FCOE_TASK_AG_CTX_UNSOL_COMP_CF_MASK 0x3
> +#define TSTORM_FCOE_TASK_AG_CTX_UNSOL_COMP_CF_SHIFT 0
> +#define TSTORM_FCOE_TASK_AG_CTX_REC_RR_TOV_CF_EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_REC_RR_TOV_CF_EN_SHIFT 2
> +#define TSTORM_FCOE_TASK_AG_CTX_ED_TOV_CF_EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_ED_TOV_CF_EN_SHIFT 3
> +#define TSTORM_FCOE_TASK_AG_CTX_CF2EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_CF2EN_SHIFT 4
> +#define TSTORM_FCOE_TASK_AG_CTX_TIMER_STOP_ALL_EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_TIMER_STOP_ALL_EN_SHIFT 5
> +#define TSTORM_FCOE_TASK_AG_CTX_EX_CLEANUP_CF_EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_EX_CLEANUP_CF_EN_SHIFT 6
> +#define TSTORM_FCOE_TASK_AG_CTX_SEQ_INIT_CF_EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_SEQ_INIT_CF_EN_SHIFT 7
> + u8 flags4;
> +#define TSTORM_FCOE_TASK_AG_CTX_SEQ_RECOVERY_CF_EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_SEQ_RECOVERY_CF_EN_SHIFT 0
> +#define TSTORM_FCOE_TASK_AG_CTX_UNSOL_COMP_CF_EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_UNSOL_COMP_CF_EN_SHIFT 1
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE0EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE0EN_SHIFT 2
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE1EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE1EN_SHIFT 3
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE2EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE2EN_SHIFT 4
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE3EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE3EN_SHIFT 5
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE4EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE4EN_SHIFT 6
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE5EN_MASK 0x1
> +#define TSTORM_FCOE_TASK_AG_CTX_RULE5EN_SHIFT 7
> + u8 cleanup_state;
> + __le16 last_sent_tid;
> + __le32 rec_rr_tov_exp_timeout;
> + u8 byte3;
> + u8 byte4;
> + __le16 word2;
> + __le16 word3;
> + __le16 word4;
> + __le32 data_offset_end_of_seq;
> + __le32 data_offset_next;
> +};
> +
> +struct fcoe_tstorm_fcoe_task_st_ctx_read_write {
> + union fcoe_cleanup_addr_exp_ro_union cleanup_addr_exp_ro_union;
> + __le16 flags;
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_RX_SGL_MODE_MASK 0x7
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_RX_SGL_MODE_SHIFT 0
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_EXP_FIRST_FRAME_MASK 0x1
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_EXP_FIRST_FRAME_SHIFT 3
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_SEQ_ACTIVE_MASK 0x1
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_SEQ_ACTIVE_SHIFT 4
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_SEQ_TIMEOUT_MASK 0x1
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_SEQ_TIMEOUT_SHIFT 5
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_SINGLE_PKT_IN_EX_MASK 0x1
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_SINGLE_PKT_IN_EX_SHIFT 6
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_OOO_RX_SEQ_STAT_MASK 0x1
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_OOO_RX_SEQ_STAT_SHIFT 7
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_CQ_ADD_ADV_MASK 0x3
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_CQ_ADD_ADV_SHIFT 8
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_RSRV1_MASK 0x3F
> +#define FCOE_TSTORM_FCOE_TASK_ST_CTX_READ_WRITE_RSRV1_SHIFT 10
A very odd way of defining a bitfield ...
Why not use a 'normal' bitfield here?
> + __le16 seq_cnt;
> + u8 seq_id;
> + u8 ooo_rx_seq_id;
> + __le16 rx_id;
> + struct fcoe_abts_pkt abts_data;
> + __le32 e_d_tov_exp_timeout_val;
> + __le16 ooo_rx_seq_cnt;
> + __le16 reserved1;
> +};
> +
> +struct fcoe_tstorm_fcoe_task_st_ctx_read_only {
> + u8 task_type;
> + u8 dev_type;
> + u8 conf_supported;
> + u8 glbl_q_num;
> + __le32 cid;
> + __le32 fcp_cmd_trns_size;
> + __le32 rsrv;
> +};
> +
> +struct tstorm_fcoe_task_st_ctx {
> + struct fcoe_tstorm_fcoe_task_st_ctx_read_write read_write;
> + struct fcoe_tstorm_fcoe_task_st_ctx_read_only read_only;
> +};
> +
> +struct mstorm_fcoe_task_ag_ctx {
> + u8 byte0;
> + u8 byte1;
> + __le16 icid;
> + u8 flags0;
> +#define MSTORM_FCOE_TASK_AG_CTX_CONNECTION_TYPE_MASK 0xF
> +#define MSTORM_FCOE_TASK_AG_CTX_CONNECTION_TYPE_SHIFT 0
> +#define MSTORM_FCOE_TASK_AG_CTX_EXIST_IN_QM0_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_EXIST_IN_QM0_SHIFT 4
> +#define MSTORM_FCOE_TASK_AG_CTX_CQE_PLACED_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_CQE_PLACED_SHIFT 5
> +#define MSTORM_FCOE_TASK_AG_CTX_BIT2_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_BIT2_SHIFT 6
> +#define MSTORM_FCOE_TASK_AG_CTX_BIT3_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_BIT3_SHIFT 7
> + u8 flags1;
> +#define MSTORM_FCOE_TASK_AG_CTX_EX_CLEANUP_CF_MASK 0x3
> +#define MSTORM_FCOE_TASK_AG_CTX_EX_CLEANUP_CF_SHIFT 0
> +#define MSTORM_FCOE_TASK_AG_CTX_CF1_MASK 0x3
> +#define MSTORM_FCOE_TASK_AG_CTX_CF1_SHIFT 2
> +#define MSTORM_FCOE_TASK_AG_CTX_CF2_MASK 0x3
> +#define MSTORM_FCOE_TASK_AG_CTX_CF2_SHIFT 4
> +#define MSTORM_FCOE_TASK_AG_CTX_EX_CLEANUP_CF_EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_EX_CLEANUP_CF_EN_SHIFT 6
> +#define MSTORM_FCOE_TASK_AG_CTX_CF1EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_CF1EN_SHIFT 7
> + u8 flags2;
> +#define MSTORM_FCOE_TASK_AG_CTX_CF2EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_CF2EN_SHIFT 0
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE0EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE0EN_SHIFT 1
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE1EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE1EN_SHIFT 2
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE2EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE2EN_SHIFT 3
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE3EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE3EN_SHIFT 4
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE4EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE4EN_SHIFT 5
> +#define MSTORM_FCOE_TASK_AG_CTX_XFER_PLACEMENT_EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_XFER_PLACEMENT_EN_SHIFT 6
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE6EN_MASK 0x1
> +#define MSTORM_FCOE_TASK_AG_CTX_RULE6EN_SHIFT 7
Bitfield again ...
> + u8 cleanup_state;
> + __le32 received_bytes;
> + u8 byte3;
> + u8 glbl_q_num;
> + __le16 word1;
> + __le16 tid_to_xfer;
> + __le16 word3;
> + __le16 word4;
> + __le16 word5;
> + __le32 expected_bytes;
> + __le32 reg2;
> +};
> +
> +struct mstorm_fcoe_task_st_ctx {
> + struct fcoe_mstorm_fcoe_task_st_ctx_non_fp non_fp;
> + struct fcoe_mstorm_fcoe_task_st_ctx_fp fp;
> +};
> +
> +struct ustorm_fcoe_task_ag_ctx {
> + u8 reserved;
> + u8 byte1;
> + __le16 icid;
> + u8 flags0;
> +#define USTORM_FCOE_TASK_AG_CTX_CONNECTION_TYPE_MASK 0xF
> +#define USTORM_FCOE_TASK_AG_CTX_CONNECTION_TYPE_SHIFT 0
> +#define USTORM_FCOE_TASK_AG_CTX_EXIST_IN_QM0_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_EXIST_IN_QM0_SHIFT 4
> +#define USTORM_FCOE_TASK_AG_CTX_BIT1_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_BIT1_SHIFT 5
> +#define USTORM_FCOE_TASK_AG_CTX_CF0_MASK 0x3
> +#define USTORM_FCOE_TASK_AG_CTX_CF0_SHIFT 6
> + u8 flags1;
> +#define USTORM_FCOE_TASK_AG_CTX_CF1_MASK 0x3
> +#define USTORM_FCOE_TASK_AG_CTX_CF1_SHIFT 0
> +#define USTORM_FCOE_TASK_AG_CTX_CF2_MASK 0x3
> +#define USTORM_FCOE_TASK_AG_CTX_CF2_SHIFT 2
> +#define USTORM_FCOE_TASK_AG_CTX_CF3_MASK 0x3
> +#define USTORM_FCOE_TASK_AG_CTX_CF3_SHIFT 4
> +#define USTORM_FCOE_TASK_AG_CTX_DIF_ERROR_CF_MASK 0x3
> +#define USTORM_FCOE_TASK_AG_CTX_DIF_ERROR_CF_SHIFT 6
> + u8 flags2;
> +#define USTORM_FCOE_TASK_AG_CTX_CF0EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_CF0EN_SHIFT 0
> +#define USTORM_FCOE_TASK_AG_CTX_CF1EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_CF1EN_SHIFT 1
> +#define USTORM_FCOE_TASK_AG_CTX_CF2EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_CF2EN_SHIFT 2
> +#define USTORM_FCOE_TASK_AG_CTX_CF3EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_CF3EN_SHIFT 3
> +#define USTORM_FCOE_TASK_AG_CTX_DIF_ERROR_CF_EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_DIF_ERROR_CF_EN_SHIFT 4
> +#define USTORM_FCOE_TASK_AG_CTX_RULE0EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_RULE0EN_SHIFT 5
> +#define USTORM_FCOE_TASK_AG_CTX_RULE1EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_RULE1EN_SHIFT 6
> +#define USTORM_FCOE_TASK_AG_CTX_RULE2EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_RULE2EN_SHIFT 7
> + u8 flags3;
> +#define USTORM_FCOE_TASK_AG_CTX_RULE3EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_RULE3EN_SHIFT 0
> +#define USTORM_FCOE_TASK_AG_CTX_RULE4EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_RULE4EN_SHIFT 1
> +#define USTORM_FCOE_TASK_AG_CTX_RULE5EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_RULE5EN_SHIFT 2
> +#define USTORM_FCOE_TASK_AG_CTX_RULE6EN_MASK 0x1
> +#define USTORM_FCOE_TASK_AG_CTX_RULE6EN_SHIFT 3
> +#define USTORM_FCOE_TASK_AG_CTX_DIF_ERROR_TYPE_MASK 0xF
> +#define USTORM_FCOE_TASK_AG_CTX_DIF_ERROR_TYPE_SHIFT 4
My, you really like these definition thingies ...
> + __le32 dif_err_intervals;
> + __le32 dif_error_1st_interval;
> + __le32 global_cq_num;
> + __le32 reg3;
> + __le32 reg4;
> + __le32 reg5;
> +};
> +
> +struct fcoe_task_context {
> + struct ystorm_fcoe_task_st_ctx ystorm_st_context;
> + struct tdif_task_context tdif_context;
> + struct ystorm_fcoe_task_ag_ctx ystorm_ag_context;
> + struct tstorm_fcoe_task_ag_ctx tstorm_ag_context;
> + struct timers_context timer_context;
> + struct tstorm_fcoe_task_st_ctx tstorm_st_context;
> + struct regpair tstorm_st_padding[2];
> + struct mstorm_fcoe_task_ag_ctx mstorm_ag_context;
> + struct mstorm_fcoe_task_st_ctx mstorm_st_context;
> + struct ustorm_fcoe_task_ag_ctx ustorm_ag_context;
> + struct rdif_task_context rdif_context;
> +};
> +
> +struct fcoe_tx_stat {
> + struct regpair fcoe_tx_byte_cnt;
> + struct regpair fcoe_tx_data_pkt_cnt;
> + struct regpair fcoe_tx_xfer_pkt_cnt;
> + struct regpair fcoe_tx_other_pkt_cnt;
> +};
> +
> +struct fcoe_wqe {
> + __le16 task_id;
> + __le16 flags;
> +#define FCOE_WQE_REQ_TYPE_MASK 0xF
> +#define FCOE_WQE_REQ_TYPE_SHIFT 0
> +#define FCOE_WQE_SGL_MODE_MASK 0x7
> +#define FCOE_WQE_SGL_MODE_SHIFT 4
> +#define FCOE_WQE_CONTINUATION_MASK 0x1
> +#define FCOE_WQE_CONTINUATION_SHIFT 7
> +#define FCOE_WQE_INVALIDATE_PTU_MASK 0x1
> +#define FCOE_WQE_INVALIDATE_PTU_SHIFT 8
> +#define FCOE_WQE_SUPER_IO_MASK 0x1
> +#define FCOE_WQE_SUPER_IO_SHIFT 9
> +#define FCOE_WQE_SEND_AUTO_RSP_MASK 0x1
> +#define FCOE_WQE_SEND_AUTO_RSP_SHIFT 10
> +#define FCOE_WQE_RESERVED0_MASK 0x1F
> +#define FCOE_WQE_RESERVED0_SHIFT 11
> + union fcoe_additional_info_union additional_info_union;
> +};
> +
And here...
> +struct xfrqe_prot_flags {
> + u8 flags;
> +#define XFRQE_PROT_FLAGS_PROT_INTERVAL_SIZE_LOG_MASK 0xF
> +#define XFRQE_PROT_FLAGS_PROT_INTERVAL_SIZE_LOG_SHIFT 0
> +#define XFRQE_PROT_FLAGS_DIF_TO_PEER_MASK 0x1
> +#define XFRQE_PROT_FLAGS_DIF_TO_PEER_SHIFT 4
> +#define XFRQE_PROT_FLAGS_HOST_INTERFACE_MASK 0x3
> +#define XFRQE_PROT_FLAGS_HOST_INTERFACE_SHIFT 5
> +#define XFRQE_PROT_FLAGS_RESERVED_MASK 0x1
> +#define XFRQE_PROT_FLAGS_RESERVED_SHIFT 7
> +};
> +
> +struct fcoe_db_data {
> + u8 params;
> +#define FCOE_DB_DATA_DEST_MASK 0x3
> +#define FCOE_DB_DATA_DEST_SHIFT 0
> +#define FCOE_DB_DATA_AGG_CMD_MASK 0x3
> +#define FCOE_DB_DATA_AGG_CMD_SHIFT 2
> +#define FCOE_DB_DATA_BYPASS_EN_MASK 0x1
> +#define FCOE_DB_DATA_BYPASS_EN_SHIFT 4
> +#define FCOE_DB_DATA_RESERVED_MASK 0x1
> +#define FCOE_DB_DATA_RESERVED_SHIFT 5
> +#define FCOE_DB_DATA_AGG_VAL_SEL_MASK 0x3
> +#define FCOE_DB_DATA_AGG_VAL_SEL_SHIFT 6
> + u8 agg_flags;
> + __le16 sq_prod;
> +};
> +#endif /* __FCOE_COMMON__ */
> diff --git a/include/linux/qed/qed_fcoe_if.h b/include/linux/qed/qed_fcoe_if.h
> new file mode 100644
> index 0000000..bd6bcb8
> --- /dev/null
> +++ b/include/linux/qed/qed_fcoe_if.h
> @@ -0,0 +1,145 @@
> +#ifndef _QED_FCOE_IF_H
> +#define _QED_FCOE_IF_H
> +#include <linux/types.h>
> +#include <linux/qed/qed_if.h>
> +struct qed_fcoe_stats {
> + u64 fcoe_rx_byte_cnt;
> + u64 fcoe_rx_data_pkt_cnt;
> + u64 fcoe_rx_xfer_pkt_cnt;
> + u64 fcoe_rx_other_pkt_cnt;
> + u32 fcoe_silent_drop_pkt_cmdq_full_cnt;
> + u32 fcoe_silent_drop_pkt_rq_full_cnt;
> + u32 fcoe_silent_drop_pkt_crc_error_cnt;
> + u32 fcoe_silent_drop_pkt_task_invalid_cnt;
> + u32 fcoe_silent_drop_total_pkt_cnt;
> +
> + u64 fcoe_tx_byte_cnt;
> + u64 fcoe_tx_data_pkt_cnt;
> + u64 fcoe_tx_xfer_pkt_cnt;
> + u64 fcoe_tx_other_pkt_cnt;
> +};
> +
> +struct qed_dev_fcoe_info {
> + struct qed_dev_info common;
> +
> + void __iomem *primary_dbq_rq_addr;
> + void __iomem *secondary_bdq_rq_addr;
> +};
> +
> +struct qed_fcoe_params_offload {
> + dma_addr_t sq_pbl_addr;
> + dma_addr_t sq_curr_page_addr;
> + dma_addr_t sq_next_page_addr;
> +
> + u8 src_mac[ETH_ALEN];
> + u8 dst_mac[ETH_ALEN];
> +
> + u16 tx_max_fc_pay_len;
> + u16 e_d_tov_timer_val;
> + u16 rec_tov_timer_val;
> + u16 rx_max_fc_pay_len;
> + u16 vlan_tag;
> +
> + struct fc_addr_nw s_id;
> + u8 max_conc_seqs_c3;
> + struct fc_addr_nw d_id;
> + u8 flags;
> + u8 def_q_idx;
> +};
> +
> +#define MAX_TID_BLOCKS_FCOE (512)
> +struct qed_fcoe_tid {
> + u32 size; /* In bytes per task */
> + u32 num_tids_per_block;
> + u8 *blocks[MAX_TID_BLOCKS_FCOE];
> +};
> +
> +struct qed_fcoe_cb_ops {
> + struct qed_common_cb_ops common;
> + u32 (*get_login_failures)(void *cookie);
> +};
> +
> +void qed_fcoe_set_pf_params(struct qed_dev *cdev,
> + struct qed_fcoe_pf_params *params);
> +
> +/**
> + * struct qed_fcoe_ops - qed FCoE operations.
> + * @common: common operations pointer
> + * @fill_dev_info: fills FCoE specific information
> + * @param cdev
> + * @param info
> + * @return 0 on sucesss, otherwise error value.
> + * @register_ops: register FCoE operations
> + * @param cdev
> + * @param ops - specified using qed_iscsi_cb_ops
> + * @param cookie - driver private
> + * @ll2: light L2 operations pointer
> + * @start: fcoe in FW
> + * @param cdev
> + * @param tasks - qed will fill information about tasks
> + * return 0 on success, otherwise error value.
> + * @stop: stops fcoe in FW
> + * @param cdev
> + * return 0 on success, otherwise error value.
> + * @acquire_conn: acquire a new fcoe connection
> + * @param cdev
> + * @param handle - qed will fill handle that should be
> + * used henceforth as identifier of the
> + * connection.
> + * @param p_doorbell - qed will fill the address of the
> + * doorbell.
> + * return 0 on sucesss, otherwise error value.
> + * @release_conn: release a previously acquired fcoe connection
> + * @param cdev
> + * @param handle - the connection handle.
> + * return 0 on success, otherwise error value.
> + * @offload_conn: configures an offloaded connection
> + * @param cdev
> + * @param handle - the connection handle.
> + * @param conn_info - the configuration to use for the
> + * offload.
> + * return 0 on success, otherwise error value.
> + * @destroy_conn: stops an offloaded connection
> + * @param cdev
> + * @param handle - the connection handle.
> + * @param terminate_params
> + * return 0 on success, otherwise error value.
> + * @get_stats: gets FCoE related statistics
> + * @param cdev
> + * @param stats - pointer to struck that would be filled
> + * we stats
> + * return 0 on success, error otherwise.
> + */
> +struct qed_fcoe_ops {
> + const struct qed_common_ops *common;
> +
> + int (*fill_dev_info)(struct qed_dev *cdev,
> + struct qed_dev_fcoe_info *info);
> +
> + void (*register_ops)(struct qed_dev *cdev,
> + struct qed_fcoe_cb_ops *ops, void *cookie);
> +
> + const struct qed_ll2_ops *ll2;
> +
> + int (*start)(struct qed_dev *cdev, struct qed_fcoe_tid *tasks);
> +
> + int (*stop)(struct qed_dev *cdev);
> +
> + int (*acquire_conn)(struct qed_dev *cdev,
> + u32 *handle,
> + u32 *fw_cid, void __iomem **p_doorbell);
> +
> + int (*release_conn)(struct qed_dev *cdev, u32 handle);
> +
> + int (*offload_conn)(struct qed_dev *cdev,
> + u32 handle,
> + struct qed_fcoe_params_offload *conn_info);
> + int (*destroy_conn)(struct qed_dev *cdev,
> + u32 handle, dma_addr_t terminate_params);
> +
> + int (*get_stats)(struct qed_dev *cdev, struct qed_fcoe_stats *stats);
> +};
> +
I prefer to have to comments directly above the function prototypes;
that is easier to read and requires editing in one place only; this way
there's a higher likelyhood of both getting out of sync.
But that may be personal preference only.
> +const struct qed_fcoe_ops *qed_get_fcoe_ops(void);
> +void qed_put_fcoe_ops(void);
> +#endif
> diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h
> index 4b454f4..ecdcfec 100644
> --- a/include/linux/qed/qed_if.h
> +++ b/include/linux/qed/qed_if.h
> @@ -159,6 +159,38 @@ struct qed_eth_pf_params {
> u16 num_cons;
> };
>
> +struct qed_fcoe_pf_params {
> + /* The following parameters are used during protocol-init */
> + u64 glbl_q_params_addr;
> + u64 bdq_pbl_base_addr[2];
> +
> + /* The following parameters are used during HW-init
> + * and these parameters need to be passed as arguments
> + * to update_pf_params routine invoked before slowpath start
> + */
> + u16 num_cons;
> + u16 num_tasks;
> +
> + /* The following parameters are used during protocol-init */
> + u16 sq_num_pbl_pages;
> +
> + u16 cq_num_entries;
> + u16 cmdq_num_entries;
> + u16 rq_buffer_log_size;
> + u16 mtu;
> + u16 dummy_icid;
> + u16 bdq_xoff_threshold[2];
> + u16 bdq_xon_threshold[2];
> + u16 rq_buffer_size;
> + u8 num_cqs; /* num of global CQs */
> + u8 log_page_size;
> + u8 gl_rq_pi;
> + u8 gl_cmd_pi;
> + u8 debug_mode;
> + u8 is_target;
> + u8 bdq_pbl_num_entries[2];
> +};
> +
> /* Most of the the parameters below are described in the FW iSCSI / TCP HSI */
> struct qed_iscsi_pf_params {
> u64 glbl_q_params_addr;
> @@ -222,6 +254,7 @@ struct qed_rdma_pf_params {
>
> struct qed_pf_params {
> struct qed_eth_pf_params eth_pf_params;
> + struct qed_fcoe_pf_params fcoe_pf_params;
> struct qed_iscsi_pf_params iscsi_pf_params;
> struct qed_rdma_pf_params rdma_pf_params;
> };
> @@ -282,6 +315,7 @@ enum qed_sb_type {
> enum qed_protocol {
> QED_PROTOCOL_ETH,
> QED_PROTOCOL_ISCSI,
> + QED_PROTOCOL_FCOE,
> };
>
> enum qed_link_mode_bits {
> @@ -368,6 +402,7 @@ struct qed_int_info {
> struct qed_common_cb_ops {
> void (*link_update)(void *dev,
> struct qed_link_output *link);
> + void (*dcbx_aen)(void *dev, struct qed_dcbx_get *get, u32 mib_type);
> };
>
> struct qed_selftest_ops {
> @@ -471,6 +506,10 @@ struct qed_common_ops {
>
> void (*simd_handler_clean)(struct qed_dev *cdev,
> int index);
> + int (*dbg_grc)(struct qed_dev *cdev,
> + void *buffer, u32 *num_dumped_bytes);
> +
> + int (*dbg_grc_size)(struct qed_dev *cdev);
>
> int (*dbg_all_data) (struct qed_dev *cdev, void *buffer);
>
>
Cheers,
Hannes
--
Dr. Hannes Reinecke zSeries & Storage
hare-l3A5Bk7waGM@public.gmane.org +49 911 74053 688
SUSE LINUX Products GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: J. Hawn, J. Guild, F. Imendörffer, HRB 16746 (AG Nürnberg)
^ permalink raw reply
* Re: [RFC PATCH net-next v4 1/2] macb: Add 1588 support in Cadence GEM.
From: Richard Cochran @ 2016-12-28 8:15 UTC (permalink / raw)
To: Andrei Pistirica
Cc: netdev, linux-kernel, linux-arm-kernel, davem, nicolas.ferre,
harinikatakamlinux, harini.katakam, punnaia, michals, anirudh,
boris.brezillon, alexandre.belloni, tbultel, rafalo
In-Reply-To: <1481720175-12703-1-git-send-email-andrei.pistirica@microchip.com>
On Wed, Dec 14, 2016 at 02:56:14PM +0200, Andrei Pistirica wrote:
> Note 1: Kbuild uses "select" instead of "imply", and the macb maintainer agreed
> to make the change when it will be available in net-next.
> +config MACB_USE_HWSTAMP
> + bool "Use IEEE 1588 hwstamp"
> + depends on MACB
> + default y
> + select PTP_1588_CLOCK
The imply key word has been merged as of:
237e3ad Kconfig: Introduce the "imply" keyword
Please use it.
Thanks,
Richard
> + ---help---
> + Enable IEEE 1588 Precision Time Protocol (PTP) support for MACB.
^ permalink raw reply
* [PATCH net-next V2 3/3] tun: rx batching
From: Jason Wang @ 2016-12-28 8:09 UTC (permalink / raw)
To: mst, kvm, virtualization, netdev, linux-kernel; +Cc: Jason Wang
In-Reply-To: <1482912571-3157-1-git-send-email-jasowang@redhat.com>
We can only process 1 packet at one time during sendmsg(). This often
lead bad cache utilization under heavy load. So this patch tries to do
some batching during rx before submitting them to host network
stack. This is done through accepting MSG_MORE as a hint from
sendmsg() caller, if it was set, batch the packet temporarily in a
linked list and submit them all once MSG_MORE were cleared.
Tests were done by pktgen (burst=128) in guest over mlx4(noqueue) on host:
Mpps -+%
rx_batched=0 0.90 +0%
rx_batched=4 0.97 +7.8%
rx_batched=8 0.97 +7.8%
rx_batched=16 0.98 +8.9%
rx_batched=32 1.03 +14.4%
rx_batched=48 1.09 +21.1%
rx_batched=64 1.02 +13.3%
The maximum number of batched packets were specified through a module
parameter.
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/net/tun.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 58 insertions(+), 8 deletions(-)
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index cd8e02c..6ea5d6d 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -75,6 +75,10 @@
#include <linux/uaccess.h>
+static int rx_batched;
+module_param(rx_batched, int, 0444);
+MODULE_PARM_DESC(rx_batched, "Number of packets batched in rx");
+
/* Uncomment to enable debugging */
/* #define TUN_DEBUG 1 */
@@ -522,6 +526,7 @@ static void tun_queue_purge(struct tun_file *tfile)
while ((skb = skb_array_consume(&tfile->tx_array)) != NULL)
kfree_skb(skb);
+ skb_queue_purge(&tfile->sk.sk_write_queue);
skb_queue_purge(&tfile->sk.sk_error_queue);
}
@@ -1140,10 +1145,44 @@ static struct sk_buff *tun_alloc_skb(struct tun_file *tfile,
return skb;
}
+static int tun_rx_batched(struct tun_file *tfile, struct sk_buff *skb,
+ int more)
+{
+ struct sk_buff_head *queue = &tfile->sk.sk_write_queue;
+ struct sk_buff_head process_queue;
+ int qlen;
+ bool rcv = false;
+
+ spin_lock(&queue->lock);
+ qlen = skb_queue_len(queue);
+ if (qlen > rx_batched)
+ goto drop;
+ __skb_queue_tail(queue, skb);
+ if (!more || qlen + 1 > rx_batched) {
+ __skb_queue_head_init(&process_queue);
+ skb_queue_splice_tail_init(queue, &process_queue);
+ rcv = true;
+ }
+ spin_unlock(&queue->lock);
+
+ if (rcv) {
+ local_bh_disable();
+ while ((skb = __skb_dequeue(&process_queue)))
+ netif_receive_skb(skb);
+ local_bh_enable();
+ }
+
+ return 0;
+drop:
+ spin_unlock(&queue->lock);
+ kfree_skb(skb);
+ return -EFAULT;
+}
+
/* Get packet from user space buffer */
static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
void *msg_control, struct iov_iter *from,
- int noblock)
+ int noblock, bool more)
{
struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) };
struct sk_buff *skb;
@@ -1283,18 +1322,27 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
skb_probe_transport_header(skb, 0);
rxhash = skb_get_hash(skb);
+
#ifndef CONFIG_4KSTACKS
- local_bh_disable();
- netif_receive_skb(skb);
- local_bh_enable();
+ if (!rx_batched) {
+ local_bh_disable();
+ netif_receive_skb(skb);
+ local_bh_enable();
+ } else {
+ err = tun_rx_batched(tfile, skb, more);
+ }
#else
netif_rx_ni(skb);
#endif
stats = get_cpu_ptr(tun->pcpu_stats);
u64_stats_update_begin(&stats->syncp);
- stats->rx_packets++;
- stats->rx_bytes += len;
+ if (err) {
+ stats->rx_dropped++;
+ } else {
+ stats->rx_packets++;
+ stats->rx_bytes += len;
+ }
u64_stats_update_end(&stats->syncp);
put_cpu_ptr(stats);
@@ -1312,7 +1360,8 @@ static ssize_t tun_chr_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (!tun)
return -EBADFD;
- result = tun_get_user(tun, tfile, NULL, from, file->f_flags & O_NONBLOCK);
+ result = tun_get_user(tun, tfile, NULL, from,
+ file->f_flags & O_NONBLOCK, false);
tun_put(tun);
return result;
@@ -1570,7 +1619,8 @@ static int tun_sendmsg(struct socket *sock, struct msghdr *m, size_t total_len)
return -EBADFD;
ret = tun_get_user(tun, tfile, m->msg_control, &m->msg_iter,
- m->msg_flags & MSG_DONTWAIT);
+ m->msg_flags & MSG_DONTWAIT,
+ m->msg_flags & MSG_MORE);
tun_put(tun);
return ret;
}
--
2.7.4
^ permalink raw reply related
* [PATCH net-next V2 2/3] vhost_net: tx batching
From: Jason Wang @ 2016-12-28 8:09 UTC (permalink / raw)
To: mst, kvm, virtualization, netdev, linux-kernel
In-Reply-To: <1482912571-3157-1-git-send-email-jasowang@redhat.com>
This patch tries to utilize tuntap rx batching by peeking the tx
virtqueue during transmission, if there's more available buffers in
the virtqueue, set MSG_MORE flag for a hint for backend (e.g tuntap)
to batch the packets.
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/vhost/net.c | 23 ++++++++++++++++++++---
1 file changed, 20 insertions(+), 3 deletions(-)
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 5dc3465..c42e9c3 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -351,6 +351,15 @@ static int vhost_net_tx_get_vq_desc(struct vhost_net *net,
return r;
}
+static bool vhost_exceeds_maxpend(struct vhost_net *net)
+{
+ struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX];
+ struct vhost_virtqueue *vq = &nvq->vq;
+
+ return (nvq->upend_idx + vq->num - VHOST_MAX_PEND) % UIO_MAXIOV
+ == nvq->done_idx;
+}
+
/* Expects to be always run from workqueue - which acts as
* read-size critical section for our kind of RCU. */
static void handle_tx(struct vhost_net *net)
@@ -394,8 +403,7 @@ static void handle_tx(struct vhost_net *net)
/* If more outstanding DMAs, queue the work.
* Handle upend_idx wrap around
*/
- if (unlikely((nvq->upend_idx + vq->num - VHOST_MAX_PEND)
- % UIO_MAXIOV == nvq->done_idx))
+ if (unlikely(vhost_exceeds_maxpend(net)))
break;
head = vhost_net_tx_get_vq_desc(net, vq, vq->iov,
@@ -454,6 +462,16 @@ static void handle_tx(struct vhost_net *net)
msg.msg_control = NULL;
ubufs = NULL;
}
+
+ total_len += len;
+ if (total_len < VHOST_NET_WEIGHT &&
+ !vhost_vq_avail_empty(&net->dev, vq) &&
+ likely(!vhost_exceeds_maxpend(net))) {
+ msg.msg_flags |= MSG_MORE;
+ } else {
+ msg.msg_flags &= ~MSG_MORE;
+ }
+
/* TODO: Check specific error and bomb out unless ENOBUFS? */
err = sock->ops->sendmsg(sock, &msg, len);
if (unlikely(err < 0)) {
@@ -472,7 +490,6 @@ static void handle_tx(struct vhost_net *net)
vhost_add_used_and_signal(&net->dev, vq, head, 0);
else
vhost_zerocopy_signal_used(net, vq);
- total_len += len;
vhost_net_tx_packet(net);
if (unlikely(total_len >= VHOST_NET_WEIGHT)) {
vhost_poll_queue(&vq->poll);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next V2 1/3] vhost: better detection of available buffers
From: Jason Wang @ 2016-12-28 8:09 UTC (permalink / raw)
To: mst, kvm, virtualization, netdev, linux-kernel
In-Reply-To: <1482912571-3157-1-git-send-email-jasowang@redhat.com>
This patch tries to do several tweaks on vhost_vq_avail_empty() for a
better performance:
- check cached avail index first which could avoid userspace memory access.
- using unlikely() for the failure of userspace access
- check vq->last_avail_idx instead of cached avail index as the last
step.
This patch is need for batching supports which needs to peek whether
or not there's still available buffers in the ring.
Signed-off-by: Jason Wang <jasowang@redhat.com>
---
drivers/vhost/vhost.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index d643260..9f11838 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -2241,11 +2241,15 @@ bool vhost_vq_avail_empty(struct vhost_dev *dev, struct vhost_virtqueue *vq)
__virtio16 avail_idx;
int r;
+ if (vq->avail_idx != vq->last_avail_idx)
+ return false;
+
r = vhost_get_user(vq, avail_idx, &vq->avail->idx);
- if (r)
+ if (unlikely(r))
return false;
+ vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
- return vhost16_to_cpu(vq, avail_idx) == vq->avail_idx;
+ return vq->avail_idx == vq->last_avail_idx;
}
EXPORT_SYMBOL_GPL(vhost_vq_avail_empty);
--
2.7.4
^ permalink raw reply related
* [PATCH net-next V2 0/3] vhost net tx batching
From: Jason Wang @ 2016-12-28 8:09 UTC (permalink / raw)
To: mst, kvm, virtualization, netdev, linux-kernel
Hi:
This series tries to implement tx batching support for vhost. This was
done by using MSG_MORE as a hint for under layer socket. The backend
(e.g tap) can then batch the packets temporarily in a list and
submit it all once the number of bacthed exceeds a limitation.
Tests shows obvious improvement on guest pktgen over over
mlx4(noqueue) on host:
Mpps -+%
rx_batched=0 0.90 +0%
rx_batched=4 0.97 +7.8%
rx_batched=8 0.97 +7.8%
rx_batched=16 0.98 +8.9%
rx_batched=32 1.03 +14.4%
rx_batched=48 1.09 +21.1%
rx_batched=64 1.02 +13.3%
Changes from V1:
- drop NAPI handler since we don't use NAPI now
- fix the issues that may exceeds max pending of zerocopy
- more improvement on available buffer detection
- move the limitation of batched pacekts from vhost to tuntap
Please review.
Thanks
Jason Wang (3):
vhost: better detection of available buffers
vhost_net: tx batching
tun: rx batching
drivers/net/tun.c | 66 ++++++++++++++++++++++++++++++++++++++++++++-------
drivers/vhost/net.c | 23 +++++++++++++++---
drivers/vhost/vhost.c | 8 +++++--
3 files changed, 84 insertions(+), 13 deletions(-)
--
2.7.4
^ permalink raw reply
* RE: [PATCH v2] net: stmmac: bug fix to synchronize stmmac_open and stmmac_dvr_probe
From: Kweh, Hock Leong @ 2016-12-28 5:49 UTC (permalink / raw)
To: David Miller, f.fainelli@gmail.com
Cc: Joao.Pinto@synopsys.com, peppe.cavallaro@st.com,
seraphin.bonnaffe@st.com, alexandre.torgue@gmail.com,
manabian@gmail.com, niklas.cassel@axis.com, johan@kernel.org,
pavel@ucw.cz, Ong, Boon Leong, Voon, Weifeng,
lars.persson@axis.com, netdev@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <20161227.113405.362102687632949941.davem@davemloft.net>
> -----Original Message-----
> From: David Miller [mailto:davem@davemloft.net]
> Sent: Wednesday, December 28, 2016 12:34 AM
> To: Kweh, Hock Leong <hock.leong.kweh@intel.com>
> Cc: Joao.Pinto@synopsys.com; peppe.cavallaro@st.com;
> seraphin.bonnaffe@st.com; f.fainelli@gmail.com;
> alexandre.torgue@gmail.com; manabian@gmail.com; niklas.cassel@axis.com;
> johan@kernel.org; pavel@ucw.cz; Ong, Boon Leong
> <boon.leong.ong@intel.com>; Voon, Weifeng <weifeng.voon@intel.com>;
> lars.persson@axis.com; netdev@vger.kernel.org; linux-kernel@vger.kernel.org
> Subject: Re: [PATCH v2] net: stmmac: bug fix to synchronize stmmac_open and
> stmmac_dvr_probe
>
> From: "Kweh, Hock Leong" <hock.leong.kweh@intel.com>
> Date: Tue, 27 Dec 2016 22:42:36 +0800
>
> > From: "Kweh, Hock Leong" <hock.leong.kweh@intel.com>
>
> You are not the author of this change, do not take credit for it.
>
> You have copied Florian's patch character by character, therefore
> he is the author.
>
> You also didn't CC: the netdev mailing list properly.
Hi David & Florian,
Just to clarify that I do not copy exactly from Florian.
I have changed it to have proper handling on mdio unregister
while netdev_register() failed as showed below:
return 0;
-error_mdio_register:
- unregister_netdev(ndev);
error_netdev_register:
+ stmmac_mdio_unregister(ndev);
+error_mdio_register:
netif_napi_del(&priv->napi);
Vs
+
+ return ret;
error_mdio_register:
- unregister_netdev(ndev);
-error_netdev_register:
netif_napi_del(&priv->napi);
Just to point it out here, so that Florian could aware if he/she submit
this fix to the mailing list.
Thanks & Regards,
Wilson
^ permalink raw reply
* Re: [PATCH 01/12] Make and configuration files.
From: David VomLehn @ 2016-12-28 5:24 UTC (permalink / raw)
To: Rami Rosen; +Cc: Netdev, Simon Edelhaus, Dmitrii Tarakanov, Alexander Loktionov
In-Reply-To: <CAKoUArnT72fQm0fd9JPu7kOjuYPhpTC57+2pswnX-Bvb_XSmgA@mail.gmail.com>
On 12/27/2016 08:47 PM, Rami Rosen wrote:
> Hi, David,
>
> For the Makefile, you should follow the pattern which is common in
> Linux Kernel Ethernet drivers, for example,
> http://lxr.free-electrons.com/source/drivers/net/ethernet/intel/i40e/Makefile or
> http://lxr.free-electrons.com/source/drivers/net/ethernet/mellanox/mlx5/core/Makefile
>
>
> Don't think that I ever saw usage of "-j" in a kernel module Makefile;
> apart from it, "-j4" is specific to one platform with a given number
> of cores, and of course there can be platforms with many more cores,
> for which it is less suitable. You can pass the "-j" when running
> "make" from the command line, there is no justification to put it in a
> Makefile:
>
>> +all:
>> + $(MAKE) -j4 CC=$(CC) -C $(BUILD_DIR) M=$(PWD) modules
>> +
>> +dox: .doxygen
>> + @doxygen $<
>> +
>> +clean:
>> + $(MAKE) -j4 -C $(BUILD_DIR) M=$(PWD) clean
> Don't think I ever encountered load/unload targets in Linux Kernel
> Makefiles (not talking about out of tree projects):
>
>> +load:
>> + insmod ./$(TARGET).ko
>> +
>> +unload:
>> + rmmod ./$(TARGET).ko
>
> Regards,
> Rami Rosen
You are right. The driver spent a while as an out-of-tree build module,
where this made sense. It clearly no longer makes sense.
--
David VL
^ permalink raw reply
* Re: George's crazy full state idea (Re: HalfSipHash Acceptable Usage)
From: Hannes Frederic Sowa @ 2016-12-28 5:23 UTC (permalink / raw)
To: George Spelvin, daniel
Cc: ak, davem, David.Laight, ebiggers3, eric.dumazet, Jason,
kernel-hardening, linux-crypto, linux-kernel, luto, netdev, tom,
tytso, vegard.nossum
In-Reply-To: <20161224011754.14207.qmail@ns.sciencehorizons.net>
Hello,
On Fri, 2016-12-23 at 20:17 -0500, George Spelvin wrote:
> Hannes Frederic Sowa wrote:
> > On 24.12.2016 00:39, George Spelvin wrote:
> > > We just finished discussing why 8 bytes isn't enough. If you only
> > > feed back 8 bytes, an attacker who can do 2^64 computation can find it
> > > (by guessing and computing forward to verify the guess) and recover the
> > > previous state. You need to feed back at least as much output as your
> > > security targete. For /dev/urandom's ChaCha20, that's 256 bits.
> > I followed the discussion but it appeared to me that this has the
> > additional constraint of time until the next reseeding event happenes,
> > which is 300s (under the assumption that calls to get_random_int happen
> > regularly, which I expect right now). After that the existing reseeding
> > mechansim will ensure enough backtracking protection. The number of
> > bytes can easily be increased here, given that reseeding was shown to be
> > quite fast already and we produce enough output. But I am not sure if
> > this is a bit overengineered in the end?
>
> I'm not following your description of how the time-based and call-based
> mechanisms interact, but for any mix-back, you should either do enough
> or none at all. (Also called "catastrophic reseeding".)
We call extract_crng when we run out of batched entropy and reseed. How
often we call down to extract_crng depends on how much entropy we
extracted by calls to get_random_int/long, so the number of calls into
those functions matter.
In extract_crng we have a timer which reseeds every 300s the CPRNG and
either uses completely new entropy from the CRNG or calls down into the
CPRNG while also doing backtracing protection (which feeds chacha's
block size / 2 back into chacha, if I read the code correctly, thus
1024 bits, which should be enough).
> For example, two mix-backs of 64 bits gives you 65 bit security, not 128.
> (Because each mixback can be guessed and verified separately.)
Exactly, but the full reseed after running out of entropy is strong
enough to not be defeated by your argumentation. Neither the reseed
from the CRNG.
> > Also agreed. Given your solution below to prandom_u32, I do think it
> > might also work without the seqlock now.
>
> It's not technically a seqlock; in particular the reader doesn't
> spin. But the write side, and general logic is so similar it's
> a good mental model.
>
> Basically, assume a 64-byte buffer. The reader has gone through
> 32 bytes of it, and has 32 left, and when he reads another 8 bytes,
> has to distinguish three cases:
>
> 1) No update; we read the old bytes and there are now 32 - 24 bytes left.
> 2) Update completed while we weren't looking. There are now new
> bytes in the buffer, and we took 8 leaving 64 - 8 = 56.
> 3) Update in progress at the time of the read. We don't know if we
> are seeing old bytes or new bytes, so we have to assume the worst
> and not proceeed unless 32 >= 8, but assume at the end there are
> 64 - 8 = 56 new bytes left.
>
> > I wouldn't have added a disable irqs, but given that I really like your
> > proposal, I would take it in my todo branch and submit it when net-next
> > window opens.
>
> If you want that, I have a pile of patches to prandom I really
> should push upstream. Shall I refresh them and send them to you?
I would like to have a look at them in the new year, certainly! I can
also take care about the core prandom patches, but don't know if I have
time to submit the others to the different subsystems.
Maybe, if David would be okay with that, we can submit all patches
through his tree, as he is also the dedicated maintainer for prandom.
> [... patch descriptions ...]
Thanks,
Hannes
^ permalink raw reply
* Re: [PATCH 05/12] Support for NIC-specific code
From: Rami Rosen @ 2016-12-28 5:21 UTC (permalink / raw)
To: David VomLehn
Cc: Netdev, Simon Edelhaus, Dmitrii Tarakanov, Alexander Loktionov
In-Reply-To: <122d7e0633e8a8ddfbb0c233d6896254b2fa3eef.1482844668.git.vomlehn@texas.net>
Hi, David,
Several nitpicks and comments, from a brief overview:
The commented label //err_exit: should be removed
> +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.c
> @@ -0,0 +1,993 @@
> +//err_exit:
> +//err_exit:
Shouldn't aq_nic_rss_init() be static? isn't it called only from
aq_nic_cfg_init_defaults()?
and it always returns 0, shouldn't it be void as well ? (+ remove
checking the return code when invoking it in
aq_nic_cfg_init_defaults())
> +int aq_nic_rss_init(struct aq_nic_s *self, unsigned int num_rss_queues)
> +{
> + struct aq_nic_cfg_s *cfg = &self->aq_nic_cfg;
> + struct aq_receive_scale_parameters *rss_params = &cfg->aq_rss;
> + int i = 0;
> +
...
> + return 0;
> +}
Shouldn't aq_nic_ndev_alloc() be static ? Isn't it invoked only from
aq_nic_alloc_cold()?
> +struct net_device *aq_nic_ndev_alloc(void)
> +{
...
> +}
> +
> +static unsigned int aq_nic_map_skb_lso(struct aq_nic_s *self,
> + struct sk_buff *skb,
> + struct aq_ring_buff_s *dx)
> +{
> + unsigned int ret = 0U;
> +
> + dx->flags = 0U;
> + dx->len_pkt = skb->len;
> + dx->len_l2 = ETH_HLEN;
> + dx->len_l3 = ip_hdrlen(skb);
> + dx->len_l4 = tcp_hdrlen(skb);
> + dx->mss = skb_shinfo(skb)->gso_size;
> + dx->is_txc = 1U;
> + ret = 1U;
> +
Why not remove this "ret" variable, and simply return 1 ? the method
always returns 1:
> + return ret;
> +}
> +
> +int aq_nic_xmit(struct aq_nic_s *self, struct sk_buff *skb)
> +{
> + struct aq_ring_s *ring = NULL;
> + unsigned int frags = 0U;
> + unsigned int vec = skb->queue_mapping % self->aq_nic_cfg.vecs;
> + unsigned int tc = 0U;
> + int err = 0;
> + bool is_nic_in_bad_state;
> + bool is_locked = false;
> + bool is_busy = false;
> + struct aq_ring_buff_s buffers[AQ_CFG_SKB_FRAGS_MAX];
> +
> + frags = skb_shinfo(skb)->nr_frags + 1;
> +
> + ring = self->aq_ring_tx[AQ_NIC_TCVEC2RING(self, tc, vec)];
> +
> + atomic_inc(&self->busy_count);
> + is_busy = true;
> +
> + if (frags > AQ_CFG_SKB_FRAGS_MAX) {
> + dev_kfree_skb_any(skb);
> + goto err_exit;
> + }
> +
> + is_nic_in_bad_state = AQ_OBJ_TST(self, AQ_NIC_FLAGS_IS_NOT_TX_READY) ||
> + (aq_ring_avail_dx(ring) < AQ_CFG_SKB_FRAGS_MAX);
> +
> + if (is_nic_in_bad_state) {
> + aq_nic_ndev_queue_stop(self, ring->idx);
> + err = NETDEV_TX_BUSY;
> + goto err_exit;
> + }
> +
Usage of this internal block is not common (unless it is under #ifdef,
and also not very common also in that case). I suggest move "unsigned
int trys" to the variables definitions in the beginning of the method
and remove the opening and closing brackets of the following block:
> + {
> + unsigned int trys = AQ_CFG_LOCK_TRYS;
> +
> + frags = aq_nic_map_skb(self, skb, &buffers[0]);
> +
> + do {
> + is_locked = spin_trylock(&ring->lock);
> + } while (--trys && !is_locked);
> + if (!(is_locked)) {
> + err = NETDEV_TX_BUSY;
> + goto err_exit;
> + }
> +
Usually you don't let the mtu be less than 68, for example:
http://lxr.free-electrons.com/source/drivers/net/ethernet/intel/i40e/i40e_main.c#L2246
See also RFV 791:
https://tools.ietf.org/html/rfc791
> +int aq_nic_set_mtu(struct aq_nic_s *self, int new_mtu)
> +{
> + int err = 0;
> +
> + if (new_mtu > self->aq_hw_caps.mtu) {
> + err = 0;
> + goto err_exit;
> + }
> + self->aq_nic_cfg.mtu = new_mtu;
> +
> +err_exit:
> + return err;
> +}
> +
> diff --git a/drivers/net/ethernet/aquantia/atlantic/aq_nic.h b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
> new file mode 100644
> index 0000000..89958e7
> --- /dev/null
> +++ b/drivers/net/ethernet/aquantia/atlantic/aq_nic.h
> @@ -0,0 +1,111 @@
> +/*
> + * Aquantia Corporation Network Driver
> + * Copyright (C) 2014-2016 Aquantia Corporation. All rights reserved
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + */
> +
> +/*
Should be, of course, aq_nic.h:
> + * File aq_nic.c: Declaration of common code for NIC.
> + */
> +
Regards,
Rami Rosen
^ permalink raw reply
* Re: [PATCH 01/12] Make and configuration files.
From: Rami Rosen @ 2016-12-28 4:47 UTC (permalink / raw)
To: David VomLehn
Cc: Netdev, Simon Edelhaus, Dmitrii Tarakanov, Alexander Loktionov
In-Reply-To: <9cc1565a3a398b4f70248ca98d12991071142682.1482844556.git.vomlehn@texas.net>
Hi, David,
For the Makefile, you should follow the pattern which is common in
Linux Kernel Ethernet drivers, for example,
http://lxr.free-electrons.com/source/drivers/net/ethernet/intel/i40e/Makefile or
http://lxr.free-electrons.com/source/drivers/net/ethernet/mellanox/mlx5/core/Makefile
Don't think that I ever saw usage of "-j" in a kernel module Makefile;
apart from it, "-j4" is specific to one platform with a given number
of cores, and of course there can be platforms with many more cores,
for which it is less suitable. You can pass the "-j" when running
"make" from the command line, there is no justification to put it in a
Makefile:
>+all:
>+ $(MAKE) -j4 CC=$(CC) -C $(BUILD_DIR) M=$(PWD) modules
>+
>+dox: .doxygen
>+ @doxygen $<
>+
>+clean:
>+ $(MAKE) -j4 -C $(BUILD_DIR) M=$(PWD) clean
Don't think I ever encountered load/unload targets in Linux Kernel
Makefiles (not talking about out of tree projects):
>+load:
>+ insmod ./$(TARGET).ko
>+
>+unload:
>+ rmmod ./$(TARGET).ko
Regards,
Rami Rosen
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox