1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 ################################################################################
4 #
5 # r8168 is the Linux device driver released for Realtek Gigabit Ethernet
6 # controllers with PCI-Express interface.
7 #
8 # Copyright(c) 2021 Realtek Semiconductor Corp. All rights reserved.
9 #
10 # This program is free software; you can redistribute it and/or modify it
11 # under the terms of the GNU General Public License as published by the Free
12 # Software Foundation; either version 2 of the License, or (at your option)
13 # any later version.
14 #
15 # This program is distributed in the hope that it will be useful, but WITHOUT
16 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
17 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
18 # more details.
19 #
20 # You should have received a copy of the GNU General Public License along with
21 # this program; if not, see <http://www.gnu.org/licenses/>.
22 #
23 # Author:
24 # Realtek NIC software team <nicfae@realtek.com>
25 # No. 2, Innovation Road II, Hsinchu Science Park, Hsinchu 300, Taiwan
26 #
27 ################################################################################
28 */
29
30 /************************************************************************************
31 * This product is covered by one or more of the following patents:
32 * US6,570,884, US6,115,776, and US6,327,625.
33 ***********************************************************************************/
34
35 #include <linux/module.h>
36 #include <linux/version.h>
37 #include <linux/pci.h>
38 #include <linux/netdevice.h>
39 #include <linux/delay.h>
40 #include <linux/in.h>
41 #include <linux/ethtool.h>
42 #include <asm/uaccess.h>
43 #include "r8168.h"
44 #include "rtl_eeprom.h"
45 #include "rtltool.h"
46
rtl8168_tool_ioctl(struct rtl8168_private * tp,struct ifreq * ifr)47 int rtl8168_tool_ioctl(struct rtl8168_private *tp, struct ifreq *ifr)
48 {
49 struct rtltool_cmd my_cmd;
50 unsigned long flags;
51 int ret;
52
53 if (copy_from_user(&my_cmd, ifr->ifr_data, sizeof(my_cmd)))
54 return -EFAULT;
55
56 ret = 0;
57 switch (my_cmd.cmd) {
58 case RTLTOOL_READ_MAC:
59 if (!capable(CAP_NET_ADMIN))
60 return -EPERM;
61
62 if (my_cmd.len==1)
63 my_cmd.data = readb(tp->mmio_addr+my_cmd.offset);
64 else if (my_cmd.len==2)
65 my_cmd.data = readw(tp->mmio_addr+(my_cmd.offset&~1));
66 else if (my_cmd.len==4)
67 my_cmd.data = readl(tp->mmio_addr+(my_cmd.offset&~3));
68 else {
69 ret = -EOPNOTSUPP;
70 break;
71 }
72
73 if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
74 ret = -EFAULT;
75 break;
76 }
77 break;
78
79 case RTLTOOL_WRITE_MAC:
80 if (!capable(CAP_NET_ADMIN))
81 return -EPERM;
82
83 if (my_cmd.len==1)
84 writeb(my_cmd.data, tp->mmio_addr+my_cmd.offset);
85 else if (my_cmd.len==2)
86 writew(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~1));
87 else if (my_cmd.len==4)
88 writel(my_cmd.data, tp->mmio_addr+(my_cmd.offset&~3));
89 else {
90 ret = -EOPNOTSUPP;
91 break;
92 }
93
94 break;
95
96 case RTLTOOL_READ_PHY:
97 if (!capable(CAP_NET_ADMIN))
98 return -EPERM;
99
100 spin_lock_irqsave(&tp->lock, flags);
101 my_cmd.data = rtl8168_mdio_prot_read(tp, my_cmd.offset);
102 spin_unlock_irqrestore(&tp->lock, flags);
103
104 if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
105 ret = -EFAULT;
106 break;
107 }
108
109 break;
110
111 case RTLTOOL_WRITE_PHY:
112 if (!capable(CAP_NET_ADMIN))
113 return -EPERM;
114
115 spin_lock_irqsave(&tp->lock, flags);
116 rtl8168_mdio_prot_write(tp, my_cmd.offset, my_cmd.data);
117 spin_unlock_irqrestore(&tp->lock, flags);
118 break;
119
120 case RTLTOOL_READ_EPHY:
121 if (!capable(CAP_NET_ADMIN))
122 return -EPERM;
123
124 spin_lock_irqsave(&tp->lock, flags);
125 my_cmd.data = rtl8168_ephy_read(tp, my_cmd.offset);
126 spin_unlock_irqrestore(&tp->lock, flags);
127
128 if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
129 ret = -EFAULT;
130 break;
131 }
132
133 break;
134
135 case RTLTOOL_WRITE_EPHY:
136 if (!capable(CAP_NET_ADMIN))
137 return -EPERM;
138
139 spin_lock_irqsave(&tp->lock, flags);
140 rtl8168_ephy_write(tp, my_cmd.offset, my_cmd.data);
141 spin_unlock_irqrestore(&tp->lock, flags);
142 break;
143
144 case RTLTOOL_READ_ERI:
145 my_cmd.data = 0;
146 if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
147 spin_lock_irqsave(&tp->lock, flags);
148 my_cmd.data = rtl8168_eri_read(tp, my_cmd.offset, my_cmd.len, ERIAR_ExGMAC);
149 spin_unlock_irqrestore(&tp->lock, flags);
150 } else {
151 ret = -EOPNOTSUPP;
152 break;
153 }
154
155 if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
156 ret = -EFAULT;
157 break;
158 }
159
160 break;
161
162 case RTLTOOL_WRITE_ERI:
163 if (!capable(CAP_NET_ADMIN))
164 return -EPERM;
165
166 if (!capable(CAP_NET_ADMIN))
167 return -EPERM;
168
169 if (my_cmd.len==1 || my_cmd.len==2 || my_cmd.len==4) {
170 spin_lock_irqsave(&tp->lock, flags);
171 rtl8168_eri_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data, ERIAR_ExGMAC);
172 spin_unlock_irqrestore(&tp->lock, flags);
173 } else {
174 ret = -EOPNOTSUPP;
175 break;
176 }
177 break;
178
179 case RTLTOOL_READ_PCI:
180 if (!capable(CAP_NET_ADMIN))
181 return -EPERM;
182
183 my_cmd.data = 0;
184 if (my_cmd.len==1)
185 pci_read_config_byte(tp->pci_dev, my_cmd.offset,
186 (u8 *)&my_cmd.data);
187 else if (my_cmd.len==2)
188 pci_read_config_word(tp->pci_dev, my_cmd.offset,
189 (u16 *)&my_cmd.data);
190 else if (my_cmd.len==4)
191 pci_read_config_dword(tp->pci_dev, my_cmd.offset,
192 &my_cmd.data);
193 else {
194 ret = -EOPNOTSUPP;
195 break;
196 }
197
198 if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
199 ret = -EFAULT;
200 break;
201 }
202 break;
203
204 case RTLTOOL_WRITE_PCI:
205 if (!capable(CAP_NET_ADMIN))
206 return -EPERM;
207
208 if (my_cmd.len==1)
209 pci_write_config_byte(tp->pci_dev, my_cmd.offset,
210 my_cmd.data);
211 else if (my_cmd.len==2)
212 pci_write_config_word(tp->pci_dev, my_cmd.offset,
213 my_cmd.data);
214 else if (my_cmd.len==4)
215 pci_write_config_dword(tp->pci_dev, my_cmd.offset,
216 my_cmd.data);
217 else {
218 ret = -EOPNOTSUPP;
219 break;
220 }
221
222 break;
223
224 case RTLTOOL_READ_EEPROM:
225 if (!capable(CAP_NET_ADMIN))
226 return -EPERM;
227
228 spin_lock_irqsave(&tp->lock, flags);
229 my_cmd.data = rtl8168_eeprom_read_sc(tp, my_cmd.offset);
230 spin_unlock_irqrestore(&tp->lock, flags);
231
232 if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
233 ret = -EFAULT;
234 break;
235 }
236
237 break;
238
239 case RTLTOOL_WRITE_EEPROM:
240 if (!capable(CAP_NET_ADMIN))
241 return -EPERM;
242
243 spin_lock_irqsave(&tp->lock, flags);
244 rtl8168_eeprom_write_sc(tp, my_cmd.offset, my_cmd.data);
245 spin_unlock_irqrestore(&tp->lock, flags);
246 break;
247
248 case RTL_READ_OOB_MAC:
249 if (!capable(CAP_NET_ADMIN))
250 return -EPERM;
251
252 spin_lock_irqsave(&tp->lock, flags);
253 rtl8168_oob_mutex_lock(tp);
254 my_cmd.data = rtl8168_ocp_read(tp, my_cmd.offset, 4);
255 rtl8168_oob_mutex_unlock(tp);
256 spin_unlock_irqrestore(&tp->lock, flags);
257
258 if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
259 ret = -EFAULT;
260 break;
261 }
262 break;
263
264 case RTL_WRITE_OOB_MAC:
265 if (!capable(CAP_NET_ADMIN))
266 return -EPERM;
267
268 if (my_cmd.len == 0 || my_cmd.len > 4)
269 return -EOPNOTSUPP;
270
271 spin_lock_irqsave(&tp->lock, flags);
272 rtl8168_oob_mutex_lock(tp);
273 rtl8168_ocp_write(tp, my_cmd.offset, my_cmd.len, my_cmd.data);
274 rtl8168_oob_mutex_unlock(tp);
275 spin_unlock_irqrestore(&tp->lock, flags);
276 break;
277
278 case RTL_ENABLE_PCI_DIAG:
279 if (!capable(CAP_NET_ADMIN))
280 return -EPERM;
281
282 spin_lock_irqsave(&tp->lock, flags);
283 tp->rtk_enable_diag = 1;
284 spin_unlock_irqrestore(&tp->lock, flags);
285
286 dprintk("enable rtk diag\n");
287 break;
288
289 case RTL_DISABLE_PCI_DIAG:
290 if (!capable(CAP_NET_ADMIN))
291 return -EPERM;
292
293 spin_lock_irqsave(&tp->lock, flags);
294 tp->rtk_enable_diag = 0;
295 spin_unlock_irqrestore(&tp->lock, flags);
296
297 dprintk("disable rtk diag\n");
298 break;
299
300 case RTL_READ_MAC_OCP:
301 if (!capable(CAP_NET_ADMIN))
302 return -EPERM;
303
304 if (my_cmd.offset % 2)
305 return -EOPNOTSUPP;
306
307 spin_lock_irqsave(&tp->lock, flags);
308 my_cmd.data = rtl8168_mac_ocp_read(tp, my_cmd.offset);
309 spin_unlock_irqrestore(&tp->lock, flags);
310
311 if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
312 ret = -EFAULT;
313 break;
314 }
315 break;
316
317 case RTL_WRITE_MAC_OCP:
318 if (!capable(CAP_NET_ADMIN))
319 return -EPERM;
320
321 if ((my_cmd.offset % 2) || (my_cmd.len != 2))
322 return -EOPNOTSUPP;
323
324 spin_lock_irqsave(&tp->lock, flags);
325 rtl8168_mac_ocp_write(tp, my_cmd.offset, (u16)my_cmd.data);
326 spin_unlock_irqrestore(&tp->lock, flags);
327 break;
328
329 case RTL_DIRECT_READ_PHY_OCP:
330 if (!capable(CAP_NET_ADMIN))
331 return -EPERM;
332
333 spin_lock_irqsave(&tp->lock, flags);
334 my_cmd.data = rtl8168_mdio_prot_direct_read_phy_ocp(tp, my_cmd.offset);
335 spin_unlock_irqrestore(&tp->lock, flags);
336
337 if (copy_to_user(ifr->ifr_data, &my_cmd, sizeof(my_cmd))) {
338 ret = -EFAULT;
339 break;
340 }
341
342 break;
343
344 case RTL_DIRECT_WRITE_PHY_OCP:
345 if (!capable(CAP_NET_ADMIN))
346 return -EPERM;
347
348 spin_lock_irqsave(&tp->lock, flags);
349 rtl8168_mdio_prot_direct_write_phy_ocp(tp, my_cmd.offset, my_cmd.data);
350 spin_unlock_irqrestore(&tp->lock, flags);
351 break;
352
353 default:
354 ret = -EOPNOTSUPP;
355 break;
356 }
357
358 return ret;
359 }
360