2023-09-12 09:32:25

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v7 00/13] Add Realtek automotive PCIe driver

This series includes adding realtek automotive ethernet driver
and adding rtase ethernet driver entry in MAINTAINERS file.

This ethernet device driver for the PCIe interface of
Realtek Automotive Ethernet Switch,applicable to
RTL9054, RTL9068, RTL9072, RTL9075, RTL9068, RTL9071.

v1 -> v2:
- Remove redundent debug message.
- Modify coding rule.
- Remove other function codes not related to netdev.

v2 -> v3:
- Remove SR-IOV function - We will add the SR-IOV function together when
uploading the vf driver in the future.
- Remove other unnecessary code and macro.

v3 -> v4:
- Remove function prototype - Our driver does not use recursion, so we
have reordered the code and removed the function prototypes.
- Define macro precisely - Improve macro code readability to make the
source code cleaner.

v4 -> v5:
- Modify ethtool function - Remove some unnecessary code.
- Don't use inline function - Let the compiler decide.

v5 -> v6:
- Some old macro definitions have been removed and replaced with the
lastest usage.
- Replace s32 with int to ensure consistency.
- Clearly point out the objects of the service and remove unnecessary
struct.

v6 -> v7:
- Split this driver into multiple patches.
- Reorganize this driver code and remove redundant code to make this
driver more concise.

Justin Lai (13):
net:ethernet:realtek:rtase: Add pci table supported in this module
net:ethernet:realtek:rtase: Implement the .ndo_open function
net:ethernet:realtek:rtase: Implement the rtase_down function
net:ethernet:realtek:rtase: Implement the interrupt routine and
rtase_poll
net:ethernet:realtek:rtase: Implement hardware configuration function
net:ethernet:realtek:rtase: Implement .ndo_start_xmit function
net:ethernet:realtek:rtase: Implement a function to receive packets
net:ethernet:realtek:rtase: Implement net_device_ops
net:ethernet:realtek:rtase: Implement pci_driver suspend and resume
function
net:ethernet:realtek:rtase: Implement ethtool function
net:ethernet:realtek:rtase: Add a Makefile in the rtase folder
net:ethernet:realtek: Update the Makefile and Kconfig in the realtek
folder
MAINTAINERS: Add the rtase ethernet driver entry

MAINTAINERS | 7 +
drivers/net/ethernet/realtek/Kconfig | 17 +
drivers/net/ethernet/realtek/Makefile | 1 +
drivers/net/ethernet/realtek/rtase/Makefile | 10 +
drivers/net/ethernet/realtek/rtase/rtase.h | 364 +++
.../net/ethernet/realtek/rtase/rtase_main.c | 2440 +++++++++++++++++
6 files changed, 2839 insertions(+)
create mode 100644 drivers/net/ethernet/realtek/rtase/Makefile
create mode 100644 drivers/net/ethernet/realtek/rtase/rtase.h
create mode 100644 drivers/net/ethernet/realtek/rtase/rtase_main.c

--
2.34.1


2023-09-12 09:35:07

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v7 11/13] net:ethernet:realtek:rtase: Add a Makefile in the rtase folder

Add a Makefile in the rtase folder to build rtase driver.

Signed-off-by: Justin Lai <[email protected]>
---
drivers/net/ethernet/realtek/rtase/Makefile | 10 ++++++++++
1 file changed, 10 insertions(+)
create mode 100644 drivers/net/ethernet/realtek/rtase/Makefile

diff --git a/drivers/net/ethernet/realtek/rtase/Makefile b/drivers/net/ethernet/realtek/rtase/Makefile
new file mode 100644
index 000000000000..f29b14687950
--- /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) 2023 Realtek Semiconductor Corp. All rights reserved.
+
+#
+# Makefile for the Realtek PCIe driver
+#
+
+obj-$(CONFIG_RTASE) += rtase.o
+
+rtase-objs := rtase_main.o
--
2.34.1

2023-09-12 10:13:58

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v7 03/13] net:ethernet:realtek:rtase: Implement the rtase_down function

Implement the rtase_down function to disable hardware setting
and interrupt and clear descriptor ring.

Signed-off-by: Justin Lai <[email protected]>
---
.../net/ethernet/realtek/rtase/rtase_main.c | 144 ++++++++++++++++++
1 file changed, 144 insertions(+)

diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c
index d3d2570a3429..2564031cbbbc 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -193,6 +193,57 @@ static void rtase_free_desc(struct rtase_private *tp)
}
}

+static void rtase_unmap_tx_skb(struct pci_dev *pdev, u32 len,
+ struct 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 = RTK_MAGIC_NUMBER;
+}
+
+static void rtase_tx_clear_range(struct rtase_ring *ring, u32 start, u32 n)
+{
+ const struct rtase_private *tp = ring->ivec->tp;
+ struct net_device *dev = tp->dev;
+ struct tx_desc *desc_base = ring->desc;
+ u32 i;
+
+ for (i = 0; i < n; i++) {
+ u32 entry = (start + i) % NUM_DESC;
+ struct 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;
+
+ dev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ ring->skbuff[entry] = NULL;
+ }
+}
+
+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, NUM_DESC);
+ ring->cur_idx = 0;
+ ring->dirty_idx = 0;
+ }
+}
+
static void rtase_mark_to_asic(union rx_desc *desc, u32 rx_buf_sz)
{
u32 eor = le32_to_cpu(desc->desc_cmd.opts1) & RING_END;
@@ -413,6 +464,77 @@ static void rtase_tally_counter_clear(const struct rtase_private *tp)
rtase_w32(tp, RTASE_DTCCR0, cmd | COUNTER_RESET);
}

+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 & ~ACCEPT_MASK);
+
+ val = rtase_r8(tp, RTASE_MISC);
+ rtase_w8(tp, RTASE_MISC, val | RX_DV_GATE_EN);
+
+ val = rtase_r8(tp, RTASE_CHIP_CMD);
+ rtase_w8(tp, RTASE_CHIP_CMD, val | STOP_REQ);
+ mdelay(2);
+
+ rtase_poll_timeout(tp, STOP_REQ_DONE, 100, 150000, RTASE_CHIP_CMD);
+
+ rtase_poll_timeout(tp, TX_FIFO_EMPTY, 100, 100000, RTASE_FIFOR);
+
+ rtase_poll_timeout(tp, RX_FIFO_EMPTY, 100, 100000, RTASE_FIFOR);
+
+ val = rtase_r8(tp, RTASE_CHIP_CMD);
+ rtase_w8(tp, RTASE_CHIP_CMD, val & ~(TE | RE));
+ val = rtase_r8(tp, RTASE_CHIP_CMD);
+ rtase_w8(tp, RTASE_CHIP_CMD, val & ~STOP_REQ);
+
+ rtase_w16(tp, RTASE_RX_CONFIG_0, rx_config);
+}
+
+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_nic_enable(const struct net_device *dev)
{
const struct rtase_private *tp = netdev_priv(dev);
@@ -520,6 +642,28 @@ static int rtase_open(struct net_device *dev)
return ret;
}

+static void rtase_down(struct net_device *dev)
+{
+ struct rtase_private *tp = netdev_priv(dev);
+ u32 i;
+
+ netif_stop_queue(dev);
+
+ /* give a racing hard_start_xmit a few cycles to complete */
+ synchronize_rcu();
+
+ netif_carrier_off(dev);
+
+ rtase_hw_reset(dev);
+
+ for (i = 0; i < tp->int_nums; i++)
+ synchronize_irq(tp->int_vector[i].irq);
+
+ rtase_tx_clear(tp);
+
+ rtase_rx_clear(tp);
+}
+
static int rtase_close(struct net_device *dev)
{
struct rtase_private *tp = netdev_priv(dev);
--
2.34.1

2023-09-12 10:15:15

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v7 12/13] net:ethernet:realtek: Update the Makefile and Kconfig in the realtek folder

1. Add the RTASE entry in the Kconfig.
2. Add the CONFIG_RTASE entry in the Makefile.

Signed-off-by: Justin Lai <[email protected]>
---
drivers/net/ethernet/realtek/Kconfig | 17 +++++++++++++++++
drivers/net/ethernet/realtek/Makefile | 1 +
2 files changed, 18 insertions(+)

diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig
index 93d9df55b361..57ef924deebd 100644
--- a/drivers/net/ethernet/realtek/Kconfig
+++ b/drivers/net/ethernet/realtek/Kconfig
@@ -113,4 +113,21 @@ config R8169
To compile this driver as a module, choose M here: the module
will be called r8169. This is recommended.

+config RTASE
+ tristate "Realtek Automotive Switch 9054/9068/9072/9075/9068/9071 PCIe Interface support"
+ depends on PCI
+ select CRC32
+ help
+ Say Y here 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 2e1d78b106b0..0c1c16f63e9a 100644
--- a/drivers/net/ethernet/realtek/Makefile
+++ b/drivers/net/ethernet/realtek/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_8139TOO) += 8139too.o
obj-$(CONFIG_ATP) += atp.o
r8169-objs += r8169_main.o r8169_firmware.o r8169_phy_config.o
obj-$(CONFIG_R8169) += r8169.o
+obj-$(CONFIG_RTASE) += rtase/
--
2.34.1

2023-09-13 02:11:26

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v7 08/13] net:ethernet:realtek:rtase: Implement net_device_ops

1. Implement .ndo_set_rx_mode so that the device can change address
list filtering.
2. Implement .ndo_set_mac_address so that mac address can be changed.
3. Implement .ndo_change_mtu so that mtu can be changed.
4. Implement .ndo_tx_timeout to perform related processing when the
transmitter does not make any progress.
5. Implement .ndo_get_stats64 to provide statistics that are called
when the user wants to get network device usage.
6. Implement .ndo_vlan_rx_add_vid to register VLAN ID when the device
supports VLAN filtering.
7. Implement .ndo_vlan_rx_kill_vid to unregister VLAN ID when the device
supports VLAN filtering.
8. Implement the .ndo_setup_tc to enable setting any "tc" scheduler,
classifier or action on dev.
9. Implement .ndo_fix_features enables adjusting requested feature flags
based on device-specific constraints.
10. Implement .ndo_set_features enables updating device configuration to
new features.

Signed-off-by: Justin Lai <[email protected]>
---
.../net/ethernet/realtek/rtase/rtase_main.c | 334 ++++++++++++++++++
1 file changed, 334 insertions(+)

diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c
index 21f135afcb8d..f5be2741bf94 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -1437,6 +1437,11 @@ static netdev_tx_t rtase_start_xmit(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}

+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;
@@ -1469,6 +1474,240 @@ static void rtase_rar_set(const struct rtase_private *tp, const u8 *addr)
rtase_w16(tp, RTASE_LBK_CTRL, LBK_ATLD | 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)
+{
+ struct rtase_private *tp = netdev_priv(dev);
+ int ret;
+
+ dev->mtu = new_mtu;
+
+ if (!netif_running(dev))
+ goto out;
+
+ rtase_down(dev);
+
+ rtase_set_rxbufsize(tp, dev);
+
+ ret = rtase_init_ring(dev);
+
+ if (ret)
+ return ret;
+
+ netif_stop_queue(dev);
+ netif_carrier_off(dev);
+ rtase_hw_config(dev);
+
+ /* always link, so start to transmit & receive */
+ rtase_hw_start(dev);
+ netif_carrier_on(dev);
+ netif_wake_queue(dev);
+
+out:
+ netdev_update_features(dev);
+
+ return ret;
+}
+
+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);
+ int ret;
+
+ 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);
+
+ ret = rtase_init_ring(dev);
+ if (ret)
+ netdev_alert(dev, "unable to init ring\n");
+
+ 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_tx_timeout(struct net_device *dev, unsigned int txqueue)
+{
+ rtase_sw_reset(dev);
+}
+
+static void rtase_dump_tally_counter(const struct rtase_private *tp,
+ dma_addr_t paddr)
+{
+ u32 cmd = lower_32_bits(le64_to_cpu(paddr));
+ u32 val;
+ int err;
+
+ rtase_w32(tp, RTASE_DTCCR4, upper_32_bits(le64_to_cpu(paddr)));
+ rtase_w32(tp, RTASE_DTCCR0, cmd);
+ rtase_w32(tp, RTASE_DTCCR0, cmd | COUNTER_DUMP);
+
+ err = read_poll_timeout(rtase_r32, val, !(val & 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_get_stats64(struct net_device *dev,
+ struct rtnl_link_stats64 *stats)
+{
+ const struct rtase_private *tp = netdev_priv(dev);
+ const struct rtase_counters *counters = tp->tally_vaddr;
+ dma_addr_t paddr = tp->tally_paddr;
+
+ if (!counters)
+ return;
+
+ netdev_stats_to_stats64(stats, &dev->stats);
+ 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, paddr);
+
+ stats->tx_errors = le64_to_cpu(counters->tx_errors);
+ stats->collisions = le64_to_cpu(counters->tx_multi_collision);
+ stats->tx_aborted_errors = le64_to_cpu(counters->tx_aborted);
+ stats->rx_missed_errors = le64_to_cpu(counters->rx_missed);
+}
+
+static void rtase_enable_vlan_filter(const struct rtase_private *tp, bool enabled)
+{
+ u16 tmp;
+
+ if (enabled == 1) {
+ tmp = rtase_r16(tp, RTASE_FCR);
+ if (!(tmp & FCR_VLAN_FTR_EN))
+ rtase_w16(tp, RTASE_FCR, tmp | FCR_VLAN_FTR_EN);
+
+ tmp = rtase_r16(tp, RTASE_PCPR);
+ if (!(tmp & PCPR_VLAN_FTR_EN))
+ rtase_w16(tp, RTASE_PCPR, tmp | PCPR_VLAN_FTR_EN);
+ } else {
+ tmp = rtase_r16(tp, RTASE_FCR);
+ if (tmp & FCR_VLAN_FTR_EN)
+ rtase_w16(tp, RTASE_FCR, tmp & ~FCR_VLAN_FTR_EN);
+
+ tmp = rtase_r16(tp, RTASE_PCPR);
+ if (!(tmp & PCPR_VLAN_FTR_EN))
+ rtase_w16(tp, RTASE_PCPR, tmp & ~PCPR_VLAN_FTR_EN);
+ }
+}
+
+static int rtase_vlan_rx_add_vid(struct net_device *dev, __be16 protocol,
+ u16 vid)
+{
+ struct rtase_private *tp = netdev_priv(dev);
+ u16 tmp_mem, i;
+
+ if (be16_to_cpu(protocol) != ETH_P_8021Q)
+ return -EINVAL;
+
+ for (i = 0; i < RTASE_VLAN_FILTER_ENTRY_NUM; i++) {
+ u16 addr, mask;
+
+ if (!(tp->vlan_filter_ctrl & BIT(i))) {
+ tp->vlan_filter_ctrl |= BIT(i);
+ tp->vlan_filter_vid[i] = vid;
+ rtase_w32(tp, RTASE_VLAN_ENTRY_0 + i * 4,
+ vid | VLAN_ENTRY_CAREBIT);
+ /* each 16-bit register contains two VLAN entries */
+ addr = RTASE_VLAN_ENTRY_MEM_0 + (i & ~0x1);
+ mask = 0x1 << ((i & 0x1) * 8);
+ tmp_mem = rtase_r16(tp, addr);
+ tmp_mem |= mask;
+ rtase_w16(tp, addr, tmp_mem);
+ break;
+ }
+ }
+
+ if (i == RTASE_VLAN_FILTER_ENTRY_NUM)
+ return -ENOENT;
+
+ rtase_enable_vlan_filter(tp, true);
+
+ return 0;
+}
+
+static int rtase_vlan_rx_kill_vid(struct net_device *dev, __be16 protocol,
+ u16 vid)
+{
+ struct rtase_private *tp = netdev_priv(dev);
+ u16 tmp_mem, i;
+
+ if (be16_to_cpu(protocol) != ETH_P_8021Q)
+ return -EINVAL;
+
+ for (i = 0; i < RTASE_VLAN_FILTER_ENTRY_NUM; i++) {
+ u16 addr, mask;
+
+ if (tp->vlan_filter_vid[i] == vid) {
+ tp->vlan_filter_ctrl &= ~BIT(i);
+ tp->vlan_filter_vid[i] = 0;
+ rtase_w32(tp, RTASE_VLAN_ENTRY_0 + i * 4, 0);
+
+ /* each 16-bit register contains two VLAN entries */
+ addr = RTASE_VLAN_ENTRY_MEM_0 + (i & ~0x1);
+ mask = ~(0x1 << ((i & 0x1) * 8));
+ tmp_mem = rtase_r16(tp, addr);
+ tmp_mem &= mask;
+ rtase_w16(tp, addr, tmp_mem);
+ break;
+ }
+ }
+
+ /* check vlan filter enabled */
+ if (!tp->vlan_filter_ctrl)
+ rtase_enable_vlan_filter(tp, false);
+
+ return 0;
+}
+
#ifdef CONFIG_NET_POLL_CONTROLLER
/* Polling 'interrupt' - used by things like netconsole to send skbs
* without having to re-enable interrupts. It's not called while
@@ -1485,13 +1724,108 @@ static void rtase_netpoll(struct net_device *dev)
}
#endif

+static void rtase_set_hw_cbs(const struct rtase_private *tp, u32 queue)
+{
+ u32 idle = tp->tx_qos[queue].idleslope * RTASE_1T_CLOCK;
+ u32 val, i;
+
+ val = u32_encode_bits(idle / RTASE_1T_POWER, RTASE_IDLESLOPE_INT_MASK);
+ idle %= RTASE_1T_POWER;
+
+ for (i = 1; i <= RTASE_IDLESLOPE_INT_SHIFT; i++) {
+ idle *= 2;
+ if ((idle / RTASE_1T_POWER) == 1)
+ val |= BIT(RTASE_IDLESLOPE_INT_SHIFT - i);
+
+ idle %= RTASE_1T_POWER;
+ }
+ rtase_w32(tp, RTASE_TXQCRDT_0 + queue * 4, val);
+}
+
+static int rtase_setup_tc_cbs(struct rtase_private *tp,
+ const struct tc_cbs_qopt_offload *qopt)
+{
+ u32 queue = qopt->queue;
+
+ tp->tx_qos[queue].hicredit = qopt->hicredit;
+ tp->tx_qos[queue].locredit = qopt->locredit;
+ tp->tx_qos[queue].idleslope = qopt->idleslope;
+ tp->tx_qos[queue].sendslope = qopt->sendslope;
+
+ /* set hardware cbs */
+ rtase_set_hw_cbs(tp, queue);
+
+ return 0;
+}
+
+static int rtase_setup_tc(struct net_device *dev, enum tc_setup_type type,
+ void *type_data)
+{
+ struct rtase_private *tp = netdev_priv(dev);
+ int ret = 0;
+
+ switch (type) {
+ case TC_SETUP_QDISC_MQPRIO:
+ break;
+ case TC_SETUP_BLOCK:
+ break;
+ case TC_SETUP_QDISC_CBS:
+ ret = rtase_setup_tc_cbs(tp, type_data);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return ret;
+}
+
+static netdev_features_t rtase_fix_features(struct net_device *dev,
+ netdev_features_t features)
+{
+ netdev_features_t features_fix = features;
+
+ if (dev->mtu > MSS_MAX)
+ features_fix &= ~NETIF_F_ALL_TSO;
+
+ if (dev->mtu > ETH_DATA_LEN) {
+ features_fix &= ~NETIF_F_ALL_TSO;
+ features_fix &= ~NETIF_F_CSUM_MASK;
+ }
+
+ 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_vlan_rx_add_vid = rtase_vlan_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = rtase_vlan_rx_kill_vid,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = rtase_netpoll,
#endif
+ .ndo_setup_tc = rtase_setup_tc,
+ .ndo_fix_features = rtase_fix_features,
+ .ndo_set_features = rtase_set_features,
};

static void rtase_get_mac_address(struct net_device *dev)
--
2.34.1

2023-09-13 02:11:56

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v7 04/13] net:ethernet:realtek:rtase: Implement the interrupt routine and rtase_poll

1. Implement rtase_interrupt to handle txQ0/rxQ0, txQ4~txQ7 interrupts,
and implement rtase_q_interrupt to handle txQ1/rxQ1, txQ2/rxQ2 and
txQ3/rxQ3 interrupts.
2. Implement rtase_poll to call ring_handler to process the tx or
rx packet of each ring. If the returned value is budget,it means that
there is still work of a certain ring that has not yet been completed.

Signed-off-by: Justin Lai <[email protected]>
---
.../net/ethernet/realtek/rtase/rtase_main.c | 89 +++++++++++++++++++
1 file changed, 89 insertions(+)

diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c
index 2564031cbbbc..6f059e85f455 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -575,6 +575,76 @@ void rtase_hw_start(const struct net_device *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 & ~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);
@@ -717,9 +787,28 @@ static void rtase_rar_set(const struct rtase_private *tp, const u8 *addr)
rtase_w16(tp, RTASE_LBK_CTRL, LBK_ATLD | LBK_CLR);
}

+#ifdef CONFIG_NET_POLL_CONTROLLER
+/* Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void rtase_netpoll(struct net_device *dev)
+{
+ const struct rtase_private *tp = netdev_priv(dev);
+ const struct pci_dev *pdev = tp->pdev;
+
+ disable_irq(pdev->irq);
+ rtase_interrupt(pdev->irq, dev);
+ enable_irq(pdev->irq);
+}
+#endif
+
static const struct net_device_ops rtase_netdev_ops = {
.ndo_open = rtase_open,
.ndo_stop = rtase_close,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+ .ndo_poll_controller = rtase_netpoll,
+#endif
};

static void rtase_get_mac_address(struct net_device *dev)
--
2.34.1

2023-09-13 02:14:21

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v7 13/13] MAINTAINERS: Add the rtase ethernet driver entry

Add myself and Larry Chiu as the maintainer for the rtase ethernet driver.

Signed-off-by: Justin Lai <[email protected]>
---
MAINTAINERS | 7 +++++++
1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 53b7ca804465..239aae94dc0f 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -18476,6 +18476,13 @@ L: [email protected]
S: Maintained
F: drivers/tty/rpmsg_tty.c

+RTASE ETHERNET DRIVER
+M: Justin Lai <[email protected]>
+M: Larry Chiu <[email protected]>
+L: [email protected]
+S: Maintained
+F: drivers/net/ethernet/realtek/rtase/
+
RTL2830 MEDIA DRIVER
M: Antti Palosaari <[email protected]>
L: [email protected]
--
2.34.1