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