The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mips/cavium/if_octm.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2010-2011 Juli Mallett <jmallett@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  *
   26  * $FreeBSD: stable/9/sys/mips/cavium/if_octm.c 219706 2011-03-16 22:51:34Z jmallett $
   27  */
   28 
   29 /*
   30  * Cavium Octeon management port Ethernet devices.
   31  */
   32 
   33 #include "opt_inet.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/bus.h>
   38 #include <sys/endian.h>
   39 #include <sys/kernel.h>
   40 #include <sys/mbuf.h>
   41 #include <sys/lock.h>
   42 #include <sys/module.h>
   43 #include <sys/mutex.h>
   44 #include <sys/rman.h>
   45 #include <sys/socket.h>
   46 #include <sys/sockio.h>
   47 #include <sys/sysctl.h>
   48 
   49 #include <net/bpf.h>
   50 #include <net/ethernet.h>
   51 #include <net/if.h>
   52 #include <net/if_dl.h>
   53 #include <net/if_media.h>
   54 #include <net/if_types.h>
   55 #include <net/if_var.h>
   56 #include <net/if_vlan_var.h>
   57 
   58 #ifdef INET
   59 #include <netinet/in.h>
   60 #include <netinet/if_ether.h>
   61 #endif
   62 
   63 #include <contrib/octeon-sdk/cvmx.h>
   64 #include <contrib/octeon-sdk/cvmx-interrupt.h>
   65 #include <contrib/octeon-sdk/cvmx-mgmt-port.h>
   66 
   67 extern cvmx_bootinfo_t *octeon_bootinfo;
   68 
   69 struct octm_softc {
   70         struct ifnet *sc_ifp;
   71         device_t sc_dev;
   72         unsigned sc_port;
   73         int sc_flags;
   74         struct ifmedia sc_ifmedia;
   75         struct resource *sc_intr;
   76         void *sc_intr_cookie;
   77 };
   78 
   79 static void     octm_identify(driver_t *, device_t);
   80 static int      octm_probe(device_t);
   81 static int      octm_attach(device_t);
   82 static int      octm_detach(device_t);
   83 static int      octm_shutdown(device_t);
   84 
   85 static void     octm_init(void *);
   86 static int      octm_transmit(struct ifnet *, struct mbuf *);
   87 
   88 static int      octm_medchange(struct ifnet *);
   89 static void     octm_medstat(struct ifnet *, struct ifmediareq *);
   90 
   91 static int      octm_ioctl(struct ifnet *, u_long, caddr_t);
   92 
   93 static void     octm_rx_intr(void *);
   94 
   95 static device_method_t octm_methods[] = {
   96         /* Device interface */
   97         DEVMETHOD(device_identify,      octm_identify),
   98         DEVMETHOD(device_probe,         octm_probe),
   99         DEVMETHOD(device_attach,        octm_attach),
  100         DEVMETHOD(device_detach,        octm_detach),
  101         DEVMETHOD(device_shutdown,      octm_shutdown),
  102 
  103         { 0, 0 }
  104 };
  105 
  106 static driver_t octm_driver = {
  107         "octm",
  108         octm_methods,
  109         sizeof (struct octm_softc),
  110 };
  111 
  112 static devclass_t octm_devclass;
  113 
  114 DRIVER_MODULE(octm, ciu, octm_driver, octm_devclass, 0, 0);
  115 
  116 static void
  117 octm_identify(driver_t *drv, device_t parent)
  118 {
  119         unsigned i;
  120 
  121         if (!octeon_has_feature(OCTEON_FEATURE_MGMT_PORT))
  122                 return;
  123 
  124         for (i = 0; i < CVMX_MGMT_PORT_NUM_PORTS; i++)
  125                 BUS_ADD_CHILD(parent, 0, "octm", i);
  126 }
  127 
  128 static int
  129 octm_probe(device_t dev)
  130 {
  131         cvmx_mgmt_port_result_t result;
  132 
  133         result = cvmx_mgmt_port_initialize(device_get_unit(dev));
  134         switch (result) {
  135         case CVMX_MGMT_PORT_SUCCESS:
  136                 break;
  137         case CVMX_MGMT_PORT_NO_MEMORY:
  138                 return (ENOBUFS);
  139         case CVMX_MGMT_PORT_INVALID_PARAM:
  140                 return (ENXIO);
  141         case CVMX_MGMT_PORT_INIT_ERROR:
  142                 return (EIO);
  143         }
  144 
  145         device_set_desc(dev, "Cavium Octeon Management Ethernet");
  146 
  147         return (0);
  148 }
  149 
  150 static int
  151 octm_attach(device_t dev)
  152 {
  153         struct ifnet *ifp;
  154         struct octm_softc *sc;
  155         cvmx_mixx_irhwm_t mixx_irhwm;
  156         cvmx_mixx_intena_t mixx_intena;
  157         uint64_t mac;
  158         int error;
  159         int irq;
  160         int rid;
  161 
  162         sc = device_get_softc(dev);
  163         sc->sc_dev = dev;
  164         sc->sc_port = device_get_unit(dev);
  165 
  166         switch (sc->sc_port) {
  167         case 0:
  168                 irq = CVMX_IRQ_MII;
  169                 break;
  170         case 1:
  171                 irq = CVMX_IRQ_MII1;
  172                 break;
  173         default:
  174                 device_printf(dev, "unsupported management port %u.\n", sc->sc_port);
  175                 return (ENXIO);
  176         }
  177 
  178         /*
  179          * Set MAC address for this management port.
  180          */
  181         mac = 0;
  182         memcpy((u_int8_t *)&mac + 2, octeon_bootinfo->mac_addr_base, 6);
  183         mac += sc->sc_port;
  184         cvmx_mgmt_port_set_mac(sc->sc_port, mac);
  185 
  186         /* No watermark for input ring.  */
  187         mixx_irhwm.u64 = 0;
  188         cvmx_write_csr(CVMX_MIXX_IRHWM(sc->sc_port), mixx_irhwm.u64);
  189 
  190         /* Enable input ring interrupts.  */
  191         mixx_intena.u64 = 0;
  192         mixx_intena.s.ithena = 1;
  193         cvmx_write_csr(CVMX_MIXX_INTENA(sc->sc_port), mixx_intena.u64);
  194 
  195         /* Allocate and establish interrupt.  */
  196         rid = 0;
  197         sc->sc_intr = bus_alloc_resource(sc->sc_dev, SYS_RES_IRQ, &rid,
  198             irq, irq, 1, RF_ACTIVE);
  199         if (sc->sc_intr == NULL) {
  200                 device_printf(dev, "unable to allocate IRQ.\n");
  201                 return (ENXIO);
  202         }
  203 
  204         error = bus_setup_intr(sc->sc_dev, sc->sc_intr, INTR_TYPE_NET, NULL,
  205             octm_rx_intr, sc, &sc->sc_intr_cookie);
  206         if (error != 0) {
  207                 device_printf(dev, "unable to setup interrupt.\n");
  208                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr);
  209                 return (ENXIO);
  210         }
  211 
  212         bus_describe_intr(sc->sc_dev, sc->sc_intr, sc->sc_intr_cookie, "rx");
  213 
  214         /* XXX Possibly should enable TX interrupts.  */
  215 
  216         ifp = if_alloc(IFT_ETHER);
  217         if (ifp == NULL) {
  218                 device_printf(dev, "cannot allocate ifnet.\n");
  219                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr);
  220                 return (ENOMEM);
  221         }
  222 
  223         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
  224         ifp->if_mtu = ETHERMTU;
  225         ifp->if_init = octm_init;
  226         ifp->if_softc = sc;
  227         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_ALLMULTI;
  228         ifp->if_ioctl = octm_ioctl;
  229 
  230         sc->sc_ifp = ifp;
  231         sc->sc_flags = ifp->if_flags;
  232 
  233         ifmedia_init(&sc->sc_ifmedia, 0, octm_medchange, octm_medstat);
  234 
  235         ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
  236         ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO);
  237 
  238         ether_ifattach(ifp, (const u_int8_t *)&mac + 2);
  239 
  240         ifp->if_transmit = octm_transmit;
  241 
  242         ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
  243         ifp->if_capabilities = IFCAP_VLAN_MTU;
  244         ifp->if_capenable = ifp->if_capabilities;
  245 
  246         IFQ_SET_MAXLEN(&ifp->if_snd, CVMX_MGMT_PORT_NUM_TX_BUFFERS);
  247         ifp->if_snd.ifq_drv_maxlen = CVMX_MGMT_PORT_NUM_TX_BUFFERS;
  248         IFQ_SET_READY(&ifp->if_snd);
  249 
  250         return (bus_generic_attach(dev));
  251 }
  252 
  253 static int
  254 octm_detach(device_t dev)
  255 {
  256         struct octm_softc *sc;
  257         cvmx_mgmt_port_result_t result;
  258 
  259         sc = device_get_softc(dev);
  260 
  261         result = cvmx_mgmt_port_initialize(sc->sc_port);
  262         switch (result) {
  263         case CVMX_MGMT_PORT_SUCCESS:
  264                 break;
  265         case CVMX_MGMT_PORT_NO_MEMORY:
  266                 return (ENOBUFS);
  267         case CVMX_MGMT_PORT_INVALID_PARAM:
  268                 return (ENXIO);
  269         case CVMX_MGMT_PORT_INIT_ERROR:
  270                 return (EIO);
  271         }
  272 
  273         bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_intr);
  274         /* XXX Incomplete.  */
  275 
  276         return (0);
  277 }
  278 
  279 static int
  280 octm_shutdown(device_t dev)
  281 {
  282         return (octm_detach(dev));
  283 }
  284 
  285 static void
  286 octm_init(void *arg)
  287 {
  288         struct ifnet *ifp;
  289         struct octm_softc *sc;
  290         cvmx_mgmt_port_netdevice_flags_t flags;
  291         uint64_t mac;
  292 
  293         sc = arg;
  294         ifp = sc->sc_ifp;
  295 
  296         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
  297                 cvmx_mgmt_port_disable(sc->sc_port);
  298 
  299                 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  300         }
  301 
  302         if (((ifp->if_flags ^ sc->sc_flags) & (IFF_ALLMULTI | IFF_MULTICAST | IFF_PROMISC)) != 0) {
  303                 flags = 0;
  304                 if ((ifp->if_flags & IFF_ALLMULTI) != 0)
  305                         flags |= CVMX_IFF_ALLMULTI;
  306                 if ((ifp->if_flags & IFF_PROMISC) != 0)
  307                         flags |= CVMX_IFF_PROMISC;
  308                 cvmx_mgmt_port_set_multicast_list(sc->sc_port, flags);
  309         }
  310 
  311         mac = 0;
  312         memcpy((u_int8_t *)&mac + 2, IF_LLADDR(ifp), 6);
  313         cvmx_mgmt_port_set_mac(sc->sc_port, mac);
  314 
  315         /* XXX link state?  */
  316 
  317         if ((ifp->if_flags & IFF_UP) != 0)
  318                 cvmx_mgmt_port_enable(sc->sc_port);
  319 
  320         ifp->if_drv_flags |= IFF_DRV_RUNNING;
  321         ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  322 }
  323 
  324 static int
  325 octm_transmit(struct ifnet *ifp, struct mbuf *m)
  326 {
  327         struct octm_softc *sc;
  328         cvmx_mgmt_port_result_t result;
  329 
  330         sc = ifp->if_softc;
  331 
  332         if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
  333             IFF_DRV_RUNNING) {
  334                 m_freem(m);
  335                 return (0);
  336         }
  337 
  338         result = cvmx_mgmt_port_sendm(sc->sc_port, m);
  339 
  340         if (result == CVMX_MGMT_PORT_SUCCESS) {
  341                 ETHER_BPF_MTAP(ifp, m);
  342 
  343                 ifp->if_opackets++;
  344                 ifp->if_obytes += m->m_pkthdr.len;
  345         } else
  346                 ifp->if_oerrors++;
  347 
  348         m_freem(m);
  349 
  350         switch (result) {
  351         case CVMX_MGMT_PORT_SUCCESS:
  352                 return (0);
  353         case CVMX_MGMT_PORT_NO_MEMORY:
  354                 return (ENOBUFS);
  355         case CVMX_MGMT_PORT_INVALID_PARAM:
  356                 return (ENXIO);
  357         case CVMX_MGMT_PORT_INIT_ERROR:
  358                 return (EIO);
  359         default:
  360                 return (EDOOFUS);
  361         }
  362 }
  363 
  364 static int
  365 octm_medchange(struct ifnet *ifp)
  366 {
  367         return (ENOTSUP);
  368 }
  369 
  370 static void
  371 octm_medstat(struct ifnet *ifp, struct ifmediareq *ifm)
  372 {
  373         struct octm_softc *sc;
  374         cvmx_helper_link_info_t link_info;
  375 
  376         sc = ifp->if_softc;
  377 
  378         ifm->ifm_status = IFM_AVALID;
  379         ifm->ifm_active = IFT_ETHER;
  380 
  381         link_info = cvmx_mgmt_port_link_get(sc->sc_port);
  382         if (!link_info.s.link_up)
  383                 return;
  384 
  385         ifm->ifm_status |= IFM_ACTIVE;
  386 
  387         switch (link_info.s.speed) {
  388         case 10:
  389                 ifm->ifm_active |= IFM_10_T;
  390                 break;
  391         case 100:
  392                 ifm->ifm_active |= IFM_100_TX;
  393                 break;
  394         case 1000:
  395                 ifm->ifm_active |= IFM_1000_T;
  396                 break;
  397         case 10000:
  398                 ifm->ifm_active |= IFM_10G_T;
  399                 break;
  400         }
  401 
  402         if (link_info.s.full_duplex)
  403                 ifm->ifm_active |= IFM_FDX;
  404         else
  405                 ifm->ifm_active |= IFM_HDX;
  406 }
  407 
  408 static int
  409 octm_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  410 {
  411         struct octm_softc *sc;
  412         struct ifreq *ifr;
  413 #ifdef INET
  414         struct ifaddr *ifa;
  415 #endif
  416         int error;
  417 
  418         sc = ifp->if_softc;
  419         ifr = (struct ifreq *)data;
  420 #ifdef INET
  421         ifa = (struct ifaddr *)data;
  422 #endif
  423 
  424         switch (cmd) {
  425         case SIOCSIFADDR:
  426 #ifdef INET
  427                 /*
  428                  * Avoid reinitialization unless it's necessary.
  429                  */
  430                 if (ifa->ifa_addr->sa_family == AF_INET) {
  431                         ifp->if_flags |= IFF_UP;
  432                         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  433                                 octm_init(sc);
  434                         arp_ifinit(ifp, ifa);
  435 
  436                         return (0);
  437                 }
  438 #endif
  439                 error = ether_ioctl(ifp, cmd, data);
  440                 if (error != 0)
  441                         return (error);
  442                 return (0);
  443 
  444         case SIOCSIFFLAGS:
  445                 if (ifp->if_flags == sc->sc_flags)
  446                         return (0);
  447                 if ((ifp->if_flags & IFF_UP) != 0) {
  448                         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
  449                                 octm_init(sc);
  450                 } else {
  451                         if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
  452                                 cvmx_mgmt_port_disable(sc->sc_port);
  453 
  454                                 ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
  455                         }
  456                 }
  457                 sc->sc_flags = ifp->if_flags;
  458                 return (0);
  459         
  460         case SIOCSIFCAP:
  461                 /*
  462                  * Just change the capabilities in software, currently none
  463                  * require reprogramming hardware, they just toggle whether we
  464                  * make use of already-present facilities in software.
  465                  */
  466                 ifp->if_capenable = ifr->ifr_reqcap;
  467                 return (0);
  468 
  469         case SIOCSIFMTU:
  470                 cvmx_mgmt_port_set_max_packet_size(sc->sc_port, ifr->ifr_mtu + ifp->if_data.ifi_hdrlen);
  471                 return (0);
  472 
  473         case SIOCSIFMEDIA:
  474         case SIOCGIFMEDIA:
  475                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
  476                 if (error != 0)
  477                         return (error);
  478                 return (0);
  479         
  480         default:
  481                 error = ether_ioctl(ifp, cmd, data);
  482                 if (error != 0)
  483                         return (error);
  484                 return (0);
  485         }
  486 }
  487 
  488 static void
  489 octm_rx_intr(void *arg)
  490 {
  491         struct octm_softc *sc = arg;
  492         cvmx_mixx_isr_t mixx_isr;
  493         int len;
  494 
  495         mixx_isr.u64 = cvmx_read_csr(CVMX_MIXX_ISR(sc->sc_port));
  496         if (!mixx_isr.s.irthresh) {
  497                 device_printf(sc->sc_dev, "stray interrupt.\n");
  498                 return;
  499         }
  500 
  501         for (;;) {
  502                 struct mbuf *m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
  503                 if (m == NULL) {
  504                         device_printf(sc->sc_dev, "no memory for receive mbuf.\n");
  505                         return;
  506                 }
  507 
  508 
  509                 len = cvmx_mgmt_port_receive(sc->sc_port, MCLBYTES, m->m_data);
  510                 if (len > 0) {
  511                         m->m_pkthdr.rcvif = sc->sc_ifp;
  512                         m->m_pkthdr.len = m->m_len = len;
  513 
  514                         sc->sc_ifp->if_ipackets++;
  515 
  516                         (*sc->sc_ifp->if_input)(sc->sc_ifp, m);
  517 
  518                         continue;
  519                 }
  520 
  521                 m_freem(m);
  522 
  523                 if (len == 0)
  524                         break;
  525 
  526                 sc->sc_ifp->if_ierrors++;
  527         }
  528 
  529         /* Acknowledge interrupts.  */
  530         cvmx_write_csr(CVMX_MIXX_ISR(sc->sc_port), mixx_isr.u64);
  531         cvmx_read_csr(CVMX_MIXX_ISR(sc->sc_port));
  532 }

Cache object: c67bee539ec7e1d353490048b9bc1746


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.