diff options
Diffstat (limited to 'drivers/net/ethernet/realtek')
-rw-r--r-- | drivers/net/ethernet/realtek/8139cp.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/8139too.c | 4 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/Kconfig | 19 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/Makefile | 1 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/r8169.h | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/r8169_firmware.c | 6 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/r8169_leds.c | 168 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/r8169_main.c | 772 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/r8169_phy_config.c | 80 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/rtase/Makefile | 10 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/rtase/rtase.h | 346 | ||||
-rw-r--r-- | drivers/net/ethernet/realtek/rtase/rtase_main.c | 2317 |
12 files changed, 3398 insertions, 343 deletions
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c index f5786d78ed23..5652da8a178c 100644 --- a/drivers/net/ethernet/realtek/8139cp.c +++ b/drivers/net/ethernet/realtek/8139cp.c @@ -1277,14 +1277,14 @@ static int cp_change_mtu(struct net_device *dev, int new_mtu) /* if network interface not up, no need for complexity */ if (!netif_running(dev)) { - dev->mtu = new_mtu; + WRITE_ONCE(dev->mtu, new_mtu); cp_set_rxbufsize(cp); /* set new rx buf size */ return 0; } /* network IS up, close it, reset MTU, and come up again. */ cp_close(dev); - dev->mtu = new_mtu; + WRITE_ONCE(dev->mtu, new_mtu); cp_set_rxbufsize(cp); return cp_open(dev); } diff --git a/drivers/net/ethernet/realtek/8139too.c b/drivers/net/ethernet/realtek/8139too.c index 9ce0e8a64ba8..a73dcaffa8c5 100644 --- a/drivers/net/ethernet/realtek/8139too.c +++ b/drivers/net/ethernet/realtek/8139too.c @@ -1684,6 +1684,7 @@ static void rtl8139_tx_timeout_task (struct work_struct *work) if (tmp8 & CmdTxEnb) RTL_W8 (ChipCmd, CmdRxEnb); + netdev_lock(dev); spin_lock_bh(&tp->rx_lock); /* Disable interrupts by clearing the interrupt mask. */ RTL_W16 (IntrMask, 0x0000); @@ -1694,11 +1695,12 @@ static void rtl8139_tx_timeout_task (struct work_struct *work) spin_unlock_irq(&tp->lock); /* ...and finally, reset everything */ - napi_enable(&tp->napi); + napi_enable_locked(&tp->napi); rtl8139_hw_start(dev); netif_wake_queue(dev); spin_unlock_bh(&tp->rx_lock); + netdev_unlock(dev); } static void rtl8139_tx_timeout(struct net_device *dev, unsigned int txqueue) diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig index 03015b665f4e..8a8ea51c639e 100644 --- a/drivers/net/ethernet/realtek/Kconfig +++ b/drivers/net/ethernet/realtek/Kconfig @@ -120,4 +120,23 @@ config R8169_LEDS Optional support for controlling the NIC LED's with the netdev LED trigger. +config RTASE + tristate "Realtek Automotive Switch 9054/9068/9072/9075/9068/9071 PCIe Interface support" + depends on PCI + select CRC32 + select PAGE_POOL + help + Say Y here and it will be compiled and linked with the kernel + if you have a Realtek Ethernet adapter belonging to the + following families: + RTL9054 5GBit Ethernet + RTL9068 5GBit Ethernet + RTL9072 5GBit Ethernet + RTL9075 5GBit Ethernet + RTL9068 5GBit Ethernet + RTL9071 5GBit Ethernet + + To compile this driver as a module, choose M here: the module + will be called rtase. This is recommended. + endif # NET_VENDOR_REALTEK diff --git a/drivers/net/ethernet/realtek/Makefile b/drivers/net/ethernet/realtek/Makefile index 635491d8826e..046adf503ff4 100644 --- a/drivers/net/ethernet/realtek/Makefile +++ b/drivers/net/ethernet/realtek/Makefile @@ -9,3 +9,4 @@ obj-$(CONFIG_ATP) += atp.o r8169-y += r8169_main.o r8169_firmware.o r8169_phy_config.o r8169-$(CONFIG_R8169_LEDS) += r8169_leds.o obj-$(CONFIG_R8169) += r8169.o +obj-$(CONFIG_RTASE) += rtase/ diff --git a/drivers/net/ethernet/realtek/r8169.h b/drivers/net/ethernet/realtek/r8169.h index 81567fcf3957..7a194a8ab989 100644 --- a/drivers/net/ethernet/realtek/r8169.h +++ b/drivers/net/ethernet/realtek/r8169.h @@ -23,7 +23,7 @@ enum mac_version { RTL_GIGA_MAC_VER_08, RTL_GIGA_MAC_VER_09, RTL_GIGA_MAC_VER_10, - RTL_GIGA_MAC_VER_11, + /* support for RTL_GIGA_MAC_VER_11 has been removed */ /* RTL_GIGA_MAC_VER_12 was handled the same as VER_17 */ /* RTL_GIGA_MAC_VER_13 was merged with VER_10 */ RTL_GIGA_MAC_VER_14, @@ -68,10 +68,16 @@ enum mac_version { /* support for RTL_GIGA_MAC_VER_60 has been removed */ RTL_GIGA_MAC_VER_61, RTL_GIGA_MAC_VER_63, + RTL_GIGA_MAC_VER_64, + RTL_GIGA_MAC_VER_65, + RTL_GIGA_MAC_VER_66, + RTL_GIGA_MAC_VER_70, + RTL_GIGA_MAC_VER_71, RTL_GIGA_MAC_NONE }; struct rtl8169_private; +struct r8169_led_classdev; void r8169_apply_firmware(struct rtl8169_private *tp); u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp); @@ -83,4 +89,8 @@ void r8169_get_led_name(struct rtl8169_private *tp, int idx, char *buf, int buf_len); int rtl8168_get_led_mode(struct rtl8169_private *tp); int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val); -void rtl8168_init_leds(struct net_device *ndev); +struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev); +int rtl8125_get_led_mode(struct rtl8169_private *tp, int index); +int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode); +struct r8169_led_classdev *rtl8125_init_leds(struct net_device *ndev); +void r8169_remove_leds(struct r8169_led_classdev *leds); diff --git a/drivers/net/ethernet/realtek/r8169_firmware.c b/drivers/net/ethernet/realtek/r8169_firmware.c index ed6e721b1555..bf055078a855 100644 --- a/drivers/net/ethernet/realtek/r8169_firmware.c +++ b/drivers/net/ethernet/realtek/r8169_firmware.c @@ -215,7 +215,7 @@ int rtl_fw_request_firmware(struct rtl_fw *rtl_fw) { int rc; - rc = request_firmware(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); + rc = firmware_request_nowarn(&rtl_fw->fw, rtl_fw->fw_name, rtl_fw->dev); if (rc < 0) goto out; @@ -227,7 +227,7 @@ int rtl_fw_request_firmware(struct rtl_fw *rtl_fw) return 0; out: - dev_err(rtl_fw->dev, "Unable to load firmware %s (%d)\n", - rtl_fw->fw_name, rc); + dev_warn(rtl_fw->dev, "Unable to load firmware %s (%d)\n", + rtl_fw->fw_name, rc); return rc; } diff --git a/drivers/net/ethernet/realtek/r8169_leds.c b/drivers/net/ethernet/realtek/r8169_leds.c index 007d077edcad..e10bee706bc6 100644 --- a/drivers/net/ethernet/realtek/r8169_leds.c +++ b/drivers/net/ethernet/realtek/r8169_leds.c @@ -18,12 +18,14 @@ #define RTL8168_LED_CTRL_LINK_100 BIT(1) #define RTL8168_LED_CTRL_LINK_10 BIT(0) -#define RTL8168_NUM_LEDS 3 +#define RTL8125_LED_CTRL_ACT BIT(9) +#define RTL8125_LED_CTRL_LINK_2500 BIT(5) +#define RTL8125_LED_CTRL_LINK_1000 BIT(3) +#define RTL8125_LED_CTRL_LINK_100 BIT(1) +#define RTL8125_LED_CTRL_LINK_10 BIT(0) -#define RTL8168_SUPPORTED_MODES \ - (BIT(TRIGGER_NETDEV_LINK_1000) | BIT(TRIGGER_NETDEV_LINK_100) | \ - BIT(TRIGGER_NETDEV_LINK_10) | BIT(TRIGGER_NETDEV_RX) | \ - BIT(TRIGGER_NETDEV_TX)) +#define RTL8168_NUM_LEDS 3 +#define RTL8125_NUM_LEDS 4 struct r8169_led_classdev { struct led_classdev led; @@ -33,28 +35,35 @@ struct r8169_led_classdev { #define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led) +static bool r8169_trigger_mode_is_valid(unsigned long flags) +{ + bool rx, tx; + + if (flags & BIT(TRIGGER_NETDEV_HALF_DUPLEX)) + return false; + if (flags & BIT(TRIGGER_NETDEV_FULL_DUPLEX)) + return false; + + rx = flags & BIT(TRIGGER_NETDEV_RX); + tx = flags & BIT(TRIGGER_NETDEV_TX); + + return rx == tx; +} + static int rtl8168_led_hw_control_is_supported(struct led_classdev *led_cdev, unsigned long flags) { struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); struct rtl8169_private *tp = netdev_priv(ldev->ndev); int shift = ldev->index * 4; - bool rx, tx; - if (flags & ~RTL8168_SUPPORTED_MODES) - goto nosupp; - - rx = flags & BIT(TRIGGER_NETDEV_RX); - tx = flags & BIT(TRIGGER_NETDEV_TX); - if (rx != tx) - goto nosupp; + if (!r8169_trigger_mode_is_valid(flags)) { + /* Switch LED off to indicate that mode isn't supported */ + rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); + return -EOPNOTSUPP; + } return 0; - -nosupp: - /* Switch LED off to indicate that mode isn't supported */ - rtl8168_led_mod_ctrl(tp, 0x000f << shift, 0); - return -EOPNOTSUPP; } static int rtl8168_led_hw_control_set(struct led_classdev *led_cdev, @@ -129,7 +138,6 @@ static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev, r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); led_cdev->name = led_name; - led_cdev->default_trigger = "netdev"; led_cdev->hw_control_trigger = "netdev"; led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; led_cdev->hw_control_is_supported = rtl8168_led_hw_control_is_supported; @@ -138,20 +146,130 @@ static void rtl8168_setup_ldev(struct r8169_led_classdev *ldev, led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; /* ignore errors */ - devm_led_classdev_register(&ndev->dev, led_cdev); + led_classdev_register(&ndev->dev, led_cdev); } -void rtl8168_init_leds(struct net_device *ndev) +struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev) { - /* bind resource mgmt to netdev */ - struct device *dev = &ndev->dev; struct r8169_led_classdev *leds; int i; - leds = devm_kcalloc(dev, RTL8168_NUM_LEDS, sizeof(*leds), GFP_KERNEL); + leds = kcalloc(RTL8168_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL); if (!leds) - return; + return NULL; for (i = 0; i < RTL8168_NUM_LEDS; i++) rtl8168_setup_ldev(leds + i, ndev, i); + + return leds; +} + +static int rtl8125_led_hw_control_is_supported(struct led_classdev *led_cdev, + unsigned long flags) +{ + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); + struct rtl8169_private *tp = netdev_priv(ldev->ndev); + + if (!r8169_trigger_mode_is_valid(flags)) { + /* Switch LED off to indicate that mode isn't supported */ + rtl8125_set_led_mode(tp, ldev->index, 0); + return -EOPNOTSUPP; + } + + return 0; +} + +static int rtl8125_led_hw_control_set(struct led_classdev *led_cdev, + unsigned long flags) +{ + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); + struct rtl8169_private *tp = netdev_priv(ldev->ndev); + u16 mode = 0; + + if (flags & BIT(TRIGGER_NETDEV_LINK_10)) + mode |= RTL8125_LED_CTRL_LINK_10; + if (flags & BIT(TRIGGER_NETDEV_LINK_100)) + mode |= RTL8125_LED_CTRL_LINK_100; + if (flags & BIT(TRIGGER_NETDEV_LINK_1000)) + mode |= RTL8125_LED_CTRL_LINK_1000; + if (flags & BIT(TRIGGER_NETDEV_LINK_2500)) + mode |= RTL8125_LED_CTRL_LINK_2500; + if (flags & (BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX))) + mode |= RTL8125_LED_CTRL_ACT; + + return rtl8125_set_led_mode(tp, ldev->index, mode); +} + +static int rtl8125_led_hw_control_get(struct led_classdev *led_cdev, + unsigned long *flags) +{ + struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev); + struct rtl8169_private *tp = netdev_priv(ldev->ndev); + int mode; + + mode = rtl8125_get_led_mode(tp, ldev->index); + if (mode < 0) + return mode; + + if (mode & RTL8125_LED_CTRL_LINK_10) + *flags |= BIT(TRIGGER_NETDEV_LINK_10); + if (mode & RTL8125_LED_CTRL_LINK_100) + *flags |= BIT(TRIGGER_NETDEV_LINK_100); + if (mode & RTL8125_LED_CTRL_LINK_1000) + *flags |= BIT(TRIGGER_NETDEV_LINK_1000); + if (mode & RTL8125_LED_CTRL_LINK_2500) + *flags |= BIT(TRIGGER_NETDEV_LINK_2500); + if (mode & RTL8125_LED_CTRL_ACT) + *flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX); + + return 0; +} + +static void rtl8125_setup_led_ldev(struct r8169_led_classdev *ldev, + struct net_device *ndev, int index) +{ + struct rtl8169_private *tp = netdev_priv(ndev); + struct led_classdev *led_cdev = &ldev->led; + char led_name[LED_MAX_NAME_SIZE]; + + ldev->ndev = ndev; + ldev->index = index; + + r8169_get_led_name(tp, index, led_name, LED_MAX_NAME_SIZE); + led_cdev->name = led_name; + led_cdev->hw_control_trigger = "netdev"; + led_cdev->flags |= LED_RETAIN_AT_SHUTDOWN; + led_cdev->hw_control_is_supported = rtl8125_led_hw_control_is_supported; + led_cdev->hw_control_set = rtl8125_led_hw_control_set; + led_cdev->hw_control_get = rtl8125_led_hw_control_get; + led_cdev->hw_control_get_device = r8169_led_hw_control_get_device; + + /* ignore errors */ + led_classdev_register(&ndev->dev, led_cdev); +} + +struct r8169_led_classdev *rtl8125_init_leds(struct net_device *ndev) +{ + struct r8169_led_classdev *leds; + int i; + + leds = kcalloc(RTL8125_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL); + if (!leds) + return NULL; + + for (i = 0; i < RTL8125_NUM_LEDS; i++) + rtl8125_setup_led_ldev(leds + i, ndev, i); + + return leds; +} + +void r8169_remove_leds(struct r8169_led_classdev *leds) +{ + if (!leds) + return; + + for (struct r8169_led_classdev *l = leds; l->ndev; l++) + led_classdev_unregister(&l->led); + + kfree(leds); } diff --git a/drivers/net/ethernet/realtek/r8169_main.c b/drivers/net/ethernet/realtek/r8169_main.c index dd73df6b17b0..5a5eba49c651 100644 --- a/drivers/net/ethernet/realtek/r8169_main.c +++ b/drivers/net/ethernet/realtek/r8169_main.c @@ -28,7 +28,7 @@ #include <linux/bitfield.h> #include <linux/prefetch.h> #include <linux/ipv6.h> -#include <asm/unaligned.h> +#include <linux/unaligned.h> #include <net/ip6_checksum.h> #include <net/netdev_queues.h> @@ -55,6 +55,11 @@ #define FIRMWARE_8107E_2 "rtl_nic/rtl8107e-2.fw" #define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw" #define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw" +#define FIRMWARE_8125D_1 "rtl_nic/rtl8125d-1.fw" +#define FIRMWARE_8125D_2 "rtl_nic/rtl8125d-2.fw" +#define FIRMWARE_8125BP_2 "rtl_nic/rtl8125bp-2.fw" +#define FIRMWARE_8126A_2 "rtl_nic/rtl8126a-2.fw" +#define FIRMWARE_8126A_3 "rtl_nic/rtl8126a-3.fw" #define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */ #define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */ @@ -100,7 +105,6 @@ static const struct { [RTL_GIGA_MAC_VER_08] = {"RTL8102e" }, [RTL_GIGA_MAC_VER_09] = {"RTL8102e/RTL8103e" }, [RTL_GIGA_MAC_VER_10] = {"RTL8101e/RTL8100e" }, - [RTL_GIGA_MAC_VER_11] = {"RTL8168b/8111b" }, [RTL_GIGA_MAC_VER_14] = {"RTL8401" }, [RTL_GIGA_MAC_VER_17] = {"RTL8168b/8111b" }, [RTL_GIGA_MAC_VER_18] = {"RTL8168cp/8111cp" }, @@ -136,6 +140,11 @@ static const struct { [RTL_GIGA_MAC_VER_61] = {"RTL8125A", FIRMWARE_8125A_3}, /* reserve 62 for CFG_METHOD_4 in the vendor driver */ [RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2}, + [RTL_GIGA_MAC_VER_64] = {"RTL8125D", FIRMWARE_8125D_1}, + [RTL_GIGA_MAC_VER_65] = {"RTL8125D", FIRMWARE_8125D_2}, + [RTL_GIGA_MAC_VER_66] = {"RTL8125BP", FIRMWARE_8125BP_2}, + [RTL_GIGA_MAC_VER_70] = {"RTL8126A", FIRMWARE_8126A_2}, + [RTL_GIGA_MAC_VER_71] = {"RTL8126A", FIRMWARE_8126A_3}, }; static const struct pci_device_id rtl8169_pci_tbl[] = { @@ -158,6 +167,7 @@ static const struct pci_device_id rtl8169_pci_tbl[] = { { PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024 }, { 0x0001, 0x8168, PCI_ANY_ID, 0x2410 }, { PCI_VDEVICE(REALTEK, 0x8125) }, + { PCI_VDEVICE(REALTEK, 0x8126) }, { PCI_VDEVICE(REALTEK, 0x3000) }, {} }; @@ -327,13 +337,25 @@ enum rtl8168_registers { }; enum rtl8125_registers { + LEDSEL0 = 0x18, + INT_CFG0_8125 = 0x34, +#define INT_CFG0_ENABLE_8125 BIT(0) +#define INT_CFG0_CLKREQEN BIT(3) IntrMask_8125 = 0x38, IntrStatus_8125 = 0x3c, + INT_CFG1_8125 = 0x7a, + LEDSEL2 = 0x84, + LEDSEL1 = 0x86, TxPoll_8125 = 0x90, + LEDSEL3 = 0x96, MAC0_BKP = 0x19e0, + RSS_CTRL_8125 = 0x4500, + Q_NUM_CTRL_8125 = 0x4800, EEE_TXIDLE_TIMER_8125 = 0x6048, }; +#define LEDSEL_MASK_8125 0x23f + #define RX_VLAN_INNER_8125 BIT(22) #define RX_VLAN_OUTER_8125 BIT(23) #define RX_VLAN_8125 (RX_VLAN_INNER_8125 | RX_VLAN_OUTER_8125) @@ -563,7 +585,34 @@ struct rtl8169_counters { __le64 rx_broadcast; __le32 rx_multicast; __le16 tx_aborted; - __le16 tx_underun; + __le16 tx_underrun; + /* new since RTL8125 */ + __le64 tx_octets; + __le64 rx_octets; + __le64 rx_multicast64; + __le64 tx_unicast64; + __le64 tx_broadcast64; + __le64 tx_multicast64; + __le32 tx_pause_on; + __le32 tx_pause_off; + __le32 tx_pause_all; + __le32 tx_deferred; + __le32 tx_late_collision; + __le32 tx_all_collision; + __le32 tx_aborted32; + __le32 align_errors32; + __le32 rx_frame_too_long; + __le32 rx_runt; + __le32 rx_pause_on; + __le32 rx_pause_off; + __le32 rx_pause_all; + __le32 rx_unknown_opcode; + __le32 rx_mac_error; + __le32 tx_underrun32; + __le32 rx_mac_missed; + __le32 rx_tcam_dropped; + __le32 tdu; + __le32 rdu; }; struct rtl8169_tc_offsets { @@ -575,9 +624,7 @@ struct rtl8169_tc_offsets { }; enum rtl_flag { - RTL_FLAG_TASK_ENABLED = 0, RTL_FLAG_TASK_RESET_PENDING, - RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, RTL_FLAG_TASK_TX_TIMEOUT, RTL_FLAG_MAX }; @@ -586,6 +633,7 @@ enum rtl_dash_type { RTL_DASH_NONE, RTL_DASH_DP, RTL_DASH_EP, + RTL_DASH_25_BP, }; struct rtl8169_private { @@ -606,6 +654,7 @@ struct rtl8169_private { struct page *Rx_databuff[NUM_RX_DESC]; /* Rx data buffers */ struct ring_info tx_skb[NUM_TX_DESC]; /* Tx data buffers */ u16 cp_cmd; + u16 tx_lpi_timer; u32 irq_mask; int irq; struct clk *clk; @@ -615,13 +664,9 @@ struct rtl8169_private { struct work_struct work; } wk; - raw_spinlock_t config25_lock; raw_spinlock_t mac_ocp_lock; struct mutex led_lock; /* serialize LED ctrl RMW access */ - raw_spinlock_t cfg9346_usage_lock; - int cfg9346_usage_count; - unsigned supports_gmii:1; unsigned aspm_manageable:1; unsigned dash_enabled:1; @@ -629,11 +674,12 @@ struct rtl8169_private { struct rtl8169_counters *counters; struct rtl8169_tc_offsets tc_offset; u32 saved_wolopts; - int eee_adv; const char *fw_name; struct rtl_fw *rtl_fw; + struct r8169_led_classdev *leds; + u32 ocp_base; }; @@ -663,6 +709,11 @@ MODULE_FIRMWARE(FIRMWARE_8168FP_3); MODULE_FIRMWARE(FIRMWARE_8107E_2); MODULE_FIRMWARE(FIRMWARE_8125A_3); MODULE_FIRMWARE(FIRMWARE_8125B_2); +MODULE_FIRMWARE(FIRMWARE_8125D_1); +MODULE_FIRMWARE(FIRMWARE_8125D_2); +MODULE_FIRMWARE(FIRMWARE_8125BP_2); +MODULE_FIRMWARE(FIRMWARE_8126A_2); +MODULE_FIRMWARE(FIRMWARE_8126A_3); static inline struct device *tp_to_dev(struct rtl8169_private *tp) { @@ -671,22 +722,12 @@ static inline struct device *tp_to_dev(struct rtl8169_private *tp) static void rtl_lock_config_regs(struct rtl8169_private *tp) { - unsigned long flags; - - raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); - if (!--tp->cfg9346_usage_count) - RTL_W8(tp, Cfg9346, Cfg9346_Lock); - raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); + RTL_W8(tp, Cfg9346, Cfg9346_Lock); } static void rtl_unlock_config_regs(struct rtl8169_private *tp) { - unsigned long flags; - - raw_spin_lock_irqsave(&tp->cfg9346_usage_lock, flags); - if (!tp->cfg9346_usage_count++) - RTL_W8(tp, Cfg9346, Cfg9346_Unlock); - raw_spin_unlock_irqrestore(&tp->cfg9346_usage_lock, flags); + RTL_W8(tp, Cfg9346, Cfg9346_Unlock); } static void rtl_pci_commit(struct rtl8169_private *tp) @@ -697,24 +738,32 @@ static void rtl_pci_commit(struct rtl8169_private *tp) static void rtl_mod_config2(struct rtl8169_private *tp, u8 clear, u8 set) { - unsigned long flags; u8 val; - raw_spin_lock_irqsave(&tp->config25_lock, flags); val = RTL_R8(tp, Config2); RTL_W8(tp, Config2, (val & ~clear) | set); - raw_spin_unlock_irqrestore(&tp->config25_lock, flags); } static void rtl_mod_config5(struct rtl8169_private *tp, u8 clear, u8 set) { - unsigned long flags; u8 val; - raw_spin_lock_irqsave(&tp->config25_lock, flags); val = RTL_R8(tp, Config5); RTL_W8(tp, Config5, (val & ~clear) | set); - raw_spin_unlock_irqrestore(&tp->config25_lock, flags); +} + +static void r8169_mod_reg8_cond(struct rtl8169_private *tp, int reg, + u8 bits, bool cond) +{ + u8 val, old_val; + + old_val = RTL_R8(tp, reg); + if (cond) + val = old_val | bits; + else + val = old_val & ~bits; + if (val != old_val) + RTL_W8(tp, reg, val); } static bool rtl_is_8125(struct rtl8169_private *tp) @@ -824,6 +873,51 @@ int rtl8168_get_led_mode(struct rtl8169_private *tp) return ret; } +static int rtl8125_get_led_reg(int index) +{ + static const int led_regs[] = { LEDSEL0, LEDSEL1, LEDSEL2, LEDSEL3 }; + + return led_regs[index]; +} + +int rtl8125_set_led_mode(struct rtl8169_private *tp, int index, u16 mode) +{ + int reg = rtl8125_get_led_reg(index); + struct device *dev = tp_to_dev(tp); + int ret; + u16 val; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + mutex_lock(&tp->led_lock); + val = RTL_R16(tp, reg) & ~LEDSEL_MASK_8125; + RTL_W16(tp, reg, val | mode); + mutex_unlock(&tp->led_lock); + + pm_runtime_put_sync(dev); + + return 0; +} + +int rtl8125_get_led_mode(struct rtl8169_private *tp, int index) +{ + int reg = rtl8125_get_led_reg(index); + struct device *dev = tp_to_dev(tp); + int ret; + + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) + return ret; + + ret = RTL_R16(tp, reg); + + pm_runtime_put_sync(dev); + + return ret; +} + void r8169_get_led_name(struct rtl8169_private *tp, int idx, char *buf, int buf_len) { @@ -1140,7 +1234,7 @@ static void rtl_writephy(struct rtl8169_private *tp, int location, int val) case RTL_GIGA_MAC_VER_31: r8168dp_2_mdio_write(tp, location, val); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: r8168g_mdio_write(tp, location, val); break; default: @@ -1155,7 +1249,7 @@ static int rtl_readphy(struct rtl8169_private *tp, int location) case RTL_GIGA_MAC_VER_28: case RTL_GIGA_MAC_VER_31: return r8168dp_2_mdio_read(tp, location); - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: return r8168g_mdio_read(tp, location); default: return r8169_mdio_read(tp, location); @@ -1258,20 +1352,31 @@ static void rtl8168ep_stop_cmac(struct rtl8169_private *tp) static void rtl8168dp_driver_start(struct rtl8169_private *tp) { r8168dp_oob_notify(tp, OOB_CMD_DRIVER_START); - rtl_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); + if (tp->dash_enabled) + rtl_loop_wait_high(tp, &rtl_dp_ocp_read_cond, 10000, 10); } static void rtl8168ep_driver_start(struct rtl8169_private *tp) { r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_START); r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); - rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); + if (tp->dash_enabled) + rtl_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30); +} + +static void rtl8125bp_driver_start(struct rtl8169_private *tp) +{ + r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_START); + r8168ep_ocp_write(tp, 0x01, 0x18, 0x00); + r8168ep_ocp_write(tp, 0x01, 0x10, 0x01); } static void rtl8168_driver_start(struct rtl8169_private *tp) { if (tp->dash_type == RTL_DASH_DP) rtl8168dp_driver_start(tp); + else if (tp->dash_type == RTL_DASH_25_BP) + rtl8125bp_driver_start(tp); else rtl8168ep_driver_start(tp); } @@ -1279,7 +1384,8 @@ static void rtl8168_driver_start(struct rtl8169_private *tp) static void rtl8168dp_driver_stop(struct rtl8169_private *tp) { r8168dp_oob_notify(tp, OOB_CMD_DRIVER_STOP); - rtl_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); + if (tp->dash_enabled) + rtl_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10); } static void rtl8168ep_driver_stop(struct rtl8169_private *tp) @@ -1287,13 +1393,23 @@ static void rtl8168ep_driver_stop(struct rtl8169_private *tp) rtl8168ep_stop_cmac(tp); r8168ep_ocp_write(tp, 0x01, 0x180, OOB_CMD_DRIVER_STOP); r8168ep_ocp_write(tp, 0x01, 0x30, r8168ep_ocp_read(tp, 0x30) | 0x01); - rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); + if (tp->dash_enabled) + rtl_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10); +} + +static void rtl8125bp_driver_stop(struct rtl8169_private *tp) +{ + r8168ep_ocp_write(tp, 0x01, 0x14, OOB_CMD_DRIVER_STOP); + r8168ep_ocp_write(tp, 0x01, 0x18, 0x00); + r8168ep_ocp_write(tp, 0x01, 0x10, 0x01); } static void rtl8168_driver_stop(struct rtl8169_private *tp) { if (tp->dash_type == RTL_DASH_DP) rtl8168dp_driver_stop(tp); + else if (tp->dash_type == RTL_DASH_25_BP) + rtl8125bp_driver_stop(tp); else rtl8168ep_driver_stop(tp); } @@ -1316,6 +1432,7 @@ static bool rtl_dash_is_enabled(struct rtl8169_private *tp) case RTL_DASH_DP: return r8168dp_check_dash(tp); case RTL_DASH_EP: + case RTL_DASH_25_BP: return r8168ep_check_dash(tp); default: return false; @@ -1330,6 +1447,8 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) return RTL_DASH_DP; case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53: return RTL_DASH_EP; + case RTL_GIGA_MAC_VER_66: + return RTL_DASH_25_BP; default: return RTL_DASH_NONE; } @@ -1337,19 +1456,11 @@ static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp) static void rtl_set_d3_pll_down(struct rtl8169_private *tp, bool enable) { - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_25 ... RTL_GIGA_MAC_VER_26: - case RTL_GIGA_MAC_VER_29 ... RTL_GIGA_MAC_VER_30: - case RTL_GIGA_MAC_VER_32 ... RTL_GIGA_MAC_VER_37: - case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63: - if (enable) - RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) & ~D3_NO_PLL_DOWN); - else - RTL_W8(tp, PMCH, RTL_R8(tp, PMCH) | D3_NO_PLL_DOWN); - break; - default: - break; - } + if (tp->mac_version >= RTL_GIGA_MAC_VER_25 && + tp->mac_version != RTL_GIGA_MAC_VER_28 && + tp->mac_version != RTL_GIGA_MAC_VER_31 && + tp->mac_version != RTL_GIGA_MAC_VER_38) + r8169_mod_reg8_cond(tp, PMCH, D3_NO_PLL_DOWN, !enable); } static void rtl_reset_packet_filter(struct rtl8169_private *tp) @@ -1458,61 +1569,40 @@ static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) { - static const struct { - u32 opt; - u16 reg; - u8 mask; - } cfg[] = { - { WAKE_PHY, Config3, LinkUp }, - { WAKE_UCAST, Config5, UWF }, - { WAKE_BCAST, Config5, BWF }, - { WAKE_MCAST, Config5, MWF }, - { WAKE_ANY, Config5, LanWake }, - { WAKE_MAGIC, Config3, MagicPacket } - }; - unsigned int i, tmp = ARRAY_SIZE(cfg); - unsigned long flags; - u8 options; - rtl_unlock_config_regs(tp); if (rtl_is_8168evl_up(tp)) { - tmp--; if (wolopts & WAKE_MAGIC) rtl_eri_set_bits(tp, 0x0dc, MagicPacket_v2); else rtl_eri_clear_bits(tp, 0x0dc, MagicPacket_v2); } else if (rtl_is_8125(tp)) { - tmp--; if (wolopts & WAKE_MAGIC) r8168_mac_ocp_modify(tp, 0xc0b6, 0, BIT(0)); else r8168_mac_ocp_modify(tp, 0xc0b6, BIT(0), 0); + } else { + r8169_mod_reg8_cond(tp, Config3, MagicPacket, + wolopts & WAKE_MAGIC); } - raw_spin_lock_irqsave(&tp->config25_lock, flags); - for (i = 0; i < tmp; i++) { - options = RTL_R8(tp, cfg[i].reg) & ~cfg[i].mask; - if (wolopts & cfg[i].opt) - options |= cfg[i].mask; - RTL_W8(tp, cfg[i].reg, options); - } - raw_spin_unlock_irqrestore(&tp->config25_lock, flags); + r8169_mod_reg8_cond(tp, Config3, LinkUp, wolopts & WAKE_PHY); + if (rtl_is_8125(tp)) + r8168_mac_ocp_modify(tp, 0xe0c6, 0x3f, + wolopts & WAKE_PHY ? 0x13 : 0); + r8169_mod_reg8_cond(tp, Config5, UWF, wolopts & WAKE_UCAST); + r8169_mod_reg8_cond(tp, Config5, BWF, wolopts & WAKE_BCAST); + r8169_mod_reg8_cond(tp, Config5, MWF, wolopts & WAKE_MCAST); + r8169_mod_reg8_cond(tp, Config5, LanWake, wolopts); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: - options = RTL_R8(tp, Config1) & ~PMEnable; - if (wolopts) - options |= PMEnable; - RTL_W8(tp, Config1, options); + r8169_mod_reg8_cond(tp, Config1, PMEnable, wolopts); break; case RTL_GIGA_MAC_VER_34: case RTL_GIGA_MAC_VER_37: - case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_63: - if (wolopts) - rtl_mod_config2(tp, 0, PME_SIGNAL); - else - rtl_mod_config2(tp, PME_SIGNAL, 0); + case RTL_GIGA_MAC_VER_39 ... RTL_GIGA_MAC_VER_71: + r8169_mod_reg8_cond(tp, Config2, PME_SIGNAL, wolopts); break; default: break; @@ -1524,7 +1614,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts) if (!tp->dash_enabled) { rtl_set_d3_pll_down(tp, !wolopts); - tp->dev->wol_enabled = wolopts ? 1 : 0; + tp->dev->ethtool->wol_enabled = wolopts ? 1 : 0; } } @@ -1757,7 +1847,7 @@ static void rtl8169_get_ethtool_stats(struct net_device *dev, data[9] = le64_to_cpu(counters->rx_broadcast); data[10] = le32_to_cpu(counters->rx_multicast); data[11] = le16_to_cpu(counters->tx_aborted); - data[12] = le16_to_cpu(counters->tx_underun); + data[12] = le16_to_cpu(counters->tx_underrun); } static void rtl8169_get_strings(struct net_device *dev, u32 stringset, u8 *data) @@ -1974,30 +2064,62 @@ static int rtl_set_coalesce(struct net_device *dev, return 0; } -static int rtl8169_get_eee(struct net_device *dev, struct ethtool_eee *data) +static void rtl_set_eee_txidle_timer(struct rtl8169_private *tp) +{ + unsigned int timer_val = READ_ONCE(tp->dev->mtu) + ETH_HLEN + 0x20; + + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_46: + case RTL_GIGA_MAC_VER_48: + tp->tx_lpi_timer = timer_val; + r8168_mac_ocp_write(tp, 0xe048, timer_val); + break; + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: + tp->tx_lpi_timer = timer_val; + RTL_W16(tp, EEE_TXIDLE_TIMER_8125, timer_val); + break; + default: + break; + } +} + +static unsigned int r8169_get_tx_lpi_timer_us(struct rtl8169_private *tp) +{ + unsigned int speed = tp->phydev->speed; + unsigned int timer = tp->tx_lpi_timer; + + if (!timer || speed == SPEED_UNKNOWN) + return 0; + + /* tx_lpi_timer value is in bytes */ + return DIV_ROUND_CLOSEST(timer * BITS_PER_BYTE, speed); +} + +static int rtl8169_get_eee(struct net_device *dev, struct ethtool_keee *data) { struct rtl8169_private *tp = netdev_priv(dev); + int ret; if (!rtl_supports_eee(tp)) return -EOPNOTSUPP; - return phy_ethtool_get_eee(tp->phydev, data); + ret = phy_ethtool_get_eee(tp->phydev, data); + if (ret) + return ret; + + data->tx_lpi_timer = r8169_get_tx_lpi_timer_us(tp); + + return 0; } -static int rtl8169_set_eee(struct net_device *dev, struct ethtool_eee *data) +static int rtl8169_set_eee(struct net_device *dev, struct ethtool_keee *data) { struct rtl8169_private *tp = netdev_priv(dev); - int ret; if (!rtl_supports_eee(tp)) return -EOPNOTSUPP; - ret = phy_ethtool_set_eee(tp->phydev, data); - - if (!ret) - tp->eee_adv = phy_read_mmd(dev->phydev, MDIO_MMD_AN, - MDIO_AN_EEE_ADV); - return ret; + return phy_ethtool_set_eee(tp->phydev, data); } static void rtl8169_get_ringparam(struct net_device *dev, @@ -2011,6 +2133,19 @@ static void rtl8169_get_ringparam(struct net_device *dev, data->tx_pending = NUM_TX_DESC; } +static void rtl8169_get_pause_stats(struct net_device *dev, + struct ethtool_pause_stats *pause_stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (!rtl_is_8125(tp)) + return; + + rtl8169_update_counters(tp); + pause_stats->tx_pause_frames = le32_to_cpu(tp->counters->tx_pause_on); + pause_stats->rx_pause_frames = le32_to_cpu(tp->counters->rx_pause_on); +} + static void rtl8169_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *data) { @@ -2037,6 +2172,69 @@ static int rtl8169_set_pauseparam(struct net_device *dev, return 0; } +static void rtl8169_get_eth_mac_stats(struct net_device *dev, + struct ethtool_eth_mac_stats *mac_stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + rtl8169_update_counters(tp); + + mac_stats->FramesTransmittedOK = + le64_to_cpu(tp->counters->tx_packets); + mac_stats->SingleCollisionFrames = + le32_to_cpu(tp->counters->tx_one_collision); + mac_stats->MultipleCollisionFrames = + le32_to_cpu(tp->counters->tx_multi_collision); + mac_stats->FramesReceivedOK = + le64_to_cpu(tp->counters->rx_packets); + mac_stats->AlignmentErrors = + le16_to_cpu(tp->counters->align_errors); + mac_stats->FramesLostDueToIntMACXmitError = + le64_to_cpu(tp->counters->tx_errors); + mac_stats->BroadcastFramesReceivedOK = + le64_to_cpu(tp->counters->rx_broadcast); + mac_stats->MulticastFramesReceivedOK = + le32_to_cpu(tp->counters->rx_multicast); + + if (!rtl_is_8125(tp)) + return; + + mac_stats->AlignmentErrors = + le32_to_cpu(tp->counters->align_errors32); + mac_stats->OctetsTransmittedOK = + le64_to_cpu(tp->counters->tx_octets); + mac_stats->LateCollisions = + le32_to_cpu(tp->counters->tx_late_collision); + mac_stats->FramesAbortedDueToXSColls = + le32_to_cpu(tp->counters->tx_aborted32); + mac_stats->OctetsReceivedOK = + le64_to_cpu(tp->counters->rx_octets); + mac_stats->FramesLostDueToIntMACRcvError = + le32_to_cpu(tp->counters->rx_mac_error); + mac_stats->MulticastFramesXmittedOK = + le64_to_cpu(tp->counters->tx_multicast64); + mac_stats->BroadcastFramesXmittedOK = + le64_to_cpu(tp->counters->tx_broadcast64); + mac_stats->MulticastFramesReceivedOK = + le64_to_cpu(tp->counters->rx_multicast64); + mac_stats->FrameTooLongErrors = + le32_to_cpu(tp->counters->rx_frame_too_long); +} + +static void rtl8169_get_eth_ctrl_stats(struct net_device *dev, + struct ethtool_eth_ctrl_stats *ctrl_stats) +{ + struct rtl8169_private *tp = netdev_priv(dev); + + if (!rtl_is_8125(tp)) + return; + + rtl8169_update_counters(tp); + + ctrl_stats->UnsupportedOpcodesReceived = + le32_to_cpu(tp->counters->rx_unknown_opcode); +} + static const struct ethtool_ops rtl8169_ethtool_ops = { .supported_coalesce_params = ETHTOOL_COALESCE_USECS | ETHTOOL_COALESCE_MAX_FRAMES, @@ -2058,25 +2256,13 @@ static const struct ethtool_ops rtl8169_ethtool_ops = { .get_link_ksettings = phy_ethtool_get_link_ksettings, .set_link_ksettings = phy_ethtool_set_link_ksettings, .get_ringparam = rtl8169_get_ringparam, + .get_pause_stats = rtl8169_get_pause_stats, .get_pauseparam = rtl8169_get_pauseparam, .set_pauseparam = rtl8169_set_pauseparam, + .get_eth_mac_stats = rtl8169_get_eth_mac_stats, + .get_eth_ctrl_stats = rtl8169_get_eth_ctrl_stats, }; -static void rtl_enable_eee(struct rtl8169_private *tp) -{ - struct phy_device *phydev = tp->phydev; - int adv; - - /* respect EEE advertisement the user may have set */ - if (tp->eee_adv >= 0) - adv = tp->eee_adv; - else - adv = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_PCS_EEE_ABLE); - - if (adv >= 0) - phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, adv); -} - static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) { /* @@ -2095,6 +2281,17 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) u16 val; enum mac_version ver; } mac_info[] = { + /* 8126A family. */ + { 0x7cf, 0x64a, RTL_GIGA_MAC_VER_71 }, + { 0x7cf, 0x649, RTL_GIGA_MAC_VER_70 }, + + /* 8125BP family. */ + { 0x7cf, 0x681, RTL_GIGA_MAC_VER_66 }, + + /* 8125D family. */ + { 0x7cf, 0x689, RTL_GIGA_MAC_VER_65 }, + { 0x7cf, 0x688, RTL_GIGA_MAC_VER_64 }, + /* 8125B family. */ { 0x7cf, 0x641, RTL_GIGA_MAC_VER_63 }, @@ -2123,6 +2320,8 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) * the wild. Let's disable detection. * { 0x7cf, 0x540, RTL_GIGA_MAC_VER_45 }, */ + /* Realtek calls it RTL8168M, but it's handled like RTL8168H */ + { 0x7cf, 0x6c0, RTL_GIGA_MAC_VER_46 }, /* 8168G family. */ { 0x7cf, 0x5c8, RTL_GIGA_MAC_VER_44 }, @@ -2166,7 +2365,9 @@ static enum mac_version rtl8169_get_mac_version(u16 xid, bool gmii) /* 8168B family. */ { 0x7c8, 0x380, RTL_GIGA_MAC_VER_17 }, - { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 }, + /* This one is very old and rare, support has been removed. + * { 0x7c8, 0x300, RTL_GIGA_MAC_VER_11 }, + */ /* 8101 family. */ { 0x7c8, 0x448, RTL_GIGA_MAC_VER_39 }, @@ -2250,14 +2451,8 @@ static void rtl8125a_config_eee_mac(struct rtl8169_private *tp) r8168_mac_ocp_modify(tp, 0xeb62, 0, BIT(2) | BIT(1)); } -static void rtl8125_set_eee_txidle_timer(struct rtl8169_private *tp) -{ - RTL_W16(tp, EEE_TXIDLE_TIMER_8125, tp->dev->mtu + ETH_HLEN + 0x20); -} - static void rtl8125b_config_eee_mac(struct rtl8169_private *tp) { - rtl8125_set_eee_txidle_timer(tp); r8168_mac_ocp_modify(tp, 0xe040, 0, BIT(1) | BIT(0)); } @@ -2287,11 +2482,9 @@ u16 rtl8168h_2_get_adc_bias_ioffset(struct rtl8169_private *tp) static void rtl_schedule_task(struct rtl8169_private *tp, enum rtl_flag flag) { - if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) - return; - set_bit(flag, tp->wk.flags); - schedule_work(&tp->wk.work); + if (!schedule_work(&tp->wk.work)) + clear_bit(flag, tp->wk.flags); } static void rtl8169_init_phy(struct rtl8169_private *tp) @@ -2313,9 +2506,6 @@ static void rtl8169_init_phy(struct rtl8169_private *tp) /* We may have called phy_speed_down before */ phy_speed_up(tp->phydev); - if (rtl_supports_eee(tp)) - rtl_enable_eee(tp); - genphy_soft_reset(tp->phydev); } @@ -2367,7 +2557,7 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61: RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST); break; - case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST | RX_PAUSE_SLOT_ON); break; @@ -2382,86 +2572,31 @@ static void rtl8169_init_ring_indexes(struct rtl8169_private *tp) tp->dirty_tx = tp->cur_tx = tp->cur_rx = 0; } -static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | Jumbo_En1); -} - -static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~Jumbo_En1); -} - -static void r8168dp_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); -} - -static void r8168dp_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); -} - -static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, MaxTxPacketSize, 0x24); - RTL_W8(tp, Config3, RTL_R8(tp, Config3) | Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | 0x01); -} - -static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, MaxTxPacketSize, 0x3f); - RTL_W8(tp, Config3, RTL_R8(tp, Config3) & ~Jumbo_En0); - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~0x01); -} - -static void r8168b_1_hw_jumbo_enable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config4, RTL_R8(tp, Config4) | (1 << 0)); -} - -static void r8168b_1_hw_jumbo_disable(struct rtl8169_private *tp) -{ - RTL_W8(tp, Config4, RTL_R8(tp, Config4) & ~(1 << 0)); -} - static void rtl_jumbo_config(struct rtl8169_private *tp) { bool jumbo = tp->dev->mtu > ETH_DATA_LEN; int readrq = 4096; + if (jumbo && tp->mac_version >= RTL_GIGA_MAC_VER_17 && + tp->mac_version <= RTL_GIGA_MAC_VER_26) + readrq = 512; + rtl_unlock_config_regs(tp); switch (tp->mac_version) { case RTL_GIGA_MAC_VER_17: - if (jumbo) { - readrq = 512; - r8168b_1_hw_jumbo_enable(tp); - } else { - r8168b_1_hw_jumbo_disable(tp); - } + r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); break; case RTL_GIGA_MAC_VER_18 ... RTL_GIGA_MAC_VER_26: - if (jumbo) { - readrq = 512; - r8168c_hw_jumbo_enable(tp); - } else { - r8168c_hw_jumbo_disable(tp); - } + r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); + r8169_mod_reg8_cond(tp, Config4, Jumbo_En1, jumbo); break; case RTL_GIGA_MAC_VER_28: - if (jumbo) - r8168dp_hw_jumbo_enable(tp); - else - r8168dp_hw_jumbo_disable(tp); + r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); break; case RTL_GIGA_MAC_VER_31 ... RTL_GIGA_MAC_VER_33: - if (jumbo) - r8168e_hw_jumbo_enable(tp); - else - r8168e_hw_jumbo_disable(tp); + RTL_W8(tp, MaxTxPacketSize, jumbo ? 0x24 : 0x3f); + r8169_mod_reg8_cond(tp, Config3, Jumbo_En0, jumbo); + r8169_mod_reg8_cond(tp, Config4, BIT(0), jumbo); break; default: break; @@ -2554,7 +2689,7 @@ static void rtl_wait_txrx_fifo_empty(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_61: rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); break; - case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_63 ... RTL_GIGA_MAC_VER_71: RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond, 100, 42); rtl_loop_wait_high(tp, &rtl_rxtx_empty_cond_2, 100, 42); @@ -2797,7 +2932,7 @@ static void rtl_enable_exit_l1(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_37 ... RTL_GIGA_MAC_VER_38: rtl_eri_set_bits(tp, 0xd4, 0x0c00); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: r8168_mac_ocp_modify(tp, 0xc0ac, 0, 0x1f80); break; default: @@ -2811,7 +2946,7 @@ static void rtl_disable_exit_l1(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_34 ... RTL_GIGA_MAC_VER_38: rtl_eri_clear_bits(tp, 0xd4, 0x1f00); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: r8168_mac_ocp_modify(tp, 0xc0ac, 0x1f80, 0); break; default: @@ -2821,6 +2956,8 @@ static void rtl_disable_exit_l1(struct rtl8169_private *tp) static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) { + u8 val8; + if (tp->mac_version < RTL_GIGA_MAC_VER_32) return; @@ -2834,11 +2971,20 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) return; rtl_mod_config5(tp, 0, ASPM_en); - rtl_mod_config2(tp, 0, ClkReqEn); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_71: + val8 = RTL_R8(tp, INT_CFG0_8125) | INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; + default: + rtl_mod_config2(tp, 0, ClkReqEn); + break; + } switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: /* reset ephy tx/rx disable timer */ r8168_mac_ocp_modify(tp, 0xe094, 0xff00, 0); /* chip can trigger L1.2 */ @@ -2850,14 +2996,23 @@ static void rtl_hw_aspm_clkreq_enable(struct rtl8169_private *tp, bool enable) } else { switch (tp->mac_version) { case RTL_GIGA_MAC_VER_46 ... RTL_GIGA_MAC_VER_48: - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: r8168_mac_ocp_modify(tp, 0xe092, 0x00ff, 0); break; default: break; } - rtl_mod_config2(tp, ClkReqEn, 0); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_71: + val8 = RTL_R8(tp, INT_CFG0_8125) & ~INT_CFG0_CLKREQEN; + RTL_W8(tp, INT_CFG0_8125, val8); + break; + default: + rtl_mod_config2(tp, ClkReqEn, 0); + break; + } rtl_mod_config5(tp, ASPM_en, 0); } } @@ -3552,8 +3707,8 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) rtl_pcie_state_l2l3_disable(tp); RTL_W16(tp, 0x382, 0x221b); - RTL_W8(tp, 0x4500, 0); - RTL_W16(tp, 0x4800, 0); + RTL_W32(tp, RSS_CTRL_8125, 0); + RTL_W16(tp, Q_NUM_CTRL_8125, 0); /* disable UPS */ r8168_mac_ocp_modify(tp, 0xd40a, 0x0010, 0x0000); @@ -3570,10 +3725,17 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) /* disable new tx descriptor format */ r8168_mac_ocp_modify(tp, 0xeb58, 0x0001, 0x0000); - if (tp->mac_version == RTL_GIGA_MAC_VER_63) + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_71) + RTL_W8(tp, 0xD8, RTL_R8(tp, 0xD8) & ~0x02); + + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_71) + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); + else if (tp->mac_version == RTL_GIGA_MAC_VER_63) r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0200); else - r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0400); + r8168_mac_ocp_modify(tp, 0xe614, 0x0700, 0x0300); if (tp->mac_version == RTL_GIGA_MAC_VER_63) r8168_mac_ocp_modify(tp, 0xe63e, 0x0c30, 0x0000); @@ -3586,6 +3748,11 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) r8168_mac_ocp_modify(tp, 0xe056, 0x00f0, 0x0030); r8168_mac_ocp_modify(tp, 0xe040, 0x1000, 0x0000); r8168_mac_ocp_modify(tp, 0xea1c, 0x0003, 0x0001); + if (tp->mac_version == RTL_GIGA_MAC_VER_70 || + tp->mac_version == RTL_GIGA_MAC_VER_71) + r8168_mac_ocp_modify(tp, 0xea1c, 0x0300, 0x0000); + else + r8168_mac_ocp_modify(tp, 0xea1c, 0x0004, 0x0000); r8168_mac_ocp_modify(tp, 0xe0c0, 0x4f0f, 0x4403); r8168_mac_ocp_modify(tp, 0xe052, 0x0080, 0x0068); r8168_mac_ocp_modify(tp, 0xd430, 0x0fff, 0x047f); @@ -3600,10 +3767,10 @@ static void rtl_hw_start_8125_common(struct rtl8169_private *tp) rtl_loop_wait_low(tp, &rtl_mac_ocp_e00e_cond, 1000, 10); - if (tp->mac_version == RTL_GIGA_MAC_VER_63) - rtl8125b_config_eee_mac(tp); - else + if (tp->mac_version == RTL_GIGA_MAC_VER_61) rtl8125a_config_eee_mac(tp); + else + rtl8125b_config_eee_mac(tp); rtl_disable_rxdvgate(tp); } @@ -3647,6 +3814,18 @@ static void rtl_hw_start_8125b(struct rtl8169_private *tp) rtl_hw_start_8125_common(tp); } +static void rtl_hw_start_8125d(struct rtl8169_private *tp) +{ + rtl_set_def_aspm_entry_latency(tp); + rtl_hw_start_8125_common(tp); +} + +static void rtl_hw_start_8126a(struct rtl8169_private *tp) +{ + rtl_set_def_aspm_entry_latency(tp); + rtl_hw_start_8125_common(tp); +} + static void rtl_hw_config(struct rtl8169_private *tp) { static const rtl_generic_fct hw_configs[] = { @@ -3654,7 +3833,6 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_08] = rtl_hw_start_8102e_3, [RTL_GIGA_MAC_VER_09] = rtl_hw_start_8102e_2, [RTL_GIGA_MAC_VER_10] = NULL, - [RTL_GIGA_MAC_VER_11] = rtl_hw_start_8168b, [RTL_GIGA_MAC_VER_14] = rtl_hw_start_8401, [RTL_GIGA_MAC_VER_17] = rtl_hw_start_8168b, [RTL_GIGA_MAC_VER_18] = rtl_hw_start_8168cp_1, @@ -3689,6 +3867,11 @@ static void rtl_hw_config(struct rtl8169_private *tp) [RTL_GIGA_MAC_VER_53] = rtl_hw_start_8117, [RTL_GIGA_MAC_VER_61] = rtl_hw_start_8125a_2, [RTL_GIGA_MAC_VER_63] = rtl_hw_start_8125b, + [RTL_GIGA_MAC_VER_64] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_65] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_66] = rtl_hw_start_8125d, + [RTL_GIGA_MAC_VER_70] = rtl_hw_start_8126a, + [RTL_GIGA_MAC_VER_71] = rtl_hw_start_8126a, }; if (hw_configs[tp->mac_version]) @@ -3699,9 +3882,30 @@ static void rtl_hw_start_8125(struct rtl8169_private *tp) { int i; + RTL_W8(tp, INT_CFG0_8125, 0x00); + /* disable interrupt coalescing */ - for (i = 0xa00; i < 0xb00; i += 4) - RTL_W32(tp, i, 0); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_61: + case RTL_GIGA_MAC_VER_64: + case RTL_GIGA_MAC_VER_65: + case RTL_GIGA_MAC_VER_66: + for (i = 0xa00; i < 0xb00; i += 4) + RTL_W32(tp, i, 0); + break; + case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_70: + case RTL_GIGA_MAC_VER_71: + for (i = 0xa00; i < 0xa80; i += 4) + RTL_W32(tp, i, 0); + RTL_W16(tp, INT_CFG1_8125, 0x0000); + break; + default: + break; + } + + /* enable extended tally counter */ + r8168_mac_ocp_modify(tp, 0xea84, 0, BIT(1) | BIT(0)); rtl_hw_config(tp); } @@ -3744,6 +3948,8 @@ static void rtl_hw_start(struct rtl8169_private *tp) rtl_hw_aspm_clkreq_enable(tp, false); RTL_W16(tp, CPlusCmd, tp->cp_cmd); + rtl_set_eee_txidle_timer(tp); + if (tp->mac_version <= RTL_GIGA_MAC_VER_06) rtl_hw_start_8169(tp); else if (rtl_is_8125(tp)) @@ -3774,18 +3980,10 @@ static int rtl8169_change_mtu(struct net_device *dev, int new_mtu) { struct rtl8169_private *tp = netdev_priv(dev); - dev->mtu = new_mtu; + WRITE_ONCE(dev->mtu, new_mtu); netdev_update_features(dev); rtl_jumbo_config(tp); - - switch (tp->mac_version) { - case RTL_GIGA_MAC_VER_61: - case RTL_GIGA_MAC_VER_63: - rtl8125_set_eee_txidle_timer(tp); - break; - default: - break; - } + rtl_set_eee_txidle_timer(tp); return 0; } @@ -3929,7 +4127,7 @@ static void rtl8169_cleanup(struct rtl8169_private *tp) RTL_W8(tp, ChipCmd, RTL_R8(tp, ChipCmd) | StopReq); rtl_loop_wait_high(tp, &rtl_txcfg_empty_cond, 100, 666); break; - case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_71: rtl_enable_rxdvgate(tp); fsleep(2000); break; @@ -4049,8 +4247,8 @@ static unsigned int rtl8125_quirk_udp_padto(struct rtl8169_private *tp, { unsigned int padto = 0, len = skb->len; - if (rtl_is_8125(tp) && len < 128 + RTL_MIN_PATCH_LEN && - rtl_skb_is_udp(skb) && skb_transport_header_was_set(skb)) { + if (len < 128 + RTL_MIN_PATCH_LEN && rtl_skb_is_udp(skb) && + skb_transport_header_was_set(skb)) { unsigned int trans_data_len = skb_tail_pointer(skb) - skb_transport_header(skb); @@ -4074,14 +4272,19 @@ static unsigned int rtl8125_quirk_udp_padto(struct rtl8169_private *tp, static unsigned int rtl_quirk_packet_padto(struct rtl8169_private *tp, struct sk_buff *skb) { - unsigned int padto; + unsigned int padto = 0; - padto = rtl8125_quirk_udp_padto(tp, skb); + switch (tp->mac_version) { + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: + padto = rtl8125_quirk_udp_padto(tp, skb); + break; + default: + break; + } switch (tp->mac_version) { case RTL_GIGA_MAC_VER_34: - case RTL_GIGA_MAC_VER_61: - case RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: padto = max_t(unsigned int, padto, ETH_ZLEN); break; default: @@ -4196,17 +4399,18 @@ static void rtl8169_doorbell(struct rtl8169_private *tp) static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev) { - unsigned int frags = skb_shinfo(skb)->nr_frags; struct rtl8169_private *tp = netdev_priv(dev); unsigned int entry = tp->cur_tx % NUM_TX_DESC; struct TxDesc *txd_first, *txd_last; bool stop_queue, door_bell; + unsigned int frags; u32 opts[2]; if (unlikely(!rtl_tx_slots_avail(tp))) { if (net_ratelimit()) netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); - goto err_stop_0; + netif_stop_queue(dev); + return NETDEV_TX_BUSY; } opts[1] = rtl8169_tx_vlan_tag(skb); @@ -4223,6 +4427,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb, txd_first = tp->TxDescArray + entry; + frags = skb_shinfo(skb)->nr_frags; if (frags) { if (rtl8169_xmit_frags(tp, skb, opts, entry)) goto err_dma_1; @@ -4261,11 +4466,6 @@ err_dma_0: dev_kfree_skb_any(skb); dev->stats.tx_dropped++; return NETDEV_TX_OK; - -err_stop_0: - netif_stop_queue(dev); - dev->stats.tx_dropped++; - return NETDEV_TX_BUSY; } static unsigned int rtl_last_frag_len(struct sk_buff *skb) @@ -4502,7 +4702,9 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) if ((status & 0xffff) == 0xffff || !(status & tp->irq_mask)) return IRQ_NONE; - if (unlikely(status & SYSErr)) { + /* At least RTL8168fp may unexpectedly set the SYSErr bit */ + if (unlikely(status & SYSErr && + tp->mac_version <= RTL_GIGA_MAC_VER_06)) { rtl8169_pcierr_interrupt(tp->dev); goto out; } @@ -4510,16 +4712,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) if (status & LinkChg) phy_mac_interrupt(tp->phydev); - if (unlikely(status & RxFIFOOver && - tp->mac_version == RTL_GIGA_MAC_VER_11)) { - netif_stop_queue(tp->dev); - rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_PENDING); - } - - if (napi_schedule_prep(&tp->napi)) { - rtl_irq_disable(tp); - __napi_schedule(&tp->napi); - } + rtl_irq_disable(tp); + napi_schedule(&tp->napi); out: rtl_ack_events(tp, status); @@ -4532,11 +4726,6 @@ static void rtl_task(struct work_struct *work) container_of(work, struct rtl8169_private, wk.work); int ret; - rtnl_lock(); - - if (!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags)) - goto out_unlock; - if (test_and_clear_bit(RTL_FLAG_TASK_TX_TIMEOUT, tp->wk.flags)) { /* if chip isn't accessible, reset bus to revive it */ if (RTL_R32(tp, TxConfig) == ~0) { @@ -4544,7 +4733,7 @@ static void rtl_task(struct work_struct *work) if (ret < 0) { netdev_err(tp->dev, "Can't reset secondary PCI bus, detach NIC\n"); netif_device_detach(tp->dev); - goto out_unlock; + return; } } @@ -4560,11 +4749,7 @@ static void rtl_task(struct work_struct *work) reset: rtl_reset_work(tp); netif_wake_queue(tp->dev); - } else if (test_and_clear_bit(RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE, tp->wk.flags)) { - rtl_reset_work(tp); } -out_unlock: - rtnl_unlock(); } static int rtl8169_poll(struct napi_struct *napi, int budget) @@ -4591,11 +4776,7 @@ static void r8169_phylink_handler(struct net_device *ndev) if (netif_carrier_ok(ndev)) { rtl_link_chg_patch(tp); pm_request_resume(d); - netif_wake_queue(tp->dev); } else { - /* In few cases rx is broken after link-down otherwise */ - if (rtl_is_8125(tp)) - rtl_schedule_task(tp, RTL_FLAG_TASK_RESET_NO_QUEUE_WAKE); pm_runtime_idle(d); } @@ -4626,6 +4807,7 @@ static int r8169_phy_connect(struct rtl8169_private *tp) static void rtl8169_down(struct rtl8169_private *tp) { + disable_work_sync(&tp->wk.work); /* Clear all task flags */ bitmap_zero(tp->wk.flags, RTL_FLAG_MAX); @@ -4654,7 +4836,7 @@ static void rtl8169_up(struct rtl8169_private *tp) phy_resume(tp->phydev); rtl8169_init_phy(tp); napi_enable(&tp->napi); - set_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags); + enable_work(&tp->wk.work); rtl_reset_work(tp); phy_start(tp->phydev); @@ -4671,8 +4853,6 @@ static int rtl8169_close(struct net_device *dev) rtl8169_down(tp); rtl8169_rx_clear(tp); - cancel_work(&tp->wk.work); - free_irq(tp->irq, tp); phy_disconnect(tp->phydev); @@ -4905,7 +5085,10 @@ static void rtl_remove_one(struct pci_dev *pdev) if (pci_dev_run_wake(pdev)) pm_runtime_get_noresume(&pdev->dev); - cancel_work_sync(&tp->wk.work); + disable_work_sync(&tp->wk.work); + + if (IS_ENABLED(CONFIG_R8169_LEDS)) + r8169_remove_leds(tp->leds); unregister_netdev(tp->dev); @@ -4943,12 +5126,7 @@ static void rtl_set_irq_mask(struct rtl8169_private *tp) tp->irq_mask = RxOK | RxErr | TxOK | TxErr | LinkChg; if (tp->mac_version <= RTL_GIGA_MAC_VER_06) - tp->irq_mask |= SYSErr | RxOverflow | RxFIFOOver; - else if (tp->mac_version == RTL_GIGA_MAC_VER_11) - /* special workaround needed */ - tp->irq_mask |= RxFIFOOver; - else - tp->irq_mask |= RxOverflow; + tp->irq_mask |= SYSErr | RxFIFOOver; } static int rtl_alloc_irq(struct rtl8169_private *tp) @@ -4962,7 +5140,7 @@ static int rtl_alloc_irq(struct rtl8169_private *tp) rtl_lock_config_regs(tp); fallthrough; case RTL_GIGA_MAC_VER_07 ... RTL_GIGA_MAC_VER_17: - flags = PCI_IRQ_LEGACY; + flags = PCI_IRQ_INTX; break; default: flags = PCI_IRQ_ALL_TYPES; @@ -5027,6 +5205,15 @@ static int r8169_mdio_register(struct rtl8169_private *tp) struct mii_bus *new_bus; int ret; + /* 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 + * accessing registers on a different page, returning a more or + * less random value. Fix this by resetting the page selector first. + */ + if (tp->mac_version == RTL_GIGA_MAC_VER_25 || + tp->mac_version == RTL_GIGA_MAC_VER_26) + r8169_mdio_write(tp, 0x1f, 0); + new_bus = devm_mdiobus_alloc(&pdev->dev); if (!new_bus) return -ENOMEM; @@ -5058,9 +5245,16 @@ static int r8169_mdio_register(struct rtl8169_private *tp) } tp->phydev->mac_managed_pm = true; - + if (rtl_supports_eee(tp)) + phy_support_eee(tp->phydev); phy_support_asym_pause(tp->phydev); + /* mimic behavior of r8125/r8126 vendor drivers */ + if (tp->mac_version == RTL_GIGA_MAC_VER_61) + phy_set_eee_broken(tp->phydev, + ETHTOOL_LINK_MODE_2500baseT_Full_BIT); + phy_set_eee_broken(tp->phydev, ETHTOOL_LINK_MODE_5000baseT_Full_BIT); + /* PHY will be woken up in rtl_open() */ phy_suspend(tp->phydev); @@ -5108,7 +5302,7 @@ static void rtl_hw_initialize(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_48: rtl_hw_init_8168g(tp); break; - case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63: + case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_71: rtl_hw_init_8125(tp); break; default: @@ -5127,7 +5321,6 @@ static int rtl_jumbo_max(struct rtl8169_private *tp) case RTL_GIGA_MAC_VER_02 ... RTL_GIGA_MAC_VER_06: return JUMBO_7K; /* RTL8168b */ - case RTL_GIGA_MAC_VER_11: case RTL_GIGA_MAC_VER_17: return JUMBO_4K; /* RTL8168c */ @@ -5193,19 +5386,11 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->dev = dev; tp->pci_dev = pdev; tp->supports_gmii = ent->driver_data == RTL_CFG_NO_GBIT ? 0 : 1; - tp->eee_adv = -1; tp->ocp_base = OCP_STD_PHY_BASE; - raw_spin_lock_init(&tp->cfg9346_usage_lock); - raw_spin_lock_init(&tp->config25_lock); raw_spin_lock_init(&tp->mac_ocp_lock); mutex_init(&tp->led_lock); - dev->tstats = devm_netdev_alloc_pcpu_stats(&pdev->dev, - struct pcpu_sw_netstats); - if (!dev->tstats) - return -ENOMEM; - /* Get the *optional* external "ether_clk" used on some boards */ tp->clk = devm_clk_get_optional_enabled(&pdev->dev, "ether_clk"); if (IS_ERR(tp->clk)) @@ -5277,6 +5462,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->irq = pci_irq_vector(pdev, 0); INIT_WORK(&tp->wk.work, rtl_task); + disable_work(&tp->wk.work); rtl_init_mac_address(tp); @@ -5302,11 +5488,6 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->features |= dev->hw_features; - /* There has been a number of reports that using SG/TSO results in - * tx timeouts. However for a lot of people SG/TSO works fine. - * Therefore disable both features by default, but allow users to - * enable them. Use at own risk! - */ if (rtl_chip_supports_csum_v2(tp)) { dev->hw_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_TSO6; netif_set_tso_max_size(dev, RTL_GSO_MAX_SIZE_V2); @@ -5317,9 +5498,22 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) netif_set_tso_max_segs(dev, RTL_GSO_MAX_SEGS_V1); } + /* There has been a number of reports that using SG/TSO results in + * tx timeouts. However for a lot of people SG/TSO works fine. + * It's not fully clear which chip versions are affected. Vendor + * drivers enable SG/TSO for certain chip versions per default, + * let's mimic this here. On other chip versions users can + * use ethtool to enable SG/TSO, use at own risk! + */ + if (tp->mac_version >= RTL_GIGA_MAC_VER_46 && + tp->mac_version != RTL_GIGA_MAC_VER_61) + dev->features |= dev->hw_features; + dev->hw_features |= NETIF_F_RXALL; dev->hw_features |= NETIF_F_RXFCS; + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; + netdev_sw_irq_coalesce_default_on(dev); /* configure chip for default features */ @@ -5329,7 +5523,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) rtl_set_d3_pll_down(tp, true); } else { rtl_set_d3_pll_down(tp, false); - dev->wol_enabled = 1; + dev->ethtool->wol_enabled = 1; } jumbo_max = rtl_jumbo_max(tp); @@ -5356,10 +5550,12 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) if (rc) return rc; - if (IS_ENABLED(CONFIG_R8169_LEDS) && - tp->mac_version > RTL_GIGA_MAC_VER_06 && - tp->mac_version < RTL_GIGA_MAC_VER_61) - rtl8168_init_leds(dev); + if (IS_ENABLED(CONFIG_R8169_LEDS)) { + if (rtl_is_8125(tp)) + tp->leds = rtl8125_init_leds(dev); + else if (tp->mac_version > RTL_GIGA_MAC_VER_06) + tp->leds = rtl8168_init_leds(dev); + } netdev_info(dev, "%s, %pM, XID %03x, IRQ %d\n", rtl_chip_infos[chipset].name, dev->dev_addr, xid, tp->irq); diff --git a/drivers/net/ethernet/realtek/r8169_phy_config.c b/drivers/net/ethernet/realtek/r8169_phy_config.c index b50f16786c24..cf95e579c65d 100644 --- a/drivers/net/ethernet/realtek/r8169_phy_config.c +++ b/drivers/net/ethernet/realtek/r8169_phy_config.c @@ -89,20 +89,17 @@ static void rtl8168h_config_eee_phy(struct phy_device *phydev) phy_modify_paged(phydev, 0xa42, 0x14, 0x0000, 0x0080); } -static void rtl8125a_config_eee_phy(struct phy_device *phydev) +static void rtl8125_common_config_eee_phy(struct phy_device *phydev) { - rtl8168h_config_eee_phy(phydev); - - phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); + phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); + phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); } -static void rtl8125b_config_eee_phy(struct phy_device *phydev) +static void rtl8125_config_eee_phy(struct phy_device *phydev) { - phy_modify_paged(phydev, 0xa6d, 0x12, 0x0001, 0x0000); - phy_modify_paged(phydev, 0xa6d, 0x14, 0x0010, 0x0000); - phy_modify_paged(phydev, 0xa42, 0x14, 0x0080, 0x0000); - phy_modify_paged(phydev, 0xa4a, 0x11, 0x0200, 0x0000); + rtl8168g_config_eee_phy(phydev); + rtl8125_common_config_eee_phy(phydev); } static void rtl8169s_hw_phy_config(struct rtl8169_private *tp, @@ -279,15 +276,6 @@ static void rtl8169sce_hw_phy_config(struct rtl8169_private *tp, rtl_writephy_batch(phydev, phy_reg_init); } -static void rtl8168bb_hw_phy_config(struct rtl8169_private *tp, - struct phy_device *phydev) -{ - phy_write(phydev, 0x1f, 0x0001); - phy_set_bits(phydev, 0x16, BIT(0)); - phy_write(phydev, 0x10, 0xf41b); - phy_write(phydev, 0x1f, 0x0000); -} - static void rtl8168bef_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev) { @@ -1060,15 +1048,16 @@ static void rtl8125a_2_hw_phy_config(struct rtl8169_private *tp, phy_modify_paged(phydev, 0xa86, 0x15, 0x0001, 0x0000); rtl8168g_enable_gphy_10m(phydev); - rtl8125a_config_eee_phy(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_config_eee_phy(phydev); } static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev) { r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); - phy_modify_paged(phydev, 0xa44, 0x11, 0x0000, 0x0800); phy_modify_paged(phydev, 0xac4, 0x13, 0x00f0, 0x0090); phy_modify_paged(phydev, 0xad3, 0x10, 0x0003, 0x0001); @@ -1099,7 +1088,50 @@ static void rtl8125b_hw_phy_config(struct rtl8169_private *tp, phy_modify_paged(phydev, 0xbf8, 0x12, 0xe000, 0xa000); rtl8125_legacy_force_mode(phydev); - rtl8125b_config_eee_phy(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_config_eee_phy(phydev); +} + +static void rtl8125d_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) +{ + r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_config_eee_phy(phydev); +} + +static void rtl8125bp_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) +{ + r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); + + r8168g_phy_param(phydev, 0x8010, 0x0800, 0x0000); + + phy_write(phydev, 0x1f, 0x0b87); + phy_write(phydev, 0x16, 0x8088); + phy_modify(phydev, 0x17, 0xff00, 0x9000); + phy_write(phydev, 0x16, 0x808f); + phy_modify(phydev, 0x17, 0xff00, 0x9000); + phy_write(phydev, 0x1f, 0x0000); + + r8168g_phy_param(phydev, 0x8174, 0x2000, 0x1800); + + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_config_eee_phy(phydev); +} + +static void rtl8126a_hw_phy_config(struct rtl8169_private *tp, + struct phy_device *phydev) +{ + r8169_apply_firmware(tp); + rtl8168g_enable_gphy_10m(phydev); + rtl8125_legacy_force_mode(phydev); + rtl8168g_disable_aldps(phydev); + rtl8125_common_config_eee_phy(phydev); } void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, @@ -1117,7 +1149,6 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_08] = rtl8102e_hw_phy_config, [RTL_GIGA_MAC_VER_09] = rtl8102e_hw_phy_config, [RTL_GIGA_MAC_VER_10] = NULL, - [RTL_GIGA_MAC_VER_11] = rtl8168bb_hw_phy_config, [RTL_GIGA_MAC_VER_14] = rtl8401_hw_phy_config, [RTL_GIGA_MAC_VER_17] = rtl8168bef_hw_phy_config, [RTL_GIGA_MAC_VER_18] = rtl8168cp_1_hw_phy_config, @@ -1152,6 +1183,11 @@ void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev, [RTL_GIGA_MAC_VER_53] = rtl8117_hw_phy_config, [RTL_GIGA_MAC_VER_61] = rtl8125a_2_hw_phy_config, [RTL_GIGA_MAC_VER_63] = rtl8125b_hw_phy_config, + [RTL_GIGA_MAC_VER_64] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_65] = rtl8125d_hw_phy_config, + [RTL_GIGA_MAC_VER_66] = rtl8125bp_hw_phy_config, + [RTL_GIGA_MAC_VER_70] = rtl8126a_hw_phy_config, + [RTL_GIGA_MAC_VER_71] = rtl8126a_hw_phy_config, }; if (phy_configs[ver]) diff --git a/drivers/net/ethernet/realtek/rtase/Makefile b/drivers/net/ethernet/realtek/rtase/Makefile new file mode 100644 index 000000000000..ba3d8550f9e6 --- /dev/null +++ b/drivers/net/ethernet/realtek/rtase/Makefile @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +# Copyright(c) 2024 Realtek Semiconductor Corp. All rights reserved. + +# +# Makefile for the Realtek PCIe driver +# + +obj-$(CONFIG_RTASE) += rtase.o + +rtase-objs := rtase_main.o diff --git a/drivers/net/ethernet/realtek/rtase/rtase.h b/drivers/net/ethernet/realtek/rtase/rtase.h new file mode 100644 index 000000000000..2bbfcad613ab --- /dev/null +++ b/drivers/net/ethernet/realtek/rtase/rtase.h @@ -0,0 +1,346 @@ +/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */ +/* + * rtase is the Linux device driver released for Realtek Automotive Switch + * controllers with PCI-Express interface. + * + * Copyright(c) 2024 Realtek Semiconductor Corp. + */ + +#ifndef RTASE_H +#define RTASE_H + +#define RTASE_HW_VER_MASK 0x7C800000 +#define RTASE_HW_VER_906X_7XA 0x00800000 +#define RTASE_HW_VER_906X_7XC 0x04000000 +#define RTASE_HW_VER_907XD_V1 0x04800000 +#define RTASE_HW_VER_907XD_VA 0x08000000 + +#define RTASE_RX_DMA_BURST_256 4 +#define RTASE_TX_DMA_BURST_UNLIMITED 7 + +#define RTASE_RX_BUF_SIZE (PAGE_SIZE - \ + SKB_DATA_ALIGN(sizeof(struct skb_shared_info))) +#define RTASE_MAX_JUMBO_SIZE (RTASE_RX_BUF_SIZE - VLAN_ETH_HLEN - ETH_FCS_LEN) + +/* 3 means InterFrameGap = the shortest one */ +#define RTASE_INTERFRAMEGAP 0x03 + +#define RTASE_REGS_SIZE 256 +#define RTASE_PCI_REGS_SIZE 0x100 + +#define RTASE_MULTICAST_FILTER_MASK GENMASK(30, 26) + +#define RTASE_VLAN_FILTER_ENTRY_NUM 32 +#define RTASE_NUM_TX_QUEUE 8 +#define RTASE_NUM_RX_QUEUE 4 + +#define RTASE_TXQ_CTRL 1 +#define RTASE_FUNC_TXQ_NUM 1 +#define RTASE_FUNC_RXQ_NUM 1 +#define RTASE_INTERRUPT_NUM 1 + +#define RTASE_MITI_TIME_COUNT_MASK GENMASK(3, 0) +#define RTASE_MITI_TIME_UNIT_MASK GENMASK(7, 4) +#define RTASE_MITI_DEFAULT_TIME 128 +#define RTASE_MITI_MAX_TIME 491520 +#define RTASE_MITI_PKT_NUM_COUNT_MASK GENMASK(11, 8) +#define RTASE_MITI_PKT_NUM_UNIT_MASK GENMASK(13, 12) +#define RTASE_MITI_DEFAULT_PKT_NUM 64 +#define RTASE_MITI_MAX_PKT_NUM_IDX 3 +#define RTASE_MITI_MAX_PKT_NUM_UNIT 16 +#define RTASE_MITI_MAX_PKT_NUM 240 +#define RTASE_MITI_COUNT_BIT_NUM 4 + +#define RTASE_NUM_MSIX 4 + +#define RTASE_DWORD_MOD 16 + +/*****************************************************************************/ +enum rtase_registers { + RTASE_MAC0 = 0x0000, + RTASE_MAC4 = 0x0004, + RTASE_MAR0 = 0x0008, + RTASE_MAR1 = 0x000C, + RTASE_DTCCR0 = 0x0010, + RTASE_DTCCR4 = 0x0014, +#define RTASE_COUNTER_RESET BIT(0) +#define RTASE_COUNTER_DUMP BIT(3) + + RTASE_FCR = 0x0018, +#define RTASE_FCR_RXQ_MASK GENMASK(5, 4) + + RTASE_LBK_CTRL = 0x001A, +#define RTASE_LBK_ATLD BIT(1) +#define RTASE_LBK_CLR BIT(0) + + RTASE_TX_DESC_ADDR0 = 0x0020, + RTASE_TX_DESC_ADDR4 = 0x0024, + RTASE_TX_DESC_COMMAND = 0x0028, +#define RTASE_TX_DESC_CMD_CS BIT(15) +#define RTASE_TX_DESC_CMD_WE BIT(14) + + RTASE_BOOT_CTL = 0x6004, + RTASE_CLKSW_SET = 0x6018, + + RTASE_CHIP_CMD = 0x0037, +#define RTASE_STOP_REQ BIT(7) +#define RTASE_STOP_REQ_DONE BIT(6) +#define RTASE_RE BIT(3) +#define RTASE_TE BIT(2) + + RTASE_IMR0 = 0x0038, + RTASE_ISR0 = 0x003C, +#define RTASE_TOK7 BIT(30) +#define RTASE_TOK6 BIT(28) +#define RTASE_TOK5 BIT(26) +#define RTASE_TOK4 BIT(24) +#define RTASE_FOVW BIT(6) +#define RTASE_RDU BIT(4) +#define RTASE_TOK BIT(2) +#define RTASE_ROK BIT(0) + + RTASE_IMR1 = 0x0800, + RTASE_ISR1 = 0x0802, +#define RTASE_Q_TOK BIT(4) +#define RTASE_Q_RDU BIT(1) +#define RTASE_Q_ROK BIT(0) + + RTASE_EPHY_ISR = 0x6014, + RTASE_EPHY_IMR = 0x6016, + + RTASE_TX_CONFIG_0 = 0x0040, +#define RTASE_TX_INTER_FRAME_GAP_MASK GENMASK(25, 24) + /* DMA burst value (0-7) is shift this many bits */ +#define RTASE_TX_DMA_MASK GENMASK(10, 8) + + RTASE_RX_CONFIG_0 = 0x0044, +#define RTASE_RX_SINGLE_FETCH BIT(14) +#define RTASE_RX_SINGLE_TAG BIT(13) +#define RTASE_RX_MX_DMA_MASK GENMASK(10, 8) +#define RTASE_ACPT_FLOW BIT(7) +#define RTASE_ACCEPT_ERR BIT(5) +#define RTASE_ACCEPT_RUNT BIT(4) +#define RTASE_ACCEPT_BROADCAST BIT(3) +#define RTASE_ACCEPT_MULTICAST BIT(2) +#define RTASE_ACCEPT_MYPHYS BIT(1) +#define RTASE_ACCEPT_ALLPHYS BIT(0) +#define RTASE_ACCEPT_MASK (RTASE_ACPT_FLOW | RTASE_ACCEPT_ERR | \ + RTASE_ACCEPT_RUNT | RTASE_ACCEPT_BROADCAST | \ + RTASE_ACCEPT_MULTICAST | RTASE_ACCEPT_MYPHYS | \ + RTASE_ACCEPT_ALLPHYS) + + RTASE_RX_CONFIG_1 = 0x0046, +#define RTASE_RX_MAX_FETCH_DESC_MASK GENMASK(15, 11) +#define RTASE_RX_NEW_DESC_FORMAT_EN BIT(8) +#define RTASE_OUTER_VLAN_DETAG_EN BIT(7) +#define RTASE_INNER_VLAN_DETAG_EN BIT(6) +#define RTASE_PCIE_NEW_FLOW BIT(2) +#define RTASE_PCIE_RELOAD_EN BIT(0) + + RTASE_EEM = 0x0050, +#define RTASE_EEM_UNLOCK 0xC0 + + RTASE_TDFNR = 0x0057, + RTASE_TPPOLL = 0x0090, + RTASE_PDR = 0x00B0, + RTASE_FIFOR = 0x00D3, +#define RTASE_TX_FIFO_EMPTY BIT(5) +#define RTASE_RX_FIFO_EMPTY BIT(4) + + RTASE_RMS = 0x00DA, + RTASE_CPLUS_CMD = 0x00E0, +#define RTASE_FORCE_RXFLOW_EN BIT(11) +#define RTASE_FORCE_TXFLOW_EN BIT(10) +#define RTASE_RX_CHKSUM BIT(5) + + RTASE_Q0_RX_DESC_ADDR0 = 0x00E4, + RTASE_Q0_RX_DESC_ADDR4 = 0x00E8, + RTASE_Q1_RX_DESC_ADDR0 = 0x4000, + RTASE_Q1_RX_DESC_ADDR4 = 0x4004, + RTASE_MTPS = 0x00EC, +#define RTASE_TAG_NUM_SEL_MASK GENMASK(10, 8) + + RTASE_MISC = 0x00F2, +#define RTASE_RX_DV_GATE_EN BIT(3) + + RTASE_TFUN_CTRL = 0x0400, +#define RTASE_TX_NEW_DESC_FORMAT_EN BIT(0) + + RTASE_TX_CONFIG_1 = 0x203E, +#define RTASE_TC_MODE_MASK GENMASK(11, 10) + + RTASE_TOKSEL = 0x2046, + RTASE_RFIFONFULL = 0x4406, + RTASE_INT_MITI_TX = 0x0A00, + RTASE_INT_MITI_RX = 0x0A80, + + RTASE_VLAN_ENTRY_0 = 0xAC80, +}; + +enum rtase_desc_status_bit { + RTASE_DESC_OWN = BIT(31), /* Descriptor is owned by NIC */ + RTASE_RING_END = BIT(30), /* End of descriptor ring */ +}; + +enum rtase_sw_flag_content { + RTASE_SWF_MSI_ENABLED = BIT(1), + RTASE_SWF_MSIX_ENABLED = BIT(2), +}; + +#define RSVD_MASK 0x3FFFC000 + +struct rtase_tx_desc { + __le32 opts1; + __le32 opts2; + __le64 addr; + __le32 opts3; + __le32 reserved1; + __le32 reserved2; + __le32 reserved3; +} __packed; + +/*------ offset 0 of tx descriptor ------*/ +#define RTASE_TX_FIRST_FRAG BIT(29) /* Tx First segment of a packet */ +#define RTASE_TX_LAST_FRAG BIT(28) /* Tx Final segment of a packet */ +#define RTASE_GIANT_SEND_V4 BIT(26) /* TCP Giant Send Offload V4 (GSOv4) */ +#define RTASE_GIANT_SEND_V6 BIT(25) /* TCP Giant Send Offload V6 (GSOv6) */ +#define RTASE_TX_VLAN_TAG BIT(17) /* Add VLAN tag */ + +/*------ offset 4 of tx descriptor ------*/ +#define RTASE_TX_UDPCS_C BIT(31) /* Calculate UDP/IP checksum */ +#define RTASE_TX_TCPCS_C BIT(30) /* Calculate TCP/IP checksum */ +#define RTASE_TX_IPCS_C BIT(29) /* Calculate IP checksum */ +#define RTASE_TX_IPV6F_C BIT(28) /* Indicate it is an IPv6 packet */ + +union rtase_rx_desc { + struct { + __le64 header_buf_addr; + __le32 reserved1; + __le32 opts_header_len; + __le64 addr; + __le32 reserved2; + __le32 opts1; + } __packed desc_cmd; + + struct { + __le32 reserved1; + __le32 reserved2; + __le32 rss; + __le32 opts4; + __le32 reserved3; + __le32 opts3; + __le32 opts2; + __le32 opts1; + } __packed desc_status; +} __packed; + +/*------ offset 28 of rx descriptor ------*/ +#define RTASE_RX_FIRST_FRAG BIT(25) /* Rx First segment of a packet */ +#define RTASE_RX_LAST_FRAG BIT(24) /* Rx Final segment of a packet */ +#define RTASE_RX_RES BIT(20) +#define RTASE_RX_RUNT BIT(19) +#define RTASE_RX_RWT BIT(18) +#define RTASE_RX_CRC BIT(16) +#define RTASE_RX_V6F BIT(31) +#define RTASE_RX_V4F BIT(30) +#define RTASE_RX_UDPT BIT(29) +#define RTASE_RX_TCPT BIT(28) +#define RTASE_RX_IPF BIT(26) /* IP checksum failed */ +#define RTASE_RX_UDPF BIT(25) /* UDP/IP checksum failed */ +#define RTASE_RX_TCPF BIT(24) /* TCP/IP checksum failed */ +#define RTASE_RX_VLAN_TAG BIT(16) /* VLAN tag available */ + +#define RTASE_NUM_DESC 1024 +#define RTASE_TX_BUDGET_DEFAULT 256 +#define RTASE_TX_RING_DESC_SIZE (RTASE_NUM_DESC * sizeof(struct rtase_tx_desc)) +#define RTASE_RX_RING_DESC_SIZE (RTASE_NUM_DESC * sizeof(union rtase_rx_desc)) +#define RTASE_TX_STOP_THRS (MAX_SKB_FRAGS + 1) +#define RTASE_TX_START_THRS (2 * RTASE_TX_STOP_THRS) +#define RTASE_VLAN_TAG_MASK GENMASK(15, 0) +#define RTASE_RX_PKT_SIZE_MASK GENMASK(13, 0) + +#define RTASE_IVEC_NAME_SIZE (IFNAMSIZ + 10) + +struct rtase_int_vector { + struct rtase_private *tp; + unsigned int irq; + char name[RTASE_IVEC_NAME_SIZE]; + u16 index; + u16 imr_addr; + u16 isr_addr; + u32 imr; + struct list_head ring_list; + struct napi_struct napi; + int (*poll)(struct napi_struct *napi, int budget); +}; + +struct rtase_ring { + struct rtase_int_vector *ivec; + void *desc; + dma_addr_t phy_addr; + u32 cur_idx; + u32 dirty_idx; + u16 index; + + struct sk_buff *skbuff[RTASE_NUM_DESC]; + void *data_buf[RTASE_NUM_DESC]; + union { + u32 len[RTASE_NUM_DESC]; + dma_addr_t data_phy_addr[RTASE_NUM_DESC]; + } mis; + + struct list_head ring_entry; + int (*ring_handler)(struct rtase_ring *ring, int budget); + u64 alloc_fail; +}; + +struct rtase_stats { + u64 tx_dropped; + u64 rx_dropped; + u64 multicast; + u64 rx_errors; + u64 rx_length_errors; + u64 rx_crc_errors; +}; + +struct rtase_private { + void __iomem *mmio_addr; + u32 sw_flag; + + struct pci_dev *pdev; + struct net_device *dev; + u32 rx_buf_sz; + + struct page_pool *page_pool; + struct rtase_ring tx_ring[RTASE_NUM_TX_QUEUE]; + struct rtase_ring rx_ring[RTASE_NUM_RX_QUEUE]; + struct rtase_counters *tally_vaddr; + dma_addr_t tally_paddr; + + u32 vlan_filter_ctrl; + u16 vlan_filter_vid[RTASE_VLAN_FILTER_ENTRY_NUM]; + + struct msix_entry msix_entry[RTASE_NUM_MSIX]; + struct rtase_int_vector int_vector[RTASE_NUM_MSIX]; + + struct rtase_stats stats; + + u16 tx_queue_ctrl; + u16 func_tx_queue_num; + u16 func_rx_queue_num; + u16 int_nums; + u16 tx_int_mit; + u16 rx_int_mit; + + u32 hw_ver; +}; + +#define RTASE_LSO_64K 64000 + +#define RTASE_NIC_MAX_PHYS_BUF_COUNT_LSO2 (16 * 4) + +#define RTASE_TCPHO_MASK GENMASK(24, 18) + +#define RTASE_MSS_MASK GENMASK(28, 18) + +#endif /* RTASE_H */ diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c new file mode 100644 index 000000000000..2aacc1996796 --- /dev/null +++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c @@ -0,0 +1,2317 @@ +// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause +/* + * rtase is the Linux device driver released for Realtek Automotive Switch + * controllers with PCI-Express interface. + * + * Copyright(c) 2024 Realtek Semiconductor Corp. + * + * Below is a simplified block diagram of the chip and its relevant interfaces. + * + * ************************* + * * * + * * CPU network device * + * * * + * * +-------------+ * + * * | PCIE Host | * + * ***********++************ + * || + * PCIE + * || + * ********************++********************** + * * | PCIE Endpoint | * + * * +---------------+ * + * * | GMAC | * + * * +--++--+ Realtek * + * * || RTL90xx Series * + * * || * + * * +-------------++----------------+ * + * * | | MAC | | * + * * | +-----+ | * + * * | | * + * * | Ethernet Switch Core | * + * * | | * + * * | +-----+ +-----+ | * + * * | | MAC |...........| MAC | | * + * * +---+-----+-----------+-----+---+ * + * * | PHY |...........| PHY | * + * * +--++-+ +--++-+ * + * *************||****************||*********** + * + * The block of the Realtek RTL90xx series is our entire chip architecture, + * the GMAC is connected to the switch core, and there is no PHY in between. + * In addition, this driver is mainly used to control GMAC, but does not + * control the switch core, so it is not the same as DSA. Linux only plays + * the role of a normal leaf node in this model. + */ + +#include <linux/crc32.h> +#include <linux/dma-mapping.h> +#include <linux/etherdevice.h> +#include <linux/if_vlan.h> +#include <linux/in.h> +#include <linux/init.h> +#include <linux/interrupt.h> +#include <linux/io.h> +#include <linux/iopoll.h> +#include <linux/ip.h> +#include <linux/ipv6.h> +#include <linux/mdio.h> +#include <linux/module.h> +#include <linux/netdevice.h> +#include <linux/pci.h> +#include <linux/pm_runtime.h> +#include <linux/prefetch.h> +#include <linux/rtnetlink.h> +#include <linux/tcp.h> +#include <asm/irq.h> +#include <net/ip6_checksum.h> +#include <net/netdev_queues.h> +#include <net/page_pool/helpers.h> +#include <net/pkt_cls.h> + +#include "rtase.h" + +#define RTK_OPTS1_DEBUG_VALUE 0x0BADBEEF +#define RTK_MAGIC_NUMBER 0x0BADBADBADBADBAD + +static const struct pci_device_id rtase_pci_tbl[] = { + {PCI_VDEVICE(REALTEK, 0x906A)}, + {} +}; + +MODULE_DEVICE_TABLE(pci, rtase_pci_tbl); + +MODULE_AUTHOR("Realtek ARD Software Team"); +MODULE_DESCRIPTION("Network Driver for the PCIe interface of Realtek Automotive Ethernet Switch"); +MODULE_LICENSE("Dual BSD/GPL"); + +struct rtase_counters { + __le64 tx_packets; + __le64 rx_packets; + __le64 tx_errors; + __le32 rx_errors; + __le16 rx_missed; + __le16 align_errors; + __le32 tx_one_collision; + __le32 tx_multi_collision; + __le64 rx_unicast; + __le64 rx_broadcast; + __le32 rx_multicast; + __le16 tx_aborted; + __le16 tx_underrun; +} __packed; + +static void rtase_w8(const struct rtase_private *tp, u16 reg, u8 val8) +{ + writeb(val8, tp->mmio_addr + reg); +} + +static void rtase_w16(const struct rtase_private *tp, u16 reg, u16 val16) +{ + writew(val16, tp->mmio_addr + reg); +} + +static void rtase_w32(const struct rtase_private *tp, u16 reg, u32 val32) +{ + writel(val32, tp->mmio_addr + reg); +} + +static u8 rtase_r8(const struct rtase_private *tp, u16 reg) +{ + return readb(tp->mmio_addr + reg); +} + +static u16 rtase_r16(const struct rtase_private *tp, u16 reg) +{ + return readw(tp->mmio_addr + reg); +} + +static u32 rtase_r32(const struct rtase_private *tp, u16 reg) +{ + return readl(tp->mmio_addr + reg); +} + +static void rtase_free_desc(struct rtase_private *tp) +{ + struct pci_dev *pdev = tp->pdev; + u32 i; + + for (i = 0; i < tp->func_tx_queue_num; i++) { + if (!tp->tx_ring[i].desc) + continue; + + dma_free_coherent(&pdev->dev, RTASE_TX_RING_DESC_SIZE, + tp->tx_ring[i].desc, + tp->tx_ring[i].phy_addr); + tp->tx_ring[i].desc = NULL; + } + + for (i = 0; i < tp->func_rx_queue_num; i++) { + if (!tp->rx_ring[i].desc) + continue; + + dma_free_coherent(&pdev->dev, RTASE_RX_RING_DESC_SIZE, + tp->rx_ring[i].desc, + tp->rx_ring[i].phy_addr); + tp->rx_ring[i].desc = NULL; + } +} + +static int rtase_alloc_desc(struct rtase_private *tp) +{ + struct pci_dev *pdev = tp->pdev; + u32 i; + + /* rx and tx descriptors needs 256 bytes alignment. + * dma_alloc_coherent provides more. + */ + for (i = 0; i < tp->func_tx_queue_num; i++) { + tp->tx_ring[i].desc = + dma_alloc_coherent(&pdev->dev, + RTASE_TX_RING_DESC_SIZE, + &tp->tx_ring[i].phy_addr, + GFP_KERNEL); + if (!tp->tx_ring[i].desc) + goto err_out; + } + + for (i = 0; i < tp->func_rx_queue_num; i++) { + tp->rx_ring[i].desc = + dma_alloc_coherent(&pdev->dev, + RTASE_RX_RING_DESC_SIZE, + &tp->rx_ring[i].phy_addr, + GFP_KERNEL); + if (!tp->rx_ring[i].desc) + goto err_out; + } + + return 0; + +err_out: + rtase_free_desc(tp); + return -ENOMEM; +} + +static void rtase_unmap_tx_skb(struct pci_dev *pdev, u32 len, + struct rtase_tx_desc *desc) +{ + dma_unmap_single(&pdev->dev, le64_to_cpu(desc->addr), len, + DMA_TO_DEVICE); + desc->opts1 = cpu_to_le32(RTK_OPTS1_DEBUG_VALUE); + desc->opts2 = 0x00; + desc->addr = cpu_to_le64(RTK_MAGIC_NUMBER); +} + +static void rtase_tx_clear_range(struct rtase_ring *ring, u32 start, u32 n) +{ + struct rtase_tx_desc *desc_base = ring->desc; + struct rtase_private *tp = ring->ivec->tp; + u32 i; + + for (i = 0; i < n; i++) { + u32 entry = (start + i) % RTASE_NUM_DESC; + struct rtase_tx_desc *desc = desc_base + entry; + u32 len = ring->mis.len[entry]; + struct sk_buff *skb; + + if (len == 0) + continue; + + rtase_unmap_tx_skb(tp->pdev, len, desc); + ring->mis.len[entry] = 0; + skb = ring->skbuff[entry]; + if (!skb) + continue; + + tp->stats.tx_dropped++; + dev_kfree_skb_any(skb); + ring->skbuff[entry] = NULL; + } +} + +static void rtase_tx_clear(struct rtase_private *tp) +{ + struct rtase_ring *ring; + u16 i; + + for (i = 0; i < tp->func_tx_queue_num; i++) { + ring = &tp->tx_ring[i]; + rtase_tx_clear_range(ring, ring->dirty_idx, RTASE_NUM_DESC); + ring->cur_idx = 0; + ring->dirty_idx = 0; + } +} + +static void rtase_mark_to_asic(union rtase_rx_desc *desc, u32 rx_buf_sz) +{ + u32 eor = le32_to_cpu(desc->desc_cmd.opts1) & RTASE_RING_END; + + desc->desc_status.opts2 = 0; + /* force memory writes to complete before releasing descriptor */ + dma_wmb(); + WRITE_ONCE(desc->desc_cmd.opts1, + cpu_to_le32(RTASE_DESC_OWN | eor | rx_buf_sz)); +} + +static u32 rtase_tx_avail(struct rtase_ring *ring) +{ + return READ_ONCE(ring->dirty_idx) + RTASE_NUM_DESC - + READ_ONCE(ring->cur_idx); +} + +static int tx_handler(struct rtase_ring *ring, int budget) +{ + const struct rtase_private *tp = ring->ivec->tp; + struct net_device *dev = tp->dev; + u32 dirty_tx, tx_left; + u32 bytes_compl = 0; + u32 pkts_compl = 0; + int workdone = 0; + + dirty_tx = ring->dirty_idx; + tx_left = READ_ONCE(ring->cur_idx) - dirty_tx; + + while (tx_left > 0) { + u32 entry = dirty_tx % RTASE_NUM_DESC; + struct rtase_tx_desc *desc = ring->desc + + sizeof(struct rtase_tx_desc) * entry; + u32 status; + + status = le32_to_cpu(desc->opts1); + + if (status & RTASE_DESC_OWN) + break; + + rtase_unmap_tx_skb(tp->pdev, ring->mis.len[entry], desc); + ring->mis.len[entry] = 0; + if (ring->skbuff[entry]) { + pkts_compl++; + bytes_compl += ring->skbuff[entry]->len; + napi_consume_skb(ring->skbuff[entry], budget); + ring->skbuff[entry] = NULL; + } + + dirty_tx++; + tx_left--; + workdone++; + + if (workdone == RTASE_TX_BUDGET_DEFAULT) + break; + } + + if (ring->dirty_idx != dirty_tx) { + dev_sw_netstats_tx_add(dev, pkts_compl, bytes_compl); + WRITE_ONCE(ring->dirty_idx, dirty_tx); + + netif_subqueue_completed_wake(dev, ring->index, pkts_compl, + bytes_compl, + rtase_tx_avail(ring), + RTASE_TX_START_THRS); + + if (ring->cur_idx != dirty_tx) + rtase_w8(tp, RTASE_TPPOLL, BIT(ring->index)); + } + + return 0; +} + +static void rtase_tx_desc_init(struct rtase_private *tp, u16 idx) +{ + struct rtase_ring *ring = &tp->tx_ring[idx]; + struct rtase_tx_desc *desc; + u32 i; + + memset(ring->desc, 0x0, RTASE_TX_RING_DESC_SIZE); + memset(ring->skbuff, 0x0, sizeof(ring->skbuff)); + ring->cur_idx = 0; + ring->dirty_idx = 0; + ring->index = idx; + ring->alloc_fail = 0; + + for (i = 0; i < RTASE_NUM_DESC; i++) { + ring->mis.len[i] = 0; + if ((RTASE_NUM_DESC - 1) == i) { + desc = ring->desc + sizeof(struct rtase_tx_desc) * i; + desc->opts1 = cpu_to_le32(RTASE_RING_END); + } + } + + ring->ring_handler = tx_handler; + if (idx < 4) { + ring->ivec = &tp->int_vector[idx]; + list_add_tail(&ring->ring_entry, + &tp->int_vector[idx].ring_list); + } else { + ring->ivec = &tp->int_vector[0]; + list_add_tail(&ring->ring_entry, &tp->int_vector[0].ring_list); + } +} + +static void rtase_map_to_asic(union rtase_rx_desc *desc, dma_addr_t mapping, + u32 rx_buf_sz) +{ + desc->desc_cmd.addr = cpu_to_le64(mapping); + + rtase_mark_to_asic(desc, rx_buf_sz); +} + +static void rtase_make_unusable_by_asic(union rtase_rx_desc *desc) +{ + desc->desc_cmd.addr = cpu_to_le64(RTK_MAGIC_NUMBER); + desc->desc_cmd.opts1 &= ~cpu_to_le32(RTASE_DESC_OWN | RSVD_MASK); +} + +static int rtase_alloc_rx_data_buf(struct rtase_ring *ring, + void **p_data_buf, + union rtase_rx_desc *desc, + dma_addr_t *rx_phy_addr) +{ + struct rtase_int_vector *ivec = ring->ivec; + const struct rtase_private *tp = ivec->tp; + dma_addr_t mapping; + struct page *page; + + page = page_pool_dev_alloc_pages(tp->page_pool); + if (!page) { + ring->alloc_fail++; + goto err_out; + } + + *p_data_buf = page_address(page); + mapping = page_pool_get_dma_addr(page); + *rx_phy_addr = mapping; + rtase_map_to_asic(desc, mapping, tp->rx_buf_sz); + + return 0; + +err_out: + rtase_make_unusable_by_asic(desc); + + return -ENOMEM; +} + +static u32 rtase_rx_ring_fill(struct rtase_ring *ring, u32 ring_start, + u32 ring_end) +{ + union rtase_rx_desc *desc_base = ring->desc; + u32 cur; + + for (cur = ring_start; ring_end - cur > 0; cur++) { + u32 i = cur % RTASE_NUM_DESC; + union rtase_rx_desc *desc = desc_base + i; + int ret; + + if (ring->data_buf[i]) + continue; + + ret = rtase_alloc_rx_data_buf(ring, &ring->data_buf[i], desc, + &ring->mis.data_phy_addr[i]); + if (ret) + break; + } + + return cur - ring_start; +} + +static void rtase_mark_as_last_descriptor(union rtase_rx_desc *desc) +{ + desc->desc_cmd.opts1 |= cpu_to_le32(RTASE_RING_END); +} + +static void rtase_rx_ring_clear(struct page_pool *page_pool, + struct rtase_ring *ring) +{ + union rtase_rx_desc *desc; + struct page *page; + u32 i; + + for (i = 0; i < RTASE_NUM_DESC; i++) { + desc = ring->desc + sizeof(union rtase_rx_desc) * i; + page = virt_to_head_page(ring->data_buf[i]); + + if (ring->data_buf[i]) + page_pool_put_full_page(page_pool, page, true); + + rtase_make_unusable_by_asic(desc); + } +} + +static int rtase_fragmented_frame(u32 status) +{ + return (status & (RTASE_RX_FIRST_FRAG | RTASE_RX_LAST_FRAG)) != + (RTASE_RX_FIRST_FRAG | RTASE_RX_LAST_FRAG); +} + +static void rtase_rx_csum(const struct rtase_private *tp, struct sk_buff *skb, + const union rtase_rx_desc *desc) +{ + u32 opts2 = le32_to_cpu(desc->desc_status.opts2); + + /* rx csum offload */ + if (((opts2 & RTASE_RX_V4F) && !(opts2 & RTASE_RX_IPF)) || + (opts2 & RTASE_RX_V6F)) { + if (((opts2 & RTASE_RX_TCPT) && !(opts2 & RTASE_RX_TCPF)) || + ((opts2 & RTASE_RX_UDPT) && !(opts2 & RTASE_RX_UDPF))) + skb->ip_summed = CHECKSUM_UNNECESSARY; + else + skb->ip_summed = CHECKSUM_NONE; + } else { + skb->ip_summed = CHECKSUM_NONE; + } +} + +static void rtase_rx_vlan_skb(union rtase_rx_desc *desc, struct sk_buff *skb) +{ + u32 opts2 = le32_to_cpu(desc->desc_status.opts2); + + if (!(opts2 & RTASE_RX_VLAN_TAG)) + return; + + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), + swab16(opts2 & RTASE_VLAN_TAG_MASK)); +} + +static void rtase_rx_skb(const struct rtase_ring *ring, struct sk_buff *skb) +{ + struct rtase_int_vector *ivec = ring->ivec; + + napi_gro_receive(&ivec->napi, skb); +} + +static int rx_handler(struct rtase_ring *ring, int budget) +{ + union rtase_rx_desc *desc_base = ring->desc; + u32 pkt_size, cur_rx, delta, entry, status; + struct rtase_private *tp = ring->ivec->tp; + struct net_device *dev = tp->dev; + union rtase_rx_desc *desc; + struct sk_buff *skb; + int workdone = 0; + + cur_rx = ring->cur_idx; + entry = cur_rx % RTASE_NUM_DESC; + desc = &desc_base[entry]; + + while (workdone < budget) { + status = le32_to_cpu(desc->desc_status.opts1); + + if (status & RTASE_DESC_OWN) + break; + + /* This barrier is needed to keep us from reading + * any other fields out of the rx descriptor until + * we know the status of RTASE_DESC_OWN + */ + dma_rmb(); + + if (unlikely(status & RTASE_RX_RES)) { + if (net_ratelimit()) + netdev_warn(dev, "Rx ERROR. status = %08x\n", + status); + + tp->stats.rx_errors++; + + if (status & (RTASE_RX_RWT | RTASE_RX_RUNT)) + tp->stats.rx_length_errors++; + + if (status & RTASE_RX_CRC) + tp->stats.rx_crc_errors++; + + if (dev->features & NETIF_F_RXALL) + goto process_pkt; + + rtase_mark_to_asic(desc, tp->rx_buf_sz); + goto skip_process_pkt; + } + +process_pkt: + pkt_size = status & RTASE_RX_PKT_SIZE_MASK; + if (likely(!(dev->features & NETIF_F_RXFCS))) + pkt_size -= ETH_FCS_LEN; + + /* The driver does not support incoming fragmented frames. + * They are seen as a symptom of over-mtu sized frames. + */ + if (unlikely(rtase_fragmented_frame(status))) { + tp->stats.rx_dropped++; + tp->stats.rx_length_errors++; + rtase_mark_to_asic(desc, tp->rx_buf_sz); + goto skip_process_pkt; + } + + dma_sync_single_for_cpu(&tp->pdev->dev, + ring->mis.data_phy_addr[entry], + tp->rx_buf_sz, DMA_FROM_DEVICE); + + skb = build_skb(ring->data_buf[entry], PAGE_SIZE); + if (!skb) { + tp->stats.rx_dropped++; + rtase_mark_to_asic(desc, tp->rx_buf_sz); + goto skip_process_pkt; + } + ring->data_buf[entry] = NULL; + + if (dev->features & NETIF_F_RXCSUM) + rtase_rx_csum(tp, skb, desc); + + skb_put(skb, pkt_size); + skb_mark_for_recycle(skb); + skb->protocol = eth_type_trans(skb, dev); + + if (skb->pkt_type == PACKET_MULTICAST) + tp->stats.multicast++; + + rtase_rx_vlan_skb(desc, skb); + rtase_rx_skb(ring, skb); + + dev_sw_netstats_rx_add(dev, pkt_size); + +skip_process_pkt: + workdone++; + cur_rx++; + entry = cur_rx % RTASE_NUM_DESC; + desc = ring->desc + sizeof(union rtase_rx_desc) * entry; + } + + ring->cur_idx = cur_rx; + delta = rtase_rx_ring_fill(ring, ring->dirty_idx, ring->cur_idx); + ring->dirty_idx += delta; + + return workdone; +} + +static void rtase_rx_desc_init(struct rtase_private *tp, u16 idx) +{ + struct rtase_ring *ring = &tp->rx_ring[idx]; + u16 i; + + memset(ring->desc, 0x0, RTASE_RX_RING_DESC_SIZE); + memset(ring->data_buf, 0x0, sizeof(ring->data_buf)); + ring->cur_idx = 0; + ring->dirty_idx = 0; + ring->index = idx; + ring->alloc_fail = 0; + + for (i = 0; i < RTASE_NUM_DESC; i++) + ring->mis.data_phy_addr[i] = 0; + + ring->ring_handler = rx_handler; + ring->ivec = &tp->int_vector[idx]; + list_add_tail(&ring->ring_entry, &tp->int_vector[idx].ring_list); +} + +static void rtase_rx_clear(struct rtase_private *tp) +{ + u32 i; + + for (i = 0; i < tp->func_rx_queue_num; i++) + rtase_rx_ring_clear(tp->page_pool, &tp->rx_ring[i]); + + page_pool_destroy(tp->page_pool); + tp->page_pool = NULL; +} + +static int rtase_init_ring(const struct net_device *dev) +{ + struct rtase_private *tp = netdev_priv(dev); + struct page_pool_params pp_params = { 0 }; + struct page_pool *page_pool; + u32 num; + u16 i; + + pp_params.flags = PP_FLAG_DMA_MAP | PP_FLAG_DMA_SYNC_DEV; + pp_params.order = 0; + pp_params.pool_size = RTASE_NUM_DESC * tp->func_rx_queue_num; + pp_params.nid = dev_to_node(&tp->pdev->dev); + pp_params.dev = &tp->pdev->dev; + pp_params.dma_dir = DMA_FROM_DEVICE; + pp_params.max_len = PAGE_SIZE; + pp_params.offset = 0; + + page_pool = page_pool_create(&pp_params); + if (IS_ERR(page_pool)) { + netdev_err(tp->dev, "failed to create page pool\n"); + return -ENOMEM; + } + + tp->page_pool = page_pool; + + for (i = 0; i < tp->func_tx_queue_num; i++) + rtase_tx_desc_init(tp, i); + + for (i = 0; i < tp->func_rx_queue_num; i++) { + rtase_rx_desc_init(tp, i); + + num = rtase_rx_ring_fill(&tp->rx_ring[i], 0, RTASE_NUM_DESC); + if (num != RTASE_NUM_DESC) + goto err_out; + + rtase_mark_as_last_descriptor(tp->rx_ring[i].desc + + sizeof(union rtase_rx_desc) * + (RTASE_NUM_DESC - 1)); + } + + return 0; + +err_out: + rtase_rx_clear(tp); + return -ENOMEM; +} + +static void rtase_interrupt_mitigation(const struct rtase_private *tp) +{ + u32 i; + + for (i = 0; i < tp->func_tx_queue_num; i++) + rtase_w16(tp, RTASE_INT_MITI_TX + i * 2, tp->tx_int_mit); + + for (i = 0; i < tp->func_rx_queue_num; i++) + rtase_w16(tp, RTASE_INT_MITI_RX + i * 2, tp->rx_int_mit); +} + +static void rtase_tally_counter_addr_fill(const struct rtase_private *tp) +{ + rtase_w32(tp, RTASE_DTCCR4, upper_32_bits(tp->tally_paddr)); + rtase_w32(tp, RTASE_DTCCR0, lower_32_bits(tp->tally_paddr)); +} + +static void rtase_tally_counter_clear(const struct rtase_private *tp) +{ + u32 cmd = lower_32_bits(tp->tally_paddr); + + rtase_w32(tp, RTASE_DTCCR4, upper_32_bits(tp->tally_paddr)); + rtase_w32(tp, RTASE_DTCCR0, cmd | RTASE_COUNTER_RESET); +} + +static void rtase_desc_addr_fill(const struct rtase_private *tp) +{ + const struct rtase_ring *ring; + u16 i, cmd, val; + int err; + + for (i = 0; i < tp->func_tx_queue_num; i++) { + ring = &tp->tx_ring[i]; + + rtase_w32(tp, RTASE_TX_DESC_ADDR0, + lower_32_bits(ring->phy_addr)); + rtase_w32(tp, RTASE_TX_DESC_ADDR4, + upper_32_bits(ring->phy_addr)); + + cmd = i | RTASE_TX_DESC_CMD_WE | RTASE_TX_DESC_CMD_CS; + rtase_w16(tp, RTASE_TX_DESC_COMMAND, cmd); + + err = read_poll_timeout(rtase_r16, val, + !(val & RTASE_TX_DESC_CMD_CS), 10, + 1000, false, tp, + RTASE_TX_DESC_COMMAND); + + if (err == -ETIMEDOUT) + netdev_err(tp->dev, + "error occurred in fill tx descriptor\n"); + } + + for (i = 0; i < tp->func_rx_queue_num; i++) { + ring = &tp->rx_ring[i]; + + if (i == 0) { + rtase_w32(tp, RTASE_Q0_RX_DESC_ADDR0, + lower_32_bits(ring->phy_addr)); + rtase_w32(tp, RTASE_Q0_RX_DESC_ADDR4, + upper_32_bits(ring->phy_addr)); + } else { + rtase_w32(tp, (RTASE_Q1_RX_DESC_ADDR0 + ((i - 1) * 8)), + lower_32_bits(ring->phy_addr)); + rtase_w32(tp, (RTASE_Q1_RX_DESC_ADDR4 + ((i - 1) * 8)), + upper_32_bits(ring->phy_addr)); + } + } +} + +static void rtase_hw_set_features(const struct net_device *dev, + netdev_features_t features) +{ + const struct rtase_private *tp = netdev_priv(dev); + u16 rx_config, val; + + rx_config = rtase_r16(tp, RTASE_RX_CONFIG_0); + if (features & NETIF_F_RXALL) + rx_config |= (RTASE_ACCEPT_ERR | RTASE_ACCEPT_RUNT); + else + rx_config &= ~(RTASE_ACCEPT_ERR | RTASE_ACCEPT_RUNT); + + rtase_w16(tp, RTASE_RX_CONFIG_0, rx_config); + + val = rtase_r16(tp, RTASE_CPLUS_CMD); + if (features & NETIF_F_RXCSUM) + rtase_w16(tp, RTASE_CPLUS_CMD, val | RTASE_RX_CHKSUM); + else + rtase_w16(tp, RTASE_CPLUS_CMD, val & ~RTASE_RX_CHKSUM); + + rx_config = rtase_r16(tp, RTASE_RX_CONFIG_1); + if (dev->features & NETIF_F_HW_VLAN_CTAG_RX) + rx_config |= (RTASE_INNER_VLAN_DETAG_EN | + RTASE_OUTER_VLAN_DETAG_EN); + else + rx_config &= ~(RTASE_INNER_VLAN_DETAG_EN | + RTASE_OUTER_VLAN_DETAG_EN); + + rtase_w16(tp, RTASE_RX_CONFIG_1, rx_config); +} + +static void rtase_hw_set_rx_packet_filter(struct net_device *dev) +{ + u32 mc_filter[2] = { 0xFFFFFFFF, 0xFFFFFFFF }; + struct rtase_private *tp = netdev_priv(dev); + u16 rx_mode; + + rx_mode = rtase_r16(tp, RTASE_RX_CONFIG_0) & ~RTASE_ACCEPT_MASK; + rx_mode |= RTASE_ACCEPT_BROADCAST | RTASE_ACCEPT_MYPHYS; + + if (dev->flags & IFF_PROMISC) { + rx_mode |= RTASE_ACCEPT_MULTICAST | RTASE_ACCEPT_ALLPHYS; + } else if (dev->flags & IFF_ALLMULTI) { + rx_mode |= RTASE_ACCEPT_MULTICAST; + } else { + struct netdev_hw_addr *hw_addr; + + mc_filter[0] = 0; + mc_filter[1] = 0; + + netdev_for_each_mc_addr(hw_addr, dev) { + u32 bit_nr = eth_hw_addr_crc(hw_addr); + u32 idx = u32_get_bits(bit_nr, BIT(31)); + u32 bit = u32_get_bits(bit_nr, + RTASE_MULTICAST_FILTER_MASK); + + mc_filter[idx] |= BIT(bit); + rx_mode |= RTASE_ACCEPT_MULTICAST; + } + } + + if (dev->features & NETIF_F_RXALL) + rx_mode |= RTASE_ACCEPT_ERR | RTASE_ACCEPT_RUNT; + + rtase_w32(tp, RTASE_MAR0, swab32(mc_filter[1])); + rtase_w32(tp, RTASE_MAR1, swab32(mc_filter[0])); + rtase_w16(tp, RTASE_RX_CONFIG_0, rx_mode); +} + +static void rtase_irq_dis_and_clear(const struct rtase_private *tp) +{ + const struct rtase_int_vector *ivec = &tp->int_vector[0]; + u32 val1; + u16 val2; + u8 i; + + rtase_w32(tp, ivec->imr_addr, 0); + val1 = rtase_r32(tp, ivec->isr_addr); + rtase_w32(tp, ivec->isr_addr, val1); + + for (i = 1; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + rtase_w16(tp, ivec->imr_addr, 0); + val2 = rtase_r16(tp, ivec->isr_addr); + rtase_w16(tp, ivec->isr_addr, val2); + } +} + +static void rtase_poll_timeout(const struct rtase_private *tp, u32 cond, + u32 sleep_us, u64 timeout_us, u16 reg) +{ + int err; + u8 val; + + err = read_poll_timeout(rtase_r8, val, val & cond, sleep_us, + timeout_us, false, tp, reg); + + if (err == -ETIMEDOUT) + netdev_err(tp->dev, "poll reg 0x00%x timeout\n", reg); +} + +static void rtase_nic_reset(const struct net_device *dev) +{ + const struct rtase_private *tp = netdev_priv(dev); + u16 rx_config; + u8 val; + + rx_config = rtase_r16(tp, RTASE_RX_CONFIG_0); + rtase_w16(tp, RTASE_RX_CONFIG_0, rx_config & ~RTASE_ACCEPT_MASK); + + val = rtase_r8(tp, RTASE_MISC); + rtase_w8(tp, RTASE_MISC, val | RTASE_RX_DV_GATE_EN); + + val = rtase_r8(tp, RTASE_CHIP_CMD); + rtase_w8(tp, RTASE_CHIP_CMD, val | RTASE_STOP_REQ); + mdelay(2); + + rtase_poll_timeout(tp, RTASE_STOP_REQ_DONE, 100, 150000, + RTASE_CHIP_CMD); + + rtase_poll_timeout(tp, RTASE_TX_FIFO_EMPTY, 100, 100000, + RTASE_FIFOR); + + rtase_poll_timeout(tp, RTASE_RX_FIFO_EMPTY, 100, 100000, + RTASE_FIFOR); + + val = rtase_r8(tp, RTASE_CHIP_CMD); + rtase_w8(tp, RTASE_CHIP_CMD, val & ~(RTASE_TE | RTASE_RE)); + val = rtase_r8(tp, RTASE_CHIP_CMD); + rtase_w8(tp, RTASE_CHIP_CMD, val & ~RTASE_STOP_REQ); + + rtase_w16(tp, RTASE_RX_CONFIG_0, rx_config); +} + +static void rtase_hw_reset(const struct net_device *dev) +{ + const struct rtase_private *tp = netdev_priv(dev); + + rtase_irq_dis_and_clear(tp); + + rtase_nic_reset(dev); +} + +static void rtase_set_rx_queue(const struct rtase_private *tp) +{ + u16 reg_data; + + reg_data = rtase_r16(tp, RTASE_FCR); + switch (tp->func_rx_queue_num) { + case 1: + u16p_replace_bits(®_data, 0x1, RTASE_FCR_RXQ_MASK); + break; + case 2: + u16p_replace_bits(®_data, 0x2, RTASE_FCR_RXQ_MASK); + break; + case 4: + u16p_replace_bits(®_data, 0x3, RTASE_FCR_RXQ_MASK); + break; + } + rtase_w16(tp, RTASE_FCR, reg_data); +} + +static void rtase_set_tx_queue(const struct rtase_private *tp) +{ + u16 reg_data; + + reg_data = rtase_r16(tp, RTASE_TX_CONFIG_1); + switch (tp->tx_queue_ctrl) { + case 1: + u16p_replace_bits(®_data, 0x0, RTASE_TC_MODE_MASK); + break; + case 2: + u16p_replace_bits(®_data, 0x1, RTASE_TC_MODE_MASK); + break; + case 3: + case 4: + u16p_replace_bits(®_data, 0x2, RTASE_TC_MODE_MASK); + break; + default: + u16p_replace_bits(®_data, 0x3, RTASE_TC_MODE_MASK); + break; + } + rtase_w16(tp, RTASE_TX_CONFIG_1, reg_data); +} + +static void rtase_hw_config(struct net_device *dev) +{ + const struct rtase_private *tp = netdev_priv(dev); + u32 reg_data32; + u16 reg_data16; + + rtase_hw_reset(dev); + + /* set rx dma burst */ + reg_data16 = rtase_r16(tp, RTASE_RX_CONFIG_0); + reg_data16 &= ~(RTASE_RX_SINGLE_TAG | RTASE_RX_SINGLE_FETCH); + u16p_replace_bits(®_data16, RTASE_RX_DMA_BURST_256, + RTASE_RX_MX_DMA_MASK); + rtase_w16(tp, RTASE_RX_CONFIG_0, reg_data16); + + /* new rx descritpor */ + reg_data16 = rtase_r16(tp, RTASE_RX_CONFIG_1); + reg_data16 |= RTASE_RX_NEW_DESC_FORMAT_EN | RTASE_PCIE_NEW_FLOW; + u16p_replace_bits(®_data16, 0xF, RTASE_RX_MAX_FETCH_DESC_MASK); + rtase_w16(tp, RTASE_RX_CONFIG_1, reg_data16); + + rtase_set_rx_queue(tp); + + rtase_interrupt_mitigation(tp); + + /* set tx dma burst size and interframe gap time */ + reg_data32 = rtase_r32(tp, RTASE_TX_CONFIG_0); + u32p_replace_bits(®_data32, RTASE_TX_DMA_BURST_UNLIMITED, + RTASE_TX_DMA_MASK); + u32p_replace_bits(®_data32, RTASE_INTERFRAMEGAP, + RTASE_TX_INTER_FRAME_GAP_MASK); + rtase_w32(tp, RTASE_TX_CONFIG_0, reg_data32); + + /* new tx descriptor */ + reg_data16 = rtase_r16(tp, RTASE_TFUN_CTRL); + rtase_w16(tp, RTASE_TFUN_CTRL, reg_data16 | + RTASE_TX_NEW_DESC_FORMAT_EN); + + /* tx fetch desc number */ + rtase_w8(tp, RTASE_TDFNR, 0x10); + + /* tag num select */ + reg_data16 = rtase_r16(tp, RTASE_MTPS); + u16p_replace_bits(®_data16, 0x4, RTASE_TAG_NUM_SEL_MASK); + rtase_w16(tp, RTASE_MTPS, reg_data16); + + rtase_set_tx_queue(tp); + + rtase_w16(tp, RTASE_TOKSEL, 0x5555); + + rtase_tally_counter_addr_fill(tp); + rtase_desc_addr_fill(tp); + rtase_hw_set_features(dev, dev->features); + + /* enable flow control */ + reg_data16 = rtase_r16(tp, RTASE_CPLUS_CMD); + reg_data16 |= (RTASE_FORCE_TXFLOW_EN | RTASE_FORCE_RXFLOW_EN); + rtase_w16(tp, RTASE_CPLUS_CMD, reg_data16); + /* set near fifo threshold - rx missed issue. */ + rtase_w16(tp, RTASE_RFIFONFULL, 0x190); + + rtase_w16(tp, RTASE_RMS, tp->rx_buf_sz); + + rtase_hw_set_rx_packet_filter(dev); +} + +static void rtase_nic_enable(const struct net_device *dev) +{ + const struct rtase_private *tp = netdev_priv(dev); + u16 rcr = rtase_r16(tp, RTASE_RX_CONFIG_1); + u8 val; + + rtase_w16(tp, RTASE_RX_CONFIG_1, rcr & ~RTASE_PCIE_RELOAD_EN); + rtase_w16(tp, RTASE_RX_CONFIG_1, rcr | RTASE_PCIE_RELOAD_EN); + + val = rtase_r8(tp, RTASE_CHIP_CMD); + rtase_w8(tp, RTASE_CHIP_CMD, val | RTASE_TE | RTASE_RE); + + val = rtase_r8(tp, RTASE_MISC); + rtase_w8(tp, RTASE_MISC, val & ~RTASE_RX_DV_GATE_EN); +} + +static void rtase_enable_hw_interrupt(const struct rtase_private *tp) +{ + const struct rtase_int_vector *ivec = &tp->int_vector[0]; + u32 i; + + rtase_w32(tp, ivec->imr_addr, ivec->imr); + + for (i = 1; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + rtase_w16(tp, ivec->imr_addr, ivec->imr); + } +} + +static void rtase_hw_start(const struct net_device *dev) +{ + const struct rtase_private *tp = netdev_priv(dev); + + rtase_nic_enable(dev); + rtase_enable_hw_interrupt(tp); +} + +/* the interrupt handler does RXQ0 and TXQ0, TXQ4~7 interrutp status + */ +static irqreturn_t rtase_interrupt(int irq, void *dev_instance) +{ + const struct rtase_private *tp; + struct rtase_int_vector *ivec; + u32 status; + + ivec = dev_instance; + tp = ivec->tp; + status = rtase_r32(tp, ivec->isr_addr); + + rtase_w32(tp, ivec->imr_addr, 0x0); + rtase_w32(tp, ivec->isr_addr, status & ~RTASE_FOVW); + + if (napi_schedule_prep(&ivec->napi)) + __napi_schedule(&ivec->napi); + + return IRQ_HANDLED; +} + +/* the interrupt handler does RXQ1&TXQ1 or RXQ2&TXQ2 or RXQ3&TXQ3 interrupt + * status according to interrupt vector + */ +static irqreturn_t rtase_q_interrupt(int irq, void *dev_instance) +{ + const struct rtase_private *tp; + struct rtase_int_vector *ivec; + u16 status; + + ivec = dev_instance; + tp = ivec->tp; + status = rtase_r16(tp, ivec->isr_addr); + + rtase_w16(tp, ivec->imr_addr, 0x0); + rtase_w16(tp, ivec->isr_addr, status); + + if (napi_schedule_prep(&ivec->napi)) + __napi_schedule(&ivec->napi); + + return IRQ_HANDLED; +} + +static int rtase_poll(struct napi_struct *napi, int budget) +{ + const struct rtase_int_vector *ivec; + const struct rtase_private *tp; + struct rtase_ring *ring; + int total_workdone = 0; + + ivec = container_of(napi, struct rtase_int_vector, napi); + tp = ivec->tp; + + list_for_each_entry(ring, &ivec->ring_list, ring_entry) + total_workdone += ring->ring_handler(ring, budget); + + if (total_workdone >= budget) + return budget; + + if (napi_complete_done(napi, total_workdone)) { + if (!ivec->index) + rtase_w32(tp, ivec->imr_addr, ivec->imr); + else + rtase_w16(tp, ivec->imr_addr, ivec->imr); + } + + return total_workdone; +} + +static int rtase_open(struct net_device *dev) +{ + struct rtase_private *tp = netdev_priv(dev); + const struct pci_dev *pdev = tp->pdev; + struct rtase_int_vector *ivec; + u16 i = 0, j; + int ret; + + ivec = &tp->int_vector[0]; + tp->rx_buf_sz = RTASE_RX_BUF_SIZE; + + ret = rtase_alloc_desc(tp); + if (ret) + return ret; + + ret = rtase_init_ring(dev); + if (ret) + goto err_free_all_allocated_mem; + + rtase_hw_config(dev); + + if (tp->sw_flag & RTASE_SWF_MSIX_ENABLED) { + ret = request_irq(ivec->irq, rtase_interrupt, 0, + dev->name, ivec); + if (ret) + goto err_free_all_allocated_irq; + + /* request other interrupts to handle multiqueue */ + for (i = 1; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + snprintf(ivec->name, sizeof(ivec->name), "%s_int%i", + tp->dev->name, i); + ret = request_irq(ivec->irq, rtase_q_interrupt, 0, + ivec->name, ivec); + if (ret) + goto err_free_all_allocated_irq; + } + } else { + ret = request_irq(pdev->irq, rtase_interrupt, 0, dev->name, + ivec); + if (ret) + goto err_free_all_allocated_mem; + } + + rtase_hw_start(dev); + + for (i = 0; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + napi_enable(&ivec->napi); + } + + netif_carrier_on(dev); + netif_wake_queue(dev); + + return 0; + +err_free_all_allocated_irq: + for (j = 0; j < i; j++) + free_irq(tp->int_vector[j].irq, &tp->int_vector[j]); + +err_free_all_allocated_mem: + rtase_free_desc(tp); + + return ret; +} + +static void rtase_down(struct net_device *dev) +{ + struct rtase_private *tp = netdev_priv(dev); + struct rtase_int_vector *ivec; + struct rtase_ring *ring, *tmp; + u32 i; + + for (i = 0; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + napi_disable(&ivec->napi); + list_for_each_entry_safe(ring, tmp, &ivec->ring_list, + ring_entry) + list_del(&ring->ring_entry); + } + + netif_tx_disable(dev); + + netif_carrier_off(dev); + + rtase_hw_reset(dev); + + rtase_tx_clear(tp); + + rtase_rx_clear(tp); +} + +static int rtase_close(struct net_device *dev) +{ + struct rtase_private *tp = netdev_priv(dev); + const struct pci_dev *pdev = tp->pdev; + u32 i; + + rtase_down(dev); + + if (tp->sw_flag & RTASE_SWF_MSIX_ENABLED) { + for (i = 0; i < tp->int_nums; i++) + free_irq(tp->int_vector[i].irq, &tp->int_vector[i]); + + } else { + free_irq(pdev->irq, &tp->int_vector[0]); + } + + rtase_free_desc(tp); + + return 0; +} + +static u32 rtase_tx_vlan_tag(const struct rtase_private *tp, + const struct sk_buff *skb) +{ + return (skb_vlan_tag_present(skb)) ? + (RTASE_TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb))) : 0x00; +} + +static u32 rtase_tx_csum(struct sk_buff *skb, const struct net_device *dev) +{ + u32 csum_cmd = 0; + u8 ip_protocol; + + switch (vlan_get_protocol(skb)) { + case htons(ETH_P_IP): + csum_cmd = RTASE_TX_IPCS_C; + ip_protocol = ip_hdr(skb)->protocol; + break; + + case htons(ETH_P_IPV6): + csum_cmd = RTASE_TX_IPV6F_C; + ip_protocol = ipv6_hdr(skb)->nexthdr; + break; + + default: + ip_protocol = IPPROTO_RAW; + break; + } + + if (ip_protocol == IPPROTO_TCP) + csum_cmd |= RTASE_TX_TCPCS_C; + else if (ip_protocol == IPPROTO_UDP) + csum_cmd |= RTASE_TX_UDPCS_C; + + csum_cmd |= u32_encode_bits(skb_transport_offset(skb), + RTASE_TCPHO_MASK); + + return csum_cmd; +} + +static int rtase_xmit_frags(struct rtase_ring *ring, struct sk_buff *skb, + u32 opts1, u32 opts2) +{ + const struct skb_shared_info *info = skb_shinfo(skb); + const struct rtase_private *tp = ring->ivec->tp; + const u8 nr_frags = info->nr_frags; + struct rtase_tx_desc *txd = NULL; + u32 cur_frag, entry; + + entry = ring->cur_idx; + for (cur_frag = 0; cur_frag < nr_frags; cur_frag++) { + const skb_frag_t *frag = &info->frags[cur_frag]; + dma_addr_t mapping; + u32 status, len; + void *addr; + + entry = (entry + 1) % RTASE_NUM_DESC; + + txd = ring->desc + sizeof(struct rtase_tx_desc) * entry; + len = skb_frag_size(frag); + addr = skb_frag_address(frag); + mapping = dma_map_single(&tp->pdev->dev, addr, len, + DMA_TO_DEVICE); + + if (unlikely(dma_mapping_error(&tp->pdev->dev, mapping))) { + if (unlikely(net_ratelimit())) + netdev_err(tp->dev, + "Failed to map TX fragments DMA!\n"); + + goto err_out; + } + + if (((entry + 1) % RTASE_NUM_DESC) == 0) + status = (opts1 | len | RTASE_RING_END); + else + status = opts1 | len; + + if (cur_frag == (nr_frags - 1)) { + ring->skbuff[entry] = skb; + status |= RTASE_TX_LAST_FRAG; + } + + ring->mis.len[entry] = len; + txd->addr = cpu_to_le64(mapping); + txd->opts2 = cpu_to_le32(opts2); + + /* make sure the operating fields have been updated */ + dma_wmb(); + txd->opts1 = cpu_to_le32(status); + } + + return cur_frag; + +err_out: + rtase_tx_clear_range(ring, ring->cur_idx + 1, cur_frag); + return -EIO; +} + +static netdev_tx_t rtase_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct skb_shared_info *shinfo = skb_shinfo(skb); + struct rtase_private *tp = netdev_priv(dev); + u32 q_idx, entry, len, opts1, opts2; + struct netdev_queue *tx_queue; + bool stop_queue, door_bell; + u32 mss = shinfo->gso_size; + struct rtase_tx_desc *txd; + struct rtase_ring *ring; + dma_addr_t mapping; + int frags; + + /* multiqueues */ + q_idx = skb_get_queue_mapping(skb); + ring = &tp->tx_ring[q_idx]; + tx_queue = netdev_get_tx_queue(dev, q_idx); + + if (unlikely(!rtase_tx_avail(ring))) { + if (net_ratelimit()) + netdev_err(dev, + "BUG! Tx Ring full when queue awake!\n"); + + netif_stop_queue(dev); + return NETDEV_TX_BUSY; + } + + entry = ring->cur_idx % RTASE_NUM_DESC; + txd = ring->desc + sizeof(struct rtase_tx_desc) * entry; + + opts1 = RTASE_DESC_OWN; + opts2 = rtase_tx_vlan_tag(tp, skb); + + /* tcp segmentation offload (or tcp large send) */ + if (mss) { + if (shinfo->gso_type & SKB_GSO_TCPV4) { + opts1 |= RTASE_GIANT_SEND_V4; + } else if (shinfo->gso_type & SKB_GSO_TCPV6) { + if (skb_cow_head(skb, 0)) + goto err_dma_0; + + tcp_v6_gso_csum_prep(skb); + opts1 |= RTASE_GIANT_SEND_V6; + } else { + WARN_ON_ONCE(1); + } + + opts1 |= u32_encode_bits(skb_transport_offset(skb), + RTASE_TCPHO_MASK); + opts2 |= u32_encode_bits(mss, RTASE_MSS_MASK); + } else if (skb->ip_summed == CHECKSUM_PARTIAL) { + opts2 |= rtase_tx_csum(skb, dev); + } + + frags = rtase_xmit_frags(ring, skb, opts1, opts2); + if (unlikely(frags < 0)) + goto err_dma_0; + + if (frags) { + len = skb_headlen(skb); + opts1 |= RTASE_TX_FIRST_FRAG; + } else { + len = skb->len; + ring->skbuff[entry] = skb; + opts1 |= RTASE_TX_FIRST_FRAG | RTASE_TX_LAST_FRAG; + } + + if (((entry + 1) % RTASE_NUM_DESC) == 0) + opts1 |= (len | RTASE_RING_END); + else + opts1 |= len; + + mapping = dma_map_single(&tp->pdev->dev, skb->data, len, + DMA_TO_DEVICE); + + if (unlikely(dma_mapping_error(&tp->pdev->dev, mapping))) { + if (unlikely(net_ratelimit())) + netdev_err(dev, "Failed to map TX DMA!\n"); + + goto err_dma_1; + } + + ring->mis.len[entry] = len; + txd->addr = cpu_to_le64(mapping); + txd->opts2 = cpu_to_le32(opts2); + txd->opts1 = cpu_to_le32(opts1 & ~RTASE_DESC_OWN); + + /* make sure the operating fields have been updated */ + dma_wmb(); + + door_bell = __netdev_tx_sent_queue(tx_queue, skb->len, + netdev_xmit_more()); + + txd->opts1 = cpu_to_le32(opts1); + + skb_tx_timestamp(skb); + + /* tx needs to see descriptor changes before updated cur_idx */ + smp_wmb(); + + WRITE_ONCE(ring->cur_idx, ring->cur_idx + frags + 1); + + stop_queue = !netif_subqueue_maybe_stop(dev, ring->index, + rtase_tx_avail(ring), + RTASE_TX_STOP_THRS, + RTASE_TX_START_THRS); + + if (door_bell || stop_queue) + rtase_w8(tp, RTASE_TPPOLL, BIT(ring->index)); + + return NETDEV_TX_OK; + +err_dma_1: + ring->skbuff[entry] = NULL; + rtase_tx_clear_range(ring, ring->cur_idx + 1, frags); + +err_dma_0: + tp->stats.tx_dropped++; + dev_kfree_skb_any(skb); + return NETDEV_TX_OK; +} + +static void rtase_set_rx_mode(struct net_device *dev) +{ + rtase_hw_set_rx_packet_filter(dev); +} + +static void rtase_enable_eem_write(const struct rtase_private *tp) +{ + u8 val; + + val = rtase_r8(tp, RTASE_EEM); + rtase_w8(tp, RTASE_EEM, val | RTASE_EEM_UNLOCK); +} + +static void rtase_disable_eem_write(const struct rtase_private *tp) +{ + u8 val; + + val = rtase_r8(tp, RTASE_EEM); + rtase_w8(tp, RTASE_EEM, val & ~RTASE_EEM_UNLOCK); +} + +static void rtase_rar_set(const struct rtase_private *tp, const u8 *addr) +{ + u32 rar_low, rar_high; + + rar_low = (u32)addr[0] | ((u32)addr[1] << 8) | + ((u32)addr[2] << 16) | ((u32)addr[3] << 24); + + rar_high = (u32)addr[4] | ((u32)addr[5] << 8); + + rtase_enable_eem_write(tp); + rtase_w32(tp, RTASE_MAC0, rar_low); + rtase_w32(tp, RTASE_MAC4, rar_high); + rtase_disable_eem_write(tp); + rtase_w16(tp, RTASE_LBK_CTRL, RTASE_LBK_ATLD | RTASE_LBK_CLR); +} + +static int rtase_set_mac_address(struct net_device *dev, void *p) +{ + struct rtase_private *tp = netdev_priv(dev); + int ret; + + ret = eth_mac_addr(dev, p); + if (ret) + return ret; + + rtase_rar_set(tp, dev->dev_addr); + + return 0; +} + +static int rtase_change_mtu(struct net_device *dev, int new_mtu) +{ + dev->mtu = new_mtu; + + netdev_update_features(dev); + + return 0; +} + +static void rtase_wait_for_quiescence(const struct net_device *dev) +{ + struct rtase_private *tp = netdev_priv(dev); + struct rtase_int_vector *ivec; + u32 i; + + for (i = 0; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + synchronize_irq(ivec->irq); + /* wait for any pending NAPI task to complete */ + napi_disable(&ivec->napi); + } + + rtase_irq_dis_and_clear(tp); + + for (i = 0; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + napi_enable(&ivec->napi); + } +} + +static void rtase_sw_reset(struct net_device *dev) +{ + struct rtase_private *tp = netdev_priv(dev); + struct rtase_ring *ring, *tmp; + struct rtase_int_vector *ivec; + int ret; + u32 i; + + netif_stop_queue(dev); + netif_carrier_off(dev); + rtase_hw_reset(dev); + + /* let's wait a bit while any (async) irq lands on */ + rtase_wait_for_quiescence(dev); + rtase_tx_clear(tp); + rtase_rx_clear(tp); + + for (i = 0; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + list_for_each_entry_safe(ring, tmp, &ivec->ring_list, + ring_entry) + list_del(&ring->ring_entry); + } + + ret = rtase_init_ring(dev); + if (ret) { + netdev_err(dev, "unable to init ring\n"); + rtase_free_desc(tp); + return; + } + + rtase_hw_config(dev); + /* always link, so start to transmit & receive */ + rtase_hw_start(dev); + + netif_carrier_on(dev); + netif_wake_queue(dev); +} + +static void rtase_dump_tally_counter(const struct rtase_private *tp) +{ + dma_addr_t paddr = tp->tally_paddr; + u32 cmd = lower_32_bits(paddr); + u32 val; + int err; + + rtase_w32(tp, RTASE_DTCCR4, upper_32_bits(paddr)); + rtase_w32(tp, RTASE_DTCCR0, cmd); + rtase_w32(tp, RTASE_DTCCR0, cmd | RTASE_COUNTER_DUMP); + + err = read_poll_timeout(rtase_r32, val, !(val & RTASE_COUNTER_DUMP), + 10, 250, false, tp, RTASE_DTCCR0); + + if (err == -ETIMEDOUT) + netdev_err(tp->dev, "error occurred in dump tally counter\n"); +} + +static void rtase_dump_state(const struct net_device *dev) +{ + const struct rtase_private *tp = netdev_priv(dev); + int max_reg_size = RTASE_PCI_REGS_SIZE; + const struct rtase_counters *counters; + const struct rtase_ring *ring; + u32 dword_rd; + int n = 0; + + ring = &tp->tx_ring[0]; + netdev_err(dev, "Tx descriptor info:\n"); + netdev_err(dev, "Tx curIdx = 0x%x\n", ring->cur_idx); + netdev_err(dev, "Tx dirtyIdx = 0x%x\n", ring->dirty_idx); + netdev_err(dev, "Tx phyAddr = %pad\n", &ring->phy_addr); + + ring = &tp->rx_ring[0]; + netdev_err(dev, "Rx descriptor info:\n"); + netdev_err(dev, "Rx curIdx = 0x%x\n", ring->cur_idx); + netdev_err(dev, "Rx dirtyIdx = 0x%x\n", ring->dirty_idx); + netdev_err(dev, "Rx phyAddr = %pad\n", &ring->phy_addr); + + netdev_err(dev, "Device Registers:\n"); + netdev_err(dev, "Chip Command = 0x%02x\n", + rtase_r8(tp, RTASE_CHIP_CMD)); + netdev_err(dev, "IMR = %08x\n", rtase_r32(tp, RTASE_IMR0)); + netdev_err(dev, "ISR = %08x\n", rtase_r32(tp, RTASE_ISR0)); + netdev_err(dev, "Boot Ctrl Reg(0xE004) = %04x\n", + rtase_r16(tp, RTASE_BOOT_CTL)); + netdev_err(dev, "EPHY ISR(0xE014) = %04x\n", + rtase_r16(tp, RTASE_EPHY_ISR)); + netdev_err(dev, "EPHY IMR(0xE016) = %04x\n", + rtase_r16(tp, RTASE_EPHY_IMR)); + netdev_err(dev, "CLKSW SET REG(0xE018) = %04x\n", + rtase_r16(tp, RTASE_CLKSW_SET)); + + netdev_err(dev, "Dump PCI Registers:\n"); + + while (n < max_reg_size) { + if ((n % RTASE_DWORD_MOD) == 0) + netdev_err(tp->dev, "0x%03x:\n", n); + + pci_read_config_dword(tp->pdev, n, &dword_rd); + netdev_err(tp->dev, "%08x\n", dword_rd); + n += 4; + } + + netdev_err(dev, "Dump tally counter:\n"); + counters = tp->tally_vaddr; + rtase_dump_tally_counter(tp); + + netdev_err(dev, "tx_packets %lld\n", + le64_to_cpu(counters->tx_packets)); + netdev_err(dev, "rx_packets %lld\n", + le64_to_cpu(counters->rx_packets)); + netdev_err(dev, "tx_errors %lld\n", + le64_to_cpu(counters->tx_errors)); + netdev_err(dev, "rx_errors %d\n", + le32_to_cpu(counters->rx_errors)); + netdev_err(dev, "rx_missed %d\n", + le16_to_cpu(counters->rx_missed)); + netdev_err(dev, "align_errors %d\n", + le16_to_cpu(counters->align_errors)); + netdev_err(dev, "tx_one_collision %d\n", + le32_to_cpu(counters->tx_one_collision)); + netdev_err(dev, "tx_multi_collision %d\n", + le32_to_cpu(counters->tx_multi_collision)); + netdev_err(dev, "rx_unicast %lld\n", + le64_to_cpu(counters->rx_unicast)); + netdev_err(dev, "rx_broadcast %lld\n", + le64_to_cpu(counters->rx_broadcast)); + netdev_err(dev, "rx_multicast %d\n", + le32_to_cpu(counters->rx_multicast)); + netdev_err(dev, "tx_aborted %d\n", + le16_to_cpu(counters->tx_aborted)); + netdev_err(dev, "tx_underrun %d\n", + le16_to_cpu(counters->tx_underrun)); +} + +static void rtase_tx_timeout(struct net_device *dev, unsigned int txqueue) +{ + rtase_dump_state(dev); + rtase_sw_reset(dev); +} + +static void rtase_get_stats64(struct net_device *dev, + struct rtnl_link_stats64 *stats) +{ + const struct rtase_private *tp = netdev_priv(dev); + const struct rtase_counters *counters; + + counters = tp->tally_vaddr; + + dev_fetch_sw_netstats(stats, dev->tstats); + + /* fetch additional counter values missing in stats collected by driver + * from tally counter + */ + rtase_dump_tally_counter(tp); + stats->rx_errors = tp->stats.rx_errors; + stats->tx_errors = le64_to_cpu(counters->tx_errors); + stats->rx_dropped = tp->stats.rx_dropped; + stats->tx_dropped = tp->stats.tx_dropped; + stats->multicast = tp->stats.multicast; + stats->rx_length_errors = tp->stats.rx_length_errors; +} + +static netdev_features_t rtase_fix_features(struct net_device *dev, + netdev_features_t features) +{ + netdev_features_t features_fix = features; + + /* not support TSO for jumbo frames */ + if (dev->mtu > ETH_DATA_LEN) + features_fix &= ~NETIF_F_ALL_TSO; + + return features_fix; +} + +static int rtase_set_features(struct net_device *dev, + netdev_features_t features) +{ + netdev_features_t features_set = features; + + features_set &= NETIF_F_RXALL | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_CTAG_RX; + + if (features_set ^ dev->features) + rtase_hw_set_features(dev, features_set); + + return 0; +} + +static const struct net_device_ops rtase_netdev_ops = { + .ndo_open = rtase_open, + .ndo_stop = rtase_close, + .ndo_start_xmit = rtase_start_xmit, + .ndo_set_rx_mode = rtase_set_rx_mode, + .ndo_set_mac_address = rtase_set_mac_address, + .ndo_change_mtu = rtase_change_mtu, + .ndo_tx_timeout = rtase_tx_timeout, + .ndo_get_stats64 = rtase_get_stats64, + .ndo_fix_features = rtase_fix_features, + .ndo_set_features = rtase_set_features, +}; + +static void rtase_get_mac_address(struct net_device *dev) +{ + struct rtase_private *tp = netdev_priv(dev); + u8 mac_addr[ETH_ALEN] __aligned(2) = {}; + u32 i; + + for (i = 0; i < ETH_ALEN; i++) + mac_addr[i] = rtase_r8(tp, RTASE_MAC0 + i); + + if (!is_valid_ether_addr(mac_addr)) { + eth_hw_addr_random(dev); + netdev_warn(dev, "Random ether addr %pM\n", dev->dev_addr); + } else { + eth_hw_addr_set(dev, mac_addr); + ether_addr_copy(dev->perm_addr, dev->dev_addr); + } + + rtase_rar_set(tp, dev->dev_addr); +} + +static int rtase_get_settings(struct net_device *dev, + struct ethtool_link_ksettings *cmd) +{ + u32 supported = SUPPORTED_MII | SUPPORTED_Pause | SUPPORTED_Asym_Pause; + const struct rtase_private *tp = netdev_priv(dev); + + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported, + supported); + + switch (tp->hw_ver) { + case RTASE_HW_VER_906X_7XA: + case RTASE_HW_VER_906X_7XC: + cmd->base.speed = SPEED_5000; + break; + case RTASE_HW_VER_907XD_V1: + case RTASE_HW_VER_907XD_VA: + cmd->base.speed = SPEED_10000; + break; + } + + cmd->base.duplex = DUPLEX_FULL; + cmd->base.port = PORT_MII; + cmd->base.autoneg = AUTONEG_DISABLE; + + return 0; +} + +static void rtase_get_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + const struct rtase_private *tp = netdev_priv(dev); + u16 value = rtase_r16(tp, RTASE_CPLUS_CMD); + + pause->autoneg = AUTONEG_DISABLE; + pause->tx_pause = !!(value & RTASE_FORCE_TXFLOW_EN); + pause->rx_pause = !!(value & RTASE_FORCE_RXFLOW_EN); +} + +static int rtase_set_pauseparam(struct net_device *dev, + struct ethtool_pauseparam *pause) +{ + const struct rtase_private *tp = netdev_priv(dev); + u16 value = rtase_r16(tp, RTASE_CPLUS_CMD); + + if (pause->autoneg) + return -EOPNOTSUPP; + + value &= ~(RTASE_FORCE_TXFLOW_EN | RTASE_FORCE_RXFLOW_EN); + + if (pause->tx_pause) + value |= RTASE_FORCE_TXFLOW_EN; + + if (pause->rx_pause) + value |= RTASE_FORCE_RXFLOW_EN; + + rtase_w16(tp, RTASE_CPLUS_CMD, value); + return 0; +} + +static void rtase_get_eth_mac_stats(struct net_device *dev, + struct ethtool_eth_mac_stats *stats) +{ + struct rtase_private *tp = netdev_priv(dev); + const struct rtase_counters *counters; + + counters = tp->tally_vaddr; + + rtase_dump_tally_counter(tp); + + stats->FramesTransmittedOK = le64_to_cpu(counters->tx_packets); + stats->FramesReceivedOK = le64_to_cpu(counters->rx_packets); + stats->FramesLostDueToIntMACXmitError = + le64_to_cpu(counters->tx_errors); + stats->BroadcastFramesReceivedOK = le64_to_cpu(counters->rx_broadcast); +} + +static const struct ethtool_ops rtase_ethtool_ops = { + .get_link = ethtool_op_get_link, + .get_link_ksettings = rtase_get_settings, + .get_pauseparam = rtase_get_pauseparam, + .set_pauseparam = rtase_set_pauseparam, + .get_eth_mac_stats = rtase_get_eth_mac_stats, + .get_ts_info = ethtool_op_get_ts_info, +}; + +static void rtase_init_netdev_ops(struct net_device *dev) +{ + dev->netdev_ops = &rtase_netdev_ops; + dev->ethtool_ops = &rtase_ethtool_ops; +} + +static void rtase_reset_interrupt(struct pci_dev *pdev, + const struct rtase_private *tp) +{ + if (tp->sw_flag & RTASE_SWF_MSIX_ENABLED) + pci_disable_msix(pdev); + else + pci_disable_msi(pdev); +} + +static int rtase_alloc_msix(struct pci_dev *pdev, struct rtase_private *tp) +{ + int ret, irq; + u16 i; + + memset(tp->msix_entry, 0x0, RTASE_NUM_MSIX * + sizeof(struct msix_entry)); + + for (i = 0; i < RTASE_NUM_MSIX; i++) + tp->msix_entry[i].entry = i; + + ret = pci_enable_msix_exact(pdev, tp->msix_entry, tp->int_nums); + + if (ret) + return ret; + + for (i = 0; i < tp->int_nums; i++) { + irq = pci_irq_vector(pdev, i); + if (irq < 0) { + pci_disable_msix(pdev); + return irq; + } + + tp->int_vector[i].irq = irq; + } + + return 0; +} + +static int rtase_alloc_interrupt(struct pci_dev *pdev, + struct rtase_private *tp) +{ + int ret; + + ret = rtase_alloc_msix(pdev, tp); + if (ret) { + ret = pci_enable_msi(pdev); + if (ret) { + dev_err(&pdev->dev, + "unable to alloc interrupt.(MSI)\n"); + return ret; + } + + tp->sw_flag |= RTASE_SWF_MSI_ENABLED; + } else { + tp->sw_flag |= RTASE_SWF_MSIX_ENABLED; + } + + return 0; +} + +static void rtase_init_hardware(const struct rtase_private *tp) +{ + u16 i; + + for (i = 0; i < RTASE_VLAN_FILTER_ENTRY_NUM; i++) + rtase_w32(tp, RTASE_VLAN_ENTRY_0 + i * 4, 0); +} + +static void rtase_init_int_vector(struct rtase_private *tp) +{ + u16 i; + + /* interrupt vector 0 */ + tp->int_vector[0].tp = tp; + tp->int_vector[0].index = 0; + tp->int_vector[0].imr_addr = RTASE_IMR0; + tp->int_vector[0].isr_addr = RTASE_ISR0; + tp->int_vector[0].imr = RTASE_ROK | RTASE_RDU | RTASE_TOK | + RTASE_TOK4 | RTASE_TOK5 | RTASE_TOK6 | + RTASE_TOK7; + tp->int_vector[0].poll = rtase_poll; + + memset(tp->int_vector[0].name, 0x0, sizeof(tp->int_vector[0].name)); + INIT_LIST_HEAD(&tp->int_vector[0].ring_list); + + netif_napi_add(tp->dev, &tp->int_vector[0].napi, + tp->int_vector[0].poll); + + /* interrupt vector 1 ~ 3 */ + for (i = 1; i < tp->int_nums; i++) { + tp->int_vector[i].tp = tp; + tp->int_vector[i].index = i; + tp->int_vector[i].imr_addr = RTASE_IMR1 + (i - 1) * 4; + tp->int_vector[i].isr_addr = RTASE_ISR1 + (i - 1) * 4; + tp->int_vector[i].imr = RTASE_Q_ROK | RTASE_Q_RDU | + RTASE_Q_TOK; + tp->int_vector[i].poll = rtase_poll; + + memset(tp->int_vector[i].name, 0x0, + sizeof(tp->int_vector[0].name)); + INIT_LIST_HEAD(&tp->int_vector[i].ring_list); + + netif_napi_add(tp->dev, &tp->int_vector[i].napi, + tp->int_vector[i].poll); + } +} + +static u16 rtase_calc_time_mitigation(u32 time_us) +{ + u8 msb, time_count, time_unit; + u16 int_miti; + + time_us = min_t(int, time_us, RTASE_MITI_MAX_TIME); + + msb = fls(time_us); + if (msb >= RTASE_MITI_COUNT_BIT_NUM) { + time_unit = msb - RTASE_MITI_COUNT_BIT_NUM; + time_count = time_us >> (msb - RTASE_MITI_COUNT_BIT_NUM); + } else { + time_unit = 0; + time_count = time_us; + } + + int_miti = u16_encode_bits(time_count, RTASE_MITI_TIME_COUNT_MASK) | + u16_encode_bits(time_unit, RTASE_MITI_TIME_UNIT_MASK); + + return int_miti; +} + +static u16 rtase_calc_packet_num_mitigation(u16 pkt_num) +{ + u8 msb, pkt_num_count, pkt_num_unit; + u16 int_miti; + + pkt_num = min_t(int, pkt_num, RTASE_MITI_MAX_PKT_NUM); + + if (pkt_num > 60) { + pkt_num_unit = RTASE_MITI_MAX_PKT_NUM_IDX; + pkt_num_count = pkt_num / RTASE_MITI_MAX_PKT_NUM_UNIT; + } else { + msb = fls(pkt_num); + if (msb >= RTASE_MITI_COUNT_BIT_NUM) { + pkt_num_unit = msb - RTASE_MITI_COUNT_BIT_NUM; + pkt_num_count = pkt_num >> (msb - + RTASE_MITI_COUNT_BIT_NUM); + } else { + pkt_num_unit = 0; + pkt_num_count = pkt_num; + } + } + + int_miti = u16_encode_bits(pkt_num_count, + RTASE_MITI_PKT_NUM_COUNT_MASK) | + u16_encode_bits(pkt_num_unit, + RTASE_MITI_PKT_NUM_UNIT_MASK); + + return int_miti; +} + +static void rtase_init_software_variable(struct pci_dev *pdev, + struct rtase_private *tp) +{ + u16 int_miti; + + tp->tx_queue_ctrl = RTASE_TXQ_CTRL; + tp->func_tx_queue_num = RTASE_FUNC_TXQ_NUM; + tp->func_rx_queue_num = RTASE_FUNC_RXQ_NUM; + tp->int_nums = RTASE_INTERRUPT_NUM; + + int_miti = rtase_calc_time_mitigation(RTASE_MITI_DEFAULT_TIME) | + rtase_calc_packet_num_mitigation(RTASE_MITI_DEFAULT_PKT_NUM); + tp->tx_int_mit = int_miti; + tp->rx_int_mit = int_miti; + + tp->sw_flag = 0; + + rtase_init_int_vector(tp); + + /* MTU range: 60 - hw-specific max */ + tp->dev->min_mtu = ETH_ZLEN; + tp->dev->max_mtu = RTASE_MAX_JUMBO_SIZE; +} + +static int rtase_check_mac_version_valid(struct rtase_private *tp) +{ + int ret = -ENODEV; + + tp->hw_ver = rtase_r32(tp, RTASE_TX_CONFIG_0) & RTASE_HW_VER_MASK; + + switch (tp->hw_ver) { + case RTASE_HW_VER_906X_7XA: + case RTASE_HW_VER_906X_7XC: + case RTASE_HW_VER_907XD_V1: + case RTASE_HW_VER_907XD_VA: + ret = 0; + break; + } + + return ret; +} + +static int rtase_init_board(struct pci_dev *pdev, struct net_device **dev_out, + void __iomem **ioaddr_out) +{ + struct net_device *dev; + void __iomem *ioaddr; + int ret = -ENOMEM; + + /* dev zeroed in alloc_etherdev */ + dev = alloc_etherdev_mq(sizeof(struct rtase_private), + RTASE_FUNC_TXQ_NUM); + if (!dev) + goto err_out; + + SET_NETDEV_DEV(dev, &pdev->dev); + + ret = pci_enable_device(pdev); + if (ret) + goto err_out_free_dev; + + /* make sure PCI base addr 1 is MMIO */ + if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { + ret = -ENODEV; + goto err_out_disable; + } + + /* check for weird/broken PCI region reporting */ + if (pci_resource_len(pdev, 2) < RTASE_REGS_SIZE) { + ret = -ENODEV; + goto err_out_disable; + } + + ret = pci_request_regions(pdev, KBUILD_MODNAME); + if (ret) + goto err_out_disable; + + ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); + if (ret) { + dev_err(&pdev->dev, "no usable dma addressing method\n"); + goto err_out_free_res; + } + + pci_set_master(pdev); + + /* ioremap MMIO region */ + ioaddr = ioremap(pci_resource_start(pdev, 2), + pci_resource_len(pdev, 2)); + if (!ioaddr) { + ret = -EIO; + goto err_out_free_res; + } + + *ioaddr_out = ioaddr; + *dev_out = dev; + + return ret; + +err_out_free_res: + pci_release_regions(pdev); + +err_out_disable: + pci_disable_device(pdev); + +err_out_free_dev: + free_netdev(dev); + +err_out: + *ioaddr_out = NULL; + *dev_out = NULL; + + return ret; +} + +static void rtase_release_board(struct pci_dev *pdev, struct net_device *dev, + void __iomem *ioaddr) +{ + const struct rtase_private *tp = netdev_priv(dev); + + rtase_rar_set(tp, tp->dev->perm_addr); + iounmap(ioaddr); + + if (tp->sw_flag & RTASE_SWF_MSIX_ENABLED) + pci_disable_msix(pdev); + else + pci_disable_msi(pdev); + + pci_release_regions(pdev); + pci_disable_device(pdev); + free_netdev(dev); +} + +static int rtase_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + struct net_device *dev = NULL; + struct rtase_int_vector *ivec; + void __iomem *ioaddr = NULL; + struct rtase_private *tp; + int ret, i; + + if (!pdev->is_physfn && pdev->is_virtfn) { + dev_err(&pdev->dev, + "This module does not support a virtual function."); + return -EINVAL; + } + + dev_dbg(&pdev->dev, "Automotive Switch Ethernet driver loaded\n"); + + ret = rtase_init_board(pdev, &dev, &ioaddr); + if (ret) + return ret; + + tp = netdev_priv(dev); + tp->mmio_addr = ioaddr; + tp->dev = dev; + tp->pdev = pdev; + + /* identify chip attached to board */ + ret = rtase_check_mac_version_valid(tp); + if (ret) { + dev_err(&pdev->dev, + "unknown chip version: 0x%08x, contact rtase maintainers (see MAINTAINERS file)\n", + tp->hw_ver); + goto err_out_release_board; + } + + rtase_init_software_variable(pdev, tp); + rtase_init_hardware(tp); + + ret = rtase_alloc_interrupt(pdev, tp); + if (ret) { + dev_err(&pdev->dev, "unable to alloc MSIX/MSI\n"); + goto err_out_del_napi; + } + + rtase_init_netdev_ops(dev); + + dev->pcpu_stat_type = NETDEV_PCPU_STAT_TSTATS; + + dev->features |= NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_IP_CSUM | NETIF_F_HIGHDMA | + NETIF_F_RXCSUM | NETIF_F_SG | + NETIF_F_TSO | NETIF_F_IPV6_CSUM | + NETIF_F_TSO6; + + dev->hw_features = NETIF_F_SG | NETIF_F_IP_CSUM | + NETIF_F_TSO | NETIF_F_RXCSUM | + NETIF_F_HW_VLAN_CTAG_TX | NETIF_F_HW_VLAN_CTAG_RX | + NETIF_F_RXALL | NETIF_F_RXFCS | + NETIF_F_IPV6_CSUM | NETIF_F_TSO6; + + dev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO | + NETIF_F_HIGHDMA; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + netif_set_tso_max_size(dev, RTASE_LSO_64K); + netif_set_tso_max_segs(dev, RTASE_NIC_MAX_PHYS_BUF_COUNT_LSO2); + + rtase_get_mac_address(dev); + + tp->tally_vaddr = dma_alloc_coherent(&pdev->dev, + sizeof(*tp->tally_vaddr), + &tp->tally_paddr, + GFP_KERNEL); + if (!tp->tally_vaddr) { + ret = -ENOMEM; + goto err_out_free_dma; + } + + rtase_tally_counter_clear(tp); + + pci_set_drvdata(pdev, dev); + + netif_carrier_off(dev); + + ret = register_netdev(dev); + if (ret) + goto err_out_free_dma; + + netdev_dbg(dev, "%pM, IRQ %d\n", dev->dev_addr, dev->irq); + + return 0; + +err_out_free_dma: + if (tp->tally_vaddr) { + dma_free_coherent(&pdev->dev, + sizeof(*tp->tally_vaddr), + tp->tally_vaddr, + tp->tally_paddr); + + tp->tally_vaddr = NULL; + } + +err_out_del_napi: + for (i = 0; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + netif_napi_del(&ivec->napi); + } + +err_out_release_board: + rtase_release_board(pdev, dev, ioaddr); + + return ret; +} + +static void rtase_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct rtase_private *tp = netdev_priv(dev); + struct rtase_int_vector *ivec; + u32 i; + + unregister_netdev(dev); + + for (i = 0; i < tp->int_nums; i++) { + ivec = &tp->int_vector[i]; + netif_napi_del(&ivec->napi); + } + + rtase_reset_interrupt(pdev, tp); + if (tp->tally_vaddr) { + dma_free_coherent(&pdev->dev, + sizeof(*tp->tally_vaddr), + tp->tally_vaddr, + tp->tally_paddr); + tp->tally_vaddr = NULL; + } + + rtase_release_board(pdev, dev, tp->mmio_addr); + pci_set_drvdata(pdev, NULL); +} + +static void rtase_shutdown(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + const struct rtase_private *tp; + + tp = netdev_priv(dev); + + if (netif_running(dev)) + rtase_close(dev); + + rtase_reset_interrupt(pdev, tp); +} + +static int rtase_suspend(struct device *device) +{ + struct net_device *dev = dev_get_drvdata(device); + + if (netif_running(dev)) { + netif_device_detach(dev); + rtase_hw_reset(dev); + } + + return 0; +} + +static int rtase_resume(struct device *device) +{ + struct net_device *dev = dev_get_drvdata(device); + struct rtase_private *tp = netdev_priv(dev); + int ret; + + /* restore last modified mac address */ + rtase_rar_set(tp, dev->dev_addr); + + if (!netif_running(dev)) + goto out; + + rtase_wait_for_quiescence(dev); + + rtase_tx_clear(tp); + rtase_rx_clear(tp); + + ret = rtase_init_ring(dev); + if (ret) { + netdev_err(dev, "unable to init ring\n"); + rtase_free_desc(tp); + return -ENOMEM; + } + + rtase_hw_config(dev); + /* always link, so start to transmit & receive */ + rtase_hw_start(dev); + + netif_device_attach(dev); +out: + + return 0; +} + +static const struct dev_pm_ops rtase_pm_ops = { + SYSTEM_SLEEP_PM_OPS(rtase_suspend, rtase_resume) +}; + +static struct pci_driver rtase_pci_driver = { + .name = KBUILD_MODNAME, + .id_table = rtase_pci_tbl, + .probe = rtase_init_one, + .remove = rtase_remove_one, + .shutdown = rtase_shutdown, + .driver.pm = pm_ptr(&rtase_pm_ops), +}; + +module_pci_driver(rtase_pci_driver); |