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