[PATCH net-next v2 2/6] r8169: create a virtual interrupt for linkchg
From: javen
Date: Thu Jun 11 2026 - 05:44:54 EST
From: Javen Xu <javen_xu@xxxxxxxxxxxxxx>
Create a virtual interrupt for linkchg. To support phylink, we should
try to decouple most of tp->phydev, so we add virtual interrupt for mac
interrupt to inform the change of link status.
generic_handle_domain_irq() will help us to call phylib.
Signed-off-by: Javen Xu <javen_xu@xxxxxxxxxxxxxx>
---
Changes in v2:
- new file
---
drivers/net/ethernet/realtek/r8169_main.c | 51 +++++++++++++++++++++--
1 file changed, 48 insertions(+), 3 deletions(-)
diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c
index c60710f9bd21..560f987437b6 100644
--- a/drivers/net/ethernet/realtek/r8169_main.c
+++ b/drivers/net/ethernet/realtek/r8169_main.c
@@ -21,6 +21,8 @@
#include <linux/in.h>
#include <linux/io.h>
#include <linux/ip.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/tcp.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
@@ -775,6 +777,7 @@ struct rtl8169_private {
struct r8169_led_classdev *leds;
u32 ocp_base;
+ struct irq_domain *phy_irq_domain;
};
typedef void (*rtl_generic_fct)(struct rtl8169_private *tp);
@@ -4869,7 +4872,7 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance)
}
if (status & LinkChg)
- phy_mac_interrupt(tp->phydev);
+ generic_handle_domain_irq(tp->phy_irq_domain, 0);
rtl_irq_disable(tp);
napi_schedule(&tp->napi);
@@ -5423,11 +5426,39 @@ static int r8169_mdio_write_reg_c45(struct mii_bus *mii_bus, int addr,
return 0;
}
+static int rtl_phy_irq_map(struct irq_domain *d, unsigned int irq,
+ irq_hw_number_t hwirq)
+{
+ irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
+ irq_set_chip_data(irq, d->host_data);
+
+ return 0;
+}
+
+static const struct irq_domain_ops rtl_phy_irq_domain_ops = {
+ .map = rtl_phy_irq_map,
+};
+
+static void rtl_phy_irq_cleanup(void *data)
+{
+ struct rtl8169_private *tp = data;
+ int virq;
+
+ if (tp->phy_irq_domain) {
+ virq = irq_find_mapping(tp->phy_irq_domain, 0);
+ if (virq)
+ irq_dispose_mapping(virq);
+
+ irq_domain_remove(tp->phy_irq_domain);
+ tp->phy_irq_domain = NULL;
+ }
+}
+
static int r8169_mdio_register(struct rtl8169_private *tp)
{
struct pci_dev *pdev = tp->pci_dev;
struct mii_bus *new_bus;
- int ret;
+ int ret, virq;
/* On some boards with this chip version the BIOS is buggy and misses
* to reset the PHY page selector. This results in the PHY ID read
@@ -5445,7 +5476,6 @@ static int r8169_mdio_register(struct rtl8169_private *tp)
new_bus->name = "r8169";
new_bus->priv = tp;
new_bus->parent = &pdev->dev;
- new_bus->irq[0] = PHY_MAC_INTERRUPT;
new_bus->phy_mask = GENMASK(31, 1);
snprintf(new_bus->id, MII_BUS_ID_SIZE, "r8169-%x-%x",
pci_domain_nr(pdev->bus), pci_dev_id(pdev));
@@ -5458,6 +5488,21 @@ static int r8169_mdio_register(struct rtl8169_private *tp)
new_bus->write_c45 = r8169_mdio_write_reg_c45;
}
+ tp->phy_irq_domain = irq_domain_add_linear(NULL, 1,
+ &rtl_phy_irq_domain_ops, tp);
+ if (!tp->phy_irq_domain)
+ return -ENOMEM;
+
+ ret = devm_add_action_or_reset(&pdev->dev, rtl_phy_irq_cleanup, tp);
+ if (ret)
+ return ret;
+
+ virq = irq_create_mapping(tp->phy_irq_domain, 0);
+ if (!virq)
+ ret = -EINVAL;
+
+ new_bus->irq[0] = virq;
+
ret = devm_mdiobus_register(&pdev->dev, new_bus);
if (ret)
return ret;
--
2.43.0