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

atl1c_ethtool.c (8280B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright(c) 2009 - 2009 Atheros Corporation. All rights reserved.
      4 *
      5 * Derived from Intel e1000 driver
      6 * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
      7 */
      8
      9#include <linux/netdevice.h>
     10#include <linux/ethtool.h>
     11#include <linux/slab.h>
     12
     13#include "atl1c.h"
     14
     15static int atl1c_get_link_ksettings(struct net_device *netdev,
     16				    struct ethtool_link_ksettings *cmd)
     17{
     18	struct atl1c_adapter *adapter = netdev_priv(netdev);
     19	struct atl1c_hw *hw = &adapter->hw;
     20	u32 supported, advertising;
     21
     22	supported = (SUPPORTED_10baseT_Half  |
     23			   SUPPORTED_10baseT_Full  |
     24			   SUPPORTED_100baseT_Half |
     25			   SUPPORTED_100baseT_Full |
     26			   SUPPORTED_Autoneg       |
     27			   SUPPORTED_TP);
     28	if (hw->link_cap_flags & ATL1C_LINK_CAP_1000M)
     29		supported |= SUPPORTED_1000baseT_Full;
     30
     31	advertising = ADVERTISED_TP;
     32
     33	advertising |= hw->autoneg_advertised;
     34
     35	cmd->base.port = PORT_TP;
     36	cmd->base.phy_address = 0;
     37
     38	if (adapter->link_speed != SPEED_0) {
     39		cmd->base.speed = adapter->link_speed;
     40		if (adapter->link_duplex == FULL_DUPLEX)
     41			cmd->base.duplex = DUPLEX_FULL;
     42		else
     43			cmd->base.duplex = DUPLEX_HALF;
     44	} else {
     45		cmd->base.speed = SPEED_UNKNOWN;
     46		cmd->base.duplex = DUPLEX_UNKNOWN;
     47	}
     48
     49	cmd->base.autoneg = AUTONEG_ENABLE;
     50
     51	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.supported,
     52						supported);
     53	ethtool_convert_legacy_u32_to_link_mode(cmd->link_modes.advertising,
     54						advertising);
     55
     56	return 0;
     57}
     58
     59static int atl1c_set_link_ksettings(struct net_device *netdev,
     60				    const struct ethtool_link_ksettings *cmd)
     61{
     62	struct atl1c_adapter *adapter = netdev_priv(netdev);
     63	struct atl1c_hw *hw = &adapter->hw;
     64	u16  autoneg_advertised;
     65
     66	while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
     67		msleep(1);
     68
     69	if (cmd->base.autoneg == AUTONEG_ENABLE) {
     70		autoneg_advertised = ADVERTISED_Autoneg;
     71	} else {
     72		u32 speed = cmd->base.speed;
     73		if (speed == SPEED_1000) {
     74			if (cmd->base.duplex != DUPLEX_FULL) {
     75				if (netif_msg_link(adapter))
     76					dev_warn(&adapter->pdev->dev,
     77						"1000M half is invalid\n");
     78				clear_bit(__AT_RESETTING, &adapter->flags);
     79				return -EINVAL;
     80			}
     81			autoneg_advertised = ADVERTISED_1000baseT_Full;
     82		} else if (speed == SPEED_100) {
     83			if (cmd->base.duplex == DUPLEX_FULL)
     84				autoneg_advertised = ADVERTISED_100baseT_Full;
     85			else
     86				autoneg_advertised = ADVERTISED_100baseT_Half;
     87		} else {
     88			if (cmd->base.duplex == DUPLEX_FULL)
     89				autoneg_advertised = ADVERTISED_10baseT_Full;
     90			else
     91				autoneg_advertised = ADVERTISED_10baseT_Half;
     92		}
     93	}
     94
     95	if (hw->autoneg_advertised != autoneg_advertised) {
     96		hw->autoneg_advertised = autoneg_advertised;
     97		if (atl1c_restart_autoneg(hw) != 0) {
     98			if (netif_msg_link(adapter))
     99				dev_warn(&adapter->pdev->dev,
    100					"ethtool speed/duplex setting failed\n");
    101			clear_bit(__AT_RESETTING, &adapter->flags);
    102			return -EINVAL;
    103		}
    104	}
    105	clear_bit(__AT_RESETTING, &adapter->flags);
    106	return 0;
    107}
    108
    109static u32 atl1c_get_msglevel(struct net_device *netdev)
    110{
    111	struct atl1c_adapter *adapter = netdev_priv(netdev);
    112	return adapter->msg_enable;
    113}
    114
    115static void atl1c_set_msglevel(struct net_device *netdev, u32 data)
    116{
    117	struct atl1c_adapter *adapter = netdev_priv(netdev);
    118	adapter->msg_enable = data;
    119}
    120
    121static int atl1c_get_regs_len(struct net_device *netdev)
    122{
    123	return AT_REGS_LEN;
    124}
    125
    126static void atl1c_get_regs(struct net_device *netdev,
    127			   struct ethtool_regs *regs, void *p)
    128{
    129	struct atl1c_adapter *adapter = netdev_priv(netdev);
    130	struct atl1c_hw *hw = &adapter->hw;
    131	u32 *regs_buff = p;
    132	u16 phy_data;
    133
    134	memset(p, 0, AT_REGS_LEN);
    135
    136	regs->version = 1;
    137	AT_READ_REG(hw, REG_PM_CTRL, 		  p++);
    138	AT_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL,  p++);
    139	AT_READ_REG(hw, REG_TWSI_CTRL, 		  p++);
    140	AT_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL,   p++);
    141	AT_READ_REG(hw, REG_MASTER_CTRL, 	  p++);
    142	AT_READ_REG(hw, REG_MANUAL_TIMER_INIT,    p++);
    143	AT_READ_REG(hw, REG_IRQ_MODRT_TIMER_INIT, p++);
    144	AT_READ_REG(hw, REG_GPHY_CTRL, 		  p++);
    145	AT_READ_REG(hw, REG_LINK_CTRL, 		  p++);
    146	AT_READ_REG(hw, REG_IDLE_STATUS, 	  p++);
    147	AT_READ_REG(hw, REG_MDIO_CTRL, 		  p++);
    148	AT_READ_REG(hw, REG_SERDES,		  p++);
    149	AT_READ_REG(hw, REG_MAC_CTRL, 		  p++);
    150	AT_READ_REG(hw, REG_MAC_IPG_IFG, 	  p++);
    151	AT_READ_REG(hw, REG_MAC_STA_ADDR, 	  p++);
    152	AT_READ_REG(hw, REG_MAC_STA_ADDR+4, 	  p++);
    153	AT_READ_REG(hw, REG_RX_HASH_TABLE, 	  p++);
    154	AT_READ_REG(hw, REG_RX_HASH_TABLE+4, 	  p++);
    155	AT_READ_REG(hw, REG_RXQ_CTRL, 		  p++);
    156	AT_READ_REG(hw, REG_TXQ_CTRL, 		  p++);
    157	AT_READ_REG(hw, REG_MTU, 		  p++);
    158	AT_READ_REG(hw, REG_WOL_CTRL, 		  p++);
    159
    160	atl1c_read_phy_reg(hw, MII_BMCR, &phy_data);
    161	regs_buff[AT_REGS_LEN/sizeof(u32) - 2] = (u32) phy_data;
    162	atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
    163	regs_buff[AT_REGS_LEN/sizeof(u32) - 1] = (u32) phy_data;
    164}
    165
    166static int atl1c_get_eeprom_len(struct net_device *netdev)
    167{
    168	struct atl1c_adapter *adapter = netdev_priv(netdev);
    169
    170	if (atl1c_check_eeprom_exist(&adapter->hw))
    171		return AT_EEPROM_LEN;
    172	else
    173		return 0;
    174}
    175
    176static int atl1c_get_eeprom(struct net_device *netdev,
    177		struct ethtool_eeprom *eeprom, u8 *bytes)
    178{
    179	struct atl1c_adapter *adapter = netdev_priv(netdev);
    180	struct atl1c_hw *hw = &adapter->hw;
    181	u32 *eeprom_buff;
    182	int first_dword, last_dword;
    183	int ret_val = 0;
    184	int i;
    185
    186	if (eeprom->len == 0)
    187		return -EINVAL;
    188
    189	if (!atl1c_check_eeprom_exist(hw)) /* not exist */
    190		return -EINVAL;
    191
    192	eeprom->magic = adapter->pdev->vendor |
    193			(adapter->pdev->device << 16);
    194
    195	first_dword = eeprom->offset >> 2;
    196	last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
    197
    198	eeprom_buff = kmalloc_array(last_dword - first_dword + 1, sizeof(u32),
    199				    GFP_KERNEL);
    200	if (eeprom_buff == NULL)
    201		return -ENOMEM;
    202
    203	for (i = first_dword; i < last_dword; i++) {
    204		if (!atl1c_read_eeprom(hw, i * 4, &(eeprom_buff[i-first_dword]))) {
    205			kfree(eeprom_buff);
    206			return -EIO;
    207		}
    208	}
    209
    210	memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3),
    211			eeprom->len);
    212	kfree(eeprom_buff);
    213
    214	return ret_val;
    215	return 0;
    216}
    217
    218static void atl1c_get_drvinfo(struct net_device *netdev,
    219		struct ethtool_drvinfo *drvinfo)
    220{
    221	struct atl1c_adapter *adapter = netdev_priv(netdev);
    222
    223	strlcpy(drvinfo->driver,  atl1c_driver_name, sizeof(drvinfo->driver));
    224	strlcpy(drvinfo->bus_info, pci_name(adapter->pdev),
    225		sizeof(drvinfo->bus_info));
    226}
    227
    228static void atl1c_get_wol(struct net_device *netdev,
    229			  struct ethtool_wolinfo *wol)
    230{
    231	struct atl1c_adapter *adapter = netdev_priv(netdev);
    232
    233	wol->supported = WAKE_MAGIC | WAKE_PHY;
    234	wol->wolopts = 0;
    235
    236	if (adapter->wol & AT_WUFC_EX)
    237		wol->wolopts |= WAKE_UCAST;
    238	if (adapter->wol & AT_WUFC_MC)
    239		wol->wolopts |= WAKE_MCAST;
    240	if (adapter->wol & AT_WUFC_BC)
    241		wol->wolopts |= WAKE_BCAST;
    242	if (adapter->wol & AT_WUFC_MAG)
    243		wol->wolopts |= WAKE_MAGIC;
    244	if (adapter->wol & AT_WUFC_LNKC)
    245		wol->wolopts |= WAKE_PHY;
    246}
    247
    248static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
    249{
    250	struct atl1c_adapter *adapter = netdev_priv(netdev);
    251
    252	if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
    253			    WAKE_UCAST | WAKE_BCAST | WAKE_MCAST))
    254		return -EOPNOTSUPP;
    255	/* these settings will always override what we currently have */
    256	adapter->wol = 0;
    257
    258	if (wol->wolopts & WAKE_MAGIC)
    259		adapter->wol |= AT_WUFC_MAG;
    260	if (wol->wolopts & WAKE_PHY)
    261		adapter->wol |= AT_WUFC_LNKC;
    262
    263	device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
    264
    265	return 0;
    266}
    267
    268static int atl1c_nway_reset(struct net_device *netdev)
    269{
    270	struct atl1c_adapter *adapter = netdev_priv(netdev);
    271	if (netif_running(netdev))
    272		atl1c_reinit_locked(adapter);
    273	return 0;
    274}
    275
    276static const struct ethtool_ops atl1c_ethtool_ops = {
    277	.get_drvinfo            = atl1c_get_drvinfo,
    278	.get_regs_len           = atl1c_get_regs_len,
    279	.get_regs               = atl1c_get_regs,
    280	.get_wol                = atl1c_get_wol,
    281	.set_wol                = atl1c_set_wol,
    282	.get_msglevel           = atl1c_get_msglevel,
    283	.set_msglevel           = atl1c_set_msglevel,
    284	.nway_reset             = atl1c_nway_reset,
    285	.get_link               = ethtool_op_get_link,
    286	.get_eeprom_len         = atl1c_get_eeprom_len,
    287	.get_eeprom             = atl1c_get_eeprom,
    288	.get_link_ksettings     = atl1c_get_link_ksettings,
    289	.set_link_ksettings     = atl1c_set_link_ksettings,
    290};
    291
    292void atl1c_set_ethtool_ops(struct net_device *netdev)
    293{
    294	netdev->ethtool_ops = &atl1c_ethtool_ops;
    295}