if_myx.c revision 1.9
1/*	$OpenBSD: if_myx.c,v 1.9 2008/10/02 20:21:14 brad 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/sensors.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#define MYX_DEBUG
61#ifdef MYX_DEBUG
62#define MYXDBG_INIT	(1<<0)	/* chipset initialization */
63#define MYXDBG_CMD	(2<<0)	/* commands */
64#define MYXDBG_INTR	(3<<0)	/* interrupts */
65#define MYXDBG_ALL	0xffff	/* enable all debugging messages */
66int myx_debug = MYXDBG_ALL;
67#define DPRINTF(_lvl, _arg...)	do {					\
68	if (myx_debug & (_lvl))						\
69		printf(_arg);						\
70} while (0)
71#else
72#define DPRINTF(_lvl, arg...)
73#endif
74
75#define DEVNAME(_s)	((_s)->_s##_dev.dv_xname)
76
77struct myx_dmamem {
78	bus_dmamap_t		 mxm_map;
79	bus_dma_segment_t	 mxm_seg;
80	int			 mxm_nsegs;
81	size_t			 mxm_size;
82	caddr_t			 mxm_kva;
83	const char		*mxm_name;
84};
85
86struct myx_buf {
87	bus_dmamap_t		 mb_dmamap;
88	struct mbuf		*mb_m;
89};
90
91struct myx_softc {
92	struct device		 sc_dev;
93	struct arpcom		 sc_ac;
94
95	pci_chipset_tag_t	 sc_pc;
96	pcitag_t		 sc_tag;
97	u_int			 sc_function;
98
99	bus_dma_tag_t		 sc_dmat;
100	bus_space_tag_t		 sc_memt;
101	bus_space_handle_t	 sc_memh;
102	bus_size_t		 sc_mems;
103
104	struct myx_dmamem	 sc_cmddma;
105	struct myx_dmamem	 sc_paddma;
106
107	struct myx_dmamem	 sc_stsdma;
108	struct myx_status	*sc_sts;
109
110	struct myx_dmamem	 sc_rxdma;
111	struct myx_rxdesc	*sc_rxdesc;
112	struct myx_rxbufdesc	*sc_rxbufdesc[2];
113	struct myx_buf		*sc_rxbuf[2];
114#define  MYX_RXSMALL		 0
115#define  MYX_RXBIG		 1
116	int			 sc_rxactive;
117	int			 sc_rxidx;
118
119	void			*sc_irqh;
120	u_int32_t		 sc_irqcoaloff;
121	u_int32_t		 sc_irqclaimoff;
122	u_int32_t		 sc_irqdeassertoff;
123
124	u_int8_t		 sc_lladdr[ETHER_ADDR_LEN];
125	struct ifmedia		 sc_media;
126
127	u_int32_t		 sc_rxringsize;
128	u_int32_t		 sc_rxsmallringoff;
129	u_int32_t		 sc_rxbigringoff;
130	int			 sc_rxndesc;
131	size_t			 sc_rxdescsize;
132	size_t			 sc_rxbufsize;
133	size_t			 sc_rxbufdescsize;
134	u_int32_t		 sc_txringsize;
135	u_int32_t		 sc_txringoff;
136	int			 sc_txndesc;
137
138	u_int			 sc_phy;	/* PHY type (CX4/SR/LR) */
139	u_int			 sc_hwflags;
140#define  MYXFLAG_FLOW_CONTROL	 (1<<0)		/* Rx/Tx pause is enabled */
141#define  MYXFLAG_PROMISC	 (1<<1)		/* promisc mode is enabled */
142#define  MYXFLAG_ALLMULTI	 (1<<2)		/* allmulti is set */
143	u_int8_t		 sc_active;
144
145	struct timeout		 sc_tick;
146};
147
148int	 myx_match(struct device *, void *, void *);
149void	 myx_attach(struct device *, struct device *, void *);
150int	 myx_query(struct myx_softc *sc);
151u_int	 myx_ether_aton(char *, u_int8_t *, u_int);
152int	 myx_loadfirmware(struct myx_softc *, u_int8_t *, size_t,
153	    u_int32_t, int);
154void	 myx_attachhook(void *);
155void	 myx_read(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
156void	 myx_rawread(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
157void	 myx_write(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
158void	 myx_rawwrite(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
159int	 myx_cmd(struct myx_softc *, u_int32_t, struct myx_cmd *, u_int32_t *);
160int	 myx_boot(struct myx_softc *, u_int32_t, struct myx_bootcmd *);
161int	 myx_rdma(struct myx_softc *, u_int);
162int	 myx_reset(struct myx_softc *);
163int	 myx_dmamem_alloc(struct myx_softc *, struct myx_dmamem *,
164	    bus_size_t, u_int align, const char *);
165void	 myx_dmamem_free(struct myx_softc *, struct myx_dmamem *);
166int	 myx_media_change(struct ifnet *);
167void	 myx_media_status(struct ifnet *, struct ifmediareq *);
168void	 myx_link_state(struct myx_softc *);
169void	 myx_watchdog(struct ifnet *);
170void	 myx_tick(void *);
171int	 myx_ioctl(struct ifnet *, u_long, caddr_t);
172void	 myx_iff(struct myx_softc *);
173void	 myx_init(struct ifnet *);
174void	 myx_start(struct ifnet *);
175void	 myx_stop(struct ifnet *);
176int	 myx_setlladdr(struct myx_softc *, u_int8_t *);
177int	 myx_intr(void *);
178int	 myx_init_rings(struct myx_softc *);
179void	 myx_free_rings(struct myx_softc *);
180struct mbuf *myx_getbuf(struct myx_softc *, bus_dmamap_t, int);
181
182struct cfdriver myx_cd = {
183	0, "myx", DV_IFNET
184};
185struct cfattach myx_ca = {
186	sizeof(struct myx_softc), myx_match, myx_attach
187};
188
189const struct pci_matchid myx_devices[] = {
190	{ PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E }
191};
192
193int
194myx_match(struct device *parent, void *match, void *aux)
195{
196	return (pci_matchbyid((struct pci_attach_args *)aux,
197	    myx_devices, sizeof(myx_devices) / sizeof(myx_devices[0])));
198}
199
200void
201myx_attach(struct device *parent, struct device *self, void *aux)
202{
203	struct myx_softc	*sc = (struct myx_softc *)self;
204	struct pci_attach_args	*pa = aux;
205	pci_intr_handle_t	 ih;
206	pcireg_t		 memtype;
207	const char		*intrstr;
208	struct ifnet		*ifp;
209
210	sc->sc_pc = pa->pa_pc;
211	sc->sc_tag = pa->pa_tag;
212	sc->sc_dmat = pa->pa_dmat;
213	sc->sc_function = pa->pa_function;
214
215	/* Map the PCI memory space */
216	memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, MYXBAR0);
217	if (pci_mapreg_map(pa, MYXBAR0, memtype, 0, &sc->sc_memt,
218	    &sc->sc_memh, NULL, &sc->sc_mems, 0)) {
219		printf(": unable to map register memory\n");
220		return;
221	}
222
223	/* Get the board information and initialize the h/w */
224	if (myx_query(sc) != 0)
225		goto unmap;
226
227	/*
228	 * Allocate command DMA memory
229	 */
230	if (myx_dmamem_alloc(sc, &sc->sc_cmddma, MYXALIGN_CMD,
231	    MYXALIGN_CMD, "cmd") != 0) {
232		printf(": failed to allocate command DMA memory\n");
233		goto unmap;
234	}
235
236	if (myx_dmamem_alloc(sc, &sc->sc_paddma,
237	    MYXALIGN_CMD, MYXALIGN_CMD, "pad") != 0) {
238		printf(": failed to allocate pad DMA memory\n");
239		goto err2;
240	}
241
242	if (myx_dmamem_alloc(sc, &sc->sc_stsdma,
243	    sizeof(struct myx_status), MYXALIGN_DATA /* XXX */, "status") != 0) {
244		printf(": failed to allocate status DMA memory\n");
245		goto err1;
246	}
247	sc->sc_sts = (struct myx_status *)sc->sc_stsdma.mxm_kva;
248
249	/*
250	 * Map and establish the interrupt
251	 */
252	if (pci_intr_map(pa, &ih) != 0) {
253		printf(": unable to map interrupt\n");
254		goto err;
255	}
256	intrstr = pci_intr_string(pa->pa_pc, ih);
257	sc->sc_irqh = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
258	    myx_intr, sc, DEVNAME(sc));
259	if (sc->sc_irqh == NULL) {
260		printf(": unable to establish interrupt %s\n", intrstr);
261		goto err;
262	}
263	printf(": %s, address %s\n", intrstr,
264	    ether_sprintf(sc->sc_ac.ac_enaddr));
265
266	ifp = &sc->sc_ac.ac_if;
267	ifp->if_softc = sc;
268	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
269	ifp->if_ioctl = myx_ioctl;
270	ifp->if_start = myx_start;
271	ifp->if_watchdog = myx_watchdog;
272	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
273	IFQ_SET_MAXLEN(&ifp->if_snd, MYX_NTXDESC_MIN - 1);
274	IFQ_SET_READY(&ifp->if_snd);
275
276	ifp->if_capabilities = IFCAP_VLAN_MTU;
277#if 0
278	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
279	ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
280		    IFCAP_CSUM_UDPv4;
281#endif
282	ifp->if_baudrate = IF_Gbps(10);
283
284	ifmedia_init(&sc->sc_media, 0,
285	    myx_media_change, myx_media_status);
286	ifmedia_add(&sc->sc_media, IFM_ETHER|sc->sc_phy, 0, NULL);
287	ifmedia_set(&sc->sc_media, IFM_ETHER|sc->sc_phy);
288
289	if_attach(ifp);
290	ether_ifattach(ifp);
291
292	timeout_set(&sc->sc_tick, myx_tick, sc);
293	timeout_add_sec(&sc->sc_tick, 1);
294
295	mountroothook_establish(myx_attachhook, sc);
296
297	return;
298
299 err:
300	myx_dmamem_free(sc, &sc->sc_stsdma);
301 err1:
302	myx_dmamem_free(sc, &sc->sc_paddma);
303 err2:
304	myx_dmamem_free(sc, &sc->sc_cmddma);
305 unmap:
306	bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
307	sc->sc_mems = 0;
308}
309
310u_int
311myx_ether_aton(char *mac, u_int8_t *lladdr, u_int maxlen)
312{
313	u_int		i, j;
314	u_int8_t	digit;
315
316	bzero(lladdr, ETHER_ADDR_LEN);
317	for (i = j = 0; mac[i] != '\0' && i < maxlen; i++) {
318		if (mac[i] >= '0' && mac[i] <= '9')
319			digit = mac[i] - '0';
320		else if (mac[i] >= 'A' && mac[i] <= 'F')
321			digit = mac[i] - 'A' + 10;
322		else if (mac[i] >= 'a' && mac[i] <= 'f')
323			digit = mac[i] - 'a' + 10;
324		else
325			continue;
326		if ((j & 1) == 0)
327			digit <<= 4;
328		lladdr[j++/2] |= digit;
329	}
330
331	return (i);
332}
333
334int
335myx_query(struct myx_softc *sc)
336{
337	u_int8_t	eeprom[MYX_EEPROM_SIZE];
338	u_int		i, maxlen;
339
340	myx_read(sc, MYX_EEPROM, eeprom, MYX_EEPROM_SIZE);
341
342	for (i = 0; i < MYX_EEPROM_SIZE; i++) {
343		maxlen = MYX_EEPROM_SIZE - i;
344		if (eeprom[i] == '\0')
345			break;
346		if (maxlen > 4 && bcmp("MAC=", &eeprom[i], 4) == 0) {
347			i += 4;
348			i += myx_ether_aton(&eeprom[i],
349			    sc->sc_ac.ac_enaddr, maxlen);
350		}
351		for (; i < MYX_EEPROM_SIZE; i++)
352			if (eeprom[i] == '\0')
353				break;
354	}
355
356	return (0);
357}
358
359int
360myx_loadfirmware(struct myx_softc *sc, u_int8_t *fw, size_t fwlen,
361    u_int32_t fwhdroff, int reload)
362{
363	struct myx_firmware_hdr	*fwhdr;
364	u_int			 i, len, ret = 0;
365
366	fwhdr = (struct myx_firmware_hdr *)(fw + fwhdroff);
367	DPRINTF(MYXDBG_INIT, "%s(%s): "
368	    "fw hdr off %d, length %d, type 0x%x, version %s\n",
369	    DEVNAME(sc), __func__,
370	    fwhdroff, betoh32(fwhdr->fw_hdrlength),
371	    betoh32(fwhdr->fw_type),
372	    fwhdr->fw_version);
373
374	if (betoh32(fwhdr->fw_type) != MYXFW_TYPE_ETH ||
375	    bcmp(MYXFW_VER, fwhdr->fw_version, strlen(MYXFW_VER)) != 0) {
376		if (reload)
377			printf("%s: invalid firmware type 0x%x version %s\n",
378			    DEVNAME(sc), betoh32(fwhdr->fw_type),
379			    fwhdr->fw_version);
380		ret = 1;
381		goto done;
382	}
383
384	if (!reload)
385		goto done;
386
387	/* Write the firmware to the card's SRAM */
388	for (i = 0; i < fwlen; i += 256) {
389		len = min(256, fwlen - i);
390		myx_rawwrite(sc, i + MYX_FW, fw + i, min(256, fwlen - i));
391	}
392
393 done:
394	free(fw, M_DEVBUF);
395	return (ret);
396}
397
398void
399myx_attachhook(void *arg)
400{
401	struct myx_softc	*sc = (struct myx_softc *)arg;
402	size_t			 fwlen;
403	u_int8_t		*fw = NULL;
404	u_int32_t		 fwhdroff;
405	struct myx_bootcmd	 bc;
406
407	/*
408	 * First try the firmware found in the SRAM
409	 */
410	myx_read(sc, MYX_HEADER_POS, (u_int8_t *)&fwhdroff, sizeof(fwhdroff));
411	fwhdroff = betoh32(fwhdroff);
412	fwlen = sizeof(struct myx_firmware_hdr);
413	if ((fwhdroff + fwlen) > MYX_SRAM_SIZE)
414		goto load;
415
416	fw = malloc(fwlen, M_DEVBUF, M_WAIT);
417	myx_rawread(sc, MYX_HEADER_POS, fw, fwlen);
418
419	if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 0) == 0)
420		goto boot;
421
422 load:
423	/*
424	 * Now try the firmware stored on disk
425	 */
426	if (loadfirmware(MYXFW_ALIGNED /* XXX */, &fw, &fwlen) != 0) {
427		printf("%s: could not load firmware\n", DEVNAME(sc));
428		return;
429	}
430	if (fwlen > MYX_SRAM_SIZE || fwlen < MYXFW_MIN_LEN) {
431		printf("%s: invalid firmware image size\n", DEVNAME(sc));
432		goto err;
433	}
434
435	bcopy(fw + MYX_HEADER_POS, &fwhdroff, sizeof(fwhdroff));
436	fwhdroff = betoh32(fwhdroff);
437	if ((fwhdroff + sizeof(struct myx_firmware_hdr)) > fwlen) {
438		printf("%s: invalid firmware image\n", DEVNAME(sc));
439		goto err;
440	}
441
442	if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 1) != 0) {
443		fw = NULL;
444		goto err;
445	}
446	fw = NULL;
447
448 boot:
449	bzero(&bc, sizeof(bc));
450	if (myx_boot(sc, fwlen, &bc) != 0) {
451		printf("%s: failed to bootstrap the device\n", DEVNAME(sc));
452		goto err;
453	}
454	if (myx_reset(sc) != 0)
455		goto err;
456
457	sc->sc_active = 1;
458	return;
459
460 err:
461	if (fw != NULL)
462		free(fw, M_DEVBUF);
463}
464
465void
466myx_read(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len)
467{
468	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
469	    BUS_SPACE_BARRIER_READ);
470	bus_space_read_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len / 4);
471}
472
473void
474myx_rawread(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr,
475    bus_size_t len)
476{
477	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
478	    BUS_SPACE_BARRIER_READ);
479	bus_space_read_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
480}
481
482void
483myx_write(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len)
484{
485	bus_space_write_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len / 4);
486	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
487	    BUS_SPACE_BARRIER_WRITE);
488}
489
490void
491myx_rawwrite(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr,
492    bus_size_t len)
493{
494	bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
495	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
496	    BUS_SPACE_BARRIER_WRITE);
497}
498
499int
500myx_dmamem_alloc(struct myx_softc *sc, struct myx_dmamem *mxm,
501    bus_size_t size, u_int align, const char *mname)
502{
503	mxm->mxm_size = size;
504
505	if (bus_dmamap_create(sc->sc_dmat, mxm->mxm_size, 1,
506	    mxm->mxm_size, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
507	    &mxm->mxm_map) != 0)
508		return (1);
509	if (bus_dmamem_alloc(sc->sc_dmat, mxm->mxm_size,
510	    align, 0, &mxm->mxm_seg, 1, &mxm->mxm_nsegs,
511	    BUS_DMA_WAITOK) != 0)
512		goto destroy;
513	if (bus_dmamem_map(sc->sc_dmat, &mxm->mxm_seg, mxm->mxm_nsegs,
514	    mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_WAITOK) != 0)
515		goto free;
516	if (bus_dmamap_load(sc->sc_dmat, mxm->mxm_map, mxm->mxm_kva,
517	    mxm->mxm_size, NULL, BUS_DMA_WAITOK) != 0)
518		goto unmap;
519
520	bzero(mxm->mxm_kva, mxm->mxm_size);
521	mxm->mxm_name = mname;
522
523	return (0);
524 unmap:
525	bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
526 free:
527	bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
528 destroy:
529	bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
530	return (1);
531}
532
533void
534myx_dmamem_free(struct myx_softc *sc, struct myx_dmamem *mxm)
535{
536	bus_dmamap_unload(sc->sc_dmat, mxm->mxm_map);
537	bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
538	bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
539	bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
540}
541
542int
543myx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r)
544{
545	bus_dmamap_t		 map = sc->sc_cmddma.mxm_map;
546	struct myx_response	*mr;
547	u_int			 i;
548	u_int32_t		 result, data;
549#ifdef MYX_DEBUG
550	static const char *cmds[MYXCMD_MAX] = {
551		"CMD_NONE",
552		"CMD_RESET",
553		"CMD_GET_VERSION",
554		"CMD_SET_INTRQDMA",
555		"CMD_SET_BIGBUFSZ",
556		"CMD_SET_SMALLBUFSZ",
557		"CMD_GET_TXRINGOFF",
558		"CMD_GET_RXSMALLRINGOFF",
559		"CMD_GET_RXBIGRINGOFF",
560		"CMD_GET_INTRACKOFF",
561		"CMD_GET_INTRDEASSERTOFF",
562		"CMD_GET_TXRINGSZ",
563		"CMD_GET_RXRINGSZ",
564		"CMD_SET_INTRQSZ",
565		"CMD_SET_IFUP",
566		"CMD_SET_IFDOWN",
567		"CMD_SET_MTU",
568		"CMD_GET_INTRCOALDELAYOFF",
569		"CMD_SET_STATSINTVL",
570		"CMD_SET_STATSDMA_OLD",
571		"CMD_SET_PROMISC",
572		"CMD_UNSET_PROMISC",
573		"CMD_SET_LLADDR",
574		"CMD_SET_FC",
575		"CMD_UNSET_FC",
576		"CMD_DMA_TEST",
577		"CMD_SET_ALLMULTI",
578		"CMD_UNSET_ALLMULTI",
579		"CMD_SET_MCASTGROUP",
580		"CMD_UNSET_MCASTGROUP",
581		"CMD_UNSET_MCAST",
582		"CMD_SET_STATSDMA",
583		"CMD_UNALIGNED_DMA_TEST",
584		"CMD_GET_UNALIGNED_STATUS"
585	};
586#endif
587
588	mc->mc_cmd = htobe32(cmd);
589	mc->mc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
590	mc->mc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
591
592	mr = (struct myx_response *)sc->sc_cmddma.mxm_kva;
593	mr->mr_result = 0xffffffff;
594
595	/* Send command */
596	myx_write(sc, MYX_CMD, (u_int8_t *)mc, sizeof(struct myx_cmd));
597
598	for (i = 0; i < 20; i++) {
599		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
600		    BUS_DMASYNC_POSTREAD);
601		result = betoh32(mr->mr_result);
602		data = betoh32(mr->mr_data);
603
604		if (result != 0xffffffff)
605			break;
606		delay(1000);
607	}
608
609	DPRINTF(MYXDBG_CMD, "%s(%s): %s completed, i %d, "
610	    "result 0x%x, data 0x%x (%u)\n", DEVNAME(sc), __func__,
611	    cmds[cmd], i, result, data, data);
612
613	if (result != 0)
614		return (-1);
615
616	if (r != NULL)
617		*r = data;
618	return (0);
619}
620
621int
622myx_boot(struct myx_softc *sc, u_int32_t length, struct myx_bootcmd *bc)
623{
624	bus_dmamap_t		 map = sc->sc_cmddma.mxm_map;
625	u_int32_t		*status;
626	u_int			 i;
627
628	bc->bc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
629	bc->bc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
630	bc->bc_result = 0xffffffff;
631	bc->bc_offset = htobe32(MYX_FW_BOOT);
632	bc->bc_length = htobe32(length);
633	bc->bc_copyto = htobe32(8);
634	bc->bc_jumpto = htobe32(0);
635
636	status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
637	*status = 0;
638
639	/* Send command */
640	myx_write(sc, MYX_BOOT, (u_int8_t *)bc, sizeof(struct myx_bootcmd));
641
642	for (i = 0; i < 200; i++) {
643		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
644		    BUS_DMASYNC_POSTREAD);
645		if (*status == 0xffffffff)
646			break;
647		delay(1000);
648	}
649
650	DPRINTF(MYXDBG_CMD, "%s(%s): boot completed, i %d, result 0x%x\n",
651	    DEVNAME(sc), __func__, i, betoh32(*status));
652
653	if (*status != 0xffffffff)
654		return (-1);
655
656	return (0);
657}
658
659int
660myx_rdma(struct myx_softc *sc, u_int do_enable)
661{
662	struct myx_rdmacmd	 rc;
663	bus_dmamap_t		 map = sc->sc_cmddma.mxm_map;
664	bus_dmamap_t		 pad = sc->sc_paddma.mxm_map;
665	u_int32_t		*status;
666	u_int			 i;
667
668	/*
669	 * It is required to setup a _dummy_ RDMA address. It also makes
670	 * some PCI-E chipsets resend dropped messages.
671	 */
672	rc.rc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
673	rc.rc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
674	rc.rc_result = 0xffffffff;
675	rc.rc_rdma_high = htobe32(MYX_ADDRHIGH(pad->dm_segs[0].ds_addr));
676	rc.rc_rdma_low = htobe32(MYX_ADDRLOW(pad->dm_segs[0].ds_addr));
677	rc.rc_enable = htobe32(do_enable);
678
679	status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
680	*status = 0;
681
682	/* Send command */
683	myx_write(sc, MYX_RDMA, (u_int8_t *)&rc, sizeof(struct myx_rdmacmd));
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		if (*status == 0xffffffff)
689			break;
690		delay(1000);
691	}
692
693	DPRINTF(MYXDBG_CMD, "%s(%s): dummy RDMA %s, i %d, result 0x%x\n",
694	    DEVNAME(sc), __func__,
695	    do_enable ? "enabled" : "disabled", i, betoh32(*status));
696
697	if (*status != 0xffffffff)
698		return (-1);
699
700	return (0);
701}
702
703int
704myx_reset(struct myx_softc *sc)
705{
706	struct myx_cmd		 mc;
707	u_int32_t		 data;
708	struct ifnet		*ifp = &sc->sc_ac.ac_if;
709
710	bzero(&mc, sizeof(mc));
711	if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
712		printf("%s: failed to reset the device\n", DEVNAME(sc));
713		return (-1);
714	}
715
716	if (myx_rdma(sc, MYXRDMA_ON) != 0) {
717		printf("%s: failed to enable dummy RDMA\n", DEVNAME(sc));
718		return (-1);
719	}
720
721	if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc,
722	    &sc->sc_irqcoaloff) != 0) {
723		printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc));
724		return (-1);
725	}
726	data = htobe32(MYX_IRQCOALDELAY);
727	myx_write(sc, sc->sc_irqcoaloff, (u_int8_t *)&data, sizeof(data));
728
729	if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc,
730	    &sc->sc_irqclaimoff) != 0) {
731		printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc));
732		return (-1);
733	}
734
735	if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc,
736	    &sc->sc_irqdeassertoff) != 0) {
737		printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc));
738		return (-1);
739	}
740
741	if (myx_cmd(sc, MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) {
742		printf("%s: failed to disable promisc mode\n", DEVNAME(sc));
743		return (-1);
744	}
745
746	if (myx_cmd(sc, MYXCMD_FC_DEFAULT, &mc, NULL) != 0) {
747		printf("%s: failed to configure flow control\n", DEVNAME(sc));
748		return (-1);
749	}
750
751	if (myx_setlladdr(sc, LLADDR(ifp->if_sadl)) != 0)
752		return (-1);
753
754	return (0);
755}
756
757
758int
759myx_media_change(struct ifnet *ifp)
760{
761	return (EINVAL);
762}
763
764void
765myx_media_status(struct ifnet *ifp, struct ifmediareq *imr)
766{
767	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
768
769	imr->ifm_active = IFM_ETHER|sc->sc_phy;
770	imr->ifm_status = IFM_AVALID;
771	myx_link_state(sc);
772	if (!LINK_STATE_IS_UP(ifp->if_link_state))
773		return;
774	imr->ifm_active |= IFM_FDX;
775	imr->ifm_status |= IFM_ACTIVE;
776
777	/* Flow control */
778	if (sc->sc_hwflags & MYXFLAG_FLOW_CONTROL)
779		imr->ifm_active |= IFM_FLOW|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE;
780}
781
782void
783myx_link_state(struct myx_softc *sc)
784{
785	struct ifnet		*ifp = &sc->sc_ac.ac_if;
786	int			 link_state = LINK_STATE_DOWN;
787
788	if (sc->sc_sts == NULL)
789		return;
790	if (sc->sc_sts->ms_linkstate == MYXSTS_LINKUP)
791		link_state = LINK_STATE_FULL_DUPLEX;
792	if (ifp->if_link_state != link_state) {
793		ifp->if_link_state = link_state;
794		if_link_state_change(ifp);
795	}
796}
797
798void
799myx_watchdog(struct ifnet *ifp)
800{
801	return;
802}
803
804void
805myx_tick(void *arg)
806{
807	struct myx_softc	*sc = (struct myx_softc *)arg;
808
809	if (!sc->sc_active)
810		return;
811
812	myx_link_state(sc);
813	timeout_add_sec(&sc->sc_tick, 1);
814}
815
816int
817myx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
818{
819	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
820	struct ifaddr		*ifa = (struct ifaddr *)data;
821	struct ifreq		*ifr = (struct ifreq *)data;
822	int			 s, error = 0;
823
824	s = splnet();
825
826	switch (cmd) {
827	case SIOCSIFADDR:
828		ifp->if_flags |= IFF_UP;
829#ifdef INET
830		if (ifa->ifa_addr->sa_family == AF_INET)
831			arp_ifinit(&sc->sc_ac, ifa);
832#endif
833		/* FALLTHROUGH */
834	case SIOCSIFFLAGS:
835		if (ifp->if_flags & IFF_UP) {
836			if (ifp->if_flags & IFF_RUNNING)
837				myx_iff(sc);
838			else
839				myx_init(ifp);
840		} else {
841			if (ifp->if_flags & IFF_RUNNING)
842				myx_stop(ifp);
843		}
844		break;
845
846	case SIOCSIFMTU:
847		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu)
848			error = EINVAL;
849		else if (ifp->if_mtu != ifr->ifr_mtu)
850			ifp->if_mtu = ifr->ifr_mtu;
851		break;
852
853	case SIOCADDMULTI:
854		error = ether_addmulti(ifr, &sc->sc_ac);
855		break;
856
857	case SIOCDELMULTI:
858		error = ether_delmulti(ifr, &sc->sc_ac);
859		break;
860
861	case SIOCGIFMEDIA:
862	case SIOCSIFMEDIA:
863		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
864		break;
865
866	default:
867		error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
868	}
869
870	if (error == ENETRESET) {
871		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
872		    (IFF_UP | IFF_RUNNING))
873			myx_iff(sc);
874		error = 0;
875	}
876
877	splx(s);
878	return (error);
879}
880
881void
882myx_iff(struct myx_softc *sc)
883{
884	/* XXX set multicast filters etc. */
885	return;
886}
887
888void
889myx_init(struct ifnet *ifp)
890{
891	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
892	struct myx_cmd		 mc;
893
894	if (myx_reset(sc) != 0)
895		return;
896
897	if (myx_init_rings(sc) != 0)
898		return;
899
900	if (myx_cmd(sc, MYXCMD_SET_IFUP, &mc, NULL) != 0) {
901		printf("%s: failed to start the device\n", DEVNAME(sc));
902		myx_free_rings(sc);
903		return;
904	}
905
906	ifp->if_flags |= IFF_RUNNING;
907	ifp->if_flags &= ~IFF_OACTIVE;
908}
909
910void
911myx_start(struct ifnet *ifp)
912{
913}
914
915void
916myx_stop(struct ifnet *ifp)
917{
918	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
919	struct myx_cmd		 mc;
920
921	bzero(&mc, sizeof(mc));
922	(void)myx_cmd(sc, MYXCMD_SET_IFDOWN, &mc, NULL);
923	myx_free_rings(sc);
924
925	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
926}
927
928int
929myx_setlladdr(struct myx_softc *sc, u_int8_t *addr)
930{
931	struct myx_cmd		 mc;
932
933	bzero(&mc, sizeof(mc));
934	mc.mc_data0 = addr[3] | addr[2] << 8 | addr[1] << 16 | addr[0] << 24;
935	mc.mc_data1 = addr[5] | addr[4] << 8;
936	if (myx_cmd(sc, MYXCMD_SET_LLADDR, &mc, NULL) != 0) {
937		printf("%s: failed to set the lladdr\n", DEVNAME(sc));
938		return (-1);
939	}
940	return (0);
941}
942
943int
944myx_intr(void *arg)
945{
946	struct myx_softc	*sc = (struct myx_softc *)arg;
947	u_int32_t		 data, valid;
948	struct myx_status	*sts = sc->sc_sts;
949	bus_dmamap_t		 map = sc->sc_stsdma.mxm_map;
950
951	if (!sc->sc_active)
952		return (0);
953
954	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
955	    BUS_DMASYNC_POSTWRITE);
956
957	/*
958	 * XXX The 'valid' flags should be set by the NIC, but it doesn't
959	 * XXX work yet.
960	 */
961	valid = sts->ms_isvalid;
962	if (!valid)
963		return (0);
964
965	data = 0;
966	myx_write(sc, sc->sc_irqdeassertoff, (u_int8_t *)&data, sizeof(data));
967
968	DPRINTF(MYXDBG_INTR, "%s(%s): interrupt, valid 0x%x\n",
969	    DEVNAME(sc), __func__, valid);
970
971#ifdef MYX_DEBUG
972#define DPRINT_STATUS(_n)						\
973	DPRINTF(MYXDBG_INTR, "%s(%s): %s: %u, 0x%x\n", DEVNAME(sc), __func__,\
974	    #_n, sts->_n, sts->_n)
975
976	DPRINT_STATUS(ms_reserved);
977	DPRINT_STATUS(ms_dropped_pause);
978	DPRINT_STATUS(ms_dropped_unicast);
979	DPRINT_STATUS(ms_dropped_crc32err);
980	DPRINT_STATUS(ms_dropped_phyerr);
981	DPRINT_STATUS(ms_dropped_mcast);
982	DPRINT_STATUS(ms_txdonecnt);
983	DPRINT_STATUS(ms_linkstate);
984	DPRINT_STATUS(ms_dropped_linkoverflow);
985	DPRINT_STATUS(ms_dropped_linkerror);
986	DPRINT_STATUS(ms_dropped_runt);
987	DPRINT_STATUS(ms_dropped_overrun);
988	DPRINT_STATUS(ms_dropped_smallbufunderrun);
989	DPRINT_STATUS(ms_dropped_bigbufunderrun);
990	DPRINT_STATUS(ms_rdmatags_available);
991	DPRINT_STATUS(ms_txstopped);
992	DPRINT_STATUS(ms_linkdowncnt);
993	DPRINT_STATUS(ms_statusupdated);
994	DPRINT_STATUS(ms_isvalid);
995#endif
996
997	data = htobe32(3);
998	if (sts->ms_isvalid)
999		myx_write(sc, sc->sc_irqclaimoff, (u_int8_t *)&data,
1000		    sizeof(data));
1001	myx_write(sc, sc->sc_irqclaimoff + sizeof(u_int32_t),
1002	    (u_int8_t *)&data, sizeof(data));
1003
1004	return (1);
1005}
1006
1007int
1008myx_init_rings(struct myx_softc *sc)
1009{
1010	struct myx_cmd		 mc;
1011	struct ifnet		*ifp = &sc->sc_ac.ac_if;
1012	bus_dmamap_t		 map;
1013	int			 i;
1014	struct myx_buf		*mb;
1015	struct myx_rxbufdesc	*rxb;
1016	u_int32_t		 data;
1017
1018	bzero(&mc, sizeof(mc));
1019	if (!(myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc,
1020	    &sc->sc_rxringsize) == 0 && sc->sc_rxringsize &&
1021	    myx_cmd(sc, MYXCMD_GET_RXSMALLRINGOFF, &mc,
1022	    &sc->sc_rxsmallringoff) == 0 && sc->sc_rxsmallringoff &&
1023	    myx_cmd(sc, MYXCMD_GET_RXBIGRINGOFF, &mc,
1024	    &sc->sc_rxbigringoff) == 0 && sc->sc_rxbigringoff &&
1025	    myx_cmd(sc, MYXCMD_GET_TXRINGSZ, &mc,
1026	    &sc->sc_txringsize) == 0 && sc->sc_txringsize &&
1027	    myx_cmd(sc, MYXCMD_GET_TXRINGOFF, &mc,
1028	    &sc->sc_txringoff) == 0 && sc->sc_txringoff)) {
1029		printf("%s: failed to get ring sizes and offsets\n",
1030		    DEVNAME(sc));
1031		return (-1);
1032	}
1033	sc->sc_rxndesc = sc->sc_rxringsize / sizeof(struct myx_rxbufdesc);
1034	sc->sc_txndesc = sc->sc_txringsize / sizeof(struct myx_txdesc);
1035	sc->sc_rxdescsize = sc->sc_rxndesc * 2 * sizeof(struct myx_rxdesc);
1036	sc->sc_rxbufsize = sc->sc_rxndesc * sizeof(struct myx_buf);
1037	sc->sc_rxbufdescsize = sc->sc_rxndesc * sizeof(struct myx_rxbufdesc);
1038	IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_txndesc - 1);
1039	IFQ_SET_READY(&ifp->if_snd);
1040
1041	DPRINTF(MYXDBG_INIT, "%s(%s): Rx ring ndesc %u size %u bufsize %u, "
1042	    "Tx ring ndesc %u size %u offset 0x%x\n", DEVNAME(sc), __func__,
1043	    sc->sc_rxndesc, sc->sc_rxdescsize, sc->sc_rxringsize,
1044	    sc->sc_txndesc, sc->sc_txringsize, sc->sc_txringoff);
1045
1046	/*
1047	 * Setup Rx DMA descriptors
1048	 */
1049	if (myx_dmamem_alloc(sc, &sc->sc_rxdma,
1050	    sc->sc_rxdescsize, MYXALIGN_DATA, "rxring") != 0) {
1051		printf(": failed to allocate Rx DMA memory\n");
1052		return (-1);
1053	}
1054	sc->sc_rxdesc = (struct myx_rxdesc *)sc->sc_rxdma.mxm_kva;
1055
1056	bzero(&mc, sizeof(mc));
1057	mc.mc_data0 = htobe32(sc->sc_rxdescsize);
1058	if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) {
1059		printf("%s: failed to set Rx DMA size\n", DEVNAME(sc));
1060		goto err;
1061	}
1062
1063	map = sc->sc_rxdma.mxm_map;
1064	mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr);
1065	mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr);
1066	if (myx_cmd(sc, MYXCMD_SET_INTRQDMA, &mc, NULL) != 0) {
1067		printf("%s: failed to set Rx DMA address\n", DEVNAME(sc));
1068		goto err;
1069	}
1070
1071#ifdef notyet
1072	/*
1073	 * XXX It fails to set the MTU and it always returns
1074	 * XXX MYXCMD_ERR_RANGE.
1075	 */
1076	bzero(&mc, sizeof(mc));
1077	mc.mc_data0 = ifp->if_mtu + ETHER_HDR_LEN + 4;
1078	if (myx_cmd(sc, MYXCMD_SET_MTU, &mc, NULL) != 0) {
1079		printf("%s: failed to set MTU size %d\n",
1080		    DEVNAME(sc), ifp->if_mtu + ETHER_HDR_LEN + 4);
1081		goto err;
1082	}
1083#endif
1084
1085	/*
1086	 * Setup Rx buffer descriptors
1087	 */
1088	sc->sc_rxbuf[MYX_RXSMALL] = (struct myx_buf *)
1089	    malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK);
1090	sc->sc_rxbufdesc[MYX_RXSMALL] = (struct myx_rxbufdesc *)
1091	    malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK);
1092	sc->sc_rxbuf[MYX_RXBIG] = (struct myx_buf *)
1093	    malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK);
1094	sc->sc_rxbufdesc[MYX_RXBIG] = (struct myx_rxbufdesc *)
1095	    malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK);
1096	if (sc->sc_rxbuf[MYX_RXSMALL] == NULL ||
1097	    sc->sc_rxbufdesc[MYX_RXSMALL] == NULL ||
1098	    sc->sc_rxbuf[MYX_RXBIG] == NULL ||
1099	    sc->sc_rxbufdesc[MYX_RXBIG] == NULL) {
1100		printf("%s: failed to allocate rx buffers\n", DEVNAME(sc));
1101		goto err;
1102	}
1103
1104	for (i = 0; i < sc->sc_rxndesc; i++) {
1105		/*
1106		 * Small Rx buffers and descriptors
1107		 */
1108		mb = sc->sc_rxbuf[MYX_RXSMALL] + i;
1109		rxb = sc->sc_rxbufdesc[MYX_RXSMALL] + i;
1110
1111		if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
1112		    MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) {
1113			printf("%s: unable to create dmamap for small rx %d\n",
1114			    DEVNAME(sc), i);
1115			goto err;
1116		}
1117
1118		map = mb->mb_dmamap;
1119		mb->mb_m = myx_getbuf(sc, map, 1);
1120		if (mb->mb_m == NULL) {
1121			bus_dmamap_destroy(sc->sc_dmat, map);
1122			goto err;
1123		}
1124
1125		bus_dmamap_sync(sc->sc_dmat, map, 0,
1126		    mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
1127
1128		rxb->rb_addr_high =
1129		    htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1130		rxb->rb_addr_low =
1131		    htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1132
1133		data = sc->sc_rxsmallringoff + i * sizeof(*rxb);
1134		myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb));
1135
1136		/*
1137		 * Big Rx buffers and descriptors
1138		 */
1139		mb = sc->sc_rxbuf[MYX_RXBIG] + i;
1140		rxb = sc->sc_rxbufdesc[MYX_RXBIG] + i;
1141
1142		if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
1143		    MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) {
1144			printf("%s: unable to create dmamap for big rx %d\n",
1145			    DEVNAME(sc), i);
1146			goto err;
1147		}
1148
1149		map = mb->mb_dmamap;
1150		mb->mb_m = myx_getbuf(sc, map, 1);
1151		if (mb->mb_m == NULL) {
1152			bus_dmamap_destroy(sc->sc_dmat, map);
1153			goto err;
1154		}
1155
1156		bus_dmamap_sync(sc->sc_dmat, map, 0,
1157		    mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
1158
1159		rxb->rb_addr_high =
1160		    htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1161		rxb->rb_addr_low =
1162		    htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1163
1164		data = sc->sc_rxbigringoff + i * sizeof(*rxb);
1165		myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb));
1166	}
1167
1168	bzero(&mc, sizeof(mc));
1169	mc.mc_data0 = MYX_MAX_MTU_SMALL;
1170	if (myx_cmd(sc, MYXCMD_SET_SMALLBUFSZ, &mc, NULL) != 0) {
1171		printf("%s: failed to set small buf size\n", DEVNAME(sc));
1172		goto err;
1173	}
1174
1175	bzero(&mc, sizeof(mc));
1176	mc.mc_data0 = MCLBYTES;
1177	if (myx_cmd(sc, MYXCMD_SET_BIGBUFSZ, &mc, NULL) != 0) {
1178		printf("%s: failed to set big buf size\n", DEVNAME(sc));
1179		goto err;
1180	}
1181
1182	/*
1183	 * Setup status DMA
1184	 */
1185	map = sc->sc_stsdma.mxm_map;
1186
1187	bzero(&mc, sizeof(mc));
1188	mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr);
1189	mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr);
1190	mc.mc_data2 = sizeof(struct myx_status);
1191	if (myx_cmd(sc, MYXCMD_SET_STATSDMA, &mc, NULL) != 0) {
1192		printf("%s: failed to set status DMA offset\n", DEVNAME(sc));
1193		goto err;
1194	}
1195
1196	bus_dmamap_sync(sc->sc_dmat, map, 0,
1197	    map->dm_mapsize, BUS_DMASYNC_PREWRITE);
1198
1199	return (0);
1200 err:
1201	myx_free_rings(sc);
1202	return (-1);
1203}
1204
1205void
1206myx_free_rings(struct myx_softc *sc)
1207{
1208	if (sc->sc_rxbuf[MYX_RXSMALL] != NULL) {
1209		free(sc->sc_rxbuf[MYX_RXSMALL], M_DEVBUF);
1210		sc->sc_rxbuf[MYX_RXSMALL] = NULL;
1211	}
1212	if (sc->sc_rxbufdesc[MYX_RXSMALL] != NULL) {
1213		free(sc->sc_rxbufdesc[MYX_RXSMALL], M_DEVBUF);
1214		sc->sc_rxbufdesc[MYX_RXSMALL] = NULL;
1215	}
1216	if (sc->sc_rxbuf[MYX_RXBIG] != NULL) {
1217		free(sc->sc_rxbuf[MYX_RXBIG], M_DEVBUF);
1218		sc->sc_rxbuf[MYX_RXBIG] = NULL;
1219	}
1220	if (sc->sc_rxbufdesc[MYX_RXBIG] != NULL) {
1221		free(sc->sc_rxbufdesc[MYX_RXBIG], M_DEVBUF);
1222		sc->sc_rxbufdesc[MYX_RXBIG] = NULL;
1223	}
1224	if (sc->sc_rxdesc != NULL) {
1225		myx_dmamem_free(sc, &sc->sc_rxdma);
1226		sc->sc_rxdesc = NULL;
1227	}
1228	if (sc->sc_sts != NULL) {
1229		myx_dmamem_free(sc, &sc->sc_stsdma);
1230		sc->sc_sts = NULL;
1231	}
1232	return;
1233}
1234
1235struct mbuf *
1236myx_getbuf(struct myx_softc *sc, bus_dmamap_t map, int wait)
1237{
1238	struct mbuf		*m = NULL;
1239
1240	MGETHDR(m, wait ? M_WAIT : M_DONTWAIT, MT_DATA);
1241	if (m == NULL)
1242		goto merr;
1243
1244	MCLGET(m, wait ? M_WAIT : M_DONTWAIT);
1245	if ((m->m_flags & M_EXT) == 0)
1246		goto merr;
1247	m->m_len = m->m_pkthdr.len = MCLBYTES;
1248
1249	if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
1250	    wait ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) != 0) {
1251		printf("%s: could not load mbuf dma map\n", DEVNAME(sc));
1252		goto err;
1253	}
1254
1255	return (m);
1256 merr:
1257	printf("%s: unable to allocate mbuf\n", DEVNAME(sc));
1258 err:
1259	if (m != NULL)
1260		m_freem(m);
1261	return (NULL);
1262}
1263