1 /*
2 * BSD LICENSE
3 *
4 * Copyright(c) 2017 Cavium, Inc.. All rights reserved.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * * Neither the name of Cavium, Inc. nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 */
33
34 #include "lio_bsd.h"
35 #include "lio_common.h"
36 #include "lio_droq.h"
37 #include "lio_iq.h"
38 #include "lio_response_manager.h"
39 #include "lio_device.h"
40 #include "lio_network.h"
41 #include "lio_ctrl.h"
42 #include "cn23xx_pf_device.h"
43 #include "lio_image.h"
44 #include "lio_ioctl.h"
45 #include "lio_main.h"
46 #include "lio_rxtx.h"
47
48 static int lio_set_rx_csum(if_t ifp, uint32_t data);
49 static int lio_set_tso4(if_t ifp);
50 static int lio_set_tso6(if_t ifp);
51 static int lio_set_lro(if_t ifp);
52 static int lio_change_mtu(if_t ifp, int new_mtu);
53 static int lio_set_mcast_list(if_t ifp);
54 static inline enum lio_ifflags lio_get_new_flags(if_t ifp);
55
56 static inline bool
lio_is_valid_ether_addr(const uint8_t * addr)57 lio_is_valid_ether_addr(const uint8_t *addr)
58 {
59
60 return (!(0x01 & addr[0]) && !((addr[0] + addr[1] + addr[2] + addr[3] +
61 addr[4] + addr[5]) == 0x00));
62 }
63
64 static int
lio_change_dev_flags(if_t ifp)65 lio_change_dev_flags(if_t ifp)
66 {
67 struct lio_ctrl_pkt nctrl;
68 struct lio *lio = if_getsoftc(ifp);
69 struct octeon_device *oct = lio->oct_dev;
70 int ret = 0;
71
72 bzero(&nctrl, sizeof(struct lio_ctrl_pkt));
73
74 /* Create a ctrl pkt command to be sent to core app. */
75 nctrl.ncmd.cmd64 = 0;
76 nctrl.ncmd.s.cmd = LIO_CMD_CHANGE_DEVFLAGS;
77 nctrl.ncmd.s.param1 = lio_get_new_flags(ifp);
78 nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
79 nctrl.lio = lio;
80 nctrl.cb_fn = lio_ctrl_cmd_completion;
81
82 ret = lio_send_ctrl_pkt(oct, &nctrl);
83 if (ret)
84 lio_dev_err(oct, "Failed to change flags ret %d\n", ret);
85
86 return (ret);
87 }
88
89 /*
90 * lio_ioctl : User calls this routine for configuring
91 * the interface.
92 *
93 * return 0 on success, positive on failure
94 */
95 int
lio_ioctl(if_t ifp,u_long cmd,caddr_t data)96 lio_ioctl(if_t ifp, u_long cmd, caddr_t data)
97 {
98 struct lio *lio = if_getsoftc(ifp);
99 struct ifreq *ifrequest = (struct ifreq *)data;
100 int error = 0;
101
102 switch (cmd) {
103 case SIOCSIFADDR:
104 lio_dev_dbg(lio->oct_dev, "ioctl: SIOCSIFADDR\n");
105 if_setflagbits(ifp, IFF_UP, 0);
106 error = ether_ioctl(ifp, cmd, data);
107 break;
108 case SIOCSIFMTU:
109 lio_dev_dbg(lio->oct_dev, "ioctl: SIOCSIFMTU\n");
110 error = lio_change_mtu(ifp, ifrequest->ifr_mtu);
111 break;
112 case SIOCSIFFLAGS:
113 lio_dev_dbg(lio->oct_dev, "ioctl: SIOCSIFFLAGS\n");
114 if (if_getflags(ifp) & IFF_UP) {
115 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
116 if ((if_getflags(ifp) ^ lio->if_flags) &
117 (IFF_PROMISC | IFF_ALLMULTI))
118 error = lio_change_dev_flags(ifp);
119 } else {
120 if (!(atomic_load_acq_int(&lio->ifstate) &
121 LIO_IFSTATE_DETACH))
122 lio_open(lio);
123 }
124 } else {
125 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
126 lio_stop(ifp);
127 }
128 lio->if_flags = if_getflags(ifp);
129 break;
130 case SIOCADDMULTI:
131 lio_dev_dbg(lio->oct_dev, "ioctl: SIOCADDMULTI\n");
132 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
133 error = lio_set_mcast_list(ifp);
134 break;
135 case SIOCDELMULTI:
136 lio_dev_dbg(lio->oct_dev, "ioctl: SIOCSIFMULTI\n");
137 break;
138 case SIOCSIFMEDIA:
139 lio_dev_dbg(lio->oct_dev, "ioctl: SIOCSIFMEDIA\n");
140 case SIOCGIFMEDIA:
141 lio_dev_dbg(lio->oct_dev, "ioctl: SIOCGIFMEDIA\n");
142 case SIOCGIFXMEDIA:
143 lio_dev_dbg(lio->oct_dev, "ioctl: SIOCGIFXMEDIA\n");
144 error = ifmedia_ioctl(ifp, ifrequest, &lio->ifmedia, cmd);
145 break;
146 case SIOCSIFCAP:
147 {
148 int features = ifrequest->ifr_reqcap ^
149 if_getcapenable(ifp);
150
151 lio_dev_dbg(lio->oct_dev, "ioctl: SIOCSIFCAP (Set Capabilities)\n");
152
153 if (!features)
154 break;
155
156 if (features & IFCAP_TXCSUM) {
157 if_togglecapenable(ifp, IFCAP_TXCSUM);
158 if (if_getcapenable(ifp) & IFCAP_TXCSUM)
159 if_sethwassistbits(ifp, (CSUM_TCP |
160 CSUM_UDP |
161 CSUM_IP), 0);
162 else
163 if_sethwassistbits(ifp, 0,
164 (CSUM_TCP | CSUM_UDP |
165 CSUM_IP));
166 }
167 if (features & IFCAP_TXCSUM_IPV6) {
168 if_togglecapenable(ifp, IFCAP_TXCSUM_IPV6);
169 if (if_getcapenable(ifp) & IFCAP_TXCSUM_IPV6)
170 if_sethwassistbits(ifp, (CSUM_UDP_IPV6 |
171 CSUM_TCP_IPV6), 0);
172 else
173 if_sethwassistbits(ifp, 0,
174 (CSUM_UDP_IPV6 |
175 CSUM_TCP_IPV6));
176 }
177 if (features & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6))
178 error |= lio_set_rx_csum(ifp, (features &
179 (IFCAP_RXCSUM |
180 IFCAP_RXCSUM_IPV6)));
181
182 if (features & IFCAP_TSO4)
183 error |= lio_set_tso4(ifp);
184
185 if (features & IFCAP_TSO6)
186 error |= lio_set_tso6(ifp);
187
188 if (features & IFCAP_LRO)
189 error |= lio_set_lro(ifp);
190
191 if (features & IFCAP_VLAN_HWTAGGING)
192 if_togglecapenable(ifp, IFCAP_VLAN_HWTAGGING);
193
194 if (features & IFCAP_VLAN_HWFILTER)
195 if_togglecapenable(ifp, IFCAP_VLAN_HWFILTER);
196
197 if (features & IFCAP_VLAN_HWTSO)
198 if_togglecapenable(ifp, IFCAP_VLAN_HWTSO);
199
200 VLAN_CAPABILITIES(ifp);
201 break;
202 }
203 default:
204 lio_dev_dbg(lio->oct_dev, "ioctl: UNKNOWN (0x%X)\n", (int)cmd);
205 error = ether_ioctl(ifp, cmd, data);
206 break;
207 }
208
209 return (error);
210 }
211
212 static int
lio_set_tso4(if_t ifp)213 lio_set_tso4(if_t ifp)
214 {
215 struct lio *lio = if_getsoftc(ifp);
216
217 if (if_getcapabilities(ifp) & IFCAP_TSO4) {
218 if_togglecapenable(ifp, IFCAP_TSO4);
219 if (if_getcapenable(ifp) & IFCAP_TSO4)
220 if_sethwassistbits(ifp, CSUM_IP_TSO, 0);
221 else
222 if_sethwassistbits(ifp, 0, CSUM_IP_TSO);
223 } else {
224 lio_dev_info(lio->oct_dev, "TSO4 capability not supported\n");
225 return (EINVAL);
226 }
227
228 return (0);
229 }
230
231 static int
lio_set_tso6(if_t ifp)232 lio_set_tso6(if_t ifp)
233 {
234 struct lio *lio = if_getsoftc(ifp);
235
236 if (if_getcapabilities(ifp) & IFCAP_TSO6) {
237 if_togglecapenable(ifp, IFCAP_TSO6);
238 if (if_getcapenable(ifp) & IFCAP_TSO6)
239 if_sethwassistbits(ifp, CSUM_IP6_TSO, 0);
240 else
241 if_sethwassistbits(ifp, 0, CSUM_IP6_TSO);
242 } else {
243 lio_dev_info(lio->oct_dev, "TSO6 capability not supported\n");
244 return (EINVAL);
245 }
246
247 return (0);
248 }
249
250 static int
lio_set_rx_csum(if_t ifp,uint32_t data)251 lio_set_rx_csum(if_t ifp, uint32_t data)
252 {
253 struct lio *lio = if_getsoftc(ifp);
254 int ret = 0;
255
256 if (if_getcapabilities(ifp) & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) {
257 if_togglecapenable(ifp, (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6));
258
259 if (data) {
260 /* LRO requires RXCSUM */
261 if ((if_getcapabilities(ifp) & IFCAP_LRO) &&
262 (if_getcapenable(ifp) & IFCAP_LRO)) {
263 ret = lio_set_feature(ifp, LIO_CMD_LRO_DISABLE,
264 LIO_LROIPV4 |
265 LIO_LROIPV6);
266 if_togglecapenable(ifp, IFCAP_LRO);
267 }
268 }
269 } else {
270 lio_dev_info(lio->oct_dev, "Rx checksum offload capability not supported\n");
271 return (ENODEV);
272 }
273
274 return ((ret) ? EINVAL : 0);
275 }
276
277 static int
lio_set_lro(if_t ifp)278 lio_set_lro(if_t ifp)
279 {
280 struct lio *lio = if_getsoftc(ifp);
281 int ret = 0;
282
283 if (!(if_getcapabilities(ifp) & IFCAP_LRO)) {
284 lio_dev_info(lio->oct_dev, "LRO capability not supported\n");
285 return (ENODEV);
286 }
287
288 if ((!(if_getcapenable(ifp) & IFCAP_LRO)) &&
289 (if_getcapenable(ifp) & IFCAP_RXCSUM) &&
290 (if_getcapenable(ifp) & IFCAP_RXCSUM_IPV6)) {
291 if_togglecapenable(ifp, IFCAP_LRO);
292
293 if (lio_hwlro)
294 ret = lio_set_feature(ifp, LIO_CMD_LRO_ENABLE, LIO_LROIPV4 |
295 LIO_LROIPV6);
296
297 } else if (if_getcapenable(ifp) & IFCAP_LRO) {
298 if_togglecapenable(ifp, IFCAP_LRO);
299
300 if (lio_hwlro)
301 ret = lio_set_feature(ifp, LIO_CMD_LRO_DISABLE, LIO_LROIPV4 |
302 LIO_LROIPV6);
303 } else
304 lio_dev_info(lio->oct_dev, "LRO requires RXCSUM");
305
306 return ((ret) ? EINVAL : 0);
307 }
308
309 static void
lio_mtu_ctl_callback(struct octeon_device * oct,uint32_t status,void * buf)310 lio_mtu_ctl_callback(struct octeon_device *oct, uint32_t status, void *buf)
311 {
312 struct lio_soft_command *sc = buf;
313 volatile int *mtu_sc_ctx;
314
315 mtu_sc_ctx = sc->ctxptr;
316
317 if (status) {
318 lio_dev_err(oct, "MTU updation ctl instruction failed. Status: %llx\n",
319 LIO_CAST64(status));
320 *mtu_sc_ctx = -1;
321 /*
322 * This barrier is required to be sure that the
323 * response has been written fully.
324 */
325 wmb();
326 return;
327 }
328
329 *mtu_sc_ctx = 1;
330
331 /*
332 * This barrier is required to be sure that the response has been
333 * written fully.
334 */
335 wmb();
336 }
337
338 /* @param ifp is network device */
339 static int
lio_change_mtu(if_t ifp,int new_mtu)340 lio_change_mtu(if_t ifp, int new_mtu)
341 {
342 struct lio *lio = if_getsoftc(ifp);
343 struct octeon_device *oct = lio->oct_dev;
344 struct lio_soft_command *sc;
345 union octeon_cmd *ncmd;
346 volatile int *mtu_sc_ctx;
347 int retval = 0;
348
349 if (lio->mtu == new_mtu)
350 return (0);
351
352 /*
353 * Limit the MTU to make sure the ethernet packets are between
354 * LIO_MIN_MTU_SIZE bytes and LIO_MAX_MTU_SIZE bytes
355 */
356 if ((new_mtu < LIO_MIN_MTU_SIZE) || (new_mtu > LIO_MAX_MTU_SIZE)) {
357 lio_dev_err(oct, "Invalid MTU: %d\n", new_mtu);
358 lio_dev_err(oct, "Valid range %d and %d\n",
359 LIO_MIN_MTU_SIZE, LIO_MAX_MTU_SIZE);
360 return (EINVAL);
361 }
362
363 sc = lio_alloc_soft_command(oct, OCTEON_CMD_SIZE, 16,
364 sizeof(*mtu_sc_ctx));
365 if (sc == NULL)
366 return (ENOMEM);
367
368 ncmd = (union octeon_cmd *)sc->virtdptr;
369 mtu_sc_ctx = sc->ctxptr;
370
371 *mtu_sc_ctx = 0;
372
373 ncmd->cmd64 = 0;
374 ncmd->s.cmd = LIO_CMD_CHANGE_MTU;
375 ncmd->s.param1 = new_mtu;
376
377 lio_swap_8B_data((uint64_t *)ncmd, (OCTEON_CMD_SIZE >> 3));
378
379 sc->iq_no = lio->linfo.txpciq[0].s.q_no;
380
381 lio_prepare_soft_command(oct, sc, LIO_OPCODE_NIC,
382 LIO_OPCODE_NIC_CMD, 0, 0, 0);
383
384 sc->callback = lio_mtu_ctl_callback;
385 sc->callback_arg = sc;
386 sc->wait_time = 5000;
387
388 retval = lio_send_soft_command(oct, sc);
389 if (retval == LIO_IQ_SEND_FAILED) {
390 lio_dev_info(oct,
391 "Failed to send MTU update Control message\n");
392 retval = EBUSY;
393 goto mtu_updation_failed;
394 }
395
396 /*
397 * Sleep on a wait queue till the cond flag indicates that the
398 * response arrived or timed-out.
399 */
400 lio_sleep_cond(oct, mtu_sc_ctx);
401
402 if (*mtu_sc_ctx < 0) {
403 retval = EBUSY;
404 goto mtu_updation_failed;
405 }
406 lio_dev_info(oct, "MTU Changed from %d to %d\n", if_getmtu(ifp),
407 new_mtu);
408 if_setmtu(ifp, new_mtu);
409 lio->mtu = new_mtu;
410 retval = 0; /*
411 * this updation is make sure that LIO_IQ_SEND_STOP case
412 * also success
413 */
414
415 mtu_updation_failed:
416 lio_free_soft_command(oct, sc);
417
418 return (retval);
419 }
420
421 /* @param ifp network device */
422 int
lio_set_mac(if_t ifp,uint8_t * p)423 lio_set_mac(if_t ifp, uint8_t *p)
424 {
425 struct lio_ctrl_pkt nctrl;
426 struct lio *lio = if_getsoftc(ifp);
427 struct octeon_device *oct = lio->oct_dev;
428 int ret = 0;
429
430 if (!lio_is_valid_ether_addr(p))
431 return (EADDRNOTAVAIL);
432
433 bzero(&nctrl, sizeof(struct lio_ctrl_pkt));
434
435 nctrl.ncmd.cmd64 = 0;
436 nctrl.ncmd.s.cmd = LIO_CMD_CHANGE_MACADDR;
437 nctrl.ncmd.s.param1 = 0;
438 nctrl.ncmd.s.more = 1;
439 nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
440 nctrl.lio = lio;
441 nctrl.cb_fn = lio_ctrl_cmd_completion;
442 nctrl.wait_time = 100;
443
444 nctrl.udd[0] = 0;
445 /* The MAC Address is presented in network byte order. */
446 memcpy((uint8_t *)&nctrl.udd[0] + 2, p, ETHER_HDR_LEN);
447
448 ret = lio_send_ctrl_pkt(lio->oct_dev, &nctrl);
449 if (ret < 0) {
450 lio_dev_err(oct, "MAC Address change failed\n");
451 return (ENOMEM);
452 }
453
454 memcpy(((uint8_t *)&lio->linfo.hw_addr) + 2, p, ETHER_HDR_LEN);
455
456 return (0);
457 }
458
459 /*
460 * \brief Converts a mask based on ifp flags
461 * @param ifp network device
462 *
463 * This routine generates a lio_ifflags mask from the ifp flags
464 * received from the OS.
465 */
466 static inline enum lio_ifflags
lio_get_new_flags(if_t ifp)467 lio_get_new_flags(if_t ifp)
468 {
469 enum lio_ifflags f = LIO_IFFLAG_UNICAST;
470
471 if (if_getflags(ifp) & IFF_PROMISC)
472 f |= LIO_IFFLAG_PROMISC;
473
474 if (if_getflags(ifp) & IFF_ALLMULTI)
475 f |= LIO_IFFLAG_ALLMULTI;
476
477 if (if_getflags(ifp) & IFF_MULTICAST) {
478 f |= LIO_IFFLAG_MULTICAST;
479
480 /*
481 * Accept all multicast addresses if there are more than we
482 * can handle
483 */
484 if (if_llmaddr_count(ifp) > LIO_MAX_MULTICAST_ADDR)
485 f |= LIO_IFFLAG_ALLMULTI;
486 }
487 if (if_getflags(ifp) & IFF_BROADCAST)
488 f |= LIO_IFFLAG_BROADCAST;
489
490 return (f);
491 }
492
493 static u_int
lio_copy_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)494 lio_copy_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
495 {
496 uint64_t *mc = arg;
497
498 if (cnt == LIO_MAX_MULTICAST_ADDR)
499 return (0);
500
501 mc += cnt;
502 *mc = 0;
503 memcpy(((uint8_t *)mc) + 2, LLADDR(sdl), ETHER_ADDR_LEN);
504 /* no need to swap bytes */
505
506 return (1);
507 }
508
509 /* @param ifp network device */
510 static int
lio_set_mcast_list(if_t ifp)511 lio_set_mcast_list(if_t ifp)
512 {
513 struct lio *lio = if_getsoftc(ifp);
514 struct octeon_device *oct = lio->oct_dev;
515 struct lio_ctrl_pkt nctrl;
516 int mc_count;
517 int ret;
518
519 bzero(&nctrl, sizeof(struct lio_ctrl_pkt));
520
521 /* Create a ctrl pkt command to be sent to core app. */
522 nctrl.ncmd.cmd64 = 0;
523 nctrl.ncmd.s.cmd = LIO_CMD_SET_MULTI_LIST;
524 nctrl.ncmd.s.param1 = lio_get_new_flags(ifp);
525 nctrl.iq_no = lio->linfo.txpciq[0].s.q_no;
526 nctrl.lio = lio;
527 nctrl.cb_fn = lio_ctrl_cmd_completion;
528
529 /* copy all the addresses into the udd */
530 mc_count = if_foreach_llmaddr(ifp, lio_copy_maddr, &nctrl.udd[0]);
531
532 /*
533 * Apparently, any activity in this call from the kernel has to
534 * be atomic. So we won't wait for response.
535 */
536 nctrl.wait_time = 0;
537 nctrl.ncmd.s.param2 = mc_count;
538 nctrl.ncmd.s.more = mc_count;
539
540 ret = lio_send_ctrl_pkt(lio->oct_dev, &nctrl);
541 if (ret < 0) {
542 lio_dev_err(oct, "DEVFLAGS change failed in core (ret: 0x%x)\n",
543 ret);
544 }
545
546 return ((ret) ? EINVAL : 0);
547 }
548