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

ax88796c_ioctl.c (5857B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (c) 2010 ASIX Electronics Corporation
      4 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
      5 *
      6 * ASIX AX88796C SPI Fast Ethernet Linux driver
      7 */
      8
      9#define pr_fmt(fmt)	"ax88796c: " fmt
     10
     11#include <linux/bitmap.h>
     12#include <linux/iopoll.h>
     13#include <linux/phy.h>
     14#include <linux/netdevice.h>
     15
     16#include "ax88796c_main.h"
     17#include "ax88796c_ioctl.h"
     18
     19static const char ax88796c_priv_flag_names[][ETH_GSTRING_LEN] = {
     20	"SPICompression",
     21};
     22
     23static void
     24ax88796c_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
     25{
     26	/* Inherit standard device info */
     27	strncpy(info->driver, DRV_NAME, sizeof(info->driver));
     28}
     29
     30static u32 ax88796c_get_msglevel(struct net_device *ndev)
     31{
     32	struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
     33
     34	return ax_local->msg_enable;
     35}
     36
     37static void ax88796c_set_msglevel(struct net_device *ndev, u32 level)
     38{
     39	struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
     40
     41	ax_local->msg_enable = level;
     42}
     43
     44static void
     45ax88796c_get_pauseparam(struct net_device *ndev, struct ethtool_pauseparam *pause)
     46{
     47	struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
     48
     49	pause->tx_pause = !!(ax_local->flowctrl & AX_FC_TX);
     50	pause->rx_pause = !!(ax_local->flowctrl & AX_FC_RX);
     51	pause->autoneg = (ax_local->flowctrl & AX_FC_ANEG) ?
     52		AUTONEG_ENABLE :
     53		AUTONEG_DISABLE;
     54}
     55
     56static int
     57ax88796c_set_pauseparam(struct net_device *ndev, struct ethtool_pauseparam *pause)
     58{
     59	struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
     60	int fc;
     61
     62	/* The following logic comes from phylink_ethtool_set_pauseparam() */
     63	fc = pause->tx_pause ? AX_FC_TX : 0;
     64	fc |= pause->rx_pause ? AX_FC_RX : 0;
     65	fc |= pause->autoneg ? AX_FC_ANEG : 0;
     66
     67	ax_local->flowctrl = fc;
     68
     69	if (pause->autoneg) {
     70		phy_set_asym_pause(ax_local->phydev, pause->tx_pause,
     71				   pause->rx_pause);
     72	} else {
     73		int maccr = 0;
     74
     75		phy_set_asym_pause(ax_local->phydev, 0, 0);
     76		maccr |= (ax_local->flowctrl & AX_FC_RX) ? MACCR_RXFC_ENABLE : 0;
     77		maccr |= (ax_local->flowctrl & AX_FC_TX) ? MACCR_TXFC_ENABLE : 0;
     78
     79		mutex_lock(&ax_local->spi_lock);
     80
     81		maccr |= AX_READ(&ax_local->ax_spi, P0_MACCR) &
     82			~(MACCR_TXFC_ENABLE | MACCR_RXFC_ENABLE);
     83		AX_WRITE(&ax_local->ax_spi, maccr, P0_MACCR);
     84
     85		mutex_unlock(&ax_local->spi_lock);
     86	}
     87
     88	return 0;
     89}
     90
     91static int ax88796c_get_regs_len(struct net_device *ndev)
     92{
     93	return AX88796C_REGDUMP_LEN + AX88796C_PHY_REGDUMP_LEN;
     94}
     95
     96static void
     97ax88796c_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *_p)
     98{
     99	struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
    100	int offset, i;
    101	u16 *p = _p;
    102
    103	memset(p, 0, ax88796c_get_regs_len(ndev));
    104
    105	mutex_lock(&ax_local->spi_lock);
    106
    107	for (offset = 0; offset < AX88796C_REGDUMP_LEN; offset += 2) {
    108		if (!test_bit(offset / 2, ax88796c_no_regs_mask))
    109			*p = AX_READ(&ax_local->ax_spi, offset);
    110		p++;
    111	}
    112
    113	mutex_unlock(&ax_local->spi_lock);
    114
    115	for (i = 0; i < AX88796C_PHY_REGDUMP_LEN / 2; i++) {
    116		*p = phy_read(ax_local->phydev, i);
    117		p++;
    118	}
    119}
    120
    121static void
    122ax88796c_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
    123{
    124	switch (stringset) {
    125	case ETH_SS_PRIV_FLAGS:
    126		memcpy(data, ax88796c_priv_flag_names,
    127		       sizeof(ax88796c_priv_flag_names));
    128		break;
    129	}
    130}
    131
    132static int
    133ax88796c_get_sset_count(struct net_device *ndev, int stringset)
    134{
    135	int ret = 0;
    136
    137	switch (stringset) {
    138	case ETH_SS_PRIV_FLAGS:
    139		ret = ARRAY_SIZE(ax88796c_priv_flag_names);
    140		break;
    141	default:
    142		ret = -EOPNOTSUPP;
    143	}
    144
    145	return ret;
    146}
    147
    148static int ax88796c_set_priv_flags(struct net_device *ndev, u32 flags)
    149{
    150	struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
    151
    152	if (flags & ~AX_PRIV_FLAGS_MASK)
    153		return -EOPNOTSUPP;
    154
    155	if ((ax_local->priv_flags ^ flags) & AX_CAP_COMP)
    156		if (netif_running(ndev))
    157			return -EBUSY;
    158
    159	ax_local->priv_flags = flags;
    160
    161	return 0;
    162}
    163
    164static u32 ax88796c_get_priv_flags(struct net_device *ndev)
    165{
    166	struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
    167
    168	return ax_local->priv_flags;
    169}
    170
    171int ax88796c_mdio_read(struct mii_bus *mdiobus, int phy_id, int loc)
    172{
    173	struct ax88796c_device *ax_local = mdiobus->priv;
    174	int ret;
    175
    176	mutex_lock(&ax_local->spi_lock);
    177	AX_WRITE(&ax_local->ax_spi, MDIOCR_RADDR(loc)
    178			| MDIOCR_FADDR(phy_id) | MDIOCR_READ, P2_MDIOCR);
    179
    180	ret = read_poll_timeout(AX_READ, ret,
    181				(ret != 0),
    182				0, jiffies_to_usecs(HZ / 100), false,
    183				&ax_local->ax_spi, P2_MDIOCR);
    184	if (!ret)
    185		ret = AX_READ(&ax_local->ax_spi, P2_MDIODR);
    186
    187	mutex_unlock(&ax_local->spi_lock);
    188
    189	return ret;
    190}
    191
    192int
    193ax88796c_mdio_write(struct mii_bus *mdiobus, int phy_id, int loc, u16 val)
    194{
    195	struct ax88796c_device *ax_local = mdiobus->priv;
    196	int ret;
    197
    198	mutex_lock(&ax_local->spi_lock);
    199	AX_WRITE(&ax_local->ax_spi, val, P2_MDIODR);
    200
    201	AX_WRITE(&ax_local->ax_spi,
    202		 MDIOCR_RADDR(loc) | MDIOCR_FADDR(phy_id)
    203		 | MDIOCR_WRITE, P2_MDIOCR);
    204
    205	ret = read_poll_timeout(AX_READ, ret,
    206				((ret & MDIOCR_VALID) != 0), 0,
    207				jiffies_to_usecs(HZ / 100), false,
    208				&ax_local->ax_spi, P2_MDIOCR);
    209	mutex_unlock(&ax_local->spi_lock);
    210
    211	return ret;
    212}
    213
    214const struct ethtool_ops ax88796c_ethtool_ops = {
    215	.get_drvinfo		= ax88796c_get_drvinfo,
    216	.get_link		= ethtool_op_get_link,
    217	.get_msglevel		= ax88796c_get_msglevel,
    218	.set_msglevel		= ax88796c_set_msglevel,
    219	.get_link_ksettings	= phy_ethtool_get_link_ksettings,
    220	.set_link_ksettings	= phy_ethtool_set_link_ksettings,
    221	.nway_reset		= phy_ethtool_nway_reset,
    222	.get_pauseparam		= ax88796c_get_pauseparam,
    223	.set_pauseparam		= ax88796c_set_pauseparam,
    224	.get_regs_len		= ax88796c_get_regs_len,
    225	.get_regs		= ax88796c_get_regs,
    226	.get_strings		= ax88796c_get_strings,
    227	.get_sset_count		= ax88796c_get_sset_count,
    228	.get_priv_flags		= ax88796c_get_priv_flags,
    229	.set_priv_flags		= ax88796c_set_priv_flags,
    230};
    231
    232int ax88796c_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
    233{
    234	int ret;
    235
    236	ret = phy_mii_ioctl(ndev->phydev, ifr, cmd);
    237
    238	return ret;
    239}