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 : ®, 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 : }
|