Blame SOURCES/0002-ionic_support_longer_tx_sg_lists.patch

1632d2
Date: Thu, 18 Jun 2020 19:42:38 -0400
1632d2
From: Jonathan Toppins <jtoppins@redhat.com>
1632d2
To: rhkernel-list@redhat.com
1632d2
Cc: darcari@redhat.com, nhorman@redhat.com, linville@redhat.com
1632d2
Subject: [PATCH RHEL-8.3 03/16] ionic: support longer tx sg lists
1632d2
1632d2
The version 1 Tx queues can use longer SG lists than the
1632d2
original version 0 queues, but we need to check to see if the
1632d2
firmware supports the v1 Tx queues.  This implements the queue
1632d2
type query for all queue types, and uses the information to
1632d2
set up for using the longer Tx SG lists.
1632d2
1632d2
Because the Tx SG list can be longer, we need to limit the
1632d2
max ring length to be sure we stay inside the boundaries of a
1632d2
DMA allocation max size, so we lower the max Tx ring size.
1632d2
1632d2
The driver sets its highest known version in the Q_IDENTITY
1632d2
command, and the FW returns the highest version that it knows,
1632d2
bounded by the driver's version.  The negotiated version number
1632d2
is later used in the Q_INIT commands.
1632d2
1632d2
Signed-off-by: Shannon Nelson <snelson@pensando.io>
1632d2
Signed-off-by: David S. Miller <davem@davemloft.net>
1632d2
(cherry picked from commit 5b3f3f2a71ed1cecf6fcf9e8c858a89589415449)
1632d2
Bugzilla: 1848149
1632d2
Build Info: https://brewweb.engineering.redhat.com/brew/taskinfo?taskID=29498383
1632d2
Tested: QE tested devel kernel as well as the partner
1632d2
Signed-off-by: Jonathan Toppins <jtoppins@redhat.com>
1632d2
---
1632d2
 drivers/net/ethernet/pensando/ionic/ionic_dev.c    |  14 +++
1632d2
 drivers/net/ethernet/pensando/ionic/ionic_dev.h    |   7 +-
1632d2
 .../net/ethernet/pensando/ionic/ionic_ethtool.c    |   4 +-
1632d2
 drivers/net/ethernet/pensando/ionic/ionic_if.h     | 112 +++++++++++++++++---
1632d2
 drivers/net/ethernet/pensando/ionic/ionic_lif.c    | 114 ++++++++++++++++++++-
1632d2
 drivers/net/ethernet/pensando/ionic/ionic_lif.h    |  13 +++
1632d2
 drivers/net/ethernet/pensando/ionic/ionic_main.c   |   2 +
1632d2
 drivers/net/ethernet/pensando/ionic/ionic_txrx.c   |  27 +++--
1632d2
 8 files changed, 263 insertions(+), 30 deletions(-)
1632d2
1632d2
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.c b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
1632d2
index f4ae40ae1e53..d83eff0ae0ac 100644
1632d2
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.c
1632d2
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.c
1632d2
@@ -388,6 +388,19 @@ int ionic_set_vf_config(struct ionic *ionic, int vf, u8 attr, u8 *data)
1632d2
 }
1632d2
 
1632d2
 /* LIF commands */
1632d2
+void ionic_dev_cmd_queue_identify(struct ionic_dev *idev,
1632d2
+				  u16 lif_type, u8 qtype, u8 qver)
1632d2
+{
1632d2
+	union ionic_dev_cmd cmd = {
1632d2
+		.q_identify.opcode = IONIC_CMD_Q_IDENTIFY,
1632d2
+		.q_identify.lif_type = lif_type,
1632d2
+		.q_identify.type = qtype,
1632d2
+		.q_identify.ver = qver,
1632d2
+	};
1632d2
+
1632d2
+	ionic_dev_cmd_go(idev, &cmd);
1632d2
+}
1632d2
+
1632d2
 void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver)
1632d2
 {
1632d2
 	union ionic_dev_cmd cmd = {
1632d2
@@ -431,6 +444,7 @@ void ionic_dev_cmd_adminq_init(struct ionic_dev *idev, struct ionic_qcq *qcq,
1632d2
 		.q_init.opcode = IONIC_CMD_Q_INIT,
1632d2
 		.q_init.lif_index = cpu_to_le16(lif_index),
1632d2
 		.q_init.type = q->type,
1632d2
+		.q_init.ver = qcq->q.lif->qtype_info[q->type].version,
1632d2
 		.q_init.index = cpu_to_le32(q->index),
1632d2
 		.q_init.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
1632d2
 					    IONIC_QINIT_F_ENA),
1632d2
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_dev.h b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
1632d2
index 587398b01997..33519a8765eb 100644
1632d2
--- a/drivers/net/ethernet/pensando/ionic/ionic_dev.h
1632d2
+++ b/drivers/net/ethernet/pensando/ionic/ionic_dev.h
1632d2
@@ -12,7 +12,8 @@
1632d2
 
1632d2
 #define IONIC_MIN_MTU			ETH_MIN_MTU
1632d2
 #define IONIC_MAX_MTU			9194
1632d2
-#define IONIC_MAX_TXRX_DESC		16384
1632d2
+#define IONIC_MAX_TX_DESC		8192
1632d2
+#define IONIC_MAX_RX_DESC		16384
1632d2
 #define IONIC_MIN_TXRX_DESC		16
1632d2
 #define IONIC_DEF_TXRX_DESC		4096
1632d2
 #define IONIC_LIFS_MAX			1024
1632d2
@@ -83,6 +84,8 @@ static_assert(sizeof(struct ionic_q_init_cmd) == 64);
1632d2
 static_assert(sizeof(struct ionic_q_init_comp) == 16);
1632d2
 static_assert(sizeof(struct ionic_q_control_cmd) == 64);
1632d2
 static_assert(sizeof(ionic_q_control_comp) == 16);
1632d2
+static_assert(sizeof(struct ionic_q_identify_cmd) == 64);
1632d2
+static_assert(sizeof(struct ionic_q_identify_comp) == 16);
1632d2
 
1632d2
 static_assert(sizeof(struct ionic_rx_mode_set_cmd) == 64);
1632d2
 static_assert(sizeof(ionic_rx_mode_set_comp) == 16);
1632d2
@@ -283,6 +286,8 @@ void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type);
1632d2
 void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type);
1632d2
 
1632d2
 int ionic_set_vf_config(struct ionic *ionic, int vf, u8 attr, u8 *data);
1632d2
+void ionic_dev_cmd_queue_identify(struct ionic_dev *idev,
1632d2
+				  u16 lif_type, u8 qtype, u8 qver);
1632d2
 void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver);
1632d2
 void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index,
1632d2
 			    dma_addr_t addr);
1632d2
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
1632d2
index 6996229facfd..3f9a73aaef61 100644
1632d2
--- a/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
1632d2
+++ b/drivers/net/ethernet/pensando/ionic/ionic_ethtool.c
1632d2
@@ -458,9 +458,9 @@ static void ionic_get_ringparam(struct net_device *netdev,
1632d2
 {
1632d2
 	struct ionic_lif *lif = netdev_priv(netdev);
1632d2
 
1632d2
-	ring->tx_max_pending = IONIC_MAX_TXRX_DESC;
1632d2
+	ring->tx_max_pending = IONIC_MAX_TX_DESC;
1632d2
 	ring->tx_pending = lif->ntxq_descs;
1632d2
-	ring->rx_max_pending = IONIC_MAX_TXRX_DESC;
1632d2
+	ring->rx_max_pending = IONIC_MAX_RX_DESC;
1632d2
 	ring->rx_pending = lif->nrxq_descs;
1632d2
 }
1632d2
 
1632d2
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_if.h b/drivers/net/ethernet/pensando/ionic/ionic_if.h
1632d2
index 2804a24a9d73..7b9ec07db363 100644
1632d2
--- a/drivers/net/ethernet/pensando/ionic/ionic_if.h
1632d2
+++ b/drivers/net/ethernet/pensando/ionic/ionic_if.h
1632d2
@@ -40,6 +40,7 @@ enum ionic_cmd_opcode {
1632d2
 	IONIC_CMD_RX_FILTER_DEL			= 32,
1632d2
 
1632d2
 	/* Queue commands */
1632d2
+	IONIC_CMD_Q_IDENTIFY			= 39,
1632d2
 	IONIC_CMD_Q_INIT			= 40,
1632d2
 	IONIC_CMD_Q_CONTROL			= 41,
1632d2
 
1632d2
@@ -469,6 +470,66 @@ struct ionic_lif_init_comp {
1632d2
 	u8 rsvd2[12];
1632d2
 };
1632d2
 
1632d2
+ /**
1632d2
+  * struct ionic_q_identify_cmd - queue identify command
1632d2
+  * @opcode:     opcode
1632d2
+  * @lif_type:   LIF type (enum ionic_lif_type)
1632d2
+  * @type:       Logical queue type (enum ionic_logical_qtype)
1632d2
+  * @ver:        Highest queue type version that the driver supports
1632d2
+  */
1632d2
+struct ionic_q_identify_cmd {
1632d2
+	u8     opcode;
1632d2
+	u8     rsvd;
1632d2
+	__le16 lif_type;
1632d2
+	u8     type;
1632d2
+	u8     ver;
1632d2
+	u8     rsvd2[58];
1632d2
+};
1632d2
+
1632d2
+/**
1632d2
+ * struct ionic_q_identify_comp - queue identify command completion
1632d2
+ * @status:     Status of the command (enum ionic_status_code)
1632d2
+ * @comp_index: Index in the descriptor ring for which this is the completion
1632d2
+ * @ver:        Queue type version that can be used with FW
1632d2
+ */
1632d2
+struct ionic_q_identify_comp {
1632d2
+	u8     status;
1632d2
+	u8     rsvd;
1632d2
+	__le16 comp_index;
1632d2
+	u8     ver;
1632d2
+	u8     rsvd2[11];
1632d2
+};
1632d2
+
1632d2
+/**
1632d2
+ * union ionic_q_identity - queue identity information
1632d2
+ *     @version:        Queue type version that can be used with FW
1632d2
+ *     @supported:      Bitfield of queue versions, first bit = ver 0
1632d2
+ *     @features:       Queue features
1632d2
+ *     @desc_sz:        Descriptor size
1632d2
+ *     @comp_sz:        Completion descriptor size
1632d2
+ *     @sg_desc_sz:     Scatter/Gather descriptor size
1632d2
+ *     @max_sg_elems:   Maximum number of Scatter/Gather elements
1632d2
+ *     @sg_desc_stride: Number of Scatter/Gather elements per descriptor
1632d2
+ */
1632d2
+union ionic_q_identity {
1632d2
+	struct {
1632d2
+		u8      version;
1632d2
+		u8      supported;
1632d2
+		u8      rsvd[6];
1632d2
+#define IONIC_QIDENT_F_CQ	0x01	/* queue has completion ring */
1632d2
+#define IONIC_QIDENT_F_SG	0x02	/* queue has scatter/gather ring */
1632d2
+#define IONIC_QIDENT_F_EQ	0x04	/* queue can use event queue */
1632d2
+#define IONIC_QIDENT_F_CMB	0x08	/* queue is in cmb bar */
1632d2
+		__le64  features;
1632d2
+		__le16  desc_sz;
1632d2
+		__le16  comp_sz;
1632d2
+		__le16  sg_desc_sz;
1632d2
+		__le16  max_sg_elems;
1632d2
+		__le16  sg_desc_stride;
1632d2
+	};
1632d2
+	__le32 words[478];
1632d2
+};
1632d2
+
1632d2
 /**
1632d2
  * struct ionic_q_init_cmd - Queue init command
1632d2
  * @opcode:       opcode
1632d2
@@ -733,20 +794,31 @@ static inline void decode_txq_desc_cmd(u64 cmd, u8 *opcode, u8 *flags,
1632d2
 	*addr = (cmd >> IONIC_TXQ_DESC_ADDR_SHIFT) & IONIC_TXQ_DESC_ADDR_MASK;
1632d2
 };
1632d2
 
1632d2
-#define IONIC_TX_MAX_SG_ELEMS	8
1632d2
-#define IONIC_RX_MAX_SG_ELEMS	8
1632d2
-
1632d2
 /**
1632d2
- * struct ionic_txq_sg_desc - Transmit scatter-gather (SG) list
1632d2
+ * struct ionic_txq_sg_elem - Transmit scatter-gather (SG) descriptor element
1632d2
  * @addr:      DMA address of SG element data buffer
1632d2
  * @len:       Length of SG element data buffer, in bytes
1632d2
  */
1632d2
+struct ionic_txq_sg_elem {
1632d2
+	__le64 addr;
1632d2
+	__le16 len;
1632d2
+	__le16 rsvd[3];
1632d2
+};
1632d2
+
1632d2
+/**
1632d2
+ * struct ionic_txq_sg_desc - Transmit scatter-gather (SG) list
1632d2
+ * @elems:     Scatter-gather elements
1632d2
+ */
1632d2
 struct ionic_txq_sg_desc {
1632d2
-	struct ionic_txq_sg_elem {
1632d2
-		__le64 addr;
1632d2
-		__le16 len;
1632d2
-		__le16 rsvd[3];
1632d2
-	} elems[IONIC_TX_MAX_SG_ELEMS];
1632d2
+#define IONIC_TX_MAX_SG_ELEMS		8
1632d2
+#define IONIC_TX_SG_DESC_STRIDE		8
1632d2
+	struct ionic_txq_sg_elem elems[IONIC_TX_MAX_SG_ELEMS];
1632d2
+};
1632d2
+
1632d2
+struct ionic_txq_sg_desc_v1 {
1632d2
+#define IONIC_TX_MAX_SG_ELEMS_V1		15
1632d2
+#define IONIC_TX_SG_DESC_STRIDE_V1		16
1632d2
+	struct ionic_txq_sg_elem elems[IONIC_TX_SG_DESC_STRIDE_V1];
1632d2
 };
1632d2
 
1632d2
 /**
1632d2
@@ -791,16 +863,24 @@ struct ionic_rxq_desc {
1632d2
 };
1632d2
 
1632d2
 /**
1632d2
- * struct ionic_rxq_sg_desc - Receive scatter-gather (SG) list
1632d2
+ * struct ionic_rxq_sg_desc - Receive scatter-gather (SG) descriptor element
1632d2
  * @addr:      DMA address of SG element data buffer
1632d2
  * @len:       Length of SG element data buffer, in bytes
1632d2
  */
1632d2
+struct ionic_rxq_sg_elem {
1632d2
+	__le64 addr;
1632d2
+	__le16 len;
1632d2
+	__le16 rsvd[3];
1632d2
+};
1632d2
+
1632d2
+/**
1632d2
+ * struct ionic_rxq_sg_desc - Receive scatter-gather (SG) list
1632d2
+ * @elems:     Scatter-gather elements
1632d2
+ */
1632d2
 struct ionic_rxq_sg_desc {
1632d2
-	struct ionic_rxq_sg_elem {
1632d2
-		__le64 addr;
1632d2
-		__le16 len;
1632d2
-		__le16 rsvd[3];
1632d2
-	} elems[IONIC_RX_MAX_SG_ELEMS];
1632d2
+#define IONIC_RX_MAX_SG_ELEMS		8
1632d2
+#define IONIC_RX_SG_DESC_STRIDE		8
1632d2
+	struct ionic_rxq_sg_elem elems[IONIC_RX_SG_DESC_STRIDE];
1632d2
 };
1632d2
 
1632d2
 /**
1632d2
@@ -2389,6 +2469,7 @@ union ionic_dev_cmd {
1632d2
 	struct ionic_qos_init_cmd qos_init;
1632d2
 	struct ionic_qos_reset_cmd qos_reset;
1632d2
 
1632d2
+	struct ionic_q_identify_cmd q_identify;
1632d2
 	struct ionic_q_init_cmd q_init;
1632d2
 };
1632d2
 
1632d2
@@ -2421,6 +2502,7 @@ union ionic_dev_cmd_comp {
1632d2
 	ionic_qos_init_comp qos_init;
1632d2
 	ionic_qos_reset_comp qos_reset;
1632d2
 
1632d2
+	struct ionic_q_identify_comp q_identify;
1632d2
 	struct ionic_q_init_comp q_init;
1632d2
 };
1632d2
 
1632d2
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.c b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
1632d2
index f8a9c1bcffc9..d60ef816604a 100644
1632d2
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.c
1632d2
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.c
1632d2
@@ -17,6 +17,16 @@
1632d2
 #include "ionic_ethtool.h"
1632d2
 #include "ionic_debugfs.h"
1632d2
 
1632d2
+/* queuetype support level */
1632d2
+static const u8 ionic_qtype_versions[IONIC_QTYPE_MAX] = {
1632d2
+	[IONIC_QTYPE_ADMINQ]  = 0,   /* 0 = Base version with CQ support */
1632d2
+	[IONIC_QTYPE_NOTIFYQ] = 0,   /* 0 = Base version */
1632d2
+	[IONIC_QTYPE_RXQ]     = 0,   /* 0 = Base version with CQ+SG support */
1632d2
+	[IONIC_QTYPE_TXQ]     = 1,   /* 0 = Base version with CQ+SG support
1632d2
+				      * 1 =   ... with Tx SG version 1
1632d2
+				      */
1632d2
+};
1632d2
+
1632d2
 static void ionic_lif_rx_mode(struct ionic_lif *lif, unsigned int rx_mode);
1632d2
 static int ionic_lif_addr_add(struct ionic_lif *lif, const u8 *addr);
1632d2
 static int ionic_lif_addr_del(struct ionic_lif *lif, const u8 *addr);
1632d2
@@ -27,6 +37,7 @@ static void ionic_lif_set_netdev_info(struct ionic_lif *lif);
1632d2
 
1632d2
 static int ionic_start_queues(struct ionic_lif *lif);
1632d2
 static void ionic_stop_queues(struct ionic_lif *lif);
1632d2
+static void ionic_lif_queue_identify(struct ionic_lif *lif);
1632d2
 
1632d2
 static void ionic_lif_deferred_work(struct work_struct *work)
1632d2
 {
1632d2
@@ -597,6 +608,7 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
1632d2
 			.opcode = IONIC_CMD_Q_INIT,
1632d2
 			.lif_index = cpu_to_le16(lif->index),
1632d2
 			.type = q->type,
1632d2
+			.ver = lif->qtype_info[q->type].version,
1632d2
 			.index = cpu_to_le32(q->index),
1632d2
 			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
1632d2
 					     IONIC_QINIT_F_SG),
1632d2
@@ -614,6 +626,8 @@ static int ionic_lif_txq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
1632d2
 	dev_dbg(dev, "txq_init.index %d\n", ctx.cmd.q_init.index);
1632d2
 	dev_dbg(dev, "txq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
1632d2
 	dev_dbg(dev, "txq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
1632d2
+	dev_dbg(dev, "txq_init.flags 0x%x\n", ctx.cmd.q_init.flags);
1632d2
+	dev_dbg(dev, "txq_init.ver %d\n", ctx.cmd.q_init.ver);
1632d2
 
1632d2
 	q->tail = q->info;
1632d2
 	q->head = q->tail;
1632d2
@@ -646,6 +660,7 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
1632d2
 			.opcode = IONIC_CMD_Q_INIT,
1632d2
 			.lif_index = cpu_to_le16(lif->index),
1632d2
 			.type = q->type,
1632d2
+			.ver = lif->qtype_info[q->type].version,
1632d2
 			.index = cpu_to_le32(q->index),
1632d2
 			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
1632d2
 					     IONIC_QINIT_F_SG),
1632d2
@@ -663,6 +678,8 @@ static int ionic_lif_rxq_init(struct ionic_lif *lif, struct ionic_qcq *qcq)
1632d2
 	dev_dbg(dev, "rxq_init.index %d\n", ctx.cmd.q_init.index);
1632d2
 	dev_dbg(dev, "rxq_init.ring_base 0x%llx\n", ctx.cmd.q_init.ring_base);
1632d2
 	dev_dbg(dev, "rxq_init.ring_size %d\n", ctx.cmd.q_init.ring_size);
1632d2
+	dev_dbg(dev, "rxq_init.flags 0x%x\n", ctx.cmd.q_init.flags);
1632d2
+	dev_dbg(dev, "rxq_init.ver %d\n", ctx.cmd.q_init.ver);
1632d2
 
1632d2
 	q->tail = q->info;
1632d2
 	q->head = q->tail;
1632d2
@@ -726,7 +743,7 @@ static bool ionic_notifyq_service(struct ionic_cq *cq,
1632d2
 		}
1632d2
 		break;
1632d2
 	default:
1632d2
-		netdev_warn(netdev, "Notifyq unknown event ecode=%d eid=%lld\n",
1632d2
+		netdev_warn(netdev, "Notifyq event ecode=%d eid=%lld\n",
1632d2
 			    comp->event.ecode, eid);
1632d2
 		break;
1632d2
 	}
1632d2
@@ -1509,17 +1526,25 @@ static void ionic_txrx_free(struct ionic_lif *lif)
1632d2
 
1632d2
 static int ionic_txrx_alloc(struct ionic_lif *lif)
1632d2
 {
1632d2
+	unsigned int sg_desc_sz;
1632d2
 	unsigned int flags;
1632d2
 	unsigned int i;
1632d2
 	int err = 0;
1632d2
 
1632d2
+	if (lif->qtype_info[IONIC_QTYPE_TXQ].version >= 1 &&
1632d2
+	    lif->qtype_info[IONIC_QTYPE_TXQ].sg_desc_sz ==
1632d2
+					  sizeof(struct ionic_txq_sg_desc_v1))
1632d2
+		sg_desc_sz = sizeof(struct ionic_txq_sg_desc_v1);
1632d2
+	else
1632d2
+		sg_desc_sz = sizeof(struct ionic_txq_sg_desc);
1632d2
+
1632d2
 	flags = IONIC_QCQ_F_TX_STATS | IONIC_QCQ_F_SG;
1632d2
 	for (i = 0; i < lif->nxqs; i++) {
1632d2
 		err = ionic_qcq_alloc(lif, IONIC_QTYPE_TXQ, i, "tx", flags,
1632d2
 				      lif->ntxq_descs,
1632d2
 				      sizeof(struct ionic_txq_desc),
1632d2
 				      sizeof(struct ionic_txq_comp),
1632d2
-				      sizeof(struct ionic_txq_sg_desc),
1632d2
+				      sg_desc_sz,
1632d2
 				      lif->kern_pid, &lif->txqcqs[i].qcq);
1632d2
 		if (err)
1632d2
 			goto err_out;
1632d2
@@ -2065,9 +2090,17 @@ int ionic_lifs_alloc(struct ionic *ionic)
1632d2
 
1632d2
 	/* only build the first lif, others are for later features */
1632d2
 	set_bit(0, ionic->lifbits);
1632d2
+
1632d2
 	lif = ionic_lif_alloc(ionic, 0);
1632d2
+	if (IS_ERR_OR_NULL(lif)) {
1632d2
+		clear_bit(0, ionic->lifbits);
1632d2
+		return -ENOMEM;
1632d2
+	}
1632d2
+
1632d2
+	lif->lif_type = IONIC_LIF_TYPE_CLASSIC;
1632d2
+	ionic_lif_queue_identify(lif);
1632d2
 
1632d2
-	return PTR_ERR_OR_ZERO(lif);
1632d2
+	return 0;
1632d2
 }
1632d2
 
1632d2
 static void ionic_lif_reset(struct ionic_lif *lif)
1632d2
@@ -2292,6 +2325,7 @@ static int ionic_lif_notifyq_init(struct ionic_lif *lif)
1632d2
 			.opcode = IONIC_CMD_Q_INIT,
1632d2
 			.lif_index = cpu_to_le16(lif->index),
1632d2
 			.type = q->type,
1632d2
+			.ver = lif->qtype_info[q->type].version,
1632d2
 			.index = cpu_to_le32(q->index),
1632d2
 			.flags = cpu_to_le16(IONIC_QINIT_F_IRQ |
1632d2
 					     IONIC_QINIT_F_ENA),
1632d2
@@ -2578,6 +2612,80 @@ void ionic_lifs_unregister(struct ionic *ionic)
1632d2
 		unregister_netdev(ionic->master_lif->netdev);
1632d2
 }
1632d2
 
1632d2
+static void ionic_lif_queue_identify(struct ionic_lif *lif)
1632d2
+{
1632d2
+	struct ionic *ionic = lif->ionic;
1632d2
+	union ionic_q_identity *q_ident;
1632d2
+	struct ionic_dev *idev;
1632d2
+	int qtype;
1632d2
+	int err;
1632d2
+
1632d2
+	idev = &lif->ionic->idev;
1632d2
+	q_ident = (union ionic_q_identity *)&idev->dev_cmd_regs->data;
1632d2
+
1632d2
+	for (qtype = 0; qtype < ARRAY_SIZE(ionic_qtype_versions); qtype++) {
1632d2
+		struct ionic_qtype_info *qti = &lif->qtype_info[qtype];
1632d2
+
1632d2
+		/* filter out the ones we know about */
1632d2
+		switch (qtype) {
1632d2
+		case IONIC_QTYPE_ADMINQ:
1632d2
+		case IONIC_QTYPE_NOTIFYQ:
1632d2
+		case IONIC_QTYPE_RXQ:
1632d2
+		case IONIC_QTYPE_TXQ:
1632d2
+			break;
1632d2
+		default:
1632d2
+			continue;
1632d2
+		}
1632d2
+
1632d2
+		memset(qti, 0, sizeof(*qti));
1632d2
+
1632d2
+		mutex_lock(&ionic->dev_cmd_lock);
1632d2
+		ionic_dev_cmd_queue_identify(idev, lif->lif_type, qtype,
1632d2
+					     ionic_qtype_versions[qtype]);
1632d2
+		err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT);
1632d2
+		if (!err) {
1632d2
+			qti->version   = q_ident->version;
1632d2
+			qti->supported = q_ident->supported;
1632d2
+			qti->features  = le64_to_cpu(q_ident->features);
1632d2
+			qti->desc_sz   = le16_to_cpu(q_ident->desc_sz);
1632d2
+			qti->comp_sz   = le16_to_cpu(q_ident->comp_sz);
1632d2
+			qti->sg_desc_sz   = le16_to_cpu(q_ident->sg_desc_sz);
1632d2
+			qti->max_sg_elems = le16_to_cpu(q_ident->max_sg_elems);
1632d2
+			qti->sg_desc_stride = le16_to_cpu(q_ident->sg_desc_stride);
1632d2
+		}
1632d2
+		mutex_unlock(&ionic->dev_cmd_lock);
1632d2
+
1632d2
+		if (err == -EINVAL) {
1632d2
+			dev_err(ionic->dev, "qtype %d not supported\n", qtype);
1632d2
+			continue;
1632d2
+		} else if (err == -EIO) {
1632d2
+			dev_err(ionic->dev, "q_ident failed, not supported on older FW\n");
1632d2
+			return;
1632d2
+		} else if (err) {
1632d2
+			dev_err(ionic->dev, "q_ident failed, qtype %d: %d\n",
1632d2
+				qtype, err);
1632d2
+			return;
1632d2
+		}
1632d2
+
1632d2
+		dev_dbg(ionic->dev, " qtype[%d].version = %d\n",
1632d2
+			qtype, qti->version);
1632d2
+		dev_dbg(ionic->dev, " qtype[%d].supported = 0x%02x\n",
1632d2
+			qtype, qti->supported);
1632d2
+		dev_dbg(ionic->dev, " qtype[%d].features = 0x%04llx\n",
1632d2
+			qtype, qti->features);
1632d2
+		dev_dbg(ionic->dev, " qtype[%d].desc_sz = %d\n",
1632d2
+			qtype, qti->desc_sz);
1632d2
+		dev_dbg(ionic->dev, " qtype[%d].comp_sz = %d\n",
1632d2
+			qtype, qti->comp_sz);
1632d2
+		dev_dbg(ionic->dev, " qtype[%d].sg_desc_sz = %d\n",
1632d2
+			qtype, qti->sg_desc_sz);
1632d2
+		dev_dbg(ionic->dev, " qtype[%d].max_sg_elems = %d\n",
1632d2
+			qtype, qti->max_sg_elems);
1632d2
+		dev_dbg(ionic->dev, " qtype[%d].sg_desc_stride = %d\n",
1632d2
+			qtype, qti->sg_desc_stride);
1632d2
+	}
1632d2
+}
1632d2
+
1632d2
 int ionic_lif_identify(struct ionic *ionic, u8 lif_type,
1632d2
 		       union ionic_lif_identity *lid)
1632d2
 {
1632d2
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_lif.h b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
1632d2
index 5d4ffda5c05f..1a30f0fb20b9 100644
1632d2
--- a/drivers/net/ethernet/pensando/ionic/ionic_lif.h
1632d2
+++ b/drivers/net/ethernet/pensando/ionic/ionic_lif.h
1632d2
@@ -133,6 +133,17 @@ enum ionic_lif_state_flags {
1632d2
 	IONIC_LIF_F_STATE_SIZE
1632d2
 };
1632d2
 
1632d2
+struct ionic_qtype_info {
1632d2
+	u8  version;
1632d2
+	u8  supported;
1632d2
+	u64 features;
1632d2
+	u16 desc_sz;
1632d2
+	u16 comp_sz;
1632d2
+	u16 sg_desc_sz;
1632d2
+	u16 max_sg_elems;
1632d2
+	u16 sg_desc_stride;
1632d2
+};
1632d2
+
1632d2
 #define IONIC_LIF_NAME_MAX_SZ		32
1632d2
 struct ionic_lif {
1632d2
 	char name[IONIC_LIF_NAME_MAX_SZ];
1632d2
@@ -161,11 +172,13 @@ struct ionic_lif {
1632d2
 	bool mc_overflow;
1632d2
 	unsigned int nmcast;
1632d2
 	bool uc_overflow;
1632d2
+	u16 lif_type;
1632d2
 	unsigned int nucast;
1632d2
 
1632d2
 	struct ionic_lif_info *info;
1632d2
 	dma_addr_t info_pa;
1632d2
 	u32 info_sz;
1632d2
+	struct ionic_qtype_info qtype_info[IONIC_QTYPE_MAX];
1632d2
 
1632d2
 	u16 rss_types;
1632d2
 	u8 rss_hash_key[IONIC_RSS_HASH_KEY_SIZE];
1632d2
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_main.c b/drivers/net/ethernet/pensando/ionic/ionic_main.c
1632d2
index 15911ee1af32..34ccb8f53cda 100644
1632d2
--- a/drivers/net/ethernet/pensando/ionic/ionic_main.c
1632d2
+++ b/drivers/net/ethernet/pensando/ionic/ionic_main.c
1632d2
@@ -152,6 +152,8 @@ static const char *ionic_opcode_to_str(enum ionic_cmd_opcode opcode)
1632d2
 		return "IONIC_CMD_RX_FILTER_ADD";
1632d2
 	case IONIC_CMD_RX_FILTER_DEL:
1632d2
 		return "IONIC_CMD_RX_FILTER_DEL";
1632d2
+	case IONIC_CMD_Q_IDENTIFY:
1632d2
+		return "IONIC_CMD_Q_IDENTIFY";
1632d2
 	case IONIC_CMD_Q_INIT:
1632d2
 		return "IONIC_CMD_Q_INIT";
1632d2
 	case IONIC_CMD_Q_CONTROL:
1632d2
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
1632d2
index d233b6e77b1e..6b14e55a6780 100644
1632d2
--- a/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
1632d2
+++ b/drivers/net/ethernet/pensando/ionic/ionic_txrx.c
1632d2
@@ -10,8 +10,10 @@
1632d2
 #include "ionic_lif.h"
1632d2
 #include "ionic_txrx.h"
1632d2
 
1632d2
-static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_info,
1632d2
-			   struct ionic_cq_info *cq_info, void *cb_arg);
1632d2
+static void ionic_rx_clean(struct ionic_queue *q,
1632d2
+			   struct ionic_desc_info *desc_info,
1632d2
+			   struct ionic_cq_info *cq_info,
1632d2
+			   void *cb_arg);
1632d2
 
1632d2
 static inline void ionic_txq_post(struct ionic_queue *q, bool ring_dbell,
1632d2
 				  ionic_desc_cb cb_func, void *cb_arg)
1632d2
@@ -140,8 +142,10 @@ static struct sk_buff *ionic_rx_copybreak(struct ionic_queue *q,
1632d2
 	return skb;
1632d2
 }
1632d2
 
1632d2
-static void ionic_rx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_info,
1632d2
-			   struct ionic_cq_info *cq_info, void *cb_arg)
1632d2
+static void ionic_rx_clean(struct ionic_queue *q,
1632d2
+			   struct ionic_desc_info *desc_info,
1632d2
+			   struct ionic_cq_info *cq_info,
1632d2
+			   void *cb_arg)
1632d2
 {
1632d2
 	struct ionic_rxq_comp *comp = cq_info->cq_desc;
1632d2
 	struct ionic_qcq *qcq = q_to_qcq(q);
1632d2
@@ -475,7 +479,8 @@ int ionic_rx_napi(struct napi_struct *napi, int budget)
1632d2
 	return work_done;
1632d2
 }
1632d2
 
1632d2
-static dma_addr_t ionic_tx_map_single(struct ionic_queue *q, void *data, size_t len)
1632d2
+static dma_addr_t ionic_tx_map_single(struct ionic_queue *q,
1632d2
+				      void *data, size_t len)
1632d2
 {
1632d2
 	struct ionic_tx_stats *stats = q_to_tx_stats(q);
1632d2
 	struct device *dev = q->lif->ionic->dev;
1632d2
@@ -491,7 +496,8 @@ static dma_addr_t ionic_tx_map_single(struct ionic_queue *q, void *data, size_t
1632d2
 	return dma_addr;
1632d2
 }
1632d2
 
1632d2
-static dma_addr_t ionic_tx_map_frag(struct ionic_queue *q, const skb_frag_t *frag,
1632d2
+static dma_addr_t ionic_tx_map_frag(struct ionic_queue *q,
1632d2
+				    const skb_frag_t *frag,
1632d2
 				    size_t offset, size_t len)
1632d2
 {
1632d2
 	struct ionic_tx_stats *stats = q_to_tx_stats(q);
1632d2
@@ -507,8 +513,10 @@ static dma_addr_t ionic_tx_map_frag(struct ionic_queue *q, const skb_frag_t *fra
1632d2
 	return dma_addr;
1632d2
 }
1632d2
 
1632d2
-static void ionic_tx_clean(struct ionic_queue *q, struct ionic_desc_info *desc_info,
1632d2
-			   struct ionic_cq_info *cq_info, void *cb_arg)
1632d2
+static void ionic_tx_clean(struct ionic_queue *q,
1632d2
+			   struct ionic_desc_info *desc_info,
1632d2
+			   struct ionic_cq_info *cq_info,
1632d2
+			   void *cb_arg)
1632d2
 {
1632d2
 	struct ionic_txq_sg_desc *sg_desc = desc_info->sg_desc;
1632d2
 	struct ionic_txq_sg_elem *elem = sg_desc->elems;
1632d2
@@ -989,6 +997,7 @@ static int ionic_tx(struct ionic_queue *q, struct sk_buff *skb)
1632d2
 
1632d2
 static int ionic_tx_descs_needed(struct ionic_queue *q, struct sk_buff *skb)
1632d2
 {
1632d2
+	int sg_elems = q->lif->qtype_info[IONIC_QTYPE_TXQ].max_sg_elems;
1632d2
 	struct ionic_tx_stats *stats = q_to_tx_stats(q);
1632d2
 	int err;
1632d2
 
1632d2
@@ -997,7 +1006,7 @@ static int ionic_tx_descs_needed(struct ionic_queue *q, struct sk_buff *skb)
1632d2
 		return (skb->len / skb_shinfo(skb)->gso_size) + 1;
1632d2
 
1632d2
 	/* If non-TSO, just need 1 desc and nr_frags sg elems */
1632d2
-	if (skb_shinfo(skb)->nr_frags <= IONIC_TX_MAX_SG_ELEMS)
1632d2
+	if (skb_shinfo(skb)->nr_frags <= sg_elems)
1632d2
 		return 1;
1632d2
 
1632d2
 	/* Too many frags, so linearize */
1632d2
-- 
1632d2
2.16.4
1632d2
1632d2