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