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