Skip to contentSkip to conversation

alx: add msi-x support

PATCH In review Tobias Regnery 2 participants 6 messages Sep 9, 2016 – Sep 10, 2016

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover alx: add msi-x support

This patchset adds msi-x support to the alx driver. It is a preparatory series for multi queue support, which I am currently working on. As there is no advantage over msi interrupts without multi queue support, msi-x interrupts are disabled by default. In order to test for regressions, a new module parameter is added to enable msi-x interrupts.

Based on information of the downstream driver at github.com/qca/alx

Tobias Regnery (4):
alx: refactor msi enablement and disablement
alx: factor out part of the interrupt handler
alx: add msi-x support
alx: add module parameter to enable msi-x support

 drivers/net/ethernet/atheros/alx/alx.h  |  10 +-
 drivers/net/ethernet/atheros/alx/hw.c   |  14 ++
 drivers/net/ethernet/atheros/alx/hw.h   |   1 +
 drivers/net/ethernet/atheros/alx/main.c | 235 ++++++++++++++++++++++++++++----
 4 files changed, 231 insertions(+), 29 deletions(-)
Signature · 1 line
2.7.4
#1 lore raw

PATCH 1/4 alx: refactor msi enablement and disablement

Introduce a new flag field for the advanced interrupt capatibilities and add new functions to enable and disable msi interrupts. These functions will be extended later to cover msi-x interrupts.

We enable msi interrupts earlier in alx_init_intr because with msi-x and multi queue support the number of queues must be set before we allocate resources for the rx and tx paths.

---
 drivers/net/ethernet/atheros/alx/alx.h  |  5 ++++-
 drivers/net/ethernet/atheros/alx/main.c | 30 ++++++++++++++++++++++--------
 2 files changed, 26 insertions(+), 9 deletions(-)
drivers/net/ethernet/atheros/alx/alx.h +4 -1
index 8fc93c5f6abc..16ca3f4fa2cc 100644
@@ -76,6 +76,9 @@ enum alx_device_quirks {
 	ALX_DEV_QUIRK_MSI_INTX_DISABLE_BUG = BIT(0),
 };
 
+#define ALX_FLAG_USING_MSIX	BIT(0)
+#define ALX_FLAG_USING_MSI	BIT(1)
+
 struct alx_priv {
 	struct net_device *dev;
 
@@ -105,7 +108,7 @@ struct alx_priv {
 
 	u16 msg_enable;
 
-	bool msi;
+	int flags;
 
 	/* protects hw.stats */
 	spinlock_t stats_lock;
drivers/net/ethernet/atheros/alx/main.c +22 -8
index d29a4f3102d6..6dc1539205eb 100644
@@ -620,6 +620,22 @@ static void alx_config_vector_mapping(struct alx_priv *alx)
 	alx_write_mem32(hw, ALX_MSI_ID_MAP, 0);
 }
 
+static void alx_init_intr(struct alx_priv *alx, bool msix)
+{
+	if (!(alx->flags & ALX_FLAG_USING_MSIX)) {
+		if (!pci_enable_msi(alx->hw.pdev))
+			alx->flags |= ALX_FLAG_USING_MSI;
+	}
+}
+
+static void alx_disable_advanced_intr(struct alx_priv *alx)
+{
+	if (alx->flags & ALX_FLAG_USING_MSI) {
+		pci_disable_msi(alx->hw.pdev);
+		alx->flags &= ~ALX_FLAG_USING_MSI;
+	}
+}
+
 static void alx_irq_enable(struct alx_priv *alx)
 {
 	struct alx_hw *hw = &alx->hw;
@@ -650,9 +666,7 @@ static int alx_request_irq(struct alx_priv *alx)
 
 	msi_ctrl = (hw->imt >> 1) << ALX_MSI_RETRANS_TM_SHIFT;
 
-	if (!pci_enable_msi(alx->hw.pdev)) {
-		alx->msi = true;
-
+	if (alx->flags & ALX_FLAG_USING_MSI) {
 		alx_write_mem32(hw, ALX_MSI_RETRANS_TIMER,
 				msi_ctrl | ALX_MSI_MASK_SEL_LINE);
 		err = request_irq(pdev->irq, alx_intr_msi, 0,
@@ -660,6 +674,7 @@ static int alx_request_irq(struct alx_priv *alx)
 		if (!err)
 			goto out;
 		/* fall back to legacy interrupt */
+		alx->flags &= ~ALX_FLAG_USING_MSI;
 		pci_disable_msi(alx->hw.pdev);
 	}
 
@@ -678,10 +693,7 @@ static void alx_free_irq(struct alx_priv *alx)
 
 	free_irq(pdev->irq, alx);
 
-	if (alx->msi) {
-		pci_disable_msi(alx->hw.pdev);
-		alx->msi = false;
-	}
+	alx_disable_advanced_intr(alx);
 }
 
 static int alx_identify_hw(struct alx_priv *alx)
@@ -847,6 +859,8 @@ static int __alx_open(struct alx_priv *alx, bool resume)
 {
 	int err;
 
+	alx_init_intr(alx, false);
+
 	if (!resume)
 		netif_carrier_off(alx->dev);
 
@@ -1236,7 +1250,7 @@ static void alx_poll_controller(struct net_device *netdev)
 {
 	struct alx_priv *alx = netdev_priv(netdev);
 
-	if (alx->msi)
+	if (alx->flags & ALX_FLAG_USING_MSI)
 		alx_intr_msi(0, alx);
 	else
 		alx_intr_legacy(0, alx);
Signature · 1 line
2.7.4
#2 lore raw

PATCH 2/4 alx: factor out part of the interrupt handler

In reply to Tobias Regnery

Factor out the handling of misc interrupts into a new function. This function can be reused later for msi-x interrupts.

---
 drivers/net/ethernet/atheros/alx/main.c | 34 +++++++++++++++++++--------------
 1 file changed, 20 insertions(+), 14 deletions(-)
drivers/net/ethernet/atheros/alx/main.c +20 -14
index 6dc1539205eb..b34f7b693cec 100644
@@ -302,22 +302,15 @@ static int alx_poll(struct napi_struct *napi, int budget)
 	return work;
 }
 
-static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
+static bool alx_intr_handle_misc(struct alx_priv *alx, u32 intr)
 {
 	struct alx_hw *hw = &alx->hw;
-	bool write_int_mask = false;
-
-	spin_lock(&alx->irq_lock);
-
-	/* ACK interrupt */
-	alx_write_mem32(hw, ALX_ISR, intr | ALX_ISR_DIS);
-	intr &= alx->int_mask;
 
 	if (intr & ALX_ISR_FATAL) {
 		netif_warn(alx, hw, alx->dev,
 			   "fatal interrupt 0x%x, resetting\n", intr);
 		alx_schedule_reset(alx);
-		goto out;
+		return true;
 	}
 
 	if (intr & ALX_ISR_ALERT)
@@ -329,19 +322,32 @@ static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
 		 * is cleared, the interrupt status could be cleared.
 		 */
 		alx->int_mask &= ~ALX_ISR_PHY;
-		write_int_mask = true;
+		alx_write_mem32(hw, ALX_IMR, alx->int_mask);
 		alx_schedule_link_check(alx);
 	}
 
+	return false;
+}
+
+static irqreturn_t alx_intr_handle(struct alx_priv *alx, u32 intr)
+{
+	struct alx_hw *hw = &alx->hw;
+
+	spin_lock(&alx->irq_lock);
+
+	/* ACK interrupt */
+	alx_write_mem32(hw, ALX_ISR, intr | ALX_ISR_DIS);
+	intr &= alx->int_mask;
+
+	if (alx_intr_handle_misc(alx, intr))
+		goto out;
+
 	if (intr & (ALX_ISR_TX_Q0 | ALX_ISR_RX_Q0)) {
 		napi_schedule(&alx->napi);
 		/* mask rx/tx interrupt, enable them when napi complete */
 		alx->int_mask &= ~ALX_ISR_ALL_QUEUES;
-		write_int_mask = true;
-	}
-
-	if (write_int_mask)
 		alx_write_mem32(hw, ALX_IMR, alx->int_mask);
+	}
 
 	alx_write_mem32(hw, ALX_ISR, 0);
 
Signature · 1 line
2.7.4
#3 lore raw

PATCH 3/4 alx: add msi-x support

In reply to Tobias Regnery

Add msi-x support to the alx driver. This is in preparation for multi queue support.

msi-x interrupts are disabled by default because without multi queue support there is no advantage over msi interrupts. The performance numbers observed with iperf stay the same.

Based on information of the downstream driver at github.com/qca/alx

---
 drivers/net/ethernet/atheros/alx/alx.h  |   5 +
 drivers/net/ethernet/atheros/alx/hw.c   |  14 +++
 drivers/net/ethernet/atheros/alx/hw.h   |   1 +
 drivers/net/ethernet/atheros/alx/main.c | 172 ++++++++++++++++++++++++++++++--
 4 files changed, 184 insertions(+), 8 deletions(-)
drivers/net/ethernet/atheros/alx/alx.h +5 -0
index 16ca3f4fa2cc..6cac919272ea 100644
@@ -84,6 +84,11 @@ struct alx_priv {
 
 	struct alx_hw hw;
 
+	/* msi-x vectors */
+	int num_vec;
+	struct msix_entry *msix_entries;
+	char irq_lbl[IFNAMSIZ + 8];
+
 	/* all descriptor memory */
 	struct {
 		dma_addr_t dma;
drivers/net/ethernet/atheros/alx/hw.c +14 -0
index 1fe35e453d43..6ac40b0003a3 100644
@@ -1031,6 +1031,20 @@ void alx_configure_basic(struct alx_hw *hw)
 	alx_write_mem32(hw, ALX_WRR, val);
 }
 
+void alx_mask_msix(struct alx_hw *hw, int index, bool mask)
+{
+	u32 reg, val;
+
+	reg = ALX_MSIX_ENTRY_BASE + index * PCI_MSIX_ENTRY_SIZE +
+		PCI_MSIX_ENTRY_VECTOR_CTRL;
+
+	val = mask ? PCI_MSIX_ENTRY_CTRL_MASKBIT : 0;
+
+	alx_write_mem32(hw, reg, val);
+	alx_post_write(hw);
+}
+
+
 bool alx_get_phy_info(struct alx_hw *hw)
 {
 	u16  devs1, devs2;
drivers/net/ethernet/atheros/alx/hw.h +1 -0
index f289c05f5cb4..0191477ace51 100644
@@ -562,6 +562,7 @@ int alx_reset_mac(struct alx_hw *hw);
 void alx_set_macaddr(struct alx_hw *hw, const u8 *addr);
 bool alx_phy_configured(struct alx_hw *hw);
 void alx_configure_basic(struct alx_hw *hw);
+void alx_mask_msix(struct alx_hw *hw, int index, bool mask);
 void alx_disable_rss(struct alx_hw *hw);
 bool alx_get_phy_info(struct alx_hw *hw);
 void alx_update_hw_stats(struct alx_hw *hw);
drivers/net/ethernet/atheros/alx/main.c +164 -8

250 lines not on this page · raw message

Signature · 1 line
2.7.4
#4 lore raw

PATCH 4/4 alx: add module parameter to enable msi-x support

In reply to Tobias Regnery

msi-x support is default disabled in the alx driver. In order to test msi-x interrupts for regressions add a module parameter to the driver.

---
 drivers/net/ethernet/atheros/alx/main.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/net/ethernet/atheros/alx/main.c +4 -1
index a4f74d4a976c..9887cee434dd 100644
@@ -51,6 +51,9 @@
 
 const char alx_drv_name[] = "alx";
 
+static bool msix = false;
+module_param(msix, bool, 0);
+MODULE_PARM_DESC(msix, "Enable msi-x interrupt support");
 
 static void alx_free_txbuf(struct alx_priv *alx, int entry)
 {
@@ -1018,7 +1021,7 @@ static int __alx_open(struct alx_priv *alx, bool resume)
 {
 	int err;
 
-	alx_init_intr(alx, false);
+	alx_init_intr(alx, msix);
 
 	if (!resume)
 		netif_carrier_off(alx->dev);
Signature · 1 line
2.7.4
maintainer
#5 lore raw
In reply to Tobias Regnery

From: Tobias Regnery <[email protected]>
Date: Fri, 9 Sep 2016 12:19:51 +0200

Quoted 7 lines

This patchset adds msi-x support to the alx driver. It is a preparatory series for multi queue support, which I am currently working on. As there is no advantage over msi interrupts without multi queue support, msi-x interrupts are disabled by default. In order to test for regressions, a new module parameter is added to enable msi-x interrupts.

Based on information of the downstream driver at github.com/qca/alx

Series applied, thanks.