Add a debugfs file (inject\_error) to allow users to trigger specific hardware errors (e.g., Burst Cap Violation, RX FIFO Overflow, USB PHY destabilization) for testing the newly introduced health and recovery mechanisms. Signed-off-by: Oleksij Rempel --- drivers/net/usb/lan78xx.c | 71 +++++++++++++++++++++++++++++++++++++++ drivers/net/usb/lan78xx.h | 4 +++ 2 files changed, 75 insertions(+) diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c index 316a3a8d0534..ae721025cf3d 100644 --- a/drivers/net/usb/lan78xx.c +++ b/drivers/net/usb/lan78xx.c @@ -3,6 +3,7 @@ * Copyright (C) 2015 Microchip Technology */ #include +#include #include #include #include @@ -519,6 +520,8 @@ struct lan78xx_net { struct irq_domain_data domain_data; + struct dentry *debugfs_pdev; + struct phylink *phylink; struct phylink_config phylink_config; @@ -5088,6 +5091,68 @@ static const struct devlink_ops lan78xx_devlink_ops = { .info_get = lan78xx_devlink_info_get, }; +static ssize_t lan78xx_inject_write(struct file *file, const char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct lan78xx_net *dev = file->private_data; + char buf[32]; + int val, ret; + u32 reg_val; + + if (count >= sizeof(buf)) + return -EINVAL; + + if (copy_from_user(buf, user_buf, count)) + return -EFAULT; + buf[count] = 0; + + if (kstrtoint(buf, 0, &val)) + return -EINVAL; + + switch (val) { + case 1: /* Trigger Burst Cap Violation (Hang UTX) */ + /* Enable Burst Cap Enforcement */ + ret = lan78xx_read_reg(dev, USB_CFG0, ®_val); + if (ret < 0) + return ret; + reg_val |= USB_CFG_BCE_; + lan78xx_write_reg(dev, USB_CFG0, reg_val); + + /* Set illegal Burst Cap size (512 bytes < Max Frame) */ + lan78xx_write_reg(dev, BURST_CAP, 0x01); + break; + + case 2: /* Trigger RX FIFO Overflow (Hold UTX in Reset) */ + ret = lan78xx_read_reg(dev, USB_CFG0, ®_val); + if (ret < 0) + return ret; + reg_val |= USB_CFG0_UTX_RESET_; + lan78xx_write_reg(dev, USB_CFG0, reg_val); + break; + + case 3: /* Destabilize USB PHY (Invalid HS State) */ + ret = lan78xx_read_reg(dev, LAN78XX_USB2_TEST_REG, ®_val); + if (ret < 0) + return ret; + /* Set bits 15:14 to '10' (Binary) - Defined as "Invalid combination" */ + reg_val &= ~(0x3 << 14); + reg_val |= (0x2 << 14); + lan78xx_write_reg(dev, LAN78XX_USB2_TEST_REG, reg_val); + break; + + default: + return -EINVAL; + } + + return count; +} + +static const struct file_operations lan78xx_inject_fops = { + .open = simple_open, + .write = lan78xx_inject_write, + .llseek = default_llseek, +}; + static void lan78xx_disconnect(struct usb_interface *intf) { struct lan78xx_net *dev; @@ -5102,6 +5167,8 @@ static void lan78xx_disconnect(struct usb_interface *intf) udev = interface_to_usbdev(intf); net = dev->net; + debugfs_remove_recursive(dev->debugfs_pdev); + lan78xx_health_cleanup(dev); if (dev->devlink) { cancel_work_sync(&dev->tx_timeout_work); @@ -5594,6 +5661,10 @@ static int lan78xx_probe(struct usb_interface *intf, lan78xx_health_init(dev); } + dev->debugfs_pdev = debugfs_create_dir(netdev_name(netdev), NULL); + debugfs_create_file("inject_error", 0200, dev->debugfs_pdev, dev, + &lan78xx_inject_fops); + return 0; phy_uninit: diff --git a/drivers/net/usb/lan78xx.h b/drivers/net/usb/lan78xx.h index 968e5e5faee0..16666a998441 100644 --- a/drivers/net/usb/lan78xx.h +++ b/drivers/net/usb/lan78xx.h @@ -366,6 +366,7 @@ #define USB_CFG_MAX_DEV_SPEED_SS_ (0x00008000) #define USB_CFG_MAX_DEV_SPEED_HS_ (0x00000000) #define USB_CFG_MAX_DEV_SPEED_FS_ (0x00002000) +#define USB_CFG0_UTX_RESET_ (0x00000400) #define USB_CFG_PHY_BOOST_MASK_ (0x00000180) #define USB_CFG_PHY_BOOST_PLUS_12_ (0x00000180) #define USB_CFG_PHY_BOOST_PLUS_8_ (0x00000100) @@ -876,4 +877,7 @@ #define OTP_TPVSR_VAL (OTP_BASE_ADDR + 4 * 0x3A) #define OTP_TPVHR_VAL (OTP_BASE_ADDR + 4 * 0x3B) #define OTP_TPVSA_VAL (OTP_BASE_ADDR + 4 * 0x3C) + +#define LAN78XX_USB2_TEST_REG (0x12C4) + #endif /* _LAN78XX_H */ -- 2.47.3