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