GNU Linux-libre 6.8.9-gnu
[releases.git] / drivers / net / ethernet / asix / ax88796c_ioctl.c
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }