0001
0002
0003
0004
0005
0006
0007
0008
0009 #define pr_fmt(fmt) "ax88796c: " fmt
0010
0011 #include <linux/bitmap.h>
0012 #include <linux/iopoll.h>
0013 #include <linux/phy.h>
0014 #include <linux/netdevice.h>
0015
0016 #include "ax88796c_main.h"
0017 #include "ax88796c_ioctl.h"
0018
0019 static const char ax88796c_priv_flag_names[][ETH_GSTRING_LEN] = {
0020 "SPICompression",
0021 };
0022
0023 static void
0024 ax88796c_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info)
0025 {
0026
0027 strncpy(info->driver, DRV_NAME, sizeof(info->driver));
0028 }
0029
0030 static u32 ax88796c_get_msglevel(struct net_device *ndev)
0031 {
0032 struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
0033
0034 return ax_local->msg_enable;
0035 }
0036
0037 static void ax88796c_set_msglevel(struct net_device *ndev, u32 level)
0038 {
0039 struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
0040
0041 ax_local->msg_enable = level;
0042 }
0043
0044 static void
0045 ax88796c_get_pauseparam(struct net_device *ndev, struct ethtool_pauseparam *pause)
0046 {
0047 struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
0048
0049 pause->tx_pause = !!(ax_local->flowctrl & AX_FC_TX);
0050 pause->rx_pause = !!(ax_local->flowctrl & AX_FC_RX);
0051 pause->autoneg = (ax_local->flowctrl & AX_FC_ANEG) ?
0052 AUTONEG_ENABLE :
0053 AUTONEG_DISABLE;
0054 }
0055
0056 static int
0057 ax88796c_set_pauseparam(struct net_device *ndev, struct ethtool_pauseparam *pause)
0058 {
0059 struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
0060 int fc;
0061
0062
0063 fc = pause->tx_pause ? AX_FC_TX : 0;
0064 fc |= pause->rx_pause ? AX_FC_RX : 0;
0065 fc |= pause->autoneg ? AX_FC_ANEG : 0;
0066
0067 ax_local->flowctrl = fc;
0068
0069 if (pause->autoneg) {
0070 phy_set_asym_pause(ax_local->phydev, pause->tx_pause,
0071 pause->rx_pause);
0072 } else {
0073 int maccr = 0;
0074
0075 phy_set_asym_pause(ax_local->phydev, 0, 0);
0076 maccr |= (ax_local->flowctrl & AX_FC_RX) ? MACCR_RXFC_ENABLE : 0;
0077 maccr |= (ax_local->flowctrl & AX_FC_TX) ? MACCR_TXFC_ENABLE : 0;
0078
0079 mutex_lock(&ax_local->spi_lock);
0080
0081 maccr |= AX_READ(&ax_local->ax_spi, P0_MACCR) &
0082 ~(MACCR_TXFC_ENABLE | MACCR_RXFC_ENABLE);
0083 AX_WRITE(&ax_local->ax_spi, maccr, P0_MACCR);
0084
0085 mutex_unlock(&ax_local->spi_lock);
0086 }
0087
0088 return 0;
0089 }
0090
0091 static int ax88796c_get_regs_len(struct net_device *ndev)
0092 {
0093 return AX88796C_REGDUMP_LEN + AX88796C_PHY_REGDUMP_LEN;
0094 }
0095
0096 static void
0097 ax88796c_get_regs(struct net_device *ndev, struct ethtool_regs *regs, void *_p)
0098 {
0099 struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
0100 int offset, i;
0101 u16 *p = _p;
0102
0103 memset(p, 0, ax88796c_get_regs_len(ndev));
0104
0105 mutex_lock(&ax_local->spi_lock);
0106
0107 for (offset = 0; offset < AX88796C_REGDUMP_LEN; offset += 2) {
0108 if (!test_bit(offset / 2, ax88796c_no_regs_mask))
0109 *p = AX_READ(&ax_local->ax_spi, offset);
0110 p++;
0111 }
0112
0113 mutex_unlock(&ax_local->spi_lock);
0114
0115 for (i = 0; i < AX88796C_PHY_REGDUMP_LEN / 2; i++) {
0116 *p = phy_read(ax_local->phydev, i);
0117 p++;
0118 }
0119 }
0120
0121 static void
0122 ax88796c_get_strings(struct net_device *ndev, u32 stringset, u8 *data)
0123 {
0124 switch (stringset) {
0125 case ETH_SS_PRIV_FLAGS:
0126 memcpy(data, ax88796c_priv_flag_names,
0127 sizeof(ax88796c_priv_flag_names));
0128 break;
0129 }
0130 }
0131
0132 static int
0133 ax88796c_get_sset_count(struct net_device *ndev, int stringset)
0134 {
0135 int ret = 0;
0136
0137 switch (stringset) {
0138 case ETH_SS_PRIV_FLAGS:
0139 ret = ARRAY_SIZE(ax88796c_priv_flag_names);
0140 break;
0141 default:
0142 ret = -EOPNOTSUPP;
0143 }
0144
0145 return ret;
0146 }
0147
0148 static int ax88796c_set_priv_flags(struct net_device *ndev, u32 flags)
0149 {
0150 struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
0151
0152 if (flags & ~AX_PRIV_FLAGS_MASK)
0153 return -EOPNOTSUPP;
0154
0155 if ((ax_local->priv_flags ^ flags) & AX_CAP_COMP)
0156 if (netif_running(ndev))
0157 return -EBUSY;
0158
0159 ax_local->priv_flags = flags;
0160
0161 return 0;
0162 }
0163
0164 static u32 ax88796c_get_priv_flags(struct net_device *ndev)
0165 {
0166 struct ax88796c_device *ax_local = to_ax88796c_device(ndev);
0167
0168 return ax_local->priv_flags;
0169 }
0170
0171 int ax88796c_mdio_read(struct mii_bus *mdiobus, int phy_id, int loc)
0172 {
0173 struct ax88796c_device *ax_local = mdiobus->priv;
0174 int ret;
0175
0176 mutex_lock(&ax_local->spi_lock);
0177 AX_WRITE(&ax_local->ax_spi, MDIOCR_RADDR(loc)
0178 | MDIOCR_FADDR(phy_id) | MDIOCR_READ, P2_MDIOCR);
0179
0180 ret = read_poll_timeout(AX_READ, ret,
0181 (ret != 0),
0182 0, jiffies_to_usecs(HZ / 100), false,
0183 &ax_local->ax_spi, P2_MDIOCR);
0184 if (!ret)
0185 ret = AX_READ(&ax_local->ax_spi, P2_MDIODR);
0186
0187 mutex_unlock(&ax_local->spi_lock);
0188
0189 return ret;
0190 }
0191
0192 int
0193 ax88796c_mdio_write(struct mii_bus *mdiobus, int phy_id, int loc, u16 val)
0194 {
0195 struct ax88796c_device *ax_local = mdiobus->priv;
0196 int ret;
0197
0198 mutex_lock(&ax_local->spi_lock);
0199 AX_WRITE(&ax_local->ax_spi, val, P2_MDIODR);
0200
0201 AX_WRITE(&ax_local->ax_spi,
0202 MDIOCR_RADDR(loc) | MDIOCR_FADDR(phy_id)
0203 | MDIOCR_WRITE, P2_MDIOCR);
0204
0205 ret = read_poll_timeout(AX_READ, ret,
0206 ((ret & MDIOCR_VALID) != 0), 0,
0207 jiffies_to_usecs(HZ / 100), false,
0208 &ax_local->ax_spi, P2_MDIOCR);
0209 mutex_unlock(&ax_local->spi_lock);
0210
0211 return ret;
0212 }
0213
0214 const struct ethtool_ops ax88796c_ethtool_ops = {
0215 .get_drvinfo = ax88796c_get_drvinfo,
0216 .get_link = ethtool_op_get_link,
0217 .get_msglevel = ax88796c_get_msglevel,
0218 .set_msglevel = ax88796c_set_msglevel,
0219 .get_link_ksettings = phy_ethtool_get_link_ksettings,
0220 .set_link_ksettings = phy_ethtool_set_link_ksettings,
0221 .nway_reset = phy_ethtool_nway_reset,
0222 .get_pauseparam = ax88796c_get_pauseparam,
0223 .set_pauseparam = ax88796c_set_pauseparam,
0224 .get_regs_len = ax88796c_get_regs_len,
0225 .get_regs = ax88796c_get_regs,
0226 .get_strings = ax88796c_get_strings,
0227 .get_sset_count = ax88796c_get_sset_count,
0228 .get_priv_flags = ax88796c_get_priv_flags,
0229 .set_priv_flags = ax88796c_set_priv_flags,
0230 };
0231
0232 int ax88796c_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd)
0233 {
0234 int ret;
0235
0236 ret = phy_mii_ioctl(ndev->phydev, ifr, cmd);
0237
0238 return ret;
0239 }