diff mbox series

[net-next,v11,10/13] net:ethernet:realtek:rtase: Implement ethtool function

Message ID 20231115133414.1221480-11-justinlai0215@realtek.com (mailing list archive)
State Superseded
Delegated to: Netdev Maintainers
Headers show
Series Add Realtek automotive PCIe driver | expand

Checks

Context Check Description
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for net-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 8 this patch: 8
netdev/cc_maintainers success CCed 5 of 5 maintainers
netdev/build_clang success Errors and warnings before: 8 this patch: 8
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 8 this patch: 8
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 153 lines checked
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0

Commit Message

Justin Lai Nov. 15, 2023, 1:34 p.m. UTC
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 <justinlai0215@realtek.com>
---
 .../net/ethernet/realtek/rtase/rtase_main.c   | 144 ++++++++++++++++++
 1 file changed, 144 insertions(+)

Comments

Heiner Kallweit Nov. 15, 2023, 3:02 p.m. UTC | #1
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 <justinlai0215@realtek.com>
> ---
>  .../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,
Justin Lai Nov. 23, 2023, 3:16 a.m. UTC | #2
> 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 <justinlai0215@realtek.com>
> > ---
> >  .../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,
>
diff mbox series

Patch

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,