I met below warning on raspberry pi 3B+: [ 4.833207] ------------[ cut here ]------------ [ 4.833442] irq 79 handler irq_default_primary_handler+0x0/0x8 enabled interrupts [ 4.833758] WARNING: CPU: 0 PID: 0 at __handle_irq_event_percpu+0x124/0x150 [ 4.834037] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 5.0.0+ #8 [ 4.834266] Hardware name: Raspberry Pi 3 Model B Plus Rev 1.3 (DT) [ 4.834511] pstate: 60000005 (nZCv daif -PAN -UAO) [ 4.834702] pc : __handle_irq_event_percpu+0x124/0x150 [ 4.834904] lr : __handle_irq_event_percpu+0x124/0x150 [ 4.835103] sp : ffffffc035fb5600 [ 4.835236] x29: ffffffc035fb5600 x28: ffffff8010720480 [ 4.835446] x27: 0000000000000001 x26: ffffff8010650fa0 [ 4.835655] x25: ffffff8010757ec6 x24: ffffffc034784e00 [ 4.835864] x23: 000000000000004f x22: ffffffc035fb568c [ 4.836073] x21: 0000000000000000 x20: 0000000000000002 [ 4.836282] x19: ffffffc03330af00 x18: 0000000000000000 [ 4.836495] x17: 0000000000000000 x16: 0000000000000000 [ 4.836704] x15: 0000000000aaaaaa x14: 7265746e69206465 [ 4.836914] x13: 0000000000000001 x12: 00000000ffffffff [ 4.837122] x11: ffffff801059cf48 x10: 0000000000000001 [ 4.837331] x9 : 0000000000000001 x8 : 0000000000000020 [ 4.837540] x7 : 0000000000000000 x6 : 00000000000000b7 [ 4.837748] x5 : ffffff80102a9f50 x4 : 0000000000000001 [ 4.837956] x3 : 0000000000000000 x2 : 0000000000000004 [ 4.838165] x1 : ffffff8010720480 x0 : 0000000000000045 [ 4.838374] Call trace: [ 4.838480] __handle_irq_event_percpu+0x124/0x150 [ 4.838672] handle_irq_event_percpu+0x1c/0x68 [ 4.842134] handle_irq_event+0x48/0x78 [ 4.845527] handle_simple_irq+0x9c/0xd8 [ 4.848890] generic_handle_irq+0x28/0x40 [ 4.852186] intr_complete+0xb4/0xe8 [ 4.855315] __usb_hcd_giveback_urb+0x58/0xd0 [ 4.858368] usb_giveback_urb_bh+0x94/0xd8 [ 4.861323] tasklet_action_common.isra.1+0x88/0x130 [ 4.864268] tasklet_hi_action+0x24/0x30 [ 4.867112] __do_softirq+0x114/0x224 [ 4.869907] irq_exit+0x9c/0xb8 [ 4.872752] __handle_domain_irq+0x64/0xb8 [ 4.875604] bcm2836_arm_irqchip_handle_irq+0x60/0xc0 [ 4.878544] el1_irq+0xb0/0x128 [ 4.881472] arch_cpu_idle+0x10/0x18 [ 4.884411] do_idle+0x12c/0x140 [ 4.887324] cpu_startup_entry+0x24/0x28 [ 4.890285] rest_init+0xd0/0xdc [ 4.893247] arch_call_rest_init+0xc/0x14 [ 4.896271] start_kernel+0x314/0x328 [ 4.899291] ---[ end trace 122fa03fe3c21930 ]--- Per my understanding, the proper handling of PHY irq is to make use of PHY_IGNORE_INTERRUPT then call phy_mac_interrupt when INT_ENP_PHY_INT is triggered. Signed-off-by: Jisheng Zhang <Jisheng.Zhang@xxxxxxxxxxxxx> --- drivers/net/usb/lan78xx.c | 208 +++----------------------------------- 1 file changed, 16 insertions(+), 192 deletions(-) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 3d92ea6fcc02..246a0d1bbc6c 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -20,10 +20,6 @@ #include <linux/mdio.h> #include <linux/phy.h> #include <net/ip6_checksum.h> -#include <linux/interrupt.h> -#include <linux/irqdomain.h> -#include <linux/irq.h> -#include <linux/irqchip/chained_irq.h> #include <linux/microchipphy.h> #include <linux/phy_fixed.h> #include <linux/of_mdio.h> @@ -87,38 +83,6 @@ /* statistic update interval (mSec) */ #define STAT_UPDATE_TIMER (1 * 1000) -/* defines interrupts from interrupt EP */ -#define MAX_INT_EP (32) -#define INT_EP_INTEP (31) -#define INT_EP_OTP_WR_DONE (28) -#define INT_EP_EEE_TX_LPI_START (26) -#define INT_EP_EEE_TX_LPI_STOP (25) -#define INT_EP_EEE_RX_LPI (24) -#define INT_EP_MAC_RESET_TIMEOUT (23) -#define INT_EP_RDFO (22) -#define INT_EP_TXE (21) -#define INT_EP_USB_STATUS (20) -#define INT_EP_TX_DIS (19) -#define INT_EP_RX_DIS (18) -#define INT_EP_PHY (17) -#define INT_EP_DP (16) -#define INT_EP_MAC_ERR (15) -#define INT_EP_TDFU (14) -#define INT_EP_TDFO (13) -#define INT_EP_UTX (12) -#define INT_EP_GPIO_11 (11) -#define INT_EP_GPIO_10 (10) -#define INT_EP_GPIO_9 (9) -#define INT_EP_GPIO_8 (8) -#define INT_EP_GPIO_7 (7) -#define INT_EP_GPIO_6 (6) -#define INT_EP_GPIO_5 (5) -#define INT_EP_GPIO_4 (4) -#define INT_EP_GPIO_3 (3) -#define INT_EP_GPIO_2 (2) -#define INT_EP_GPIO_1 (1) -#define INT_EP_GPIO_0 (0) - static const char lan78xx_gstrings[][ETH_GSTRING_LEN] = { "RX FCS Errors", "RX Alignment Errors", @@ -350,15 +314,6 @@ struct statstage { struct lan78xx_statstage64 curr_stat; }; -struct irq_domain_data { - struct irq_domain *irqdomain; - unsigned int phyirq; - struct irq_chip *irqchip; - irq_flow_handler_t irq_handler; - u32 irqenable; - struct mutex irq_lock; /* for irq bus access */ -}; - struct lan78xx_net { struct net_device *net; struct usb_device *udev; @@ -415,8 +370,6 @@ struct lan78xx_net { int delta; struct statstage stats; - - struct irq_domain_data domain_data; }; /* define external phy id */ @@ -1251,6 +1204,7 @@ static void lan78xx_defer_kevent(struct lan78xx_net *dev, int work) static void lan78xx_status(struct lan78xx_net *dev, struct urb *urb) { u32 intdata; + struct phy_device *phydev = dev->net->phydev; if (urb->actual_length != 4) { netdev_warn(dev->net, @@ -1264,9 +1218,7 @@ static void lan78xx_status(struct lan78xx_net *dev, struct urb *urb) if (intdata & INT_ENP_PHY_INT) { netif_dbg(dev, link, dev->net, "PHY INTR: 0x%08x\n", intdata); lan78xx_defer_kevent(dev, EVENT_LINK_RESET); - - if (dev->domain_data.phyirq > 0) - generic_handle_irq(dev->domain_data.phyirq); + phy_mac_interrupt(phydev); } else netdev_warn(dev->net, "unexpected interrupt: 0x%08x\n", intdata); @@ -1875,127 +1827,6 @@ static void lan78xx_link_status_change(struct net_device *net) } } -static int irq_map(struct irq_domain *d, unsigned int irq, - irq_hw_number_t hwirq) -{ - struct irq_domain_data *data = d->host_data; - - irq_set_chip_data(irq, data); - irq_set_chip_and_handler(irq, data->irqchip, data->irq_handler); - irq_set_noprobe(irq); - - return 0; -} - -static void irq_unmap(struct irq_domain *d, unsigned int irq) -{ - irq_set_chip_and_handler(irq, NULL, NULL); - irq_set_chip_data(irq, NULL); -} - -static const struct irq_domain_ops chip_domain_ops = { - .map = irq_map, - .unmap = irq_unmap, -}; - -static void lan78xx_irq_mask(struct irq_data *irqd) -{ - struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd); - - data->irqenable &= ~BIT(irqd_to_hwirq(irqd)); -} - -static void lan78xx_irq_unmask(struct irq_data *irqd) -{ - struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd); - - data->irqenable |= BIT(irqd_to_hwirq(irqd)); -} - -static void lan78xx_irq_bus_lock(struct irq_data *irqd) -{ - struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd); - - mutex_lock(&data->irq_lock); -} - -static void lan78xx_irq_bus_sync_unlock(struct irq_data *irqd) -{ - struct irq_domain_data *data = irq_data_get_irq_chip_data(irqd); - struct lan78xx_net *dev = - container_of(data, struct lan78xx_net, domain_data); - u32 buf; - int ret; - - /* call register access here because irq_bus_lock & irq_bus_sync_unlock - * are only two callbacks executed in non-atomic contex. - */ - ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf); - if (buf != data->irqenable) - ret = lan78xx_write_reg(dev, INT_EP_CTL, data->irqenable); - - mutex_unlock(&data->irq_lock); -} - -static struct irq_chip lan78xx_irqchip = { - .name = "lan78xx-irqs", - .irq_mask = lan78xx_irq_mask, - .irq_unmask = lan78xx_irq_unmask, - .irq_bus_lock = lan78xx_irq_bus_lock, - .irq_bus_sync_unlock = lan78xx_irq_bus_sync_unlock, -}; - -static int lan78xx_setup_irq_domain(struct lan78xx_net *dev) -{ - struct device_node *of_node; - struct irq_domain *irqdomain; - unsigned int irqmap = 0; - u32 buf; - int ret = 0; - - of_node = dev->udev->dev.parent->of_node; - - mutex_init(&dev->domain_data.irq_lock); - - lan78xx_read_reg(dev, INT_EP_CTL, &buf); - dev->domain_data.irqenable = buf; - - dev->domain_data.irqchip = &lan78xx_irqchip; - dev->domain_data.irq_handler = handle_simple_irq; - - irqdomain = irq_domain_add_simple(of_node, MAX_INT_EP, 0, - &chip_domain_ops, &dev->domain_data); - if (irqdomain) { - /* create mapping for PHY interrupt */ - irqmap = irq_create_mapping(irqdomain, INT_EP_PHY); - if (!irqmap) { - irq_domain_remove(irqdomain); - - irqdomain = NULL; - ret = -EINVAL; - } - } else { - ret = -EINVAL; - } - - dev->domain_data.irqdomain = irqdomain; - dev->domain_data.phyirq = irqmap; - - return ret; -} - -static void lan78xx_remove_irq_domain(struct lan78xx_net *dev) -{ - if (dev->domain_data.phyirq > 0) { - irq_dispose_mapping(dev->domain_data.phyirq); - - if (dev->domain_data.irqdomain) - irq_domain_remove(dev->domain_data.irqdomain); - } - dev->domain_data.phyirq = 0; - dev->domain_data.irqdomain = NULL; -} - static int lan8835_fixup(struct phy_device *phydev) { int buf; @@ -2124,16 +1955,15 @@ static int lan78xx_phy_init(struct lan78xx_net *dev) return -EIO; } - /* if phyirq is not set, use polling mode in phylib */ - if (dev->domain_data.phyirq > 0) - phydev->irq = dev->domain_data.phyirq; - else - phydev->irq = 0; - netdev_dbg(dev->net, "phydev->irq = %d\n", phydev->irq); - /* set to AUTOMDIX */ phydev->mdix = ETH_TP_MDI_AUTO; + ret = phy_read(phydev, LAN88XX_INT_STS); + ret = phy_write(phydev, LAN88XX_INT_MASK, + LAN88XX_INT_MASK_MDINTPIN_EN_ | + LAN88XX_INT_MASK_LINK_CHANGE_); + phydev->irq = PHY_IGNORE_INTERRUPT; + ret = phy_connect_direct(dev->net, phydev, lan78xx_link_status_change, dev->interface); @@ -2571,6 +2401,11 @@ static int lan78xx_reset(struct lan78xx_net *dev) } ret = lan78xx_write_reg(dev, MAC_CR, buf); + /* enable PHY interrupts */ + ret = lan78xx_read_reg(dev, INT_EP_CTL, &buf); + buf |= INT_ENP_PHY_INT; + ret = lan78xx_write_reg(dev, INT_EP_CTL, buf); + ret = lan78xx_read_reg(dev, MAC_TX, &buf); buf |= MAC_TX_TXEN_; ret = lan78xx_write_reg(dev, MAC_TX, buf); @@ -2981,13 +2816,6 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) dev->net->hw_features = dev->net->features; - ret = lan78xx_setup_irq_domain(dev); - if (ret < 0) { - netdev_warn(dev->net, - "lan78xx_setup_irq_domain() failed : %d", ret); - goto out1; - } - dev->net->hard_header_len += TX_OVERHEAD; dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; @@ -2995,13 +2823,13 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) ret = lan78xx_reset(dev); if (ret) { netdev_warn(dev->net, "Registers INIT FAILED...."); - goto out2; + goto out; } ret = lan78xx_mdio_init(dev); if (ret) { netdev_warn(dev->net, "MDIO INIT FAILED....."); - goto out2; + goto out; } dev->net->flags |= IFF_MULTICAST; @@ -3010,10 +2838,7 @@ static int lan78xx_bind(struct lan78xx_net *dev, struct usb_interface *intf) return ret; -out2: - lan78xx_remove_irq_domain(dev); - -out1: +out: netdev_warn(dev->net, "Bind routine FAILED"); cancel_work_sync(&pdata->set_multicast); cancel_work_sync(&pdata->set_vlan); @@ -3025,7 +2850,6 @@ static void lan78xx_unbind(struct lan78xx_net *dev, struct usb_interface *intf) { struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0]); - lan78xx_remove_irq_domain(dev); lan78xx_remove_mdio(dev); -- 2.20.1