if_myx.c revision 1.5
180708Sjake/* $OpenBSD: if_myx.c,v 1.5 2007/06/01 18:07:08 reyk Exp $ */ 286228Stmm 380708Sjake/* 480708Sjake * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org> 586228Stmm * 686228Stmm * Permission to use, copy, modify, and distribute this software for any 786228Stmm * purpose with or without fee is hereby granted, provided that the above 886228Stmm * copyright notice and this permission notice appear in all copies. 980708Sjake * 1080708Sjake * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1180708Sjake * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1280708Sjake * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1380708Sjake * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1480708Sjake * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1580708Sjake * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1680708Sjake * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1780708Sjake */ 1886228Stmm 1986228Stmm/* 2086228Stmm * Driver for the Myricom Myri-10G Lanai-Z8E Ethernet chipsets. 2186228Stmm */ 2286228Stmm 2386228Stmm#include "bpfilter.h" 2486228Stmm 2586228Stmm#include <sys/param.h> 2686228Stmm#include <sys/systm.h> 2786228Stmm#include <sys/sockio.h> 2886228Stmm#include <sys/mbuf.h> 2986228Stmm#include <sys/kernel.h> 3086228Stmm#include <sys/socket.h> 3186228Stmm#include <sys/malloc.h> 3286228Stmm#include <sys/timeout.h> 3386228Stmm#include <sys/proc.h> 3480708Sjake#include <sys/device.h> 3586228Stmm#include <sys/sensors.h> 3686228Stmm 3786228Stmm#include <machine/bus.h> 3886228Stmm#include <machine/intr.h> 3986228Stmm 4086228Stmm#include <net/if.h> 4186228Stmm#include <net/if_dl.h> 4286228Stmm#include <net/if_media.h> 4386228Stmm#include <net/if_types.h> 4486228Stmm 4586228Stmm#if NBPFILTER > 0 4686228Stmm#include <net/bpf.h> 4786228Stmm#endif 4886228Stmm 4986228Stmm#ifdef INET 5086228Stmm#include <netinet/in.h> 5186228Stmm#include <netinet/if_ether.h> 5286228Stmm#endif 5386228Stmm 5486228Stmm#include <dev/pci/pcireg.h> 5586228Stmm#include <dev/pci/pcivar.h> 5686228Stmm#include <dev/pci/pcidevs.h> 5786228Stmm 5886228Stmm#include <dev/pci/if_myxreg.h> 5986228Stmm 6086228Stmm#define MYX_DEBUG 61219567Smarius#ifdef MYX_DEBUG 6286228Stmm#define MYXDBG_INIT (1<<0) /* chipset initialization */ 6386228Stmm#define MYXDBG_CMD (2<<0) /* commands */ 6486228Stmm#define MYXDBG_INTR (3<<0) /* interrupts */ 6580708Sjake#define MYXDBG_ALL 0xffff /* enable all debugging messages */ 6680708Sjakeint myx_debug = MYXDBG_ALL; 6780708Sjake#define DPRINTF(_lvl, _arg...) do { \ 6880708Sjake if (myx_debug & (_lvl)) \ 6980708Sjake printf(_arg); \ 7080708Sjake} while (0) 7190615Stmm#else 7290615Stmm#define DPRINTF(_lvl, arg...) 7390615Stmm#endif 7490615Stmm 75145253Simp#define DEVNAME(_s) ((_s)->_s##_dev.dv_xname) 7686228Stmm 7780708Sjakestruct myx_dmamem { 7886228Stmm bus_dmamap_t mxm_map; 79166096Smarius bus_dma_segment_t mxm_seg; 8086228Stmm int mxm_nsegs; 8186228Stmm size_t mxm_size; 8286228Stmm caddr_t mxm_kva; 8386228Stmm const char *mxm_name; 84166096Smarius}; 8586228Stmm 8686228Stmmstruct myx_buf { 8786228Stmm bus_dmamap_t mb_dmamap; 8886228Stmm struct mbuf *mb_m; 8986228Stmm}; 9086228Stmm 91177565Smariusstruct myx_softc { 92177565Smarius struct device sc_dev; 9386228Stmm struct arpcom sc_ac; 94178860Smarius 9586228Stmm pci_chipset_tag_t sc_pc; 96178860Smarius pcitag_t sc_tag; 97178860Smarius u_int sc_function; 98178860Smarius 99178860Smarius bus_dma_tag_t sc_dmat; 100178860Smarius bus_space_tag_t sc_memt; 101178860Smarius bus_space_handle_t sc_memh; 10286228Stmm bus_size_t sc_mems; 103178860Smarius 10486228Stmm struct myx_dmamem sc_cmddma; 10586228Stmm struct myx_dmamem sc_paddma; 106108815Stmm 107108815Stmm struct myx_dmamem sc_stsdma; 108108815Stmm struct myx_status *sc_sts; 10986228Stmm 110108815Stmm struct myx_dmamem sc_rxdma; 111178860Smarius struct myx_rxdesc *sc_rxdesc; 11286228Stmm struct myx_rxbufdesc *sc_rxbufdesc[2]; 11386228Stmm struct myx_buf *sc_rxbuf[2]; 11486228Stmm#define MYX_RXSMALL 0 11586228Stmm#define MYX_RXBIG 1 11686228Stmm int sc_rxactive; 11793052Stmm int sc_rxidx; 11893052Stmm 119108917Sjake void *sc_irqh; 120108917Sjake u_int32_t sc_irqcoaloff; 121120375Snyan u_int32_t sc_irqclaimoff; 122111347Sobrien u_int32_t sc_irqdeassertoff; 123120375Snyan 124120375Snyan u_int8_t sc_lladdr[ETHER_ADDR_LEN]; 125225931Smarius struct ifmedia sc_media; 126225931Smarius 127120375Snyan u_int32_t sc_rxringsize; 128120375Snyan u_int32_t sc_rxsmallringoff; 129111347Sobrien u_int32_t sc_rxbigringoff; 130111347Sobrien int sc_rxndesc; 131225931Smarius size_t sc_rxdescsize; 132178860Smarius size_t sc_rxbufsize; 13386228Stmm size_t sc_rxbufdescsize; 13486228Stmm u_int32_t sc_txringsize; 135178860Smarius u_int32_t sc_txringoff; 13693052Stmm int sc_txndesc; 137178860Smarius 13886228Stmm u_int sc_phy; /* PHY type (CX4/SR/LR) */ 13986228Stmm u_int sc_hwflags; 14093052Stmm#define MYXFLAG_FLOW_CONTROL (1<<0) /* Rx/Tx pause is enabled */ 14193052Stmm#define MYXFLAG_PROMISC (1<<1) /* promisc mode is enabled */ 14293052Stmm#define MYXFLAG_ALLMULTI (1<<2) /* allmulti is set */ 14386228Stmm u_int8_t sc_active; 144178860Smarius 145108815Stmm struct timeout sc_tick; 14686228Stmm}; 14786228Stmm 148108917Sjakeint myx_match(struct device *, void *, void *); 149108917Sjakevoid myx_attach(struct device *, struct device *, void *); 150108917Sjakeint myx_query(struct myx_softc *sc); 151108917Sjakeu_int myx_ether_aton(char *, u_int8_t *, u_int); 152178860Smariusint myx_loadfirmware(struct myx_softc *, u_int8_t *, size_t, 153108917Sjake u_int32_t, int); 154108917Sjakevoid myx_attachhook(void *); 155108917Sjakevoid myx_read(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t); 156108917Sjakevoid myx_rawread(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t); 15786228Stmmvoid myx_write(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t); 158178860Smariusvoid myx_rawwrite(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t); 159178860Smariusint myx_cmd(struct myx_softc *, u_int32_t, struct myx_cmd *, u_int32_t *); 160178860Smariusint myx_boot(struct myx_softc *, u_int32_t, struct myx_bootcmd *); 161178860Smariusint myx_rdma(struct myx_softc *, u_int); 16286228Stmmint myx_reset(struct myx_softc *); 163178860Smariusint myx_dmamem_alloc(struct myx_softc *, struct myx_dmamem *, 164178860Smarius bus_size_t, u_int align, const char *); 165178860Smariusvoid myx_dmamem_free(struct myx_softc *, struct myx_dmamem *); 166178860Smariusint myx_media_change(struct ifnet *); 16786228Stmmvoid myx_media_status(struct ifnet *, struct ifmediareq *); 16886228Stmmvoid myx_link_state(struct myx_softc *); 16986228Stmmvoid myx_watchdog(struct ifnet *); 17086228Stmmvoid myx_tick(void *); 17186228Stmmint myx_ioctl(struct ifnet *, u_long, caddr_t); 17290615Stmmvoid myx_iff(struct myx_softc *); 173210334Sattiliovoid myx_init(struct ifnet *); 17490615Stmmvoid myx_start(struct ifnet *); 17590615Stmmvoid myx_stop(struct ifnet *); 17690615Stmmint myx_setlladdr(struct myx_softc *, u_int8_t *); 17790615Stmmint myx_intr(void *); 17890615Stmmint myx_init_rings(struct myx_softc *); 17990615Stmmvoid myx_free_rings(struct myx_softc *); 18090615Stmmstruct mbuf *myx_getbuf(struct myx_softc *, bus_dmamap_t, int); 18190615Stmm 182104304Sjakestruct cfdriver myx_cd = { 183104304Sjake 0, "myx", DV_IFNET 184104304Sjake}; 18586228Stmmstruct cfattach myx_ca = { 186104304Sjake sizeof(struct myx_softc), myx_match, myx_attach 187108815Stmm}; 188104304Sjake 18986228Stmmconst struct pci_matchid myx_devices[] = { 190104304Sjake { PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E } 191104304Sjake}; 192104304Sjake 19386228Stmmint 194104304Sjakemyx_match(struct device *parent, void *match, void *aux) 195108815Stmm{ 196104304Sjake return (pci_matchbyid((struct pci_attach_args *)aux, 19786228Stmm myx_devices, sizeof(myx_devices) / sizeof(myx_devices[0]))); 198104304Sjake} 199104304Sjake 200104304Sjakevoid 20186228Stmmmyx_attach(struct device *parent, struct device *self, void *aux) 202104304Sjake{ 203108815Stmm struct myx_softc *sc = (struct myx_softc *)self; 204104304Sjake struct pci_attach_args *pa = aux; 20586228Stmm pci_intr_handle_t ih; 206104304Sjake pcireg_t memtype; 207104304Sjake const char *intrstr; 208104304Sjake struct ifnet *ifp; 20986228Stmm 210104304Sjake sc->sc_pc = pa->pa_pc; 211108815Stmm sc->sc_tag = pa->pa_tag; 212104304Sjake sc->sc_dmat = pa->pa_dmat; 21386228Stmm sc->sc_function = pa->pa_function; 214104304Sjake 215104304Sjake memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, MYXBAR0); 216104304Sjake switch (memtype) { 217104304Sjake case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT: 218216143Sbrucec case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT: 219104304Sjake break; 220104304Sjake default: 221104304Sjake printf(": invalid memory type: 0x%x\n", memtype); 22286228Stmm return; 223104304Sjake } 224104304Sjake 225104304Sjake /* Map the PCI memory space */ 226104304Sjake if (pci_mapreg_map(pa, MYXBAR0, memtype, 0, &sc->sc_memt, 227216143Sbrucec &sc->sc_memh, NULL, &sc->sc_mems, 0) != 0) { 228104304Sjake printf(": unable to map register memory\n"); 229104304Sjake return; 230104304Sjake } 23186228Stmm 232104304Sjake /* Get the board information and initialize the h/w */ 233104304Sjake if (myx_query(sc) != 0) 234104304Sjake goto unmap; 235104304Sjake 236216143Sbrucec /* 237104304Sjake * Allocate command DMA memory 238104304Sjake */ 239104304Sjake if (myx_dmamem_alloc(sc, &sc->sc_cmddma, MYXALIGN_CMD, 24086228Stmm MYXALIGN_CMD, "cmd") != 0) { 241104304Sjake printf(": failed to allocate command DMA memory\n"); 242104304Sjake goto unmap; 243104304Sjake } 244104304Sjake 245216143Sbrucec if (myx_dmamem_alloc(sc, &sc->sc_paddma, 246104304Sjake MYXALIGN_CMD, MYXALIGN_CMD, "pad") != 0) { 247104304Sjake printf(": failed to allocate pad DMA memory\n"); 248104304Sjake goto err2; 24986228Stmm } 250104304Sjake 251104304Sjake if (myx_dmamem_alloc(sc, &sc->sc_stsdma, 252104304Sjake sizeof(struct myx_status), MYXALIGN_DATA /* XXX */, "status") != 0) { 253104304Sjake printf(": failed to allocate status DMA memory\n"); 25486228Stmm goto err1; 255104304Sjake } 256108815Stmm sc->sc_sts = (struct myx_status *)sc->sc_stsdma.mxm_kva; 257104304Sjake 25886228Stmm /* 259104304Sjake * Map and establish the interrupt 260104304Sjake */ 261104304Sjake if (pci_intr_map(pa, &ih) != 0) { 262104304Sjake printf(": unable to map interrupt\n"); 26386228Stmm goto err; 264104304Sjake } 265108815Stmm intrstr = pci_intr_string(pa->pa_pc, ih); 266104304Sjake sc->sc_irqh = pci_intr_establish(pa->pa_pc, ih, IPL_NET, 26786228Stmm myx_intr, sc, DEVNAME(sc)); 26893052Stmm if (sc->sc_irqh == NULL) { 269104304Sjake printf(": unable to establish interrupt %s\n", intrstr); 270104304Sjake goto err; 271104304Sjake } 272104304Sjake printf(": %s, address %s\n", intrstr, 273104304Sjake ether_sprintf(sc->sc_ac.ac_enaddr)); 274108815Stmm 275104304Sjake ifp = &sc->sc_ac.ac_if; 276104304Sjake ifp->if_softc = sc; 277104304Sjake ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; 278104304Sjake ifp->if_ioctl = myx_ioctl; 279104304Sjake ifp->if_start = myx_start; 280104304Sjake ifp->if_watchdog = myx_watchdog; 281104304Sjake strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ); 282104304Sjake IFQ_SET_MAXLEN(&ifp->if_snd, MYX_NTXDESC_MIN - 1); 283108815Stmm IFQ_SET_READY(&ifp->if_snd); 284104304Sjake 285104304Sjake ifp->if_capabilities = IFCAP_VLAN_MTU; 286104304Sjake#if 0 287104304Sjake ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING; 288157224Smarius ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | 289104304Sjake IFCAP_CSUM_UDPv4; 290216143Sbrucec#endif 291104304Sjake ifp->if_baudrate = ULONG_MAX; /* XXX fix if_baudrate */ 292104304Sjake 293104304Sjake ifmedia_init(&sc->sc_media, 0, 294104304Sjake myx_media_change, myx_media_status); 295104304Sjake ifmedia_add(&sc->sc_media, IFM_ETHER|sc->sc_phy, 0, NULL); 296104304Sjake ifmedia_set(&sc->sc_media, IFM_ETHER|sc->sc_phy); 297157224Smarius 298104304Sjake if_attach(ifp); 299216143Sbrucec ether_ifattach(ifp); 300104304Sjake 301104304Sjake timeout_set(&sc->sc_tick, myx_tick, sc); 302104304Sjake timeout_add(&sc->sc_tick, hz); 303104304Sjake 304104304Sjake mountroothook_establish(myx_attachhook, sc); 305104304Sjake 306157224Smarius return; 307104304Sjake 308216143Sbrucec err: 309104304Sjake myx_dmamem_free(sc, &sc->sc_stsdma); 310104304Sjake err1: 311104304Sjake myx_dmamem_free(sc, &sc->sc_paddma); 312104304Sjake err2: 313104304Sjake myx_dmamem_free(sc, &sc->sc_cmddma); 314104304Sjake unmap: 315157224Smarius bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems); 316104304Sjake sc->sc_mems = 0; 317216143Sbrucec} 318104304Sjake 319104304Sjakeu_int 320104304Sjakemyx_ether_aton(char *mac, u_int8_t *lladdr, u_int maxlen) 321104304Sjake{ 322104304Sjake u_int i, j; 323104304Sjake u_int8_t digit; 324104304Sjake 325104304Sjake bzero(lladdr, ETHER_ADDR_LEN); 326216143Sbrucec for (i = j = 0; mac[i] != '\0' && i < maxlen; i++) { 327104304Sjake if (mac[i] >= '0' && mac[i] <= '9') 328104304Sjake digit = mac[i] - '0'; 329104304Sjake else if (mac[i] >= 'A' && mac[i] <= 'F') 330104304Sjake digit = mac[i] - 'A' + 10; 331104304Sjake else if (mac[i] >= 'a' && mac[i] <= 'f') 332104304Sjake digit = mac[i] - 'a' + 10; 333104304Sjake else 334104304Sjake continue; 335216143Sbrucec if ((j & 1) == 0) 336104304Sjake digit <<= 4; 337104304Sjake lladdr[j++/2] |= digit; 338104304Sjake } 339104304Sjake 340104304Sjake return (i); 341104304Sjake} 342104304Sjake 343104304Sjakeint 344216143Sbrucecmyx_query(struct myx_softc *sc) 345104304Sjake{ 346104304Sjake u_int8_t eeprom[MYX_EEPROM_SIZE]; 347104304Sjake u_int i, maxlen; 348104304Sjake 349104304Sjake myx_read(sc, MYX_EEPROM, eeprom, MYX_EEPROM_SIZE); 350104304Sjake 351104304Sjake for (i = 0; i < MYX_EEPROM_SIZE; i++) { 352104304Sjake maxlen = MYX_EEPROM_SIZE - i; 353216143Sbrucec if (eeprom[i] == '\0') 354104304Sjake break; 355104304Sjake if (maxlen > 4 && bcmp("MAC=", &eeprom[i], 4) == 0) { 356104304Sjake i += 4; 357104304Sjake i += myx_ether_aton(&eeprom[i], 358104304Sjake sc->sc_ac.ac_enaddr, maxlen); 35993052Stmm } 360178860Smarius for (; i < MYX_EEPROM_SIZE; i++) 36186228Stmm if (eeprom[i] == '\0') 362216143Sbrucec break; 36386228Stmm } 36486228Stmm 36586228Stmm return (0); 36686228Stmm} 36793052Stmm 36893052Stmmint 369178860Smariusmyx_loadfirmware(struct myx_softc *sc, u_int8_t *fw, size_t fwlen, 37086228Stmm u_int32_t fwhdroff, int reload) 371216143Sbrucec{ 372178860Smarius struct myx_firmware_hdr *fwhdr; 37386228Stmm u_int i, len, ret = 0; 37486228Stmm 37586228Stmm fwhdr = (struct myx_firmware_hdr *)(fw + fwhdroff); 37693052Stmm DPRINTF(MYXDBG_INIT, "%s(%s): " 37793052Stmm "fw hdr off %d, length %d, type 0x%x, version %s\n", 378178860Smarius DEVNAME(sc), __func__, 37986228Stmm fwhdroff, betoh32(fwhdr->fw_hdrlength), 380216143Sbrucec betoh32(fwhdr->fw_type), 381178860Smarius fwhdr->fw_version); 38286228Stmm 38386228Stmm if (betoh32(fwhdr->fw_type) != MYXFW_TYPE_ETH || 38486228Stmm bcmp(MYXFW_VER, fwhdr->fw_version, strlen(MYXFW_VER)) != 0) { 38593052Stmm if (reload) 38693052Stmm printf("%s: invalid firmware type 0x%x version %s\n", 387178860Smarius DEVNAME(sc), betoh32(fwhdr->fw_type), 38886228Stmm fwhdr->fw_version); 389216143Sbrucec ret = 1; 390178860Smarius goto done; 39186228Stmm } 39286228Stmm 39386228Stmm if (!reload) 39493052Stmm goto done; 39593052Stmm 396178860Smarius /* Write the firmware to the card's SRAM */ 39786228Stmm for (i = 0; i < fwlen; i += 256) { 398216143Sbrucec len = min(256, fwlen - i); 39986228Stmm myx_rawwrite(sc, i + MYX_FW, fw + i, min(256, fwlen - i)); 40086228Stmm } 40186228Stmm 40286228Stmm done: 40393052Stmm free(fw, M_DEVBUF); 40493052Stmm return (ret); 405178860Smarius} 40686228Stmm 407216143Sbrucecvoid 408178860Smariusmyx_attachhook(void *arg) 40986228Stmm{ 41086228Stmm struct myx_softc *sc = (struct myx_softc *)arg; 41186228Stmm size_t fwlen; 41293052Stmm u_int8_t *fw = NULL; 41393052Stmm u_int32_t fwhdroff; 414178860Smarius struct myx_bootcmd bc; 41586228Stmm 416216143Sbrucec /* 417178860Smarius * First try the firmware found in the SRAM 41886228Stmm */ 41986228Stmm myx_read(sc, MYX_HEADER_POS, (u_int8_t *)&fwhdroff, sizeof(fwhdroff)); 42086228Stmm fwhdroff = betoh32(fwhdroff); 42193052Stmm fwlen = sizeof(struct myx_firmware_hdr); 42293052Stmm if ((fwhdroff + fwlen) > MYX_SRAM_SIZE) 423178860Smarius goto load; 42486228Stmm 425216143Sbrucec fw = malloc(fwlen, M_DEVBUF, M_WAIT); 426178860Smarius myx_rawread(sc, MYX_HEADER_POS, fw, fwlen); 42786228Stmm 42886228Stmm if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 0) == 0) 42986228Stmm goto boot; 43093052Stmm 43193052Stmm load: 432178860Smarius /* 43386228Stmm * Now try the firmware stored on disk 434216143Sbrucec */ 43586228Stmm if (loadfirmware(MYXFW_ALIGNED /* XXX */, &fw, &fwlen) != 0) { 43686228Stmm printf("%s: could not load firmware\n", DEVNAME(sc)); 43786228Stmm return; 43886228Stmm } 43993052Stmm if (fwlen > MYX_SRAM_SIZE || fwlen < MYXFW_MIN_LEN) { 44093052Stmm printf("%s: invalid firmware image size\n", DEVNAME(sc)); 441178860Smarius goto err; 44286228Stmm } 443216143Sbrucec 444178860Smarius bcopy(fw + MYX_HEADER_POS, &fwhdroff, sizeof(fwhdroff)); 44586228Stmm fwhdroff = betoh32(fwhdroff); 44686228Stmm if ((fwhdroff + sizeof(struct myx_firmware_hdr)) > fwlen) { 44786228Stmm printf("%s: invalid firmware image\n", DEVNAME(sc)); 44893052Stmm goto err; 44993052Stmm } 450178860Smarius 45186228Stmm if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 1) != 0) { 452216143Sbrucec fw = NULL; 453178860Smarius goto err; 45486228Stmm } 45586228Stmm fw = NULL; 45686228Stmm 45793052Stmm boot: 45893052Stmm bzero(&bc, sizeof(bc)); 459178860Smarius if (myx_boot(sc, fwlen, &bc) != 0) { 46086228Stmm printf("%s: failed to bootstrap the device\n", DEVNAME(sc)); 461216143Sbrucec goto err; 462178860Smarius } 46386228Stmm if (myx_reset(sc) != 0) 46486228Stmm goto err; 46586228Stmm 46693052Stmm sc->sc_active = 1; 46793052Stmm return; 46893052Stmm 46986228Stmm err: 470216143Sbrucec if (fw != NULL) 47186228Stmm free(fw, M_DEVBUF); 47286228Stmm} 47386228Stmm 47486228Stmmvoid 47593052Stmmmyx_read(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len) 47693052Stmm{ 47793052Stmm bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len, 47886228Stmm BUS_SPACE_BARRIER_READ); 479216143Sbrucec bus_space_read_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len / 4); 480178860Smarius} 48186228Stmm 48286228Stmmvoid 48386228Stmmmyx_rawread(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, 48493052Stmm bus_size_t len) 48593052Stmm{ 48693052Stmm bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len, 48786228Stmm BUS_SPACE_BARRIER_READ); 488216143Sbrucec bus_space_read_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len); 489178860Smarius} 49086228Stmm 49186228Stmmvoid 49286228Stmmmyx_write(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len) 49393052Stmm{ 49493052Stmm bus_space_write_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len / 4); 49593052Stmm bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len, 49686228Stmm BUS_SPACE_BARRIER_WRITE); 497216143Sbrucec} 498178860Smarius 49986228Stmmvoid 50086228Stmmmyx_rawwrite(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, 50186228Stmm bus_size_t len) 502104304Sjake{ 503104304Sjake bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len); 504104304Sjake bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len, 50586228Stmm BUS_SPACE_BARRIER_WRITE); 506104304Sjake} 507108815Stmm 508104304Sjakeint 50986228Stmmmyx_dmamem_alloc(struct myx_softc *sc, struct myx_dmamem *mxm, 510104304Sjake bus_size_t size, u_int align, const char *mname) 511104304Sjake{ 512104304Sjake mxm->mxm_size = size; 51386228Stmm 514104304Sjake if (bus_dmamap_create(sc->sc_dmat, mxm->mxm_size, 1, 515108815Stmm mxm->mxm_size, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW, 516104304Sjake &mxm->mxm_map) != 0) 51786228Stmm return (1); 518104304Sjake if (bus_dmamem_alloc(sc->sc_dmat, mxm->mxm_size, 519104304Sjake align, 0, &mxm->mxm_seg, 1, &mxm->mxm_nsegs, 520104304Sjake BUS_DMA_WAITOK) != 0) 52186228Stmm goto destroy; 522104304Sjake if (bus_dmamem_map(sc->sc_dmat, &mxm->mxm_seg, mxm->mxm_nsegs, 523108815Stmm mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_WAITOK) != 0) 524104304Sjake goto free; 52586228Stmm if (bus_dmamap_load(sc->sc_dmat, mxm->mxm_map, mxm->mxm_kva, 526104304Sjake mxm->mxm_size, NULL, BUS_DMA_WAITOK) != 0) 527104304Sjake goto unmap; 528104304Sjake 52986228Stmm bzero(mxm->mxm_kva, mxm->mxm_size); 530104304Sjake mxm->mxm_name = mname; 531108815Stmm 532104304Sjake return (0); 53386228Stmm unmap: 534104304Sjake bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size); 535104304Sjake free: 536104304Sjake bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1); 537104304Sjake destroy: 538216143Sbrucec bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map); 539104304Sjake return (1); 540104304Sjake} 541104304Sjake 54286228Stmmvoid 543104304Sjakemyx_dmamem_free(struct myx_softc *sc, struct myx_dmamem *mxm) 544104304Sjake{ 545104304Sjake bus_dmamap_unload(sc->sc_dmat, mxm->mxm_map); 546104304Sjake bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size); 547216143Sbrucec bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1); 548104304Sjake bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map); 549104304Sjake} 550104304Sjake 55186228Stmmint 552104304Sjakemyx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r) 553104304Sjake{ 554104304Sjake bus_dmamap_t map = sc->sc_cmddma.mxm_map; 555104304Sjake struct myx_response *mr; 556216143Sbrucec u_int i; 557104304Sjake u_int32_t result, data; 558104304Sjake#ifdef MYX_DEBUG 559104304Sjake static const char *cmds[MYXCMD_MAX] = { 56086228Stmm "CMD_NONE", 561104304Sjake "CMD_RESET", 562104304Sjake "CMD_GET_VERSION", 563104304Sjake "CMD_SET_INTRQDMA", 564104304Sjake "CMD_SET_BIGBUFSZ", 565216143Sbrucec "CMD_SET_SMALLBUFSZ", 566104304Sjake "CMD_GET_TXRINGOFF", 567104304Sjake "CMD_GET_RXSMALLRINGOFF", 568104304Sjake "CMD_GET_RXBIGRINGOFF", 56986228Stmm "CMD_GET_INTRACKOFF", 570104304Sjake "CMD_GET_INTRDEASSERTOFF", 571104304Sjake "CMD_GET_TXRINGSZ", 572104304Sjake "CMD_GET_RXRINGSZ", 573104304Sjake "CMD_SET_INTRQSZ", 57486228Stmm "CMD_SET_IFUP", 575104304Sjake "CMD_SET_IFDOWN", 576108815Stmm "CMD_SET_MTU", 577104304Sjake "CMD_GET_INTRCOALDELAYOFF", 57886228Stmm "CMD_SET_STATSINTVL", 579104304Sjake "CMD_SET_STATSDMA_OLD", 580104304Sjake "CMD_SET_PROMISC", 581104304Sjake "CMD_UNSET_PROMISC", 582104304Sjake "CMD_SET_LLADDR", 58386228Stmm "CMD_SET_FC", 584104304Sjake "CMD_UNSET_FC", 585108815Stmm "CMD_DMA_TEST", 586104304Sjake "CMD_SET_ALLMULTI", 58786228Stmm "CMD_UNSET_ALLMULTI", 58893052Stmm "CMD_SET_MCASTGROUP", 589104304Sjake "CMD_UNSET_MCASTGROUP", 590104304Sjake "CMD_UNSET_MCAST", 591104304Sjake "CMD_SET_STATSDMA", 592104304Sjake "CMD_UNALIGNED_DMA_TEST", 593104304Sjake "CMD_GET_UNALIGNED_STATUS" 594108815Stmm }; 595104304Sjake#endif 596104304Sjake 597104304Sjake mc->mc_cmd = htobe32(cmd); 598104304Sjake mc->mc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 599104304Sjake mc->mc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 600104304Sjake 601104304Sjake mr = (struct myx_response *)sc->sc_cmddma.mxm_kva; 602104304Sjake mr->mr_result = 0xffffffff; 603108815Stmm 604104304Sjake /* Send command */ 605104304Sjake myx_write(sc, MYX_CMD, (u_int8_t *)mc, sizeof(struct myx_cmd)); 606104304Sjake 607104304Sjake for (i = 0; i < 20; i++) { 608111383Sobrien bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 609104304Sjake BUS_DMASYNC_POSTREAD); 610216143Sbrucec result = betoh32(mr->mr_result); 611104304Sjake data = betoh32(mr->mr_data); 612104304Sjake 613104304Sjake if (result != 0xffffffff) 614104304Sjake break; 615104304Sjake delay(1000); 616104304Sjake } 617111353Sobrien 618104304Sjake DPRINTF(MYXDBG_CMD, "%s(%s): %s completed, i %d, " 619216143Sbrucec "result 0x%x, data 0x%x (%u)\n", DEVNAME(sc), __func__, 620104304Sjake cmds[cmd], i, result, data, data); 621104304Sjake 622104304Sjake if (result != 0) 623104304Sjake return (-1); 624104304Sjake 625104304Sjake if (r != NULL) 626111383Sobrien *r = data; 627104304Sjake return (0); 628216143Sbrucec} 629104304Sjake 630104304Sjakeint 631104304Sjakemyx_boot(struct myx_softc *sc, u_int32_t length, struct myx_bootcmd *bc) 632104304Sjake{ 633104304Sjake bus_dmamap_t map = sc->sc_cmddma.mxm_map; 634104304Sjake u_int32_t *status; 635111383Sobrien u_int i; 636104304Sjake 637216143Sbrucec bc->bc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 638104304Sjake bc->bc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 639104304Sjake bc->bc_result = 0xffffffff; 640104304Sjake bc->bc_offset = htobe32(MYX_FW_BOOT); 641104304Sjake bc->bc_length = htobe32(length); 642104304Sjake bc->bc_copyto = htobe32(8); 643104304Sjake bc->bc_jumpto = htobe32(0); 644104304Sjake 645104304Sjake status = (u_int32_t *)sc->sc_cmddma.mxm_kva; 646216143Sbrucec *status = 0; 647104304Sjake 648104304Sjake /* Send command */ 649104304Sjake myx_write(sc, MYX_BOOT, (u_int8_t *)bc, sizeof(struct myx_bootcmd)); 650104304Sjake 651104304Sjake for (i = 0; i < 200; i++) { 652104304Sjake bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 653104304Sjake BUS_DMASYNC_POSTREAD); 654104304Sjake if (*status == 0xffffffff) 655216143Sbrucec break; 656104304Sjake delay(1000); 657104304Sjake } 658104304Sjake 659104304Sjake DPRINTF(MYXDBG_CMD, "%s(%s): boot completed, i %d, result 0x%x\n", 660104304Sjake DEVNAME(sc), __func__, i, betoh32(*status)); 661104304Sjake 662104304Sjake if (*status != 0xffffffff) 663104304Sjake return (-1); 664216143Sbrucec 665104304Sjake return (0); 666104304Sjake} 667104304Sjake 668104304Sjakeint 669104304Sjakemyx_rdma(struct myx_softc *sc, u_int do_enable) 670104304Sjake{ 671104304Sjake struct myx_rdmacmd rc; 672104304Sjake bus_dmamap_t map = sc->sc_cmddma.mxm_map; 673216143Sbrucec bus_dmamap_t pad = sc->sc_paddma.mxm_map; 674104304Sjake u_int32_t *status; 675104304Sjake u_int i; 676104304Sjake 677104304Sjake /* 678104304Sjake * It is required to setup a _dummy_ RDMA address. It also makes 67993052Stmm * some PCI-E chipsets resend dropped messages. 680178860Smarius */ 68186228Stmm rc.rc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 682216143Sbrucec rc.rc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr)); 68386228Stmm rc.rc_result = 0xffffffff; 68486228Stmm rc.rc_rdma_high = htobe32(MYX_ADDRHIGH(pad->dm_segs[0].ds_addr)); 68586228Stmm rc.rc_rdma_low = htobe32(MYX_ADDRLOW(pad->dm_segs[0].ds_addr)); 68686228Stmm rc.rc_enable = htobe32(do_enable); 68793052Stmm 68893052Stmm status = (u_int32_t *)sc->sc_cmddma.mxm_kva; 689178860Smarius *status = 0; 69086228Stmm 691216143Sbrucec /* Send command */ 692178860Smarius myx_write(sc, MYX_RDMA, (u_int8_t *)&rc, sizeof(struct myx_rdmacmd)); 69386228Stmm 69486228Stmm for (i = 0; i < 20; i++) { 69586228Stmm bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 69693052Stmm BUS_DMASYNC_POSTREAD); 69793052Stmm if (*status == 0xffffffff) 698178860Smarius break; 69986228Stmm delay(1000); 700216143Sbrucec } 701178860Smarius 70286228Stmm DPRINTF(MYXDBG_CMD, "%s(%s): dummy RDMA %s, i %d, result 0x%x\n", 70386228Stmm DEVNAME(sc), __func__, 70486228Stmm do_enable ? "enabled" : "disabled", i, betoh32(*status)); 70593052Stmm 70693052Stmm if (*status != 0xffffffff) 707178860Smarius return (-1); 70886228Stmm 709216143Sbrucec return (0); 710178860Smarius} 71186228Stmm 71286228Stmmint 71386228Stmmmyx_reset(struct myx_softc *sc) 71493052Stmm{ 71593052Stmm struct myx_cmd mc; 716178860Smarius u_int32_t data; 71786228Stmm struct ifnet *ifp = &sc->sc_ac.ac_if; 718216143Sbrucec 71986228Stmm bzero(&mc, sizeof(mc)); 72086228Stmm if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) { 72186228Stmm printf("%s: failed to reset the device\n", DEVNAME(sc)); 72286228Stmm return (-1); 72393052Stmm } 72493052Stmm 725178860Smarius if (myx_rdma(sc, MYXRDMA_ON) != 0) { 72686228Stmm printf("%s: failed to enable dummy RDMA\n", DEVNAME(sc)); 727216143Sbrucec return (-1); 728178860Smarius } 72986228Stmm 73086228Stmm if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc, 73186228Stmm &sc->sc_irqcoaloff) != 0) { 73293052Stmm printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc)); 73393052Stmm return (-1); 734178860Smarius } 73586228Stmm data = htobe32(MYX_IRQCOALDELAY); 736216143Sbrucec myx_write(sc, sc->sc_irqcoaloff, (u_int8_t *)&data, sizeof(data)); 737178860Smarius 73886228Stmm if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc, 73986228Stmm &sc->sc_irqclaimoff) != 0) { 74086228Stmm printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc)); 74193052Stmm return (-1); 74293052Stmm } 743178860Smarius 74486228Stmm if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc, 745216143Sbrucec &sc->sc_irqdeassertoff) != 0) { 746178860Smarius printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc)); 74786228Stmm return (-1); 74886228Stmm } 74986228Stmm 75093052Stmm if (myx_cmd(sc, MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) { 75193052Stmm printf("%s: failed to disable promisc mode\n", DEVNAME(sc)); 752178860Smarius return (-1); 75386228Stmm } 754216143Sbrucec 75586228Stmm if (myx_cmd(sc, MYXCMD_FC_DEFAULT, &mc, NULL) != 0) { 75686228Stmm printf("%s: failed to configure flow control\n", DEVNAME(sc)); 75786228Stmm return (-1); 75886228Stmm } 75993052Stmm 76093052Stmm if (myx_setlladdr(sc, LLADDR(ifp->if_sadl)) != 0) 761178860Smarius return (-1); 76286228Stmm 763216143Sbrucec return (0); 764178860Smarius} 76586228Stmm 76686228Stmm 76786228Stmmint 76893052Stmmmyx_media_change(struct ifnet *ifp) 76993052Stmm{ 770178860Smarius return (EINVAL); 77186228Stmm} 772216143Sbrucec 773178860Smariusvoid 77486228Stmmmyx_media_status(struct ifnet *ifp, struct ifmediareq *imr) 77586228Stmm{ 77686228Stmm struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; 77793052Stmm 77893052Stmm imr->ifm_active = IFM_ETHER|sc->sc_phy; 779178860Smarius imr->ifm_status = IFM_AVALID; 78086228Stmm myx_link_state(sc); 781216143Sbrucec if (!LINK_STATE_IS_UP(ifp->if_link_state)) 782178860Smarius return; 78386228Stmm imr->ifm_active |= IFM_FDX; 78486228Stmm imr->ifm_status |= IFM_ACTIVE; 78586228Stmm 78693052Stmm /* Flow control */ 78793052Stmm if (sc->sc_hwflags & MYXFLAG_FLOW_CONTROL) 78893052Stmm imr->ifm_active |= IFM_FLOW|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE; 78986228Stmm} 790216143Sbrucec 79186228Stmmvoid 79286228Stmmmyx_link_state(struct myx_softc *sc) 79386228Stmm{ 79486228Stmm struct ifnet *ifp = &sc->sc_ac.ac_if; 79586228Stmm int link_state = LINK_STATE_DOWN; 79693052Stmm 79793052Stmm if (sc->sc_sts == NULL) 79893052Stmm return; 79986228Stmm if (sc->sc_sts->ms_linkstate == MYXSTS_LINKUP) 800216143Sbrucec link_state = LINK_STATE_FULL_DUPLEX; 801178860Smarius if (ifp->if_link_state != link_state) { 80286228Stmm ifp->if_link_state = link_state; 80386228Stmm if_link_state_change(ifp); 80486228Stmm } 80586228Stmm} 80693052Stmm 80793052Stmmvoid 80893052Stmmmyx_watchdog(struct ifnet *ifp) 80986228Stmm{ 810216143Sbrucec return; 811178860Smarius} 81286228Stmm 81386228Stmmvoid 81486228Stmmmyx_tick(void *arg) 81586228Stmm{ 81693052Stmm struct myx_softc *sc = (struct myx_softc *)arg; 81793052Stmm 81893052Stmm if (!sc->sc_active) 81986228Stmm return; 820216143Sbrucec 821178860Smarius myx_link_state(sc); 82286228Stmm timeout_add(&sc->sc_tick, hz); 82386228Stmm} 82486228Stmm 825116659Sjmgint 826116659Sjmgmyx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) 827178860Smarius{ 828116659Sjmg struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; 829116659Sjmg struct ifaddr *ifa = (struct ifaddr *)data; 830116659Sjmg struct ifreq *ifr = (struct ifreq *)data; 831116659Sjmg int s, error = 0; 832116659Sjmg 833116659Sjmg s = splnet(); 834116659Sjmg if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) { 835116659Sjmg splx(s); 836178860Smarius return (error); 837116659Sjmg } 838116659Sjmg 839116659Sjmg switch (cmd) { 840116659Sjmg case SIOCSIFADDR: 841116659Sjmg ifp->if_flags |= IFF_UP; 842116659Sjmg#ifdef INET 843116659Sjmg if (ifa->ifa_addr->sa_family == AF_INET) 844116659Sjmg arp_ifinit(&sc->sc_ac, ifa); 845178860Smarius#endif 846116659Sjmg /* FALLTHROUGH */ 847116659Sjmg case SIOCSIFFLAGS: 848116659Sjmg if (ifp->if_flags & IFF_UP) { 849116659Sjmg if (ifp->if_flags & IFF_RUNNING) 850116659Sjmg myx_iff(sc); 851116659Sjmg else 852143598Sscottl myx_init(ifp); 85386228Stmm } else { 85480708Sjake if (ifp->if_flags & IFF_RUNNING) 855 myx_stop(ifp); 856 } 857 break; 858 859 case SIOCSIFMTU: 860 if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu) 861 error = EINVAL; 862 else if (ifp->if_mtu != ifr->ifr_mtu) 863 ifp->if_mtu = ifr->ifr_mtu; 864 break; 865 866 case SIOCADDMULTI: 867 error = ether_addmulti(ifr, &sc->sc_ac); 868 break; 869 870 case SIOCDELMULTI: 871 error = ether_delmulti(ifr, &sc->sc_ac); 872 break; 873 874 case SIOCGIFMEDIA: 875 case SIOCSIFMEDIA: 876 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 877 break; 878 879 default: 880 error = ENOTTY; 881 } 882 883 if (error == ENETRESET) { 884 if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) == 885 (IFF_UP | IFF_RUNNING)) 886 myx_iff(sc); 887 error = 0; 888 } 889 890 splx(s); 891 892 return (error); 893} 894 895void 896myx_iff(struct myx_softc *sc) 897{ 898 /* XXX set multicast filters etc. */ 899 return; 900} 901 902void 903myx_init(struct ifnet *ifp) 904{ 905 struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; 906 struct myx_cmd mc; 907 908 if (myx_reset(sc) != 0) 909 return; 910 911 if (myx_init_rings(sc) != 0) 912 return; 913 914 if (myx_cmd(sc, MYXCMD_SET_IFUP, &mc, NULL) != 0) { 915 printf("%s: failed to start the device\n", DEVNAME(sc)); 916 myx_free_rings(sc); 917 return; 918 } 919 920 ifp->if_flags |= IFF_RUNNING; 921 ifp->if_flags &= ~IFF_OACTIVE; 922} 923 924void 925myx_start(struct ifnet *ifp) 926{ 927} 928 929void 930myx_stop(struct ifnet *ifp) 931{ 932 struct myx_softc *sc = (struct myx_softc *)ifp->if_softc; 933 struct myx_cmd mc; 934 935 bzero(&mc, sizeof(mc)); 936 (void)myx_cmd(sc, MYXCMD_SET_IFDOWN, &mc, NULL); 937 myx_free_rings(sc); 938 939 ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE); 940} 941 942int 943myx_setlladdr(struct myx_softc *sc, u_int8_t *addr) 944{ 945 struct myx_cmd mc; 946 947 bzero(&mc, sizeof(mc)); 948 mc.mc_data0 = addr[3] | addr[2] << 8 | addr[1] << 16 | addr[0] << 24; 949 mc.mc_data1 = addr[5] | addr[4] << 8; 950 if (myx_cmd(sc, MYXCMD_SET_LLADDR, &mc, NULL) != 0) { 951 printf("%s: failed to set the lladdr\n", DEVNAME(sc)); 952 return (-1); 953 } 954 return (0); 955} 956 957int 958myx_intr(void *arg) 959{ 960 struct myx_softc *sc = (struct myx_softc *)arg; 961 u_int32_t data, valid; 962 struct myx_status *sts = sc->sc_sts; 963 bus_dmamap_t map = sc->sc_stsdma.mxm_map; 964 965 if (!sc->sc_active) 966 return (0); 967 968 bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize, 969 BUS_DMASYNC_POSTWRITE); 970 971 /* 972 * XXX The 'valid' flags should be set by the NIC, but it doesn't 973 * XXX work yet. 974 */ 975 valid = sts->ms_isvalid; 976 if (!valid) 977 return (0); 978 979 data = 0; 980 myx_write(sc, sc->sc_irqdeassertoff, (u_int8_t *)&data, sizeof(data)); 981 982 DPRINTF(MYXDBG_INTR, "%s(%s): interrupt, valid 0x%x\n", 983 DEVNAME(sc), __func__, valid); 984 985#ifdef MYX_DEBUG 986#define DPRINT_STATUS(_n) \ 987 DPRINTF(MYXDBG_INTR, "%s(%s): %s: %u, 0x%x\n", DEVNAME(sc), __func__,\ 988 #_n, sts->_n, sts->_n) 989 990 DPRINT_STATUS(ms_reserved); 991 DPRINT_STATUS(ms_dropped_pause); 992 DPRINT_STATUS(ms_dropped_unicast); 993 DPRINT_STATUS(ms_dropped_crc32err); 994 DPRINT_STATUS(ms_dropped_phyerr); 995 DPRINT_STATUS(ms_dropped_mcast); 996 DPRINT_STATUS(ms_txdonecnt); 997 DPRINT_STATUS(ms_linkstate); 998 DPRINT_STATUS(ms_dropped_linkoverflow); 999 DPRINT_STATUS(ms_dropped_linkerror); 1000 DPRINT_STATUS(ms_dropped_runt); 1001 DPRINT_STATUS(ms_dropped_overrun); 1002 DPRINT_STATUS(ms_dropped_smallbufunderrun); 1003 DPRINT_STATUS(ms_dropped_bigbufunderrun); 1004 DPRINT_STATUS(ms_rdmatags_available); 1005 DPRINT_STATUS(ms_txstopped); 1006 DPRINT_STATUS(ms_linkdowncnt); 1007 DPRINT_STATUS(ms_statusupdated); 1008 DPRINT_STATUS(ms_isvalid); 1009#endif 1010 1011 data = htobe32(3); 1012 if (sts->ms_isvalid) 1013 myx_write(sc, sc->sc_irqclaimoff, (u_int8_t *)&data, 1014 sizeof(data)); 1015 myx_write(sc, sc->sc_irqclaimoff + sizeof(u_int32_t), 1016 (u_int8_t *)&data, sizeof(data)); 1017 1018 return (1); 1019} 1020 1021int 1022myx_init_rings(struct myx_softc *sc) 1023{ 1024 struct myx_cmd mc; 1025 struct ifnet *ifp = &sc->sc_ac.ac_if; 1026 bus_dmamap_t map; 1027 int i; 1028 struct myx_buf *mb; 1029 struct myx_rxbufdesc *rxb; 1030 u_int32_t data; 1031 1032 bzero(&mc, sizeof(mc)); 1033 if (!(myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc, 1034 &sc->sc_rxringsize) == 0 && sc->sc_rxringsize && 1035 myx_cmd(sc, MYXCMD_GET_RXSMALLRINGOFF, &mc, 1036 &sc->sc_rxsmallringoff) == 0 && sc->sc_rxsmallringoff && 1037 myx_cmd(sc, MYXCMD_GET_RXBIGRINGOFF, &mc, 1038 &sc->sc_rxbigringoff) == 0 && sc->sc_rxbigringoff && 1039 myx_cmd(sc, MYXCMD_GET_TXRINGSZ, &mc, 1040 &sc->sc_txringsize) == 0 && sc->sc_txringsize && 1041 myx_cmd(sc, MYXCMD_GET_TXRINGOFF, &mc, 1042 &sc->sc_txringoff) == 0 && sc->sc_txringoff)) { 1043 printf("%s: failed to get ring sizes and offsets\n", 1044 DEVNAME(sc)); 1045 return (-1); 1046 } 1047 sc->sc_rxndesc = sc->sc_rxringsize / sizeof(struct myx_rxbufdesc); 1048 sc->sc_txndesc = sc->sc_txringsize / sizeof(struct myx_txdesc); 1049 sc->sc_rxdescsize = sc->sc_rxndesc * 2 * sizeof(struct myx_rxdesc); 1050 sc->sc_rxbufsize = sc->sc_rxndesc * sizeof(struct myx_buf); 1051 sc->sc_rxbufdescsize = sc->sc_rxndesc * sizeof(struct myx_rxbufdesc); 1052 IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_txndesc - 1); 1053 IFQ_SET_READY(&ifp->if_snd); 1054 1055 DPRINTF(MYXDBG_INIT, "%s(%s): Rx ring ndesc %u size %u bufsize %u, " 1056 "Tx ring ndesc %u size %u offset 0x%x\n", DEVNAME(sc), __func__, 1057 sc->sc_rxndesc, sc->sc_rxdescsize, sc->sc_rxringsize, 1058 sc->sc_txndesc, sc->sc_txringsize, sc->sc_txringoff); 1059 1060 /* 1061 * Setup Rx DMA descriptors 1062 */ 1063 if (myx_dmamem_alloc(sc, &sc->sc_rxdma, 1064 sc->sc_rxdescsize, MYXALIGN_DATA, "rxring") != 0) { 1065 printf(": failed to allocate Rx DMA memory\n"); 1066 return (-1); 1067 } 1068 sc->sc_rxdesc = (struct myx_rxdesc *)sc->sc_rxdma.mxm_kva; 1069 1070 bzero(&mc, sizeof(mc)); 1071 mc.mc_data0 = htobe32(sc->sc_rxdescsize); 1072 if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) { 1073 printf("%s: failed to set Rx DMA size\n", DEVNAME(sc)); 1074 goto err; 1075 } 1076 1077 map = sc->sc_rxdma.mxm_map; 1078 mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr); 1079 mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); 1080 if (myx_cmd(sc, MYXCMD_SET_INTRQDMA, &mc, NULL) != 0) { 1081 printf("%s: failed to set Rx DMA address\n", DEVNAME(sc)); 1082 goto err; 1083 } 1084 1085#ifdef notyet 1086 /* 1087 * XXX It fails to set the MTU and it always returns 1088 * XXX MYXCMD_ERR_RANGE. 1089 */ 1090 bzero(&mc, sizeof(mc)); 1091 mc.mc_data0 = ifp->if_mtu + ETHER_HDR_LEN + 4; 1092 if (myx_cmd(sc, MYXCMD_SET_MTU, &mc, NULL) != 0) { 1093 printf("%s: failed to set MTU size %d\n", 1094 DEVNAME(sc), ifp->if_mtu + ETHER_HDR_LEN + 4); 1095 goto err; 1096 } 1097#endif 1098 1099 /* 1100 * Setup Rx buffer descriptors 1101 */ 1102 sc->sc_rxbuf[MYX_RXSMALL] = (struct myx_buf *) 1103 malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK); 1104 sc->sc_rxbufdesc[MYX_RXSMALL] = (struct myx_rxbufdesc *) 1105 malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK); 1106 sc->sc_rxbuf[MYX_RXBIG] = (struct myx_buf *) 1107 malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK); 1108 sc->sc_rxbufdesc[MYX_RXBIG] = (struct myx_rxbufdesc *) 1109 malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK); 1110 if (sc->sc_rxbuf[MYX_RXSMALL] == NULL || 1111 sc->sc_rxbufdesc[MYX_RXSMALL] == NULL || 1112 sc->sc_rxbuf[MYX_RXBIG] == NULL || 1113 sc->sc_rxbufdesc[MYX_RXBIG] == NULL) { 1114 printf("%s: failed to allocate rx buffers\n", DEVNAME(sc)); 1115 goto err; 1116 } 1117 1118 for (i = 0; i < sc->sc_rxndesc; i++) { 1119 /* 1120 * Small Rx buffers and descriptors 1121 */ 1122 mb = sc->sc_rxbuf[MYX_RXSMALL] + i; 1123 rxb = sc->sc_rxbufdesc[MYX_RXSMALL] + i; 1124 1125 if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 1126 MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) { 1127 printf("%s: unable to create dmamap for small rx %d\n", 1128 DEVNAME(sc), i); 1129 goto err; 1130 } 1131 1132 map = mb->mb_dmamap; 1133 mb->mb_m = myx_getbuf(sc, map, 1); 1134 if (mb->mb_m == NULL) { 1135 bus_dmamap_destroy(sc->sc_dmat, map); 1136 goto err; 1137 } 1138 1139 bus_dmamap_sync(sc->sc_dmat, map, 0, 1140 mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD); 1141 1142 rxb->rb_addr_high = 1143 htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 1144 rxb->rb_addr_low = 1145 htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 1146 1147 data = sc->sc_rxsmallringoff + i * sizeof(*rxb); 1148 myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb)); 1149 1150 /* 1151 * Big Rx buffers and descriptors 1152 */ 1153 mb = sc->sc_rxbuf[MYX_RXBIG] + i; 1154 rxb = sc->sc_rxbufdesc[MYX_RXBIG] + i; 1155 1156 if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, 1157 MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) { 1158 printf("%s: unable to create dmamap for big rx %d\n", 1159 DEVNAME(sc), i); 1160 goto err; 1161 } 1162 1163 map = mb->mb_dmamap; 1164 mb->mb_m = myx_getbuf(sc, map, 1); 1165 if (mb->mb_m == NULL) { 1166 bus_dmamap_destroy(sc->sc_dmat, map); 1167 goto err; 1168 } 1169 1170 bus_dmamap_sync(sc->sc_dmat, map, 0, 1171 mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD); 1172 1173 rxb->rb_addr_high = 1174 htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 1175 rxb->rb_addr_low = 1176 htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr)); 1177 1178 data = sc->sc_rxbigringoff + i * sizeof(*rxb); 1179 myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb)); 1180 } 1181 1182 bzero(&mc, sizeof(mc)); 1183 mc.mc_data0 = MYX_MAX_MTU_SMALL; 1184 if (myx_cmd(sc, MYXCMD_SET_SMALLBUFSZ, &mc, NULL) != 0) { 1185 printf("%s: failed to set small buf size\n", DEVNAME(sc)); 1186 goto err; 1187 } 1188 1189 bzero(&mc, sizeof(mc)); 1190 mc.mc_data0 = MCLBYTES; 1191 if (myx_cmd(sc, MYXCMD_SET_BIGBUFSZ, &mc, NULL) != 0) { 1192 printf("%s: failed to set big buf size\n", DEVNAME(sc)); 1193 goto err; 1194 } 1195 1196 /* 1197 * Setup status DMA 1198 */ 1199 map = sc->sc_stsdma.mxm_map; 1200 1201 bzero(&mc, sizeof(mc)); 1202 mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr); 1203 mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr); 1204 mc.mc_data2 = sizeof(struct myx_status); 1205 if (myx_cmd(sc, MYXCMD_SET_STATSDMA, &mc, NULL) != 0) { 1206 printf("%s: failed to set status DMA offset\n", DEVNAME(sc)); 1207 goto err; 1208 } 1209 1210 bus_dmamap_sync(sc->sc_dmat, map, 0, 1211 map->dm_mapsize, BUS_DMASYNC_PREWRITE); 1212 1213 return (0); 1214 err: 1215 myx_free_rings(sc); 1216 return (-1); 1217} 1218 1219void 1220myx_free_rings(struct myx_softc *sc) 1221{ 1222 if (sc->sc_rxbuf[MYX_RXSMALL] != NULL) { 1223 free(sc->sc_rxbuf[MYX_RXSMALL], M_DEVBUF); 1224 sc->sc_rxbuf[MYX_RXSMALL] = NULL; 1225 } 1226 if (sc->sc_rxbufdesc[MYX_RXSMALL] != NULL) { 1227 free(sc->sc_rxbufdesc[MYX_RXSMALL], M_DEVBUF); 1228 sc->sc_rxbufdesc[MYX_RXSMALL] = NULL; 1229 } 1230 if (sc->sc_rxbuf[MYX_RXBIG] != NULL) { 1231 free(sc->sc_rxbuf[MYX_RXBIG], M_DEVBUF); 1232 sc->sc_rxbuf[MYX_RXBIG] = NULL; 1233 } 1234 if (sc->sc_rxbufdesc[MYX_RXBIG] != NULL) { 1235 free(sc->sc_rxbufdesc[MYX_RXBIG], M_DEVBUF); 1236 sc->sc_rxbufdesc[MYX_RXBIG] = NULL; 1237 } 1238 if (sc->sc_rxdesc != NULL) { 1239 myx_dmamem_free(sc, &sc->sc_rxdma); 1240 sc->sc_rxdesc = NULL; 1241 } 1242 if (sc->sc_sts != NULL) { 1243 myx_dmamem_free(sc, &sc->sc_stsdma); 1244 sc->sc_sts = NULL; 1245 } 1246 return; 1247} 1248 1249struct mbuf * 1250myx_getbuf(struct myx_softc *sc, bus_dmamap_t map, int wait) 1251{ 1252 struct mbuf *m = NULL; 1253 1254 MGETHDR(m, wait ? M_WAIT : M_DONTWAIT, MT_DATA); 1255 if (m == NULL) 1256 goto merr; 1257 1258 MCLGET(m, wait ? M_WAIT : M_DONTWAIT); 1259 if ((m->m_flags & M_EXT) == 0) 1260 goto merr; 1261 m->m_len = m->m_pkthdr.len = MCLBYTES; 1262 1263 if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m, 1264 wait ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) != 0) { 1265 printf("%s: could not load mbuf dma map\n", DEVNAME(sc)); 1266 goto err; 1267 } 1268 1269 return (m); 1270 merr: 1271 printf("%s: unable to allocate mbuf\n", DEVNAME(sc)); 1272 err: 1273 if (m != NULL) 1274 m_freem(m); 1275 return (NULL); 1276} 1277