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