if_myx.c revision 1.5
180708Sjake/*	$OpenBSD: if_myx.c,v 1.5 2007/06/01 18:07:08 reyk Exp $	*/
286228Stmm
380708Sjake/*
480708Sjake * Copyright (c) 2007 Reyk Floeter <reyk@openbsd.org>
586228Stmm *
686228Stmm * Permission to use, copy, modify, and distribute this software for any
786228Stmm * purpose with or without fee is hereby granted, provided that the above
886228Stmm * copyright notice and this permission notice appear in all copies.
980708Sjake *
1080708Sjake * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1180708Sjake * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1280708Sjake * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1380708Sjake * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1480708Sjake * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1580708Sjake * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1680708Sjake * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1780708Sjake */
1886228Stmm
1986228Stmm/*
2086228Stmm * Driver for the Myricom Myri-10G Lanai-Z8E Ethernet chipsets.
2186228Stmm */
2286228Stmm
2386228Stmm#include "bpfilter.h"
2486228Stmm
2586228Stmm#include <sys/param.h>
2686228Stmm#include <sys/systm.h>
2786228Stmm#include <sys/sockio.h>
2886228Stmm#include <sys/mbuf.h>
2986228Stmm#include <sys/kernel.h>
3086228Stmm#include <sys/socket.h>
3186228Stmm#include <sys/malloc.h>
3286228Stmm#include <sys/timeout.h>
3386228Stmm#include <sys/proc.h>
3480708Sjake#include <sys/device.h>
3586228Stmm#include <sys/sensors.h>
3686228Stmm
3786228Stmm#include <machine/bus.h>
3886228Stmm#include <machine/intr.h>
3986228Stmm
4086228Stmm#include <net/if.h>
4186228Stmm#include <net/if_dl.h>
4286228Stmm#include <net/if_media.h>
4386228Stmm#include <net/if_types.h>
4486228Stmm
4586228Stmm#if NBPFILTER > 0
4686228Stmm#include <net/bpf.h>
4786228Stmm#endif
4886228Stmm
4986228Stmm#ifdef INET
5086228Stmm#include <netinet/in.h>
5186228Stmm#include <netinet/if_ether.h>
5286228Stmm#endif
5386228Stmm
5486228Stmm#include <dev/pci/pcireg.h>
5586228Stmm#include <dev/pci/pcivar.h>
5686228Stmm#include <dev/pci/pcidevs.h>
5786228Stmm
5886228Stmm#include <dev/pci/if_myxreg.h>
5986228Stmm
6086228Stmm#define MYX_DEBUG
61219567Smarius#ifdef MYX_DEBUG
6286228Stmm#define MYXDBG_INIT	(1<<0)	/* chipset initialization */
6386228Stmm#define MYXDBG_CMD	(2<<0)	/* commands */
6486228Stmm#define MYXDBG_INTR	(3<<0)	/* interrupts */
6580708Sjake#define MYXDBG_ALL	0xffff	/* enable all debugging messages */
6680708Sjakeint myx_debug = MYXDBG_ALL;
6780708Sjake#define DPRINTF(_lvl, _arg...)	do {					\
6880708Sjake	if (myx_debug & (_lvl))						\
6980708Sjake		printf(_arg);						\
7080708Sjake} while (0)
7190615Stmm#else
7290615Stmm#define DPRINTF(_lvl, arg...)
7390615Stmm#endif
7490615Stmm
75145253Simp#define DEVNAME(_s)	((_s)->_s##_dev.dv_xname)
7686228Stmm
7780708Sjakestruct myx_dmamem {
7886228Stmm	bus_dmamap_t		 mxm_map;
79166096Smarius	bus_dma_segment_t	 mxm_seg;
8086228Stmm	int			 mxm_nsegs;
8186228Stmm	size_t			 mxm_size;
8286228Stmm	caddr_t			 mxm_kva;
8386228Stmm	const char		*mxm_name;
84166096Smarius};
8586228Stmm
8686228Stmmstruct myx_buf {
8786228Stmm	bus_dmamap_t		 mb_dmamap;
8886228Stmm	struct mbuf		*mb_m;
8986228Stmm};
9086228Stmm
91177565Smariusstruct myx_softc {
92177565Smarius	struct device		 sc_dev;
9386228Stmm	struct arpcom		 sc_ac;
94178860Smarius
9586228Stmm	pci_chipset_tag_t	 sc_pc;
96178860Smarius	pcitag_t		 sc_tag;
97178860Smarius	u_int			 sc_function;
98178860Smarius
99178860Smarius	bus_dma_tag_t		 sc_dmat;
100178860Smarius	bus_space_tag_t		 sc_memt;
101178860Smarius	bus_space_handle_t	 sc_memh;
10286228Stmm	bus_size_t		 sc_mems;
103178860Smarius
10486228Stmm	struct myx_dmamem	 sc_cmddma;
10586228Stmm	struct myx_dmamem	 sc_paddma;
106108815Stmm
107108815Stmm	struct myx_dmamem	 sc_stsdma;
108108815Stmm	struct myx_status	*sc_sts;
10986228Stmm
110108815Stmm	struct myx_dmamem	 sc_rxdma;
111178860Smarius	struct myx_rxdesc	*sc_rxdesc;
11286228Stmm	struct myx_rxbufdesc	*sc_rxbufdesc[2];
11386228Stmm	struct myx_buf		*sc_rxbuf[2];
11486228Stmm#define  MYX_RXSMALL		 0
11586228Stmm#define  MYX_RXBIG		 1
11686228Stmm	int			 sc_rxactive;
11793052Stmm	int			 sc_rxidx;
11893052Stmm
119108917Sjake	void			*sc_irqh;
120108917Sjake	u_int32_t		 sc_irqcoaloff;
121120375Snyan	u_int32_t		 sc_irqclaimoff;
122111347Sobrien	u_int32_t		 sc_irqdeassertoff;
123120375Snyan
124120375Snyan	u_int8_t		 sc_lladdr[ETHER_ADDR_LEN];
125225931Smarius	struct ifmedia		 sc_media;
126225931Smarius
127120375Snyan	u_int32_t		 sc_rxringsize;
128120375Snyan	u_int32_t		 sc_rxsmallringoff;
129111347Sobrien	u_int32_t		 sc_rxbigringoff;
130111347Sobrien	int			 sc_rxndesc;
131225931Smarius	size_t			 sc_rxdescsize;
132178860Smarius	size_t			 sc_rxbufsize;
13386228Stmm	size_t			 sc_rxbufdescsize;
13486228Stmm	u_int32_t		 sc_txringsize;
135178860Smarius	u_int32_t		 sc_txringoff;
13693052Stmm	int			 sc_txndesc;
137178860Smarius
13886228Stmm	u_int			 sc_phy;	/* PHY type (CX4/SR/LR) */
13986228Stmm	u_int			 sc_hwflags;
14093052Stmm#define  MYXFLAG_FLOW_CONTROL	 (1<<0)		/* Rx/Tx pause is enabled */
14193052Stmm#define  MYXFLAG_PROMISC	 (1<<1)		/* promisc mode is enabled */
14293052Stmm#define  MYXFLAG_ALLMULTI	 (1<<2)		/* allmulti is set */
14386228Stmm	u_int8_t		 sc_active;
144178860Smarius
145108815Stmm	struct timeout		 sc_tick;
14686228Stmm};
14786228Stmm
148108917Sjakeint	 myx_match(struct device *, void *, void *);
149108917Sjakevoid	 myx_attach(struct device *, struct device *, void *);
150108917Sjakeint	 myx_query(struct myx_softc *sc);
151108917Sjakeu_int	 myx_ether_aton(char *, u_int8_t *, u_int);
152178860Smariusint	 myx_loadfirmware(struct myx_softc *, u_int8_t *, size_t,
153108917Sjake	    u_int32_t, int);
154108917Sjakevoid	 myx_attachhook(void *);
155108917Sjakevoid	 myx_read(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
156108917Sjakevoid	 myx_rawread(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
15786228Stmmvoid	 myx_write(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
158178860Smariusvoid	 myx_rawwrite(struct myx_softc *, bus_size_t, u_int8_t *, bus_size_t);
159178860Smariusint	 myx_cmd(struct myx_softc *, u_int32_t, struct myx_cmd *, u_int32_t *);
160178860Smariusint	 myx_boot(struct myx_softc *, u_int32_t, struct myx_bootcmd *);
161178860Smariusint	 myx_rdma(struct myx_softc *, u_int);
16286228Stmmint	 myx_reset(struct myx_softc *);
163178860Smariusint	 myx_dmamem_alloc(struct myx_softc *, struct myx_dmamem *,
164178860Smarius	    bus_size_t, u_int align, const char *);
165178860Smariusvoid	 myx_dmamem_free(struct myx_softc *, struct myx_dmamem *);
166178860Smariusint	 myx_media_change(struct ifnet *);
16786228Stmmvoid	 myx_media_status(struct ifnet *, struct ifmediareq *);
16886228Stmmvoid	 myx_link_state(struct myx_softc *);
16986228Stmmvoid	 myx_watchdog(struct ifnet *);
17086228Stmmvoid	 myx_tick(void *);
17186228Stmmint	 myx_ioctl(struct ifnet *, u_long, caddr_t);
17290615Stmmvoid	 myx_iff(struct myx_softc *);
173210334Sattiliovoid	 myx_init(struct ifnet *);
17490615Stmmvoid	 myx_start(struct ifnet *);
17590615Stmmvoid	 myx_stop(struct ifnet *);
17690615Stmmint	 myx_setlladdr(struct myx_softc *, u_int8_t *);
17790615Stmmint	 myx_intr(void *);
17890615Stmmint	 myx_init_rings(struct myx_softc *);
17990615Stmmvoid	 myx_free_rings(struct myx_softc *);
18090615Stmmstruct mbuf *myx_getbuf(struct myx_softc *, bus_dmamap_t, int);
18190615Stmm
182104304Sjakestruct cfdriver myx_cd = {
183104304Sjake	0, "myx", DV_IFNET
184104304Sjake};
18586228Stmmstruct cfattach myx_ca = {
186104304Sjake	sizeof(struct myx_softc), myx_match, myx_attach
187108815Stmm};
188104304Sjake
18986228Stmmconst struct pci_matchid myx_devices[] = {
190104304Sjake	{ PCI_VENDOR_MYRICOM, PCI_PRODUCT_MYRICOM_Z8E }
191104304Sjake};
192104304Sjake
19386228Stmmint
194104304Sjakemyx_match(struct device *parent, void *match, void *aux)
195108815Stmm{
196104304Sjake	return (pci_matchbyid((struct pci_attach_args *)aux,
19786228Stmm	    myx_devices, sizeof(myx_devices) / sizeof(myx_devices[0])));
198104304Sjake}
199104304Sjake
200104304Sjakevoid
20186228Stmmmyx_attach(struct device *parent, struct device *self, void *aux)
202104304Sjake{
203108815Stmm	struct myx_softc	*sc = (struct myx_softc *)self;
204104304Sjake	struct pci_attach_args	*pa = aux;
20586228Stmm	pci_intr_handle_t	 ih;
206104304Sjake	pcireg_t		 memtype;
207104304Sjake	const char		*intrstr;
208104304Sjake	struct ifnet		*ifp;
20986228Stmm
210104304Sjake	sc->sc_pc = pa->pa_pc;
211108815Stmm	sc->sc_tag = pa->pa_tag;
212104304Sjake	sc->sc_dmat = pa->pa_dmat;
21386228Stmm	sc->sc_function = pa->pa_function;
214104304Sjake
215104304Sjake	memtype = pci_mapreg_type(sc->sc_pc, sc->sc_tag, MYXBAR0);
216104304Sjake	switch (memtype) {
217104304Sjake	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT:
218216143Sbrucec	case PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_64BIT:
219104304Sjake		break;
220104304Sjake	default:
221104304Sjake		printf(": invalid memory type: 0x%x\n", memtype);
22286228Stmm		return;
223104304Sjake	}
224104304Sjake
225104304Sjake	/* Map the PCI memory space */
226104304Sjake	if (pci_mapreg_map(pa, MYXBAR0, memtype, 0, &sc->sc_memt,
227216143Sbrucec	    &sc->sc_memh, NULL, &sc->sc_mems, 0) != 0) {
228104304Sjake		printf(": unable to map register memory\n");
229104304Sjake		return;
230104304Sjake	}
23186228Stmm
232104304Sjake	/* Get the board information and initialize the h/w */
233104304Sjake	if (myx_query(sc) != 0)
234104304Sjake		goto unmap;
235104304Sjake
236216143Sbrucec	/*
237104304Sjake	 * Allocate command DMA memory
238104304Sjake	 */
239104304Sjake	if (myx_dmamem_alloc(sc, &sc->sc_cmddma, MYXALIGN_CMD,
24086228Stmm	    MYXALIGN_CMD, "cmd") != 0) {
241104304Sjake		printf(": failed to allocate command DMA memory\n");
242104304Sjake		goto unmap;
243104304Sjake	}
244104304Sjake
245216143Sbrucec	if (myx_dmamem_alloc(sc, &sc->sc_paddma,
246104304Sjake	    MYXALIGN_CMD, MYXALIGN_CMD, "pad") != 0) {
247104304Sjake		printf(": failed to allocate pad DMA memory\n");
248104304Sjake		goto err2;
24986228Stmm	}
250104304Sjake
251104304Sjake	if (myx_dmamem_alloc(sc, &sc->sc_stsdma,
252104304Sjake	    sizeof(struct myx_status), MYXALIGN_DATA /* XXX */, "status") != 0) {
253104304Sjake		printf(": failed to allocate status DMA memory\n");
25486228Stmm		goto err1;
255104304Sjake	}
256108815Stmm	sc->sc_sts = (struct myx_status *)sc->sc_stsdma.mxm_kva;
257104304Sjake
25886228Stmm	/*
259104304Sjake	 * Map and establish the interrupt
260104304Sjake	 */
261104304Sjake	if (pci_intr_map(pa, &ih) != 0) {
262104304Sjake		printf(": unable to map interrupt\n");
26386228Stmm		goto err;
264104304Sjake	}
265108815Stmm	intrstr = pci_intr_string(pa->pa_pc, ih);
266104304Sjake	sc->sc_irqh = pci_intr_establish(pa->pa_pc, ih, IPL_NET,
26786228Stmm	    myx_intr, sc, DEVNAME(sc));
26893052Stmm	if (sc->sc_irqh == NULL) {
269104304Sjake		printf(": unable to establish interrupt %s\n", intrstr);
270104304Sjake		goto err;
271104304Sjake	}
272104304Sjake	printf(": %s, address %s\n", intrstr,
273104304Sjake	    ether_sprintf(sc->sc_ac.ac_enaddr));
274108815Stmm
275104304Sjake	ifp = &sc->sc_ac.ac_if;
276104304Sjake	ifp->if_softc = sc;
277104304Sjake	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
278104304Sjake	ifp->if_ioctl = myx_ioctl;
279104304Sjake	ifp->if_start = myx_start;
280104304Sjake	ifp->if_watchdog = myx_watchdog;
281104304Sjake	strlcpy(ifp->if_xname, DEVNAME(sc), IFNAMSIZ);
282104304Sjake	IFQ_SET_MAXLEN(&ifp->if_snd, MYX_NTXDESC_MIN - 1);
283108815Stmm	IFQ_SET_READY(&ifp->if_snd);
284104304Sjake
285104304Sjake	ifp->if_capabilities = IFCAP_VLAN_MTU;
286104304Sjake#if 0
287104304Sjake	ifp->if_capabilities |= IFCAP_VLAN_HWTAGGING;
288157224Smarius	ifp->if_capabilities |= IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 |
289104304Sjake		    IFCAP_CSUM_UDPv4;
290216143Sbrucec#endif
291104304Sjake	ifp->if_baudrate = ULONG_MAX;	/* XXX fix if_baudrate */
292104304Sjake
293104304Sjake	ifmedia_init(&sc->sc_media, 0,
294104304Sjake	    myx_media_change, myx_media_status);
295104304Sjake	ifmedia_add(&sc->sc_media, IFM_ETHER|sc->sc_phy, 0, NULL);
296104304Sjake	ifmedia_set(&sc->sc_media, IFM_ETHER|sc->sc_phy);
297157224Smarius
298104304Sjake	if_attach(ifp);
299216143Sbrucec	ether_ifattach(ifp);
300104304Sjake
301104304Sjake	timeout_set(&sc->sc_tick, myx_tick, sc);
302104304Sjake	timeout_add(&sc->sc_tick, hz);
303104304Sjake
304104304Sjake	mountroothook_establish(myx_attachhook, sc);
305104304Sjake
306157224Smarius	return;
307104304Sjake
308216143Sbrucec err:
309104304Sjake	myx_dmamem_free(sc, &sc->sc_stsdma);
310104304Sjake err1:
311104304Sjake	myx_dmamem_free(sc, &sc->sc_paddma);
312104304Sjake err2:
313104304Sjake	myx_dmamem_free(sc, &sc->sc_cmddma);
314104304Sjake unmap:
315157224Smarius	bus_space_unmap(sc->sc_memt, sc->sc_memh, sc->sc_mems);
316104304Sjake	sc->sc_mems = 0;
317216143Sbrucec}
318104304Sjake
319104304Sjakeu_int
320104304Sjakemyx_ether_aton(char *mac, u_int8_t *lladdr, u_int maxlen)
321104304Sjake{
322104304Sjake	u_int		i, j;
323104304Sjake	u_int8_t	digit;
324104304Sjake
325104304Sjake	bzero(lladdr, ETHER_ADDR_LEN);
326216143Sbrucec	for (i = j = 0; mac[i] != '\0' && i < maxlen; i++) {
327104304Sjake		if (mac[i] >= '0' && mac[i] <= '9')
328104304Sjake			digit = mac[i] - '0';
329104304Sjake		else if (mac[i] >= 'A' && mac[i] <= 'F')
330104304Sjake			digit = mac[i] - 'A' + 10;
331104304Sjake		else if (mac[i] >= 'a' && mac[i] <= 'f')
332104304Sjake			digit = mac[i] - 'a' + 10;
333104304Sjake		else
334104304Sjake			continue;
335216143Sbrucec		if ((j & 1) == 0)
336104304Sjake			digit <<= 4;
337104304Sjake		lladdr[j++/2] |= digit;
338104304Sjake	}
339104304Sjake
340104304Sjake	return (i);
341104304Sjake}
342104304Sjake
343104304Sjakeint
344216143Sbrucecmyx_query(struct myx_softc *sc)
345104304Sjake{
346104304Sjake	u_int8_t	eeprom[MYX_EEPROM_SIZE];
347104304Sjake	u_int		i, maxlen;
348104304Sjake
349104304Sjake	myx_read(sc, MYX_EEPROM, eeprom, MYX_EEPROM_SIZE);
350104304Sjake
351104304Sjake	for (i = 0; i < MYX_EEPROM_SIZE; i++) {
352104304Sjake		maxlen = MYX_EEPROM_SIZE - i;
353216143Sbrucec		if (eeprom[i] == '\0')
354104304Sjake			break;
355104304Sjake		if (maxlen > 4 && bcmp("MAC=", &eeprom[i], 4) == 0) {
356104304Sjake			i += 4;
357104304Sjake			i += myx_ether_aton(&eeprom[i],
358104304Sjake			    sc->sc_ac.ac_enaddr, maxlen);
35993052Stmm		}
360178860Smarius		for (; i < MYX_EEPROM_SIZE; i++)
36186228Stmm			if (eeprom[i] == '\0')
362216143Sbrucec				break;
36386228Stmm	}
36486228Stmm
36586228Stmm	return (0);
36686228Stmm}
36793052Stmm
36893052Stmmint
369178860Smariusmyx_loadfirmware(struct myx_softc *sc, u_int8_t *fw, size_t fwlen,
37086228Stmm    u_int32_t fwhdroff, int reload)
371216143Sbrucec{
372178860Smarius	struct myx_firmware_hdr	*fwhdr;
37386228Stmm	u_int			 i, len, ret = 0;
37486228Stmm
37586228Stmm	fwhdr = (struct myx_firmware_hdr *)(fw + fwhdroff);
37693052Stmm	DPRINTF(MYXDBG_INIT, "%s(%s): "
37793052Stmm	    "fw hdr off %d, length %d, type 0x%x, version %s\n",
378178860Smarius	    DEVNAME(sc), __func__,
37986228Stmm	    fwhdroff, betoh32(fwhdr->fw_hdrlength),
380216143Sbrucec	    betoh32(fwhdr->fw_type),
381178860Smarius	    fwhdr->fw_version);
38286228Stmm
38386228Stmm	if (betoh32(fwhdr->fw_type) != MYXFW_TYPE_ETH ||
38486228Stmm	    bcmp(MYXFW_VER, fwhdr->fw_version, strlen(MYXFW_VER)) != 0) {
38593052Stmm		if (reload)
38693052Stmm			printf("%s: invalid firmware type 0x%x version %s\n",
387178860Smarius			    DEVNAME(sc), betoh32(fwhdr->fw_type),
38886228Stmm			    fwhdr->fw_version);
389216143Sbrucec		ret = 1;
390178860Smarius		goto done;
39186228Stmm	}
39286228Stmm
39386228Stmm	if (!reload)
39493052Stmm		goto done;
39593052Stmm
396178860Smarius	/* Write the firmware to the card's SRAM */
39786228Stmm	for (i = 0; i < fwlen; i += 256) {
398216143Sbrucec		len = min(256, fwlen - i);
39986228Stmm		myx_rawwrite(sc, i + MYX_FW, fw + i, min(256, fwlen - i));
40086228Stmm	}
40186228Stmm
40286228Stmm done:
40393052Stmm	free(fw, M_DEVBUF);
40493052Stmm	return (ret);
405178860Smarius}
40686228Stmm
407216143Sbrucecvoid
408178860Smariusmyx_attachhook(void *arg)
40986228Stmm{
41086228Stmm	struct myx_softc	*sc = (struct myx_softc *)arg;
41186228Stmm	size_t			 fwlen;
41293052Stmm	u_int8_t		*fw = NULL;
41393052Stmm	u_int32_t		 fwhdroff;
414178860Smarius	struct myx_bootcmd	 bc;
41586228Stmm
416216143Sbrucec	/*
417178860Smarius	 * First try the firmware found in the SRAM
41886228Stmm	 */
41986228Stmm	myx_read(sc, MYX_HEADER_POS, (u_int8_t *)&fwhdroff, sizeof(fwhdroff));
42086228Stmm	fwhdroff = betoh32(fwhdroff);
42193052Stmm	fwlen = sizeof(struct myx_firmware_hdr);
42293052Stmm	if ((fwhdroff + fwlen) > MYX_SRAM_SIZE)
423178860Smarius		goto load;
42486228Stmm
425216143Sbrucec	fw = malloc(fwlen, M_DEVBUF, M_WAIT);
426178860Smarius	myx_rawread(sc, MYX_HEADER_POS, fw, fwlen);
42786228Stmm
42886228Stmm	if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 0) == 0)
42986228Stmm		goto boot;
43093052Stmm
43193052Stmm load:
432178860Smarius	/*
43386228Stmm	 * Now try the firmware stored on disk
434216143Sbrucec	 */
43586228Stmm	if (loadfirmware(MYXFW_ALIGNED /* XXX */, &fw, &fwlen) != 0) {
43686228Stmm		printf("%s: could not load firmware\n", DEVNAME(sc));
43786228Stmm		return;
43886228Stmm	}
43993052Stmm	if (fwlen > MYX_SRAM_SIZE || fwlen < MYXFW_MIN_LEN) {
44093052Stmm		printf("%s: invalid firmware image size\n", DEVNAME(sc));
441178860Smarius		goto err;
44286228Stmm	}
443216143Sbrucec
444178860Smarius	bcopy(fw + MYX_HEADER_POS, &fwhdroff, sizeof(fwhdroff));
44586228Stmm	fwhdroff = betoh32(fwhdroff);
44686228Stmm	if ((fwhdroff + sizeof(struct myx_firmware_hdr)) > fwlen) {
44786228Stmm		printf("%s: invalid firmware image\n", DEVNAME(sc));
44893052Stmm		goto err;
44993052Stmm	}
450178860Smarius
45186228Stmm	if (myx_loadfirmware(sc, fw, fwlen, fwhdroff, 1) != 0) {
452216143Sbrucec		fw = NULL;
453178860Smarius		goto err;
45486228Stmm	}
45586228Stmm	fw = NULL;
45686228Stmm
45793052Stmm boot:
45893052Stmm	bzero(&bc, sizeof(bc));
459178860Smarius	if (myx_boot(sc, fwlen, &bc) != 0) {
46086228Stmm		printf("%s: failed to bootstrap the device\n", DEVNAME(sc));
461216143Sbrucec		goto err;
462178860Smarius	}
46386228Stmm	if (myx_reset(sc) != 0)
46486228Stmm		goto err;
46586228Stmm
46693052Stmm	sc->sc_active = 1;
46793052Stmm	return;
46893052Stmm
46986228Stmm err:
470216143Sbrucec	if (fw != NULL)
47186228Stmm		free(fw, M_DEVBUF);
47286228Stmm}
47386228Stmm
47486228Stmmvoid
47593052Stmmmyx_read(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len)
47693052Stmm{
47793052Stmm	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
47886228Stmm	    BUS_SPACE_BARRIER_READ);
479216143Sbrucec	bus_space_read_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len / 4);
480178860Smarius}
48186228Stmm
48286228Stmmvoid
48386228Stmmmyx_rawread(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr,
48493052Stmm    bus_size_t len)
48593052Stmm{
48693052Stmm	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
48786228Stmm	    BUS_SPACE_BARRIER_READ);
488216143Sbrucec	bus_space_read_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
489178860Smarius}
49086228Stmm
49186228Stmmvoid
49286228Stmmmyx_write(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr, bus_size_t len)
49393052Stmm{
49493052Stmm	bus_space_write_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len / 4);
49593052Stmm	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
49686228Stmm	    BUS_SPACE_BARRIER_WRITE);
497216143Sbrucec}
498178860Smarius
49986228Stmmvoid
50086228Stmmmyx_rawwrite(struct myx_softc *sc, bus_size_t off, u_int8_t *ptr,
50186228Stmm    bus_size_t len)
502104304Sjake{
503104304Sjake	bus_space_write_raw_region_4(sc->sc_memt, sc->sc_memh, off, ptr, len);
504104304Sjake	bus_space_barrier(sc->sc_memt, sc->sc_memh, off, len,
50586228Stmm	    BUS_SPACE_BARRIER_WRITE);
506104304Sjake}
507108815Stmm
508104304Sjakeint
50986228Stmmmyx_dmamem_alloc(struct myx_softc *sc, struct myx_dmamem *mxm,
510104304Sjake    bus_size_t size, u_int align, const char *mname)
511104304Sjake{
512104304Sjake	mxm->mxm_size = size;
51386228Stmm
514104304Sjake	if (bus_dmamap_create(sc->sc_dmat, mxm->mxm_size, 1,
515108815Stmm	    mxm->mxm_size, 0, BUS_DMA_WAITOK | BUS_DMA_ALLOCNOW,
516104304Sjake	    &mxm->mxm_map) != 0)
51786228Stmm		return (1);
518104304Sjake	if (bus_dmamem_alloc(sc->sc_dmat, mxm->mxm_size,
519104304Sjake	    align, 0, &mxm->mxm_seg, 1, &mxm->mxm_nsegs,
520104304Sjake	    BUS_DMA_WAITOK) != 0)
52186228Stmm		goto destroy;
522104304Sjake	if (bus_dmamem_map(sc->sc_dmat, &mxm->mxm_seg, mxm->mxm_nsegs,
523108815Stmm	    mxm->mxm_size, &mxm->mxm_kva, BUS_DMA_WAITOK) != 0)
524104304Sjake		goto free;
52586228Stmm	if (bus_dmamap_load(sc->sc_dmat, mxm->mxm_map, mxm->mxm_kva,
526104304Sjake	    mxm->mxm_size, NULL, BUS_DMA_WAITOK) != 0)
527104304Sjake		goto unmap;
528104304Sjake
52986228Stmm	bzero(mxm->mxm_kva, mxm->mxm_size);
530104304Sjake	mxm->mxm_name = mname;
531108815Stmm
532104304Sjake	return (0);
53386228Stmm unmap:
534104304Sjake	bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
535104304Sjake free:
536104304Sjake	bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
537104304Sjake destroy:
538216143Sbrucec	bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
539104304Sjake	return (1);
540104304Sjake}
541104304Sjake
54286228Stmmvoid
543104304Sjakemyx_dmamem_free(struct myx_softc *sc, struct myx_dmamem *mxm)
544104304Sjake{
545104304Sjake	bus_dmamap_unload(sc->sc_dmat, mxm->mxm_map);
546104304Sjake	bus_dmamem_unmap(sc->sc_dmat, mxm->mxm_kva, mxm->mxm_size);
547216143Sbrucec	bus_dmamem_free(sc->sc_dmat, &mxm->mxm_seg, 1);
548104304Sjake	bus_dmamap_destroy(sc->sc_dmat, mxm->mxm_map);
549104304Sjake}
550104304Sjake
55186228Stmmint
552104304Sjakemyx_cmd(struct myx_softc *sc, u_int32_t cmd, struct myx_cmd *mc, u_int32_t *r)
553104304Sjake{
554104304Sjake	bus_dmamap_t		 map = sc->sc_cmddma.mxm_map;
555104304Sjake	struct myx_response	*mr;
556216143Sbrucec	u_int			 i;
557104304Sjake	u_int32_t		 result, data;
558104304Sjake#ifdef MYX_DEBUG
559104304Sjake	static const char *cmds[MYXCMD_MAX] = {
56086228Stmm		"CMD_NONE",
561104304Sjake		"CMD_RESET",
562104304Sjake		"CMD_GET_VERSION",
563104304Sjake		"CMD_SET_INTRQDMA",
564104304Sjake		"CMD_SET_BIGBUFSZ",
565216143Sbrucec		"CMD_SET_SMALLBUFSZ",
566104304Sjake		"CMD_GET_TXRINGOFF",
567104304Sjake		"CMD_GET_RXSMALLRINGOFF",
568104304Sjake		"CMD_GET_RXBIGRINGOFF",
56986228Stmm		"CMD_GET_INTRACKOFF",
570104304Sjake		"CMD_GET_INTRDEASSERTOFF",
571104304Sjake		"CMD_GET_TXRINGSZ",
572104304Sjake		"CMD_GET_RXRINGSZ",
573104304Sjake		"CMD_SET_INTRQSZ",
57486228Stmm		"CMD_SET_IFUP",
575104304Sjake		"CMD_SET_IFDOWN",
576108815Stmm		"CMD_SET_MTU",
577104304Sjake		"CMD_GET_INTRCOALDELAYOFF",
57886228Stmm		"CMD_SET_STATSINTVL",
579104304Sjake		"CMD_SET_STATSDMA_OLD",
580104304Sjake		"CMD_SET_PROMISC",
581104304Sjake		"CMD_UNSET_PROMISC",
582104304Sjake		"CMD_SET_LLADDR",
58386228Stmm		"CMD_SET_FC",
584104304Sjake		"CMD_UNSET_FC",
585108815Stmm		"CMD_DMA_TEST",
586104304Sjake		"CMD_SET_ALLMULTI",
58786228Stmm		"CMD_UNSET_ALLMULTI",
58893052Stmm		"CMD_SET_MCASTGROUP",
589104304Sjake		"CMD_UNSET_MCASTGROUP",
590104304Sjake		"CMD_UNSET_MCAST",
591104304Sjake		"CMD_SET_STATSDMA",
592104304Sjake		"CMD_UNALIGNED_DMA_TEST",
593104304Sjake		"CMD_GET_UNALIGNED_STATUS"
594108815Stmm	};
595104304Sjake#endif
596104304Sjake
597104304Sjake	mc->mc_cmd = htobe32(cmd);
598104304Sjake	mc->mc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
599104304Sjake	mc->mc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
600104304Sjake
601104304Sjake	mr = (struct myx_response *)sc->sc_cmddma.mxm_kva;
602104304Sjake	mr->mr_result = 0xffffffff;
603108815Stmm
604104304Sjake	/* Send command */
605104304Sjake	myx_write(sc, MYX_CMD, (u_int8_t *)mc, sizeof(struct myx_cmd));
606104304Sjake
607104304Sjake	for (i = 0; i < 20; i++) {
608111383Sobrien		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
609104304Sjake		    BUS_DMASYNC_POSTREAD);
610216143Sbrucec		result = betoh32(mr->mr_result);
611104304Sjake		data = betoh32(mr->mr_data);
612104304Sjake
613104304Sjake		if (result != 0xffffffff)
614104304Sjake			break;
615104304Sjake		delay(1000);
616104304Sjake	}
617111353Sobrien
618104304Sjake	DPRINTF(MYXDBG_CMD, "%s(%s): %s completed, i %d, "
619216143Sbrucec	    "result 0x%x, data 0x%x (%u)\n", DEVNAME(sc), __func__,
620104304Sjake	    cmds[cmd], i, result, data, data);
621104304Sjake
622104304Sjake	if (result != 0)
623104304Sjake		return (-1);
624104304Sjake
625104304Sjake	if (r != NULL)
626111383Sobrien		*r = data;
627104304Sjake	return (0);
628216143Sbrucec}
629104304Sjake
630104304Sjakeint
631104304Sjakemyx_boot(struct myx_softc *sc, u_int32_t length, struct myx_bootcmd *bc)
632104304Sjake{
633104304Sjake	bus_dmamap_t		 map = sc->sc_cmddma.mxm_map;
634104304Sjake	u_int32_t		*status;
635111383Sobrien	u_int			 i;
636104304Sjake
637216143Sbrucec	bc->bc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
638104304Sjake	bc->bc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
639104304Sjake	bc->bc_result = 0xffffffff;
640104304Sjake	bc->bc_offset = htobe32(MYX_FW_BOOT);
641104304Sjake	bc->bc_length = htobe32(length);
642104304Sjake	bc->bc_copyto = htobe32(8);
643104304Sjake	bc->bc_jumpto = htobe32(0);
644104304Sjake
645104304Sjake	status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
646216143Sbrucec	*status = 0;
647104304Sjake
648104304Sjake	/* Send command */
649104304Sjake	myx_write(sc, MYX_BOOT, (u_int8_t *)bc, sizeof(struct myx_bootcmd));
650104304Sjake
651104304Sjake	for (i = 0; i < 200; i++) {
652104304Sjake		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
653104304Sjake		    BUS_DMASYNC_POSTREAD);
654104304Sjake		if (*status == 0xffffffff)
655216143Sbrucec			break;
656104304Sjake		delay(1000);
657104304Sjake	}
658104304Sjake
659104304Sjake	DPRINTF(MYXDBG_CMD, "%s(%s): boot completed, i %d, result 0x%x\n",
660104304Sjake	    DEVNAME(sc), __func__, i, betoh32(*status));
661104304Sjake
662104304Sjake	if (*status != 0xffffffff)
663104304Sjake		return (-1);
664216143Sbrucec
665104304Sjake	return (0);
666104304Sjake}
667104304Sjake
668104304Sjakeint
669104304Sjakemyx_rdma(struct myx_softc *sc, u_int do_enable)
670104304Sjake{
671104304Sjake	struct myx_rdmacmd	 rc;
672104304Sjake	bus_dmamap_t		 map = sc->sc_cmddma.mxm_map;
673216143Sbrucec	bus_dmamap_t		 pad = sc->sc_paddma.mxm_map;
674104304Sjake	u_int32_t		*status;
675104304Sjake	u_int			 i;
676104304Sjake
677104304Sjake	/*
678104304Sjake	 * It is required to setup a _dummy_ RDMA address. It also makes
67993052Stmm	 * some PCI-E chipsets resend dropped messages.
680178860Smarius	 */
68186228Stmm	rc.rc_addr_high = htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
682216143Sbrucec	rc.rc_addr_low = htobe32(MYX_ADDRLOW(map->dm_segs[0].ds_addr));
68386228Stmm	rc.rc_result = 0xffffffff;
68486228Stmm	rc.rc_rdma_high = htobe32(MYX_ADDRHIGH(pad->dm_segs[0].ds_addr));
68586228Stmm	rc.rc_rdma_low = htobe32(MYX_ADDRLOW(pad->dm_segs[0].ds_addr));
68686228Stmm	rc.rc_enable = htobe32(do_enable);
68793052Stmm
68893052Stmm	status = (u_int32_t *)sc->sc_cmddma.mxm_kva;
689178860Smarius	*status = 0;
69086228Stmm
691216143Sbrucec	/* Send command */
692178860Smarius	myx_write(sc, MYX_RDMA, (u_int8_t *)&rc, sizeof(struct myx_rdmacmd));
69386228Stmm
69486228Stmm	for (i = 0; i < 20; i++) {
69586228Stmm		bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
69693052Stmm		    BUS_DMASYNC_POSTREAD);
69793052Stmm		if (*status == 0xffffffff)
698178860Smarius			break;
69986228Stmm		delay(1000);
700216143Sbrucec	}
701178860Smarius
70286228Stmm	DPRINTF(MYXDBG_CMD, "%s(%s): dummy RDMA %s, i %d, result 0x%x\n",
70386228Stmm	    DEVNAME(sc), __func__,
70486228Stmm	    do_enable ? "enabled" : "disabled", i, betoh32(*status));
70593052Stmm
70693052Stmm	if (*status != 0xffffffff)
707178860Smarius		return (-1);
70886228Stmm
709216143Sbrucec	return (0);
710178860Smarius}
71186228Stmm
71286228Stmmint
71386228Stmmmyx_reset(struct myx_softc *sc)
71493052Stmm{
71593052Stmm	struct myx_cmd		 mc;
716178860Smarius	u_int32_t		 data;
71786228Stmm	struct ifnet		*ifp = &sc->sc_ac.ac_if;
718216143Sbrucec
71986228Stmm	bzero(&mc, sizeof(mc));
72086228Stmm	if (myx_cmd(sc, MYXCMD_RESET, &mc, NULL) != 0) {
72186228Stmm		printf("%s: failed to reset the device\n", DEVNAME(sc));
72286228Stmm		return (-1);
72393052Stmm	}
72493052Stmm
725178860Smarius	if (myx_rdma(sc, MYXRDMA_ON) != 0) {
72686228Stmm		printf("%s: failed to enable dummy RDMA\n", DEVNAME(sc));
727216143Sbrucec		return (-1);
728178860Smarius	}
72986228Stmm
73086228Stmm	if (myx_cmd(sc, MYXCMD_GET_INTRCOALDELAYOFF, &mc,
73186228Stmm	    &sc->sc_irqcoaloff) != 0) {
73293052Stmm		printf("%s: failed to get IRQ coal offset\n", DEVNAME(sc));
73393052Stmm		return (-1);
734178860Smarius	}
73586228Stmm	data = htobe32(MYX_IRQCOALDELAY);
736216143Sbrucec	myx_write(sc, sc->sc_irqcoaloff, (u_int8_t *)&data, sizeof(data));
737178860Smarius
73886228Stmm	if (myx_cmd(sc, MYXCMD_GET_INTRACKOFF, &mc,
73986228Stmm	    &sc->sc_irqclaimoff) != 0) {
74086228Stmm		printf("%s: failed to get IRQ ack offset\n", DEVNAME(sc));
74193052Stmm		return (-1);
74293052Stmm	}
743178860Smarius
74486228Stmm	if (myx_cmd(sc, MYXCMD_GET_INTRDEASSERTOFF, &mc,
745216143Sbrucec	    &sc->sc_irqdeassertoff) != 0) {
746178860Smarius		printf("%s: failed to get IRQ deassert offset\n", DEVNAME(sc));
74786228Stmm		return (-1);
74886228Stmm	}
74986228Stmm
75093052Stmm	if (myx_cmd(sc, MYXCMD_UNSET_PROMISC, &mc, NULL) != 0) {
75193052Stmm		printf("%s: failed to disable promisc mode\n", DEVNAME(sc));
752178860Smarius		return (-1);
75386228Stmm	}
754216143Sbrucec
75586228Stmm	if (myx_cmd(sc, MYXCMD_FC_DEFAULT, &mc, NULL) != 0) {
75686228Stmm		printf("%s: failed to configure flow control\n", DEVNAME(sc));
75786228Stmm		return (-1);
75886228Stmm	}
75993052Stmm
76093052Stmm	if (myx_setlladdr(sc, LLADDR(ifp->if_sadl)) != 0)
761178860Smarius		return (-1);
76286228Stmm
763216143Sbrucec	return (0);
764178860Smarius}
76586228Stmm
76686228Stmm
76786228Stmmint
76893052Stmmmyx_media_change(struct ifnet *ifp)
76993052Stmm{
770178860Smarius	return (EINVAL);
77186228Stmm}
772216143Sbrucec
773178860Smariusvoid
77486228Stmmmyx_media_status(struct ifnet *ifp, struct ifmediareq *imr)
77586228Stmm{
77686228Stmm	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
77793052Stmm
77893052Stmm	imr->ifm_active = IFM_ETHER|sc->sc_phy;
779178860Smarius	imr->ifm_status = IFM_AVALID;
78086228Stmm	myx_link_state(sc);
781216143Sbrucec	if (!LINK_STATE_IS_UP(ifp->if_link_state))
782178860Smarius		return;
78386228Stmm	imr->ifm_active |= IFM_FDX;
78486228Stmm	imr->ifm_status |= IFM_ACTIVE;
78586228Stmm
78693052Stmm	/* Flow control */
78793052Stmm	if (sc->sc_hwflags & MYXFLAG_FLOW_CONTROL)
78893052Stmm		imr->ifm_active |= IFM_FLOW|IFM_ETH_RXPAUSE|IFM_ETH_TXPAUSE;
78986228Stmm}
790216143Sbrucec
79186228Stmmvoid
79286228Stmmmyx_link_state(struct myx_softc *sc)
79386228Stmm{
79486228Stmm	struct ifnet		*ifp = &sc->sc_ac.ac_if;
79586228Stmm	int			 link_state = LINK_STATE_DOWN;
79693052Stmm
79793052Stmm	if (sc->sc_sts == NULL)
79893052Stmm		return;
79986228Stmm	if (sc->sc_sts->ms_linkstate == MYXSTS_LINKUP)
800216143Sbrucec		link_state = LINK_STATE_FULL_DUPLEX;
801178860Smarius	if (ifp->if_link_state != link_state) {
80286228Stmm		ifp->if_link_state = link_state;
80386228Stmm		if_link_state_change(ifp);
80486228Stmm	}
80586228Stmm}
80693052Stmm
80793052Stmmvoid
80893052Stmmmyx_watchdog(struct ifnet *ifp)
80986228Stmm{
810216143Sbrucec	return;
811178860Smarius}
81286228Stmm
81386228Stmmvoid
81486228Stmmmyx_tick(void *arg)
81586228Stmm{
81693052Stmm	struct myx_softc	*sc = (struct myx_softc *)arg;
81793052Stmm
81893052Stmm	if (!sc->sc_active)
81986228Stmm		return;
820216143Sbrucec
821178860Smarius	myx_link_state(sc);
82286228Stmm	timeout_add(&sc->sc_tick, hz);
82386228Stmm}
82486228Stmm
825116659Sjmgint
826116659Sjmgmyx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
827178860Smarius{
828116659Sjmg	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
829116659Sjmg	struct ifaddr		*ifa = (struct ifaddr *)data;
830116659Sjmg	struct ifreq		*ifr = (struct ifreq *)data;
831116659Sjmg	int			 s, error = 0;
832116659Sjmg
833116659Sjmg	s = splnet();
834116659Sjmg	if ((error = ether_ioctl(ifp, &sc->sc_ac, cmd, data)) > 0) {
835116659Sjmg		splx(s);
836178860Smarius		return (error);
837116659Sjmg	}
838116659Sjmg
839116659Sjmg	switch (cmd) {
840116659Sjmg	case SIOCSIFADDR:
841116659Sjmg		ifp->if_flags |= IFF_UP;
842116659Sjmg#ifdef INET
843116659Sjmg		if (ifa->ifa_addr->sa_family == AF_INET)
844116659Sjmg			arp_ifinit(&sc->sc_ac, ifa);
845178860Smarius#endif
846116659Sjmg		/* FALLTHROUGH */
847116659Sjmg	case SIOCSIFFLAGS:
848116659Sjmg		if (ifp->if_flags & IFF_UP) {
849116659Sjmg			if (ifp->if_flags & IFF_RUNNING)
850116659Sjmg				myx_iff(sc);
851116659Sjmg			else
852143598Sscottl				myx_init(ifp);
85386228Stmm		} else {
85480708Sjake			if (ifp->if_flags & IFF_RUNNING)
855				myx_stop(ifp);
856		}
857		break;
858
859	case SIOCSIFMTU:
860		if (ifr->ifr_mtu < ETHERMIN || ifr->ifr_mtu > ifp->if_hardmtu)
861			error = EINVAL;
862		else if (ifp->if_mtu != ifr->ifr_mtu)
863			ifp->if_mtu = ifr->ifr_mtu;
864		break;
865
866	case SIOCADDMULTI:
867		error = ether_addmulti(ifr, &sc->sc_ac);
868		break;
869
870	case SIOCDELMULTI:
871		error = ether_delmulti(ifr, &sc->sc_ac);
872		break;
873
874	case SIOCGIFMEDIA:
875	case SIOCSIFMEDIA:
876		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
877		break;
878
879	default:
880		error = ENOTTY;
881	}
882
883	if (error == ENETRESET) {
884		if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) ==
885		    (IFF_UP | IFF_RUNNING))
886			myx_iff(sc);
887		error = 0;
888	}
889
890	splx(s);
891
892	return (error);
893}
894
895void
896myx_iff(struct myx_softc *sc)
897{
898	/* XXX set multicast filters etc. */
899	return;
900}
901
902void
903myx_init(struct ifnet *ifp)
904{
905	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
906	struct myx_cmd		 mc;
907
908	if (myx_reset(sc) != 0)
909		return;
910
911	if (myx_init_rings(sc) != 0)
912		return;
913
914	if (myx_cmd(sc, MYXCMD_SET_IFUP, &mc, NULL) != 0) {
915		printf("%s: failed to start the device\n", DEVNAME(sc));
916		myx_free_rings(sc);
917		return;
918	}
919
920	ifp->if_flags |= IFF_RUNNING;
921	ifp->if_flags &= ~IFF_OACTIVE;
922}
923
924void
925myx_start(struct ifnet *ifp)
926{
927}
928
929void
930myx_stop(struct ifnet *ifp)
931{
932	struct myx_softc	*sc = (struct myx_softc *)ifp->if_softc;
933	struct myx_cmd		 mc;
934
935	bzero(&mc, sizeof(mc));
936	(void)myx_cmd(sc, MYXCMD_SET_IFDOWN, &mc, NULL);
937	myx_free_rings(sc);
938
939	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
940}
941
942int
943myx_setlladdr(struct myx_softc *sc, u_int8_t *addr)
944{
945	struct myx_cmd		 mc;
946
947	bzero(&mc, sizeof(mc));
948	mc.mc_data0 = addr[3] | addr[2] << 8 | addr[1] << 16 | addr[0] << 24;
949	mc.mc_data1 = addr[5] | addr[4] << 8;
950	if (myx_cmd(sc, MYXCMD_SET_LLADDR, &mc, NULL) != 0) {
951		printf("%s: failed to set the lladdr\n", DEVNAME(sc));
952		return (-1);
953	}
954	return (0);
955}
956
957int
958myx_intr(void *arg)
959{
960	struct myx_softc	*sc = (struct myx_softc *)arg;
961	u_int32_t		 data, valid;
962	struct myx_status	*sts = sc->sc_sts;
963	bus_dmamap_t		 map = sc->sc_stsdma.mxm_map;
964
965	if (!sc->sc_active)
966		return (0);
967
968	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
969	    BUS_DMASYNC_POSTWRITE);
970
971	/*
972	 * XXX The 'valid' flags should be set by the NIC, but it doesn't
973	 * XXX work yet.
974	 */
975	valid = sts->ms_isvalid;
976	if (!valid)
977		return (0);
978
979	data = 0;
980	myx_write(sc, sc->sc_irqdeassertoff, (u_int8_t *)&data, sizeof(data));
981
982	DPRINTF(MYXDBG_INTR, "%s(%s): interrupt, valid 0x%x\n",
983	    DEVNAME(sc), __func__, valid);
984
985#ifdef MYX_DEBUG
986#define DPRINT_STATUS(_n)						\
987	DPRINTF(MYXDBG_INTR, "%s(%s): %s: %u, 0x%x\n", DEVNAME(sc), __func__,\
988	    #_n, sts->_n, sts->_n)
989
990	DPRINT_STATUS(ms_reserved);
991	DPRINT_STATUS(ms_dropped_pause);
992	DPRINT_STATUS(ms_dropped_unicast);
993	DPRINT_STATUS(ms_dropped_crc32err);
994	DPRINT_STATUS(ms_dropped_phyerr);
995	DPRINT_STATUS(ms_dropped_mcast);
996	DPRINT_STATUS(ms_txdonecnt);
997	DPRINT_STATUS(ms_linkstate);
998	DPRINT_STATUS(ms_dropped_linkoverflow);
999	DPRINT_STATUS(ms_dropped_linkerror);
1000	DPRINT_STATUS(ms_dropped_runt);
1001	DPRINT_STATUS(ms_dropped_overrun);
1002	DPRINT_STATUS(ms_dropped_smallbufunderrun);
1003	DPRINT_STATUS(ms_dropped_bigbufunderrun);
1004	DPRINT_STATUS(ms_rdmatags_available);
1005	DPRINT_STATUS(ms_txstopped);
1006	DPRINT_STATUS(ms_linkdowncnt);
1007	DPRINT_STATUS(ms_statusupdated);
1008	DPRINT_STATUS(ms_isvalid);
1009#endif
1010
1011	data = htobe32(3);
1012	if (sts->ms_isvalid)
1013		myx_write(sc, sc->sc_irqclaimoff, (u_int8_t *)&data,
1014		    sizeof(data));
1015	myx_write(sc, sc->sc_irqclaimoff + sizeof(u_int32_t),
1016	    (u_int8_t *)&data, sizeof(data));
1017
1018	return (1);
1019}
1020
1021int
1022myx_init_rings(struct myx_softc *sc)
1023{
1024	struct myx_cmd		 mc;
1025	struct ifnet		*ifp = &sc->sc_ac.ac_if;
1026	bus_dmamap_t		 map;
1027	int			 i;
1028	struct myx_buf		*mb;
1029	struct myx_rxbufdesc	*rxb;
1030	u_int32_t		 data;
1031
1032	bzero(&mc, sizeof(mc));
1033	if (!(myx_cmd(sc, MYXCMD_GET_RXRINGSZ, &mc,
1034	    &sc->sc_rxringsize) == 0 && sc->sc_rxringsize &&
1035	    myx_cmd(sc, MYXCMD_GET_RXSMALLRINGOFF, &mc,
1036	    &sc->sc_rxsmallringoff) == 0 && sc->sc_rxsmallringoff &&
1037	    myx_cmd(sc, MYXCMD_GET_RXBIGRINGOFF, &mc,
1038	    &sc->sc_rxbigringoff) == 0 && sc->sc_rxbigringoff &&
1039	    myx_cmd(sc, MYXCMD_GET_TXRINGSZ, &mc,
1040	    &sc->sc_txringsize) == 0 && sc->sc_txringsize &&
1041	    myx_cmd(sc, MYXCMD_GET_TXRINGOFF, &mc,
1042	    &sc->sc_txringoff) == 0 && sc->sc_txringoff)) {
1043		printf("%s: failed to get ring sizes and offsets\n",
1044		    DEVNAME(sc));
1045		return (-1);
1046	}
1047	sc->sc_rxndesc = sc->sc_rxringsize / sizeof(struct myx_rxbufdesc);
1048	sc->sc_txndesc = sc->sc_txringsize / sizeof(struct myx_txdesc);
1049	sc->sc_rxdescsize = sc->sc_rxndesc * 2 * sizeof(struct myx_rxdesc);
1050	sc->sc_rxbufsize = sc->sc_rxndesc * sizeof(struct myx_buf);
1051	sc->sc_rxbufdescsize = sc->sc_rxndesc * sizeof(struct myx_rxbufdesc);
1052	IFQ_SET_MAXLEN(&ifp->if_snd, sc->sc_txndesc - 1);
1053	IFQ_SET_READY(&ifp->if_snd);
1054
1055	DPRINTF(MYXDBG_INIT, "%s(%s): Rx ring ndesc %u size %u bufsize %u, "
1056	    "Tx ring ndesc %u size %u offset 0x%x\n", DEVNAME(sc), __func__,
1057	    sc->sc_rxndesc, sc->sc_rxdescsize, sc->sc_rxringsize,
1058	    sc->sc_txndesc, sc->sc_txringsize, sc->sc_txringoff);
1059
1060	/*
1061	 * Setup Rx DMA descriptors
1062	 */
1063	if (myx_dmamem_alloc(sc, &sc->sc_rxdma,
1064	    sc->sc_rxdescsize, MYXALIGN_DATA, "rxring") != 0) {
1065		printf(": failed to allocate Rx DMA memory\n");
1066		return (-1);
1067	}
1068	sc->sc_rxdesc = (struct myx_rxdesc *)sc->sc_rxdma.mxm_kva;
1069
1070	bzero(&mc, sizeof(mc));
1071	mc.mc_data0 = htobe32(sc->sc_rxdescsize);
1072	if (myx_cmd(sc, MYXCMD_SET_INTRQSZ, &mc, NULL) != 0) {
1073		printf("%s: failed to set Rx DMA size\n", DEVNAME(sc));
1074		goto err;
1075	}
1076
1077	map = sc->sc_rxdma.mxm_map;
1078	mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr);
1079	mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr);
1080	if (myx_cmd(sc, MYXCMD_SET_INTRQDMA, &mc, NULL) != 0) {
1081		printf("%s: failed to set Rx DMA address\n", DEVNAME(sc));
1082		goto err;
1083	}
1084
1085#ifdef notyet
1086	/*
1087	 * XXX It fails to set the MTU and it always returns
1088	 * XXX MYXCMD_ERR_RANGE.
1089	 */
1090	bzero(&mc, sizeof(mc));
1091	mc.mc_data0 = ifp->if_mtu + ETHER_HDR_LEN + 4;
1092	if (myx_cmd(sc, MYXCMD_SET_MTU, &mc, NULL) != 0) {
1093		printf("%s: failed to set MTU size %d\n",
1094		    DEVNAME(sc), ifp->if_mtu + ETHER_HDR_LEN + 4);
1095		goto err;
1096	}
1097#endif
1098
1099	/*
1100	 * Setup Rx buffer descriptors
1101	 */
1102	sc->sc_rxbuf[MYX_RXSMALL] = (struct myx_buf *)
1103	    malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK);
1104	sc->sc_rxbufdesc[MYX_RXSMALL] = (struct myx_rxbufdesc *)
1105	    malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK);
1106	sc->sc_rxbuf[MYX_RXBIG] = (struct myx_buf *)
1107	    malloc(sc->sc_rxbufsize, M_DEVBUF, M_WAITOK);
1108	sc->sc_rxbufdesc[MYX_RXBIG] = (struct myx_rxbufdesc *)
1109	    malloc(sc->sc_rxbufdescsize, M_DEVBUF, M_WAITOK);
1110	if (sc->sc_rxbuf[MYX_RXSMALL] == NULL ||
1111	    sc->sc_rxbufdesc[MYX_RXSMALL] == NULL ||
1112	    sc->sc_rxbuf[MYX_RXBIG] == NULL ||
1113	    sc->sc_rxbufdesc[MYX_RXBIG] == NULL) {
1114		printf("%s: failed to allocate rx buffers\n", DEVNAME(sc));
1115		goto err;
1116	}
1117
1118	for (i = 0; i < sc->sc_rxndesc; i++) {
1119		/*
1120		 * Small Rx buffers and descriptors
1121		 */
1122		mb = sc->sc_rxbuf[MYX_RXSMALL] + i;
1123		rxb = sc->sc_rxbufdesc[MYX_RXSMALL] + i;
1124
1125		if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
1126		    MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) {
1127			printf("%s: unable to create dmamap for small rx %d\n",
1128			    DEVNAME(sc), i);
1129			goto err;
1130		}
1131
1132		map = mb->mb_dmamap;
1133		mb->mb_m = myx_getbuf(sc, map, 1);
1134		if (mb->mb_m == NULL) {
1135			bus_dmamap_destroy(sc->sc_dmat, map);
1136			goto err;
1137		}
1138
1139		bus_dmamap_sync(sc->sc_dmat, map, 0,
1140		    mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
1141
1142		rxb->rb_addr_high =
1143		    htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1144		rxb->rb_addr_low =
1145		    htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1146
1147		data = sc->sc_rxsmallringoff + i * sizeof(*rxb);
1148		myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb));
1149
1150		/*
1151		 * Big Rx buffers and descriptors
1152		 */
1153		mb = sc->sc_rxbuf[MYX_RXBIG] + i;
1154		rxb = sc->sc_rxbufdesc[MYX_RXBIG] + i;
1155
1156		if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
1157		    MCLBYTES, 0, BUS_DMA_WAITOK, &mb->mb_dmamap) != 0) {
1158			printf("%s: unable to create dmamap for big rx %d\n",
1159			    DEVNAME(sc), i);
1160			goto err;
1161		}
1162
1163		map = mb->mb_dmamap;
1164		mb->mb_m = myx_getbuf(sc, map, 1);
1165		if (mb->mb_m == NULL) {
1166			bus_dmamap_destroy(sc->sc_dmat, map);
1167			goto err;
1168		}
1169
1170		bus_dmamap_sync(sc->sc_dmat, map, 0,
1171		    mb->mb_m->m_pkthdr.len, BUS_DMASYNC_PREREAD);
1172
1173		rxb->rb_addr_high =
1174		    htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1175		rxb->rb_addr_low =
1176		    htobe32(MYX_ADDRHIGH(map->dm_segs[0].ds_addr));
1177
1178		data = sc->sc_rxbigringoff + i * sizeof(*rxb);
1179		myx_write(sc, data, (u_int8_t *)rxb, sizeof(*rxb));
1180	}
1181
1182	bzero(&mc, sizeof(mc));
1183	mc.mc_data0 = MYX_MAX_MTU_SMALL;
1184	if (myx_cmd(sc, MYXCMD_SET_SMALLBUFSZ, &mc, NULL) != 0) {
1185		printf("%s: failed to set small buf size\n", DEVNAME(sc));
1186		goto err;
1187	}
1188
1189	bzero(&mc, sizeof(mc));
1190	mc.mc_data0 = MCLBYTES;
1191	if (myx_cmd(sc, MYXCMD_SET_BIGBUFSZ, &mc, NULL) != 0) {
1192		printf("%s: failed to set big buf size\n", DEVNAME(sc));
1193		goto err;
1194	}
1195
1196	/*
1197	 * Setup status DMA
1198	 */
1199	map = sc->sc_stsdma.mxm_map;
1200
1201	bzero(&mc, sizeof(mc));
1202	mc.mc_data0 = MYX_ADDRLOW(map->dm_segs[0].ds_addr);
1203	mc.mc_data1 = MYX_ADDRHIGH(map->dm_segs[0].ds_addr);
1204	mc.mc_data2 = sizeof(struct myx_status);
1205	if (myx_cmd(sc, MYXCMD_SET_STATSDMA, &mc, NULL) != 0) {
1206		printf("%s: failed to set status DMA offset\n", DEVNAME(sc));
1207		goto err;
1208	}
1209
1210	bus_dmamap_sync(sc->sc_dmat, map, 0,
1211	    map->dm_mapsize, BUS_DMASYNC_PREWRITE);
1212
1213	return (0);
1214 err:
1215	myx_free_rings(sc);
1216	return (-1);
1217}
1218
1219void
1220myx_free_rings(struct myx_softc *sc)
1221{
1222	if (sc->sc_rxbuf[MYX_RXSMALL] != NULL) {
1223		free(sc->sc_rxbuf[MYX_RXSMALL], M_DEVBUF);
1224		sc->sc_rxbuf[MYX_RXSMALL] = NULL;
1225	}
1226	if (sc->sc_rxbufdesc[MYX_RXSMALL] != NULL) {
1227		free(sc->sc_rxbufdesc[MYX_RXSMALL], M_DEVBUF);
1228		sc->sc_rxbufdesc[MYX_RXSMALL] = NULL;
1229	}
1230	if (sc->sc_rxbuf[MYX_RXBIG] != NULL) {
1231		free(sc->sc_rxbuf[MYX_RXBIG], M_DEVBUF);
1232		sc->sc_rxbuf[MYX_RXBIG] = NULL;
1233	}
1234	if (sc->sc_rxbufdesc[MYX_RXBIG] != NULL) {
1235		free(sc->sc_rxbufdesc[MYX_RXBIG], M_DEVBUF);
1236		sc->sc_rxbufdesc[MYX_RXBIG] = NULL;
1237	}
1238	if (sc->sc_rxdesc != NULL) {
1239		myx_dmamem_free(sc, &sc->sc_rxdma);
1240		sc->sc_rxdesc = NULL;
1241	}
1242	if (sc->sc_sts != NULL) {
1243		myx_dmamem_free(sc, &sc->sc_stsdma);
1244		sc->sc_sts = NULL;
1245	}
1246	return;
1247}
1248
1249struct mbuf *
1250myx_getbuf(struct myx_softc *sc, bus_dmamap_t map, int wait)
1251{
1252	struct mbuf		*m = NULL;
1253
1254	MGETHDR(m, wait ? M_WAIT : M_DONTWAIT, MT_DATA);
1255	if (m == NULL)
1256		goto merr;
1257
1258	MCLGET(m, wait ? M_WAIT : M_DONTWAIT);
1259	if ((m->m_flags & M_EXT) == 0)
1260		goto merr;
1261	m->m_len = m->m_pkthdr.len = MCLBYTES;
1262
1263	if (bus_dmamap_load_mbuf(sc->sc_dmat, map, m,
1264	    wait ? BUS_DMA_WAITOK : BUS_DMA_NOWAIT) != 0) {
1265		printf("%s: could not load mbuf dma map\n", DEVNAME(sc));
1266		goto err;
1267	}
1268
1269	return (m);
1270 merr:
1271	printf("%s: unable to allocate mbuf\n", DEVNAME(sc));
1272 err:
1273	if (m != NULL)
1274		m_freem(m);
1275	return (NULL);
1276}
1277