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
19 static const char ax88796c_priv_flag_names[][ETH_GSTRING_LEN] = {
20 "SPICompression",
21 };
22
23 static void
ax88796c_get_drvinfo(struct net_device * ndev,struct ethtool_drvinfo * info)24 ax88796c_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
ax88796c_get_msglevel(struct net_device * ndev)30 static 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
ax88796c_set_msglevel(struct net_device * ndev,u32 level)37 static 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
44 static void
ax88796c_get_pauseparam(struct net_device * ndev,struct ethtool_pauseparam * pause)45 ax88796c_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
56 static int
ax88796c_set_pauseparam(struct net_device * ndev,struct ethtool_pauseparam * pause)57 ax88796c_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
ax88796c_get_regs_len(struct net_device * ndev)91 static int ax88796c_get_regs_len(struct net_device *ndev)
92 {
93 return AX88796C_REGDUMP_LEN + AX88796C_PHY_REGDUMP_LEN;
94 }
95
96 static void
ax88796c_get_regs(struct net_device * ndev,struct ethtool_regs * regs,void * _p)97 ax88796c_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
121 static void
ax88796c_get_strings(struct net_device * ndev,u32 stringset,u8 * data)122 ax88796c_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
132 static int
ax88796c_get_sset_count(struct net_device * ndev,int stringset)133 ax88796c_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
ax88796c_set_priv_flags(struct net_device * ndev,u32 flags)148 static 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
ax88796c_get_priv_flags(struct net_device * ndev)164 static 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
ax88796c_mdio_read(struct mii_bus * mdiobus,int phy_id,int loc)171 int 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
192 int
ax88796c_mdio_write(struct mii_bus * mdiobus,int phy_id,int loc,u16 val)193 ax88796c_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
214 const 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
ax88796c_ioctl(struct net_device * ndev,struct ifreq * ifr,int cmd)232 int 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