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