[PATCH] net: lan78xx: fix "enabled interrupts" warninig

From: Jisheng Zhang
Date: Mon Apr 08 2019 - 02:11:09 EST


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