xref: /freebsd/sys/dev/liquidio/lio_ioctl.c (revision 408c909dc64f77d2696d6fec77a2e0b00255cf96)
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