1217214Sjmallett/*- 2217214Sjmallett * Copyright (c) 2010-2011 Juli Mallett <jmallett@FreeBSD.org> 3217214Sjmallett * All rights reserved. 4217214Sjmallett * 5217214Sjmallett * Redistribution and use in source and binary forms, with or without 6217214Sjmallett * modification, are permitted provided that the following conditions 7217214Sjmallett * are met: 8217214Sjmallett * 1. Redistributions of source code must retain the above copyright 9217214Sjmallett * notice, this list of conditions and the following disclaimer. 10217214Sjmallett * 2. Redistributions in binary form must reproduce the above copyright 11217214Sjmallett * notice, this list of conditions and the following disclaimer in the 12217214Sjmallett * documentation and/or other materials provided with the distribution. 13217214Sjmallett * 14217214Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15217214Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16217214Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17217214Sjmallett * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18217214Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19217214Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20217214Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21217214Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22217214Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23217214Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24217214Sjmallett * SUCH DAMAGE. 25217214Sjmallett * 26217214Sjmallett * $FreeBSD$ 27217214Sjmallett */ 28217214Sjmallett 29217214Sjmallett/* 30217214Sjmallett * Cavium Octeon management port Ethernet devices. 31217214Sjmallett */ 32217214Sjmallett 33217214Sjmallett#include "opt_inet.h" 34217214Sjmallett 35217214Sjmallett#include <sys/param.h> 36217214Sjmallett#include <sys/systm.h> 37217214Sjmallett#include <sys/bus.h> 38217214Sjmallett#include <sys/endian.h> 39217214Sjmallett#include <sys/kernel.h> 40217214Sjmallett#include <sys/mbuf.h> 41217214Sjmallett#include <sys/lock.h> 42217214Sjmallett#include <sys/module.h> 43217214Sjmallett#include <sys/mutex.h> 44217214Sjmallett#include <sys/rman.h> 45217214Sjmallett#include <sys/socket.h> 46217214Sjmallett#include <sys/sockio.h> 47217214Sjmallett#include <sys/sysctl.h> 48217214Sjmallett 49217214Sjmallett#include <net/bpf.h> 50217214Sjmallett#include <net/ethernet.h> 51217214Sjmallett#include <net/if.h> 52217214Sjmallett#include <net/if_dl.h> 53217214Sjmallett#include <net/if_media.h> 54217214Sjmallett#include <net/if_types.h> 55217214Sjmallett#include <net/if_var.h> 56217214Sjmallett#include <net/if_vlan_var.h> 57217214Sjmallett 58217214Sjmallett#ifdef INET 59217214Sjmallett#include <netinet/in.h> 60217214Sjmallett#include <netinet/if_ether.h> 61217214Sjmallett#endif 62217214Sjmallett 63217214Sjmallett#include <contrib/octeon-sdk/cvmx.h> 64217214Sjmallett#include <contrib/octeon-sdk/cvmx-interrupt.h> 65217214Sjmallett#include <contrib/octeon-sdk/cvmx-mgmt-port.h> 66217214Sjmallett 67218594Sjmallettextern cvmx_bootinfo_t *octeon_bootinfo; 68218594Sjmallett 69217214Sjmallettstruct octm_softc { 70217214Sjmallett struct ifnet *sc_ifp; 71217214Sjmallett device_t sc_dev; 72217214Sjmallett unsigned sc_port; 73217214Sjmallett int sc_flags; 74217214Sjmallett struct ifmedia sc_ifmedia; 75217214Sjmallett struct resource *sc_intr; 76217214Sjmallett void *sc_intr_cookie; 77217214Sjmallett}; 78217214Sjmallett 79217214Sjmallettstatic void octm_identify(driver_t *, device_t); 80217214Sjmallettstatic int octm_probe(device_t); 81217214Sjmallettstatic int octm_attach(device_t); 82217214Sjmallettstatic int octm_detach(device_t); 83217214Sjmallettstatic int octm_shutdown(device_t); 84217214Sjmallett 85217214Sjmallettstatic void octm_init(void *); 86217214Sjmallettstatic int octm_transmit(struct ifnet *, struct mbuf *); 87217214Sjmallett 88217214Sjmallettstatic int octm_medchange(struct ifnet *); 89217214Sjmallettstatic void octm_medstat(struct ifnet *, struct ifmediareq *); 90217214Sjmallett 91217214Sjmallettstatic int octm_ioctl(struct ifnet *, u_long, caddr_t); 92217214Sjmallett 93217214Sjmallettstatic void octm_rx_intr(void *); 94217214Sjmallett 95217214Sjmallettstatic device_method_t octm_methods[] = { 96217214Sjmallett /* Device interface */ 97217214Sjmallett DEVMETHOD(device_identify, octm_identify), 98217214Sjmallett DEVMETHOD(device_probe, octm_probe), 99217214Sjmallett DEVMETHOD(device_attach, octm_attach), 100217214Sjmallett DEVMETHOD(device_detach, octm_detach), 101217214Sjmallett DEVMETHOD(device_shutdown, octm_shutdown), 102217214Sjmallett 103217214Sjmallett { 0, 0 } 104217214Sjmallett}; 105217214Sjmallett 106217214Sjmallettstatic driver_t octm_driver = { 107217214Sjmallett "octm", 108217214Sjmallett octm_methods, 109217214Sjmallett sizeof (struct octm_softc), 110217214Sjmallett}; 111217214Sjmallett 112217214Sjmallettstatic devclass_t octm_devclass; 113217214Sjmallett 114217214SjmallettDRIVER_MODULE(octm, ciu, octm_driver, octm_devclass, 0, 0); 115217214Sjmallett 116217214Sjmallettstatic void 117217214Sjmallettoctm_identify(driver_t *drv, device_t parent) 118217214Sjmallett{ 119217214Sjmallett unsigned i; 120217214Sjmallett 121217214Sjmallett if (!octeon_has_feature(OCTEON_FEATURE_MGMT_PORT)) 122217214Sjmallett return; 123217214Sjmallett 124217214Sjmallett for (i = 0; i < CVMX_MGMT_PORT_NUM_PORTS; i++) 125217214Sjmallett BUS_ADD_CHILD(parent, 0, "octm", i); 126217214Sjmallett} 127217214Sjmallett 128217214Sjmallettstatic int 129217214Sjmallettoctm_probe(device_t dev) 130217214Sjmallett{ 131217214Sjmallett cvmx_mgmt_port_result_t result; 132217214Sjmallett 133217214Sjmallett result = cvmx_mgmt_port_initialize(device_get_unit(dev)); 134217214Sjmallett switch (result) { 135217214Sjmallett case CVMX_MGMT_PORT_SUCCESS: 136217214Sjmallett break; 137217214Sjmallett case CVMX_MGMT_PORT_NO_MEMORY: 138217214Sjmallett return (ENOBUFS); 139217214Sjmallett case CVMX_MGMT_PORT_INVALID_PARAM: 140217214Sjmallett return (ENXIO); 141217214Sjmallett case CVMX_MGMT_PORT_INIT_ERROR: 142217214Sjmallett return (EIO); 143217214Sjmallett } 144217214Sjmallett 145217214Sjmallett device_set_desc(dev, "Cavium Octeon Management Ethernet"); 146217214Sjmallett 147217214Sjmallett return (0); 148217214Sjmallett} 149217214Sjmallett 150217214Sjmallettstatic int 151217214Sjmallettoctm_attach(device_t dev) 152217214Sjmallett{ 153217214Sjmallett struct ifnet *ifp; 154217214Sjmallett struct octm_softc *sc; 155217214Sjmallett cvmx_mixx_irhwm_t mixx_irhwm; 156217214Sjmallett cvmx_mixx_intena_t mixx_intena; 157217214Sjmallett uint64_t mac; 158217214Sjmallett int error; 159217214Sjmallett int irq; 160217214Sjmallett int rid; 161217214Sjmallett 162217214Sjmallett sc = device_get_softc(dev); 163217214Sjmallett sc->sc_dev = dev; 164217214Sjmallett sc->sc_port = device_get_unit(dev); 165217214Sjmallett 166217214Sjmallett switch (sc->sc_port) { 167217214Sjmallett case 0: 168217214Sjmallett irq = CVMX_IRQ_MII; 169217214Sjmallett break; 170217214Sjmallett case 1: 171217214Sjmallett irq = CVMX_IRQ_MII1; 172217214Sjmallett break; 173217214Sjmallett default: 174217214Sjmallett device_printf(dev, "unsupported management port %u.\n", sc->sc_port); 175217214Sjmallett return (ENXIO); 176217214Sjmallett } 177217214Sjmallett 178219706Sjmallett /* 179219706Sjmallett * Set MAC address for this management port. 180219706Sjmallett */ 181219706Sjmallett mac = 0; 182219706Sjmallett memcpy((u_int8_t *)&mac + 2, octeon_bootinfo->mac_addr_base, 6); 183219706Sjmallett mac += sc->sc_port; 184219706Sjmallett cvmx_mgmt_port_set_mac(sc->sc_port, mac); 185217214Sjmallett 186217214Sjmallett /* No watermark for input ring. */ 187217214Sjmallett mixx_irhwm.u64 = 0; 188217214Sjmallett cvmx_write_csr(CVMX_MIXX_IRHWM(sc->sc_port), mixx_irhwm.u64); 189217214Sjmallett 190217214Sjmallett /* Enable input ring interrupts. */ 191217214Sjmallett mixx_intena.u64 = 0; 192217214Sjmallett mixx_intena.s.ithena = 1; 193217214Sjmallett cvmx_write_csr(CVMX_MIXX_INTENA(sc->sc_port), mixx_intena.u64); 194217214Sjmallett 195217214Sjmallett /* Allocate and establish interrupt. */ 196217214Sjmallett rid = 0; 197217214Sjmallett sc->sc_intr = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ, &rid, 198217214Sjmallett irq, irq, 1, RF_ACTIVE); 199217214Sjmallett if (sc->sc_intr == NULL) { 200217214Sjmallett device_printf(dev, "unable to allocate IRQ.\n"); 201217214Sjmallett return (ENXIO); 202217214Sjmallett } 203217214Sjmallett 204217214Sjmallett error = bus_setup_intr(sc->sc_dev, sc->sc_intr, INTR_TYPE_NET, NULL, 205217214Sjmallett octm_rx_intr, sc, &sc->sc_intr_cookie); 206217214Sjmallett if (error != 0) { 207217214Sjmallett device_printf(dev, "unable to setup interrupt.\n"); 208217214Sjmallett bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr); 209217214Sjmallett return (ENXIO); 210217214Sjmallett } 211217214Sjmallett 212217214Sjmallett bus_describe_intr(sc->sc_dev, sc->sc_intr, sc->sc_intr_cookie, "rx"); 213217214Sjmallett 214217214Sjmallett /* XXX Possibly should enable TX interrupts. */ 215217214Sjmallett 216217214Sjmallett ifp = if_alloc(IFT_ETHER); 217217214Sjmallett if (ifp == NULL) { 218217214Sjmallett device_printf(dev, "cannot allocate ifnet.\n"); 219217214Sjmallett bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr); 220217214Sjmallett return (ENOMEM); 221217214Sjmallett } 222217214Sjmallett 223217214Sjmallett if_initname(ifp, device_get_name(dev), device_get_unit(dev)); 224217214Sjmallett ifp->if_mtu = ETHERMTU; 225217214Sjmallett ifp->if_init = octm_init; 226217214Sjmallett ifp->if_softc = sc; 227217214Sjmallett ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI; 228217214Sjmallett ifp->if_ioctl = octm_ioctl; 229217214Sjmallett 230217214Sjmallett sc->sc_ifp = ifp; 231217214Sjmallett sc->sc_flags = ifp->if_flags; 232217214Sjmallett 233217214Sjmallett ifmedia_init(&sc->sc_ifmedia, 0, octm_medchange, octm_medstat); 234217214Sjmallett 235217214Sjmallett ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL); 236217214Sjmallett ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO); 237217214Sjmallett 238217214Sjmallett ether_ifattach(ifp, (const u_int8_t *)&mac + 2); 239217214Sjmallett 240217214Sjmallett ifp->if_transmit = octm_transmit; 241217214Sjmallett 242217214Sjmallett ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header); 243217214Sjmallett ifp->if_capabilities = IFCAP_VLAN_MTU; 244217214Sjmallett ifp->if_capenable = ifp->if_capabilities; 245217214Sjmallett 246217214Sjmallett IFQ_SET_MAXLEN(&ifp->if_snd, CVMX_MGMT_PORT_NUM_TX_BUFFERS); 247217214Sjmallett ifp->if_snd.ifq_drv_maxlen = CVMX_MGMT_PORT_NUM_TX_BUFFERS; 248217214Sjmallett IFQ_SET_READY(&ifp->if_snd); 249217214Sjmallett 250217214Sjmallett return (bus_generic_attach(dev)); 251217214Sjmallett} 252217214Sjmallett 253217214Sjmallettstatic int 254217214Sjmallettoctm_detach(device_t dev) 255217214Sjmallett{ 256217214Sjmallett struct octm_softc *sc; 257217214Sjmallett cvmx_mgmt_port_result_t result; 258217214Sjmallett 259217214Sjmallett sc = device_get_softc(dev); 260217214Sjmallett 261217214Sjmallett result = cvmx_mgmt_port_initialize(sc->sc_port); 262217214Sjmallett switch (result) { 263217214Sjmallett case CVMX_MGMT_PORT_SUCCESS: 264217214Sjmallett break; 265217214Sjmallett case CVMX_MGMT_PORT_NO_MEMORY: 266217214Sjmallett return (ENOBUFS); 267217214Sjmallett case CVMX_MGMT_PORT_INVALID_PARAM: 268217214Sjmallett return (ENXIO); 269217214Sjmallett case CVMX_MGMT_PORT_INIT_ERROR: 270217214Sjmallett return (EIO); 271217214Sjmallett } 272217214Sjmallett 273217214Sjmallett bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr); 274217214Sjmallett /* XXX Incomplete. */ 275217214Sjmallett 276217214Sjmallett return (0); 277217214Sjmallett} 278217214Sjmallett 279217214Sjmallettstatic int 280217214Sjmallettoctm_shutdown(device_t dev) 281217214Sjmallett{ 282217214Sjmallett return (octm_detach(dev)); 283217214Sjmallett} 284217214Sjmallett 285217214Sjmallettstatic void 286217214Sjmallettoctm_init(void *arg) 287217214Sjmallett{ 288217214Sjmallett struct ifnet *ifp; 289217214Sjmallett struct octm_softc *sc; 290217214Sjmallett cvmx_mgmt_port_netdevice_flags_t flags; 291217214Sjmallett uint64_t mac; 292217214Sjmallett 293217214Sjmallett sc = arg; 294217214Sjmallett ifp = sc->sc_ifp; 295217214Sjmallett 296217214Sjmallett if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 297217214Sjmallett cvmx_mgmt_port_disable(sc->sc_port); 298217214Sjmallett 299217214Sjmallett ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 300217214Sjmallett } 301217214Sjmallett 302217214Sjmallett if (((ifp->if_flags ^ sc->sc_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0) { 303217214Sjmallett flags = 0; 304217214Sjmallett if ((ifp->if_flags & IFF_ALLMULTI) != 0) 305217214Sjmallett flags |= CVMX_IFF_ALLMULTI; 306217214Sjmallett if ((ifp->if_flags & IFF_PROMISC) != 0) 307217214Sjmallett flags |= CVMX_IFF_PROMISC; 308217214Sjmallett cvmx_mgmt_port_set_multicast_list(sc->sc_port, flags); 309217214Sjmallett } 310217214Sjmallett 311217214Sjmallett mac = 0; 312217214Sjmallett memcpy((u_int8_t *)&mac + 2, IF_LLADDR(ifp), 6); 313217214Sjmallett cvmx_mgmt_port_set_mac(sc->sc_port, mac); 314217214Sjmallett 315217214Sjmallett /* XXX link state? */ 316217214Sjmallett 317217214Sjmallett if ((ifp->if_flags & IFF_UP) != 0) 318217214Sjmallett cvmx_mgmt_port_enable(sc->sc_port); 319217214Sjmallett 320217214Sjmallett ifp->if_drv_flags |= IFF_DRV_RUNNING; 321217214Sjmallett ifp->if_drv_flags &= ~IFF_DRV_OACTIVE; 322217214Sjmallett} 323217214Sjmallett 324217214Sjmallettstatic int 325217214Sjmallettoctm_transmit(struct ifnet *ifp, struct mbuf *m) 326217214Sjmallett{ 327217214Sjmallett struct octm_softc *sc; 328217214Sjmallett cvmx_mgmt_port_result_t result; 329217214Sjmallett 330217214Sjmallett sc = ifp->if_softc; 331217214Sjmallett 332217214Sjmallett if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != 333217214Sjmallett IFF_DRV_RUNNING) { 334217214Sjmallett m_freem(m); 335217214Sjmallett return (0); 336217214Sjmallett } 337217214Sjmallett 338217214Sjmallett result = cvmx_mgmt_port_sendm(sc->sc_port, m); 339217214Sjmallett 340217244Sjmallett if (result == CVMX_MGMT_PORT_SUCCESS) { 341217214Sjmallett ETHER_BPF_MTAP(ifp, m); 342217244Sjmallett 343217244Sjmallett ifp->if_opackets++; 344217244Sjmallett ifp->if_obytes += m->m_pkthdr.len; 345217244Sjmallett } else 346217214Sjmallett ifp->if_oerrors++; 347217214Sjmallett 348217214Sjmallett m_freem(m); 349217214Sjmallett 350217214Sjmallett switch (result) { 351217214Sjmallett case CVMX_MGMT_PORT_SUCCESS: 352217214Sjmallett return (0); 353217214Sjmallett case CVMX_MGMT_PORT_NO_MEMORY: 354217214Sjmallett return (ENOBUFS); 355217214Sjmallett case CVMX_MGMT_PORT_INVALID_PARAM: 356217214Sjmallett return (ENXIO); 357217214Sjmallett case CVMX_MGMT_PORT_INIT_ERROR: 358217214Sjmallett return (EIO); 359217214Sjmallett default: 360217214Sjmallett return (EDOOFUS); 361217214Sjmallett } 362217214Sjmallett} 363217214Sjmallett 364217214Sjmallettstatic int 365217214Sjmallettoctm_medchange(struct ifnet *ifp) 366217214Sjmallett{ 367217214Sjmallett return (ENOTSUP); 368217214Sjmallett} 369217214Sjmallett 370217214Sjmallettstatic void 371217214Sjmallettoctm_medstat(struct ifnet *ifp, struct ifmediareq *ifm) 372217214Sjmallett{ 373217214Sjmallett struct octm_softc *sc; 374217214Sjmallett cvmx_helper_link_info_t link_info; 375217214Sjmallett 376217214Sjmallett sc = ifp->if_softc; 377217214Sjmallett 378217214Sjmallett ifm->ifm_status = IFM_AVALID; 379217214Sjmallett ifm->ifm_active = IFT_ETHER; 380217214Sjmallett 381217214Sjmallett link_info = cvmx_mgmt_port_link_get(sc->sc_port); 382217214Sjmallett if (!link_info.s.link_up) 383217214Sjmallett return; 384217214Sjmallett 385217214Sjmallett ifm->ifm_status |= IFM_ACTIVE; 386217214Sjmallett 387217214Sjmallett switch (link_info.s.speed) { 388217214Sjmallett case 10: 389217214Sjmallett ifm->ifm_active |= IFM_10_T; 390217214Sjmallett break; 391217214Sjmallett case 100: 392217214Sjmallett ifm->ifm_active |= IFM_100_TX; 393217214Sjmallett break; 394217214Sjmallett case 1000: 395217214Sjmallett ifm->ifm_active |= IFM_1000_T; 396217214Sjmallett break; 397217214Sjmallett case 10000: 398217214Sjmallett ifm->ifm_active |= IFM_10G_T; 399217214Sjmallett break; 400217214Sjmallett } 401217214Sjmallett 402217214Sjmallett if (link_info.s.full_duplex) 403217214Sjmallett ifm->ifm_active |= IFM_FDX; 404217214Sjmallett else 405217214Sjmallett ifm->ifm_active |= IFM_HDX; 406217214Sjmallett} 407217214Sjmallett 408217214Sjmallettstatic int 409217214Sjmallettoctm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 410217214Sjmallett{ 411217214Sjmallett struct octm_softc *sc; 412217214Sjmallett struct ifreq *ifr; 413217214Sjmallett#ifdef INET 414217214Sjmallett struct ifaddr *ifa; 415217214Sjmallett#endif 416217214Sjmallett int error; 417217214Sjmallett 418217214Sjmallett sc = ifp->if_softc; 419217214Sjmallett ifr = (struct ifreq *)data; 420217214Sjmallett#ifdef INET 421217214Sjmallett ifa = (struct ifaddr *)data; 422217214Sjmallett#endif 423217214Sjmallett 424217214Sjmallett switch (cmd) { 425217214Sjmallett case SIOCSIFADDR: 426217214Sjmallett#ifdef INET 427217214Sjmallett /* 428217214Sjmallett * Avoid reinitialization unless it's necessary. 429217214Sjmallett */ 430217214Sjmallett if (ifa->ifa_addr->sa_family == AF_INET) { 431217214Sjmallett ifp->if_flags |= IFF_UP; 432217214Sjmallett if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 433217214Sjmallett octm_init(sc); 434217214Sjmallett arp_ifinit(ifp, ifa); 435217214Sjmallett 436217214Sjmallett return (0); 437217214Sjmallett } 438217214Sjmallett#endif 439217214Sjmallett error = ether_ioctl(ifp, cmd, data); 440217214Sjmallett if (error != 0) 441217214Sjmallett return (error); 442217214Sjmallett return (0); 443217214Sjmallett 444217214Sjmallett case SIOCSIFFLAGS: 445217214Sjmallett if (ifp->if_flags == sc->sc_flags) 446217214Sjmallett return (0); 447217214Sjmallett if ((ifp->if_flags & IFF_UP) != 0) { 448217214Sjmallett if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) 449217214Sjmallett octm_init(sc); 450217214Sjmallett } else { 451217214Sjmallett if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) { 452217214Sjmallett cvmx_mgmt_port_disable(sc->sc_port); 453217214Sjmallett 454217214Sjmallett ifp->if_drv_flags &= ~IFF_DRV_RUNNING; 455217214Sjmallett } 456217214Sjmallett } 457217214Sjmallett sc->sc_flags = ifp->if_flags; 458217214Sjmallett return (0); 459217214Sjmallett 460217214Sjmallett case SIOCSIFCAP: 461217214Sjmallett /* 462217214Sjmallett * Just change the capabilities in software, currently none 463217214Sjmallett * require reprogramming hardware, they just toggle whether we 464217214Sjmallett * make use of already-present facilities in software. 465217214Sjmallett */ 466217214Sjmallett ifp->if_capenable = ifr->ifr_reqcap; 467217214Sjmallett return (0); 468217214Sjmallett 469217214Sjmallett case SIOCSIFMTU: 470217214Sjmallett cvmx_mgmt_port_set_max_packet_size(sc->sc_port, ifr->ifr_mtu + ifp->if_data.ifi_hdrlen); 471217214Sjmallett return (0); 472217214Sjmallett 473217214Sjmallett case SIOCSIFMEDIA: 474217214Sjmallett case SIOCGIFMEDIA: 475217214Sjmallett error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd); 476217214Sjmallett if (error != 0) 477217214Sjmallett return (error); 478217214Sjmallett return (0); 479217214Sjmallett 480217214Sjmallett default: 481217214Sjmallett error = ether_ioctl(ifp, cmd, data); 482217214Sjmallett if (error != 0) 483217214Sjmallett return (error); 484217214Sjmallett return (0); 485217214Sjmallett } 486217214Sjmallett} 487217214Sjmallett 488217214Sjmallettstatic void 489217214Sjmallettoctm_rx_intr(void *arg) 490217214Sjmallett{ 491217214Sjmallett struct octm_softc *sc = arg; 492217214Sjmallett cvmx_mixx_isr_t mixx_isr; 493217214Sjmallett int len; 494217214Sjmallett 495217214Sjmallett mixx_isr.u64 = cvmx_read_csr(CVMX_MIXX_ISR(sc->sc_port)); 496217214Sjmallett if (!mixx_isr.s.irthresh) { 497217214Sjmallett device_printf(sc->sc_dev, "stray interrupt.\n"); 498217214Sjmallett return; 499217214Sjmallett } 500217214Sjmallett 501217214Sjmallett for (;;) { 502217214Sjmallett struct mbuf *m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR); 503217214Sjmallett if (m == NULL) { 504217214Sjmallett device_printf(sc->sc_dev, "no memory for receive mbuf.\n"); 505217214Sjmallett return; 506217214Sjmallett } 507217214Sjmallett 508217214Sjmallett 509217214Sjmallett len = cvmx_mgmt_port_receive(sc->sc_port, MCLBYTES, m->m_data); 510217214Sjmallett if (len > 0) { 511217214Sjmallett m->m_pkthdr.rcvif = sc->sc_ifp; 512217214Sjmallett m->m_pkthdr.len = m->m_len = len; 513217214Sjmallett 514217214Sjmallett sc->sc_ifp->if_ipackets++; 515217214Sjmallett 516217214Sjmallett (*sc->sc_ifp->if_input)(sc->sc_ifp, m); 517217214Sjmallett 518217214Sjmallett continue; 519217214Sjmallett } 520217214Sjmallett 521217222Sjmallett m_freem(m); 522217222Sjmallett 523217214Sjmallett if (len == 0) 524217214Sjmallett break; 525217214Sjmallett 526217214Sjmallett sc->sc_ifp->if_ierrors++; 527217214Sjmallett } 528217222Sjmallett 529217222Sjmallett /* Acknowledge interrupts. */ 530217222Sjmallett cvmx_write_csr(CVMX_MIXX_ISR(sc->sc_port), mixx_isr.u64); 531217222Sjmallett cvmx_read_csr(CVMX_MIXX_ISR(sc->sc_port)); 532217214Sjmallett} 533