diff mbox series

[net] net: txgbe: fix lost GPIO interrupt

Message ID 20241106101717.981850-1-jiawenwu@trustnetic.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series [net] net: txgbe: fix lost GPIO interrupt | expand

Checks

Context Check Description
netdev/series_format success Single patches do not need cover letters
netdev/tree_selection success Clearly marked for net
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
netdev/fixes_present success Fixes tag present in non-next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 3 this patch: 3
netdev/build_tools success No tools touched, skip
netdev/cc_maintainers success CCed 8 of 8 maintainers
netdev/build_clang success Errors and warnings before: 3 this patch: 3
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 4 this patch: 4
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 63 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 6 this patch: 6
netdev/source_inline success Was 0 now: 0
netdev/contest success net-next-2024-11-07--12-00 (tests: 787)

Commit Message

Jiawen Wu Nov. 6, 2024, 10:17 a.m. UTC
Sometimes when clearing interrupts for workaround in txgbe_up_complete(),
the GPIO interrupt is lost once due to the interrupt polarity is
consistent with the GPIO state. It causes the SFP state cannot be updated
immediately. That is, SFP driver can only get into the correct state if
the GPIO state changes again.

So mannually trigger the GPIO interrupt while clearing it in
txgbe_reinit_gpio_intr(), causing SFP driver to update to the correct
state. And also clear GPIO interrupts in txgbe_down() to ensure that the
interrupt polarity is consistent with the GPIO state.

Fixes: b4a2496c17ed ("net: txgbe: fix GPIO interrupt blocking")
Signed-off-by: Jiawen Wu <jiawenwu@trustnetic.com>
---
 drivers/net/ethernet/wangxun/libwx/wx_type.h    |  1 +
 drivers/net/ethernet/wangxun/txgbe/txgbe_main.c |  5 ++++-
 drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c  | 15 ++++++++++-----
 3 files changed, 15 insertions(+), 6 deletions(-)

Comments

Andrew Lunn Nov. 6, 2024, 6:01 p.m. UTC | #1
On Wed, Nov 06, 2024 at 06:17:17PM +0800, Jiawen Wu wrote:
> Sometimes when clearing interrupts for workaround in txgbe_up_complete(),
> the GPIO interrupt is lost once due to the interrupt polarity is
> consistent with the GPIO state. It causes the SFP state cannot be updated
> immediately. That is, SFP driver can only get into the correct state if
> the GPIO state changes again.

If i remember correctly, the basic issue is that your hardware cannot
do IRQ_TYPE_EDGE_BOTH? You try to fake it by configuring for
IRQ_TYPE_EDGE_RISING when the GPIO is low, IRQ_TYPE_EDGE_FALLING when
the GPIO is high. And then hope you can handle the interrupt fast
enough you don't miss an edge?

Maybe you should just accept the interrupt controller hardware is
broken, and let the SFP driver poll the GPIO? Do you really need to
know in less than a second the SFP has been ejected, or changed is LOS
status?

	Andrew
diff mbox series

Patch

diff --git a/drivers/net/ethernet/wangxun/libwx/wx_type.h b/drivers/net/ethernet/wangxun/libwx/wx_type.h
index b54bffda027b..bf4285db605e 100644
--- a/drivers/net/ethernet/wangxun/libwx/wx_type.h
+++ b/drivers/net/ethernet/wangxun/libwx/wx_type.h
@@ -1078,6 +1078,7 @@  struct wx {
 	bool wol_hw_supported;
 	bool ncsi_enabled;
 	bool gpio_ctrl;
+	bool gpio_trigger;
 	raw_spinlock_t gpio_lock;
 
 	/* Tx fast path data */
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
index 93180225a6f1..0e6129dcff8f 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_main.c
@@ -82,7 +82,6 @@  static void txgbe_up_complete(struct wx *wx)
 {
 	struct net_device *netdev = wx->netdev;
 
-	txgbe_reinit_gpio_intr(wx);
 	wx_control_hw(wx, true);
 	wx_configure_vectors(wx);
 
@@ -97,6 +96,9 @@  static void txgbe_up_complete(struct wx *wx)
 	rd32(wx, WX_PX_IC(1));
 	rd32(wx, WX_PX_MISC_IC);
 	txgbe_irq_enable(wx, true);
+	wx->gpio_trigger = true;
+	txgbe_reinit_gpio_intr(wx);
+	wx->gpio_trigger = false;
 
 	/* enable transmits */
 	netif_tx_start_all_queues(netdev);
@@ -169,6 +171,7 @@  void txgbe_down(struct wx *wx)
 	txgbe_disable_device(wx);
 	txgbe_reset(wx);
 	phylink_stop(wx->phylink);
+	txgbe_reinit_gpio_intr(wx);
 
 	wx_clean_all_tx_rings(wx);
 	wx_clean_all_rx_rings(wx);
diff --git a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
index 67b61afdde96..361dcb362d42 100644
--- a/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
+++ b/drivers/net/ethernet/wangxun/txgbe/txgbe_phy.c
@@ -401,17 +401,21 @@  static void txgbe_gpio_irq_unmask(struct irq_data *d)
 static void txgbe_toggle_trigger(struct gpio_chip *gc, unsigned int offset)
 {
 	struct wx *wx = gpiochip_get_data(gc);
-	u32 pol, val;
+	u32 pol_r, pol_w, val;
 
-	pol = rd32(wx, WX_GPIO_POLARITY);
+	pol_r = rd32(wx, WX_GPIO_POLARITY);
 	val = rd32(wx, WX_GPIO_EXT);
 
 	if (val & BIT(offset))
-		pol &= ~BIT(offset);
+		pol_w = pol_r & ~BIT(offset);
 	else
-		pol |= BIT(offset);
+		pol_w = pol_r | BIT(offset);
 
-	wr32(wx, WX_GPIO_POLARITY, pol);
+	wr32(wx, WX_GPIO_POLARITY, pol_w);
+
+	/* manually trigger the lost inpterrupt */
+	if (wx->gpio_trigger)
+		wr32(wx, WX_GPIO_POLARITY, pol_r);
 }
 
 static int txgbe_gpio_set_type(struct irq_data *d, unsigned int type)
@@ -560,6 +564,7 @@  static int txgbe_gpio_init(struct txgbe *txgbe)
 		return ret;
 
 	txgbe->gpio = gc;
+	wx->gpio_trigger = false;
 
 	return 0;
 }