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