cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ucc_geth_ethtool.c (11049B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (c) 2007 Freescale Semiconductor, Inc. All rights reserved.
      4 *
      5 * Description: QE UCC Gigabit Ethernet Ethtool API Set
      6 *
      7 * Author: Li Yang <leoli@freescale.com>
      8 *
      9 * Limitation:
     10 * Can only get/set settings of the first queue.
     11 * Need to re-open the interface manually after changing some parameters.
     12 */
     13
     14#include <linux/kernel.h>
     15#include <linux/errno.h>
     16#include <linux/stddef.h>
     17#include <linux/interrupt.h>
     18#include <linux/netdevice.h>
     19#include <linux/etherdevice.h>
     20#include <linux/skbuff.h>
     21#include <linux/spinlock.h>
     22#include <linux/mm.h>
     23#include <linux/delay.h>
     24#include <linux/dma-mapping.h>
     25#include <linux/ethtool.h>
     26#include <linux/mii.h>
     27#include <linux/phy.h>
     28
     29#include <asm/io.h>
     30#include <asm/irq.h>
     31#include <linux/uaccess.h>
     32#include <asm/types.h>
     33
     34#include "ucc_geth.h"
     35
     36static const char hw_stat_gstrings[][ETH_GSTRING_LEN] = {
     37	"tx-64-frames",
     38	"tx-65-127-frames",
     39	"tx-128-255-frames",
     40	"rx-64-frames",
     41	"rx-65-127-frames",
     42	"rx-128-255-frames",
     43	"tx-bytes-ok",
     44	"tx-pause-frames",
     45	"tx-multicast-frames",
     46	"tx-broadcast-frames",
     47	"rx-frames",
     48	"rx-bytes-ok",
     49	"rx-bytes-all",
     50	"rx-multicast-frames",
     51	"rx-broadcast-frames",
     52	"stats-counter-carry",
     53	"stats-counter-mask",
     54	"rx-dropped-frames",
     55};
     56
     57static const char tx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
     58	"tx-single-collision",
     59	"tx-multiple-collision",
     60	"tx-late-collision",
     61	"tx-aborted-frames",
     62	"tx-lost-frames",
     63	"tx-carrier-sense-errors",
     64	"tx-frames-ok",
     65	"tx-excessive-differ-frames",
     66	"tx-256-511-frames",
     67	"tx-512-1023-frames",
     68	"tx-1024-1518-frames",
     69	"tx-jumbo-frames",
     70};
     71
     72static const char rx_fw_stat_gstrings[][ETH_GSTRING_LEN] = {
     73	"rx-crc-errors",
     74	"rx-alignment-errors",
     75	"rx-in-range-length-errors",
     76	"rx-out-of-range-length-errors",
     77	"rx-too-long-frames",
     78	"rx-runt",
     79	"rx-very-long-event",
     80	"rx-symbol-errors",
     81	"rx-busy-drop-frames",
     82	"reserved",
     83	"reserved",
     84	"rx-mismatch-drop-frames",
     85	"rx-small-than-64",
     86	"rx-256-511-frames",
     87	"rx-512-1023-frames",
     88	"rx-1024-1518-frames",
     89	"rx-jumbo-frames",
     90	"rx-mac-error-loss",
     91	"rx-pause-frames",
     92	"reserved",
     93	"rx-vlan-removed",
     94	"rx-vlan-replaced",
     95	"rx-vlan-inserted",
     96	"rx-ip-checksum-errors",
     97};
     98
     99#define UEC_HW_STATS_LEN ARRAY_SIZE(hw_stat_gstrings)
    100#define UEC_TX_FW_STATS_LEN ARRAY_SIZE(tx_fw_stat_gstrings)
    101#define UEC_RX_FW_STATS_LEN ARRAY_SIZE(rx_fw_stat_gstrings)
    102
    103static int
    104uec_get_ksettings(struct net_device *netdev, struct ethtool_link_ksettings *cmd)
    105{
    106	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    107	struct phy_device *phydev = ugeth->phydev;
    108
    109	if (!phydev)
    110		return -ENODEV;
    111
    112	phy_ethtool_ksettings_get(phydev, cmd);
    113
    114	return 0;
    115}
    116
    117static int
    118uec_set_ksettings(struct net_device *netdev,
    119		  const struct ethtool_link_ksettings *cmd)
    120{
    121	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    122	struct phy_device *phydev = ugeth->phydev;
    123
    124	if (!phydev)
    125		return -ENODEV;
    126
    127	return phy_ethtool_ksettings_set(phydev, cmd);
    128}
    129
    130static void
    131uec_get_pauseparam(struct net_device *netdev,
    132                     struct ethtool_pauseparam *pause)
    133{
    134	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    135
    136	pause->autoneg = ugeth->phydev->autoneg;
    137
    138	if (ugeth->ug_info->receiveFlowControl)
    139		pause->rx_pause = 1;
    140	if (ugeth->ug_info->transmitFlowControl)
    141		pause->tx_pause = 1;
    142}
    143
    144static int
    145uec_set_pauseparam(struct net_device *netdev,
    146                     struct ethtool_pauseparam *pause)
    147{
    148	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    149	int ret = 0;
    150
    151	ugeth->ug_info->receiveFlowControl = pause->rx_pause;
    152	ugeth->ug_info->transmitFlowControl = pause->tx_pause;
    153
    154	if (ugeth->phydev->autoneg) {
    155		if (netif_running(netdev)) {
    156			/* FIXME: automatically restart */
    157			netdev_info(netdev, "Please re-open the interface\n");
    158		}
    159	} else {
    160		struct ucc_geth_info *ug_info = ugeth->ug_info;
    161
    162		ret = init_flow_control_params(ug_info->aufc,
    163					ug_info->receiveFlowControl,
    164					ug_info->transmitFlowControl,
    165					ug_info->pausePeriod,
    166					ug_info->extensionField,
    167					&ugeth->uccf->uf_regs->upsmr,
    168					&ugeth->ug_regs->uempr,
    169					&ugeth->ug_regs->maccfg1);
    170	}
    171
    172	return ret;
    173}
    174
    175static uint32_t
    176uec_get_msglevel(struct net_device *netdev)
    177{
    178	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    179	return ugeth->msg_enable;
    180}
    181
    182static void
    183uec_set_msglevel(struct net_device *netdev, uint32_t data)
    184{
    185	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    186	ugeth->msg_enable = data;
    187}
    188
    189static int
    190uec_get_regs_len(struct net_device *netdev)
    191{
    192	return sizeof(struct ucc_geth);
    193}
    194
    195static void
    196uec_get_regs(struct net_device *netdev,
    197               struct ethtool_regs *regs, void *p)
    198{
    199	int i;
    200	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    201	u32 __iomem *ug_regs = (u32 __iomem *)ugeth->ug_regs;
    202	u32 *buff = p;
    203
    204	for (i = 0; i < sizeof(struct ucc_geth) / sizeof(u32); i++)
    205		buff[i] = in_be32(&ug_regs[i]);
    206}
    207
    208static void
    209uec_get_ringparam(struct net_device *netdev,
    210		  struct ethtool_ringparam *ring,
    211		  struct kernel_ethtool_ringparam *kernel_ring,
    212		  struct netlink_ext_ack *extack)
    213{
    214	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    215	struct ucc_geth_info *ug_info = ugeth->ug_info;
    216	int queue = 0;
    217
    218	ring->rx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
    219	ring->rx_mini_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
    220	ring->rx_jumbo_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
    221	ring->tx_max_pending = UCC_GETH_BD_RING_SIZE_MAX;
    222
    223	ring->rx_pending = ug_info->bdRingLenRx[queue];
    224	ring->rx_mini_pending = ug_info->bdRingLenRx[queue];
    225	ring->rx_jumbo_pending = ug_info->bdRingLenRx[queue];
    226	ring->tx_pending = ug_info->bdRingLenTx[queue];
    227}
    228
    229static int
    230uec_set_ringparam(struct net_device *netdev,
    231		  struct ethtool_ringparam *ring,
    232		  struct kernel_ethtool_ringparam *kernel_ring,
    233		  struct netlink_ext_ack *extack)
    234{
    235	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    236	struct ucc_geth_info *ug_info = ugeth->ug_info;
    237	int queue = 0, ret = 0;
    238
    239	if (ring->rx_pending < UCC_GETH_RX_BD_RING_SIZE_MIN) {
    240		netdev_info(netdev, "RxBD ring size must be no smaller than %d\n",
    241			    UCC_GETH_RX_BD_RING_SIZE_MIN);
    242		return -EINVAL;
    243	}
    244	if (ring->rx_pending % UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT) {
    245		netdev_info(netdev, "RxBD ring size must be multiple of %d\n",
    246			    UCC_GETH_RX_BD_RING_SIZE_ALIGNMENT);
    247		return -EINVAL;
    248	}
    249	if (ring->tx_pending < UCC_GETH_TX_BD_RING_SIZE_MIN) {
    250		netdev_info(netdev, "TxBD ring size must be no smaller than %d\n",
    251			    UCC_GETH_TX_BD_RING_SIZE_MIN);
    252		return -EINVAL;
    253	}
    254
    255	if (netif_running(netdev))
    256		return -EBUSY;
    257
    258	ug_info->bdRingLenRx[queue] = ring->rx_pending;
    259	ug_info->bdRingLenTx[queue] = ring->tx_pending;
    260
    261	return ret;
    262}
    263
    264static int uec_get_sset_count(struct net_device *netdev, int sset)
    265{
    266	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    267	u32 stats_mode = ugeth->ug_info->statisticsMode;
    268	int len = 0;
    269
    270	switch (sset) {
    271	case ETH_SS_STATS:
    272		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE)
    273			len += UEC_HW_STATS_LEN;
    274		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX)
    275			len += UEC_TX_FW_STATS_LEN;
    276		if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
    277			len += UEC_RX_FW_STATS_LEN;
    278
    279		return len;
    280
    281	default:
    282		return -EOPNOTSUPP;
    283	}
    284}
    285
    286static void uec_get_strings(struct net_device *netdev, u32 stringset, u8 *buf)
    287{
    288	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    289	u32 stats_mode = ugeth->ug_info->statisticsMode;
    290
    291	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
    292		memcpy(buf, hw_stat_gstrings, UEC_HW_STATS_LEN *
    293			       	ETH_GSTRING_LEN);
    294		buf += UEC_HW_STATS_LEN * ETH_GSTRING_LEN;
    295	}
    296	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
    297		memcpy(buf, tx_fw_stat_gstrings, UEC_TX_FW_STATS_LEN *
    298			       	ETH_GSTRING_LEN);
    299		buf += UEC_TX_FW_STATS_LEN * ETH_GSTRING_LEN;
    300	}
    301	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX)
    302		memcpy(buf, rx_fw_stat_gstrings, UEC_RX_FW_STATS_LEN *
    303			       	ETH_GSTRING_LEN);
    304}
    305
    306static void uec_get_ethtool_stats(struct net_device *netdev,
    307		struct ethtool_stats *stats, uint64_t *data)
    308{
    309	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    310	u32 stats_mode = ugeth->ug_info->statisticsMode;
    311	u32 __iomem *base;
    312	int i, j = 0;
    313
    314	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_HARDWARE) {
    315		if (ugeth->ug_regs)
    316			base = (u32 __iomem *)&ugeth->ug_regs->tx64;
    317		else
    318			base = NULL;
    319
    320		for (i = 0; i < UEC_HW_STATS_LEN; i++)
    321			data[j++] = base ? in_be32(&base[i]) : 0;
    322	}
    323	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_TX) {
    324		base = (u32 __iomem *)ugeth->p_tx_fw_statistics_pram;
    325		for (i = 0; i < UEC_TX_FW_STATS_LEN; i++)
    326			data[j++] = base ? in_be32(&base[i]) : 0;
    327	}
    328	if (stats_mode & UCC_GETH_STATISTICS_GATHERING_MODE_FIRMWARE_RX) {
    329		base = (u32 __iomem *)ugeth->p_rx_fw_statistics_pram;
    330		for (i = 0; i < UEC_RX_FW_STATS_LEN; i++)
    331			data[j++] = base ? in_be32(&base[i]) : 0;
    332	}
    333}
    334
    335/* Report driver information */
    336static void
    337uec_get_drvinfo(struct net_device *netdev,
    338                       struct ethtool_drvinfo *drvinfo)
    339{
    340	strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
    341	strlcpy(drvinfo->bus_info, "QUICC ENGINE", sizeof(drvinfo->bus_info));
    342}
    343
    344#ifdef CONFIG_PM
    345
    346static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
    347{
    348	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    349	struct phy_device *phydev = ugeth->phydev;
    350
    351	if (phydev && phydev->irq)
    352		wol->supported |= WAKE_PHY;
    353	if (qe_alive_during_sleep())
    354		wol->supported |= WAKE_MAGIC;
    355
    356	wol->wolopts = ugeth->wol_en;
    357}
    358
    359static int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
    360{
    361	struct ucc_geth_private *ugeth = netdev_priv(netdev);
    362	struct phy_device *phydev = ugeth->phydev;
    363
    364	if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
    365		return -EINVAL;
    366	else if (wol->wolopts & WAKE_PHY && (!phydev || !phydev->irq))
    367		return -EINVAL;
    368	else if (wol->wolopts & WAKE_MAGIC && !qe_alive_during_sleep())
    369		return -EINVAL;
    370
    371	ugeth->wol_en = wol->wolopts;
    372	device_set_wakeup_enable(&netdev->dev, ugeth->wol_en);
    373
    374	return 0;
    375}
    376
    377#else
    378#define uec_get_wol NULL
    379#define uec_set_wol NULL
    380#endif /* CONFIG_PM */
    381
    382static const struct ethtool_ops uec_ethtool_ops = {
    383	.get_drvinfo            = uec_get_drvinfo,
    384	.get_regs_len           = uec_get_regs_len,
    385	.get_regs               = uec_get_regs,
    386	.get_msglevel           = uec_get_msglevel,
    387	.set_msglevel           = uec_set_msglevel,
    388	.nway_reset             = phy_ethtool_nway_reset,
    389	.get_link               = ethtool_op_get_link,
    390	.get_ringparam          = uec_get_ringparam,
    391	.set_ringparam          = uec_set_ringparam,
    392	.get_pauseparam         = uec_get_pauseparam,
    393	.set_pauseparam         = uec_set_pauseparam,
    394	.get_sset_count		= uec_get_sset_count,
    395	.get_strings            = uec_get_strings,
    396	.get_ethtool_stats      = uec_get_ethtool_stats,
    397	.get_wol		= uec_get_wol,
    398	.set_wol		= uec_set_wol,
    399	.get_ts_info		= ethtool_op_get_ts_info,
    400	.get_link_ksettings	= uec_get_ksettings,
    401	.set_link_ksettings	= uec_set_ksettings,
    402};
    403
    404void uec_set_ethtool_ops(struct net_device *netdev)
    405{
    406	netdev->ethtool_ops = &uec_ethtool_ops;
    407}