From bdd7d1f8f7086daadb2beefb06e8c50c4cf7951b Mon Sep 17 00:00:00 2001 From: Bjarne von Horn Date: Thu, 1 Feb 2024 16:03:33 +0100 Subject: [PATCH] Fix r8169 link detection with Xenomai ``` [ 741.073012] IRQ pipeline: some code running in oob context 'Xenomai' [ 741.073013] called an in-band only routine [ 741.073013] CPU: 1 PID: 22419 Comm: my_task Tainted: G O 5.10.179-lp154.3-0510xenomai3 #1 [ 741.073014] Hardware name: ICP / iEi IMBA-9454ISA/IMBA-9454ISA(E168), BIOS 080014 02/20/2009 [ 741.073015] IRQ stage: Xenomai [ 741.073015] Call Trace: [ 741.073015] dump_stack+0x86/0xa6 [ 741.073016] check_inband_stage+0x8c/0xa0 [ 741.073017] inband_irq_save+0xe/0x30 [ 741.073017] try_to_grab_pending+0x1e/0x180 [ 741.073018] mod_delayed_work_on+0x42/0xa0 [ 741.073018] phy_trigger_machine+0x23/0x30 [ 741.073019] phy_mac_interrupt+0xe/0x20 [ 741.073019] ec_poll+0x105/0x110 [ec_r8169] [ 741.073020] ec_device_poll+0x24/0x30 [ec_master] [ 741.073020] ecrt_master_receive+0x21/0x160 [ec_master] [ 741.073021] ec_ioctl_rtdm_rt+0x430/0x4c0 [ec_master] [ 741.073021] ? rtdm_fd_get+0x11d/0x210 [ 741.073022] ec_rtdm_ioctl_rt_handler+0x26/0x40 [ec_master] [ 741.073022] rtdm_fd_ioctl+0xdc/0x240 [ 741.073023] ? xnlock_dbg_release+0x21/0xf0 [ 741.073023] CoBaLt_ioctl+0xe/0x20 [ 741.073024] handle_head_syscall+0x10f/0x4d0 [ 741.073025] ? CoBaLt_fcntl+0x20/0x20 [ 741.073025] ? handle_pipelined_syscall+0x39/0x40 [ 741.073026] handle_oob_syscall+0x13/0x20 [ 741.073026] pipeline_syscall+0x8c/0x130 [ 741.073027] syscall_enter_from_user_mode+0x26/0x90 [ 741.073027] do_syscall_64+0x13/0x60 [ 741.073028] entry_SYSCALL_64_after_hwframe+0x61/0xc6 [ 741.073029] RIP: 0033:0x7fac8da13c8f [ 741.073029] Code: Unable to access opcode bytes at RIP 0x7fac8da13c65. [ 741.073030] RSP: 002b:00007fac8e864c90 EFLAGS: 00000206 ORIG_RAX: 0000000010000050 [ 741.073031] RAX: ffffffffffffffda RBX: 0000000000000003 RCX: 00007fac8da13c8f [ 741.073032] RDX: 0000000000000000 RSI: 000000000000a426 RDI: 0000000000000003 [ 741.073032] RBP: 000000000000a426 R08: 00007fac8e865700 R09: 0000000000000000 [ 741.073033] R10: 0000000000000113 R11: 0000000000000206 R12: 0000000000000000 [ 741.073033] R13: 0000000000000000 R14: 0000000000000000 R15: 00007fac8e864e80 ``` --- devices/r8169/r8169_main-5.10-ethercat.c | 15 +++++++++++++-- devices/r8169/r8169_main-5.14-ethercat.c | 14 +++++++++++++- devices/r8169/r8169_main-5.15-ethercat.c | 14 +++++++++++++- devices/r8169/r8169_main-6.1-ethercat.c | 14 +++++++++++++- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/devices/r8169/r8169_main-5.10-ethercat.c b/devices/r8169/r8169_main-5.10-ethercat.c index 9508e74d..b00c04af 100644 --- a/devices/r8169/r8169_main-5.10-ethercat.c +++ b/devices/r8169/r8169_main-5.10-ethercat.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -633,6 +634,7 @@ struct rtl8169_private { ec_device_t *ecdev; unsigned long ec_watchdog_jiffies; + struct irq_work ec_watchdog_kicker; }; typedef void (*rtl_generic_fct)(struct rtl8169_private *tp); @@ -5079,6 +5081,7 @@ static void rtl_remove_one(struct pci_dev *pdev) if (tp->ecdev) { ecdev_close(tp->ecdev); + irq_work_sync(&tp->ec_watchdog_kicker); ecdev_withdraw(tp->ecdev); } else { unregister_netdev(tp->dev); @@ -5369,6 +5372,14 @@ done: rtl_rar_set(tp, mac_addr); } +static void ec_kick_watchdog(struct irq_work *work) +{ + struct rtl8169_private *tp = + container_of(work, struct rtl8169_private, ec_watchdog_kicker); + + phy_mac_interrupt(tp->phydev); +} + static void ec_poll(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -5387,8 +5398,7 @@ static void ec_poll(struct net_device *dev) rtl_rx(dev, tp, 100); if (status & LinkChg) - phy_mac_interrupt(tp->phydev); - + irq_work_queue(&tp->ec_watchdog_kicker); rtl_ack_events(tp, status); } @@ -5588,6 +5598,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pm_runtime_put_sync(&pdev->dev); if (tp->ecdev) { + init_irq_work(&tp->ec_watchdog_kicker, ec_kick_watchdog); rc = ecdev_open(tp->ecdev); if (rc) { ecdev_withdraw(tp->ecdev); diff --git a/devices/r8169/r8169_main-5.14-ethercat.c b/devices/r8169/r8169_main-5.14-ethercat.c index 58ed3d95..51c54f47 100644 --- a/devices/r8169/r8169_main-5.14-ethercat.c +++ b/devices/r8169/r8169_main-5.14-ethercat.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -653,6 +654,7 @@ struct rtl8169_private { ec_device_t *ecdev; unsigned long ec_watchdog_jiffies; + struct irq_work ec_watchdog_kicker; }; typedef void (*rtl_generic_fct)(struct rtl8169_private *tp); @@ -5048,6 +5050,7 @@ static void rtl_remove_one(struct pci_dev *pdev) if (tp->ecdev) { ecdev_close(tp->ecdev); + irq_work_sync(&tp->ec_watchdog_kicker); ecdev_withdraw(tp->ecdev); } else { unregister_netdev(tp->dev); @@ -5338,6 +5341,14 @@ done: rtl_rar_set(tp, mac_addr); } +static void ec_kick_watchdog(struct irq_work *work) +{ + struct rtl8169_private *tp = + container_of(work, struct rtl8169_private, ec_watchdog_kicker); + + phy_mac_interrupt(tp->phydev); +} + static void ec_poll(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -5356,7 +5367,7 @@ static void ec_poll(struct net_device *dev) rtl_rx(dev, tp, 100); if (status & LinkChg) - phy_mac_interrupt(tp->phydev); + irq_work_queue(&tp->ec_watchdog_kicker); rtl_ack_events(tp, status); } @@ -5560,6 +5571,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pm_runtime_put_sync(&pdev->dev); if (tp->ecdev) { + init_irq_work(&tp->ec_watchdog_kicker, ec_kick_watchdog); rc = ecdev_open(tp->ecdev); if (rc) { ecdev_withdraw(tp->ecdev); diff --git a/devices/r8169/r8169_main-5.15-ethercat.c b/devices/r8169/r8169_main-5.15-ethercat.c index f2bc5230..df956257 100644 --- a/devices/r8169/r8169_main-5.15-ethercat.c +++ b/devices/r8169/r8169_main-5.15-ethercat.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -641,6 +642,7 @@ struct rtl8169_private { ec_device_t *ecdev; unsigned long ec_watchdog_jiffies; + struct irq_work ec_watchdog_kicker; }; typedef void (*rtl_generic_fct)(struct rtl8169_private *tp); @@ -5041,6 +5043,7 @@ static void rtl_remove_one(struct pci_dev *pdev) if (tp->ecdev) { ecdev_close(tp->ecdev); + irq_work_sync(&tp->ec_watchdog_kicker); ecdev_withdraw(tp->ecdev); } else { unregister_netdev(tp->dev); @@ -5331,6 +5334,14 @@ done: rtl_rar_set(tp, mac_addr); } +static void ec_kick_watchdog(struct irq_work *work) +{ + struct rtl8169_private *tp = + container_of(work, struct rtl8169_private, ec_watchdog_kicker); + + phy_mac_interrupt(tp->phydev); +} + static void ec_poll(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -5349,7 +5360,7 @@ static void ec_poll(struct net_device *dev) rtl_rx(dev, tp, 100); if (status & LinkChg) - phy_mac_interrupt(tp->phydev); + irq_work_queue(&tp->ec_watchdog_kicker); rtl_ack_events(tp, status); } @@ -5552,6 +5563,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pm_runtime_put_sync(&pdev->dev); if (tp->ecdev) { + init_irq_work(&tp->ec_watchdog_kicker, ec_kick_watchdog); rc = ecdev_open(tp->ecdev); if (rc) { ecdev_withdraw(tp->ecdev); diff --git a/devices/r8169/r8169_main-6.1-ethercat.c b/devices/r8169/r8169_main-6.1-ethercat.c index 82405979..06e02bc6 100644 --- a/devices/r8169/r8169_main-6.1-ethercat.c +++ b/devices/r8169/r8169_main-6.1-ethercat.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -630,6 +631,7 @@ struct rtl8169_private { ec_device_t *ecdev; unsigned long ec_watchdog_jiffies; + struct irq_work ec_watchdog_kicker; }; typedef void (*rtl_generic_fct)(struct rtl8169_private *tp); @@ -4919,6 +4921,7 @@ static void rtl_remove_one(struct pci_dev *pdev) if (tp->ecdev) { ecdev_close(tp->ecdev); + irq_work_sync(&tp->ec_watchdog_kicker); ecdev_withdraw(tp->ecdev); } else { unregister_netdev(tp->dev); @@ -5189,6 +5192,14 @@ static bool rtl_aspm_is_safe(struct rtl8169_private *tp) return false; } +static void ec_kick_watchdog(struct irq_work *work) +{ + struct rtl8169_private *tp = + container_of(work, struct rtl8169_private, ec_watchdog_kicker); + + phy_mac_interrupt(tp->phydev); +} + static void ec_poll(struct net_device *dev) { struct rtl8169_private *tp = netdev_priv(dev); @@ -5207,7 +5218,7 @@ static void ec_poll(struct net_device *dev) rtl_rx(dev, tp, 100); if (status & LinkChg) - phy_mac_interrupt(tp->phydev); + irq_work_queue(&tp->ec_watchdog_kicker); rtl_ack_events(tp, status); } @@ -5416,6 +5427,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pm_runtime_put_sync(&pdev->dev); if (tp->ecdev) { + init_irq_work(&tp->ec_watchdog_kicker, ec_kick_watchdog); rc = ecdev_open(tp->ecdev); if (rc) { ecdev_withdraw(tp->ecdev);