Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2010 ASIX Electronics Corporation
0004  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
0005  *
0006  * ASIX AX88796C SPI Fast Ethernet Linux driver
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     /* Inherit standard device info */
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     /* The following logic comes from phylink_ethtool_set_pauseparam() */
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 }