LCOV - code coverage report
Current view: top level - dev/pci - if_myx.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 971 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 43 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: if_myx.c,v 1.103 2017/08/01 01:11:35 dlg Exp $        */
       2             : 
       3             : /*
       4             :  * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org>
       5             :  *
       6             :  * Permission to use, copy, modify, and distribute this software for any
       7             :  * purpose with or without fee is hereby granted, provided that the above
       8             :  * copyright notice and this permission notice appear in all copies.
       9             :  *
      10             :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      11             :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      12             :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      13             :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      14             :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      15             :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      16             :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      17             :  */
      18             : 
      19             : /*
      20             :  * Driver for the Myricom Myri-10G Lanai-Z8E Ethernet chipsets.
      21             :  */
      22             : 
      23             : #include "bpfilter.h"
      24             : 
      25             : #include <sys/param.h>
      26             : #include <sys/systm.h>
      27             : #include <sys/sockio.h>
      28             : #include <sys/mbuf.h>
      29             : #include <sys/kernel.h>
      30             : #include <sys/socket.h>
      31             : #include <sys/malloc.h>
      32             : #include <sys/pool.h>
      33             : #include <sys/timeout.h>
      34             : #include <sys/device.h>
      35             : #include <sys/proc.h>
      36             : #include <sys/queue.h>
      37             : 
      38             : #include <machine/bus.h>
      39             : #include <machine/intr.h>
      40             : 
      41             : #include <net/if.h>
      42             : #include <net/if_dl.h>
      43             : #include <net/if_media.h>
      44             : 
      45             : #if NBPFILTER > 0
      46             : #include <net/bpf.h>
      47             : #endif
      48             : 
      49             : #include <netinet/in.h>
      50             : #include <netinet/if_ether.h>
      51             : 
      52             : #include <dev/pci/pcireg.h>
      53             : #include <dev/pci/pcivar.h>
      54             : #include <dev/pci/pcidevs.h>
      55             : 
      56             : #include <dev/pci/if_myxreg.h>
      57             : 
      58             : #ifdef MYX_DEBUG
      59             : #define MYXDBG_INIT     (1<<0)    /* chipset initialization */
      60             : #define MYXDBG_CMD      (2<<0)    /* commands */
      61             : #define MYXDBG_INTR     (3<<0)    /* interrupts */
      62             : #define MYXDBG_ALL      0xffff  /* enable all debugging messages */
      63             : int myx_debug = MYXDBG_ALL;
      64             : #define DPRINTF(_lvl, _arg...)  do {                                    \
      65             :         if (myx_debug & (_lvl))                                             \
      66             :                 printf(_arg);                                           \
      67             : } while (0)
      68             : #else
      69             : #define DPRINTF(_lvl, arg...)
      70             : #endif
      71             : 
      72             : #define DEVNAME(_s)     ((_s)->sc_dev.dv_xname)
      73             : 
      74             : struct myx_dmamem {
      75             :         bus_dmamap_t             mxm_map;
      76             :         bus_dma_segment_t        mxm_seg;
      77             :         int                      mxm_nsegs;
      78             :         size_t                   mxm_size;
      79             :         caddr_t                  mxm_kva;
      80             : };
      81             : 
      82             : struct pool *myx_mcl_pool;
      83             : 
      84             : struct myx_slot {
      85             :         bus_dmamap_t             ms_map;
      86             :         struct mbuf             *ms_m;
      87             : };
      88             : 
      89             : struct myx_rx_ring {
      90             :         struct myx_softc        *mrr_softc;
      91             :         struct timeout           mrr_refill;
      92             :         struct if_rxring         mrr_rxr;
      93             :         struct myx_slot         *mrr_slots;
      94             :         u_int32_t                mrr_offset;
      95             :         u_int                    mrr_running;
      96             :         u_int                    mrr_prod;
      97             :         u_int                    mrr_cons;
      98             :         struct mbuf             *(*mrr_mclget)(void);
      99             : };
     100             : 
     101             : enum myx_state {
     102             :         MYX_S_OFF = 0,
     103             :         MYX_S_RUNNING,
     104             :         MYX_S_DOWN
     105             : };
     106             : 
     107             : struct myx_softc {
     108             :         struct device            sc_dev;
     109             :         struct arpcom            sc_ac;
     110             : 
     111             :         pci_chipset_tag_t        sc_pc;
     112             :         pci_intr_handle_t        sc_ih;
     113             :         pcitag_t                 sc_tag;
     114             : 
     115             :         bus_dma_tag_t            sc_dmat;
     116             :         bus_space_tag_t          sc_memt;
     117             :         bus_space_handle_t       sc_memh;
     118             :         bus_size_t               sc_mems;
     119             : 
     120             :         struct myx_dmamem        sc_zerodma;
     121             :         struct myx_dmamem        sc_cmddma;
     122             :         struct myx_dmamem        sc_paddma;
     123             : 
     124             :         struct myx_dmamem        sc_sts_dma;
     125             :         volatile struct myx_status      *sc_sts;
     126             : 
     127             :         int                      sc_intx;
     128             :         void                    *sc_irqh;
     129             :         u_int32_t                sc_irqcoaloff;
     130             :         u_int32_t                sc_irqclaimoff;
     131             :         u_int32_t                sc_irqdeassertoff;
     132             : 
     133             :         struct myx_dmamem        sc_intrq_dma;
     134             :         struct myx_intrq_desc   *sc_intrq;
     135             :         u_int                    sc_intrq_count;
     136             :         u_int                    sc_intrq_idx;
     137             : 
     138             :         u_int                    sc_rx_ring_count;
     139             : #define  MYX_RXSMALL             0
     140             : #define  MYX_RXBIG               1
     141             :         struct myx_rx_ring       sc_rx_ring[2];
     142             : 
     143             :         bus_size_t               sc_tx_boundary;
     144             :         u_int                    sc_tx_ring_count;
     145             :         u_int32_t                sc_tx_ring_offset;
     146             :         u_int                    sc_tx_nsegs;
     147             :         u_int32_t                sc_tx_count; /* shadows ms_txdonecnt */
     148             :         u_int                    sc_tx_ring_prod;
     149             :         u_int                    sc_tx_ring_cons;
     150             : 
     151             :         u_int                    sc_tx_prod;
     152             :         u_int                    sc_tx_cons;
     153             :         struct myx_slot         *sc_tx_slots;
     154             : 
     155             :         struct ifmedia           sc_media;
     156             : 
     157             :         volatile enum myx_state  sc_state;
     158             :         volatile u_int8_t        sc_linkdown;
     159             : };
     160             : 
     161             : #define MYX_RXSMALL_SIZE        MCLBYTES
     162             : #define MYX_RXBIG_SIZE          (MYX_MTU - \
     163             :     (ETHER_ALIGN + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN))
     164             : 
     165             : int      myx_match(struct device *, void *, void *);
     166             : void     myx_attach(struct device *, struct device *, void *);
     167             : int      myx_pcie_dc(struct myx_softc *, struct pci_attach_args *);
     168             : int      myx_query(struct myx_softc *sc, char *, size_t);
     169             : u_int    myx_ether_aton(char *, u_int8_t *, u_int);
     170             : void     myx_attachhook(struct device *);
     171             : int      myx_loadfirmware(struct myx_softc *, const char *);
     172             : int      myx_probe_firmware(struct myx_softc *);
     173             : 
     174             : void     myx_read(struct myx_softc *, bus_size_t, void *, bus_size_t);
     175             : void     myx_write(struct myx_softc *, bus_size_t, void *, bus_size_t);
     176             : 
     177             : #if defined(__LP64__)
     178             : #define _myx_bus_space_write bus_space_write_raw_region_8
     179             : typedef u_int64_t myx_bus_t;
     180             : #else
     181             : #define _myx_bus_space_write bus_space_write_raw_region_4
     182             : typedef u_int32_t myx_bus_t;
     183             : #endif
     184             : #define myx_bus_space_write(_sc, _o, _a, _l) \
     185             :     _myx_bus_space_write((_sc)->sc_memt, (_sc)->sc_memh, (_o), (_a), (_l))
     186             : 
     187             : int      myx_cmd(struct myx_softc *, u_int32_t, struct myx_cmd *, u_int32_t *);
     188             : int      myx_boot(struct myx_softc *, u_int32_t);
     189             : 
     190             : int      myx_rdma(struct myx_softc *, u_int);
     191             : int      myx_dmamem_alloc(struct myx_softc *, struct myx_dmamem *,
     192             :             bus_size_t, u_int align);
     193             : void     myx_dmamem_free(struct myx_softc *, struct myx_dmamem *);
     194             : int      myx_media_change(struct ifnet *);
     195             : void     myx_media_status(struct ifnet *, struct ifmediareq *);
     196             : void     myx_link_state(struct myx_softc *, u_int32_t);
     197             : void     myx_watchdog(struct ifnet *);
     198             : int      myx_ioctl(struct ifnet *, u_long, caddr_t);
     199             : int      myx_rxrinfo(struct myx_softc *, struct if_rxrinfo *);
     200             : void     myx_up(struct myx_softc *);
     201             : void     myx_iff(struct myx_softc *);
     202             : void     myx_down(struct myx_softc *);
     203             : 
     204             : void     myx_start(struct ifqueue *);
     205             : void     myx_write_txd_tail(struct myx_softc *, struct myx_slot *, u_int8_t,
     206             :             u_int32_t, u_int);
     207             : int      myx_load_mbuf(struct myx_softc *, struct myx_slot *, struct mbuf *);
     208             : int      myx_setlladdr(struct myx_softc *, u_int32_t, u_int8_t *);
     209             : int      myx_intr(void *);
     210             : void     myx_rxeof(struct myx_softc *);
     211             : void     myx_txeof(struct myx_softc *, u_int32_t);
     212             : 
     213             : int                     myx_buf_fill(struct myx_softc *, struct myx_slot *,
     214             :                             struct mbuf *(*)(void));
     215             : struct mbuf *           myx_mcl_small(void);
     216             : struct mbuf *           myx_mcl_big(void);
     217             : 
     218             : int                     myx_rx_init(struct myx_softc *, int, bus_size_t);
     219             : int                     myx_rx_fill(struct myx_softc *, struct myx_rx_ring *);
     220             : void                    myx_rx_empty(struct myx_softc *, struct myx_rx_ring *);
     221             : void                    myx_rx_free(struct myx_softc *, struct myx_rx_ring *);
     222             : 
     223             : int                     myx_tx_init(struct myx_softc *, bus_size_t);
     224             : void                    myx_tx_empty(struct myx_softc *);
     225             : void                    myx_tx_free(struct myx_softc *);
     226             : 
     227             : void                    myx_refill(void *);
     228             : 
     229             : struct cfdriver myx_cd = {
     230             :         NULL, "myx", DV_IFNET
     231             : };
     232             : struct cfattach myx_ca = {
     233             :         sizeof(struct myx_softc), myx_match, myx_attach
     234             : };
     235             : 
     236             : const struct pci_matchid myx_devices[] = {
     237             :         { PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E },
     238             :         { PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E_9 }
     239             : };
     240             : 
     241             : int
     242           0 : myx_match(struct device *parent, void *match, void *aux)
     243             : {
     244           0 :         return (pci_matchbyid(aux, myx_devices, nitems(myx_devices)));
     245             : }
     246             : 
     247             : void
     248           0 : myx_attach(struct device *parent, struct device *self, void *aux)
     249             : {
     250           0 :         struct myx_softc        *sc = (struct myx_softc *)self;
     251           0 :         struct pci_attach_args  *pa = aux;
     252           0 :         char                     part[32];
     253             :         pcireg_t                 memtype;
     254             : 
     255           0 :         sc->sc_pc = pa->pa_pc;
     256           0 :         sc->sc_tag = pa->pa_tag;
     257           0 :         sc->sc_dmat = pa->pa_dmat;
     258             : 
     259           0 :         sc->sc_rx_ring[MYX_RXSMALL].mrr_softc = sc;
     260           0 :         sc->sc_rx_ring[MYX_RXSMALL].mrr_mclget = myx_mcl_small;
     261           0 :         timeout_set(&sc->sc_rx_ring[MYX_RXSMALL].mrr_refill, myx_refill,
     262           0 :             &sc->sc_rx_ring[MYX_RXSMALL]);
     263           0 :         sc->sc_rx_ring[MYX_RXBIG].mrr_softc = sc;
     264           0 :         sc->sc_rx_ring[MYX_RXBIG].mrr_mclget = myx_mcl_big;
     265           0 :         timeout_set(&sc->sc_rx_ring[MYX_RXBIG].mrr_refill, myx_refill,
     266           0 :             &sc->sc_rx_ring[MYX_RXBIG]);
     267             : 
     268             :         /* Map the PCI memory space */
     269           0 :         memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, MYXBAR0);
     270           0 :         if (pci_mapreg_map(pa, MYXBAR0, memtype, BUS_SPACE_MAP_PREFETCHABLE,
     271           0 :             &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_mems, 0)) {
     272           0 :                 printf(": unable to map register memory\n");
     273           0 :                 return;
     274             :         }
     275             : 
     276             :         /* Get board details (mac/part) */
     277           0 :         memset(part, 0, sizeof(part));
     278           0 :         if (myx_query(sc, part, sizeof(part)) != 0)
     279             :                 goto unmap;
     280             : 
     281             :         /* Map the interrupt */
     282           0 :         if (pci_intr_map_msi(pa, &sc->sc_ih) != 0) {
     283           0 :                 if (pci_intr_map(pa, &sc->sc_ih) != 0) {
     284           0 :                         printf(": unable to map interrupt\n");
     285           0 :                         goto unmap;
     286             :                 }
     287           0 :                 sc->sc_intx = 1;
     288           0 :         }
     289             : 
     290           0 :         printf(": %s, model %s, address %s\n",
     291           0 :             pci_intr_string(pa->pa_pc, sc->sc_ih),
     292           0 :             part[0] == '\0' ? "(unknown)" : part,
     293           0 :             ether_sprintf(sc->sc_ac.ac_enaddr));
     294             : 
     295           0 :         if (myx_pcie_dc(sc, pa) != 0)
     296           0 :                 printf("%s: unable to configure PCI Express\n", DEVNAME(sc));
     297             : 
     298           0 :         config_mountroot(self, myx_attachhook);
     299             : 
     300           0 :         return;
     301             : 
     302             :  unmap:
     303           0 :         bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
     304           0 :         sc->sc_mems = 0;
     305           0 : }
     306             : 
     307             : int
     308           0 : myx_pcie_dc(struct myx_softc *sc, struct pci_attach_args *pa)
     309             : {
     310             :         pcireg_t dcsr;
     311             :         pcireg_t mask = PCI_PCIE_DCSR_MPS | PCI_PCIE_DCSR_ERO;
     312           0 :         pcireg_t dc = ((fls(4096) - 8) << 12) | PCI_PCIE_DCSR_ERO;
     313           0 :         int reg;
     314             : 
     315           0 :         if (pci_get_capability(sc->sc_pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
     316           0 :             &reg, NULL) == 0)
     317           0 :                 return (-1);
     318             : 
     319           0 :         reg += PCI_PCIE_DCSR;
     320           0 :         dcsr = pci_conf_read(sc->sc_pc, pa->pa_tag, reg);
     321           0 :         if ((dcsr & mask) != dc) {
     322           0 :                 CLR(dcsr, mask);
     323           0 :                 SET(dcsr, dc);
     324           0 :                 pci_conf_write(sc->sc_pc, pa->pa_tag, reg, dcsr);
     325           0 :         }
     326             : 
     327           0 :         return (0);
     328           0 : }
     329             : 
     330             : u_int
     331           0 : myx_ether_aton(char *mac, u_int8_t *lladdr, u_int maxlen)
     332             : {
     333             :         u_int           i, j;
     334             :         u_int8_t        digit;
     335             : 
     336           0 :         memset(lladdr, 0, ETHER_ADDR_LEN);
     337           0 :         for (i = j = 0; mac[i] != '\0' && i < maxlen; i++) {
     338           0 :                 if (mac[i] >= '0' && mac[i] <= '9')
     339           0 :                         digit = mac[i] - '0';
     340           0 :                 else if (mac[i] >= 'A' && mac[i] <= 'F')
     341           0 :                         digit = mac[i] - 'A' + 10;
     342           0 :                 else if (mac[i] >= 'a' && mac[i] <= 'f')
     343           0 :                         digit = mac[i] - 'a' + 10;
     344             :                 else
     345             :                         continue;
     346           0 :                 if ((j & 1) == 0)
     347           0 :                         digit <<= 4;
     348           0 :                 lladdr[j++/2] |= digit;
     349           0 :         }
     350             : 
     351           0 :         return (i);
     352             : }
     353             : 
     354             : int
     355           0 : myx_query(struct myx_softc *sc, char *part, size_t partlen)
     356             : {
     357           0 :         struct myx_gen_hdr hdr;
     358           0 :         u_int32_t       offset;
     359           0 :         u_int8_t        strings[MYX_STRING_SPECS_SIZE];
     360             :         u_int           i, len, maxlen;
     361             : 
     362           0 :         myx_read(sc, MYX_HEADER_POS, &offset, sizeof(offset));
     363           0 :         offset = betoh32(offset);
     364           0 :         if (offset + sizeof(hdr) > sc->sc_mems) {
     365           0 :                 printf(": header is outside register window\n");
     366           0 :                 return (1);
     367             :         }
     368             : 
     369           0 :         myx_read(sc, offset, &hdr, sizeof(hdr));
     370           0 :         offset = betoh32(hdr.fw_specs);
     371           0 :         len = min(betoh32(hdr.fw_specs_len), sizeof(strings));
     372             : 
     373           0 :         bus_space_read_region_1(sc->sc_memt, sc->sc_memh, offset, strings, len);
     374             : 
     375           0 :         for (i = 0; i < len; i++) {
     376           0 :                 maxlen = len - i;
     377           0 :                 if (strings[i] == '\0')
     378             :                         break;
     379           0 :                 if (maxlen > 4 && memcmp("MAC=", &strings[i], 4) == 0) {
     380           0 :                         i += 4;
     381           0 :                         i += myx_ether_aton(&strings[i],
     382           0 :                             sc->sc_ac.ac_enaddr, maxlen);
     383           0 :                 } else if (maxlen > 3 && memcmp("PC=", &strings[i], 3) == 0) {
     384           0 :                         i += 3;
     385           0 :                         i += strlcpy(part, &strings[i], min(maxlen, partlen));
     386           0 :                 }
     387           0 :                 for (; i < len; i++) {
     388           0 :                         if (strings[i] == '\0')
     389             :                                 break;
     390             :                 }
     391             :         }
     392             : 
     393           0 :         return (0);
     394           0 : }
     395             : 
     396             : int
     397           0 : myx_loadfirmware(struct myx_softc *sc, const char *filename)
     398             : {
     399           0 :         struct myx_gen_hdr      hdr;
     400           0 :         u_int8_t                *fw;
     401           0 :         size_t                  fwlen;
     402             :         u_int32_t               offset;
     403             :         u_int                   i, ret = 1;
     404             : 
     405           0 :         if (loadfirmware(filename, &fw, &fwlen) != 0) {
     406           0 :                 printf("%s: could not load firmware %s\n", DEVNAME(sc),
     407             :                     filename);
     408           0 :                 return (1);
     409             :         }
     410           0 :         if (fwlen > MYX_SRAM_SIZE || fwlen < MYXFW_MIN_LEN) {
     411           0 :                 printf("%s: invalid firmware %s size\n", DEVNAME(sc), filename);
     412           0 :                 goto err;
     413             :         }
     414             : 
     415           0 :         memcpy(&offset, fw + MYX_HEADER_POS, sizeof(offset));
     416           0 :         offset = betoh32(offset);
     417           0 :         if ((offset + sizeof(hdr)) > fwlen) {
     418           0 :                 printf("%s: invalid firmware %s\n", DEVNAME(sc), filename);
     419           0 :                 goto err;
     420             :         }
     421             : 
     422           0 :         memcpy(&hdr, fw + offset, sizeof(hdr));
     423             :         DPRINTF(MYXDBG_INIT, "%s: "
     424             :             "fw hdr off %u, length %u, type 0x%x, version %s\n",
     425             :             DEVNAME(sc), offset, betoh32(hdr.fw_hdrlength),
     426             :             betoh32(hdr.fw_type), hdr.fw_version);
     427             : 
     428           0 :         if (betoh32(hdr.fw_type) != MYXFW_TYPE_ETH ||
     429           0 :             memcmp(MYXFW_VER, hdr.fw_version, strlen(MYXFW_VER)) != 0) {
     430           0 :                 printf("%s: invalid firmware type 0x%x version %s\n",
     431           0 :                     DEVNAME(sc), betoh32(hdr.fw_type), hdr.fw_version);
     432           0 :                 goto err;
     433             :         }
     434             : 
     435             :         /* Write the firmware to the card's SRAM */
     436           0 :         for (i = 0; i < fwlen; i += 256)
     437           0 :                 myx_write(sc, i + MYX_FW, fw + i, min(256, fwlen - i));
     438             : 
     439           0 :         if (myx_boot(sc, fwlen) != 0) {
     440           0 :                 printf("%s: failed to boot %s\n", DEVNAME(sc), filename);
     441           0 :                 goto err;
     442             :         }
     443             : 
     444           0 :         ret = 0;
     445             : 
     446             : err:
     447           0 :         free(fw, M_DEVBUF, fwlen);
     448           0 :         return (ret);
     449           0 : }
     450             : 
     451             : void
     452           0 : myx_attachhook(struct device *self)
     453             : {
     454           0 :         struct myx_softc        *sc = (struct myx_softc *)self;
     455           0 :         struct ifnet            *ifp = &sc->sc_ac.ac_if;
     456           0 :         struct myx_cmd           mc;
     457             : 
     458             :         /* this is sort of racy */
     459           0 :         if (myx_mcl_pool == NULL) {
     460           0 :                 myx_mcl_pool = malloc(sizeof(*myx_mcl_pool), M_DEVBUF,
     461             :                     M_WAITOK);
     462             : 
     463           0 :                 m_pool_init(myx_mcl_pool, MYX_RXBIG_SIZE, MYX_BOUNDARY,
     464             :                     "myxmcl");
     465           0 :                 pool_cache_init(myx_mcl_pool);
     466           0 :         }
     467             : 
     468             :         /* Allocate command DMA memory */
     469           0 :         if (myx_dmamem_alloc(sc, &sc->sc_cmddma, MYXALIGN_CMD,
     470           0 :             MYXALIGN_CMD) != 0) {
     471           0 :                 printf("%s: failed to allocate command DMA memory\n",
     472           0 :                     DEVNAME(sc));
     473           0 :                 return;
     474             :         }
     475             : 
     476             :         /* Try the firmware stored on disk */
     477           0 :         if (myx_loadfirmware(sc, MYXFW_ALIGNED) != 0) {
     478             :                 /* error printed by myx_loadfirmware */
     479             :                 goto freecmd;
     480             :         }
     481             : 
     482           0 :         memset(&mc, 0, sizeof(mc));
     483             : 
     484           0 :         if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
     485           0 :                 printf("%s: failed to reset the device\n", DEVNAME(sc));
     486           0 :                 goto freecmd;
     487             :         }
     488             : 
     489           0 :         sc->sc_tx_boundary = 4096;
     490             : 
     491           0 :         if (myx_probe_firmware(sc) != 0) {
     492           0 :                 printf("%s: error while selecting firmware\n", DEVNAME(sc));
     493           0 :                 goto freecmd;
     494             :         }
     495             : 
     496           0 :         sc->sc_irqh = pci_intr_establish(sc->sc_pc, sc->sc_ih,
     497           0 :             IPL_NET | IPL_MPSAFE, myx_intr, sc, DEVNAME(sc));
     498           0 :         if (sc->sc_irqh == NULL) {
     499           0 :                 printf("%s: unable to establish interrupt\n", DEVNAME(sc));
     500           0 :                 goto freecmd;
     501             :         }
     502             : 
     503           0 :         ifp->if_softc = sc;
     504           0 :         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     505           0 :         ifp->if_xflags = IFXF_MPSAFE;
     506           0 :         ifp->if_ioctl = myx_ioctl;
     507           0 :         ifp->if_qstart = myx_start;
     508           0 :         ifp->if_watchdog = myx_watchdog;
     509           0 :         ifp->if_hardmtu = MYX_RXBIG_SIZE;
     510           0 :         strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
     511           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, 1);
     512             : 
     513           0 :         ifp->if_capabilities = IFCAP_VLAN_MTU;
     514             : #if 0
     515             :         ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
     516             :         ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
     517             :             IFCAP_CSUM_UDPv4;
     518             : #endif
     519             : 
     520           0 :         ifmedia_init(&sc->sc_media, 0, myx_media_change, myx_media_status);
     521           0 :         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
     522           0 :         ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
     523             : 
     524           0 :         if_attach(ifp);
     525           0 :         ether_ifattach(ifp);
     526             : 
     527           0 :         return;
     528             : 
     529             : freecmd:
     530           0 :         myx_dmamem_free(sc, &sc->sc_cmddma);
     531           0 : }
     532             : 
     533             : int
     534           0 : myx_probe_firmware(struct myx_softc *sc)
     535             : {
     536           0 :         struct myx_dmamem test;
     537             :         bus_dmamap_t map;
     538           0 :         struct myx_cmd mc;
     539             :         pcireg_t csr;
     540           0 :         int offset;
     541             :         int width = 0;
     542             : 
     543           0 :         if (pci_get_capability(sc->sc_pc, sc->sc_tag, PCI_CAP_PCIEXPRESS,
     544             :             &offset, NULL)) {
     545           0 :                 csr = pci_conf_read(sc->sc_pc, sc->sc_tag,
     546           0 :                     offset + PCI_PCIE_LCSR);
     547           0 :                 width = (csr >> 20) & 0x3f;
     548             : 
     549           0 :                 if (width <= 4) {
     550             :                         /*
     551             :                          * if the link width is 4 or less we can use the
     552             :                          * aligned firmware.
     553             :                          */
     554           0 :                         return (0);
     555             :                 }
     556             :         }
     557             : 
     558           0 :         if (myx_dmamem_alloc(sc, &test, 4096, 4096) != 0)
     559           0 :                 return (1);
     560           0 :         map = test.mxm_map;
     561             : 
     562           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     563             :             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
     564             : 
     565           0 :         memset(&mc, 0, sizeof(mc));
     566           0 :         mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
     567           0 :         mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
     568           0 :         mc.mc_data2 = htobe32(4096 * 0x10000);
     569           0 :         if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) {
     570           0 :                 printf("%s: DMA read test failed\n", DEVNAME(sc));
     571           0 :                 goto fail;
     572             :         }
     573             : 
     574           0 :         memset(&mc, 0, sizeof(mc));
     575           0 :         mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
     576           0 :         mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
     577           0 :         mc.mc_data2 = htobe32(4096 * 0x1);
     578           0 :         if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) {
     579           0 :                 printf("%s: DMA write test failed\n", DEVNAME(sc));
     580           0 :                 goto fail;
     581             :         }
     582             : 
     583           0 :         memset(&mc, 0, sizeof(mc));
     584           0 :         mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
     585           0 :         mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
     586           0 :         mc.mc_data2 = htobe32(4096 * 0x10001);
     587           0 :         if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) {
     588           0 :                 printf("%s: DMA read/write test failed\n", DEVNAME(sc));
     589           0 :                 goto fail;
     590             :         }
     591             : 
     592           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     593             :             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
     594           0 :         myx_dmamem_free(sc, &test);
     595           0 :         return (0);
     596             : 
     597             : fail:
     598           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     599             :             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
     600           0 :         myx_dmamem_free(sc, &test);
     601             : 
     602           0 :         if (myx_loadfirmware(sc, MYXFW_UNALIGNED) != 0) {
     603           0 :                 printf("%s: unable to load %s\n", DEVNAME(sc),
     604             :                     MYXFW_UNALIGNED);
     605           0 :                 return (1);
     606             :         }
     607             : 
     608           0 :         sc->sc_tx_boundary = 2048;
     609             : 
     610           0 :         printf("%s: using unaligned firmware\n", DEVNAME(sc));
     611           0 :         return (0);
     612           0 : }
     613             : 
     614             : void
     615           0 : myx_read(struct myx_softc *sc, bus_size_t off, void *ptr, bus_size_t len)
     616             : {
     617           0 :         bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
     618             :             BUS_SPACE_BARRIER_READ);
     619           0 :         bus_space_read_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
     620           0 : }
     621             : 
     622             : void
     623           0 : myx_write(struct myx_softc *sc, bus_size_t off, void *ptr, bus_size_t len)
     624             : {
     625           0 :         bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
     626           0 :         bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
     627             :             BUS_SPACE_BARRIER_WRITE);
     628           0 : }
     629             : 
     630             : int
     631           0 : myx_dmamem_alloc(struct myx_softc *sc, struct myx_dmamem *mxm,
     632             :     bus_size_t size, u_int align)
     633             : {
     634           0 :         mxm->mxm_size = size;
     635             : 
     636           0 :         if (bus_dmamap_create(sc->sc_dmat, mxm->mxm_size, 1,
     637             :             mxm->mxm_size, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
     638           0 :             &mxm->mxm_map) != 0)
     639           0 :                 return (1);
     640           0 :         if (bus_dmamem_alloc(sc->sc_dmat, mxm->mxm_size,
     641             :             align, 0, &mxm->mxm_seg, 1, &mxm->mxm_nsegs,
     642           0 :             BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
     643             :                 goto destroy;
     644           0 :         if (bus_dmamem_map(sc->sc_dmat, &mxm->mxm_seg, mxm->mxm_nsegs,
     645           0 :             mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_WAITOK) != 0)
     646             :                 goto free;
     647           0 :         if (bus_dmamap_load(sc->sc_dmat, mxm->mxm_map, mxm->mxm_kva,
     648           0 :             mxm->mxm_size, NULL, BUS_DMA_WAITOK) != 0)
     649             :                 goto unmap;
     650             : 
     651           0 :         return (0);
     652             :  unmap:
     653           0 :         bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
     654             :  free:
     655           0 :         bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
     656             :  destroy:
     657           0 :         bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
     658           0 :         return (1);
     659           0 : }
     660             : 
     661             : void
     662           0 : myx_dmamem_free(struct myx_softc *sc, struct myx_dmamem *mxm)
     663             : {
     664           0 :         bus_dmamap_unload(sc->sc_dmat, mxm->mxm_map);
     665           0 :         bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
     666           0 :         bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
     667           0 :         bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
     668           0 : }
     669             : 
     670             : int
     671           0 : myx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r)
     672             : {
     673           0 :         bus_dmamap_t             map = sc->sc_cmddma.mxm_map;
     674             :         struct myx_response     *mr;
     675             :         u_int                    i;
     676             :         u_int32_t                result, data;
     677             : #ifdef MYX_DEBUG
     678             :         static const char *cmds[MYXCMD_MAX] = {
     679             :                 "CMD_NONE",
     680             :                 "CMD_RESET",
     681             :                 "CMD_GET_VERSION",
     682             :                 "CMD_SET_INTRQDMA",
     683             :                 "CMD_SET_BIGBUFSZ",
     684             :                 "CMD_SET_SMALLBUFSZ",
     685             :                 "CMD_GET_TXRINGOFF",
     686             :                 "CMD_GET_RXSMALLRINGOFF",
     687             :                 "CMD_GET_RXBIGRINGOFF",
     688             :                 "CMD_GET_INTRACKOFF",
     689             :                 "CMD_GET_INTRDEASSERTOFF",
     690             :                 "CMD_GET_TXRINGSZ",
     691             :                 "CMD_GET_RXRINGSZ",
     692             :                 "CMD_SET_INTRQSZ",
     693             :                 "CMD_SET_IFUP",
     694             :                 "CMD_SET_IFDOWN",
     695             :                 "CMD_SET_MTU",
     696             :                 "CMD_GET_INTRCOALDELAYOFF",
     697             :                 "CMD_SET_STATSINTVL",
     698             :                 "CMD_SET_STATSDMA_OLD",
     699             :                 "CMD_SET_PROMISC",
     700             :                 "CMD_UNSET_PROMISC",
     701             :                 "CMD_SET_LLADDR",
     702             :                 "CMD_SET_FC",
     703             :                 "CMD_UNSET_FC",
     704             :                 "CMD_DMA_TEST",
     705             :                 "CMD_SET_ALLMULTI",
     706             :                 "CMD_UNSET_ALLMULTI",
     707             :                 "CMD_SET_MCASTGROUP",
     708             :                 "CMD_UNSET_MCASTGROUP",
     709             :                 "CMD_UNSET_MCAST",
     710             :                 "CMD_SET_STATSDMA",
     711             :                 "CMD_UNALIGNED_DMA_TEST",
     712             :                 "CMD_GET_UNALIGNED_STATUS"
     713             :         };
     714             : #endif
     715             : 
     716           0 :         mc->mc_cmd = htobe32(cmd);
     717           0 :         mc->mc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
     718           0 :         mc->mc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
     719             : 
     720           0 :         mr = (struct myx_response *)sc->sc_cmddma.mxm_kva;
     721           0 :         mr->mr_result = 0xffffffff;
     722             : 
     723             :         /* Send command */
     724           0 :         myx_write(sc, MYX_CMD, (u_int8_t *)mc, sizeof(struct myx_cmd));
     725           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     726             :             BUS_DMASYNC_PREREAD);
     727             : 
     728           0 :         for (i = 0; i < 20; i++) {
     729           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     730             :                     BUS_DMASYNC_POSTREAD);
     731           0 :                 result = betoh32(mr->mr_result);
     732           0 :                 data = betoh32(mr->mr_data);
     733             : 
     734           0 :                 if (result != 0xffffffff)
     735             :                         break;
     736             : 
     737           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     738             :                     BUS_DMASYNC_PREREAD);
     739           0 :                 delay(1000);
     740             :         }
     741             : 
     742             :         DPRINTF(MYXDBG_CMD, "%s(%s): %s completed, i %d, "
     743             :             "result 0x%x, data 0x%x (%u)\n", DEVNAME(sc), __func__,
     744             :             cmds[cmd], i, result, data, data);
     745             : 
     746           0 :         if (result != 0)
     747           0 :                 return (-1);
     748             : 
     749           0 :         if (r != NULL)
     750           0 :                 *r = data;
     751           0 :         return (0);
     752           0 : }
     753             : 
     754             : int
     755           0 : myx_boot(struct myx_softc *sc, u_int32_t length)
     756             : {
     757           0 :         struct myx_bootcmd       bc;
     758           0 :         bus_dmamap_t             map = sc->sc_cmddma.mxm_map;
     759             :         u_int32_t               *status;
     760             :         u_int                    i, ret = 1;
     761             : 
     762           0 :         memset(&bc, 0, sizeof(bc));
     763           0 :         bc.bc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
     764           0 :         bc.bc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
     765           0 :         bc.bc_result = 0xffffffff;
     766           0 :         bc.bc_offset = htobe32(MYX_FW_BOOT);
     767           0 :         bc.bc_length = htobe32(length - 8);
     768           0 :         bc.bc_copyto = htobe32(8);
     769           0 :         bc.bc_jumpto = htobe32(0);
     770             : 
     771           0 :         status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
     772           0 :         *status = 0;
     773             : 
     774             :         /* Send command */
     775           0 :         myx_write(sc, MYX_BOOT, &bc, sizeof(bc));
     776           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     777             :             BUS_DMASYNC_PREREAD);
     778             : 
     779           0 :         for (i = 0; i < 200; i++) {
     780           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     781             :                     BUS_DMASYNC_POSTREAD);
     782           0 :                 if (*status == 0xffffffff) {
     783             :                         ret = 0;
     784           0 :                         break;
     785             :                 }
     786             : 
     787           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     788             :                     BUS_DMASYNC_PREREAD);
     789           0 :                 delay(1000);
     790             :         }
     791             : 
     792             :         DPRINTF(MYXDBG_CMD, "%s: boot completed, i %d, result %d\n",
     793             :             DEVNAME(sc), i, ret);
     794             : 
     795           0 :         return (ret);
     796           0 : }
     797             : 
     798             : int
     799           0 : myx_rdma(struct myx_softc *sc, u_int do_enable)
     800             : {
     801           0 :         struct myx_rdmacmd       rc;
     802           0 :         bus_dmamap_t             map = sc->sc_cmddma.mxm_map;
     803           0 :         bus_dmamap_t             pad = sc->sc_paddma.mxm_map;
     804             :         u_int32_t               *status;
     805             :         int                      ret = 1;
     806             :         u_int                    i;
     807             : 
     808             :         /*
     809             :          * It is required to setup a _dummy_ RDMA address. It also makes
     810             :          * some PCI-E chipsets resend dropped messages.
     811             :          */
     812           0 :         rc.rc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
     813           0 :         rc.rc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
     814           0 :         rc.rc_result = 0xffffffff;
     815           0 :         rc.rc_rdma_high = htobe32(MYX_ADDRHIGH(pad->dm_segs[0].ds_addr));
     816           0 :         rc.rc_rdma_low = htobe32(MYX_ADDRLOW(pad->dm_segs[0].ds_addr));
     817           0 :         rc.rc_enable = htobe32(do_enable);
     818             : 
     819           0 :         status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
     820           0 :         *status = 0;
     821             : 
     822           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     823             :             BUS_DMASYNC_PREREAD);
     824             : 
     825             :         /* Send command */
     826           0 :         myx_write(sc, MYX_RDMA, &rc, sizeof(rc));
     827             : 
     828           0 :         for (i = 0; i < 20; i++) {
     829           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     830             :                     BUS_DMASYNC_POSTREAD);
     831             : 
     832           0 :                 if (*status == 0xffffffff) {
     833             :                         ret = 0;
     834           0 :                         break;
     835             :                 }
     836             : 
     837           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     838             :                     BUS_DMASYNC_PREREAD);
     839           0 :                 delay(1000);
     840             :         }
     841             : 
     842             :         DPRINTF(MYXDBG_CMD, "%s(%s): dummy RDMA %s, i %d, result 0x%x\n",
     843             :             DEVNAME(sc), __func__,
     844             :             do_enable ? "enabled" : "disabled", i, betoh32(*status));
     845             : 
     846           0 :         return (ret);
     847           0 : }
     848             : 
     849             : int
     850           0 : myx_media_change(struct ifnet *ifp)
     851             : {
     852             :         /* ignore */
     853           0 :         return (0);
     854             : }
     855             : 
     856             : void
     857           0 : myx_media_status(struct ifnet *ifp, struct ifmediareq *imr)
     858             : {
     859           0 :         struct myx_softc        *sc = (struct myx_softc *)ifp->if_softc;
     860           0 :         bus_dmamap_t             map = sc->sc_sts_dma.mxm_map;
     861             :         u_int32_t                sts;
     862             : 
     863           0 :         imr->ifm_active = IFM_ETHER | IFM_AUTO;
     864           0 :         if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
     865           0 :                 imr->ifm_status = 0;
     866           0 :                 return;
     867             :         }
     868             : 
     869           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     870             :             BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
     871           0 :         sts = sc->sc_sts->ms_linkstate;
     872           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
     873             :             BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
     874             : 
     875           0 :         myx_link_state(sc, sts);
     876             : 
     877           0 :         imr->ifm_status = IFM_AVALID;
     878           0 :         if (!LINK_STATE_IS_UP(ifp->if_link_state))
     879           0 :                 return;
     880             : 
     881           0 :         imr->ifm_active |= IFM_FDX | IFM_FLOW |
     882             :             IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE;
     883           0 :         imr->ifm_status |= IFM_ACTIVE;
     884           0 : }
     885             : 
     886             : void
     887           0 : myx_link_state(struct myx_softc *sc, u_int32_t sts)
     888             : {
     889           0 :         struct ifnet            *ifp = &sc->sc_ac.ac_if;
     890             :         int                      link_state = LINK_STATE_DOWN;
     891             : 
     892           0 :         if (betoh32(sts) == MYXSTS_LINKUP)
     893           0 :                 link_state = LINK_STATE_FULL_DUPLEX;
     894           0 :         if (ifp->if_link_state != link_state) {
     895           0 :                 ifp->if_link_state = link_state;
     896           0 :                 if_link_state_change(ifp);
     897           0 :                 ifp->if_baudrate = LINK_STATE_IS_UP(ifp->if_link_state) ?
     898             :                     IF_Gbps(10) : 0;
     899           0 :         }
     900           0 : }
     901             : 
     902             : void
     903           0 : myx_watchdog(struct ifnet *ifp)
     904             : {
     905           0 :         return;
     906             : }
     907             : 
     908             : int
     909           0 : myx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
     910             : {
     911           0 :         struct myx_softc        *sc = (struct myx_softc *)ifp->if_softc;
     912           0 :         struct ifreq            *ifr = (struct ifreq *)data;
     913             :         int                      s, error = 0;
     914             : 
     915           0 :         s = splnet();
     916             : 
     917           0 :         switch (cmd) {
     918             :         case SIOCSIFADDR:
     919           0 :                 ifp->if_flags |= IFF_UP;
     920             :                 /* FALLTHROUGH */
     921             : 
     922             :         case SIOCSIFFLAGS:
     923           0 :                 if (ISSET(ifp->if_flags, IFF_UP)) {
     924           0 :                         if (ISSET(ifp->if_flags, IFF_RUNNING))
     925           0 :                                 error = ENETRESET;
     926             :                         else
     927           0 :                                 myx_up(sc);
     928             :                 } else {
     929           0 :                         if (ISSET(ifp->if_flags, IFF_RUNNING))
     930           0 :                                 myx_down(sc);
     931             :                 }
     932             :                 break;
     933             : 
     934             :         case SIOCGIFMEDIA:
     935             :         case SIOCSIFMEDIA:
     936           0 :                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
     937           0 :                 break;
     938             : 
     939             :         case SIOCGIFRXR:
     940           0 :                 error = myx_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data);
     941           0 :                 break;
     942             : 
     943             :         default:
     944           0 :                 error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
     945           0 :         }
     946             : 
     947           0 :         if (error == ENETRESET) {
     948           0 :                 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
     949             :                     (IFF_UP | IFF_RUNNING))
     950           0 :                         myx_iff(sc);
     951             :                 error = 0;
     952           0 :         }
     953             : 
     954           0 :         splx(s);
     955           0 :         return (error);
     956             : }
     957             : 
     958             : int
     959           0 : myx_rxrinfo(struct myx_softc *sc, struct if_rxrinfo *ifri)
     960             : {
     961           0 :         struct if_rxring_info ifr[2];
     962             : 
     963           0 :         memset(ifr, 0, sizeof(ifr));
     964             : 
     965           0 :         ifr[0].ifr_size = MYX_RXSMALL_SIZE;
     966           0 :         ifr[0].ifr_info = sc->sc_rx_ring[0].mrr_rxr;
     967             : 
     968           0 :         ifr[1].ifr_size = MYX_RXBIG_SIZE;
     969           0 :         ifr[1].ifr_info = sc->sc_rx_ring[1].mrr_rxr;
     970             : 
     971           0 :         return (if_rxr_info_ioctl(ifri, nitems(ifr), ifr));
     972           0 : }
     973             : 
     974             : void
     975           0 : myx_up(struct myx_softc *sc)
     976             : {
     977           0 :         struct ifnet            *ifp = &sc->sc_ac.ac_if;
     978           0 :         struct myx_cmd          mc;
     979             :         bus_dmamap_t            map;
     980             :         size_t                  size;
     981             :         u_int                   maxpkt;
     982           0 :         u_int32_t               r;
     983             : 
     984           0 :         memset(&mc, 0, sizeof(mc));
     985           0 :         if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
     986           0 :                 printf("%s: failed to reset the device\n", DEVNAME(sc));
     987           0 :                 return;
     988             :         }
     989             : 
     990           0 :         if (myx_dmamem_alloc(sc, &sc->sc_zerodma,
     991           0 :             64, MYXALIGN_CMD) != 0) {
     992           0 :                 printf("%s: failed to allocate zero pad memory\n",
     993           0 :                     DEVNAME(sc));
     994           0 :                 return;
     995             :         }
     996           0 :         memset(sc->sc_zerodma.mxm_kva, 0, 64);
     997           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0,
     998             :             sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_PREREAD);
     999             : 
    1000           0 :         if (myx_dmamem_alloc(sc, &sc->sc_paddma,
    1001           0 :             MYXALIGN_CMD, MYXALIGN_CMD) != 0) {
    1002           0 :                 printf("%s: failed to allocate pad DMA memory\n",
    1003           0 :                     DEVNAME(sc));
    1004           0 :                 goto free_zero;
    1005             :         }
    1006           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_paddma.mxm_map, 0,
    1007             :             sc->sc_paddma.mxm_map->dm_mapsize,
    1008             :             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
    1009             : 
    1010           0 :         if (myx_rdma(sc, MYXRDMA_ON) != 0) {
    1011           0 :                 printf("%s: failed to enable dummy RDMA\n", DEVNAME(sc));
    1012           0 :                 goto free_pad;
    1013             :         }
    1014             : 
    1015           0 :         if (myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc, &r) != 0) {
    1016           0 :                 printf("%s: unable to get rx ring size\n", DEVNAME(sc));
    1017           0 :                 goto free_pad;
    1018             :         }
    1019           0 :         sc->sc_rx_ring_count = r / sizeof(struct myx_rx_desc);
    1020             : 
    1021           0 :         memset(&mc, 0, sizeof(mc));
    1022           0 :         if (myx_cmd(sc, MYXCMD_GET_TXRINGSZ, &mc, &r) != 0) {
    1023           0 :                 printf("%s: unable to get tx ring size\n", DEVNAME(sc));
    1024           0 :                 goto free_pad;
    1025             :         }
    1026           0 :         sc->sc_tx_ring_prod = 0;
    1027           0 :         sc->sc_tx_ring_cons = 0;
    1028           0 :         sc->sc_tx_ring_count = r / sizeof(struct myx_tx_desc);
    1029           0 :         sc->sc_tx_nsegs = min(16, sc->sc_tx_ring_count / 4); /* magic */
    1030           0 :         sc->sc_tx_count = 0;
    1031           0 :         IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_tx_ring_count - 1);
    1032             : 
    1033             :         /* Allocate Interrupt Queue */
    1034             : 
    1035           0 :         sc->sc_intrq_count = sc->sc_rx_ring_count * 2;
    1036           0 :         sc->sc_intrq_idx = 0;
    1037             : 
    1038           0 :         size = sc->sc_intrq_count * sizeof(struct myx_intrq_desc);
    1039           0 :         if (myx_dmamem_alloc(sc, &sc->sc_intrq_dma,
    1040           0 :             size, MYXALIGN_DATA) != 0) {
    1041             :                 goto free_pad;
    1042             :         }
    1043           0 :         sc->sc_intrq = (struct myx_intrq_desc *)sc->sc_intrq_dma.mxm_kva;
    1044           0 :         map = sc->sc_intrq_dma.mxm_map;
    1045           0 :         memset(sc->sc_intrq, 0, size);
    1046           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
    1047             :             BUS_DMASYNC_PREREAD);
    1048             : 
    1049           0 :         memset(&mc, 0, sizeof(mc));
    1050           0 :         mc.mc_data0 = htobe32(size);
    1051           0 :         if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) {
    1052           0 :                 printf("%s: failed to set intrq size\n", DEVNAME(sc));
    1053           0 :                 goto free_intrq;
    1054             :         }
    1055             : 
    1056           0 :         memset(&mc, 0, sizeof(mc));
    1057           0 :         mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
    1058           0 :         mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
    1059           0 :         if (myx_cmd(sc, MYXCMD_SET_INTRQDMA, &mc, NULL) != 0) {
    1060           0 :                 printf("%s: failed to set intrq address\n", DEVNAME(sc));
    1061           0 :                 goto free_intrq;
    1062             :         }
    1063             : 
    1064             :         /*
    1065             :          * get interrupt offsets
    1066             :          */
    1067             : 
    1068           0 :         memset(&mc, 0, sizeof(mc));
    1069           0 :         if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc,
    1070           0 :             &sc->sc_irqclaimoff) != 0) {
    1071           0 :                 printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc));
    1072           0 :                 goto free_intrq;
    1073             :         }
    1074             : 
    1075           0 :         memset(&mc, 0, sizeof(mc));
    1076           0 :         if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc,
    1077           0 :             &sc->sc_irqdeassertoff) != 0) {
    1078           0 :                 printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc));
    1079           0 :                 goto free_intrq;
    1080             :         }
    1081             : 
    1082           0 :         memset(&mc, 0, sizeof(mc));
    1083           0 :         if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc,
    1084           0 :             &sc->sc_irqcoaloff) != 0) {
    1085           0 :                 printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc));
    1086           0 :                 goto free_intrq;
    1087             :         }
    1088             : 
    1089             :         /* Set an appropriate interrupt coalescing period */
    1090           0 :         r = htobe32(MYX_IRQCOALDELAY);
    1091           0 :         myx_write(sc, sc->sc_irqcoaloff, &r, sizeof(r));
    1092             : 
    1093           0 :         if (myx_setlladdr(sc, MYXCMD_SET_LLADDR, LLADDR(ifp->if_sadl)) != 0) {
    1094           0 :                 printf("%s: failed to configure lladdr\n", DEVNAME(sc));
    1095           0 :                 goto free_intrq;
    1096             :         }
    1097             : 
    1098           0 :         memset(&mc, 0, sizeof(mc));
    1099           0 :         if (myx_cmd(sc, MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) {
    1100           0 :                 printf("%s: failed to disable promisc mode\n", DEVNAME(sc));
    1101           0 :                 goto free_intrq;
    1102             :         }
    1103             : 
    1104           0 :         memset(&mc, 0, sizeof(mc));
    1105           0 :         if (myx_cmd(sc, MYXCMD_FC_DEFAULT, &mc, NULL) != 0) {
    1106           0 :                 printf("%s: failed to configure flow control\n", DEVNAME(sc));
    1107           0 :                 goto free_intrq;
    1108             :         }
    1109             : 
    1110           0 :         memset(&mc, 0, sizeof(mc));
    1111           0 :         if (myx_cmd(sc, MYXCMD_GET_TXRINGOFF, &mc,
    1112           0 :             &sc->sc_tx_ring_offset) != 0) {
    1113           0 :                 printf("%s: unable to get tx ring offset\n", DEVNAME(sc));
    1114           0 :                 goto free_intrq;
    1115             :         }
    1116             : 
    1117           0 :         memset(&mc, 0, sizeof(mc));
    1118           0 :         if (myx_cmd(sc, MYXCMD_GET_RXSMALLRINGOFF, &mc,
    1119           0 :             &sc->sc_rx_ring[MYX_RXSMALL].mrr_offset) != 0) {
    1120           0 :                 printf("%s: unable to get small rx ring offset\n", DEVNAME(sc));
    1121           0 :                 goto free_intrq;
    1122             :         }
    1123             : 
    1124           0 :         memset(&mc, 0, sizeof(mc));
    1125           0 :         if (myx_cmd(sc, MYXCMD_GET_RXBIGRINGOFF, &mc,
    1126           0 :             &sc->sc_rx_ring[MYX_RXBIG].mrr_offset) != 0) {
    1127           0 :                 printf("%s: unable to get big rx ring offset\n", DEVNAME(sc));
    1128           0 :                 goto free_intrq;
    1129             :         }
    1130             : 
    1131             :         /* Allocate Interrupt Data */
    1132           0 :         if (myx_dmamem_alloc(sc, &sc->sc_sts_dma,
    1133           0 :             sizeof(struct myx_status), MYXALIGN_DATA) != 0) {
    1134           0 :                 printf("%s: failed to allocate status DMA memory\n",
    1135           0 :                     DEVNAME(sc));
    1136           0 :                 goto free_intrq;
    1137             :         }
    1138           0 :         sc->sc_sts = (struct myx_status *)sc->sc_sts_dma.mxm_kva;
    1139           0 :         map = sc->sc_sts_dma.mxm_map;
    1140           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
    1141             :             BUS_DMASYNC_PREREAD);
    1142             : 
    1143           0 :         memset(&mc, 0, sizeof(mc));
    1144           0 :         mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
    1145           0 :         mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
    1146           0 :         mc.mc_data2 = htobe32(sizeof(struct myx_status));
    1147           0 :         if (myx_cmd(sc, MYXCMD_SET_STATSDMA, &mc, NULL) != 0) {
    1148           0 :                 printf("%s: failed to set status DMA offset\n", DEVNAME(sc));
    1149           0 :                 goto free_sts;
    1150             :         }
    1151             : 
    1152           0 :         maxpkt = ifp->if_hardmtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
    1153             : 
    1154           0 :         memset(&mc, 0, sizeof(mc));
    1155           0 :         mc.mc_data0 = htobe32(maxpkt);
    1156           0 :         if (myx_cmd(sc, MYXCMD_SET_MTU, &mc, NULL) != 0) {
    1157           0 :                 printf("%s: failed to set MTU size %d\n", DEVNAME(sc), maxpkt);
    1158           0 :                 goto free_sts;
    1159             :         }
    1160             : 
    1161           0 :         if (myx_tx_init(sc, maxpkt) != 0)
    1162             :                 goto free_sts;
    1163             : 
    1164           0 :         if (myx_rx_init(sc, MYX_RXSMALL, MCLBYTES) != 0)
    1165             :                 goto free_tx_ring;
    1166             : 
    1167           0 :         if (myx_rx_fill(sc, &sc->sc_rx_ring[MYX_RXSMALL]) != 0)
    1168             :                 goto free_rx_ring_small;
    1169             : 
    1170           0 :         if (myx_rx_init(sc, MYX_RXBIG, MYX_RXBIG_SIZE) != 0)
    1171             :                 goto empty_rx_ring_small;
    1172             : 
    1173           0 :         if (myx_rx_fill(sc, &sc->sc_rx_ring[MYX_RXBIG]) != 0)
    1174             :                 goto free_rx_ring_big;
    1175             : 
    1176           0 :         memset(&mc, 0, sizeof(mc));
    1177           0 :         mc.mc_data0 = htobe32(MYX_RXSMALL_SIZE - ETHER_ALIGN);
    1178           0 :         if (myx_cmd(sc, MYXCMD_SET_SMALLBUFSZ, &mc, NULL) != 0) {
    1179           0 :                 printf("%s: failed to set small buf size\n", DEVNAME(sc));
    1180           0 :                 goto empty_rx_ring_big;
    1181             :         }
    1182             : 
    1183           0 :         memset(&mc, 0, sizeof(mc));
    1184           0 :         mc.mc_data0 = htobe32(16384);
    1185           0 :         if (myx_cmd(sc, MYXCMD_SET_BIGBUFSZ, &mc, NULL) != 0) {
    1186           0 :                 printf("%s: failed to set big buf size\n", DEVNAME(sc));
    1187           0 :                 goto empty_rx_ring_big;
    1188             :         }
    1189             : 
    1190           0 :         sc->sc_state = MYX_S_RUNNING;
    1191             : 
    1192           0 :         if (myx_cmd(sc, MYXCMD_SET_IFUP, &mc, NULL) != 0) {
    1193           0 :                 printf("%s: failed to start the device\n", DEVNAME(sc));
    1194           0 :                 goto empty_rx_ring_big;
    1195             :         }
    1196             : 
    1197           0 :         myx_iff(sc);
    1198           0 :         SET(ifp->if_flags, IFF_RUNNING);
    1199           0 :         ifq_restart(&ifp->if_snd);
    1200             : 
    1201           0 :         return;
    1202             : 
    1203             : empty_rx_ring_big:
    1204           0 :         myx_rx_empty(sc, &sc->sc_rx_ring[MYX_RXBIG]);
    1205             : free_rx_ring_big:
    1206           0 :         myx_rx_free(sc, &sc->sc_rx_ring[MYX_RXBIG]);
    1207             : empty_rx_ring_small:
    1208           0 :         myx_rx_empty(sc, &sc->sc_rx_ring[MYX_RXSMALL]);
    1209             : free_rx_ring_small:
    1210           0 :         myx_rx_free(sc, &sc->sc_rx_ring[MYX_RXSMALL]);
    1211             : free_tx_ring:
    1212           0 :         myx_tx_free(sc);
    1213             : free_sts:
    1214           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_sts_dma.mxm_map, 0,
    1215             :             sc->sc_sts_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1216           0 :         myx_dmamem_free(sc, &sc->sc_sts_dma);
    1217             : free_intrq:
    1218           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0,
    1219             :             sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1220           0 :         myx_dmamem_free(sc, &sc->sc_intrq_dma);
    1221             : free_pad:
    1222           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_paddma.mxm_map, 0,
    1223             :             sc->sc_paddma.mxm_map->dm_mapsize,
    1224             :             BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    1225           0 :         myx_dmamem_free(sc, &sc->sc_paddma);
    1226             : 
    1227           0 :         memset(&mc, 0, sizeof(mc));
    1228           0 :         if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
    1229           0 :                 printf("%s: failed to reset the device\n", DEVNAME(sc));
    1230           0 :         }
    1231             : free_zero:
    1232           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0,
    1233             :             sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1234           0 :         myx_dmamem_free(sc, &sc->sc_zerodma);
    1235           0 : }
    1236             : 
    1237             : int
    1238           0 : myx_setlladdr(struct myx_softc *sc, u_int32_t cmd, u_int8_t *addr)
    1239             : {
    1240           0 :         struct myx_cmd           mc;
    1241             : 
    1242           0 :         memset(&mc, 0, sizeof(mc));
    1243           0 :         mc.mc_data0 = htobe32(addr[0] << 24 | addr[1] << 16 |
    1244             :             addr[2] << 8 | addr[3]);
    1245           0 :         mc.mc_data1 = htobe32(addr[4] << 8 | addr[5]);
    1246             : 
    1247           0 :         if (myx_cmd(sc, cmd, &mc, NULL) != 0) {
    1248           0 :                 printf("%s: failed to set the lladdr\n", DEVNAME(sc));
    1249           0 :                 return (-1);
    1250             :         }
    1251           0 :         return (0);
    1252           0 : }
    1253             : 
    1254             : void
    1255           0 : myx_iff(struct myx_softc *sc)
    1256             : {
    1257           0 :         struct myx_cmd          mc;
    1258           0 :         struct ifnet            *ifp = &sc->sc_ac.ac_if;
    1259             :         struct ether_multi      *enm;
    1260             :         struct ether_multistep  step;
    1261             :         u_int8_t *addr;
    1262             : 
    1263           0 :         CLR(ifp->if_flags, IFF_ALLMULTI);
    1264             : 
    1265           0 :         if (myx_cmd(sc, ISSET(ifp->if_flags, IFF_PROMISC) ?
    1266           0 :             MYXCMD_SET_PROMISC : MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) {
    1267           0 :                 printf("%s: failed to configure promisc mode\n", DEVNAME(sc));
    1268           0 :                 return;
    1269             :         }
    1270             : 
    1271           0 :         if (myx_cmd(sc, MYXCMD_SET_ALLMULTI, &mc, NULL) != 0) {
    1272           0 :                 printf("%s: failed to enable ALLMULTI\n", DEVNAME(sc));
    1273           0 :                 return;
    1274             :         }
    1275             : 
    1276           0 :         if (myx_cmd(sc, MYXCMD_UNSET_MCAST, &mc, NULL) != 0) {
    1277           0 :                 printf("%s: failed to leave all mcast groups \n", DEVNAME(sc));
    1278           0 :                 return;
    1279             :         }
    1280             : 
    1281           0 :         if (ISSET(ifp->if_flags, IFF_PROMISC) ||
    1282           0 :             sc->sc_ac.ac_multirangecnt > 0) {
    1283           0 :                 SET(ifp->if_flags, IFF_ALLMULTI);
    1284           0 :                 return;
    1285             :         }
    1286             : 
    1287           0 :         ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
    1288           0 :         while (enm != NULL) {
    1289           0 :                 addr = enm->enm_addrlo;
    1290             : 
    1291           0 :                 memset(&mc, 0, sizeof(mc));
    1292           0 :                 mc.mc_data0 = htobe32(addr[0] << 24 | addr[1] << 16 |
    1293             :                     addr[2] << 8 | addr[3]);
    1294           0 :                 mc.mc_data1 = htobe32(addr[4] << 24 | addr[5] << 16);
    1295           0 :                 if (myx_cmd(sc, MYXCMD_SET_MCASTGROUP, &mc, NULL) != 0) {
    1296           0 :                         printf("%s: failed to join mcast group\n", DEVNAME(sc));
    1297           0 :                         return;
    1298             :                 }
    1299             : 
    1300           0 :                 ETHER_NEXT_MULTI(step, enm);
    1301             :         }
    1302             : 
    1303           0 :         memset(&mc, 0, sizeof(mc));
    1304           0 :         if (myx_cmd(sc, MYXCMD_UNSET_ALLMULTI, &mc, NULL) != 0) {
    1305           0 :                 printf("%s: failed to disable ALLMULTI\n", DEVNAME(sc));
    1306           0 :                 return;
    1307             :         }
    1308           0 : }
    1309             : 
    1310             : void
    1311           0 : myx_down(struct myx_softc *sc)
    1312             : {
    1313           0 :         struct ifnet            *ifp = &sc->sc_ac.ac_if;
    1314           0 :         volatile struct myx_status *sts = sc->sc_sts;
    1315           0 :         bus_dmamap_t             map = sc->sc_sts_dma.mxm_map;
    1316           0 :         struct sleep_state       sls;
    1317           0 :         struct myx_cmd           mc;
    1318             :         int                      s;
    1319             :         int                      ring;
    1320             : 
    1321           0 :         CLR(ifp->if_flags, IFF_RUNNING);
    1322             : 
    1323           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
    1324             :             BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
    1325           0 :         sc->sc_linkdown = sts->ms_linkdown;
    1326           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
    1327             :             BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
    1328             : 
    1329           0 :         sc->sc_state = MYX_S_DOWN;
    1330           0 :         membar_producer();
    1331             : 
    1332           0 :         memset(&mc, 0, sizeof(mc));
    1333           0 :         (void)myx_cmd(sc, MYXCMD_SET_IFDOWN, &mc, NULL);
    1334             : 
    1335           0 :         while (sc->sc_state != MYX_S_OFF) {
    1336           0 :                 sleep_setup(&sls, sts, PWAIT, "myxdown");
    1337           0 :                 membar_consumer();
    1338           0 :                 sleep_finish(&sls, sc->sc_state != MYX_S_OFF);
    1339             :         }
    1340             : 
    1341           0 :         s = splnet();
    1342           0 :         if (ifp->if_link_state != LINK_STATE_UNKNOWN) {
    1343           0 :                 ifp->if_link_state = LINK_STATE_UNKNOWN;
    1344           0 :                 ifp->if_baudrate = 0;
    1345           0 :                 if_link_state_change(ifp);
    1346           0 :         }
    1347           0 :         splx(s);
    1348             : 
    1349           0 :         memset(&mc, 0, sizeof(mc));
    1350           0 :         if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
    1351           0 :                 printf("%s: failed to reset the device\n", DEVNAME(sc));
    1352           0 :         }
    1353             : 
    1354           0 :         ifq_clr_oactive(&ifp->if_snd);
    1355           0 :         ifq_barrier(&ifp->if_snd);
    1356             : 
    1357           0 :         for (ring = 0; ring < 2; ring++) {
    1358           0 :                 struct myx_rx_ring *mrr = &sc->sc_rx_ring[ring];
    1359             : 
    1360           0 :                 timeout_del(&mrr->mrr_refill);
    1361           0 :                 myx_rx_empty(sc, mrr);
    1362           0 :                 myx_rx_free(sc, mrr);
    1363             :         }
    1364             : 
    1365           0 :         myx_tx_empty(sc);
    1366           0 :         myx_tx_free(sc);
    1367             : 
    1368             :         /* the sleep shizz above already synced this dmamem */
    1369           0 :         myx_dmamem_free(sc, &sc->sc_sts_dma);
    1370             : 
    1371           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0,
    1372             :             sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1373           0 :         myx_dmamem_free(sc, &sc->sc_intrq_dma);
    1374             : 
    1375           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_paddma.mxm_map, 0,
    1376             :             sc->sc_paddma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1377           0 :         myx_dmamem_free(sc, &sc->sc_paddma);
    1378             : 
    1379           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0,
    1380             :             sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1381           0 :         myx_dmamem_free(sc, &sc->sc_zerodma);
    1382           0 : }
    1383             : 
    1384             : void
    1385           0 : myx_write_txd_tail(struct myx_softc *sc, struct myx_slot *ms, u_int8_t flags,
    1386             :     u_int32_t offset, u_int idx)
    1387             : {
    1388           0 :         struct myx_tx_desc              txd;
    1389           0 :         bus_dmamap_t                    zmap = sc->sc_zerodma.mxm_map;
    1390           0 :         bus_dmamap_t                    map = ms->ms_map;
    1391             :         int                             i;
    1392             : 
    1393           0 :         for (i = 1; i < map->dm_nsegs; i++) {
    1394           0 :                 memset(&txd, 0, sizeof(txd));
    1395           0 :                 txd.tx_addr = htobe64(map->dm_segs[i].ds_addr);
    1396           0 :                 txd.tx_length = htobe16(map->dm_segs[i].ds_len);
    1397           0 :                 txd.tx_flags = flags;
    1398             : 
    1399           0 :                 myx_bus_space_write(sc,
    1400             :                     offset + sizeof(txd) * ((idx + i) % sc->sc_tx_ring_count),
    1401             :                     &txd, sizeof(txd));
    1402             :         }
    1403             : 
    1404             :         /* pad runt frames */
    1405           0 :         if (map->dm_mapsize < 60) {
    1406           0 :                 memset(&txd, 0, sizeof(txd));
    1407           0 :                 txd.tx_addr = htobe64(zmap->dm_segs[0].ds_addr);
    1408           0 :                 txd.tx_length = htobe16(60 - map->dm_mapsize);
    1409           0 :                 txd.tx_flags = flags;
    1410             : 
    1411           0 :                 myx_bus_space_write(sc,
    1412             :                     offset + sizeof(txd) * ((idx + i) % sc->sc_tx_ring_count),
    1413             :                     &txd, sizeof(txd));
    1414           0 :         }
    1415           0 : }
    1416             : 
    1417             : void
    1418           0 : myx_start(struct ifqueue *ifq)
    1419             : {
    1420           0 :         struct ifnet                    *ifp = ifq->ifq_if;
    1421           0 :         struct myx_tx_desc              txd;
    1422           0 :         struct myx_softc                *sc = ifp->if_softc;
    1423             :         struct myx_slot                 *ms;
    1424             :         bus_dmamap_t                    map;
    1425             :         struct mbuf                     *m;
    1426           0 :         u_int32_t                       offset = sc->sc_tx_ring_offset;
    1427             :         u_int                           idx, cons, prod;
    1428             :         u_int                           free, used;
    1429             :         u_int8_t                        flags;
    1430             : 
    1431           0 :         idx = sc->sc_tx_ring_prod;
    1432             : 
    1433             :         /* figure out space */
    1434           0 :         free = sc->sc_tx_ring_cons;
    1435           0 :         if (free <= idx)
    1436           0 :                 free += sc->sc_tx_ring_count;
    1437           0 :         free -= idx;
    1438             : 
    1439           0 :         cons = prod = sc->sc_tx_prod;
    1440             : 
    1441             :         used = 0;
    1442             : 
    1443           0 :         for (;;) {
    1444           0 :                 if (used + sc->sc_tx_nsegs + 1 > free) {
    1445           0 :                         ifq_set_oactive(ifq);
    1446           0 :                         break;
    1447             :                 }
    1448             : 
    1449           0 :                 m = ifq_dequeue(ifq);
    1450           0 :                 if (m == NULL)
    1451             :                         break;
    1452             : 
    1453           0 :                 ms = &sc->sc_tx_slots[prod];
    1454             : 
    1455           0 :                 if (myx_load_mbuf(sc, ms, m) != 0) {
    1456           0 :                         m_freem(m);
    1457           0 :                         ifp->if_oerrors++;
    1458           0 :                         continue;
    1459             :                 }
    1460             : 
    1461             : #if NBPFILTER > 0
    1462           0 :                 if (ifp->if_bpf)
    1463           0 :                         bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
    1464             : #endif
    1465             : 
    1466           0 :                 map = ms->ms_map;
    1467           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0,
    1468             :                     map->dm_mapsize, BUS_DMASYNC_PREWRITE);
    1469             : 
    1470           0 :                 used += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0);
    1471             : 
    1472           0 :                 if (++prod >= sc->sc_tx_ring_count)
    1473             :                         prod = 0;
    1474             :         }
    1475             : 
    1476           0 :         if (cons == prod)
    1477           0 :                 return;
    1478             : 
    1479           0 :         ms = &sc->sc_tx_slots[cons];
    1480             : 
    1481           0 :         for (;;) {
    1482           0 :                 idx += ms->ms_map->dm_nsegs +
    1483           0 :                     (ms->ms_map->dm_mapsize < 60 ? 1 : 0);
    1484           0 :                 if (idx >= sc->sc_tx_ring_count)
    1485           0 :                         idx -= sc->sc_tx_ring_count;
    1486             : 
    1487           0 :                 if (++cons >= sc->sc_tx_ring_count)
    1488             :                         cons = 0;
    1489             : 
    1490           0 :                 if (cons == prod)
    1491             :                         break;
    1492             : 
    1493           0 :                 ms = &sc->sc_tx_slots[cons];
    1494           0 :                 map = ms->ms_map;
    1495             : 
    1496             :                 flags = MYXTXD_FLAGS_NO_TSO;
    1497           0 :                 if (map->dm_mapsize < 1520)
    1498           0 :                         flags |= MYXTXD_FLAGS_SMALL;
    1499             : 
    1500           0 :                 memset(&txd, 0, sizeof(txd));
    1501           0 :                 txd.tx_addr = htobe64(map->dm_segs[0].ds_addr);
    1502           0 :                 txd.tx_length = htobe16(map->dm_segs[0].ds_len);
    1503           0 :                 txd.tx_nsegs = map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0);
    1504           0 :                 txd.tx_flags = flags | MYXTXD_FLAGS_FIRST;
    1505           0 :                 myx_bus_space_write(sc,
    1506             :                     offset + sizeof(txd) * idx, &txd, sizeof(txd));
    1507             : 
    1508           0 :                 myx_write_txd_tail(sc, ms, flags, offset, idx);
    1509             :         }
    1510             : 
    1511             :         /* go back and post first packet */
    1512           0 :         ms = &sc->sc_tx_slots[sc->sc_tx_prod];
    1513           0 :         map = ms->ms_map;
    1514             : 
    1515             :         flags = MYXTXD_FLAGS_NO_TSO;
    1516           0 :         if (map->dm_mapsize < 1520)
    1517           0 :                 flags |= MYXTXD_FLAGS_SMALL;
    1518             : 
    1519           0 :         memset(&txd, 0, sizeof(txd));
    1520           0 :         txd.tx_addr = htobe64(map->dm_segs[0].ds_addr);
    1521           0 :         txd.tx_length = htobe16(map->dm_segs[0].ds_len);
    1522           0 :         txd.tx_nsegs = map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0);
    1523           0 :         txd.tx_flags = flags | MYXTXD_FLAGS_FIRST;
    1524             : 
    1525             :         /* make sure the first descriptor is seen after the others */
    1526           0 :         myx_write_txd_tail(sc, ms, flags, offset, sc->sc_tx_ring_prod);
    1527             : 
    1528           0 :         myx_bus_space_write(sc,
    1529             :             offset + sizeof(txd) * sc->sc_tx_ring_prod, &txd,
    1530             :             sizeof(txd) - sizeof(myx_bus_t));
    1531             : 
    1532           0 :         bus_space_barrier(sc->sc_memt, sc->sc_memh, offset,
    1533           0 :             sizeof(txd) * sc->sc_tx_ring_count, BUS_SPACE_BARRIER_WRITE);
    1534             : 
    1535           0 :         myx_bus_space_write(sc,
    1536             :             offset + sizeof(txd) * (sc->sc_tx_ring_prod + 1) -
    1537             :             sizeof(myx_bus_t),
    1538             :             (u_int8_t *)&txd + sizeof(txd) - sizeof(myx_bus_t),
    1539             :             sizeof(myx_bus_t));
    1540             : 
    1541           0 :         bus_space_barrier(sc->sc_memt, sc->sc_memh,
    1542           0 :             offset + sizeof(txd) * sc->sc_tx_ring_prod, sizeof(txd),
    1543             :             BUS_SPACE_BARRIER_WRITE);
    1544             : 
    1545             :         /* commit */
    1546           0 :         sc->sc_tx_ring_prod = idx;
    1547           0 :         sc->sc_tx_prod = prod;
    1548           0 : }
    1549             : 
    1550             : int
    1551           0 : myx_load_mbuf(struct myx_softc *sc, struct myx_slot *ms, struct mbuf *m)
    1552             : {
    1553           0 :         bus_dma_tag_t                   dmat = sc->sc_dmat;
    1554           0 :         bus_dmamap_t                    dmap = ms->ms_map;
    1555             : 
    1556           0 :         switch (bus_dmamap_load_mbuf(dmat, dmap, m,
    1557             :             BUS_DMA_STREAMING | BUS_DMA_NOWAIT)) {
    1558             :         case 0:
    1559             :                 break;
    1560             : 
    1561             :         case EFBIG: /* mbuf chain is too fragmented */
    1562           0 :                 if (m_defrag(m, M_DONTWAIT) == 0 &&
    1563           0 :                     bus_dmamap_load_mbuf(dmat, dmap, m,
    1564           0 :                     BUS_DMA_STREAMING | BUS_DMA_NOWAIT) == 0)
    1565             :                         break;
    1566             :         default:
    1567           0 :                 return (1);
    1568             :         }
    1569             : 
    1570           0 :         ms->ms_m = m;
    1571           0 :         return (0);
    1572           0 : }
    1573             : 
    1574             : int
    1575           0 : myx_intr(void *arg)
    1576             : {
    1577           0 :         struct myx_softc        *sc = (struct myx_softc *)arg;
    1578           0 :         volatile struct myx_status *sts = sc->sc_sts;
    1579             :         enum myx_state           state;
    1580           0 :         bus_dmamap_t             map = sc->sc_sts_dma.mxm_map;
    1581           0 :         u_int32_t                data;
    1582             :         u_int8_t                 valid = 0;
    1583             : 
    1584           0 :         state = sc->sc_state;
    1585           0 :         if (state == MYX_S_OFF)
    1586           0 :                 return (0);
    1587             : 
    1588           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
    1589             :             BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
    1590             : 
    1591           0 :         valid = sts->ms_isvalid;
    1592           0 :         if (valid == 0x0) {
    1593           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
    1594             :                     BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
    1595           0 :                 return (0);
    1596             :         }
    1597             : 
    1598           0 :         if (sc->sc_intx) {
    1599           0 :                 data = htobe32(0);
    1600           0 :                 bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh,
    1601             :                     sc->sc_irqdeassertoff, &data, sizeof(data));
    1602           0 :         }
    1603           0 :         sts->ms_isvalid = 0;
    1604             : 
    1605           0 :         do {
    1606           0 :                 data = sts->ms_txdonecnt;
    1607             : 
    1608           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
    1609             :                     BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE |
    1610             :                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
    1611           0 :         } while (sts->ms_isvalid);
    1612             : 
    1613           0 :         data = betoh32(data);
    1614           0 :         if (data != sc->sc_tx_count)
    1615           0 :                 myx_txeof(sc, data);
    1616             : 
    1617           0 :         data = htobe32(3);
    1618           0 :         if (valid & 0x1) {
    1619           0 :                 myx_rxeof(sc);
    1620             : 
    1621           0 :                 bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh,
    1622             :                     sc->sc_irqclaimoff, &data, sizeof(data));
    1623           0 :         }
    1624           0 :         bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh,
    1625             :             sc->sc_irqclaimoff + sizeof(data), &data, sizeof(data));
    1626             : 
    1627           0 :         if (sts->ms_statusupdated) {
    1628           0 :                 if (state == MYX_S_DOWN &&
    1629           0 :                     sc->sc_linkdown != sts->ms_linkdown) {
    1630           0 :                         sc->sc_state = MYX_S_OFF;
    1631           0 :                         membar_producer();
    1632           0 :                         wakeup(sts);
    1633           0 :                 } else {
    1634           0 :                         data = sts->ms_linkstate;
    1635           0 :                         if (data != 0xffffffff) {
    1636           0 :                                 KERNEL_LOCK();
    1637           0 :                                 myx_link_state(sc, data);
    1638           0 :                                 KERNEL_UNLOCK();
    1639           0 :                         }
    1640             :                 }
    1641             :         }
    1642             : 
    1643           0 :         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
    1644             :             BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
    1645             : 
    1646           0 :         return (1);
    1647           0 : }
    1648             : 
    1649             : void
    1650           0 : myx_refill(void *xmrr)
    1651             : {
    1652           0 :         struct myx_rx_ring *mrr = xmrr;
    1653           0 :         struct myx_softc *sc = mrr->mrr_softc;
    1654             : 
    1655           0 :         myx_rx_fill(sc, mrr);
    1656             : 
    1657           0 :         if (mrr->mrr_prod == mrr->mrr_cons)
    1658           0 :                 timeout_add(&mrr->mrr_refill, 1);
    1659           0 : }
    1660             : 
    1661             : void
    1662           0 : myx_txeof(struct myx_softc *sc, u_int32_t done_count)
    1663             : {
    1664           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
    1665             :         struct myx_slot *ms;
    1666             :         bus_dmamap_t map;
    1667             :         u_int idx, cons;
    1668             : 
    1669           0 :         idx = sc->sc_tx_ring_cons;
    1670           0 :         cons = sc->sc_tx_cons;
    1671             : 
    1672           0 :         do {
    1673           0 :                 ms = &sc->sc_tx_slots[cons];
    1674           0 :                 map = ms->ms_map;
    1675             : 
    1676           0 :                 idx += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0);
    1677             : 
    1678           0 :                 bus_dmamap_sync(sc->sc_dmat, map, 0,
    1679             :                     map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
    1680           0 :                 bus_dmamap_unload(sc->sc_dmat, map);
    1681           0 :                 m_freem(ms->ms_m);
    1682             : 
    1683           0 :                 if (++cons >= sc->sc_tx_ring_count)
    1684             :                         cons = 0;
    1685           0 :         } while (++sc->sc_tx_count != done_count);
    1686             : 
    1687           0 :         if (idx >= sc->sc_tx_ring_count)
    1688           0 :                 idx -= sc->sc_tx_ring_count;
    1689             : 
    1690           0 :         sc->sc_tx_ring_cons = idx;
    1691           0 :         sc->sc_tx_cons = cons;
    1692             : 
    1693           0 :         if (ifq_is_oactive(&ifp->if_snd))
    1694           0 :                 ifq_restart(&ifp->if_snd);
    1695           0 : }
    1696             : 
    1697             : void
    1698           0 : myx_rxeof(struct myx_softc *sc)
    1699             : {
    1700             :         static const struct myx_intrq_desc zerodesc = { 0, 0 };
    1701           0 :         struct ifnet *ifp = &sc->sc_ac.ac_if;
    1702           0 :         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
    1703             :         struct myx_rx_ring *mrr;
    1704             :         struct myx_slot *ms;
    1705             :         struct mbuf *m;
    1706             :         int ring;
    1707           0 :         u_int rxfree[2] = { 0 , 0 };
    1708             :         u_int len;
    1709             : 
    1710           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0,
    1711             :             sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1712             : 
    1713           0 :         while ((len = betoh16(sc->sc_intrq[sc->sc_intrq_idx].iq_length)) != 0) {
    1714           0 :                 sc->sc_intrq[sc->sc_intrq_idx] = zerodesc;
    1715             : 
    1716           0 :                 if (++sc->sc_intrq_idx >= sc->sc_intrq_count)
    1717           0 :                         sc->sc_intrq_idx = 0;
    1718             : 
    1719           0 :                 ring = (len <= (MYX_RXSMALL_SIZE - ETHER_ALIGN)) ?
    1720             :                     MYX_RXSMALL : MYX_RXBIG;
    1721             : 
    1722           0 :                 mrr = &sc->sc_rx_ring[ring];
    1723           0 :                 ms = &mrr->mrr_slots[mrr->mrr_cons];
    1724             : 
    1725           0 :                 if (++mrr->mrr_cons >= sc->sc_rx_ring_count)
    1726           0 :                         mrr->mrr_cons = 0;
    1727             : 
    1728           0 :                 bus_dmamap_sync(sc->sc_dmat, ms->ms_map, 0,
    1729             :                     ms->ms_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1730           0 :                 bus_dmamap_unload(sc->sc_dmat, ms->ms_map);
    1731             : 
    1732           0 :                 m = ms->ms_m;
    1733           0 :                 m->m_data += ETHER_ALIGN;
    1734           0 :                 m->m_pkthdr.len = m->m_len = len;
    1735             : 
    1736           0 :                 ml_enqueue(&ml, m);
    1737             : 
    1738           0 :                 rxfree[ring]++;
    1739             :         }
    1740             : 
    1741           0 :         bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0,
    1742             :             sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_PREREAD);
    1743             : 
    1744           0 :         for (ring = MYX_RXSMALL; ring <= MYX_RXBIG; ring++) {
    1745           0 :                 if (rxfree[ring] == 0)
    1746             :                         continue;
    1747             : 
    1748           0 :                 mrr = &sc->sc_rx_ring[ring];
    1749             : 
    1750           0 :                 if_rxr_put(&mrr->mrr_rxr, rxfree[ring]);
    1751           0 :                 myx_rx_fill(sc, mrr);
    1752           0 :                 if (mrr->mrr_prod == mrr->mrr_cons)
    1753           0 :                         timeout_add(&mrr->mrr_refill, 0);
    1754             :         }
    1755             : 
    1756           0 :         if_input(ifp, &ml);
    1757           0 : }
    1758             : 
    1759             : static int
    1760           0 : myx_rx_fill_slots(struct myx_softc *sc, struct myx_rx_ring *mrr, u_int slots)
    1761             : {
    1762           0 :         struct myx_rx_desc rxd;
    1763             :         struct myx_slot *ms;
    1764           0 :         u_int32_t offset = mrr->mrr_offset;
    1765             :         u_int p, first, fills;
    1766             : 
    1767           0 :         first = p = mrr->mrr_prod;
    1768           0 :         if (myx_buf_fill(sc, &mrr->mrr_slots[first], mrr->mrr_mclget) != 0)
    1769           0 :                 return (slots);
    1770             : 
    1771           0 :         if (++p >= sc->sc_rx_ring_count)
    1772             :                 p = 0;
    1773             : 
    1774           0 :         for (fills = 1; fills < slots; fills++) {
    1775           0 :                 ms = &mrr->mrr_slots[p];
    1776             : 
    1777           0 :                 if (myx_buf_fill(sc, ms, mrr->mrr_mclget) != 0)
    1778             :                         break;
    1779             : 
    1780           0 :                 rxd.rx_addr = htobe64(ms->ms_map->dm_segs[0].ds_addr);
    1781           0 :                 myx_bus_space_write(sc, offset + p * sizeof(rxd),
    1782             :                     &rxd, sizeof(rxd));
    1783             : 
    1784           0 :                 if (++p >= sc->sc_rx_ring_count)
    1785             :                         p = 0;
    1786             :         }
    1787             : 
    1788           0 :         mrr->mrr_prod = p;
    1789             : 
    1790             :         /* make sure the first descriptor is seen after the others */
    1791           0 :         if (fills > 1) {
    1792           0 :                 bus_space_barrier(sc->sc_memt, sc->sc_memh,
    1793           0 :                     offset, sizeof(rxd) * sc->sc_rx_ring_count,
    1794             :                     BUS_SPACE_BARRIER_WRITE);
    1795           0 :         }
    1796             : 
    1797           0 :         ms = &mrr->mrr_slots[first];
    1798           0 :         rxd.rx_addr = htobe64(ms->ms_map->dm_segs[0].ds_addr);
    1799           0 :         myx_bus_space_write(sc, offset + first * sizeof(rxd),
    1800             :             &rxd, sizeof(rxd));
    1801             : 
    1802           0 :         return (slots - fills);
    1803           0 : }
    1804             : 
    1805             : int
    1806           0 : myx_rx_init(struct myx_softc *sc, int ring, bus_size_t size)
    1807             : {
    1808           0 :         struct myx_rx_desc rxd;
    1809           0 :         struct myx_rx_ring *mrr = &sc->sc_rx_ring[ring];
    1810             :         struct myx_slot *ms;
    1811           0 :         u_int32_t offset = mrr->mrr_offset;
    1812             :         int rv;
    1813             :         int i;
    1814             : 
    1815           0 :         mrr->mrr_slots = mallocarray(sizeof(*ms), sc->sc_rx_ring_count,
    1816             :             M_DEVBUF, M_WAITOK);
    1817           0 :         if (mrr->mrr_slots == NULL)
    1818           0 :                 return (ENOMEM);
    1819             : 
    1820           0 :         memset(&rxd, 0xff, sizeof(rxd));
    1821           0 :         for (i = 0; i < sc->sc_rx_ring_count; i++) {
    1822           0 :                 ms = &mrr->mrr_slots[i];
    1823           0 :                 rv = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
    1824             :                     BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &ms->ms_map);
    1825           0 :                 if (rv != 0)
    1826             :                         goto destroy;
    1827             : 
    1828           0 :                 myx_bus_space_write(sc, offset + i * sizeof(rxd),
    1829             :                     &rxd, sizeof(rxd));
    1830             :         }
    1831             : 
    1832           0 :         if_rxr_init(&mrr->mrr_rxr, 2, sc->sc_rx_ring_count - 2);
    1833           0 :         mrr->mrr_prod = mrr->mrr_cons = 0;
    1834             : 
    1835           0 :         return (0);
    1836             : 
    1837             : destroy:
    1838           0 :         while (i-- > 0) {
    1839           0 :                 ms = &mrr->mrr_slots[i];
    1840           0 :                 bus_dmamap_destroy(sc->sc_dmat, ms->ms_map);
    1841             :         }
    1842           0 :         free(mrr->mrr_slots, M_DEVBUF, sizeof(*ms) * sc->sc_rx_ring_count);
    1843           0 :         return (rv);
    1844           0 : }
    1845             : 
    1846             : int
    1847           0 : myx_rx_fill(struct myx_softc *sc, struct myx_rx_ring *mrr)
    1848             : {
    1849             :         u_int slots;
    1850             : 
    1851           0 :         slots = if_rxr_get(&mrr->mrr_rxr, sc->sc_rx_ring_count);
    1852           0 :         if (slots == 0)
    1853           0 :                 return (1);
    1854             : 
    1855           0 :         slots = myx_rx_fill_slots(sc, mrr, slots);
    1856           0 :         if (slots > 0)
    1857           0 :                 if_rxr_put(&mrr->mrr_rxr, slots);
    1858             : 
    1859           0 :         return (0);
    1860           0 : }
    1861             : 
    1862             : void
    1863           0 : myx_rx_empty(struct myx_softc *sc, struct myx_rx_ring *mrr)
    1864             : {
    1865             :         struct myx_slot *ms;
    1866             : 
    1867           0 :         while (mrr->mrr_cons != mrr->mrr_prod) {
    1868           0 :                 ms = &mrr->mrr_slots[mrr->mrr_cons];
    1869             : 
    1870           0 :                 if (++mrr->mrr_cons >= sc->sc_rx_ring_count)
    1871           0 :                         mrr->mrr_cons = 0;
    1872             : 
    1873           0 :                 bus_dmamap_sync(sc->sc_dmat, ms->ms_map, 0,
    1874             :                     ms->ms_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
    1875           0 :                 bus_dmamap_unload(sc->sc_dmat, ms->ms_map);
    1876           0 :                 m_freem(ms->ms_m);
    1877             :         }
    1878             : 
    1879           0 :         if_rxr_init(&mrr->mrr_rxr, 2, sc->sc_rx_ring_count - 2);
    1880           0 : }
    1881             : 
    1882             : void
    1883           0 : myx_rx_free(struct myx_softc *sc, struct myx_rx_ring *mrr)
    1884             : {
    1885             :         struct myx_slot *ms;
    1886             :         int i;
    1887             : 
    1888           0 :         for (i = 0; i < sc->sc_rx_ring_count; i++) {
    1889           0 :                 ms = &mrr->mrr_slots[i];
    1890           0 :                 bus_dmamap_destroy(sc->sc_dmat, ms->ms_map);
    1891             :         }
    1892             : 
    1893           0 :         free(mrr->mrr_slots, M_DEVBUF, sizeof(*ms) * sc->sc_rx_ring_count);
    1894           0 : }
    1895             : 
    1896             : struct mbuf *
    1897           0 : myx_mcl_small(void)
    1898             : {
    1899             :         struct mbuf *m;
    1900             : 
    1901           0 :         m = MCLGETI(NULL, M_DONTWAIT, NULL, MYX_RXSMALL_SIZE);
    1902           0 :         if (m == NULL)
    1903           0 :                 return (NULL);
    1904             : 
    1905           0 :         m->m_len = m->m_pkthdr.len = MYX_RXSMALL_SIZE;
    1906             : 
    1907           0 :         return (m);
    1908           0 : }
    1909             : 
    1910             : struct mbuf *
    1911           0 : myx_mcl_big(void)
    1912             : {
    1913             :         struct mbuf *m;
    1914             :         void *mcl;
    1915             : 
    1916           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
    1917           0 :         if (m == NULL)
    1918           0 :                 return (NULL);
    1919             : 
    1920           0 :         mcl = pool_get(myx_mcl_pool, PR_NOWAIT);
    1921           0 :         if (mcl == NULL) {
    1922           0 :                 m_free(m);
    1923           0 :                 return (NULL);
    1924             :         }
    1925             : 
    1926           0 :         MEXTADD(m, mcl, MYX_RXBIG_SIZE, M_EXTWR, MEXTFREE_POOL, myx_mcl_pool);
    1927           0 :         m->m_len = m->m_pkthdr.len = MYX_RXBIG_SIZE;
    1928             : 
    1929           0 :         return (m);
    1930           0 : }
    1931             : 
    1932             : int
    1933           0 : myx_buf_fill(struct myx_softc *sc, struct myx_slot *ms,
    1934             :     struct mbuf *(*mclget)(void))
    1935             : {
    1936             :         struct mbuf *m;
    1937             :         int rv;
    1938             : 
    1939           0 :         m = (*mclget)();
    1940           0 :         if (m == NULL)
    1941           0 :                 return (ENOMEM);
    1942             : 
    1943           0 :         rv = bus_dmamap_load_mbuf(sc->sc_dmat, ms->ms_map, m, BUS_DMA_NOWAIT);
    1944           0 :         if (rv != 0) {
    1945           0 :                 m_freem(m);
    1946           0 :                 return (rv);
    1947             :         }
    1948             : 
    1949           0 :         bus_dmamap_sync(sc->sc_dmat, ms->ms_map, 0,
    1950             :             ms->ms_map->dm_mapsize, BUS_DMASYNC_PREREAD);
    1951             : 
    1952           0 :         ms->ms_m = m;
    1953             : 
    1954           0 :         return (0);
    1955           0 : }
    1956             : 
    1957             : int
    1958           0 : myx_tx_init(struct myx_softc *sc, bus_size_t size)
    1959             : {
    1960             :         struct myx_slot *ms;
    1961             :         int rv;
    1962             :         int i;
    1963             : 
    1964           0 :         sc->sc_tx_slots = mallocarray(sizeof(*ms), sc->sc_tx_ring_count,
    1965             :             M_DEVBUF, M_WAITOK);
    1966           0 :         if (sc->sc_tx_slots == NULL)
    1967           0 :                 return (ENOMEM);
    1968             : 
    1969           0 :         for (i = 0; i < sc->sc_tx_ring_count; i++) {
    1970           0 :                 ms = &sc->sc_tx_slots[i];
    1971           0 :                 rv = bus_dmamap_create(sc->sc_dmat, size, sc->sc_tx_nsegs,
    1972             :                     sc->sc_tx_boundary, sc->sc_tx_boundary,
    1973             :                     BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, &ms->ms_map);
    1974           0 :                 if (rv != 0)
    1975             :                         goto destroy;
    1976             :         }
    1977             : 
    1978           0 :         sc->sc_tx_prod = sc->sc_tx_cons = 0;
    1979             : 
    1980           0 :         return (0);
    1981             : 
    1982             : destroy:
    1983           0 :         while (i-- > 0) {
    1984           0 :                 ms = &sc->sc_tx_slots[i];
    1985           0 :                 bus_dmamap_destroy(sc->sc_dmat, ms->ms_map);
    1986             :         }
    1987           0 :         free(sc->sc_tx_slots, M_DEVBUF, sizeof(*ms) * sc->sc_tx_ring_count);
    1988           0 :         return (rv);
    1989           0 : }
    1990             : 
    1991             : void
    1992           0 : myx_tx_empty(struct myx_softc *sc)
    1993             : {
    1994             :         struct myx_slot *ms;
    1995           0 :         u_int cons = sc->sc_tx_cons;
    1996           0 :         u_int prod = sc->sc_tx_prod;
    1997             : 
    1998           0 :         while (cons != prod) {
    1999           0 :                 ms = &sc->sc_tx_slots[cons];
    2000             :                 
    2001           0 :                 bus_dmamap_sync(sc->sc_dmat, ms->ms_map, 0,
    2002             :                     ms->ms_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
    2003           0 :                 bus_dmamap_unload(sc->sc_dmat, ms->ms_map);
    2004           0 :                 m_freem(ms->ms_m);
    2005             : 
    2006           0 :                 if (++cons >= sc->sc_tx_ring_count)
    2007             :                         cons = 0;
    2008             :         }
    2009             : 
    2010           0 :         sc->sc_tx_cons = cons;
    2011           0 : }
    2012             : 
    2013             : void
    2014           0 : myx_tx_free(struct myx_softc *sc)
    2015             : {
    2016             :         struct myx_slot *ms;
    2017             :         int i;
    2018             : 
    2019           0 :         for (i = 0; i < sc->sc_tx_ring_count; i++) {
    2020           0 :                 ms = &sc->sc_tx_slots[i];
    2021           0 :                 bus_dmamap_destroy(sc->sc_dmat, ms->ms_map);
    2022             :         }
    2023             : 
    2024           0 :         free(sc->sc_tx_slots, M_DEVBUF, sizeof(*ms) * sc->sc_tx_ring_count);
    2025           0 : }

Generated by: LCOV version 1.13