if_myx.c revision 1.120
1/*	$OpenBSD: if_myx.c,v 1.120 2024/05/24 06:02:56 jsg 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#include "kstat.h"
25
26#include <sys/param.h>
27#include <sys/systm.h>
28#include <sys/sockio.h>
29#include <sys/mbuf.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/rwlock.h>
36#include <sys/kstat.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 */
63int 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
74struct 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
82struct pool *myx_mcl_pool;
83
84struct myx_slot {
85	bus_dmamap_t		 ms_map;
86	struct mbuf		*ms_m;
87};
88
89struct 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
101enum myx_state {
102	MYX_S_OFF = 0,
103	MYX_S_RUNNING,
104	MYX_S_DOWN
105};
106
107struct 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	struct rwlock		 sc_sff_lock;
161
162#if NKSTAT > 0
163	struct mutex		 sc_kstat_mtx;
164	struct timeout		 sc_kstat_tmo;
165	struct kstat		*sc_kstat;
166#endif
167};
168
169#define MYX_RXSMALL_SIZE	MCLBYTES
170#define MYX_RXBIG_SIZE		(MYX_MTU - \
171    (ETHER_ALIGN + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN))
172
173int	 myx_match(struct device *, void *, void *);
174void	 myx_attach(struct device *, struct device *, void *);
175int	 myx_pcie_dc(struct myx_softc *, struct pci_attach_args *);
176int	 myx_query(struct myx_softc *sc, char *, size_t);
177u_int	 myx_ether_aton(char *, u_int8_t *, u_int);
178void	 myx_attachhook(struct device *);
179int	 myx_loadfirmware(struct myx_softc *, const char *);
180int	 myx_probe_firmware(struct myx_softc *);
181
182void	 myx_read(struct myx_softc *, bus_size_t, void *, bus_size_t);
183void	 myx_write(struct myx_softc *, bus_size_t, void *, bus_size_t);
184
185#if defined(__LP64__)
186#define _myx_bus_space_write bus_space_write_raw_region_8
187typedef u_int64_t myx_bus_t;
188#else
189#define _myx_bus_space_write bus_space_write_raw_region_4
190typedef u_int32_t myx_bus_t;
191#endif
192#define myx_bus_space_write(_sc, _o, _a, _l) \
193    _myx_bus_space_write((_sc)->sc_memt, (_sc)->sc_memh, (_o), (_a), (_l))
194
195int	 myx_cmd(struct myx_softc *, u_int32_t, struct myx_cmd *, u_int32_t *);
196int	 myx_boot(struct myx_softc *, u_int32_t);
197
198int	 myx_rdma(struct myx_softc *, u_int);
199int	 myx_dmamem_alloc(struct myx_softc *, struct myx_dmamem *,
200	    bus_size_t, u_int align);
201void	 myx_dmamem_free(struct myx_softc *, struct myx_dmamem *);
202int	 myx_media_change(struct ifnet *);
203void	 myx_media_status(struct ifnet *, struct ifmediareq *);
204void	 myx_link_state(struct myx_softc *, u_int32_t);
205void	 myx_watchdog(struct ifnet *);
206int	 myx_ioctl(struct ifnet *, u_long, caddr_t);
207int	 myx_rxrinfo(struct myx_softc *, struct if_rxrinfo *);
208void	 myx_up(struct myx_softc *);
209void	 myx_iff(struct myx_softc *);
210void	 myx_down(struct myx_softc *);
211int	 myx_get_sffpage(struct myx_softc *, struct if_sffpage *);
212
213void	 myx_start(struct ifqueue *);
214void	 myx_write_txd_tail(struct myx_softc *, struct myx_slot *, u_int8_t,
215	    u_int32_t, u_int);
216int	 myx_load_mbuf(struct myx_softc *, struct myx_slot *, struct mbuf *);
217int	 myx_setlladdr(struct myx_softc *, u_int32_t, u_int8_t *);
218int	 myx_intr(void *);
219void	 myx_rxeof(struct myx_softc *);
220void	 myx_txeof(struct myx_softc *, u_int32_t);
221
222int			myx_buf_fill(struct myx_softc *, struct myx_slot *,
223			    struct mbuf *(*)(void));
224struct mbuf *		myx_mcl_small(void);
225struct mbuf *		myx_mcl_big(void);
226
227int			myx_rx_init(struct myx_softc *, int, bus_size_t);
228int			myx_rx_fill(struct myx_softc *, struct myx_rx_ring *);
229void			myx_rx_empty(struct myx_softc *, struct myx_rx_ring *);
230void			myx_rx_free(struct myx_softc *, struct myx_rx_ring *);
231
232int			myx_tx_init(struct myx_softc *, bus_size_t);
233void			myx_tx_empty(struct myx_softc *);
234void			myx_tx_free(struct myx_softc *);
235
236void			myx_refill(void *);
237
238#if NKSTAT > 0
239void			myx_kstat_attach(struct myx_softc *);
240void			myx_kstat_start(struct myx_softc *);
241void			myx_kstat_stop(struct myx_softc *);
242#endif
243
244struct cfdriver myx_cd = {
245	NULL, "myx", DV_IFNET
246};
247const struct cfattach myx_ca = {
248	sizeof(struct myx_softc), myx_match, myx_attach
249};
250
251const struct pci_matchid myx_devices[] = {
252	{ PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E },
253	{ PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E_9 }
254};
255
256int
257myx_match(struct device *parent, void *match, void *aux)
258{
259	return (pci_matchbyid(aux, myx_devices, nitems(myx_devices)));
260}
261
262void
263myx_attach(struct device *parent, struct device *self, void *aux)
264{
265	struct myx_softc	*sc = (struct myx_softc *)self;
266	struct pci_attach_args	*pa = aux;
267	char			 part[32];
268	pcireg_t		 memtype;
269
270	rw_init(&sc->sc_sff_lock, "myxsff");
271
272	sc->sc_pc = pa->pa_pc;
273	sc->sc_tag = pa->pa_tag;
274	sc->sc_dmat = pa->pa_dmat;
275
276	sc->sc_rx_ring[MYX_RXSMALL].mrr_softc = sc;
277	sc->sc_rx_ring[MYX_RXSMALL].mrr_mclget = myx_mcl_small;
278	timeout_set(&sc->sc_rx_ring[MYX_RXSMALL].mrr_refill, myx_refill,
279	    &sc->sc_rx_ring[MYX_RXSMALL]);
280	sc->sc_rx_ring[MYX_RXBIG].mrr_softc = sc;
281	sc->sc_rx_ring[MYX_RXBIG].mrr_mclget = myx_mcl_big;
282	timeout_set(&sc->sc_rx_ring[MYX_RXBIG].mrr_refill, myx_refill,
283	    &sc->sc_rx_ring[MYX_RXBIG]);
284
285	/* Map the PCI memory space */
286	memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, MYXBAR0);
287	if (pci_mapreg_map(pa, MYXBAR0, memtype, BUS_SPACE_MAP_PREFETCHABLE,
288	    &sc->sc_memt, &sc->sc_memh, NULL, &sc->sc_mems, 0)) {
289		printf(": unable to map register memory\n");
290		return;
291	}
292
293	/* Get board details (mac/part) */
294	memset(part, 0, sizeof(part));
295	if (myx_query(sc, part, sizeof(part)) != 0)
296		goto unmap;
297
298	/* Map the interrupt */
299	if (pci_intr_map_msi(pa, &sc->sc_ih) != 0) {
300		if (pci_intr_map(pa, &sc->sc_ih) != 0) {
301			printf(": unable to map interrupt\n");
302			goto unmap;
303		}
304		sc->sc_intx = 1;
305	}
306
307	printf(": %s, model %s, address %s\n",
308	    pci_intr_string(pa->pa_pc, sc->sc_ih),
309	    part[0] == '\0' ? "(unknown)" : part,
310	    ether_sprintf(sc->sc_ac.ac_enaddr));
311
312	if (myx_pcie_dc(sc, pa) != 0)
313		printf("%s: unable to configure PCI Express\n", DEVNAME(sc));
314
315	config_mountroot(self, myx_attachhook);
316
317	return;
318
319 unmap:
320	bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
321	sc->sc_mems = 0;
322}
323
324int
325myx_pcie_dc(struct myx_softc *sc, struct pci_attach_args *pa)
326{
327	pcireg_t dcsr;
328	pcireg_t mask = PCI_PCIE_DCSR_MPS | PCI_PCIE_DCSR_ERO;
329	pcireg_t dc = ((fls(4096) - 8) << 12) | PCI_PCIE_DCSR_ERO;
330	int reg;
331
332	if (pci_get_capability(sc->sc_pc, pa->pa_tag, PCI_CAP_PCIEXPRESS,
333	    &reg, NULL) == 0)
334		return (-1);
335
336	reg += PCI_PCIE_DCSR;
337	dcsr = pci_conf_read(sc->sc_pc, pa->pa_tag, reg);
338	if ((dcsr & mask) != dc) {
339		CLR(dcsr, mask);
340		SET(dcsr, dc);
341		pci_conf_write(sc->sc_pc, pa->pa_tag, reg, dcsr);
342	}
343
344	return (0);
345}
346
347u_int
348myx_ether_aton(char *mac, u_int8_t *lladdr, u_int maxlen)
349{
350	u_int		i, j;
351	u_int8_t	digit;
352
353	memset(lladdr, 0, ETHER_ADDR_LEN);
354	for (i = j = 0; mac[i] != '\0' && i < maxlen; i++) {
355		if (mac[i] >= '0' && mac[i] <= '9')
356			digit = mac[i] - '0';
357		else if (mac[i] >= 'A' && mac[i] <= 'F')
358			digit = mac[i] - 'A' + 10;
359		else if (mac[i] >= 'a' && mac[i] <= 'f')
360			digit = mac[i] - 'a' + 10;
361		else
362			continue;
363		if ((j & 1) == 0)
364			digit <<= 4;
365		lladdr[j++/2] |= digit;
366	}
367
368	return (i);
369}
370
371int
372myx_query(struct myx_softc *sc, char *part, size_t partlen)
373{
374	struct myx_gen_hdr hdr;
375	u_int32_t	offset;
376	u_int8_t	strings[MYX_STRING_SPECS_SIZE];
377	u_int		i, len, maxlen;
378
379	myx_read(sc, MYX_HEADER_POS, &offset, sizeof(offset));
380	offset = betoh32(offset);
381	if (offset + sizeof(hdr) > sc->sc_mems) {
382		printf(": header is outside register window\n");
383		return (1);
384	}
385
386	myx_read(sc, offset, &hdr, sizeof(hdr));
387	offset = betoh32(hdr.fw_specs);
388	len = min(betoh32(hdr.fw_specs_len), sizeof(strings));
389
390	bus_space_read_region_1(sc->sc_memt, sc->sc_memh, offset, strings, len);
391
392	for (i = 0; i < len; i++) {
393		maxlen = len - i;
394		if (strings[i] == '\0')
395			break;
396		if (maxlen > 4 && memcmp("MAC=", &strings[i], 4) == 0) {
397			i += 4;
398			i += myx_ether_aton(&strings[i],
399			    sc->sc_ac.ac_enaddr, maxlen);
400		} else if (maxlen > 3 && memcmp("PC=", &strings[i], 3) == 0) {
401			i += 3;
402			i += strlcpy(part, &strings[i], min(maxlen, partlen));
403		}
404		for (; i < len; i++) {
405			if (strings[i] == '\0')
406				break;
407		}
408	}
409
410	return (0);
411}
412
413int
414myx_loadfirmware(struct myx_softc *sc, const char *filename)
415{
416	struct myx_gen_hdr	hdr;
417	u_int8_t		*fw;
418	size_t			fwlen;
419	u_int32_t		offset;
420	u_int			i, ret = 1;
421
422	if (loadfirmware(filename, &fw, &fwlen) != 0) {
423		printf("%s: could not load firmware %s\n", DEVNAME(sc),
424		    filename);
425		return (1);
426	}
427	if (fwlen > MYX_SRAM_SIZE || fwlen < MYXFW_MIN_LEN) {
428		printf("%s: invalid firmware %s size\n", DEVNAME(sc), filename);
429		goto err;
430	}
431
432	memcpy(&offset, fw + MYX_HEADER_POS, sizeof(offset));
433	offset = betoh32(offset);
434	if ((offset + sizeof(hdr)) > fwlen) {
435		printf("%s: invalid firmware %s\n", DEVNAME(sc), filename);
436		goto err;
437	}
438
439	memcpy(&hdr, fw + offset, sizeof(hdr));
440	DPRINTF(MYXDBG_INIT, "%s: "
441	    "fw hdr off %u, length %u, type 0x%x, version %s\n",
442	    DEVNAME(sc), offset, betoh32(hdr.fw_hdrlength),
443	    betoh32(hdr.fw_type), hdr.fw_version);
444
445	if (betoh32(hdr.fw_type) != MYXFW_TYPE_ETH ||
446	    memcmp(MYXFW_VER, hdr.fw_version, strlen(MYXFW_VER)) != 0) {
447		printf("%s: invalid firmware type 0x%x version %s\n",
448		    DEVNAME(sc), betoh32(hdr.fw_type), hdr.fw_version);
449		goto err;
450	}
451
452	/* Write the firmware to the card's SRAM */
453	for (i = 0; i < fwlen; i += 256)
454		myx_write(sc, i + MYX_FW, fw + i, min(256, fwlen - i));
455
456	if (myx_boot(sc, fwlen) != 0) {
457		printf("%s: failed to boot %s\n", DEVNAME(sc), filename);
458		goto err;
459	}
460
461	ret = 0;
462
463err:
464	free(fw, M_DEVBUF, fwlen);
465	return (ret);
466}
467
468void
469myx_attachhook(struct device *self)
470{
471	struct myx_softc	*sc = (struct myx_softc *)self;
472	struct ifnet		*ifp = &sc->sc_ac.ac_if;
473	struct myx_cmd		 mc;
474
475	/* this is sort of racy */
476	if (myx_mcl_pool == NULL) {
477		myx_mcl_pool = malloc(sizeof(*myx_mcl_pool), M_DEVBUF,
478		    M_WAITOK);
479
480		m_pool_init(myx_mcl_pool, MYX_RXBIG_SIZE, MYX_BOUNDARY,
481		    "myxmcl");
482		pool_cache_init(myx_mcl_pool);
483	}
484
485	/* Allocate command DMA memory */
486	if (myx_dmamem_alloc(sc, &sc->sc_cmddma, MYXALIGN_CMD,
487	    MYXALIGN_CMD) != 0) {
488		printf("%s: failed to allocate command DMA memory\n",
489		    DEVNAME(sc));
490		return;
491	}
492
493	/* Try the firmware stored on disk */
494	if (myx_loadfirmware(sc, MYXFW_ALIGNED) != 0) {
495		/* error printed by myx_loadfirmware */
496		goto freecmd;
497	}
498
499	memset(&mc, 0, sizeof(mc));
500
501	if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
502		printf("%s: failed to reset the device\n", DEVNAME(sc));
503		goto freecmd;
504	}
505
506	sc->sc_tx_boundary = 4096;
507
508	if (myx_probe_firmware(sc) != 0) {
509		printf("%s: error while selecting firmware\n", DEVNAME(sc));
510		goto freecmd;
511	}
512
513	sc->sc_irqh = pci_intr_establish(sc->sc_pc, sc->sc_ih,
514	    IPL_NET | IPL_MPSAFE, myx_intr, sc, DEVNAME(sc));
515	if (sc->sc_irqh == NULL) {
516		printf("%s: unable to establish interrupt\n", DEVNAME(sc));
517		goto freecmd;
518	}
519
520#if NKSTAT > 0
521	myx_kstat_attach(sc);
522#endif
523
524	ifp->if_softc = sc;
525	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
526	ifp->if_xflags = IFXF_MPSAFE;
527	ifp->if_ioctl = myx_ioctl;
528	ifp->if_qstart = myx_start;
529	ifp->if_watchdog = myx_watchdog;
530	ifp->if_hardmtu = MYX_RXBIG_SIZE;
531	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
532	ifq_init_maxlen(&ifp->if_snd, 1);
533
534	ifp->if_capabilities = IFCAP_VLAN_MTU;
535#if 0
536	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
537	ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
538	    IFCAP_CSUM_UDPv4;
539#endif
540
541	ifmedia_init(&sc->sc_media, 0, myx_media_change, myx_media_status);
542	ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_AUTO, 0, NULL);
543	ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_AUTO);
544
545	if_attach(ifp);
546	ether_ifattach(ifp);
547
548	return;
549
550freecmd:
551	myx_dmamem_free(sc, &sc->sc_cmddma);
552}
553
554int
555myx_probe_firmware(struct myx_softc *sc)
556{
557	struct myx_dmamem test;
558	bus_dmamap_t map;
559	struct myx_cmd mc;
560	pcireg_t csr;
561	int offset;
562	int width = 0;
563
564	if (pci_get_capability(sc->sc_pc, sc->sc_tag, PCI_CAP_PCIEXPRESS,
565	    &offset, NULL)) {
566		csr = pci_conf_read(sc->sc_pc, sc->sc_tag,
567		    offset + PCI_PCIE_LCSR);
568		width = (csr >> 20) & 0x3f;
569
570		if (width <= 4) {
571			/*
572			 * if the link width is 4 or less we can use the
573			 * aligned firmware.
574			 */
575			return (0);
576		}
577	}
578
579	if (myx_dmamem_alloc(sc, &test, 4096, 4096) != 0)
580		return (1);
581	map = test.mxm_map;
582
583	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
584	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
585
586	memset(&mc, 0, sizeof(mc));
587	mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
588	mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
589	mc.mc_data2 = htobe32(4096 * 0x10000);
590	if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) {
591		printf("%s: DMA read test failed\n", DEVNAME(sc));
592		goto fail;
593	}
594
595	memset(&mc, 0, sizeof(mc));
596	mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
597	mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
598	mc.mc_data2 = htobe32(4096 * 0x1);
599	if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) {
600		printf("%s: DMA write test failed\n", DEVNAME(sc));
601		goto fail;
602	}
603
604	memset(&mc, 0, sizeof(mc));
605	mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
606	mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
607	mc.mc_data2 = htobe32(4096 * 0x10001);
608	if (myx_cmd(sc, MYXCMD_UNALIGNED_DMA_TEST, &mc, NULL) != 0) {
609		printf("%s: DMA read/write test failed\n", DEVNAME(sc));
610		goto fail;
611	}
612
613	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
614	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
615	myx_dmamem_free(sc, &test);
616	return (0);
617
618fail:
619	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
620	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
621	myx_dmamem_free(sc, &test);
622
623	if (myx_loadfirmware(sc, MYXFW_UNALIGNED) != 0) {
624		printf("%s: unable to load %s\n", DEVNAME(sc),
625		    MYXFW_UNALIGNED);
626		return (1);
627	}
628
629	sc->sc_tx_boundary = 2048;
630
631	printf("%s: using unaligned firmware\n", DEVNAME(sc));
632	return (0);
633}
634
635void
636myx_read(struct myx_softc *sc, bus_size_t off, void *ptr, bus_size_t len)
637{
638	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
639	    BUS_SPACE_BARRIER_READ);
640	bus_space_read_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
641}
642
643void
644myx_write(struct myx_softc *sc, bus_size_t off, void *ptr, bus_size_t len)
645{
646	bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
647	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
648	    BUS_SPACE_BARRIER_WRITE);
649}
650
651int
652myx_dmamem_alloc(struct myx_softc *sc, struct myx_dmamem *mxm,
653    bus_size_t size, u_int align)
654{
655	mxm->mxm_size = size;
656
657	if (bus_dmamap_create(sc->sc_dmat, mxm->mxm_size, 1,
658	    mxm->mxm_size, 0,
659	    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
660	    &mxm->mxm_map) != 0)
661		return (1);
662	if (bus_dmamem_alloc(sc->sc_dmat, mxm->mxm_size,
663	    align, 0, &mxm->mxm_seg, 1, &mxm->mxm_nsegs,
664	    BUS_DMA_WAITOK | BUS_DMA_ZERO) != 0)
665		goto destroy;
666	if (bus_dmamem_map(sc->sc_dmat, &mxm->mxm_seg, mxm->mxm_nsegs,
667	    mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_WAITOK) != 0)
668		goto free;
669	if (bus_dmamap_load(sc->sc_dmat, mxm->mxm_map, mxm->mxm_kva,
670	    mxm->mxm_size, NULL, BUS_DMA_WAITOK) != 0)
671		goto unmap;
672
673	return (0);
674 unmap:
675	bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
676 free:
677	bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
678 destroy:
679	bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
680	return (1);
681}
682
683void
684myx_dmamem_free(struct myx_softc *sc, struct myx_dmamem *mxm)
685{
686	bus_dmamap_unload(sc->sc_dmat, mxm->mxm_map);
687	bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
688	bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
689	bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
690}
691
692int
693myx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r)
694{
695	bus_dmamap_t		 map = sc->sc_cmddma.mxm_map;
696	struct myx_response	*mr;
697	u_int			 i;
698	u_int32_t		 result, data;
699
700	mc->mc_cmd = htobe32(cmd);
701	mc->mc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
702	mc->mc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
703
704	mr = (struct myx_response *)sc->sc_cmddma.mxm_kva;
705	mr->mr_result = 0xffffffff;
706
707	/* Send command */
708	myx_write(sc, MYX_CMD, (u_int8_t *)mc, sizeof(struct myx_cmd));
709	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
710	    BUS_DMASYNC_PREREAD);
711
712	for (i = 0; i < 20; i++) {
713		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
714		    BUS_DMASYNC_POSTREAD);
715		result = betoh32(mr->mr_result);
716		data = betoh32(mr->mr_data);
717
718		if (result != 0xffffffff)
719			break;
720
721		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
722		    BUS_DMASYNC_PREREAD);
723		delay(1000);
724	}
725
726	DPRINTF(MYXDBG_CMD, "%s(%s): cmd %u completed, i %d, "
727	    "result 0x%x, data 0x%x (%u)\n", DEVNAME(sc), __func__,
728	    cmd, i, result, data, data);
729
730	if (result == MYXCMD_OK) {
731		if (r != NULL)
732			*r = data;
733	}
734
735	return (result);
736}
737
738int
739myx_boot(struct myx_softc *sc, u_int32_t length)
740{
741	struct myx_bootcmd	 bc;
742	bus_dmamap_t		 map = sc->sc_cmddma.mxm_map;
743	u_int32_t		*status;
744	u_int			 i, ret = 1;
745
746	memset(&bc, 0, sizeof(bc));
747	bc.bc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
748	bc.bc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
749	bc.bc_result = 0xffffffff;
750	bc.bc_offset = htobe32(MYX_FW_BOOT);
751	bc.bc_length = htobe32(length - 8);
752	bc.bc_copyto = htobe32(8);
753	bc.bc_jumpto = htobe32(0);
754
755	status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
756	*status = 0;
757
758	/* Send command */
759	myx_write(sc, MYX_BOOT, &bc, sizeof(bc));
760	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
761	    BUS_DMASYNC_PREREAD);
762
763	for (i = 0; i < 200; i++) {
764		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
765		    BUS_DMASYNC_POSTREAD);
766		if (*status == 0xffffffff) {
767			ret = 0;
768			break;
769		}
770
771		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
772		    BUS_DMASYNC_PREREAD);
773		delay(1000);
774	}
775
776	DPRINTF(MYXDBG_CMD, "%s: boot completed, i %d, result %d\n",
777	    DEVNAME(sc), i, ret);
778
779	return (ret);
780}
781
782int
783myx_rdma(struct myx_softc *sc, u_int do_enable)
784{
785	struct myx_rdmacmd	 rc;
786	bus_dmamap_t		 map = sc->sc_cmddma.mxm_map;
787	bus_dmamap_t		 pad = sc->sc_paddma.mxm_map;
788	u_int32_t		*status;
789	int			 ret = 1;
790	u_int			 i;
791
792	/*
793	 * It is required to setup a _dummy_ RDMA address. It also makes
794	 * some PCI-E chipsets resend dropped messages.
795	 */
796	rc.rc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
797	rc.rc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
798	rc.rc_result = 0xffffffff;
799	rc.rc_rdma_high = htobe32(MYX_ADDRHIGH(pad->dm_segs[0].ds_addr));
800	rc.rc_rdma_low = htobe32(MYX_ADDRLOW(pad->dm_segs[0].ds_addr));
801	rc.rc_enable = htobe32(do_enable);
802
803	status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
804	*status = 0;
805
806	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
807	    BUS_DMASYNC_PREREAD);
808
809	/* Send command */
810	myx_write(sc, MYX_RDMA, &rc, sizeof(rc));
811
812	for (i = 0; i < 20; i++) {
813		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
814		    BUS_DMASYNC_POSTREAD);
815
816		if (*status == 0xffffffff) {
817			ret = 0;
818			break;
819		}
820
821		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
822		    BUS_DMASYNC_PREREAD);
823		delay(1000);
824	}
825
826	DPRINTF(MYXDBG_CMD, "%s(%s): dummy RDMA %s, i %d, result 0x%x\n",
827	    DEVNAME(sc), __func__,
828	    do_enable ? "enabled" : "disabled", i, betoh32(*status));
829
830	return (ret);
831}
832
833int
834myx_media_change(struct ifnet *ifp)
835{
836	/* ignore */
837	return (0);
838}
839
840void
841myx_media_status(struct ifnet *ifp, struct ifmediareq *imr)
842{
843	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
844	bus_dmamap_t		 map = sc->sc_sts_dma.mxm_map;
845	u_int32_t		 sts;
846
847	imr->ifm_active = IFM_ETHER | IFM_AUTO;
848	if (!ISSET(ifp->if_flags, IFF_RUNNING)) {
849		imr->ifm_status = 0;
850		return;
851	}
852
853	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
854	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
855	sts = sc->sc_sts->ms_linkstate;
856	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
857	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
858
859	myx_link_state(sc, sts);
860
861	imr->ifm_status = IFM_AVALID;
862	if (!LINK_STATE_IS_UP(ifp->if_link_state))
863		return;
864
865	imr->ifm_active |= IFM_FDX | IFM_FLOW |
866	    IFM_ETH_RXPAUSE | IFM_ETH_TXPAUSE;
867	imr->ifm_status |= IFM_ACTIVE;
868}
869
870void
871myx_link_state(struct myx_softc *sc, u_int32_t sts)
872{
873	struct ifnet		*ifp = &sc->sc_ac.ac_if;
874	int			 link_state = LINK_STATE_DOWN;
875
876	if (betoh32(sts) == MYXSTS_LINKUP)
877		link_state = LINK_STATE_FULL_DUPLEX;
878	if (ifp->if_link_state != link_state) {
879		ifp->if_link_state = link_state;
880		if_link_state_change(ifp);
881		ifp->if_baudrate = LINK_STATE_IS_UP(ifp->if_link_state) ?
882		    IF_Gbps(10) : 0;
883	}
884}
885
886void
887myx_watchdog(struct ifnet *ifp)
888{
889	return;
890}
891
892int
893myx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
894{
895	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
896	struct ifreq		*ifr = (struct ifreq *)data;
897	int			 s, error = 0;
898
899	s = splnet();
900
901	switch (cmd) {
902	case SIOCSIFADDR:
903		ifp->if_flags |= IFF_UP;
904		/* FALLTHROUGH */
905
906	case SIOCSIFFLAGS:
907		if (ISSET(ifp->if_flags, IFF_UP)) {
908			if (ISSET(ifp->if_flags, IFF_RUNNING))
909				error = ENETRESET;
910			else
911				myx_up(sc);
912		} else {
913			if (ISSET(ifp->if_flags, IFF_RUNNING))
914				myx_down(sc);
915		}
916		break;
917
918	case SIOCGIFMEDIA:
919	case SIOCSIFMEDIA:
920		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
921		break;
922
923	case SIOCGIFRXR:
924		error = myx_rxrinfo(sc, (struct if_rxrinfo *)ifr->ifr_data);
925		break;
926
927	case SIOCGIFSFFPAGE:
928		error = rw_enter(&sc->sc_sff_lock, RW_WRITE|RW_INTR);
929		if (error != 0)
930			break;
931
932		error = myx_get_sffpage(sc, (struct if_sffpage *)data);
933		rw_exit(&sc->sc_sff_lock);
934		break;
935
936	default:
937		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
938	}
939
940	if (error == ENETRESET) {
941		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
942		    (IFF_UP | IFF_RUNNING))
943			myx_iff(sc);
944		error = 0;
945	}
946
947	splx(s);
948	return (error);
949}
950
951int
952myx_rxrinfo(struct myx_softc *sc, struct if_rxrinfo *ifri)
953{
954	struct if_rxring_info ifr[2];
955
956	memset(ifr, 0, sizeof(ifr));
957
958	ifr[0].ifr_size = MYX_RXSMALL_SIZE;
959	ifr[0].ifr_info = sc->sc_rx_ring[0].mrr_rxr;
960	strlcpy(ifr[0].ifr_name, "small", sizeof(ifr[0].ifr_name));
961
962	ifr[1].ifr_size = MYX_RXBIG_SIZE;
963	ifr[1].ifr_info = sc->sc_rx_ring[1].mrr_rxr;
964	strlcpy(ifr[1].ifr_name, "large", sizeof(ifr[1].ifr_name));
965
966	return (if_rxr_info_ioctl(ifri, nitems(ifr), ifr));
967}
968
969static int
970myx_i2c_byte(struct myx_softc *sc, uint8_t addr, uint8_t off, uint8_t *byte)
971{
972	struct myx_cmd		mc;
973	int			result;
974	uint32_t		r;
975	unsigned int		ms;
976
977	memset(&mc, 0, sizeof(mc));
978	mc.mc_data0 = htobe32(0); /* get 1 byte */
979	mc.mc_data1 = htobe32((addr << 8) | off);
980	result = myx_cmd(sc, MYXCMD_I2C_READ, &mc, NULL);
981	if (result != 0)
982		return (EIO);
983
984	for (ms = 0; ms < 50; ms++) {
985		memset(&mc, 0, sizeof(mc));
986		mc.mc_data0 = htobe32(off);
987		result = myx_cmd(sc, MYXCMD_I2C_BYTE, &mc, &r);
988		switch (result) {
989		case MYXCMD_OK:
990			*byte = r;
991			return (0);
992		case MYXCMD_ERR_BUSY:
993			break;
994		default:
995			return (EIO);
996		}
997
998		delay(1000);
999	}
1000
1001	return (EBUSY);
1002}
1003
1004int
1005myx_get_sffpage(struct myx_softc *sc, struct if_sffpage *sff)
1006{
1007	unsigned int		i;
1008	int			result;
1009
1010	if (sff->sff_addr == IFSFF_ADDR_EEPROM) {
1011		uint8_t page;
1012
1013		result = myx_i2c_byte(sc, IFSFF_ADDR_EEPROM, 127, &page);
1014		if (result != 0)
1015			return (result);
1016
1017		if (page != sff->sff_page)
1018			return (ENXIO);
1019	}
1020
1021	for (i = 0; i < sizeof(sff->sff_data); i++) {
1022		result = myx_i2c_byte(sc, sff->sff_addr,
1023		    i, &sff->sff_data[i]);
1024		if (result != 0)
1025			return (result);
1026	}
1027
1028	return (0);
1029}
1030
1031void
1032myx_up(struct myx_softc *sc)
1033{
1034	struct ifnet		*ifp = &sc->sc_ac.ac_if;
1035	struct myx_cmd		mc;
1036	bus_dmamap_t		map;
1037	size_t			size;
1038	u_int			maxpkt;
1039	u_int32_t		r;
1040
1041	memset(&mc, 0, sizeof(mc));
1042	if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
1043		printf("%s: failed to reset the device\n", DEVNAME(sc));
1044		return;
1045	}
1046
1047	if (myx_dmamem_alloc(sc, &sc->sc_zerodma,
1048	    64, MYXALIGN_CMD) != 0) {
1049		printf("%s: failed to allocate zero pad memory\n",
1050		    DEVNAME(sc));
1051		return;
1052	}
1053	memset(sc->sc_zerodma.mxm_kva, 0, 64);
1054	bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0,
1055	    sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_PREREAD);
1056
1057	if (myx_dmamem_alloc(sc, &sc->sc_paddma,
1058	    MYXALIGN_CMD, MYXALIGN_CMD) != 0) {
1059		printf("%s: failed to allocate pad DMA memory\n",
1060		    DEVNAME(sc));
1061		goto free_zero;
1062	}
1063	bus_dmamap_sync(sc->sc_dmat, sc->sc_paddma.mxm_map, 0,
1064	    sc->sc_paddma.mxm_map->dm_mapsize,
1065	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1066
1067	if (myx_rdma(sc, MYXRDMA_ON) != 0) {
1068		printf("%s: failed to enable dummy RDMA\n", DEVNAME(sc));
1069		goto free_pad;
1070	}
1071
1072	if (myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc, &r) != 0) {
1073		printf("%s: unable to get rx ring size\n", DEVNAME(sc));
1074		goto free_pad;
1075	}
1076	sc->sc_rx_ring_count = r / sizeof(struct myx_rx_desc);
1077
1078	memset(&mc, 0, sizeof(mc));
1079	if (myx_cmd(sc, MYXCMD_GET_TXRINGSZ, &mc, &r) != 0) {
1080		printf("%s: unable to get tx ring size\n", DEVNAME(sc));
1081		goto free_pad;
1082	}
1083	sc->sc_tx_ring_prod = 0;
1084	sc->sc_tx_ring_cons = 0;
1085	sc->sc_tx_ring_count = r / sizeof(struct myx_tx_desc);
1086	sc->sc_tx_nsegs = min(16, sc->sc_tx_ring_count / 4); /* magic */
1087	sc->sc_tx_count = 0;
1088	ifq_init_maxlen(&ifp->if_snd, sc->sc_tx_ring_count - 1);
1089
1090	/* Allocate Interrupt Queue */
1091
1092	sc->sc_intrq_count = sc->sc_rx_ring_count * 2;
1093	sc->sc_intrq_idx = 0;
1094
1095	size = sc->sc_intrq_count * sizeof(struct myx_intrq_desc);
1096	if (myx_dmamem_alloc(sc, &sc->sc_intrq_dma,
1097	    size, MYXALIGN_DATA) != 0) {
1098		goto free_pad;
1099	}
1100	sc->sc_intrq = (struct myx_intrq_desc *)sc->sc_intrq_dma.mxm_kva;
1101	map = sc->sc_intrq_dma.mxm_map;
1102	memset(sc->sc_intrq, 0, size);
1103	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1104	    BUS_DMASYNC_PREREAD);
1105
1106	memset(&mc, 0, sizeof(mc));
1107	mc.mc_data0 = htobe32(size);
1108	if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) {
1109		printf("%s: failed to set intrq size\n", DEVNAME(sc));
1110		goto free_intrq;
1111	}
1112
1113	memset(&mc, 0, sizeof(mc));
1114	mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
1115	mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1116	if (myx_cmd(sc, MYXCMD_SET_INTRQDMA, &mc, NULL) != 0) {
1117		printf("%s: failed to set intrq address\n", DEVNAME(sc));
1118		goto free_intrq;
1119	}
1120
1121	/*
1122	 * get interrupt offsets
1123	 */
1124
1125	memset(&mc, 0, sizeof(mc));
1126	if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc,
1127	    &sc->sc_irqclaimoff) != 0) {
1128		printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc));
1129		goto free_intrq;
1130	}
1131
1132	memset(&mc, 0, sizeof(mc));
1133	if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc,
1134	    &sc->sc_irqdeassertoff) != 0) {
1135		printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc));
1136		goto free_intrq;
1137	}
1138
1139	memset(&mc, 0, sizeof(mc));
1140	if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc,
1141	    &sc->sc_irqcoaloff) != 0) {
1142		printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc));
1143		goto free_intrq;
1144	}
1145
1146	/* Set an appropriate interrupt coalescing period */
1147	r = htobe32(MYX_IRQCOALDELAY);
1148	myx_write(sc, sc->sc_irqcoaloff, &r, sizeof(r));
1149
1150	if (myx_setlladdr(sc, MYXCMD_SET_LLADDR, LLADDR(ifp->if_sadl)) != 0) {
1151		printf("%s: failed to configure lladdr\n", DEVNAME(sc));
1152		goto free_intrq;
1153	}
1154
1155	memset(&mc, 0, sizeof(mc));
1156	if (myx_cmd(sc, MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) {
1157		printf("%s: failed to disable promisc mode\n", DEVNAME(sc));
1158		goto free_intrq;
1159	}
1160
1161	memset(&mc, 0, sizeof(mc));
1162	if (myx_cmd(sc, MYXCMD_FC_DEFAULT, &mc, NULL) != 0) {
1163		printf("%s: failed to configure flow control\n", DEVNAME(sc));
1164		goto free_intrq;
1165	}
1166
1167	memset(&mc, 0, sizeof(mc));
1168	if (myx_cmd(sc, MYXCMD_GET_TXRINGOFF, &mc,
1169	    &sc->sc_tx_ring_offset) != 0) {
1170		printf("%s: unable to get tx ring offset\n", DEVNAME(sc));
1171		goto free_intrq;
1172	}
1173
1174	memset(&mc, 0, sizeof(mc));
1175	if (myx_cmd(sc, MYXCMD_GET_RXSMALLRINGOFF, &mc,
1176	    &sc->sc_rx_ring[MYX_RXSMALL].mrr_offset) != 0) {
1177		printf("%s: unable to get small rx ring offset\n", DEVNAME(sc));
1178		goto free_intrq;
1179	}
1180
1181	memset(&mc, 0, sizeof(mc));
1182	if (myx_cmd(sc, MYXCMD_GET_RXBIGRINGOFF, &mc,
1183	    &sc->sc_rx_ring[MYX_RXBIG].mrr_offset) != 0) {
1184		printf("%s: unable to get big rx ring offset\n", DEVNAME(sc));
1185		goto free_intrq;
1186	}
1187
1188	/* Allocate Interrupt Data */
1189	if (myx_dmamem_alloc(sc, &sc->sc_sts_dma,
1190	    sizeof(struct myx_status), MYXALIGN_DATA) != 0) {
1191		printf("%s: failed to allocate status DMA memory\n",
1192		    DEVNAME(sc));
1193		goto free_intrq;
1194	}
1195	sc->sc_sts = (struct myx_status *)sc->sc_sts_dma.mxm_kva;
1196	map = sc->sc_sts_dma.mxm_map;
1197	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1198	    BUS_DMASYNC_PREREAD);
1199
1200	memset(&mc, 0, sizeof(mc));
1201	mc.mc_data0 = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
1202	mc.mc_data1 = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1203	mc.mc_data2 = htobe32(sizeof(struct myx_status));
1204	if (myx_cmd(sc, MYXCMD_SET_STATSDMA, &mc, NULL) != 0) {
1205		printf("%s: failed to set status DMA offset\n", DEVNAME(sc));
1206		goto free_sts;
1207	}
1208
1209	maxpkt = ifp->if_hardmtu + ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN;
1210
1211	memset(&mc, 0, sizeof(mc));
1212	mc.mc_data0 = htobe32(maxpkt);
1213	if (myx_cmd(sc, MYXCMD_SET_MTU, &mc, NULL) != 0) {
1214		printf("%s: failed to set MTU size %d\n", DEVNAME(sc), maxpkt);
1215		goto free_sts;
1216	}
1217
1218	if (myx_tx_init(sc, maxpkt) != 0)
1219		goto free_sts;
1220
1221	if (myx_rx_init(sc, MYX_RXSMALL, MCLBYTES) != 0)
1222		goto free_tx_ring;
1223
1224	if (myx_rx_fill(sc, &sc->sc_rx_ring[MYX_RXSMALL]) != 0)
1225		goto free_rx_ring_small;
1226
1227	if (myx_rx_init(sc, MYX_RXBIG, MYX_RXBIG_SIZE) != 0)
1228		goto empty_rx_ring_small;
1229
1230	if (myx_rx_fill(sc, &sc->sc_rx_ring[MYX_RXBIG]) != 0)
1231		goto free_rx_ring_big;
1232
1233	memset(&mc, 0, sizeof(mc));
1234	mc.mc_data0 = htobe32(MYX_RXSMALL_SIZE - ETHER_ALIGN);
1235	if (myx_cmd(sc, MYXCMD_SET_SMALLBUFSZ, &mc, NULL) != 0) {
1236		printf("%s: failed to set small buf size\n", DEVNAME(sc));
1237		goto empty_rx_ring_big;
1238	}
1239
1240	memset(&mc, 0, sizeof(mc));
1241	mc.mc_data0 = htobe32(16384);
1242	if (myx_cmd(sc, MYXCMD_SET_BIGBUFSZ, &mc, NULL) != 0) {
1243		printf("%s: failed to set big buf size\n", DEVNAME(sc));
1244		goto empty_rx_ring_big;
1245	}
1246
1247	sc->sc_state = MYX_S_RUNNING;
1248
1249	if (myx_cmd(sc, MYXCMD_SET_IFUP, &mc, NULL) != 0) {
1250		printf("%s: failed to start the device\n", DEVNAME(sc));
1251		goto empty_rx_ring_big;
1252	}
1253
1254	myx_iff(sc);
1255	SET(ifp->if_flags, IFF_RUNNING);
1256	ifq_restart(&ifp->if_snd);
1257
1258#if NKSTAT > 0
1259	timeout_add_sec(&sc->sc_kstat_tmo, 1);
1260#endif
1261
1262	return;
1263
1264empty_rx_ring_big:
1265	myx_rx_empty(sc, &sc->sc_rx_ring[MYX_RXBIG]);
1266free_rx_ring_big:
1267	myx_rx_free(sc, &sc->sc_rx_ring[MYX_RXBIG]);
1268empty_rx_ring_small:
1269	myx_rx_empty(sc, &sc->sc_rx_ring[MYX_RXSMALL]);
1270free_rx_ring_small:
1271	myx_rx_free(sc, &sc->sc_rx_ring[MYX_RXSMALL]);
1272free_tx_ring:
1273	myx_tx_free(sc);
1274free_sts:
1275	bus_dmamap_sync(sc->sc_dmat, sc->sc_sts_dma.mxm_map, 0,
1276	    sc->sc_sts_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1277	myx_dmamem_free(sc, &sc->sc_sts_dma);
1278free_intrq:
1279	bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0,
1280	    sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1281	myx_dmamem_free(sc, &sc->sc_intrq_dma);
1282free_pad:
1283	bus_dmamap_sync(sc->sc_dmat, sc->sc_paddma.mxm_map, 0,
1284	    sc->sc_paddma.mxm_map->dm_mapsize,
1285	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1286	myx_dmamem_free(sc, &sc->sc_paddma);
1287
1288	memset(&mc, 0, sizeof(mc));
1289	if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
1290		printf("%s: failed to reset the device\n", DEVNAME(sc));
1291	}
1292free_zero:
1293	bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0,
1294	    sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1295	myx_dmamem_free(sc, &sc->sc_zerodma);
1296}
1297
1298int
1299myx_setlladdr(struct myx_softc *sc, u_int32_t cmd, u_int8_t *addr)
1300{
1301	struct myx_cmd		 mc;
1302
1303	memset(&mc, 0, sizeof(mc));
1304	mc.mc_data0 = htobe32(addr[0] << 24 | addr[1] << 16 |
1305	    addr[2] << 8 | addr[3]);
1306	mc.mc_data1 = htobe32(addr[4] << 8 | addr[5]);
1307
1308	if (myx_cmd(sc, cmd, &mc, NULL) != 0) {
1309		printf("%s: failed to set the lladdr\n", DEVNAME(sc));
1310		return (-1);
1311	}
1312	return (0);
1313}
1314
1315void
1316myx_iff(struct myx_softc *sc)
1317{
1318	struct myx_cmd		mc;
1319	struct ifnet		*ifp = &sc->sc_ac.ac_if;
1320	struct ether_multi	*enm;
1321	struct ether_multistep	step;
1322	u_int8_t *addr;
1323
1324	CLR(ifp->if_flags, IFF_ALLMULTI);
1325
1326	if (myx_cmd(sc, ISSET(ifp->if_flags, IFF_PROMISC) ?
1327	    MYXCMD_SET_PROMISC : MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) {
1328		printf("%s: failed to configure promisc mode\n", DEVNAME(sc));
1329		return;
1330	}
1331
1332	if (myx_cmd(sc, MYXCMD_SET_ALLMULTI, &mc, NULL) != 0) {
1333		printf("%s: failed to enable ALLMULTI\n", DEVNAME(sc));
1334		return;
1335	}
1336
1337	if (myx_cmd(sc, MYXCMD_UNSET_MCAST, &mc, NULL) != 0) {
1338		printf("%s: failed to leave all mcast groups \n", DEVNAME(sc));
1339		return;
1340	}
1341
1342	if (ISSET(ifp->if_flags, IFF_PROMISC) ||
1343	    sc->sc_ac.ac_multirangecnt > 0) {
1344		SET(ifp->if_flags, IFF_ALLMULTI);
1345		return;
1346	}
1347
1348	ETHER_FIRST_MULTI(step, &sc->sc_ac, enm);
1349	while (enm != NULL) {
1350		addr = enm->enm_addrlo;
1351
1352		memset(&mc, 0, sizeof(mc));
1353		mc.mc_data0 = htobe32(addr[0] << 24 | addr[1] << 16 |
1354		    addr[2] << 8 | addr[3]);
1355		mc.mc_data1 = htobe32(addr[4] << 24 | addr[5] << 16);
1356		if (myx_cmd(sc, MYXCMD_SET_MCASTGROUP, &mc, NULL) != 0) {
1357			printf("%s: failed to join mcast group\n", DEVNAME(sc));
1358			return;
1359		}
1360
1361		ETHER_NEXT_MULTI(step, enm);
1362	}
1363
1364	memset(&mc, 0, sizeof(mc));
1365	if (myx_cmd(sc, MYXCMD_UNSET_ALLMULTI, &mc, NULL) != 0) {
1366		printf("%s: failed to disable ALLMULTI\n", DEVNAME(sc));
1367		return;
1368	}
1369}
1370
1371void
1372myx_down(struct myx_softc *sc)
1373{
1374	struct ifnet		*ifp = &sc->sc_ac.ac_if;
1375	volatile struct myx_status *sts = sc->sc_sts;
1376	bus_dmamap_t		 map = sc->sc_sts_dma.mxm_map;
1377	struct myx_cmd		 mc;
1378	int			 s;
1379	int			 ring;
1380
1381	CLR(ifp->if_flags, IFF_RUNNING);
1382
1383	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1384	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1385	sc->sc_linkdown = sts->ms_linkdown;
1386	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1387	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1388
1389	sc->sc_state = MYX_S_DOWN;
1390	membar_producer();
1391
1392	memset(&mc, 0, sizeof(mc));
1393	(void)myx_cmd(sc, MYXCMD_SET_IFDOWN, &mc, NULL);
1394
1395	while (sc->sc_state != MYX_S_OFF) {
1396		sleep_setup(sts, PWAIT, "myxdown");
1397		membar_consumer();
1398		sleep_finish(0, sc->sc_state != MYX_S_OFF);
1399	}
1400
1401	s = splnet();
1402	if (ifp->if_link_state != LINK_STATE_UNKNOWN) {
1403		ifp->if_link_state = LINK_STATE_UNKNOWN;
1404		ifp->if_baudrate = 0;
1405		if_link_state_change(ifp);
1406	}
1407	splx(s);
1408
1409	memset(&mc, 0, sizeof(mc));
1410	if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
1411		printf("%s: failed to reset the device\n", DEVNAME(sc));
1412	}
1413
1414	ifq_clr_oactive(&ifp->if_snd);
1415	ifq_barrier(&ifp->if_snd);
1416
1417	for (ring = 0; ring < 2; ring++) {
1418		struct myx_rx_ring *mrr = &sc->sc_rx_ring[ring];
1419
1420		timeout_del(&mrr->mrr_refill);
1421		myx_rx_empty(sc, mrr);
1422		myx_rx_free(sc, mrr);
1423	}
1424
1425	myx_tx_empty(sc);
1426	myx_tx_free(sc);
1427
1428#if NKSTAT > 0
1429	myx_kstat_stop(sc);
1430	sc->sc_sts = NULL;
1431#endif
1432
1433	/* the sleep shizz above already synced this dmamem */
1434	myx_dmamem_free(sc, &sc->sc_sts_dma);
1435
1436	bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0,
1437	    sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1438	myx_dmamem_free(sc, &sc->sc_intrq_dma);
1439
1440	bus_dmamap_sync(sc->sc_dmat, sc->sc_paddma.mxm_map, 0,
1441	    sc->sc_paddma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1442	myx_dmamem_free(sc, &sc->sc_paddma);
1443
1444	bus_dmamap_sync(sc->sc_dmat, sc->sc_zerodma.mxm_map, 0,
1445	    sc->sc_zerodma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1446	myx_dmamem_free(sc, &sc->sc_zerodma);
1447}
1448
1449void
1450myx_write_txd_tail(struct myx_softc *sc, struct myx_slot *ms, u_int8_t flags,
1451    u_int32_t offset, u_int idx)
1452{
1453	struct myx_tx_desc		txd;
1454	bus_dmamap_t			zmap = sc->sc_zerodma.mxm_map;
1455	bus_dmamap_t			map = ms->ms_map;
1456	int				i;
1457
1458	for (i = 1; i < map->dm_nsegs; i++) {
1459		memset(&txd, 0, sizeof(txd));
1460		txd.tx_addr = htobe64(map->dm_segs[i].ds_addr);
1461		txd.tx_length = htobe16(map->dm_segs[i].ds_len);
1462		txd.tx_flags = flags;
1463
1464		myx_bus_space_write(sc,
1465		    offset + sizeof(txd) * ((idx + i) % sc->sc_tx_ring_count),
1466		    &txd, sizeof(txd));
1467	}
1468
1469	/* pad runt frames */
1470	if (map->dm_mapsize < 60) {
1471		memset(&txd, 0, sizeof(txd));
1472		txd.tx_addr = htobe64(zmap->dm_segs[0].ds_addr);
1473		txd.tx_length = htobe16(60 - map->dm_mapsize);
1474		txd.tx_flags = flags;
1475
1476		myx_bus_space_write(sc,
1477		    offset + sizeof(txd) * ((idx + i) % sc->sc_tx_ring_count),
1478		    &txd, sizeof(txd));
1479	}
1480}
1481
1482void
1483myx_start(struct ifqueue *ifq)
1484{
1485	struct ifnet			*ifp = ifq->ifq_if;
1486	struct myx_tx_desc		txd;
1487	struct myx_softc		*sc = ifp->if_softc;
1488	struct myx_slot			*ms;
1489	bus_dmamap_t			map;
1490	struct mbuf			*m;
1491	u_int32_t			offset = sc->sc_tx_ring_offset;
1492	u_int				idx, cons, prod;
1493	u_int				free, used;
1494	u_int8_t			flags;
1495
1496	idx = sc->sc_tx_ring_prod;
1497
1498	/* figure out space */
1499	free = sc->sc_tx_ring_cons;
1500	if (free <= idx)
1501		free += sc->sc_tx_ring_count;
1502	free -= idx;
1503
1504	cons = prod = sc->sc_tx_prod;
1505
1506	used = 0;
1507
1508	for (;;) {
1509		if (used + sc->sc_tx_nsegs + 1 > free) {
1510			ifq_set_oactive(ifq);
1511			break;
1512		}
1513
1514		m = ifq_dequeue(ifq);
1515		if (m == NULL)
1516			break;
1517
1518		ms = &sc->sc_tx_slots[prod];
1519
1520		if (myx_load_mbuf(sc, ms, m) != 0) {
1521			m_freem(m);
1522			ifp->if_oerrors++;
1523			continue;
1524		}
1525
1526#if NBPFILTER > 0
1527		if (ifp->if_bpf)
1528			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
1529#endif
1530
1531		map = ms->ms_map;
1532		bus_dmamap_sync(sc->sc_dmat, map, 0,
1533		    map->dm_mapsize, BUS_DMASYNC_PREWRITE);
1534
1535		used += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0);
1536
1537		if (++prod >= sc->sc_tx_ring_count)
1538			prod = 0;
1539	}
1540
1541	if (cons == prod)
1542		return;
1543
1544	ms = &sc->sc_tx_slots[cons];
1545
1546	for (;;) {
1547		idx += ms->ms_map->dm_nsegs +
1548		    (ms->ms_map->dm_mapsize < 60 ? 1 : 0);
1549		if (idx >= sc->sc_tx_ring_count)
1550			idx -= sc->sc_tx_ring_count;
1551
1552		if (++cons >= sc->sc_tx_ring_count)
1553			cons = 0;
1554
1555		if (cons == prod)
1556			break;
1557
1558		ms = &sc->sc_tx_slots[cons];
1559		map = ms->ms_map;
1560
1561		flags = MYXTXD_FLAGS_NO_TSO;
1562		if (map->dm_mapsize < 1520)
1563			flags |= MYXTXD_FLAGS_SMALL;
1564
1565		memset(&txd, 0, sizeof(txd));
1566		txd.tx_addr = htobe64(map->dm_segs[0].ds_addr);
1567		txd.tx_length = htobe16(map->dm_segs[0].ds_len);
1568		txd.tx_nsegs = map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0);
1569		txd.tx_flags = flags | MYXTXD_FLAGS_FIRST;
1570		myx_bus_space_write(sc,
1571		    offset + sizeof(txd) * idx, &txd, sizeof(txd));
1572
1573		myx_write_txd_tail(sc, ms, flags, offset, idx);
1574	}
1575
1576	/* go back and post first packet */
1577	ms = &sc->sc_tx_slots[sc->sc_tx_prod];
1578	map = ms->ms_map;
1579
1580	flags = MYXTXD_FLAGS_NO_TSO;
1581	if (map->dm_mapsize < 1520)
1582		flags |= MYXTXD_FLAGS_SMALL;
1583
1584	memset(&txd, 0, sizeof(txd));
1585	txd.tx_addr = htobe64(map->dm_segs[0].ds_addr);
1586	txd.tx_length = htobe16(map->dm_segs[0].ds_len);
1587	txd.tx_nsegs = map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0);
1588	txd.tx_flags = flags | MYXTXD_FLAGS_FIRST;
1589
1590	/* make sure the first descriptor is seen after the others */
1591	myx_write_txd_tail(sc, ms, flags, offset, sc->sc_tx_ring_prod);
1592
1593	myx_bus_space_write(sc,
1594	    offset + sizeof(txd) * sc->sc_tx_ring_prod, &txd,
1595	    sizeof(txd) - sizeof(myx_bus_t));
1596
1597	bus_space_barrier(sc->sc_memt, sc->sc_memh, offset,
1598	    sizeof(txd) * sc->sc_tx_ring_count, BUS_SPACE_BARRIER_WRITE);
1599
1600	myx_bus_space_write(sc,
1601	    offset + sizeof(txd) * (sc->sc_tx_ring_prod + 1) -
1602	    sizeof(myx_bus_t),
1603	    (u_int8_t *)&txd + sizeof(txd) - sizeof(myx_bus_t),
1604	    sizeof(myx_bus_t));
1605
1606	bus_space_barrier(sc->sc_memt, sc->sc_memh,
1607	    offset + sizeof(txd) * sc->sc_tx_ring_prod, sizeof(txd),
1608	    BUS_SPACE_BARRIER_WRITE);
1609
1610	/* commit */
1611	sc->sc_tx_ring_prod = idx;
1612	sc->sc_tx_prod = prod;
1613}
1614
1615int
1616myx_load_mbuf(struct myx_softc *sc, struct myx_slot *ms, struct mbuf *m)
1617{
1618	bus_dma_tag_t			dmat = sc->sc_dmat;
1619	bus_dmamap_t			dmap = ms->ms_map;
1620
1621	switch (bus_dmamap_load_mbuf(dmat, dmap, m,
1622	    BUS_DMA_STREAMING | BUS_DMA_NOWAIT)) {
1623	case 0:
1624		break;
1625
1626	case EFBIG: /* mbuf chain is too fragmented */
1627		if (m_defrag(m, M_DONTWAIT) == 0 &&
1628		    bus_dmamap_load_mbuf(dmat, dmap, m,
1629		    BUS_DMA_STREAMING | BUS_DMA_NOWAIT) == 0)
1630			break;
1631	default:
1632		return (1);
1633	}
1634
1635	ms->ms_m = m;
1636	return (0);
1637}
1638
1639int
1640myx_intr(void *arg)
1641{
1642	struct myx_softc	*sc = (struct myx_softc *)arg;
1643	volatile struct myx_status *sts = sc->sc_sts;
1644	enum myx_state		 state;
1645	bus_dmamap_t		 map = sc->sc_sts_dma.mxm_map;
1646	u_int32_t		 data;
1647	u_int8_t		 valid = 0;
1648
1649	state = sc->sc_state;
1650	if (state == MYX_S_OFF)
1651		return (0);
1652
1653	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1654	    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
1655
1656	valid = sts->ms_isvalid;
1657	if (valid == 0x0) {
1658		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1659		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1660		return (0);
1661	}
1662
1663	if (sc->sc_intx) {
1664		data = htobe32(0);
1665		bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh,
1666		    sc->sc_irqdeassertoff, &data, sizeof(data));
1667	}
1668	sts->ms_isvalid = 0;
1669
1670	do {
1671		data = sts->ms_txdonecnt;
1672
1673		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1674		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE |
1675		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1676	} while (sts->ms_isvalid);
1677
1678	data = betoh32(data);
1679	if (data != sc->sc_tx_count)
1680		myx_txeof(sc, data);
1681
1682	data = htobe32(3);
1683	if (valid & 0x1) {
1684		myx_rxeof(sc);
1685
1686		bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh,
1687		    sc->sc_irqclaimoff, &data, sizeof(data));
1688	}
1689	bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh,
1690	    sc->sc_irqclaimoff + sizeof(data), &data, sizeof(data));
1691
1692	if (sts->ms_statusupdated) {
1693		if (state == MYX_S_DOWN &&
1694		    sc->sc_linkdown != sts->ms_linkdown) {
1695			sc->sc_state = MYX_S_OFF;
1696			membar_producer();
1697			wakeup(sts);
1698		} else {
1699			data = sts->ms_linkstate;
1700			if (data != 0xffffffff) {
1701				KERNEL_LOCK();
1702				myx_link_state(sc, data);
1703				KERNEL_UNLOCK();
1704			}
1705		}
1706	}
1707
1708	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
1709	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
1710
1711	return (1);
1712}
1713
1714void
1715myx_refill(void *xmrr)
1716{
1717	struct myx_rx_ring *mrr = xmrr;
1718	struct myx_softc *sc = mrr->mrr_softc;
1719
1720	myx_rx_fill(sc, mrr);
1721
1722	if (mrr->mrr_prod == mrr->mrr_cons)
1723		timeout_add(&mrr->mrr_refill, 1);
1724}
1725
1726void
1727myx_txeof(struct myx_softc *sc, u_int32_t done_count)
1728{
1729	struct ifnet *ifp = &sc->sc_ac.ac_if;
1730	struct myx_slot *ms;
1731	bus_dmamap_t map;
1732	u_int idx, cons;
1733
1734	idx = sc->sc_tx_ring_cons;
1735	cons = sc->sc_tx_cons;
1736
1737	do {
1738		ms = &sc->sc_tx_slots[cons];
1739		map = ms->ms_map;
1740
1741		idx += map->dm_nsegs + (map->dm_mapsize < 60 ? 1 : 0);
1742
1743		bus_dmamap_sync(sc->sc_dmat, map, 0,
1744		    map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1745		bus_dmamap_unload(sc->sc_dmat, map);
1746		m_freem(ms->ms_m);
1747
1748		if (++cons >= sc->sc_tx_ring_count)
1749			cons = 0;
1750	} while (++sc->sc_tx_count != done_count);
1751
1752	if (idx >= sc->sc_tx_ring_count)
1753		idx -= sc->sc_tx_ring_count;
1754
1755	sc->sc_tx_ring_cons = idx;
1756	sc->sc_tx_cons = cons;
1757
1758	if (ifq_is_oactive(&ifp->if_snd))
1759		ifq_restart(&ifp->if_snd);
1760}
1761
1762void
1763myx_rxeof(struct myx_softc *sc)
1764{
1765	static const struct myx_intrq_desc zerodesc = { 0, 0 };
1766	struct ifnet *ifp = &sc->sc_ac.ac_if;
1767	struct mbuf_list ml = MBUF_LIST_INITIALIZER();
1768	struct myx_rx_ring *mrr;
1769	struct myx_slot *ms;
1770	struct mbuf *m;
1771	int ring;
1772	u_int rxfree[2] = { 0 , 0 };
1773	u_int len;
1774	int livelocked;
1775
1776	bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0,
1777	    sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1778
1779	while ((len = betoh16(sc->sc_intrq[sc->sc_intrq_idx].iq_length)) != 0) {
1780		sc->sc_intrq[sc->sc_intrq_idx] = zerodesc;
1781
1782		if (++sc->sc_intrq_idx >= sc->sc_intrq_count)
1783			sc->sc_intrq_idx = 0;
1784
1785		ring = (len <= (MYX_RXSMALL_SIZE - ETHER_ALIGN)) ?
1786		    MYX_RXSMALL : MYX_RXBIG;
1787
1788		mrr = &sc->sc_rx_ring[ring];
1789		ms = &mrr->mrr_slots[mrr->mrr_cons];
1790
1791		if (++mrr->mrr_cons >= sc->sc_rx_ring_count)
1792			mrr->mrr_cons = 0;
1793
1794		bus_dmamap_sync(sc->sc_dmat, ms->ms_map, 0,
1795		    ms->ms_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1796		bus_dmamap_unload(sc->sc_dmat, ms->ms_map);
1797
1798		m = ms->ms_m;
1799		m->m_data += ETHER_ALIGN;
1800		m->m_pkthdr.len = m->m_len = len;
1801
1802		ml_enqueue(&ml, m);
1803
1804		rxfree[ring]++;
1805	}
1806
1807	bus_dmamap_sync(sc->sc_dmat, sc->sc_intrq_dma.mxm_map, 0,
1808	    sc->sc_intrq_dma.mxm_map->dm_mapsize, BUS_DMASYNC_PREREAD);
1809
1810	livelocked = ifiq_input(&ifp->if_rcv, &ml);
1811	for (ring = MYX_RXSMALL; ring <= MYX_RXBIG; ring++) {
1812		if (rxfree[ring] == 0)
1813			continue;
1814
1815		mrr = &sc->sc_rx_ring[ring];
1816
1817		if (livelocked)
1818			if_rxr_livelocked(&mrr->mrr_rxr);
1819
1820		if_rxr_put(&mrr->mrr_rxr, rxfree[ring]);
1821		myx_rx_fill(sc, mrr);
1822		if (mrr->mrr_prod == mrr->mrr_cons)
1823			timeout_add(&mrr->mrr_refill, 0);
1824	}
1825}
1826
1827static int
1828myx_rx_fill_slots(struct myx_softc *sc, struct myx_rx_ring *mrr, u_int slots)
1829{
1830	struct myx_rx_desc rxd;
1831	struct myx_slot *ms;
1832	u_int32_t offset = mrr->mrr_offset;
1833	u_int p, first, fills;
1834
1835	first = p = mrr->mrr_prod;
1836	if (myx_buf_fill(sc, &mrr->mrr_slots[first], mrr->mrr_mclget) != 0)
1837		return (slots);
1838
1839	if (++p >= sc->sc_rx_ring_count)
1840		p = 0;
1841
1842	for (fills = 1; fills < slots; fills++) {
1843		ms = &mrr->mrr_slots[p];
1844
1845		if (myx_buf_fill(sc, ms, mrr->mrr_mclget) != 0)
1846			break;
1847
1848		rxd.rx_addr = htobe64(ms->ms_map->dm_segs[0].ds_addr);
1849		myx_bus_space_write(sc, offset + p * sizeof(rxd),
1850		    &rxd, sizeof(rxd));
1851
1852		if (++p >= sc->sc_rx_ring_count)
1853			p = 0;
1854	}
1855
1856	mrr->mrr_prod = p;
1857
1858	/* make sure the first descriptor is seen after the others */
1859	if (fills > 1) {
1860		bus_space_barrier(sc->sc_memt, sc->sc_memh,
1861		    offset, sizeof(rxd) * sc->sc_rx_ring_count,
1862		    BUS_SPACE_BARRIER_WRITE);
1863	}
1864
1865	ms = &mrr->mrr_slots[first];
1866	rxd.rx_addr = htobe64(ms->ms_map->dm_segs[0].ds_addr);
1867	myx_bus_space_write(sc, offset + first * sizeof(rxd),
1868	    &rxd, sizeof(rxd));
1869
1870	return (slots - fills);
1871}
1872
1873int
1874myx_rx_init(struct myx_softc *sc, int ring, bus_size_t size)
1875{
1876	struct myx_rx_desc rxd;
1877	struct myx_rx_ring *mrr = &sc->sc_rx_ring[ring];
1878	struct myx_slot *ms;
1879	u_int32_t offset = mrr->mrr_offset;
1880	int rv;
1881	int i;
1882
1883	mrr->mrr_slots = mallocarray(sizeof(*ms), sc->sc_rx_ring_count,
1884	    M_DEVBUF, M_WAITOK);
1885	if (mrr->mrr_slots == NULL)
1886		return (ENOMEM);
1887
1888	memset(&rxd, 0xff, sizeof(rxd));
1889	for (i = 0; i < sc->sc_rx_ring_count; i++) {
1890		ms = &mrr->mrr_slots[i];
1891		rv = bus_dmamap_create(sc->sc_dmat, size, 1, size, 0,
1892		    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
1893		    &ms->ms_map);
1894		if (rv != 0)
1895			goto destroy;
1896
1897		myx_bus_space_write(sc, offset + i * sizeof(rxd),
1898		    &rxd, sizeof(rxd));
1899	}
1900
1901	if_rxr_init(&mrr->mrr_rxr, 2, sc->sc_rx_ring_count - 2);
1902	mrr->mrr_prod = mrr->mrr_cons = 0;
1903
1904	return (0);
1905
1906destroy:
1907	while (i-- > 0) {
1908		ms = &mrr->mrr_slots[i];
1909		bus_dmamap_destroy(sc->sc_dmat, ms->ms_map);
1910	}
1911	free(mrr->mrr_slots, M_DEVBUF, sizeof(*ms) * sc->sc_rx_ring_count);
1912	return (rv);
1913}
1914
1915int
1916myx_rx_fill(struct myx_softc *sc, struct myx_rx_ring *mrr)
1917{
1918	u_int slots;
1919
1920	slots = if_rxr_get(&mrr->mrr_rxr, sc->sc_rx_ring_count);
1921	if (slots == 0)
1922		return (1);
1923
1924	slots = myx_rx_fill_slots(sc, mrr, slots);
1925	if (slots > 0)
1926		if_rxr_put(&mrr->mrr_rxr, slots);
1927
1928	return (0);
1929}
1930
1931void
1932myx_rx_empty(struct myx_softc *sc, struct myx_rx_ring *mrr)
1933{
1934	struct myx_slot *ms;
1935
1936	while (mrr->mrr_cons != mrr->mrr_prod) {
1937		ms = &mrr->mrr_slots[mrr->mrr_cons];
1938
1939		if (++mrr->mrr_cons >= sc->sc_rx_ring_count)
1940			mrr->mrr_cons = 0;
1941
1942		bus_dmamap_sync(sc->sc_dmat, ms->ms_map, 0,
1943		    ms->ms_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1944		bus_dmamap_unload(sc->sc_dmat, ms->ms_map);
1945		m_freem(ms->ms_m);
1946	}
1947
1948	if_rxr_init(&mrr->mrr_rxr, 2, sc->sc_rx_ring_count - 2);
1949}
1950
1951void
1952myx_rx_free(struct myx_softc *sc, struct myx_rx_ring *mrr)
1953{
1954	struct myx_slot *ms;
1955	int i;
1956
1957	for (i = 0; i < sc->sc_rx_ring_count; i++) {
1958		ms = &mrr->mrr_slots[i];
1959		bus_dmamap_destroy(sc->sc_dmat, ms->ms_map);
1960	}
1961
1962	free(mrr->mrr_slots, M_DEVBUF, sizeof(*ms) * sc->sc_rx_ring_count);
1963}
1964
1965struct mbuf *
1966myx_mcl_small(void)
1967{
1968	struct mbuf *m;
1969
1970	m = MCLGETL(NULL, M_DONTWAIT, MYX_RXSMALL_SIZE);
1971	if (m == NULL)
1972		return (NULL);
1973
1974	m->m_len = m->m_pkthdr.len = MYX_RXSMALL_SIZE;
1975
1976	return (m);
1977}
1978
1979struct mbuf *
1980myx_mcl_big(void)
1981{
1982	struct mbuf *m;
1983	void *mcl;
1984
1985	MGETHDR(m, M_DONTWAIT, MT_DATA);
1986	if (m == NULL)
1987		return (NULL);
1988
1989	mcl = pool_get(myx_mcl_pool, PR_NOWAIT);
1990	if (mcl == NULL) {
1991		m_free(m);
1992		return (NULL);
1993	}
1994
1995	MEXTADD(m, mcl, MYX_RXBIG_SIZE, M_EXTWR, MEXTFREE_POOL, myx_mcl_pool);
1996	m->m_len = m->m_pkthdr.len = MYX_RXBIG_SIZE;
1997
1998	return (m);
1999}
2000
2001int
2002myx_buf_fill(struct myx_softc *sc, struct myx_slot *ms,
2003    struct mbuf *(*mclget)(void))
2004{
2005	struct mbuf *m;
2006	int rv;
2007
2008	m = (*mclget)();
2009	if (m == NULL)
2010		return (ENOMEM);
2011
2012	rv = bus_dmamap_load_mbuf(sc->sc_dmat, ms->ms_map, m, BUS_DMA_NOWAIT);
2013	if (rv != 0) {
2014		m_freem(m);
2015		return (rv);
2016	}
2017
2018	bus_dmamap_sync(sc->sc_dmat, ms->ms_map, 0,
2019	    ms->ms_map->dm_mapsize, BUS_DMASYNC_PREREAD);
2020
2021	ms->ms_m = m;
2022
2023	return (0);
2024}
2025
2026int
2027myx_tx_init(struct myx_softc *sc, bus_size_t size)
2028{
2029	struct myx_slot *ms;
2030	int rv;
2031	int i;
2032
2033	sc->sc_tx_slots = mallocarray(sizeof(*ms), sc->sc_tx_ring_count,
2034	    M_DEVBUF, M_WAITOK);
2035	if (sc->sc_tx_slots == NULL)
2036		return (ENOMEM);
2037
2038	for (i = 0; i < sc->sc_tx_ring_count; i++) {
2039		ms = &sc->sc_tx_slots[i];
2040		rv = bus_dmamap_create(sc->sc_dmat, size, sc->sc_tx_nsegs,
2041		    sc->sc_tx_boundary, sc->sc_tx_boundary,
2042		    BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW | BUS_DMA_64BIT,
2043		    &ms->ms_map);
2044		if (rv != 0)
2045			goto destroy;
2046	}
2047
2048	sc->sc_tx_prod = sc->sc_tx_cons = 0;
2049
2050	return (0);
2051
2052destroy:
2053	while (i-- > 0) {
2054		ms = &sc->sc_tx_slots[i];
2055		bus_dmamap_destroy(sc->sc_dmat, ms->ms_map);
2056	}
2057	free(sc->sc_tx_slots, M_DEVBUF, sizeof(*ms) * sc->sc_tx_ring_count);
2058	return (rv);
2059}
2060
2061void
2062myx_tx_empty(struct myx_softc *sc)
2063{
2064	struct myx_slot *ms;
2065	u_int cons = sc->sc_tx_cons;
2066	u_int prod = sc->sc_tx_prod;
2067
2068	while (cons != prod) {
2069		ms = &sc->sc_tx_slots[cons];
2070
2071		bus_dmamap_sync(sc->sc_dmat, ms->ms_map, 0,
2072		    ms->ms_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
2073		bus_dmamap_unload(sc->sc_dmat, ms->ms_map);
2074		m_freem(ms->ms_m);
2075
2076		if (++cons >= sc->sc_tx_ring_count)
2077			cons = 0;
2078	}
2079
2080	sc->sc_tx_cons = cons;
2081}
2082
2083void
2084myx_tx_free(struct myx_softc *sc)
2085{
2086	struct myx_slot *ms;
2087	int i;
2088
2089	for (i = 0; i < sc->sc_tx_ring_count; i++) {
2090		ms = &sc->sc_tx_slots[i];
2091		bus_dmamap_destroy(sc->sc_dmat, ms->ms_map);
2092	}
2093
2094	free(sc->sc_tx_slots, M_DEVBUF, sizeof(*ms) * sc->sc_tx_ring_count);
2095}
2096
2097#if NKSTAT > 0
2098enum myx_counters {
2099	myx_stat_dropped_pause,
2100	myx_stat_dropped_ucast_filtered,
2101	myx_stat_dropped_bad_crc32,
2102	myx_stat_dropped_bad_phy,
2103	myx_stat_dropped_mcast_filtered,
2104	myx_stat_send_done,
2105	myx_stat_dropped_link_overflow,
2106	myx_stat_dropped_link,
2107	myx_stat_dropped_runt,
2108	myx_stat_dropped_overrun,
2109	myx_stat_dropped_no_small_bufs,
2110	myx_stat_dropped_no_large_bufs,
2111
2112	myx_ncounters,
2113};
2114
2115struct myx_counter {
2116	const char		*mc_name;
2117	unsigned int		 mc_offset;
2118};
2119
2120#define MYX_C_OFF(_f)	offsetof(struct myx_status, _f)
2121
2122static const struct myx_counter myx_counters[myx_ncounters] = {
2123	{ "pause drops",	MYX_C_OFF(ms_dropped_pause), },
2124	{ "ucast filtered",	MYX_C_OFF(ms_dropped_unicast), },
2125	{ "bad crc32",		MYX_C_OFF(ms_dropped_pause), },
2126	{ "bad phy",		MYX_C_OFF(ms_dropped_phyerr), },
2127	{ "mcast filtered",	MYX_C_OFF(ms_dropped_mcast), },
2128	{ "tx done",		MYX_C_OFF(ms_txdonecnt), },
2129	{ "rx discards",	MYX_C_OFF(ms_dropped_linkoverflow), },
2130	{ "rx errors",		MYX_C_OFF(ms_dropped_linkerror), },
2131	{ "rx undersize",	MYX_C_OFF(ms_dropped_runt), },
2132	{ "rx oversize",	MYX_C_OFF(ms_dropped_overrun), },
2133	{ "small discards",	MYX_C_OFF(ms_dropped_smallbufunderrun), },
2134	{ "large discards",	MYX_C_OFF(ms_dropped_bigbufunderrun), },
2135};
2136
2137struct myx_kstats {
2138	struct kstat_kv		mk_counters[myx_ncounters];
2139	struct kstat_kv		mk_rdma_tags_available;
2140};
2141
2142struct myx_kstat_cache {
2143	uint32_t		mkc_counters[myx_ncounters];
2144};
2145
2146struct myx_kstat_state {
2147	struct myx_kstat_cache	mks_caches[2];
2148	unsigned int		mks_gen;
2149};
2150
2151int
2152myx_kstat_read(struct kstat *ks)
2153{
2154	struct myx_softc *sc = ks->ks_softc;
2155	struct myx_kstats *mk = ks->ks_data;
2156	struct myx_kstat_state *mks = ks->ks_ptr;
2157	unsigned int gen = (mks->mks_gen++ & 1);
2158	struct myx_kstat_cache *omkc = &mks->mks_caches[gen];
2159	struct myx_kstat_cache *nmkc = &mks->mks_caches[!gen];
2160	unsigned int i = 0;
2161
2162	volatile struct myx_status *sts = sc->sc_sts;
2163	bus_dmamap_t map = sc->sc_sts_dma.mxm_map;
2164
2165	if (sc->sc_sts == NULL)
2166		return (0); /* counters are valid, just not updated */
2167
2168	getnanouptime(&ks->ks_updated);
2169
2170	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
2171	    BUS_DMASYNC_POSTREAD);
2172	for (i = 0; i < myx_ncounters; i++) {
2173		const struct myx_counter *mc = &myx_counters[i];
2174		nmkc->mkc_counters[i] =
2175		    bemtoh32((uint32_t *)((uint8_t *)sts + mc->mc_offset));
2176	}
2177
2178	kstat_kv_u32(&mk->mk_rdma_tags_available) =
2179	    bemtoh32(&sts->ms_rdmatags_available);
2180	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
2181	    BUS_DMASYNC_PREREAD);
2182
2183	for (i = 0; i < myx_ncounters; i++) {
2184		kstat_kv_u64(&mk->mk_counters[i]) +=
2185		    nmkc->mkc_counters[i] - omkc->mkc_counters[i];
2186	}
2187
2188	return (0);
2189}
2190
2191void
2192myx_kstat_tick(void *arg)
2193{
2194	struct myx_softc *sc = arg;
2195
2196	if (!ISSET(sc->sc_ac.ac_if.if_flags, IFF_RUNNING))
2197		return;
2198
2199	timeout_add_sec(&sc->sc_kstat_tmo, 4);
2200
2201	if (!mtx_enter_try(&sc->sc_kstat_mtx))
2202		return;
2203
2204	myx_kstat_read(sc->sc_kstat);
2205
2206	mtx_leave(&sc->sc_kstat_mtx);
2207}
2208
2209void
2210myx_kstat_start(struct myx_softc *sc)
2211{
2212	if (sc->sc_kstat == NULL)
2213		return;
2214
2215	myx_kstat_tick(sc);
2216}
2217
2218void
2219myx_kstat_stop(struct myx_softc *sc)
2220{
2221	struct myx_kstat_state *mks;
2222
2223	if (sc->sc_kstat == NULL)
2224		return;
2225
2226	timeout_del_barrier(&sc->sc_kstat_tmo);
2227
2228	mks = sc->sc_kstat->ks_ptr;
2229
2230	mtx_enter(&sc->sc_kstat_mtx);
2231	memset(mks, 0, sizeof(*mks));
2232	mtx_leave(&sc->sc_kstat_mtx);
2233}
2234
2235void
2236myx_kstat_attach(struct myx_softc *sc)
2237{
2238	struct kstat *ks;
2239	struct myx_kstats *mk;
2240	struct myx_kstat_state *mks;
2241	unsigned int i;
2242
2243	mtx_init(&sc->sc_kstat_mtx, IPL_SOFTCLOCK);
2244	timeout_set(&sc->sc_kstat_tmo, myx_kstat_tick, sc);
2245
2246	ks = kstat_create(DEVNAME(sc), 0, "myx-stats", 0, KSTAT_T_KV, 0);
2247	if (ks == NULL)
2248		return;
2249
2250	mk = malloc(sizeof(*mk), M_DEVBUF, M_WAITOK|M_ZERO);
2251	for (i = 0; i < myx_ncounters; i++) {
2252		const struct myx_counter *mc = &myx_counters[i];
2253
2254		kstat_kv_unit_init(&mk->mk_counters[i], mc->mc_name,
2255		    KSTAT_KV_T_COUNTER64, KSTAT_KV_U_PACKETS);
2256	}
2257	kstat_kv_init(&mk->mk_rdma_tags_available, "rdma tags free",
2258	    KSTAT_KV_T_UINT32);
2259
2260	mks = malloc(sizeof(*mks), M_DEVBUF, M_WAITOK|M_ZERO);
2261	/* these start at 0 */
2262
2263	kstat_set_mutex(ks, &sc->sc_kstat_mtx);
2264	ks->ks_data = mk;
2265	ks->ks_datalen = sizeof(*mk);
2266	ks->ks_read = myx_kstat_read;
2267	ks->ks_ptr = mks;
2268
2269	ks->ks_softc = sc;
2270	sc->sc_kstat = ks;
2271	kstat_install(ks);
2272}
2273#endif /* NKSTAT > 0 */
2274