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