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