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