• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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