brintos

brintos / linux-shallow public Read only

0
0
Text · 5.7 KiB · 7d2fe2e Raw
240 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2010 ASIX Electronics Corporation4 * Copyright (c) 2020 Samsung Electronics Co., Ltd.5 *6 * ASIX AX88796C SPI Fast Ethernet Linux driver7 */8 9#define pr_fmt(fmt)	"ax88796c: " fmt10 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 void24ax88796c_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)25{26	/* Inherit standard device info */27	strscpy(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 void45ax88796c_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 int57ax88796c_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 void97ax88796c_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 void122ax88796c_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 int133ax88796c_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 192int193ax88796c_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}240