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