summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_en.c137
-rw-r--r--drivers/net/ethernet/microsoft/mana/mana_ethtool.c29
-rw-r--r--include/net/mana/gdma.h4
-rw-r--r--include/net/mana/mana.h44
4 files changed, 150 insertions, 64 deletions
diff --git a/drivers/net/ethernet/microsoft/mana/mana_en.c b/drivers/net/ethernet/microsoft/mana/mana_en.c
index 2519a98ad00b..3c96e6fc3d81 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_en.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_en.c
@@ -1259,6 +1259,9 @@ int mana_gd_query_device_cfg(struct gdma_context *gc, u32 proto_major_ver,
return err;
}
+ gc->cqe8_coalescing_sup = !!(resp.pf_cap_flags1 &
+ MANA_PF_FLAG_1_CQE_8_COALESCING_SUPPORTED);
+
*max_num_vports = resp.max_num_vports;
if (resp.hdr.response.msg_version >= GDMA_MESSAGE_V2) {
@@ -1444,7 +1447,11 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc,
mana_gd_init_req_hdr(&req->hdr, MANA_CONFIG_VPORT_RX, req_buf_size,
sizeof(resp));
- req->hdr.req.msg_version = GDMA_MESSAGE_V2;
+ /* Request & response versions can be different.
+ * HW can handle newer msg versions, by skipping
+ * new fields.
+ */
+ req->hdr.req.msg_version = GDMA_MESSAGE_V5;
req->hdr.resp.msg_version = GDMA_MESSAGE_V2;
req->vport = apc->port_handle;
@@ -1458,8 +1465,13 @@ static int mana_cfg_vport_steering(struct mana_port_context *apc,
req->update_indir_tab = update_tab;
req->default_rxobj = apc->default_rxobj;
- if (rx != TRI_STATE_FALSE)
+ /* Request-msg v5 requires this field */
+ req->rss_hash_types = MANA_HASH_ENABLE_SUPPORTED;
+
+ if (rx != TRI_STATE_FALSE) {
req->cqe_coalescing_enable = apc->cqe_coalescing_enable;
+ req->cqe8_coalescing_enable = apc->cqe8_coalescing_enable;
+ }
if (update_key)
memcpy(&req->hashkey, apc->hashkey, MANA_HASH_KEY_SIZE);
@@ -2064,16 +2076,14 @@ static struct sk_buff *mana_build_skb(struct mana_rxq *rxq, void *buf_va,
static void mana_rx_skb(void *buf_va, bool from_pool,
struct mana_rxcomp_oob *cqe, struct mana_rxq *rxq,
- int i)
+ u32 pkt_len, u32 pkt_hash)
{
struct mana_stats_rx *rx_stats = &rxq->stats;
struct net_device *ndev = rxq->ndev;
- uint pkt_len = cqe->ppi[i].pkt_len;
u16 rxq_idx = rxq->rxq_idx;
struct napi_struct *napi;
struct xdp_buff xdp = {};
struct sk_buff *skb;
- u32 hash_value;
u32 act;
rxq->rx_cq.work_done++;
@@ -2112,12 +2122,10 @@ static void mana_rx_skb(void *buf_va, bool from_pool,
}
if (cqe->rx_hashtype != 0 && (ndev->features & NETIF_F_RXHASH)) {
- hash_value = cqe->ppi[i].pkt_hash;
-
if (cqe->rx_hashtype & MANA_HASH_L4)
- skb_set_hash(skb, hash_value, PKT_HASH_TYPE_L4);
+ skb_set_hash(skb, pkt_hash, PKT_HASH_TYPE_L4);
else
- skb_set_hash(skb, hash_value, PKT_HASH_TYPE_L3);
+ skb_set_hash(skb, pkt_hash, PKT_HASH_TYPE_L3);
}
if (cqe->rx_vlantag_present) {
@@ -2258,6 +2266,43 @@ static void mana_refill_rx_oob(struct device *dev, struct mana_rxq *rxq,
rxoob->dma_sync_offset = dma_sync_offset;
}
+static void mana_process_one_rx_pkt(struct device *dev, struct mana_rxq *rxq,
+ struct mana_rxcomp_oob *oob,
+ u32 pktlen, u32 pkt_hash)
+{
+ struct mana_recv_buf_oob *rxbuf_oob;
+ struct net_device *ndev = rxq->ndev;
+ void *old_buf = NULL;
+ bool old_fp;
+
+ rxbuf_oob = &rxq->rx_oobs[rxq->buf_index];
+ WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1);
+
+ if (unlikely(pktlen > rxq->datasize)) {
+ /* Increase it even if mana_rx_skb() isn't called. */
+ rxq->rx_cq.work_done++;
+
+ ++ndev->stats.rx_dropped;
+ netdev_warn_once(ndev,
+ "Dropped oversized RX packet: len=%u, datasize=%u\n",
+ pktlen, rxq->datasize);
+
+ /* Reuse the RX buffer since rxbuf_oob is unchanged. */
+ } else {
+ mana_refill_rx_oob(dev, rxq, rxbuf_oob, pktlen,
+ &old_buf, &old_fp);
+
+ /* Unsuccessful refill will have old_buf == NULL.
+ * In this case, mana_rx_skb() will drop the packet.
+ */
+ mana_rx_skb(old_buf, old_fp, oob, rxq, pktlen, pkt_hash);
+ }
+
+ mana_move_wq_tail(rxq->gdma_rq, rxbuf_oob->wqe_inf.wqe_size_in_bu);
+
+ mana_post_pkt_rxq(rxq);
+}
+
static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
struct gdma_comp *cqe)
{
@@ -2267,10 +2312,10 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
struct mana_recv_buf_oob *rxbuf_oob;
struct mana_port_context *apc;
struct device *dev = gc->dev;
+ bool coalesced_8 = false;
bool coalesced = false;
- void *old_buf = NULL;
- u32 curr, pktlen;
- bool old_fp;
+ u32 pktlen;
+ int pkt_i;
int i;
apc = netdev_priv(ndev);
@@ -2293,6 +2338,11 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
coalesced = true;
break;
+ case CQE_RX_COALESCED_8:
+ coalesced = true;
+ coalesced_8 = true;
+ break;
+
case CQE_RX_OBJECT_FENCE:
complete(&rxq->fence_event);
return;
@@ -2304,54 +2354,48 @@ static void mana_process_rx_cqe(struct mana_rxq *rxq, struct mana_cq *cq,
return;
}
+ pkt_i = 0;
for (i = 0; i < MANA_RXCOMP_OOB_NUM_PPI; i++) {
- old_buf = NULL;
- pktlen = oob->ppi[i].pkt_len;
- if (pktlen == 0)
- break;
-
- curr = rxq->buf_index;
- rxbuf_oob = &rxq->rx_oobs[curr];
- WARN_ON_ONCE(rxbuf_oob->wqe_inf.wqe_size_in_bu != 1);
-
- if (unlikely(pktlen > rxq->datasize)) {
- /* Increase it even if mana_rx_skb() isn't called. */
- rxq->rx_cq.work_done++;
+ u32 pkt_hash;
- ++ndev->stats.rx_dropped;
- netdev_warn_once(ndev,
- "Dropped oversized RX packet: len=%u, datasize=%u\n",
- pktlen, rxq->datasize);
-
- /* Reuse the RX buffer since rxbuf_oob is unchanged. */
+ if (coalesced_8) {
+ /* 8-pkt mode: 2 packets per PPI entry */
+ pktlen = oob->ppi[i].pkt_len0;
+ pkt_hash = oob->ppi[i].pkt_hash0;
} else {
-
- mana_refill_rx_oob(dev, rxq, rxbuf_oob, pktlen,
- &old_buf, &old_fp);
-
- /* Unsuccessful refill will have old_buf == NULL.
- * In this case, mana_rx_skb() will drop the packet.
- */
- mana_rx_skb(old_buf, old_fp, oob, rxq, i);
+ pktlen = oob->ppi[i].pkt_len;
+ pkt_hash = oob->ppi[i].pkt_hash;
}
+ if (pktlen == 0)
+ break;
- mana_move_wq_tail(rxq->gdma_rq,
- rxbuf_oob->wqe_inf.wqe_size_in_bu);
-
- mana_post_pkt_rxq(rxq);
+ mana_process_one_rx_pkt(dev, rxq, oob, pktlen, pkt_hash);
+ pkt_i++;
if (!coalesced)
break;
+
+ /* Process 2nd packet from the same PPI in 8-pkt mode */
+ if (coalesced_8) {
+ pktlen = oob->ppi[i].pkt_len1;
+ pkt_hash = oob->ppi[i].pkt_hash1;
+ if (pktlen == 0)
+ break;
+
+ mana_process_one_rx_pkt(dev, rxq, oob, pktlen,
+ pkt_hash);
+ pkt_i++;
+ }
}
/* Collect coalesced CQE count based on packets processed.
- * Coalesced CQEs have at least 2 packets, so index is i - 2.
+ * Coalesced CQEs have at least 2 packets, so index is pkt_i - 2.
*/
- if (i > 1) {
+ if (pkt_i > 1) {
u64_stats_update_begin(&rxq->stats.syncp);
- rxq->stats.coalesced_cqe[i - 2]++;
+ rxq->stats.coalesced_cqe[pkt_i - 2]++;
u64_stats_update_end(&rxq->stats.syncp);
- } else if (!i && !pktlen) {
+ } else if (!pkt_i && !pktlen) {
u64_stats_update_begin(&rxq->stats.syncp);
rxq->stats.pkt_len0_err++;
u64_stats_update_end(&rxq->stats.syncp);
@@ -3781,6 +3825,7 @@ static int mana_probe_port(struct mana_context *ac, int port_idx,
apc->port_idx = port_idx;
apc->link_cfg_error = 1;
apc->cqe_coalescing_enable = 0;
+ apc->cqe8_coalescing_enable = 0;
/* Initialize interrupt moderation settings if supported by HW */
if (gc->pf_cap_flags1 & GDMA_PF_CAP_FLAG_1_DYN_INTERRUPT_MODERATION) {
diff --git a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
index 7e441d6ae5dc..ece7ff9cc409 100644
--- a/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
+++ b/drivers/net/ethernet/microsoft/mana/mana_ethtool.c
@@ -178,7 +178,7 @@ static void mana_get_strings_stats(struct mana_port_context *apc, u8 **data)
ethtool_sprintf(data, "rx_%d_xdp_tx", i);
ethtool_sprintf(data, "rx_%d_xdp_redirect", i);
ethtool_sprintf(data, "rx_%d_pkt_len0_err", i);
- for (j = 0; j < MANA_RXCOMP_OOB_NUM_PPI - 1; j++)
+ for (j = 0; j < MANA_CQE_COAL_PKTS_8 - 1; j++)
ethtool_sprintf(data,
"rx_%d_coalesced_cqe_%d",
i,
@@ -241,7 +241,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
u64 xdp_drop;
u64 xdp_tx;
u64 pkt_len0_err;
- u64 coalesced_cqe[MANA_RXCOMP_OOB_NUM_PPI - 1];
+ u64 coalesced_cqe[MANA_CQE_COAL_PKTS_8 - 1];
u64 tso_packets;
u64 tso_bytes;
u64 tso_inner_packets;
@@ -281,7 +281,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
xdp_tx = rx_stats->xdp_tx;
xdp_redirect = rx_stats->xdp_redirect;
pkt_len0_err = rx_stats->pkt_len0_err;
- for (j = 0; j < MANA_RXCOMP_OOB_NUM_PPI - 1; j++)
+ for (j = 0; j < MANA_CQE_COAL_PKTS_8 - 1; j++)
coalesced_cqe[j] = rx_stats->coalesced_cqe[j];
} while (u64_stats_fetch_retry(&rx_stats->syncp, start));
@@ -291,7 +291,7 @@ static void mana_get_ethtool_stats(struct net_device *ndev,
data[i++] = xdp_tx;
data[i++] = xdp_redirect;
data[i++] = pkt_len0_err;
- for (j = 0; j < MANA_RXCOMP_OOB_NUM_PPI - 1; j++)
+ for (j = 0; j < MANA_CQE_COAL_PKTS_8 - 1; j++)
data[i++] = coalesced_cqe[j];
}
@@ -444,6 +444,7 @@ static int mana_get_coalesce(struct net_device *ndev,
struct mana_port_context *apc = netdev_priv(ndev);
kernel_coal->rx_cqe_frames =
+ apc->cqe8_coalescing_enable ? MANA_CQE_COAL_PKTS_8 :
apc->cqe_coalescing_enable ? MANA_RXCOMP_OOB_NUM_PPI : 1;
kernel_coal->rx_cqe_nsecs = apc->cqe_coalescing_timeout_ns;
@@ -479,15 +480,19 @@ static int mana_set_coalesce(struct net_device *ndev,
u16 intr_modr_tx_usec;
u16 intr_modr_tx_comp;
u8 cqe_coalescing_enable;
+ u8 cqe8_coalescing_enable;
bool rx_dim_enabled;
bool tx_dim_enabled;
} saved;
bool modr_changed = false;
bool dim_changed = false;
struct gdma_context *gc;
+ u32 max_cqe_frames;
int err;
gc = apc->ac->gdma_dev->gdma_context;
+ max_cqe_frames = gc->cqe8_coalescing_sup ? MANA_CQE_COAL_PKTS_8 :
+ MANA_RXCOMP_OOB_NUM_PPI;
/* Both static and dynamic interrupt moderation (DIM) rely on the
* same HW capability advertised by the PF.
@@ -502,10 +507,12 @@ static int mana_set_coalesce(struct net_device *ndev,
}
if (kernel_coal->rx_cqe_frames != 1 &&
- kernel_coal->rx_cqe_frames != MANA_RXCOMP_OOB_NUM_PPI) {
+ kernel_coal->rx_cqe_frames != MANA_RXCOMP_OOB_NUM_PPI &&
+ kernel_coal->rx_cqe_frames != max_cqe_frames) {
NL_SET_ERR_MSG_FMT(extack,
- "rx-frames must be 1 or %u, got %u",
+ "rx-frames must be 1 or %u%s, got %u",
MANA_RXCOMP_OOB_NUM_PPI,
+ gc->cqe8_coalescing_sup ? " or 8" : "",
kernel_coal->rx_cqe_frames);
return -EINVAL;
}
@@ -550,8 +557,11 @@ static int mana_set_coalesce(struct net_device *ndev,
saved.tx_dim_enabled = apc->tx_dim_enabled;
saved.cqe_coalescing_enable = apc->cqe_coalescing_enable;
+ saved.cqe8_coalescing_enable = apc->cqe8_coalescing_enable;
apc->cqe_coalescing_enable =
- kernel_coal->rx_cqe_frames == MANA_RXCOMP_OOB_NUM_PPI;
+ kernel_coal->rx_cqe_frames >= MANA_RXCOMP_OOB_NUM_PPI;
+ apc->cqe8_coalescing_enable =
+ kernel_coal->rx_cqe_frames == MANA_CQE_COAL_PKTS_8;
if (!apc->port_is_up) {
WRITE_ONCE(apc->rx_dim_enabled, !!ec->use_adaptive_rx_coalesce);
@@ -559,7 +569,8 @@ static int mana_set_coalesce(struct net_device *ndev,
return 0;
}
- if (apc->cqe_coalescing_enable != saved.cqe_coalescing_enable) {
+ if (apc->cqe_coalescing_enable != saved.cqe_coalescing_enable ||
+ apc->cqe8_coalescing_enable != saved.cqe8_coalescing_enable) {
/* CQE coalescing setting is applied via RSS configuration. */
err = mana_config_rss(apc, TRI_STATE_TRUE, false, false);
if (err) {
@@ -567,6 +578,8 @@ static int mana_set_coalesce(struct net_device *ndev,
err);
apc->cqe_coalescing_enable =
saved.cqe_coalescing_enable;
+ apc->cqe8_coalescing_enable =
+ saved.cqe8_coalescing_enable;
apc->intr_modr_rx_usec = saved.intr_modr_rx_usec;
apc->intr_modr_rx_comp = saved.intr_modr_rx_comp;
apc->intr_modr_tx_usec = saved.intr_modr_tx_usec;
diff --git a/include/net/mana/gdma.h b/include/net/mana/gdma.h
index 8529cef0d7c4..70a7f1fee5d3 100644
--- a/include/net/mana/gdma.h
+++ b/include/net/mana/gdma.h
@@ -182,6 +182,7 @@ struct gdma_general_req {
#define GDMA_MESSAGE_V2 2
#define GDMA_MESSAGE_V3 3
#define GDMA_MESSAGE_V4 4
+#define GDMA_MESSAGE_V5 5
struct gdma_general_resp {
struct gdma_resp_hdr hdr;
@@ -428,6 +429,9 @@ struct gdma_context {
/* L2 MTU */
u16 adapter_mtu;
+ /* NIC supports CQE x8 coalescing */
+ bool cqe8_coalescing_sup;
+
/* This maps a CQ index to the queue structure. */
unsigned int max_num_cqs;
struct gdma_queue **cq_table;
diff --git a/include/net/mana/mana.h b/include/net/mana/mana.h
index 9ffbdff5746f..83b7eff4646e 100644
--- a/include/net/mana/mana.h
+++ b/include/net/mana/mana.h
@@ -68,9 +68,12 @@ enum mana_priv_flag_bits {
#define MAX_PORTS_IN_MANA_DEV 256
-/* Maximum number of packets per coalesced CQE */
+/* Maximum number of PPIs per coalesced CQE */
#define MANA_RXCOMP_OOB_NUM_PPI 4
+/* 8-pkt mode packs up to 2 packets per PPI entry */
+#define MANA_CQE_COAL_PKTS_8 8
+
/* Default/max interrupt moderation settings */
#define MANA_INTR_MODR_USEC_DEF 0
#define MANA_INTR_MODR_COMP_DEF 0
@@ -85,7 +88,7 @@ enum mana_priv_flag_bits {
#define MANA_INTR_MODR_COMP_MASK GENMASK(23, 16)
/* Update this count whenever the respective structures are changed */
-#define MANA_STATS_RX_COUNT (6 + MANA_RXCOMP_OOB_NUM_PPI - 1)
+#define MANA_STATS_RX_COUNT (6 + MANA_CQE_COAL_PKTS_8 - 1)
#define MANA_STATS_TX_COUNT 11
#define MANA_RX_FRAG_ALIGNMENT 64
@@ -97,7 +100,7 @@ struct mana_stats_rx {
u64 xdp_tx;
u64 xdp_redirect;
u64 pkt_len0_err;
- u64 coalesced_cqe[MANA_RXCOMP_OOB_NUM_PPI - 1];
+ u64 coalesced_cqe[MANA_CQE_COAL_PKTS_8 - 1];
struct u64_stats_sync syncp;
};
@@ -208,6 +211,7 @@ enum mana_cqe_type {
CQE_RX_COALESCED_4 = 2,
CQE_RX_OBJECT_FENCE = 3,
CQE_RX_TRUNCATED = 4,
+ CQE_RX_COALESCED_8 = 7,
CQE_TX_OKAY = 32,
CQE_TX_SA_DROP = 33,
@@ -244,12 +248,26 @@ struct mana_cqe_header {
#define MANA_HASH_L4 \
(NDIS_HASH_TCP_IPV4 | NDIS_HASH_UDP_IPV4 | NDIS_HASH_TCP_IPV6 | \
NDIS_HASH_UDP_IPV6 | NDIS_HASH_TCP_IPV6_EX | NDIS_HASH_UDP_IPV6_EX)
+#define MANA_HASH_ENABLE_SUPPORTED \
+ (NDIS_HASH_IPV4 | NDIS_HASH_TCP_IPV4 | NDIS_HASH_UDP_IPV4 | \
+ NDIS_HASH_IPV6 | NDIS_HASH_TCP_IPV6 | NDIS_HASH_UDP_IPV6)
+
+/* Read PPI in two different layouts based on cqe_type */
+union mana_rxcomp_perpkt_info {
+ struct {
+ u32 pkt_len : 16;
+ u32 reserved1 : 16;
+ u32 reserved2;
+ u32 pkt_hash;
+ };
-struct mana_rxcomp_perpkt_info {
- u32 pkt_len : 16;
- u32 reserved1 : 16;
- u32 reserved2;
- u32 pkt_hash;
+ /* Up to two pkts per PPI entry */
+ struct {
+ u32 pkt_hash0;
+ u16 pkt_len0;
+ u16 pkt_len1;
+ u32 pkt_hash1;
+ };
}; /* HW DATA */
/* Receive completion OOB */
@@ -270,7 +288,7 @@ struct mana_rxcomp_oob {
u32 rx_udp_csum_fail : 1;
u32 reserved2 : 1;
- struct mana_rxcomp_perpkt_info ppi[MANA_RXCOMP_OOB_NUM_PPI];
+ union mana_rxcomp_perpkt_info ppi[MANA_RXCOMP_OOB_NUM_PPI];
u32 rx_wqe_offset;
}; /* HW DATA */
@@ -615,6 +633,7 @@ struct mana_port_context {
bool port_st_save; /* Saved port state */
u8 cqe_coalescing_enable;
+ u8 cqe8_coalescing_enable;
u32 cqe_coalescing_timeout_ns;
/* Interrupt moderation settings */
@@ -759,6 +778,8 @@ struct mana_query_device_cfg_req {
u32 reserved;
}; /* HW DATA */
+#define MANA_PF_FLAG_1_CQE_8_COALESCING_SUPPORTED BIT(5)
+
struct mana_query_device_cfg_resp {
struct gdma_resp_hdr hdr;
@@ -994,7 +1015,10 @@ struct mana_cfg_rx_steer_req_v2 {
mana_handle_t default_rxobj;
u8 hashkey[MANA_HASH_KEY_SIZE];
u8 cqe_coalescing_enable;
- u8 reserved2[7];
+ u8 reserved2[3];
+ u16 rss_hash_types;
+ u8 cqe8_coalescing_enable; /* v5 message */
+ u8 reserved3;
mana_handle_t indir_tab[] __counted_by(num_indir_entries);
}; /* HW DATA */