r8169: update

Signed-off-by: AuxXxilium <info@auxxxilium.tech>
This commit is contained in:
AuxXxilium 2024-06-13 19:10:12 +02:00
parent 670e669178
commit 3ca1a3b749
5 changed files with 439 additions and 206 deletions

View File

@ -1,20 +1,44 @@
# SPDX-License-Identifier: GPL-2.0-only
################################################################################
#
# Makefile for the Realtek network device drivers.
# r8169 is the Linux device driver released for Realtek Gigabit Ethernet
# controllers with PCI-Express interface.
#
# Author:
# Copyright (c) 2002 ShuChen <shuchen@realtek.com.tw>
# Copyright (c) 2003 - 2007 Francois Romieu <romieu@fr.zoreil.com>
# Copyright (c) a lot of people too. Please respect their work.
#
################################################################################
CONFIG_R8169 = m
################################################################################
# This product is covered by one or more of the following patents:
# US6,570,884, US6,115,776, and US6,327,625.
################################################################################
ENABLE_INCLUDE_R8168 = n
ENABLE_INCLUDE_R8125 = n
# Set the kernel build directory
KDIR ?= "/lib/modules/$(shell uname -r)/build"
# Directory for module updates
MUPDATE ?= "/lib/modules/$(shell uname -r)/updates"
# Hash for signing
HASH = sha3-512
obj-m := r8169.o
r8169-objs := r8169_main.o r8169_firmware.o r8169_phy_config.o r8169_leds.o
ifeq ($(ENABLE_INCLUDE_R8168), y)
EXTRA_CFLAGS += -DINCLUDE_R8168
all:
$(MAKE) -C $(KDIR) M=$(PWD) modules
modules_install:
$(MAKE) -C $(KDIR) M=$(PWD) modules_install
clean:
$(MAKE) -C $(KDIR) M=$(PWD) clean
ifdef $(MUPDATE)
$(MAKE) -c $(KDIR) M=$(MUPDATE) clean
endif
ifeq ($(ENABLE_INCLUDE_R8125), y)
EXTRA_CFLAGS += -DINCLUDE_R8125
endif
sign:
/usr/src/linux/scripts/sign-file $(HASH) /usr/src/linux/certs/signing_key.pem /usr/src/linux/certs/signing_key.x509 r8169.ko
r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o
obj-$(CONFIG_R8169) += r8169.o
.PHONY: all modules_install clean sign

13
r8169.h
View File

@ -8,6 +8,7 @@
* See MAINTAINERS file for support contact information.
*/
#include <linux/netdevice.h>
#include <linux/types.h>
#include <linux/phy.h>
@ -71,9 +72,21 @@ enum mac_version {
};
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);
u8 rtl8168d_efuse_read(struct rtl8169_private *tp, int reg_addr);
void r8169_hw_phy_config(struct rtl8169_private *tp, struct phy_device *phydev,
enum mac_version ver);
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);
struct r8169_led_classdev *rtl8168_init_leds(struct net_device *ndev);
void r8169_remove_leds(struct r8169_led_classdev *leds);
int r8169_get_wolparam(void);
void r8169_set_wolparam(int state);

View File

@ -151,9 +151,6 @@ void rtl_fw_write_firmware(struct rtl8169_private *tp, struct rtl_fw *rtl_fw)
u32 regno = (action & 0x0fff0000) >> 16;
enum rtl_fw_opcode opcode = action >> 28;
if (!action)
break;
switch (opcode) {
case PHY_READ:
predata = fw_read(tp, regno);

168
r8169_leds.c Normal file
View File

@ -0,0 +1,168 @@
// SPDX-License-Identifier: GPL-2.0-only
/* r8169_leds.c: Realtek 8169/8168/8101/8125 ethernet driver.
*
* Copyright (c) 2023 Heiner Kallweit <hkallweit1@gmail.com>
*
* See MAINTAINERS file for support contact information.
*/
#include <linux/leds.h>
#include <linux/netdevice.h>
#include <uapi/linux/uleds.h>
#include "r8169.h"
#define RTL8168_LED_CTRL_OPTION2 BIT(15)
#define RTL8168_LED_CTRL_ACT BIT(3)
#define RTL8168_LED_CTRL_LINK_1000 BIT(2)
#define RTL8168_LED_CTRL_LINK_100 BIT(1)
#define RTL8168_LED_CTRL_LINK_10 BIT(0)
#define RTL8168_NUM_LEDS 3
#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))
struct r8169_led_classdev {
struct led_classdev led;
struct net_device *ndev;
int index;
};
#define lcdev_to_r8169_ldev(lcdev) container_of(lcdev, struct r8169_led_classdev, led)
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;
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,
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;
u16 mode = 0;
if (flags & BIT(TRIGGER_NETDEV_LINK_10))
mode |= RTL8168_LED_CTRL_LINK_10;
if (flags & BIT(TRIGGER_NETDEV_LINK_100))
mode |= RTL8168_LED_CTRL_LINK_100;
if (flags & BIT(TRIGGER_NETDEV_LINK_1000))
mode |= RTL8168_LED_CTRL_LINK_1000;
if (flags & BIT(TRIGGER_NETDEV_TX))
mode |= RTL8168_LED_CTRL_ACT;
return rtl8168_led_mod_ctrl(tp, 0x000f << shift, mode << shift);
}
static int rtl8168_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 shift = ldev->index * 4;
int mode;
mode = rtl8168_get_led_mode(tp);
if (mode < 0)
return mode;
if (mode & RTL8168_LED_CTRL_OPTION2) {
rtl8168_led_mod_ctrl(tp, RTL8168_LED_CTRL_OPTION2, 0);
netdev_notice(ldev->ndev, "Deactivating unsupported Option2 LED mode\n");
}
mode = (mode >> shift) & 0x000f;
if (mode & RTL8168_LED_CTRL_ACT)
*flags |= BIT(TRIGGER_NETDEV_TX) | BIT(TRIGGER_NETDEV_RX);
if (mode & RTL8168_LED_CTRL_LINK_10)
*flags |= BIT(TRIGGER_NETDEV_LINK_10);
if (mode & RTL8168_LED_CTRL_LINK_100)
*flags |= BIT(TRIGGER_NETDEV_LINK_100);
if (mode & RTL8168_LED_CTRL_LINK_1000)
*flags |= BIT(TRIGGER_NETDEV_LINK_1000);
return 0;
}
static struct device *
r8169_led_hw_control_get_device(struct led_classdev *led_cdev)
{
struct r8169_led_classdev *ldev = lcdev_to_r8169_ldev(led_cdev);
return &ldev->ndev->dev;
}
static void rtl8168_setup_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->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;
led_cdev->hw_control_set = rtl8168_led_hw_control_set;
led_cdev->hw_control_get = rtl8168_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 *rtl8168_init_leds(struct net_device *ndev)
{
struct r8169_led_classdev *leds;
int i;
leds = kcalloc(RTL8168_NUM_LEDS + 1, sizeof(*leds), GFP_KERNEL);
if (!leds)
return NULL;
for (i = 0; i < RTL8168_NUM_LEDS; i++)
rtl8168_setup_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);
}

View File

@ -56,10 +56,6 @@
#define FIRMWARE_8125A_3 "rtl_nic/rtl8125a-3.fw"
#define FIRMWARE_8125B_2 "rtl_nic/rtl8125b-2.fw"
/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast).
The RTL chips use a 64 element hash table based on the Ethernet CRC. */
#define MC_FILTER_LIMIT 32
#define TX_DMA_BURST 7 /* Maximum PCI burst, '7' is unlimited */
#define InterFrameGap 0x03 /* 3 means InterFrameGap = the shortest one */
@ -89,6 +85,10 @@
#define JUMBO_7K (7 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
#define JUMBO_9K (9 * SZ_1K - VLAN_ETH_HLEN - ETH_FCS_LEN)
static int wol_param = 1;
module_param(wol_param, int, 0);
MODULE_PARM_DESC(wol_param, "Current state of system WOL");
static const struct {
const char *name;
const char *fw_name;
@ -142,56 +142,27 @@ static const struct {
[RTL_GIGA_MAC_VER_63] = {"RTL8125B", FIRMWARE_8125B_2},
};
/*
author: Realtek and the Linux r8168 crew <netdev@vger.kernel.org>
srcversion: D2B16DB8E92DC6B16FB1E04
alias: pci:v00001186d00004300sv00001186sd00004B10bc*sc*i*
alias: pci:v000010ECd00002600sv*sd*bc*sc*i*
alias: pci:v000010ECd00002502sv*sd*bc*sc*i*
alias: pci:v000010ECd00008161sv*sd*bc*sc*i*
alias: pci:v000010ECd00008168sv*sd*bc*sc*i*
author: Realtek and the Linux r8125 crew <netdev@vger.kernel.org>
srcversion: 80AA932EEAEA9E2392B4B5E
alias: pci:v000010ECd00005000sv*sd*bc*sc*i*
alias: pci:v000010ECd00008126sv*sd*bc*sc*i*
alias: pci:v000010ECd00003000sv*sd*bc*sc*i*
alias: pci:v000010ECd00008162sv*sd*bc*sc*i*
alias: pci:v000010ECd00008125sv*sd*bc*sc*i*
*/
static const struct pci_device_id rtl8169_pci_tbl[] = {
#ifdef INCLUDE_R8168
{ PCI_VDEVICE(REALTEK, 0x2502) },
{ PCI_VDEVICE(REALTEK, 0x2600) },
#endif
{ PCI_VDEVICE(REALTEK, 0x8129) },
{ PCI_VDEVICE(REALTEK, 0x8136), RTL_CFG_NO_GBIT },
#ifdef INCLUDE_R8168
{ PCI_VDEVICE(REALTEK, 0x8161) },
#endif
#ifdef INCLUDE_R8125
{ PCI_VDEVICE(REALTEK, 0x8162) },
#endif
{ PCI_VDEVICE(REALTEK, 0x8167) },
#ifdef INCLUDE_R8168
{ PCI_VDEVICE(REALTEK, 0x8168) },
#endif
{ PCI_VDEVICE(NCUBE, 0x8168) },
{ PCI_VDEVICE(REALTEK, 0x8169) },
#ifdef INCLUDE_R8168
{ PCI_VENDOR_ID_DLINK, 0x4300,
PCI_VENDOR_ID_DLINK, 0x4b10, 0, 0 },
#endif
{ PCI_VDEVICE(DLINK, 0x4300) },
{ PCI_VDEVICE(DLINK, 0x4302) },
{ PCI_VDEVICE(AT, 0xc107) },
{ PCI_VDEVICE(USR, 0x0116) },
{ PCI_VENDOR_ID_LINKSYS, 0x1032, PCI_ANY_ID, 0x0024 },
{ 0x0001, 0x8168, PCI_ANY_ID, 0x2410 },
#ifdef INCLUDE_R8125
{ PCI_VDEVICE(REALTEK, 0x8125) },
{ PCI_VDEVICE(REALTEK, 0x3000) },
#endif
{}
};
@ -225,6 +196,7 @@ enum rtl_registers {
/* No threshold before first PCI xfer */
#define RX_FIFO_THRESH (7 << RXCFG_FIFO_SHIFT)
#define RX_EARLY_OFF (1 << 11)
#define RX_PAUSE_SLOT_ON (1 << 11) /* 8125b and later */
#define RXCFG_DMA_SHIFT 8
/* Unlimited maximum PCI burst. */
#define RX_DMA_BURST (7 << RXCFG_DMA_SHIFT)
@ -317,6 +289,7 @@ enum rtl8168_8101_registers {
};
enum rtl8168_registers {
LED_CTRL = 0x18,
LED_FREQ = 0x1a,
EEE_LED = 0x1b,
ERIDR = 0x70,
@ -608,6 +581,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
};
@ -647,12 +621,14 @@ struct rtl8169_private {
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;
dma_addr_t counters_phys_addr;
struct rtl8169_counters *counters;
struct rtl8169_tc_offsets tc_offset;
@ -662,6 +638,8 @@ struct rtl8169_private {
const char *fw_name;
struct rtl_fw *rtl_fw;
struct r8169_led_classdev *leds;
u32 ocp_base;
};
@ -818,6 +796,62 @@ static const struct rtl_cond name = { \
\
static bool name ## _check(struct rtl8169_private *tp)
int rtl8168_led_mod_ctrl(struct rtl8169_private *tp, u16 mask, u16 val)
{
struct device *dev = tp_to_dev(tp);
int ret;
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;
mutex_lock(&tp->led_lock);
RTL_W16(tp, LED_CTRL, (RTL_R16(tp, LED_CTRL) & ~mask) | val);
mutex_unlock(&tp->led_lock);
pm_runtime_put_sync(dev);
return 0;
}
int rtl8168_get_led_mode(struct rtl8169_private *tp)
{
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, LED_CTRL);
pm_runtime_put_sync(dev);
return ret;
}
void r8169_get_led_name(struct rtl8169_private *tp, int idx,
char *buf, int buf_len)
{
struct pci_dev *pdev = tp->pci_dev;
char pdom[8], pfun[8];
int domain;
domain = pci_domain_nr(pdev->bus);
if (domain)
snprintf(pdom, sizeof(pdom), "P%d", domain);
else
pdom[0] = '\0';
if (pdev->multifunction)
snprintf(pfun, sizeof(pfun), "f%d", PCI_FUNC(pdev->devfn));
else
pfun[0] = '\0';
snprintf(buf, buf_len, "en%sp%ds%d%s-%d::lan", pdom, pdev->bus->number,
PCI_SLOT(pdev->devfn), pfun, idx);
}
static void r8168fp_adjust_ocp_cmd(struct rtl8169_private *tp, u32 *cmd, int type)
{
/* based on RTL8168FP_OOBMAC_BASE in vendor driver */
@ -1227,17 +1261,40 @@ static void rtl8168ep_stop_cmac(struct rtl8169_private *tp)
RTL_W8(tp, IBCR0, RTL_R8(tp, IBCR0) & ~0x01);
}
static void rtl_dash_loop_wait(struct rtl8169_private *tp,
const struct rtl_cond *c,
unsigned long usecs, int n, bool high)
{
if (!tp->dash_enabled)
return;
rtl_loop_wait(tp, c, usecs, n, high);
}
static void rtl_dash_loop_wait_high(struct rtl8169_private *tp,
const struct rtl_cond *c,
unsigned long d, int n)
{
rtl_dash_loop_wait(tp, c, d, n, true);
}
static void rtl_dash_loop_wait_low(struct rtl8169_private *tp,
const struct rtl_cond *c,
unsigned long d, int n)
{
rtl_dash_loop_wait(tp, c, d, n, false);
}
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);
rtl_dash_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, 10);
rtl_dash_loop_wait_high(tp, &rtl_ep_ocp_read_cond, 10000, 30);
}
static void rtl8168_driver_start(struct rtl8169_private *tp)
@ -1251,7 +1308,7 @@ 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);
rtl_dash_loop_wait_low(tp, &rtl_dp_ocp_read_cond, 10000, 10);
}
static void rtl8168ep_driver_stop(struct rtl8169_private *tp)
@ -1259,7 +1316,7 @@ 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);
rtl_dash_loop_wait_low(tp, &rtl_ep_ocp_read_cond, 10000, 10);
}
static void rtl8168_driver_stop(struct rtl8169_private *tp)
@ -1282,14 +1339,26 @@ static bool r8168ep_check_dash(struct rtl8169_private *tp)
return r8168ep_ocp_read(tp, 0x128) & BIT(0);
}
static enum rtl_dash_type rtl_check_dash(struct rtl8169_private *tp)
static bool rtl_dash_is_enabled(struct rtl8169_private *tp)
{
switch (tp->dash_type) {
case RTL_DASH_DP:
return r8168dp_check_dash(tp);
case RTL_DASH_EP:
return r8168ep_check_dash(tp);
default:
return false;
}
}
static enum rtl_dash_type rtl_get_dash_type(struct rtl8169_private *tp)
{
switch (tp->mac_version) {
case RTL_GIGA_MAC_VER_28:
case RTL_GIGA_MAC_VER_31:
return r8168dp_check_dash(tp) ? RTL_DASH_DP : RTL_DASH_NONE;
return RTL_DASH_DP;
case RTL_GIGA_MAC_VER_51 ... RTL_GIGA_MAC_VER_53:
return r8168ep_check_dash(tp) ? RTL_DASH_EP : RTL_DASH_NONE;
return RTL_DASH_EP;
default:
return RTL_DASH_NONE;
}
@ -1408,6 +1477,14 @@ static void rtl_link_chg_patch(struct rtl8169_private *tp)
#define WAKE_ANY (WAKE_PHY | WAKE_MAGIC | WAKE_UCAST | WAKE_BCAST | WAKE_MCAST)
int r8169_get_wolparam(void) {
return wol_param;
}
void r8169_set_wolparam(int state) {
wol_param = state;
}
static void rtl8169_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
{
struct rtl8169_private *tp = netdev_priv(dev);
@ -1482,7 +1559,7 @@ static void __rtl8169_set_wol(struct rtl8169_private *tp, u32 wolopts)
device_set_wakeup_enable(tp_to_dev(tp), wolopts);
if (tp->dash_type == RTL_DASH_NONE) {
if (!tp->dash_enabled) {
rtl_set_d3_pll_down(tp, !wolopts);
tp->dev->wol_enabled = wolopts ? 1 : 0;
}
@ -2247,6 +2324,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);
}
@ -2321,9 +2401,13 @@ static void rtl_init_rxcfg(struct rtl8169_private *tp)
case RTL_GIGA_MAC_VER_40 ... RTL_GIGA_MAC_VER_53:
RTL_W32(tp, RxConfig, RX128_INT_EN | RX_MULTI_EN | RX_DMA_BURST | RX_EARLY_OFF);
break;
case RTL_GIGA_MAC_VER_61 ... RTL_GIGA_MAC_VER_63:
case RTL_GIGA_MAC_VER_61:
RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST);
break;
case RTL_GIGA_MAC_VER_63:
RTL_W32(tp, RxConfig, RX_FETCH_DFLT_8125 | RX_DMA_BURST |
RX_PAUSE_SLOT_ON);
break;
default:
RTL_W32(tp, RxConfig, RX128_INT_EN | RX_DMA_BURST);
break;
@ -2541,7 +2625,7 @@ static void rtl_wol_enable_rx(struct rtl8169_private *tp)
static void rtl_prepare_power_down(struct rtl8169_private *tp)
{
if (tp->dash_type != RTL_DASH_NONE)
if (tp->dash_enabled)
return;
if (tp->mac_version == RTL_GIGA_MAC_VER_32 ||
@ -2611,8 +2695,9 @@ static void rtl_set_rx_mode(struct net_device *dev)
if (dev->flags & IFF_PROMISC) {
rx_mode |= AcceptAllPhys;
} else if (netdev_mc_count(dev) > MC_FILTER_LIMIT ||
dev->flags & IFF_ALLMULTI ||
} else if (!(dev->flags & IFF_MULTICAST)) {
rx_mode &= ~AcceptMulticast;
} else if (dev->flags & IFF_ALLMULTI ||
tp->mac_version == RTL_GIGA_MAC_VER_35) {
/* accept all multicasts */
} else if (netdev_mc_empty(dev)) {
@ -3114,6 +3199,33 @@ static void rtl_hw_start_8168g_2(struct rtl8169_private *tp)
rtl_ephy_init(tp, e_info_8168g_2);
}
static void rtl8411b_fix_phy_down(struct rtl8169_private *tp)
{
static const u16 fix_data[] = {
/* 0xf800 */ 0xe008, 0xe00a, 0xe00c, 0xe00e, 0xe027, 0xe04f, 0xe05e, 0xe065,
/* 0xf810 */ 0xc602, 0xbe00, 0x0000, 0xc502, 0xbd00, 0x074c, 0xc302, 0xbb00,
/* 0xf820 */ 0x080a, 0x6420, 0x48c2, 0x8c20, 0xc516, 0x64a4, 0x49c0, 0xf009,
/* 0xf830 */ 0x74a2, 0x8ca5, 0x74a0, 0xc50e, 0x9ca2, 0x1c11, 0x9ca0, 0xe006,
/* 0xf840 */ 0x74f8, 0x48c4, 0x8cf8, 0xc404, 0xbc00, 0xc403, 0xbc00, 0x0bf2,
/* 0xf850 */ 0x0c0a, 0xe434, 0xd3c0, 0x49d9, 0xf01f, 0xc526, 0x64a5, 0x1400,
/* 0xf860 */ 0xf007, 0x0c01, 0x8ca5, 0x1c15, 0xc51b, 0x9ca0, 0xe013, 0xc519,
/* 0xf870 */ 0x74a0, 0x48c4, 0x8ca0, 0xc516, 0x74a4, 0x48c8, 0x48ca, 0x9ca4,
/* 0xf880 */ 0xc512, 0x1b00, 0x9ba0, 0x1b1c, 0x483f, 0x9ba2, 0x1b04, 0xc508,
/* 0xf890 */ 0x9ba0, 0xc505, 0xbd00, 0xc502, 0xbd00, 0x0300, 0x051e, 0xe434,
/* 0xf8a0 */ 0xe018, 0xe092, 0xde20, 0xd3c0, 0xc50f, 0x76a4, 0x49e3, 0xf007,
/* 0xf8b0 */ 0x49c0, 0xf103, 0xc607, 0xbe00, 0xc606, 0xbe00, 0xc602, 0xbe00,
/* 0xf8c0 */ 0x0c4c, 0x0c28, 0x0c2c, 0xdc00, 0xc707, 0x1d00, 0x8de2, 0x48c1,
/* 0xf8d0 */ 0xc502, 0xbd00, 0x00aa, 0xe0c0, 0xc502, 0xbd00, 0x0132
};
unsigned long flags;
int i;
raw_spin_lock_irqsave(&tp->mac_ocp_lock, flags);
for (i = 0; i < ARRAY_SIZE(fix_data); i++)
__r8168_mac_ocp_write(tp, 0xf800 + 2 * i, fix_data[i]);
raw_spin_unlock_irqrestore(&tp->mac_ocp_lock, flags);
}
static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
{
static const struct ephy_info e_info_8411_2[] = {
@ -3147,117 +3259,7 @@ static void rtl_hw_start_8411_2(struct rtl8169_private *tp)
mdelay(3);
r8168_mac_ocp_write(tp, 0xFC26, 0x0000);
r8168_mac_ocp_write(tp, 0xF800, 0xE008);
r8168_mac_ocp_write(tp, 0xF802, 0xE00A);
r8168_mac_ocp_write(tp, 0xF804, 0xE00C);
r8168_mac_ocp_write(tp, 0xF806, 0xE00E);
r8168_mac_ocp_write(tp, 0xF808, 0xE027);
r8168_mac_ocp_write(tp, 0xF80A, 0xE04F);
r8168_mac_ocp_write(tp, 0xF80C, 0xE05E);
r8168_mac_ocp_write(tp, 0xF80E, 0xE065);
r8168_mac_ocp_write(tp, 0xF810, 0xC602);
r8168_mac_ocp_write(tp, 0xF812, 0xBE00);
r8168_mac_ocp_write(tp, 0xF814, 0x0000);
r8168_mac_ocp_write(tp, 0xF816, 0xC502);
r8168_mac_ocp_write(tp, 0xF818, 0xBD00);
r8168_mac_ocp_write(tp, 0xF81A, 0x074C);
r8168_mac_ocp_write(tp, 0xF81C, 0xC302);
r8168_mac_ocp_write(tp, 0xF81E, 0xBB00);
r8168_mac_ocp_write(tp, 0xF820, 0x080A);
r8168_mac_ocp_write(tp, 0xF822, 0x6420);
r8168_mac_ocp_write(tp, 0xF824, 0x48C2);
r8168_mac_ocp_write(tp, 0xF826, 0x8C20);
r8168_mac_ocp_write(tp, 0xF828, 0xC516);
r8168_mac_ocp_write(tp, 0xF82A, 0x64A4);
r8168_mac_ocp_write(tp, 0xF82C, 0x49C0);
r8168_mac_ocp_write(tp, 0xF82E, 0xF009);
r8168_mac_ocp_write(tp, 0xF830, 0x74A2);
r8168_mac_ocp_write(tp, 0xF832, 0x8CA5);
r8168_mac_ocp_write(tp, 0xF834, 0x74A0);
r8168_mac_ocp_write(tp, 0xF836, 0xC50E);
r8168_mac_ocp_write(tp, 0xF838, 0x9CA2);
r8168_mac_ocp_write(tp, 0xF83A, 0x1C11);
r8168_mac_ocp_write(tp, 0xF83C, 0x9CA0);
r8168_mac_ocp_write(tp, 0xF83E, 0xE006);
r8168_mac_ocp_write(tp, 0xF840, 0x74F8);
r8168_mac_ocp_write(tp, 0xF842, 0x48C4);
r8168_mac_ocp_write(tp, 0xF844, 0x8CF8);
r8168_mac_ocp_write(tp, 0xF846, 0xC404);
r8168_mac_ocp_write(tp, 0xF848, 0xBC00);
r8168_mac_ocp_write(tp, 0xF84A, 0xC403);
r8168_mac_ocp_write(tp, 0xF84C, 0xBC00);
r8168_mac_ocp_write(tp, 0xF84E, 0x0BF2);
r8168_mac_ocp_write(tp, 0xF850, 0x0C0A);
r8168_mac_ocp_write(tp, 0xF852, 0xE434);
r8168_mac_ocp_write(tp, 0xF854, 0xD3C0);
r8168_mac_ocp_write(tp, 0xF856, 0x49D9);
r8168_mac_ocp_write(tp, 0xF858, 0xF01F);
r8168_mac_ocp_write(tp, 0xF85A, 0xC526);
r8168_mac_ocp_write(tp, 0xF85C, 0x64A5);
r8168_mac_ocp_write(tp, 0xF85E, 0x1400);
r8168_mac_ocp_write(tp, 0xF860, 0xF007);
r8168_mac_ocp_write(tp, 0xF862, 0x0C01);
r8168_mac_ocp_write(tp, 0xF864, 0x8CA5);
r8168_mac_ocp_write(tp, 0xF866, 0x1C15);
r8168_mac_ocp_write(tp, 0xF868, 0xC51B);
r8168_mac_ocp_write(tp, 0xF86A, 0x9CA0);
r8168_mac_ocp_write(tp, 0xF86C, 0xE013);
r8168_mac_ocp_write(tp, 0xF86E, 0xC519);
r8168_mac_ocp_write(tp, 0xF870, 0x74A0);
r8168_mac_ocp_write(tp, 0xF872, 0x48C4);
r8168_mac_ocp_write(tp, 0xF874, 0x8CA0);
r8168_mac_ocp_write(tp, 0xF876, 0xC516);
r8168_mac_ocp_write(tp, 0xF878, 0x74A4);
r8168_mac_ocp_write(tp, 0xF87A, 0x48C8);
r8168_mac_ocp_write(tp, 0xF87C, 0x48CA);
r8168_mac_ocp_write(tp, 0xF87E, 0x9CA4);
r8168_mac_ocp_write(tp, 0xF880, 0xC512);
r8168_mac_ocp_write(tp, 0xF882, 0x1B00);
r8168_mac_ocp_write(tp, 0xF884, 0x9BA0);
r8168_mac_ocp_write(tp, 0xF886, 0x1B1C);
r8168_mac_ocp_write(tp, 0xF888, 0x483F);
r8168_mac_ocp_write(tp, 0xF88A, 0x9BA2);
r8168_mac_ocp_write(tp, 0xF88C, 0x1B04);
r8168_mac_ocp_write(tp, 0xF88E, 0xC508);
r8168_mac_ocp_write(tp, 0xF890, 0x9BA0);
r8168_mac_ocp_write(tp, 0xF892, 0xC505);
r8168_mac_ocp_write(tp, 0xF894, 0xBD00);
r8168_mac_ocp_write(tp, 0xF896, 0xC502);
r8168_mac_ocp_write(tp, 0xF898, 0xBD00);
r8168_mac_ocp_write(tp, 0xF89A, 0x0300);
r8168_mac_ocp_write(tp, 0xF89C, 0x051E);
r8168_mac_ocp_write(tp, 0xF89E, 0xE434);
r8168_mac_ocp_write(tp, 0xF8A0, 0xE018);
r8168_mac_ocp_write(tp, 0xF8A2, 0xE092);
r8168_mac_ocp_write(tp, 0xF8A4, 0xDE20);
r8168_mac_ocp_write(tp, 0xF8A6, 0xD3C0);
r8168_mac_ocp_write(tp, 0xF8A8, 0xC50F);
r8168_mac_ocp_write(tp, 0xF8AA, 0x76A4);
r8168_mac_ocp_write(tp, 0xF8AC, 0x49E3);
r8168_mac_ocp_write(tp, 0xF8AE, 0xF007);
r8168_mac_ocp_write(tp, 0xF8B0, 0x49C0);
r8168_mac_ocp_write(tp, 0xF8B2, 0xF103);
r8168_mac_ocp_write(tp, 0xF8B4, 0xC607);
r8168_mac_ocp_write(tp, 0xF8B6, 0xBE00);
r8168_mac_ocp_write(tp, 0xF8B8, 0xC606);
r8168_mac_ocp_write(tp, 0xF8BA, 0xBE00);
r8168_mac_ocp_write(tp, 0xF8BC, 0xC602);
r8168_mac_ocp_write(tp, 0xF8BE, 0xBE00);
r8168_mac_ocp_write(tp, 0xF8C0, 0x0C4C);
r8168_mac_ocp_write(tp, 0xF8C2, 0x0C28);
r8168_mac_ocp_write(tp, 0xF8C4, 0x0C2C);
r8168_mac_ocp_write(tp, 0xF8C6, 0xDC00);
r8168_mac_ocp_write(tp, 0xF8C8, 0xC707);
r8168_mac_ocp_write(tp, 0xF8CA, 0x1D00);
r8168_mac_ocp_write(tp, 0xF8CC, 0x8DE2);
r8168_mac_ocp_write(tp, 0xF8CE, 0x48C1);
r8168_mac_ocp_write(tp, 0xF8D0, 0xC502);
r8168_mac_ocp_write(tp, 0xF8D2, 0xBD00);
r8168_mac_ocp_write(tp, 0xF8D4, 0x00AA);
r8168_mac_ocp_write(tp, 0xF8D6, 0xE0C0);
r8168_mac_ocp_write(tp, 0xF8D8, 0xC502);
r8168_mac_ocp_write(tp, 0xF8DA, 0xBD00);
r8168_mac_ocp_write(tp, 0xF8DC, 0x0132);
rtl8411b_fix_phy_down(tp);
r8168_mac_ocp_write(tp, 0xFC26, 0x8000);
@ -4393,7 +4395,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
unsigned int entry = dirty_tx % NUM_TX_DESC;
u32 status;
status = le32_to_cpu(tp->TxDescArray[entry].opts1);
status = le32_to_cpu(READ_ONCE(tp->TxDescArray[entry].opts1));
if (status & DescOwn)
break;
@ -4423,7 +4425,7 @@ static void rtl_tx(struct net_device *dev, struct rtl8169_private *tp,
* If skb is NULL then we come here again once a tx irq is
* triggered after the last fragment is marked transmitted.
*/
if (tp->cur_tx != dirty_tx && skb)
if (READ_ONCE(tp->cur_tx) != dirty_tx && skb)
rtl8169_doorbell(tp);
}
}
@ -4456,7 +4458,7 @@ static int rtl_rx(struct net_device *dev, struct rtl8169_private *tp, int budget
dma_addr_t addr;
u32 status;
status = le32_to_cpu(desc->opts1);
status = le32_to_cpu(READ_ONCE(desc->opts1));
if (status & DescOwn)
break;
@ -4569,8 +4571,7 @@ static void rtl_task(struct work_struct *work)
rtnl_lock();
if (!netif_running(tp->dev) ||
!test_bit(RTL_FLAG_TASK_ENABLED, tp->wk.flags))
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)) {
@ -4596,6 +4597,8 @@ 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();
@ -4625,7 +4628,11 @@ 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);
}
@ -4669,10 +4676,16 @@ static void rtl8169_down(struct rtl8169_private *tp)
rtl8169_cleanup(tp);
rtl_disable_exit_l1(tp);
rtl_prepare_power_down(tp);
if (tp->dash_type != RTL_DASH_NONE)
rtl8168_driver_stop(tp);
}
static void rtl8169_up(struct rtl8169_private *tp)
{
if (tp->dash_type != RTL_DASH_NONE)
rtl8168_driver_start(tp);
pci_set_master(tp->pci_dev);
phy_init_hw(tp->phydev);
phy_resume(tp->phydev);
@ -4695,7 +4708,7 @@ static int rtl8169_close(struct net_device *dev)
rtl8169_down(tp);
rtl8169_rx_clear(tp);
cancel_work_sync(&tp->wk.work);
cancel_work(&tp->wk.work);
free_irq(tp->irq, tp);
@ -4890,7 +4903,7 @@ static int rtl8169_runtime_idle(struct device *device)
{
struct rtl8169_private *tp = dev_get_drvdata(device);
if (tp->dash_type != RTL_DASH_NONE)
if (tp->dash_enabled)
return -EBUSY;
if (!netif_running(tp->dev) || !netif_carrier_ok(tp->dev))
@ -4916,8 +4929,7 @@ static void rtl_shutdown(struct pci_dev *pdev)
/* Restore original MAC address */
rtl_rar_set(tp, tp->dev->perm_addr);
if (system_state == SYSTEM_POWER_OFF &&
tp->dash_type == RTL_DASH_NONE) {
if (system_state == SYSTEM_POWER_OFF && !tp->dash_enabled) {
pci_wake_from_d3(pdev, tp->saved_wolopts);
pci_set_power_state(pdev, PCI_D3hot);
}
@ -4930,6 +4942,11 @@ 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);
if (IS_ENABLED(CONFIG_R8169_LEDS))
r8169_remove_leds(tp->leds);
unregister_netdev(tp->dev);
if (tp->dash_type != RTL_DASH_NONE)
@ -5050,6 +5067,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;
@ -5203,6 +5229,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
int jumbo_max, region, rc;
enum mac_version chipset;
struct net_device *dev;
u32 txconfig;
u16 xid;
dev = devm_alloc_etherdev(&pdev->dev, sizeof (*tp));
@ -5221,6 +5248,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
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);
@ -5234,38 +5262,35 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* enable device (incl. PCI PM wakeup and hotplug setup) */
rc = pcim_enable_device(pdev);
if (rc < 0) {
dev_err(&pdev->dev, "enable failure\n");
return rc;
}
if (rc < 0)
return dev_err_probe(&pdev->dev, rc, "enable failure\n");
if (pcim_set_mwi(pdev) < 0)
dev_info(&pdev->dev, "Mem-Wr-Inval unavailable\n");
/* use first MMIO region */
region = ffs(pci_select_bars(pdev, IORESOURCE_MEM)) - 1;
if (region < 0) {
dev_err(&pdev->dev, "no MMIO resource found\n");
return -ENODEV;
}
if (region < 0)
return dev_err_probe(&pdev->dev, -ENODEV, "no MMIO resource found\n");
rc = pcim_iomap_regions(pdev, BIT(region), KBUILD_MODNAME);
if (rc < 0) {
dev_err(&pdev->dev, "cannot remap MMIO, aborting\n");
return rc;
}
if (rc < 0)
return dev_err_probe(&pdev->dev, rc, "cannot remap MMIO, aborting\n");
tp->mmio_addr = pcim_iomap_table(pdev)[region];
xid = (RTL_R32(tp, TxConfig) >> 20) & 0xfcf;
txconfig = RTL_R32(tp, TxConfig);
if (txconfig == ~0U)
return dev_err_probe(&pdev->dev, -EIO, "PCI read failed\n");
xid = (txconfig >> 20) & 0xfcf;
/* Identify chip attached to board */
chipset = rtl8169_get_mac_version(xid, tp->supports_gmii);
if (chipset == RTL_GIGA_MAC_NONE) {
dev_err(&pdev->dev, "unknown chip XID %03x, contact r8169 maintainers (see MAINTAINERS file)\n", xid);
return -ENODEV;
}
if (chipset == RTL_GIGA_MAC_NONE)
return dev_err_probe(&pdev->dev, -ENODEV,
"unknown chip XID %03x, contact r8169 maintainers (see MAINTAINERS file)\n",
xid);
tp->mac_version = chipset;
/* Disable ASPM L1 as that cause random device stop working
@ -5277,7 +5302,8 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rc = pci_disable_link_state(pdev, PCIE_LINK_STATE_L1);
tp->aspm_manageable = !rc;
tp->dash_type = rtl_check_dash(tp);
tp->dash_type = rtl_get_dash_type(tp);
tp->dash_enabled = rtl_dash_is_enabled(tp);
tp->cp_cmd = RTL_R16(tp, CPlusCmd) & CPCMD_MASK;
@ -5294,10 +5320,9 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
rtl_hw_reset(tp);
rc = rtl_alloc_irq(tp);
if (rc < 0) {
dev_err(&pdev->dev, "Can't allocate interrupt\n");
return rc;
}
if (rc < 0)
return dev_err_probe(&pdev->dev, rc, "Can't allocate interrupt\n");
tp->irq = pci_irq_vector(pdev, 0);
INIT_WORK(&tp->wk.work, rtl_task);
@ -5349,7 +5374,7 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
/* configure chip for default features */
rtl8169_set_features(dev, dev->features);
if (tp->dash_type == RTL_DASH_NONE) {
if (!tp->dash_enabled) {
rtl_set_d3_pll_down(tp, true);
} else {
rtl_set_d3_pll_down(tp, false);
@ -5380,6 +5405,11 @@ 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)
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);
@ -5389,13 +5419,14 @@ static int rtl_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
"ok" : "ko");
if (tp->dash_type != RTL_DASH_NONE) {
netdev_info(dev, "DASH enabled\n");
netdev_info(dev, "DASH %s\n",
tp->dash_enabled ? "enabled" : "disabled");
rtl8168_driver_start(tp);
}
if (pci_dev_run_wake(pdev))
pm_runtime_put_sync(&pdev->dev);
printk(KERN_INFO "Intializing module_parameter: wol_param = %d\n", wol_param);
return 0;
}