2023-11-15 13:38:32

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v11 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.

v7 -> v8:
- Add the function to calculate time mitigation and the function to
calculate packet number mitigation. Users can use these two functions
to calculate the reg value that needs to be set for the mitigation value
they want to set.
- This device is usually used in automotive embedded systems. The page
pool api will use more memory in receiving packets and requires more
verification, so we currently do not plan to use it in this patch.

v8 -> v9:
- Declare functions that are not extern as static functions and increase
the size of the character array named name in the rtase_int_vector struct
to correct the build warning noticed by the kernel test robot.

v9 -> v10:
- Currently we change to use the page pool api. However, when we allocate
more than one page to an rx buffer, it will cause system errors
in some cases. Therefore, we set the rx buffer to fixed size with 3776
(PAGE_SIZE - SKB_DATA_ALIGN(sizeof(skb_shared_info) )), and the maximum
value of mtu is set to 3754(rx buffer size - VLAN_ETH_HLEN - ETH_FCS_LEN).
- When ndo_tx_timeout is called, it will dump some device information,
which can be used for debugging.
- When the mtu is greater than 1500, the device supports checksums
but not TSO.
- Fix compiler warnning.

v10 -> v11:
- Added error handling of rtase_init_ring().
- Modify the error related to asymmetric pause in rtase_get_settings.
- Fix compiler error.

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 | 353 +++
.../net/ethernet/realtek/rtase/rtase_main.c | 2542 +++++++++++++++++
drivers/net/ethernet/realtek/rtase/tt.c | 2542 +++++++++++++++++
drivers/net/ethernet/realtek/rtase/tt.h | 353 +++
8 files changed, 5825 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
create mode 100644 drivers/net/ethernet/realtek/rtase/tt.c
create mode 100644 drivers/net/ethernet/realtek/rtase/tt.h

--
2.34.1


2023-11-15 13:38:34

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v11 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 | 378 ++++++++++++++++++
1 file changed, 378 insertions(+)

diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c
index 5c03d9abaa26..12607663dd72 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -1442,6 +1442,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;
@@ -1474,6 +1479,293 @@ 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)
+{
+ 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);
+ 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_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 | 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_dump_state(const struct net_device *dev)
+{
+ const struct rtase_private *tp = netdev_priv(dev);
+ const struct rtase_counters *counters;
+ int max_reg_size = RTASE_PCI_REGS_SIZE;
+ 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 = 0x%llx\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 = 0x%llx\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_missed %lld\n",
+ le64_to_cpu(counters->rx_missed));
+ netdev_err(dev, "align_errors %lld\n",
+ le64_to_cpu(counters->align_errors));
+ netdev_err(dev, "tx_one_collision %lld\n",
+ le64_to_cpu(counters->tx_one_collision));
+ netdev_err(dev, "tx_multi_collision %lld\n",
+ le64_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 %lld\n",
+ le64_to_cpu(counters->rx_multicast));
+ netdev_err(dev, "tx_aborted %lld\n",
+ le64_to_cpu(counters->tx_aborted));
+ netdev_err(dev, "tx_underun %lld\n",
+ le64_to_cpu(counters->tx_underun));
+}
+
+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 = tp->tally_vaddr;
+
+ 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);
+
+ stats->tx_errors = le64_to_cpu(counters->tx_errors);
+ stats->collisions = le32_to_cpu(counters->tx_multi_collision);
+ stats->tx_aborted_errors = le16_to_cpu(counters->tx_aborted);
+ stats->rx_missed_errors = le16_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
@@ -1490,13 +1782,99 @@ 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 void 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);
+}
+
+static int rtase_setup_tc(struct net_device *dev, enum tc_setup_type type,
+ void *type_data)
+{
+ struct rtase_private *tp = netdev_priv(dev);
+
+ switch (type) {
+ case TC_SETUP_QDISC_CBS:
+ rtase_setup_tc_cbs(tp, type_data);
+ break;
+ default:
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+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;
+
+ 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-11-15 13:38:38

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v11 10/13] net:ethernet:realtek:rtase: Implement ethtool function

Implement the ethtool function to support users to obtain network card
information, including obtaining various device settings, Report whether
physical link is up, Report pause parameters, Set pause parameters,
Return a set of strings that describe the requested objects, Get number
of strings that @get_strings will write, Return extended statistics
about the device.

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 b7679b74cc8a..5ea4d51fcc47 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -1900,9 +1900,153 @@ static void rtase_get_mac_address(struct net_device *dev)
ether_addr_copy(dev->perm_addr, dev->dev_addr);
}

+static void rtase_get_drvinfo(struct net_device *dev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ const struct rtase_private *tp = netdev_priv(dev);
+
+ strscpy(drvinfo->driver, KBUILD_MODNAME, 32);
+ strscpy(drvinfo->bus_info, pci_name(tp->pdev), 32);
+}
+
+static int rtase_get_settings(struct net_device *dev,
+ struct ethtool_link_ksettings *cmd)
+{
+ u32 supported = SUPPORTED_MII | SUPPORTED_Pause | SUPPORTED_Asym_Pause;
+
+ ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
+ supported);
+ cmd->base.speed = SPEED_5000;
+ 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;
+
+ if ((value & (FORCE_TXFLOW_EN | FORCE_RXFLOW_EN)) ==
+ (FORCE_TXFLOW_EN | FORCE_RXFLOW_EN)) {
+ pause->rx_pause = 1;
+ pause->tx_pause = 1;
+ } else if ((value & FORCE_TXFLOW_EN)) {
+ pause->tx_pause = 1;
+ } else if ((value & FORCE_RXFLOW_EN)) {
+ pause->rx_pause = 1;
+ }
+}
+
+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 &= ~(FORCE_TXFLOW_EN | FORCE_RXFLOW_EN);
+
+ if (pause->tx_pause)
+ value |= FORCE_TXFLOW_EN;
+
+ if (pause->rx_pause)
+ value |= FORCE_RXFLOW_EN;
+
+ rtase_w16(tp, RTASE_CPLUS_CMD, value);
+ return 0;
+}
+
+static const char rtase_gstrings[][ETH_GSTRING_LEN] = {
+ "tx_packets",
+ "rx_packets",
+ "tx_errors",
+ "rx_errors",
+ "rx_missed",
+ "align_errors",
+ "tx_single_collisions",
+ "tx_multi_collisions",
+ "unicast",
+ "broadcast",
+ "multicast",
+ "tx_aborted",
+ "tx_underrun",
+};
+
+static void rtase_get_strings(struct net_device *dev, u32 stringset, u8 *data)
+{
+ switch (stringset) {
+ case ETH_SS_STATS:
+ memcpy(data, *rtase_gstrings, sizeof(rtase_gstrings));
+ break;
+ }
+}
+
+static int rtase_get_sset_count(struct net_device *dev, int sset)
+{
+ int ret = -EOPNOTSUPP;
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ ret = ARRAY_SIZE(rtase_gstrings);
+ break;
+ }
+
+ return ret;
+}
+
+static void rtase_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct rtase_private *tp = netdev_priv(dev);
+ const struct rtase_counters *counters;
+
+ ASSERT_RTNL();
+
+ counters = tp->tally_vaddr;
+ if (!counters)
+ return;
+
+ rtase_dump_tally_counter(tp);
+
+ data[0] = le64_to_cpu(counters->tx_packets);
+ data[1] = le64_to_cpu(counters->rx_packets);
+ data[2] = le64_to_cpu(counters->tx_errors);
+ data[3] = le32_to_cpu(counters->rx_errors);
+ data[4] = le16_to_cpu(counters->rx_missed);
+ data[5] = le16_to_cpu(counters->align_errors);
+ data[6] = le32_to_cpu(counters->tx_one_collision);
+ data[7] = le32_to_cpu(counters->tx_multi_collision);
+ data[8] = le64_to_cpu(counters->rx_unicast);
+ 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);
+}
+
+static const struct ethtool_ops rtase_ethtool_ops = {
+ .get_drvinfo = rtase_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_link_ksettings = rtase_get_settings,
+ .get_pauseparam = rtase_get_pauseparam,
+ .set_pauseparam = rtase_set_pauseparam,
+ .get_strings = rtase_get_strings,
+ .get_sset_count = rtase_get_sset_count,
+ .get_ethtool_stats = rtase_get_ethtool_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,
--
2.34.1

2023-11-15 13:38:41

by Justin Lai

[permalink] [raw]
Subject: [PATCH net-next v11 06/13] net:ethernet:realtek:rtase: Implement .ndo_start_xmit function

Implement .ndo_start_xmit function to fill the information of the packet
to be transmitted into the tx descriptor, and then the hardware will
transmit the packet using the information in the tx descriptor.
In addition, we also implemented the tx_handler function to enable the
tx descriptor to be reused.

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

diff --git a/drivers/net/ethernet/realtek/rtase/rtase_main.c b/drivers/net/ethernet/realtek/rtase/rtase_main.c
index 4e04189050cc..c90941d5b989 100644
--- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
+++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
@@ -252,6 +252,68 @@ static void rtase_mark_to_asic(union rx_desc *desc, u32 rx_buf_sz)
cpu_to_le32(DESC_OWN | eor | rx_buf_sz));
}

+static bool rtase_tx_avail(struct rtase_ring *ring)
+{
+ u32 avail_num = READ_ONCE(ring->dirty_idx) + NUM_DESC -
+ READ_ONCE(ring->cur_idx);
+
+ return avail_num > MAX_SKB_FRAGS;
+}
+
+static int tx_handler(struct rtase_ring *ring, int budget)
+{
+ const struct rtase_private *tp = ring->ivec->tp;
+ struct net_device *dev = tp->dev;
+ int workdone = 0;
+ u32 dirty_tx;
+ u32 tx_left;
+
+ dirty_tx = ring->dirty_idx;
+ tx_left = READ_ONCE(ring->cur_idx) - dirty_tx;
+
+ while (tx_left > 0) {
+ u32 entry = dirty_tx % NUM_DESC;
+ struct tx_desc *desc = ring->desc +
+ sizeof(struct tx_desc) * entry;
+ u32 len = ring->mis.len[entry];
+ u32 status;
+
+ status = le32_to_cpu(desc->opts1);
+
+ if (status & DESC_OWN)
+ break;
+
+ rtase_unmap_tx_skb(tp->pdev, len, desc);
+ ring->mis.len[entry] = 0;
+ if (ring->skbuff[entry]) {
+ dev_consume_skb_any(ring->skbuff[entry]);
+ ring->skbuff[entry] = NULL;
+ }
+
+ dev->stats.tx_bytes += len;
+ dev->stats.tx_packets++;
+ dirty_tx++;
+ tx_left--;
+ workdone++;
+
+ if (workdone == budget)
+ break;
+ }
+
+ if (ring->dirty_idx != dirty_tx) {
+ WRITE_ONCE(ring->dirty_idx, dirty_tx);
+
+ if (__netif_subqueue_stopped(dev, ring->index) &&
+ rtase_tx_avail(ring))
+ netif_start_subqueue(dev, ring->index);
+
+ if (ring->cur_idx != dirty_tx)
+ rtase_w8(tp, RTASE_TPPOLL, BIT(ring->index));
+ }
+
+ return workdone;
+}
+
static void rtase_tx_desc_init(struct rtase_private *tp, u16 idx)
{
struct rtase_ring *ring = &tp->tx_ring[idx];
@@ -1007,6 +1069,231 @@ static int rtase_close(struct net_device *dev)
return 0;
}

+static u32 rtase_tx_vlan_tag(const struct rtase_private *tp,
+ const struct sk_buff *skb)
+{
+ return (skb_vlan_tag_present(skb)) ?
+ (TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb))) : 0x00;
+}
+
+static u32 rtase_tx_csum(struct sk_buff *skb, const struct net_device *dev)
+{
+ u8 ip_protocol;
+ u32 csum_cmd;
+
+ switch (vlan_get_protocol(skb)) {
+ case htons(ETH_P_IP):
+ csum_cmd = TX_IPCS_C;
+ ip_protocol = ip_hdr(skb)->protocol;
+ break;
+
+ case htons(ETH_P_IPV6):
+ csum_cmd = TX_IPV6F_C;
+ ip_protocol = ipv6_hdr(skb)->nexthdr;
+ break;
+
+ default:
+ ip_protocol = IPPROTO_RAW;
+ break;
+ }
+
+ if (ip_protocol == IPPROTO_TCP)
+ csum_cmd |= TX_TCPCS_C;
+ else if (ip_protocol == IPPROTO_UDP)
+ csum_cmd |= TX_UDPCS_C;
+ else
+ WARN_ON_ONCE(1);
+
+ csum_cmd |= u32_encode_bits(skb_transport_offset(skb), 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 tx_desc *txd = NULL;
+ u32 cur_frag, entry;
+ u64 pkt_len_cnt = 0;
+
+ 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) % NUM_DESC;
+
+ txd = ring->desc + sizeof(struct 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) % NUM_DESC) == 0)
+ status = (opts1 | len | RING_END);
+ else
+ status = opts1 | len;
+
+ if (cur_frag == (nr_frags - 1)) {
+ ring->skbuff[entry] = skb;
+ status |= 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 */
+ wmb();
+ txd->opts1 = cpu_to_le32(status);
+ pkt_len_cnt += len;
+ }
+
+ 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;
+ u32 mss = shinfo->gso_size;
+ struct rtase_ring *ring;
+ struct tx_desc *txd;
+ dma_addr_t mapping;
+ bool stop_queue;
+ int frags;
+
+ /* multiqueues */
+ q_idx = skb_get_queue_mapping(skb);
+ ring = &tp->tx_ring[q_idx];
+
+ if (unlikely(!rtase_tx_avail(ring))) {
+ if (net_ratelimit())
+ netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
+ goto err_stop;
+ }
+
+ entry = ring->cur_idx % NUM_DESC;
+ txd = ring->desc + sizeof(struct tx_desc) * entry;
+
+ opts1 = 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 |= 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 |= GIANT_SEND_V6;
+ } else {
+ WARN_ON_ONCE(1);
+ }
+
+ opts1 |= u32_encode_bits(skb_transport_offset(skb), TCPHO_MASK);
+ opts2 |= u32_encode_bits(mss, 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 |= TX_FIRST_FRAG;
+ } else {
+ len = skb->len;
+ ring->skbuff[entry] = skb;
+ opts1 |= TX_FIRST_FRAG | TX_LAST_FRAG;
+ }
+
+ if (((entry + 1) % NUM_DESC) == 0)
+ opts1 |= (len | 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 & ~DESC_OWN);
+
+ /* make sure the operating fields have been updated */
+ wmb();
+
+ 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 = !rtase_tx_avail(ring);
+ if (unlikely(stop_queue))
+ netif_stop_subqueue(dev, q_idx);
+
+ /* set polling bit */
+ rtase_w8(tp, RTASE_TPPOLL, BIT(ring->index));
+
+ if (unlikely(stop_queue)) {
+ /* make sure cur_idx and dirty_idx have been updated */
+ smp_rmb();
+ if (rtase_tx_avail(ring))
+ netif_start_subqueue(dev, q_idx);
+ }
+
+ return NETDEV_TX_OK;
+
+err_dma_1:
+ ring->skbuff[entry] = NULL;
+ rtase_tx_clear_range(ring, ring->cur_idx + 1, frags);
+
+err_dma_0:
+ dev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+
+err_stop:
+ netif_stop_queue(dev);
+ dev->stats.tx_dropped++;
+ return NETDEV_TX_BUSY;
+}
+
static void rtase_enable_eem_write(const struct rtase_private *tp)
{
u8 val;
@@ -1058,6 +1345,7 @@ static void rtase_netpoll(struct net_device *dev)
static const struct net_device_ops rtase_netdev_ops = {
.ndo_open = rtase_open,
.ndo_stop = rtase_close,
+ .ndo_start_xmit = rtase_start_xmit,
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = rtase_netpoll,
#endif
--
2.34.1

2023-11-15 15:03:14

by Heiner Kallweit

[permalink] [raw]
Subject: Re: [PATCH net-next v11 10/13] net:ethernet:realtek:rtase: Implement ethtool function

On 15.11.2023 14:34, Justin Lai wrote:
> Implement the ethtool function to support users to obtain network card
> information, including obtaining various device settings, Report whether
> physical link is up, Report pause parameters, Set pause parameters,
> Return a set of strings that describe the requested objects, Get number
> of strings that @get_strings will write, Return extended statistics
> about the device.
>
> 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 b7679b74cc8a..5ea4d51fcc47 100644
> --- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
> +++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
> @@ -1900,9 +1900,153 @@ static void rtase_get_mac_address(struct net_device *dev)
> ether_addr_copy(dev->perm_addr, dev->dev_addr);
> }
>
> +static void rtase_get_drvinfo(struct net_device *dev,
> + struct ethtool_drvinfo *drvinfo)
> +{
> + const struct rtase_private *tp = netdev_priv(dev);
> +
> + strscpy(drvinfo->driver, KBUILD_MODNAME, 32);
> + strscpy(drvinfo->bus_info, pci_name(tp->pdev), 32);
> +}
> +
> +static int rtase_get_settings(struct net_device *dev,
> + struct ethtool_link_ksettings *cmd)
> +{
> + u32 supported = SUPPORTED_MII | SUPPORTED_Pause | SUPPORTED_Asym_Pause;
> +
> + ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
> + supported);
> + cmd->base.speed = SPEED_5000;
> + cmd->base.duplex = DUPLEX_FULL;
> + cmd->base.port = PORT_MII;
> + cmd->base.autoneg = AUTONEG_DISABLE;
> +
What are you reporting here? Does this refer to the link between MAC and
switch CPU port? Because I would assume that the switch ports can do autoneg.

> + 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;
> +
> + if ((value & (FORCE_TXFLOW_EN | FORCE_RXFLOW_EN)) ==
> + (FORCE_TXFLOW_EN | FORCE_RXFLOW_EN)) {
> + pause->rx_pause = 1;
> + pause->tx_pause = 1;
> + } else if ((value & FORCE_TXFLOW_EN)) {
> + pause->tx_pause = 1;
> + } else if ((value & FORCE_RXFLOW_EN)) {
> + pause->rx_pause = 1;
> + }
> +}
> +
> +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 &= ~(FORCE_TXFLOW_EN | FORCE_RXFLOW_EN);
> +
> + if (pause->tx_pause)
> + value |= FORCE_TXFLOW_EN;
> +
> + if (pause->rx_pause)
> + value |= FORCE_RXFLOW_EN;
> +
> + rtase_w16(tp, RTASE_CPLUS_CMD, value);
> + return 0;
> +}
> +
> +static const char rtase_gstrings[][ETH_GSTRING_LEN] = {
> + "tx_packets",
> + "rx_packets",
> + "tx_errors",
> + "rx_errors",
> + "rx_missed",
> + "align_errors",
> + "tx_single_collisions",
> + "tx_multi_collisions",
> + "unicast",
> + "broadcast",
> + "multicast",
> + "tx_aborted",
> + "tx_underrun",
> +};
> +
> +static void rtase_get_strings(struct net_device *dev, u32 stringset, u8 *data)
> +{
> + switch (stringset) {
> + case ETH_SS_STATS:
> + memcpy(data, *rtase_gstrings, sizeof(rtase_gstrings));
> + break;
> + }
> +}
> +
> +static int rtase_get_sset_count(struct net_device *dev, int sset)
> +{
> + int ret = -EOPNOTSUPP;
> +
> + switch (sset) {
> + case ETH_SS_STATS:
> + ret = ARRAY_SIZE(rtase_gstrings);
> + break;
> + }
> +
> + return ret;
> +}
> +
> +static void rtase_get_ethtool_stats(struct net_device *dev,
> + struct ethtool_stats *stats, u64 *data)
> +{
> + struct rtase_private *tp = netdev_priv(dev);
> + const struct rtase_counters *counters;
> +
> + ASSERT_RTNL();
> +
> + counters = tp->tally_vaddr;
> + if (!counters)
> + return;
> +
> + rtase_dump_tally_counter(tp);
> +
> + data[0] = le64_to_cpu(counters->tx_packets);
> + data[1] = le64_to_cpu(counters->rx_packets);
> + data[2] = le64_to_cpu(counters->tx_errors);
> + data[3] = le32_to_cpu(counters->rx_errors);
> + data[4] = le16_to_cpu(counters->rx_missed);
> + data[5] = le16_to_cpu(counters->align_errors);
> + data[6] = le32_to_cpu(counters->tx_one_collision);
> + data[7] = le32_to_cpu(counters->tx_multi_collision);
> + data[8] = le64_to_cpu(counters->rx_unicast);
> + 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);
> +}
> +
> +static const struct ethtool_ops rtase_ethtool_ops = {
> + .get_drvinfo = rtase_get_drvinfo,
> + .get_link = ethtool_op_get_link,
> + .get_link_ksettings = rtase_get_settings,
> + .get_pauseparam = rtase_get_pauseparam,
> + .set_pauseparam = rtase_set_pauseparam,
> + .get_strings = rtase_get_strings,
> + .get_sset_count = rtase_get_sset_count,
> + .get_ethtool_stats = rtase_get_ethtool_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,

2023-11-16 17:57:46

by Simon Horman

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

On Wed, Nov 15, 2023 at 09:34:01PM +0800, Justin Lai wrote:
> 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.

...

> 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 | 353 +++
> .../net/ethernet/realtek/rtase/rtase_main.c | 2542 +++++++++++++++++
> drivers/net/ethernet/realtek/rtase/tt.c | 2542 +++++++++++++++++
> drivers/net/ethernet/realtek/rtase/tt.h | 353 +++

Hi Justin,

Unless I am mistaken, by the end of this patch set tt.c is identical to
rtase_main.c, and tt.h is identical to rtase.h.

If so, why?

$ cd drivers/net/ethernet/realtek/rtase
$ sha1sum *.[ch] | sort
9762c7f0fc1acb214d1705905495fad6b902a3c8 rtase.h
9762c7f0fc1acb214d1705905495fad6b902a3c8 tt.h
ccfe889f5ae3b6ecfa0dfba91d30fd7beffd4291 rtase_main.c
ccfe889f5ae3b6ecfa0dfba91d30fd7beffd4291 tt.c

2023-11-21 09:38:12

by Justin Lai

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

> On Wed, Nov 15, 2023 at 09:34:01PM +0800, Justin Lai wrote:
> > 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.
>
> ...
>
> > 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 | 353 +++
> > .../net/ethernet/realtek/rtase/rtase_main.c | 2542 +++++++++++++++++
> > drivers/net/ethernet/realtek/rtase/tt.c | 2542 +++++++++++++++++
> > drivers/net/ethernet/realtek/rtase/tt.h | 353 +++
>
> Hi Justin,
>
> Unless I am mistaken, by the end of this patch set tt.c is identical to
> rtase_main.c, and tt.h is identical to rtase.h.
>
> If so, why?

Sorry, tt.c and tt.h are redundant codes. This part will be corrected in the next version of the patch.
>
> $ cd drivers/net/ethernet/realtek/rtase
> $ sha1sum *.[ch] | sort
> 9762c7f0fc1acb214d1705905495fad6b902a3c8 rtase.h
> 9762c7f0fc1acb214d1705905495fad6b902a3c8 tt.h
> ccfe889f5ae3b6ecfa0dfba91d30fd7beffd4291 rtase_main.c
> ccfe889f5ae3b6ecfa0dfba91d30fd7beffd4291 tt.c

2023-11-23 03:16:55

by Justin Lai

[permalink] [raw]
Subject: RE: [PATCH net-next v11 10/13] net:ethernet:realtek:rtase: Implement ethtool function

> On 15.11.2023 14:34, Justin Lai wrote:
> > Implement the ethtool function to support users to obtain network card
> > information, including obtaining various device settings, Report
> > whether physical link is up, Report pause parameters, Set pause
> > parameters, Return a set of strings that describe the requested
> > objects, Get number of strings that @get_strings will write, Return
> > extended statistics about the device.
> >
> > 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 b7679b74cc8a..5ea4d51fcc47 100644
> > --- a/drivers/net/ethernet/realtek/rtase/rtase_main.c
> > +++ b/drivers/net/ethernet/realtek/rtase/rtase_main.c
> > @@ -1900,9 +1900,153 @@ static void rtase_get_mac_address(struct
> net_device *dev)
> > ether_addr_copy(dev->perm_addr, dev->dev_addr); }
> >
> > +static void rtase_get_drvinfo(struct net_device *dev,
> > + struct ethtool_drvinfo *drvinfo) {
> > + const struct rtase_private *tp = netdev_priv(dev);
> > +
> > + strscpy(drvinfo->driver, KBUILD_MODNAME, 32);
> > + strscpy(drvinfo->bus_info, pci_name(tp->pdev), 32); }
> > +
> > +static int rtase_get_settings(struct net_device *dev,
> > + struct ethtool_link_ksettings *cmd) {
> > + u32 supported = SUPPORTED_MII | SUPPORTED_Pause |
> > +SUPPORTED_Asym_Pause;
> > +
> > +
> ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
> > + supported);
> > + cmd->base.speed = SPEED_5000;
> > + cmd->base.duplex = DUPLEX_FULL;
> > + cmd->base.port = PORT_MII;
> > + cmd->base.autoneg = AUTONEG_DISABLE;
> > +
> What are you reporting here? Does this refer to the link between MAC and
> switch CPU port? Because I would assume that the switch ports can do
> autoneg.

PATCH 1/13 has our CHIP architecture. The mac and switch are directly connected, and the line seed is fixed at 5G, so there is no need for autoneg.
>
> > + 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;
> > +
> > + if ((value & (FORCE_TXFLOW_EN | FORCE_RXFLOW_EN)) ==
> > + (FORCE_TXFLOW_EN | FORCE_RXFLOW_EN)) {
> > + pause->rx_pause = 1;
> > + pause->tx_pause = 1;
> > + } else if ((value & FORCE_TXFLOW_EN)) {
> > + pause->tx_pause = 1;
> > + } else if ((value & FORCE_RXFLOW_EN)) {
> > + pause->rx_pause = 1;
> > + }
> > +}
> > +
> > +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 &= ~(FORCE_TXFLOW_EN | FORCE_RXFLOW_EN);
> > +
> > + if (pause->tx_pause)
> > + value |= FORCE_TXFLOW_EN;
> > +
> > + if (pause->rx_pause)
> > + value |= FORCE_RXFLOW_EN;
> > +
> > + rtase_w16(tp, RTASE_CPLUS_CMD, value);
> > + return 0;
> > +}
> > +
> > +static const char rtase_gstrings[][ETH_GSTRING_LEN] = {
> > + "tx_packets",
> > + "rx_packets",
> > + "tx_errors",
> > + "rx_errors",
> > + "rx_missed",
> > + "align_errors",
> > + "tx_single_collisions",
> > + "tx_multi_collisions",
> > + "unicast",
> > + "broadcast",
> > + "multicast",
> > + "tx_aborted",
> > + "tx_underrun",
> > +};
> > +
> > +static void rtase_get_strings(struct net_device *dev, u32 stringset,
> > +u8 *data) {
> > + switch (stringset) {
> > + case ETH_SS_STATS:
> > + memcpy(data, *rtase_gstrings, sizeof(rtase_gstrings));
> > + break;
> > + }
> > +}
> > +
> > +static int rtase_get_sset_count(struct net_device *dev, int sset) {
> > + int ret = -EOPNOTSUPP;
> > +
> > + switch (sset) {
> > + case ETH_SS_STATS:
> > + ret = ARRAY_SIZE(rtase_gstrings);
> > + break;
> > + }
> > +
> > + return ret;
> > +}
> > +
> > +static void rtase_get_ethtool_stats(struct net_device *dev,
> > + struct ethtool_stats *stats, u64
> > +*data) {
> > + struct rtase_private *tp = netdev_priv(dev);
> > + const struct rtase_counters *counters;
> > +
> > + ASSERT_RTNL();
> > +
> > + counters = tp->tally_vaddr;
> > + if (!counters)
> > + return;
> > +
> > + rtase_dump_tally_counter(tp);
> > +
> > + data[0] = le64_to_cpu(counters->tx_packets);
> > + data[1] = le64_to_cpu(counters->rx_packets);
> > + data[2] = le64_to_cpu(counters->tx_errors);
> > + data[3] = le32_to_cpu(counters->rx_errors);
> > + data[4] = le16_to_cpu(counters->rx_missed);
> > + data[5] = le16_to_cpu(counters->align_errors);
> > + data[6] = le32_to_cpu(counters->tx_one_collision);
> > + data[7] = le32_to_cpu(counters->tx_multi_collision);
> > + data[8] = le64_to_cpu(counters->rx_unicast);
> > + 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);
> > +}
> > +
> > +static const struct ethtool_ops rtase_ethtool_ops = {
> > + .get_drvinfo = rtase_get_drvinfo,
> > + .get_link = ethtool_op_get_link,
> > + .get_link_ksettings = rtase_get_settings,
> > + .get_pauseparam = rtase_get_pauseparam,
> > + .set_pauseparam = rtase_set_pauseparam,
> > + .get_strings = rtase_get_strings,
> > + .get_sset_count = rtase_get_sset_count,
> > + .get_ethtool_stats = rtase_get_ethtool_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,
>