1178173Simp/*-
2178173Simp * Copyright (C) 2007
3178173Simp *	Oleksandr Tymoshenko <gonzo@freebsd.org>. All rights reserved.
4178173Simp *
5178173Simp * Redistribution and use in source and binary forms, with or without
6178173Simp * modification, are permitted provided that the following conditions
7178173Simp * are met:
8178173Simp * 1. Redistributions of source code must retain the above copyright
9178173Simp *    notice, this list of conditions and the following disclaimer.
10178173Simp * 2. Redistributions in binary form must reproduce the above copyright
11178173Simp *    notice, this list of conditions and the following disclaimer in the
12178173Simp *    documentation and/or other materials provided with the distribution.
13178173Simp *
14178173Simp * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15178173Simp * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16178173Simp * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17178173Simp * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
18178173Simp * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19178173Simp * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20178173Simp * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21178173Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
22178173Simp * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
23178173Simp * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24178173Simp * THE POSSIBILITY OF SUCH DAMAGE.
25178173Simp *
26178173Simp * $Id: $
27178173Simp *
28178173Simp */
29178173Simp
30178173Simp#include <sys/cdefs.h>
31178173Simp__FBSDID("$FreeBSD$");
32178173Simp
33178173Simp/*
34178173Simp * RC32434 Ethernet interface driver
35178173Simp */
36178173Simp#include <sys/param.h>
37178173Simp#include <sys/endian.h>
38178173Simp#include <sys/systm.h>
39178173Simp#include <sys/sockio.h>
40178173Simp#include <sys/mbuf.h>
41178173Simp#include <sys/malloc.h>
42178173Simp#include <sys/kernel.h>
43257420Smarkj#include <sys/lock.h>
44178173Simp#include <sys/module.h>
45257420Smarkj#include <sys/mutex.h>
46178173Simp#include <sys/socket.h>
47178173Simp#include <sys/taskqueue.h>
48178173Simp
49178173Simp#include <net/if.h>
50178173Simp#include <net/if_arp.h>
51178173Simp#include <net/ethernet.h>
52178173Simp#include <net/if_dl.h>
53178173Simp#include <net/if_media.h>
54178173Simp#include <net/if_types.h>
55257420Smarkj#include <net/if_var.h>
56178173Simp
57178173Simp#include <net/bpf.h>
58178173Simp
59178173Simp#include <machine/bus.h>
60178173Simp#include <machine/resource.h>
61178173Simp#include <sys/bus.h>
62178173Simp#include <sys/rman.h>
63178173Simp
64178173Simp#include <dev/mii/mii.h>
65178173Simp#include <dev/mii/miivar.h>
66178173Simp
67178173Simp#include <dev/pci/pcireg.h>
68178173Simp#include <dev/pci/pcivar.h>
69178173Simp
70178173SimpMODULE_DEPEND(kr, ether, 1, 1, 1);
71178173SimpMODULE_DEPEND(kr, miibus, 1, 1, 1);
72178173Simp
73178173Simp#include "miibus_if.h"
74178173Simp
75182901Sgonzo#include <mips/idt/if_krreg.h>
76178173Simp
77178173Simp#define KR_DEBUG
78178173Simp
79178173Simpstatic int kr_attach(device_t);
80178173Simpstatic int kr_detach(device_t);
81178173Simpstatic int kr_ifmedia_upd(struct ifnet *);
82178173Simpstatic void kr_ifmedia_sts(struct ifnet *, struct ifmediareq *);
83178173Simpstatic int kr_ioctl(struct ifnet *, u_long, caddr_t);
84178173Simpstatic void kr_init(void *);
85178173Simpstatic void kr_init_locked(struct kr_softc *);
86178173Simpstatic void kr_link_task(void *, int);
87178173Simpstatic int kr_miibus_readreg(device_t, int, int);
88178173Simpstatic void kr_miibus_statchg(device_t);
89178173Simpstatic int kr_miibus_writereg(device_t, int, int, int);
90178173Simpstatic int kr_probe(device_t);
91178173Simpstatic void kr_reset(struct kr_softc *);
92178173Simpstatic int kr_resume(device_t);
93178173Simpstatic int kr_rx_ring_init(struct kr_softc *);
94178173Simpstatic int kr_tx_ring_init(struct kr_softc *);
95194342Sbzstatic int kr_shutdown(device_t);
96178173Simpstatic void kr_start(struct ifnet *);
97178173Simpstatic void kr_start_locked(struct ifnet *);
98178173Simpstatic void kr_stop(struct kr_softc *);
99178173Simpstatic int kr_suspend(device_t);
100178173Simp
101178173Simpstatic void kr_rx(struct kr_softc *);
102178173Simpstatic void kr_tx(struct kr_softc *);
103178173Simpstatic void kr_rx_intr(void *);
104178173Simpstatic void kr_tx_intr(void *);
105178173Simpstatic void kr_rx_und_intr(void *);
106178173Simpstatic void kr_tx_ovr_intr(void *);
107178173Simpstatic void kr_tick(void *);
108178173Simp
109178173Simpstatic void kr_dmamap_cb(void *, bus_dma_segment_t *, int, int);
110178173Simpstatic int kr_dma_alloc(struct kr_softc *);
111178173Simpstatic void kr_dma_free(struct kr_softc *);
112178173Simpstatic int kr_newbuf(struct kr_softc *, int);
113178173Simpstatic __inline void kr_fixup_rx(struct mbuf *);
114178173Simp
115178173Simpstatic device_method_t kr_methods[] = {
116178173Simp	/* Device interface */
117178173Simp	DEVMETHOD(device_probe,		kr_probe),
118178173Simp	DEVMETHOD(device_attach,	kr_attach),
119178173Simp	DEVMETHOD(device_detach,	kr_detach),
120178173Simp	DEVMETHOD(device_suspend,	kr_suspend),
121178173Simp	DEVMETHOD(device_resume,	kr_resume),
122178173Simp	DEVMETHOD(device_shutdown,	kr_shutdown),
123178173Simp
124178173Simp	/* MII interface */
125178173Simp	DEVMETHOD(miibus_readreg,	kr_miibus_readreg),
126178173Simp	DEVMETHOD(miibus_writereg,	kr_miibus_writereg),
127178173Simp	DEVMETHOD(miibus_statchg,	kr_miibus_statchg),
128178173Simp
129227843Smarius	DEVMETHOD_END
130178173Simp};
131178173Simp
132178173Simpstatic driver_t kr_driver = {
133178173Simp	"kr",
134178173Simp	kr_methods,
135178173Simp	sizeof(struct kr_softc)
136178173Simp};
137178173Simp
138178173Simpstatic devclass_t kr_devclass;
139178173Simp
140178173SimpDRIVER_MODULE(kr, obio, kr_driver, kr_devclass, 0, 0);
141178173SimpDRIVER_MODULE(miibus, kr, miibus_driver, miibus_devclass, 0, 0);
142178173Simp
143178173Simpstatic int
144178173Simpkr_probe(device_t dev)
145178173Simp{
146178173Simp
147178173Simp	device_set_desc(dev, "RC32434 Ethernet interface");
148178173Simp	return (0);
149178173Simp}
150178173Simp
151178173Simpstatic int
152178173Simpkr_attach(device_t dev)
153178173Simp{
154178173Simp	uint8_t			eaddr[ETHER_ADDR_LEN];
155178173Simp	struct ifnet		*ifp;
156178173Simp	struct kr_softc		*sc;
157178173Simp	int			error = 0, rid;
158178173Simp	int			unit;
159178173Simp
160178173Simp	sc = device_get_softc(dev);
161178173Simp	unit = device_get_unit(dev);
162178173Simp	sc->kr_dev = dev;
163178173Simp
164178173Simp	mtx_init(&sc->kr_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
165178173Simp	    MTX_DEF);
166178173Simp	callout_init_mtx(&sc->kr_stat_callout, &sc->kr_mtx, 0);
167178173Simp	TASK_INIT(&sc->kr_link_task, 0, kr_link_task, sc);
168178173Simp	pci_enable_busmaster(dev);
169178173Simp
170178173Simp	/* Map control/status registers. */
171178173Simp	sc->kr_rid = 0;
172178173Simp	sc->kr_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->kr_rid,
173178173Simp	    RF_ACTIVE);
174178173Simp
175178173Simp	if (sc->kr_res == NULL) {
176178173Simp		device_printf(dev, "couldn't map memory\n");
177178173Simp		error = ENXIO;
178178173Simp		goto fail;
179178173Simp	}
180178173Simp
181178173Simp	sc->kr_btag = rman_get_bustag(sc->kr_res);
182178173Simp	sc->kr_bhandle = rman_get_bushandle(sc->kr_res);
183178173Simp
184178173Simp	/* Allocate interrupts */
185178173Simp	rid = 0;
186178173Simp	sc->kr_rx_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_RX_IRQ,
187178173Simp	    KR_RX_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
188178173Simp
189178173Simp	if (sc->kr_rx_irq == NULL) {
190178173Simp		device_printf(dev, "couldn't map rx interrupt\n");
191178173Simp		error = ENXIO;
192178173Simp		goto fail;
193178173Simp	}
194178173Simp
195178173Simp	rid = 0;
196178173Simp	sc->kr_tx_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, KR_TX_IRQ,
197178173Simp	    KR_TX_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
198178173Simp
199178173Simp	if (sc->kr_tx_irq == NULL) {
200178173Simp		device_printf(dev, "couldn't map tx interrupt\n");
201178173Simp		error = ENXIO;
202178173Simp		goto fail;
203178173Simp	}
204178173Simp
205178173Simp	rid = 0;
206178173Simp	sc->kr_rx_und_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
207178173Simp	    KR_RX_UND_IRQ, KR_RX_UND_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
208178173Simp
209178173Simp	if (sc->kr_rx_und_irq == NULL) {
210178173Simp		device_printf(dev, "couldn't map rx underrun interrupt\n");
211178173Simp		error = ENXIO;
212178173Simp		goto fail;
213178173Simp	}
214178173Simp
215178173Simp	rid = 0;
216178173Simp	sc->kr_tx_ovr_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
217178173Simp	    KR_TX_OVR_IRQ, KR_TX_OVR_IRQ, 1, RF_SHAREABLE | RF_ACTIVE);
218178173Simp
219178173Simp	if (sc->kr_tx_ovr_irq == NULL) {
220178173Simp		device_printf(dev, "couldn't map tx overrun interrupt\n");
221178173Simp		error = ENXIO;
222178173Simp		goto fail;
223178173Simp	}
224178173Simp
225178173Simp	/* Allocate ifnet structure. */
226178173Simp	ifp = sc->kr_ifp = if_alloc(IFT_ETHER);
227178173Simp
228178173Simp	if (ifp == NULL) {
229178173Simp		device_printf(dev, "couldn't allocate ifnet structure\n");
230178173Simp		error = ENOSPC;
231178173Simp		goto fail;
232178173Simp	}
233178173Simp	ifp->if_softc = sc;
234178173Simp	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
235178173Simp	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
236178173Simp	ifp->if_ioctl = kr_ioctl;
237178173Simp	ifp->if_start = kr_start;
238178173Simp	ifp->if_init = kr_init;
239178173Simp
240178173Simp	/* XXX: add real size */
241178173Simp	IFQ_SET_MAXLEN(&ifp->if_snd, 9);
242178173Simp	ifp->if_snd.ifq_maxlen = 9;
243178173Simp	IFQ_SET_READY(&ifp->if_snd);
244178173Simp
245178173Simp	ifp->if_capenable = ifp->if_capabilities;
246178173Simp
247178173Simp	eaddr[0] = 0x00;
248178173Simp	eaddr[1] = 0x0C;
249178173Simp	eaddr[2] = 0x42;
250178173Simp	eaddr[3] = 0x09;
251178173Simp	eaddr[4] = 0x5E;
252178173Simp	eaddr[5] = 0x6B;
253178173Simp
254178173Simp	if (kr_dma_alloc(sc) != 0) {
255178173Simp		error = ENXIO;
256178173Simp		goto fail;
257178173Simp	}
258178173Simp
259178173Simp	/* TODO: calculate prescale */
260178173Simp	CSR_WRITE_4(sc, KR_ETHMCP, (165000000 / (1250000 + 1)) & ~1);
261178173Simp
262178173Simp	CSR_WRITE_4(sc, KR_MIIMCFG, KR_MIIMCFG_R);
263178173Simp	DELAY(1000);
264178173Simp	CSR_WRITE_4(sc, KR_MIIMCFG, 0);
265178173Simp
266178173Simp	/* Do MII setup. */
267213894Smarius	error = mii_attach(dev, &sc->kr_miibus, ifp, kr_ifmedia_upd,
268213894Smarius	    kr_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
269213894Smarius	if (error != 0) {
270213894Smarius		device_printf(dev, "attaching PHYs failed\n");
271178173Simp		goto fail;
272178173Simp	}
273178173Simp
274178173Simp	/* Call MI attach routine. */
275178173Simp	ether_ifattach(ifp, eaddr);
276178173Simp
277178173Simp	/* Hook interrupt last to avoid having to lock softc */
278178173Simp	error = bus_setup_intr(dev, sc->kr_rx_irq, INTR_TYPE_NET | INTR_MPSAFE,
279178173Simp	    NULL, kr_rx_intr, sc, &sc->kr_rx_intrhand);
280178173Simp
281178173Simp	if (error) {
282178173Simp		device_printf(dev, "couldn't set up rx irq\n");
283178173Simp		ether_ifdetach(ifp);
284178173Simp		goto fail;
285178173Simp	}
286178173Simp
287178173Simp	error = bus_setup_intr(dev, sc->kr_tx_irq, INTR_TYPE_NET | INTR_MPSAFE,
288178173Simp	    NULL, kr_tx_intr, sc, &sc->kr_tx_intrhand);
289178173Simp
290178173Simp	if (error) {
291178173Simp		device_printf(dev, "couldn't set up tx irq\n");
292178173Simp		ether_ifdetach(ifp);
293178173Simp		goto fail;
294178173Simp	}
295178173Simp
296178173Simp	error = bus_setup_intr(dev, sc->kr_rx_und_irq,
297178173Simp	    INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_rx_und_intr, sc,
298178173Simp	    &sc->kr_rx_und_intrhand);
299178173Simp
300178173Simp	if (error) {
301178173Simp		device_printf(dev, "couldn't set up rx underrun irq\n");
302178173Simp		ether_ifdetach(ifp);
303178173Simp		goto fail;
304178173Simp	}
305178173Simp
306178173Simp	error = bus_setup_intr(dev, sc->kr_tx_ovr_irq,
307178173Simp	    INTR_TYPE_NET | INTR_MPSAFE, NULL, kr_tx_ovr_intr, sc,
308178173Simp	    &sc->kr_tx_ovr_intrhand);
309178173Simp
310178173Simp	if (error) {
311178173Simp		device_printf(dev, "couldn't set up tx overrun irq\n");
312178173Simp		ether_ifdetach(ifp);
313178173Simp		goto fail;
314178173Simp	}
315178173Simp
316178173Simpfail:
317178173Simp	if (error)
318178173Simp		kr_detach(dev);
319178173Simp
320178173Simp	return (error);
321178173Simp}
322178173Simp
323178173Simpstatic int
324178173Simpkr_detach(device_t dev)
325178173Simp{
326178173Simp	struct kr_softc		*sc = device_get_softc(dev);
327178173Simp	struct ifnet		*ifp = sc->kr_ifp;
328178173Simp
329178173Simp	KASSERT(mtx_initialized(&sc->kr_mtx), ("vr mutex not initialized"));
330178173Simp
331178173Simp	/* These should only be active if attach succeeded */
332178173Simp	if (device_is_attached(dev)) {
333178173Simp		KR_LOCK(sc);
334178173Simp		sc->kr_detach = 1;
335178173Simp		kr_stop(sc);
336178173Simp		KR_UNLOCK(sc);
337178173Simp		taskqueue_drain(taskqueue_swi, &sc->kr_link_task);
338178173Simp		ether_ifdetach(ifp);
339178173Simp	}
340178173Simp	if (sc->kr_miibus)
341178173Simp		device_delete_child(dev, sc->kr_miibus);
342178173Simp	bus_generic_detach(dev);
343178173Simp
344178173Simp	if (sc->kr_rx_intrhand)
345178173Simp		bus_teardown_intr(dev, sc->kr_rx_irq, sc->kr_rx_intrhand);
346178173Simp	if (sc->kr_rx_irq)
347178173Simp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_rx_irq);
348178173Simp	if (sc->kr_tx_intrhand)
349178173Simp		bus_teardown_intr(dev, sc->kr_tx_irq, sc->kr_tx_intrhand);
350178173Simp	if (sc->kr_tx_irq)
351178173Simp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_tx_irq);
352178173Simp	if (sc->kr_rx_und_intrhand)
353178173Simp		bus_teardown_intr(dev, sc->kr_rx_und_irq,
354178173Simp		    sc->kr_rx_und_intrhand);
355178173Simp	if (sc->kr_rx_und_irq)
356178173Simp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_rx_und_irq);
357178173Simp	if (sc->kr_tx_ovr_intrhand)
358178173Simp		bus_teardown_intr(dev, sc->kr_tx_ovr_irq,
359178173Simp		    sc->kr_tx_ovr_intrhand);
360178173Simp	if (sc->kr_tx_ovr_irq)
361178173Simp		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->kr_tx_ovr_irq);
362178173Simp
363178173Simp	if (sc->kr_res)
364178173Simp		bus_release_resource(dev, SYS_RES_MEMORY, sc->kr_rid,
365178173Simp		    sc->kr_res);
366178173Simp
367178173Simp	if (ifp)
368178173Simp		if_free(ifp);
369178173Simp
370178173Simp	kr_dma_free(sc);
371178173Simp
372178173Simp	mtx_destroy(&sc->kr_mtx);
373178173Simp
374178173Simp	return (0);
375178173Simp
376178173Simp}
377178173Simp
378178173Simpstatic int
379178173Simpkr_suspend(device_t dev)
380178173Simp{
381178173Simp
382178173Simp	panic("%s", __func__);
383178173Simp	return 0;
384178173Simp}
385178173Simp
386178173Simpstatic int
387178173Simpkr_resume(device_t dev)
388178173Simp{
389178173Simp
390178173Simp	panic("%s", __func__);
391178173Simp	return 0;
392178173Simp}
393178173Simp
394194342Sbzstatic int
395178173Simpkr_shutdown(device_t dev)
396178173Simp{
397178173Simp	struct kr_softc	*sc;
398178173Simp
399178173Simp	sc = device_get_softc(dev);
400178173Simp
401178173Simp	KR_LOCK(sc);
402178173Simp	kr_stop(sc);
403178173Simp	KR_UNLOCK(sc);
404194342Sbz
405194342Sbz	return (0);
406178173Simp}
407178173Simp
408178173Simpstatic int
409178173Simpkr_miibus_readreg(device_t dev, int phy, int reg)
410178173Simp{
411178173Simp	struct kr_softc * sc = device_get_softc(dev);
412178173Simp	int i, result;
413178173Simp
414178173Simp	i = KR_MII_TIMEOUT;
415178173Simp	while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
416178173Simp		i--;
417178173Simp
418178173Simp	if (i == 0)
419178173Simp		device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
420178173Simp
421178173Simp	CSR_WRITE_4(sc, KR_MIIMADDR, (phy << 8) | reg);
422178173Simp
423178173Simp	i = KR_MII_TIMEOUT;
424178173Simp	while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
425178173Simp		i--;
426178173Simp
427178173Simp	if (i == 0)
428178173Simp		device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
429178173Simp
430178173Simp	CSR_WRITE_4(sc, KR_MIIMCMD, KR_MIIMCMD_RD);
431178173Simp
432178173Simp	i = KR_MII_TIMEOUT;
433178173Simp	while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
434178173Simp		i--;
435178173Simp
436178173Simp	if (i == 0)
437178173Simp		device_printf(dev, "phy mii read is timed out %d:%d\n", phy,
438178173Simp		    reg);
439178173Simp
440178173Simp	if (CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_NV)
441178173Simp		printf("phy mii readreg failed %d:%d: data not valid\n",
442178173Simp		    phy, reg);
443178173Simp
444178173Simp	result = CSR_READ_4(sc , KR_MIIMRDD);
445178173Simp	CSR_WRITE_4(sc, KR_MIIMCMD, 0);
446178173Simp
447178173Simp	return (result);
448178173Simp}
449178173Simp
450178173Simpstatic int
451178173Simpkr_miibus_writereg(device_t dev, int phy, int reg, int data)
452178173Simp{
453178173Simp	struct kr_softc * sc = device_get_softc(dev);
454178173Simp	int i;
455178173Simp
456178173Simp	i = KR_MII_TIMEOUT;
457178173Simp	while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
458178173Simp		i--;
459178173Simp
460178173Simp	if (i == 0)
461178173Simp		device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
462178173Simp
463178173Simp	CSR_WRITE_4(sc, KR_MIIMADDR, (phy << 8) | reg);
464178173Simp
465178173Simp	i = KR_MII_TIMEOUT;
466178173Simp	while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
467178173Simp		i--;
468178173Simp
469178173Simp	if (i == 0)
470178173Simp		device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
471178173Simp
472178173Simp	CSR_WRITE_4(sc, KR_MIIMWTD, data);
473178173Simp
474178173Simp	i = KR_MII_TIMEOUT;
475178173Simp	while ((CSR_READ_4(sc, KR_MIIMIND) & KR_MIIMIND_BSY) && i)
476178173Simp		i--;
477178173Simp
478178173Simp	if (i == 0)
479178173Simp		device_printf(dev, "phy mii is busy %d:%d\n", phy, reg);
480178173Simp
481178173Simp	return (0);
482178173Simp}
483178173Simp
484178173Simpstatic void
485178173Simpkr_miibus_statchg(device_t dev)
486178173Simp{
487178173Simp	struct kr_softc		*sc;
488178173Simp
489178173Simp	sc = device_get_softc(dev);
490178173Simp	taskqueue_enqueue(taskqueue_swi, &sc->kr_link_task);
491178173Simp}
492178173Simp
493178173Simpstatic void
494178173Simpkr_link_task(void *arg, int pending)
495178173Simp{
496178173Simp	struct kr_softc		*sc;
497178173Simp	struct mii_data		*mii;
498178173Simp	struct ifnet		*ifp;
499178173Simp	/* int			lfdx, mfdx; */
500178173Simp
501178173Simp	sc = (struct kr_softc *)arg;
502178173Simp
503178173Simp	KR_LOCK(sc);
504178173Simp	mii = device_get_softc(sc->kr_miibus);
505178173Simp	ifp = sc->kr_ifp;
506178173Simp	if (mii == NULL || ifp == NULL ||
507178173Simp	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
508178173Simp		KR_UNLOCK(sc);
509178173Simp		return;
510178173Simp	}
511178173Simp
512178173Simp	if (mii->mii_media_status & IFM_ACTIVE) {
513178173Simp		if (IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
514178173Simp			sc->kr_link_status = 1;
515178173Simp	} else
516178173Simp		sc->kr_link_status = 0;
517178173Simp
518178173Simp	KR_UNLOCK(sc);
519178173Simp}
520178173Simp
521178173Simpstatic void
522178173Simpkr_reset(struct kr_softc *sc)
523178173Simp{
524178173Simp	int		i;
525178173Simp
526178173Simp	CSR_WRITE_4(sc, KR_ETHINTFC, 0);
527178173Simp
528178173Simp	for (i = 0; i < KR_TIMEOUT; i++) {
529178173Simp		DELAY(10);
530178173Simp		if (!(CSR_READ_4(sc, KR_ETHINTFC) & ETH_INTFC_RIP))
531178173Simp			break;
532178173Simp	}
533178173Simp
534178173Simp	if (i == KR_TIMEOUT)
535178173Simp		device_printf(sc->kr_dev, "reset time out\n");
536178173Simp}
537178173Simp
538178173Simpstatic void
539178173Simpkr_init(void *xsc)
540178173Simp{
541178173Simp	struct kr_softc	 *sc = xsc;
542178173Simp
543178173Simp	KR_LOCK(sc);
544178173Simp	kr_init_locked(sc);
545178173Simp	KR_UNLOCK(sc);
546178173Simp}
547178173Simp
548178173Simpstatic void
549178173Simpkr_init_locked(struct kr_softc *sc)
550178173Simp{
551178173Simp	struct ifnet		*ifp = sc->kr_ifp;
552178173Simp	struct mii_data		*mii;
553178173Simp
554178173Simp	KR_LOCK_ASSERT(sc);
555178173Simp
556178173Simp	mii = device_get_softc(sc->kr_miibus);
557178173Simp
558178173Simp	kr_stop(sc);
559178173Simp	kr_reset(sc);
560178173Simp
561178173Simp	CSR_WRITE_4(sc, KR_ETHINTFC, ETH_INTFC_EN);
562178173Simp
563178173Simp	/* Init circular RX list. */
564178173Simp	if (kr_rx_ring_init(sc) != 0) {
565178173Simp		device_printf(sc->kr_dev,
566178173Simp		    "initialization failed: no memory for rx buffers\n");
567178173Simp		kr_stop(sc);
568178173Simp		return;
569178173Simp	}
570178173Simp
571178173Simp	/* Init tx descriptors. */
572178173Simp	kr_tx_ring_init(sc);
573178173Simp
574178173Simp	KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, 0);
575178173Simp	KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_NDPTR, 0);
576178173Simp	KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR,
577178173Simp	    sc->kr_rdata.kr_rx_ring_paddr);
578178173Simp
579178173Simp
580178173Simp	KR_DMA_CLEARBITS_REG(KR_DMA_RXCHAN, DMA_SM,
581178173Simp	    DMA_SM_H | DMA_SM_E | DMA_SM_D) ;
582178173Simp
583178173Simp	KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, 0);
584178173Simp	KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR, 0);
585178173Simp	KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_DPTR, 0);
586178173Simp	KR_DMA_CLEARBITS_REG(KR_DMA_TXCHAN, DMA_SM,
587178173Simp	    DMA_SM_F | DMA_SM_E);
588178173Simp
589178173Simp
590178173Simp	/* Accept only packets destined for THIS Ethernet device address */
591178173Simp	CSR_WRITE_4(sc, KR_ETHARC, 1);
592178173Simp
593178173Simp	/*
594178173Simp	 * Set all Ethernet address registers to the same initial values
595178173Simp	 * set all four addresses to 66-88-aa-cc-dd-ee
596178173Simp	 */
597178173Simp	CSR_WRITE_4(sc, KR_ETHSAL0, 0x42095E6B);
598178173Simp	CSR_WRITE_4(sc, KR_ETHSAH0, 0x0000000C);
599178173Simp
600178173Simp	CSR_WRITE_4(sc, KR_ETHSAL1, 0x42095E6B);
601178173Simp	CSR_WRITE_4(sc, KR_ETHSAH1, 0x0000000C);
602178173Simp
603178173Simp	CSR_WRITE_4(sc, KR_ETHSAL2, 0x42095E6B);
604178173Simp	CSR_WRITE_4(sc, KR_ETHSAH2, 0x0000000C);
605178173Simp
606178173Simp	CSR_WRITE_4(sc, KR_ETHSAL3, 0x42095E6B);
607178173Simp	CSR_WRITE_4(sc, KR_ETHSAH3, 0x0000000C);
608178173Simp
609178173Simp	CSR_WRITE_4(sc, KR_ETHMAC2,
610178173Simp	    KR_ETH_MAC2_PEN | KR_ETH_MAC2_CEN | KR_ETH_MAC2_FD);
611178173Simp
612178173Simp	CSR_WRITE_4(sc, KR_ETHIPGT, KR_ETHIPGT_FULL_DUPLEX);
613178173Simp	CSR_WRITE_4(sc, KR_ETHIPGR, 0x12); /* minimum value */
614178173Simp
615178173Simp	CSR_WRITE_4(sc, KR_MIIMCFG, KR_MIIMCFG_R);
616178173Simp	DELAY(1000);
617178173Simp	CSR_WRITE_4(sc, KR_MIIMCFG, 0);
618178173Simp
619178173Simp	/* TODO: calculate prescale */
620178173Simp	CSR_WRITE_4(sc, KR_ETHMCP, (165000000 / (1250000 + 1)) & ~1);
621178173Simp
622178173Simp	/* FIFO Tx threshold level */
623178173Simp	CSR_WRITE_4(sc, KR_ETHFIFOTT, 0x30);
624178173Simp
625178173Simp	CSR_WRITE_4(sc, KR_ETHMAC1, KR_ETH_MAC1_RE);
626178173Simp
627178173Simp	sc->kr_link_status = 0;
628178173Simp	mii_mediachg(mii);
629178173Simp
630178173Simp	ifp->if_drv_flags |= IFF_DRV_RUNNING;
631178173Simp	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
632178173Simp
633178173Simp	callout_reset(&sc->kr_stat_callout, hz, kr_tick, sc);
634178173Simp}
635178173Simp
636178173Simpstatic void
637178173Simpkr_start(struct ifnet *ifp)
638178173Simp{
639178173Simp	struct kr_softc	 *sc;
640178173Simp
641178173Simp	sc = ifp->if_softc;
642178173Simp
643178173Simp	KR_LOCK(sc);
644178173Simp	kr_start_locked(ifp);
645178173Simp	KR_UNLOCK(sc);
646178173Simp}
647178173Simp
648178173Simp/*
649178173Simp * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
650178173Simp * pointers to the fragment pointers.
651178173Simp */
652178173Simpstatic int
653178173Simpkr_encap(struct kr_softc *sc, struct mbuf **m_head)
654178173Simp{
655178173Simp	struct kr_txdesc	*txd;
656178173Simp	struct kr_desc		*desc, *prev_desc;
657178173Simp	bus_dma_segment_t	txsegs[KR_MAXFRAGS];
658178173Simp	uint32_t		link_addr;
659178173Simp	int			error, i, nsegs, prod, si, prev_prod;
660178173Simp
661178173Simp	KR_LOCK_ASSERT(sc);
662178173Simp
663178173Simp	prod = sc->kr_cdata.kr_tx_prod;
664178173Simp	txd = &sc->kr_cdata.kr_txdesc[prod];
665178173Simp	error = bus_dmamap_load_mbuf_sg(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap,
666178173Simp	    *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
667178173Simp	if (error == EFBIG) {
668178173Simp		panic("EFBIG");
669178173Simp	} else if (error != 0)
670178173Simp		return (error);
671178173Simp	if (nsegs == 0) {
672178173Simp		m_freem(*m_head);
673178173Simp		*m_head = NULL;
674178173Simp		return (EIO);
675178173Simp	}
676178173Simp
677178173Simp	/* Check number of available descriptors. */
678178173Simp	if (sc->kr_cdata.kr_tx_cnt + nsegs >= (KR_TX_RING_CNT - 1)) {
679178173Simp		bus_dmamap_unload(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap);
680178173Simp		return (ENOBUFS);
681178173Simp	}
682178173Simp
683178173Simp	txd->tx_m = *m_head;
684178173Simp	bus_dmamap_sync(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap,
685178173Simp	    BUS_DMASYNC_PREWRITE);
686178173Simp
687178173Simp	si = prod;
688178173Simp
689178173Simp	/*
690178173Simp	 * Make a list of descriptors for this packet. DMA controller will
691178173Simp	 * walk through it while kr_link is not zero. The last one should
692178173Simp	 * have COF flag set, to pickup next chain from NDPTR
693178173Simp	 */
694178173Simp	prev_prod = prod;
695178173Simp	desc = prev_desc = NULL;
696178173Simp	for (i = 0; i < nsegs; i++) {
697178173Simp		desc = &sc->kr_rdata.kr_tx_ring[prod];
698178173Simp		desc->kr_ctl = KR_DMASIZE(txsegs[i].ds_len) | KR_CTL_IOF;
699178173Simp		if (i == 0)
700178173Simp			desc->kr_devcs = KR_DMATX_DEVCS_FD;
701178173Simp		desc->kr_ca = txsegs[i].ds_addr;
702178173Simp		desc->kr_link = 0;
703178173Simp		/* link with previous descriptor */
704178173Simp		if (prev_desc)
705178173Simp			prev_desc->kr_link = KR_TX_RING_ADDR(sc, prod);
706178173Simp
707178173Simp		sc->kr_cdata.kr_tx_cnt++;
708178173Simp		prev_desc = desc;
709178173Simp		KR_INC(prod, KR_TX_RING_CNT);
710178173Simp	}
711178173Simp
712178173Simp	/*
713178173Simp	 * Set COF for last descriptor and mark last fragment with LD flag
714178173Simp	 */
715178173Simp	if (desc) {
716178173Simp		desc->kr_ctl |=  KR_CTL_COF;
717178173Simp		desc->kr_devcs |= KR_DMATX_DEVCS_LD;
718178173Simp	}
719178173Simp
720178173Simp	/* Update producer index. */
721178173Simp	sc->kr_cdata.kr_tx_prod = prod;
722178173Simp
723178173Simp	/* Sync descriptors. */
724178173Simp	bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
725178173Simp	    sc->kr_cdata.kr_tx_ring_map,
726178173Simp	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
727178173Simp
728178173Simp	/* Start transmitting */
729178173Simp	/* Check if new list is queued in NDPTR */
730178173Simp	if (KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_NDPTR) == 0) {
731178173Simp		/* NDPTR is not busy - start new list */
732178173Simp		KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR,
733178173Simp		    KR_TX_RING_ADDR(sc, si));
734178173Simp	}
735178173Simp	else {
736178173Simp		link_addr = KR_TX_RING_ADDR(sc, si);
737178173Simp		/* Get previous descriptor */
738178173Simp		si = (si + KR_TX_RING_CNT - 1) % KR_TX_RING_CNT;
739178173Simp		desc = &sc->kr_rdata.kr_tx_ring[si];
740178173Simp		desc->kr_link = link_addr;
741178173Simp	}
742178173Simp
743178173Simp	return (0);
744178173Simp}
745178173Simp
746178173Simpstatic void
747178173Simpkr_start_locked(struct ifnet *ifp)
748178173Simp{
749178173Simp	struct kr_softc		*sc;
750178173Simp	struct mbuf		*m_head;
751178173Simp	int			enq;
752178173Simp
753178173Simp	sc = ifp->if_softc;
754178173Simp
755178173Simp	KR_LOCK_ASSERT(sc);
756178173Simp
757178173Simp	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
758178173Simp	    IFF_DRV_RUNNING || sc->kr_link_status == 0 )
759178173Simp		return;
760178173Simp
761178173Simp	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
762178173Simp	    sc->kr_cdata.kr_tx_cnt < KR_TX_RING_CNT - 2; ) {
763178173Simp		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
764178173Simp		if (m_head == NULL)
765178173Simp			break;
766178173Simp		/*
767178173Simp		 * Pack the data into the transmit ring. If we
768178173Simp		 * don't have room, set the OACTIVE flag and wait
769178173Simp		 * for the NIC to drain the ring.
770178173Simp		 */
771178173Simp		if (kr_encap(sc, &m_head)) {
772178173Simp			if (m_head == NULL)
773178173Simp				break;
774178173Simp			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
775178173Simp			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
776178173Simp			break;
777178173Simp		}
778178173Simp
779178173Simp		enq++;
780178173Simp		/*
781178173Simp		 * If there's a BPF listener, bounce a copy of this frame
782178173Simp		 * to him.
783178173Simp		 */
784178173Simp		ETHER_BPF_MTAP(ifp, m_head);
785178173Simp	}
786178173Simp}
787178173Simp
788178173Simpstatic void
789178173Simpkr_stop(struct kr_softc *sc)
790178173Simp{
791178173Simp	struct ifnet	    *ifp;
792178173Simp
793178173Simp	KR_LOCK_ASSERT(sc);
794178173Simp
795178173Simp
796178173Simp	ifp = sc->kr_ifp;
797178173Simp	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
798178173Simp	callout_stop(&sc->kr_stat_callout);
799178173Simp
800178173Simp	/* mask out RX interrupts */
801178173Simp	KR_DMA_SETBITS_REG(KR_DMA_RXCHAN, DMA_SM,
802178173Simp	    DMA_SM_D | DMA_SM_H | DMA_SM_E);
803178173Simp
804178173Simp	/* mask out TX interrupts */
805178173Simp	KR_DMA_SETBITS_REG(KR_DMA_TXCHAN, DMA_SM,
806178173Simp	    DMA_SM_F | DMA_SM_E);
807178173Simp
808178173Simp	/* Abort RX DMA transactions */
809178173Simp	if (KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_C) & DMA_C_R) {
810178173Simp		/* Set ABORT bit if trunsuction is in progress */
811178173Simp		KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_C, DMA_C_ABORT);
812178173Simp		/* XXX: Add timeout */
813178173Simp		while ((KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S) & DMA_S_H) == 0)
814178173Simp			DELAY(10);
815178173Simp		KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, 0);
816178173Simp	}
817178173Simp	KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR, 0);
818178173Simp	KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_NDPTR, 0);
819178173Simp
820178173Simp	/* Abort TX DMA transactions */
821178173Simp	if (KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_C) & DMA_C_R) {
822178173Simp		/* Set ABORT bit if trunsuction is in progress */
823178173Simp		KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_C, DMA_C_ABORT);
824178173Simp		/* XXX: Add timeout */
825178173Simp		while ((KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_S) & DMA_S_H) == 0)
826178173Simp			DELAY(10);
827178173Simp		KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, 0);
828178173Simp	}
829178173Simp	KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_DPTR, 0);
830178173Simp	KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_NDPTR, 0);
831178173Simp
832178173Simp	CSR_WRITE_4(sc, KR_ETHINTFC, 0);
833178173Simp}
834178173Simp
835178173Simp
836178173Simpstatic int
837178173Simpkr_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
838178173Simp{
839178173Simp	struct kr_softc		*sc = ifp->if_softc;
840178173Simp	struct ifreq		*ifr = (struct ifreq *) data;
841178173Simp	struct mii_data		*mii;
842178173Simp	int			error;
843178173Simp
844178173Simp	switch (command) {
845178173Simp	case SIOCSIFFLAGS:
846178173Simp#if 0
847178173Simp		KR_LOCK(sc);
848178173Simp		if (ifp->if_flags & IFF_UP) {
849178173Simp			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
850178173Simp				if ((ifp->if_flags ^ sc->kr_if_flags) &
851178173Simp				    (IFF_PROMISC | IFF_ALLMULTI))
852178173Simp					kr_set_filter(sc);
853178173Simp			} else {
854178173Simp				if (sc->kr_detach == 0)
855178173Simp					kr_init_locked(sc);
856178173Simp			}
857178173Simp		} else {
858178173Simp			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
859178173Simp				kr_stop(sc);
860178173Simp		}
861178173Simp		sc->kr_if_flags = ifp->if_flags;
862178173Simp		KR_UNLOCK(sc);
863178173Simp#endif
864178173Simp		error = 0;
865178173Simp		break;
866178173Simp	case SIOCADDMULTI:
867178173Simp	case SIOCDELMULTI:
868178173Simp#if 0
869178173Simp		KR_LOCK(sc);
870178173Simp		kr_set_filter(sc);
871178173Simp		KR_UNLOCK(sc);
872178173Simp#endif
873178173Simp		error = 0;
874178173Simp		break;
875178173Simp	case SIOCGIFMEDIA:
876178173Simp	case SIOCSIFMEDIA:
877178173Simp		mii = device_get_softc(sc->kr_miibus);
878178173Simp		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
879178173Simp		break;
880178173Simp	case SIOCSIFCAP:
881178173Simp		error = 0;
882178173Simp#if 0
883178173Simp		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
884178173Simp		if ((mask & IFCAP_HWCSUM) != 0) {
885178173Simp			ifp->if_capenable ^= IFCAP_HWCSUM;
886178173Simp			if ((IFCAP_HWCSUM & ifp->if_capenable) &&
887178173Simp			    (IFCAP_HWCSUM & ifp->if_capabilities))
888178173Simp				ifp->if_hwassist = KR_CSUM_FEATURES;
889178173Simp			else
890178173Simp				ifp->if_hwassist = 0;
891178173Simp		}
892178173Simp		if ((mask & IFCAP_VLAN_HWTAGGING) != 0) {
893178173Simp			ifp->if_capenable ^= IFCAP_VLAN_HWTAGGING;
894178173Simp			if (IFCAP_VLAN_HWTAGGING & ifp->if_capenable &&
895178173Simp			    IFCAP_VLAN_HWTAGGING & ifp->if_capabilities &&
896178173Simp			    ifp->if_drv_flags & IFF_DRV_RUNNING) {
897178173Simp				KR_LOCK(sc);
898178173Simp				kr_vlan_setup(sc);
899178173Simp				KR_UNLOCK(sc);
900178173Simp			}
901178173Simp		}
902178173Simp		VLAN_CAPABILITIES(ifp);
903178173Simp#endif
904178173Simp		break;
905178173Simp	default:
906178173Simp		error = ether_ioctl(ifp, command, data);
907178173Simp		break;
908178173Simp	}
909178173Simp
910178173Simp	return (error);
911178173Simp}
912178173Simp
913178173Simp/*
914178173Simp * Set media options.
915178173Simp */
916178173Simpstatic int
917178173Simpkr_ifmedia_upd(struct ifnet *ifp)
918178173Simp{
919178173Simp	struct kr_softc		*sc;
920178173Simp	struct mii_data		*mii;
921178173Simp	struct mii_softc	*miisc;
922178173Simp	int			error;
923178173Simp
924178173Simp	sc = ifp->if_softc;
925178173Simp	KR_LOCK(sc);
926178173Simp	mii = device_get_softc(sc->kr_miibus);
927221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
928221407Smarius		PHY_RESET(miisc);
929178173Simp	error = mii_mediachg(mii);
930178173Simp	KR_UNLOCK(sc);
931178173Simp
932178173Simp	return (error);
933178173Simp}
934178173Simp
935178173Simp/*
936178173Simp * Report current media status.
937178173Simp */
938178173Simpstatic void
939178173Simpkr_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
940178173Simp{
941178173Simp	struct kr_softc		*sc = ifp->if_softc;
942178173Simp	struct mii_data		*mii;
943178173Simp
944178173Simp	mii = device_get_softc(sc->kr_miibus);
945178173Simp	KR_LOCK(sc);
946178173Simp	mii_pollstat(mii);
947178173Simp	ifmr->ifm_active = mii->mii_media_active;
948178173Simp	ifmr->ifm_status = mii->mii_media_status;
949226478Syongari	KR_UNLOCK(sc);
950178173Simp}
951178173Simp
952178173Simpstruct kr_dmamap_arg {
953178173Simp	bus_addr_t	kr_busaddr;
954178173Simp};
955178173Simp
956178173Simpstatic void
957178173Simpkr_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
958178173Simp{
959178173Simp	struct kr_dmamap_arg	*ctx;
960178173Simp
961178173Simp	if (error != 0)
962178173Simp		return;
963178173Simp	ctx = arg;
964178173Simp	ctx->kr_busaddr = segs[0].ds_addr;
965178173Simp}
966178173Simp
967178173Simpstatic int
968178173Simpkr_dma_alloc(struct kr_softc *sc)
969178173Simp{
970178173Simp	struct kr_dmamap_arg	ctx;
971178173Simp	struct kr_txdesc	*txd;
972178173Simp	struct kr_rxdesc	*rxd;
973178173Simp	int			error, i;
974178173Simp
975178173Simp	/* Create parent DMA tag. */
976178173Simp	error = bus_dma_tag_create(
977178173Simp	    bus_get_dma_tag(sc->kr_dev),	/* parent */
978178173Simp	    1, 0,			/* alignment, boundary */
979178173Simp	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
980178173Simp	    BUS_SPACE_MAXADDR,		/* highaddr */
981178173Simp	    NULL, NULL,			/* filter, filterarg */
982178173Simp	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
983178173Simp	    0,				/* nsegments */
984178173Simp	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
985178173Simp	    0,				/* flags */
986178173Simp	    NULL, NULL,			/* lockfunc, lockarg */
987178173Simp	    &sc->kr_cdata.kr_parent_tag);
988178173Simp	if (error != 0) {
989178173Simp		device_printf(sc->kr_dev, "failed to create parent DMA tag\n");
990178173Simp		goto fail;
991178173Simp	}
992178173Simp	/* Create tag for Tx ring. */
993178173Simp	error = bus_dma_tag_create(
994178173Simp	    sc->kr_cdata.kr_parent_tag,	/* parent */
995178173Simp	    KR_RING_ALIGN, 0,		/* alignment, boundary */
996178173Simp	    BUS_SPACE_MAXADDR,		/* lowaddr */
997178173Simp	    BUS_SPACE_MAXADDR,		/* highaddr */
998178173Simp	    NULL, NULL,			/* filter, filterarg */
999178173Simp	    KR_TX_RING_SIZE,		/* maxsize */
1000178173Simp	    1,				/* nsegments */
1001178173Simp	    KR_TX_RING_SIZE,		/* maxsegsize */
1002178173Simp	    0,				/* flags */
1003178173Simp	    NULL, NULL,			/* lockfunc, lockarg */
1004178173Simp	    &sc->kr_cdata.kr_tx_ring_tag);
1005178173Simp	if (error != 0) {
1006178173Simp		device_printf(sc->kr_dev, "failed to create Tx ring DMA tag\n");
1007178173Simp		goto fail;
1008178173Simp	}
1009178173Simp
1010178173Simp	/* Create tag for Rx ring. */
1011178173Simp	error = bus_dma_tag_create(
1012178173Simp	    sc->kr_cdata.kr_parent_tag,	/* parent */
1013178173Simp	    KR_RING_ALIGN, 0,		/* alignment, boundary */
1014178173Simp	    BUS_SPACE_MAXADDR,		/* lowaddr */
1015178173Simp	    BUS_SPACE_MAXADDR,		/* highaddr */
1016178173Simp	    NULL, NULL,			/* filter, filterarg */
1017178173Simp	    KR_RX_RING_SIZE,		/* maxsize */
1018178173Simp	    1,				/* nsegments */
1019178173Simp	    KR_RX_RING_SIZE,		/* maxsegsize */
1020178173Simp	    0,				/* flags */
1021178173Simp	    NULL, NULL,			/* lockfunc, lockarg */
1022178173Simp	    &sc->kr_cdata.kr_rx_ring_tag);
1023178173Simp	if (error != 0) {
1024178173Simp		device_printf(sc->kr_dev, "failed to create Rx ring DMA tag\n");
1025178173Simp		goto fail;
1026178173Simp	}
1027178173Simp
1028178173Simp	/* Create tag for Tx buffers. */
1029178173Simp	error = bus_dma_tag_create(
1030178173Simp	    sc->kr_cdata.kr_parent_tag,	/* parent */
1031178173Simp	    sizeof(uint32_t), 0,	/* alignment, boundary */
1032178173Simp	    BUS_SPACE_MAXADDR,		/* lowaddr */
1033178173Simp	    BUS_SPACE_MAXADDR,		/* highaddr */
1034178173Simp	    NULL, NULL,			/* filter, filterarg */
1035178173Simp	    MCLBYTES * KR_MAXFRAGS,	/* maxsize */
1036178173Simp	    KR_MAXFRAGS,		/* nsegments */
1037178173Simp	    MCLBYTES,			/* maxsegsize */
1038178173Simp	    0,				/* flags */
1039178173Simp	    NULL, NULL,			/* lockfunc, lockarg */
1040178173Simp	    &sc->kr_cdata.kr_tx_tag);
1041178173Simp	if (error != 0) {
1042178173Simp		device_printf(sc->kr_dev, "failed to create Tx DMA tag\n");
1043178173Simp		goto fail;
1044178173Simp	}
1045178173Simp
1046178173Simp	/* Create tag for Rx buffers. */
1047178173Simp	error = bus_dma_tag_create(
1048178173Simp	    sc->kr_cdata.kr_parent_tag,	/* parent */
1049178173Simp	    KR_RX_ALIGN, 0,		/* alignment, boundary */
1050178173Simp	    BUS_SPACE_MAXADDR,		/* lowaddr */
1051178173Simp	    BUS_SPACE_MAXADDR,		/* highaddr */
1052178173Simp	    NULL, NULL,			/* filter, filterarg */
1053178173Simp	    MCLBYTES,			/* maxsize */
1054178173Simp	    1,				/* nsegments */
1055178173Simp	    MCLBYTES,			/* maxsegsize */
1056178173Simp	    0,				/* flags */
1057178173Simp	    NULL, NULL,			/* lockfunc, lockarg */
1058178173Simp	    &sc->kr_cdata.kr_rx_tag);
1059178173Simp	if (error != 0) {
1060178173Simp		device_printf(sc->kr_dev, "failed to create Rx DMA tag\n");
1061178173Simp		goto fail;
1062178173Simp	}
1063178173Simp
1064178173Simp	/* Allocate DMA'able memory and load the DMA map for Tx ring. */
1065178173Simp	error = bus_dmamem_alloc(sc->kr_cdata.kr_tx_ring_tag,
1066178173Simp	    (void **)&sc->kr_rdata.kr_tx_ring, BUS_DMA_WAITOK |
1067178173Simp	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->kr_cdata.kr_tx_ring_map);
1068178173Simp	if (error != 0) {
1069178173Simp		device_printf(sc->kr_dev,
1070178173Simp		    "failed to allocate DMA'able memory for Tx ring\n");
1071178173Simp		goto fail;
1072178173Simp	}
1073178173Simp
1074178173Simp	ctx.kr_busaddr = 0;
1075178173Simp	error = bus_dmamap_load(sc->kr_cdata.kr_tx_ring_tag,
1076178173Simp	    sc->kr_cdata.kr_tx_ring_map, sc->kr_rdata.kr_tx_ring,
1077178173Simp	    KR_TX_RING_SIZE, kr_dmamap_cb, &ctx, 0);
1078178173Simp	if (error != 0 || ctx.kr_busaddr == 0) {
1079178173Simp		device_printf(sc->kr_dev,
1080178173Simp		    "failed to load DMA'able memory for Tx ring\n");
1081178173Simp		goto fail;
1082178173Simp	}
1083178173Simp	sc->kr_rdata.kr_tx_ring_paddr = ctx.kr_busaddr;
1084178173Simp
1085178173Simp	/* Allocate DMA'able memory and load the DMA map for Rx ring. */
1086178173Simp	error = bus_dmamem_alloc(sc->kr_cdata.kr_rx_ring_tag,
1087178173Simp	    (void **)&sc->kr_rdata.kr_rx_ring, BUS_DMA_WAITOK |
1088178173Simp	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->kr_cdata.kr_rx_ring_map);
1089178173Simp	if (error != 0) {
1090178173Simp		device_printf(sc->kr_dev,
1091178173Simp		    "failed to allocate DMA'able memory for Rx ring\n");
1092178173Simp		goto fail;
1093178173Simp	}
1094178173Simp
1095178173Simp	ctx.kr_busaddr = 0;
1096178173Simp	error = bus_dmamap_load(sc->kr_cdata.kr_rx_ring_tag,
1097178173Simp	    sc->kr_cdata.kr_rx_ring_map, sc->kr_rdata.kr_rx_ring,
1098178173Simp	    KR_RX_RING_SIZE, kr_dmamap_cb, &ctx, 0);
1099178173Simp	if (error != 0 || ctx.kr_busaddr == 0) {
1100178173Simp		device_printf(sc->kr_dev,
1101178173Simp		    "failed to load DMA'able memory for Rx ring\n");
1102178173Simp		goto fail;
1103178173Simp	}
1104178173Simp	sc->kr_rdata.kr_rx_ring_paddr = ctx.kr_busaddr;
1105178173Simp
1106178173Simp	/* Create DMA maps for Tx buffers. */
1107178173Simp	for (i = 0; i < KR_TX_RING_CNT; i++) {
1108178173Simp		txd = &sc->kr_cdata.kr_txdesc[i];
1109178173Simp		txd->tx_m = NULL;
1110178173Simp		txd->tx_dmamap = NULL;
1111178173Simp		error = bus_dmamap_create(sc->kr_cdata.kr_tx_tag, 0,
1112178173Simp		    &txd->tx_dmamap);
1113178173Simp		if (error != 0) {
1114178173Simp			device_printf(sc->kr_dev,
1115178173Simp			    "failed to create Tx dmamap\n");
1116178173Simp			goto fail;
1117178173Simp		}
1118178173Simp	}
1119178173Simp	/* Create DMA maps for Rx buffers. */
1120178173Simp	if ((error = bus_dmamap_create(sc->kr_cdata.kr_rx_tag, 0,
1121178173Simp	    &sc->kr_cdata.kr_rx_sparemap)) != 0) {
1122178173Simp		device_printf(sc->kr_dev,
1123178173Simp		    "failed to create spare Rx dmamap\n");
1124178173Simp		goto fail;
1125178173Simp	}
1126178173Simp	for (i = 0; i < KR_RX_RING_CNT; i++) {
1127178173Simp		rxd = &sc->kr_cdata.kr_rxdesc[i];
1128178173Simp		rxd->rx_m = NULL;
1129178173Simp		rxd->rx_dmamap = NULL;
1130178173Simp		error = bus_dmamap_create(sc->kr_cdata.kr_rx_tag, 0,
1131178173Simp		    &rxd->rx_dmamap);
1132178173Simp		if (error != 0) {
1133178173Simp			device_printf(sc->kr_dev,
1134178173Simp			    "failed to create Rx dmamap\n");
1135178173Simp			goto fail;
1136178173Simp		}
1137178173Simp	}
1138178173Simp
1139178173Simpfail:
1140178173Simp	return (error);
1141178173Simp}
1142178173Simp
1143178173Simpstatic void
1144178173Simpkr_dma_free(struct kr_softc *sc)
1145178173Simp{
1146178173Simp	struct kr_txdesc	*txd;
1147178173Simp	struct kr_rxdesc	*rxd;
1148178173Simp	int			i;
1149178173Simp
1150178173Simp	/* Tx ring. */
1151178173Simp	if (sc->kr_cdata.kr_tx_ring_tag) {
1152267363Sjhb		if (sc->kr_rdata.kr_tx_ring_paddr)
1153178173Simp			bus_dmamap_unload(sc->kr_cdata.kr_tx_ring_tag,
1154178173Simp			    sc->kr_cdata.kr_tx_ring_map);
1155267363Sjhb		if (sc->kr_rdata.kr_tx_ring)
1156178173Simp			bus_dmamem_free(sc->kr_cdata.kr_tx_ring_tag,
1157178173Simp			    sc->kr_rdata.kr_tx_ring,
1158178173Simp			    sc->kr_cdata.kr_tx_ring_map);
1159178173Simp		sc->kr_rdata.kr_tx_ring = NULL;
1160267363Sjhb		sc->kr_rdata.kr_tx_ring_paddr = 0;
1161178173Simp		bus_dma_tag_destroy(sc->kr_cdata.kr_tx_ring_tag);
1162178173Simp		sc->kr_cdata.kr_tx_ring_tag = NULL;
1163178173Simp	}
1164178173Simp	/* Rx ring. */
1165178173Simp	if (sc->kr_cdata.kr_rx_ring_tag) {
1166267363Sjhb		if (sc->kr_rdata.kr_rx_ring_paddr)
1167178173Simp			bus_dmamap_unload(sc->kr_cdata.kr_rx_ring_tag,
1168178173Simp			    sc->kr_cdata.kr_rx_ring_map);
1169267363Sjhb		if (sc->kr_rdata.kr_rx_ring)
1170178173Simp			bus_dmamem_free(sc->kr_cdata.kr_rx_ring_tag,
1171178173Simp			    sc->kr_rdata.kr_rx_ring,
1172178173Simp			    sc->kr_cdata.kr_rx_ring_map);
1173178173Simp		sc->kr_rdata.kr_rx_ring = NULL;
1174267363Sjhb		sc->kr_rdata.kr_rx_ring_paddr = 0;
1175178173Simp		bus_dma_tag_destroy(sc->kr_cdata.kr_rx_ring_tag);
1176178173Simp		sc->kr_cdata.kr_rx_ring_tag = NULL;
1177178173Simp	}
1178178173Simp	/* Tx buffers. */
1179178173Simp	if (sc->kr_cdata.kr_tx_tag) {
1180178173Simp		for (i = 0; i < KR_TX_RING_CNT; i++) {
1181178173Simp			txd = &sc->kr_cdata.kr_txdesc[i];
1182178173Simp			if (txd->tx_dmamap) {
1183178173Simp				bus_dmamap_destroy(sc->kr_cdata.kr_tx_tag,
1184178173Simp				    txd->tx_dmamap);
1185178173Simp				txd->tx_dmamap = NULL;
1186178173Simp			}
1187178173Simp		}
1188178173Simp		bus_dma_tag_destroy(sc->kr_cdata.kr_tx_tag);
1189178173Simp		sc->kr_cdata.kr_tx_tag = NULL;
1190178173Simp	}
1191178173Simp	/* Rx buffers. */
1192178173Simp	if (sc->kr_cdata.kr_rx_tag) {
1193178173Simp		for (i = 0; i < KR_RX_RING_CNT; i++) {
1194178173Simp			rxd = &sc->kr_cdata.kr_rxdesc[i];
1195178173Simp			if (rxd->rx_dmamap) {
1196178173Simp				bus_dmamap_destroy(sc->kr_cdata.kr_rx_tag,
1197178173Simp				    rxd->rx_dmamap);
1198178173Simp				rxd->rx_dmamap = NULL;
1199178173Simp			}
1200178173Simp		}
1201178173Simp		if (sc->kr_cdata.kr_rx_sparemap) {
1202178173Simp			bus_dmamap_destroy(sc->kr_cdata.kr_rx_tag,
1203178173Simp			    sc->kr_cdata.kr_rx_sparemap);
1204178173Simp			sc->kr_cdata.kr_rx_sparemap = 0;
1205178173Simp		}
1206178173Simp		bus_dma_tag_destroy(sc->kr_cdata.kr_rx_tag);
1207178173Simp		sc->kr_cdata.kr_rx_tag = NULL;
1208178173Simp	}
1209178173Simp
1210178173Simp	if (sc->kr_cdata.kr_parent_tag) {
1211178173Simp		bus_dma_tag_destroy(sc->kr_cdata.kr_parent_tag);
1212178173Simp		sc->kr_cdata.kr_parent_tag = NULL;
1213178173Simp	}
1214178173Simp}
1215178173Simp
1216178173Simp/*
1217178173Simp * Initialize the transmit descriptors.
1218178173Simp */
1219178173Simpstatic int
1220178173Simpkr_tx_ring_init(struct kr_softc *sc)
1221178173Simp{
1222178173Simp	struct kr_ring_data	*rd;
1223178173Simp	struct kr_txdesc	*txd;
1224178173Simp	bus_addr_t		addr;
1225178173Simp	int			i;
1226178173Simp
1227178173Simp	sc->kr_cdata.kr_tx_prod = 0;
1228178173Simp	sc->kr_cdata.kr_tx_cons = 0;
1229178173Simp	sc->kr_cdata.kr_tx_cnt = 0;
1230178173Simp	sc->kr_cdata.kr_tx_pkts = 0;
1231178173Simp
1232178173Simp	rd = &sc->kr_rdata;
1233178173Simp	bzero(rd->kr_tx_ring, KR_TX_RING_SIZE);
1234178173Simp	for (i = 0; i < KR_TX_RING_CNT; i++) {
1235178173Simp		if (i == KR_TX_RING_CNT - 1)
1236178173Simp			addr = KR_TX_RING_ADDR(sc, 0);
1237178173Simp		else
1238178173Simp			addr = KR_TX_RING_ADDR(sc, i + 1);
1239178173Simp		rd->kr_tx_ring[i].kr_ctl = KR_CTL_IOF;
1240178173Simp		rd->kr_tx_ring[i].kr_ca = 0;
1241178173Simp		rd->kr_tx_ring[i].kr_devcs = 0;
1242178173Simp		rd->kr_tx_ring[i].kr_link = 0;
1243178173Simp		txd = &sc->kr_cdata.kr_txdesc[i];
1244178173Simp		txd->tx_m = NULL;
1245178173Simp	}
1246178173Simp
1247178173Simp	bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
1248178173Simp	    sc->kr_cdata.kr_tx_ring_map,
1249178173Simp	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1250178173Simp
1251178173Simp	return (0);
1252178173Simp}
1253178173Simp
1254178173Simp/*
1255178173Simp * Initialize the RX descriptors and allocate mbufs for them. Note that
1256178173Simp * we arrange the descriptors in a closed ring, so that the last descriptor
1257178173Simp * points back to the first.
1258178173Simp */
1259178173Simpstatic int
1260178173Simpkr_rx_ring_init(struct kr_softc *sc)
1261178173Simp{
1262178173Simp	struct kr_ring_data	*rd;
1263178173Simp	struct kr_rxdesc	*rxd;
1264178173Simp	bus_addr_t		addr;
1265178173Simp	int			i;
1266178173Simp
1267178173Simp	sc->kr_cdata.kr_rx_cons = 0;
1268178173Simp
1269178173Simp	rd = &sc->kr_rdata;
1270178173Simp	bzero(rd->kr_rx_ring, KR_RX_RING_SIZE);
1271178173Simp	for (i = 0; i < KR_RX_RING_CNT; i++) {
1272178173Simp		rxd = &sc->kr_cdata.kr_rxdesc[i];
1273178173Simp		rxd->rx_m = NULL;
1274178173Simp		rxd->desc = &rd->kr_rx_ring[i];
1275178173Simp		if (i == KR_RX_RING_CNT - 1)
1276178173Simp			addr = KR_RX_RING_ADDR(sc, 0);
1277178173Simp		else
1278178173Simp			addr = KR_RX_RING_ADDR(sc, i + 1);
1279178173Simp		rd->kr_rx_ring[i].kr_ctl = KR_CTL_IOD;
1280178173Simp		if (i == KR_RX_RING_CNT - 1)
1281178173Simp			rd->kr_rx_ring[i].kr_ctl |= KR_CTL_COD;
1282178173Simp		rd->kr_rx_ring[i].kr_devcs = 0;
1283178173Simp		rd->kr_rx_ring[i].kr_ca = 0;
1284178173Simp		rd->kr_rx_ring[i].kr_link = addr;
1285178173Simp		if (kr_newbuf(sc, i) != 0)
1286178173Simp			return (ENOBUFS);
1287178173Simp	}
1288178173Simp
1289178173Simp	bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
1290178173Simp	    sc->kr_cdata.kr_rx_ring_map,
1291178173Simp	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1292178173Simp
1293178173Simp	return (0);
1294178173Simp}
1295178173Simp
1296178173Simp/*
1297178173Simp * Initialize an RX descriptor and attach an MBUF cluster.
1298178173Simp */
1299178173Simpstatic int
1300178173Simpkr_newbuf(struct kr_softc *sc, int idx)
1301178173Simp{
1302178173Simp	struct kr_desc		*desc;
1303178173Simp	struct kr_rxdesc	*rxd;
1304178173Simp	struct mbuf		*m;
1305178173Simp	bus_dma_segment_t	segs[1];
1306178173Simp	bus_dmamap_t		map;
1307178173Simp	int			nsegs;
1308178173Simp
1309243882Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1310178173Simp	if (m == NULL)
1311178173Simp		return (ENOBUFS);
1312178173Simp	m->m_len = m->m_pkthdr.len = MCLBYTES;
1313178173Simp	m_adj(m, sizeof(uint64_t));
1314178173Simp
1315178173Simp	if (bus_dmamap_load_mbuf_sg(sc->kr_cdata.kr_rx_tag,
1316178173Simp	    sc->kr_cdata.kr_rx_sparemap, m, segs, &nsegs, 0) != 0) {
1317178173Simp		m_freem(m);
1318178173Simp		return (ENOBUFS);
1319178173Simp	}
1320178173Simp	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1321178173Simp
1322178173Simp	rxd = &sc->kr_cdata.kr_rxdesc[idx];
1323178173Simp	if (rxd->rx_m != NULL) {
1324178173Simp		bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap,
1325178173Simp		    BUS_DMASYNC_POSTREAD);
1326178173Simp		bus_dmamap_unload(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap);
1327178173Simp	}
1328178173Simp	map = rxd->rx_dmamap;
1329178173Simp	rxd->rx_dmamap = sc->kr_cdata.kr_rx_sparemap;
1330178173Simp	sc->kr_cdata.kr_rx_sparemap = map;
1331178173Simp	bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap,
1332178173Simp	    BUS_DMASYNC_PREREAD);
1333178173Simp	rxd->rx_m = m;
1334178173Simp	desc = rxd->desc;
1335178173Simp	desc->kr_ca = segs[0].ds_addr;
1336178173Simp	desc->kr_ctl |= KR_DMASIZE(segs[0].ds_len);
1337178173Simp	rxd->saved_ca = desc->kr_ca ;
1338178173Simp	rxd->saved_ctl = desc->kr_ctl ;
1339178173Simp
1340178173Simp	return (0);
1341178173Simp}
1342178173Simp
1343178173Simpstatic __inline void
1344178173Simpkr_fixup_rx(struct mbuf *m)
1345178173Simp{
1346178173Simp        int		i;
1347178173Simp        uint16_t	*src, *dst;
1348178173Simp
1349178173Simp	src = mtod(m, uint16_t *);
1350178173Simp	dst = src - 1;
1351178173Simp
1352178173Simp	for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
1353178173Simp		*dst++ = *src++;
1354178173Simp
1355178173Simp	m->m_data -= ETHER_ALIGN;
1356178173Simp}
1357178173Simp
1358178173Simp
1359178173Simpstatic void
1360178173Simpkr_tx(struct kr_softc *sc)
1361178173Simp{
1362178173Simp	struct kr_txdesc	*txd;
1363178173Simp	struct kr_desc		*cur_tx;
1364178173Simp	struct ifnet		*ifp;
1365178173Simp	uint32_t		ctl, devcs;
1366178173Simp	int			cons, prod;
1367178173Simp
1368178173Simp	KR_LOCK_ASSERT(sc);
1369178173Simp
1370178173Simp	cons = sc->kr_cdata.kr_tx_cons;
1371178173Simp	prod = sc->kr_cdata.kr_tx_prod;
1372178173Simp	if (cons == prod)
1373178173Simp		return;
1374178173Simp
1375178173Simp	bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
1376178173Simp	    sc->kr_cdata.kr_tx_ring_map,
1377178173Simp	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1378178173Simp
1379178173Simp	ifp = sc->kr_ifp;
1380178173Simp	/*
1381178173Simp	 * Go through our tx list and free mbufs for those
1382178173Simp	 * frames that have been transmitted.
1383178173Simp	 */
1384178173Simp	for (; cons != prod; KR_INC(cons, KR_TX_RING_CNT)) {
1385178173Simp		cur_tx = &sc->kr_rdata.kr_tx_ring[cons];
1386178173Simp		ctl = cur_tx->kr_ctl;
1387178173Simp		devcs = cur_tx->kr_devcs;
1388178173Simp		/* Check if descriptor has "finished" flag */
1389178173Simp		if ((ctl & KR_CTL_F) == 0)
1390178173Simp			break;
1391178173Simp
1392178173Simp		sc->kr_cdata.kr_tx_cnt--;
1393178173Simp		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1394178173Simp
1395178173Simp		txd = &sc->kr_cdata.kr_txdesc[cons];
1396178173Simp
1397178173Simp		if (devcs & KR_DMATX_DEVCS_TOK)
1398271858Sglebius			if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
1399178173Simp		else {
1400271858Sglebius			if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1401178173Simp			/* collisions: medium busy, late collision */
1402178173Simp			if ((devcs & KR_DMATX_DEVCS_EC) ||
1403178173Simp			    (devcs & KR_DMATX_DEVCS_LC))
1404271858Sglebius				if_inc_counter(ifp, IFCOUNTER_COLLISIONS, 1);
1405178173Simp		}
1406178173Simp
1407178173Simp		bus_dmamap_sync(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap,
1408178173Simp		    BUS_DMASYNC_POSTWRITE);
1409178173Simp		bus_dmamap_unload(sc->kr_cdata.kr_tx_tag, txd->tx_dmamap);
1410178173Simp
1411178173Simp		/* Free only if it's first descriptor in list */
1412178173Simp		if (txd->tx_m)
1413178173Simp			m_freem(txd->tx_m);
1414178173Simp		txd->tx_m = NULL;
1415178173Simp
1416178173Simp		/* reset descriptor */
1417178173Simp		cur_tx->kr_ctl = KR_CTL_IOF;
1418178173Simp		cur_tx->kr_devcs = 0;
1419178173Simp		cur_tx->kr_ca = 0;
1420178173Simp		cur_tx->kr_link = 0;
1421178173Simp	}
1422178173Simp
1423178173Simp	sc->kr_cdata.kr_tx_cons = cons;
1424178173Simp
1425178173Simp	bus_dmamap_sync(sc->kr_cdata.kr_tx_ring_tag,
1426178173Simp	    sc->kr_cdata.kr_tx_ring_map, BUS_DMASYNC_PREWRITE);
1427178173Simp}
1428178173Simp
1429178173Simp
1430178173Simpstatic void
1431178173Simpkr_rx(struct kr_softc *sc)
1432178173Simp{
1433178173Simp	struct kr_rxdesc	*rxd;
1434178173Simp	struct ifnet		*ifp = sc->kr_ifp;
1435178173Simp	int			cons, prog, packet_len, count, error;
1436178173Simp	struct kr_desc		*cur_rx;
1437178173Simp	struct mbuf		*m;
1438178173Simp
1439178173Simp	KR_LOCK_ASSERT(sc);
1440178173Simp
1441178173Simp	cons = sc->kr_cdata.kr_rx_cons;
1442178173Simp
1443178173Simp	bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
1444178173Simp	    sc->kr_cdata.kr_rx_ring_map,
1445178173Simp	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1446178173Simp
1447178173Simp	for (prog = 0; prog < KR_RX_RING_CNT; KR_INC(cons, KR_RX_RING_CNT)) {
1448178173Simp		cur_rx = &sc->kr_rdata.kr_rx_ring[cons];
1449178173Simp		rxd = &sc->kr_cdata.kr_rxdesc[cons];
1450178173Simp		m = rxd->rx_m;
1451178173Simp
1452178173Simp		if ((cur_rx->kr_ctl & KR_CTL_D) == 0)
1453178173Simp		       break;
1454178173Simp
1455178173Simp		prog++;
1456178173Simp
1457178173Simp		packet_len = KR_PKTSIZE(cur_rx->kr_devcs);
1458178173Simp		count = m->m_len - KR_DMASIZE(cur_rx->kr_ctl);
1459178173Simp		/* Assume it's error */
1460178173Simp		error = 1;
1461178173Simp
1462178173Simp		if (packet_len != count)
1463271858Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1464178173Simp		else if (count < 64)
1465271858Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1466178173Simp		else if ((cur_rx->kr_devcs & KR_DMARX_DEVCS_LD) == 0)
1467271858Sglebius			if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
1468178173Simp		else if ((cur_rx->kr_devcs & KR_DMARX_DEVCS_ROK) != 0) {
1469178173Simp			error = 0;
1470178173Simp			bus_dmamap_sync(sc->kr_cdata.kr_rx_tag, rxd->rx_dmamap,
1471178173Simp			    BUS_DMASYNC_PREREAD);
1472178173Simp			m = rxd->rx_m;
1473178173Simp			kr_fixup_rx(m);
1474178173Simp			m->m_pkthdr.rcvif = ifp;
1475178173Simp			/* Skip 4 bytes of CRC */
1476178173Simp			m->m_pkthdr.len = m->m_len = packet_len - ETHER_CRC_LEN;
1477271858Sglebius			if_inc_counter(ifp, IFCOUNTER_IPACKETS, 1);
1478178173Simp
1479178173Simp			KR_UNLOCK(sc);
1480178173Simp			(*ifp->if_input)(ifp, m);
1481178173Simp			KR_LOCK(sc);
1482178173Simp		}
1483178173Simp
1484178173Simp		if (error) {
1485178173Simp			/* Restore CONTROL and CA values, reset DEVCS */
1486178173Simp			cur_rx->kr_ctl = rxd->saved_ctl;
1487178173Simp			cur_rx->kr_ca = rxd->saved_ca;
1488178173Simp			cur_rx->kr_devcs = 0;
1489178173Simp		}
1490178173Simp		else {
1491178173Simp			/* Reinit descriptor */
1492178173Simp			cur_rx->kr_ctl = KR_CTL_IOD;
1493178173Simp			if (cons == KR_RX_RING_CNT - 1)
1494178173Simp				cur_rx->kr_ctl |= KR_CTL_COD;
1495178173Simp			cur_rx->kr_devcs = 0;
1496178173Simp			cur_rx->kr_ca = 0;
1497178173Simp			if (kr_newbuf(sc, cons) != 0) {
1498178173Simp				device_printf(sc->kr_dev,
1499178173Simp				    "Failed to allocate buffer\n");
1500178173Simp				break;
1501178173Simp			}
1502178173Simp		}
1503178173Simp
1504178173Simp		bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
1505178173Simp		    sc->kr_cdata.kr_rx_ring_map,
1506178173Simp		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1507178173Simp
1508178173Simp	}
1509178173Simp
1510178173Simp	if (prog > 0) {
1511178173Simp		sc->kr_cdata.kr_rx_cons = cons;
1512178173Simp
1513178173Simp		bus_dmamap_sync(sc->kr_cdata.kr_rx_ring_tag,
1514178173Simp		    sc->kr_cdata.kr_rx_ring_map,
1515178173Simp		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1516178173Simp	}
1517178173Simp}
1518178173Simp
1519178173Simpstatic void
1520178173Simpkr_rx_intr(void *arg)
1521178173Simp{
1522178173Simp	struct kr_softc		*sc = arg;
1523178173Simp	uint32_t		status;
1524178173Simp
1525178173Simp	KR_LOCK(sc);
1526178173Simp
1527178173Simp	/* mask out interrupts */
1528178173Simp	KR_DMA_SETBITS_REG(KR_DMA_RXCHAN, DMA_SM,
1529178173Simp	    DMA_SM_D | DMA_SM_H | DMA_SM_E);
1530178173Simp
1531178173Simp	status = KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S);
1532178173Simp	if (status & (DMA_S_D | DMA_S_E | DMA_S_H)) {
1533178173Simp		kr_rx(sc);
1534178173Simp
1535178173Simp		if (status & DMA_S_E)
1536178173Simp			device_printf(sc->kr_dev, "RX DMA error\n");
1537178173Simp	}
1538178173Simp
1539178173Simp	/* Reread status */
1540178173Simp	status = KR_DMA_READ_REG(KR_DMA_RXCHAN, DMA_S);
1541178173Simp
1542178173Simp	/* restart DMA RX  if it has been halted */
1543178173Simp	if (status & DMA_S_H) {
1544178173Simp		KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_DPTR,
1545178173Simp		    KR_RX_RING_ADDR(sc, sc->kr_cdata.kr_rx_cons));
1546178173Simp	}
1547178173Simp
1548178173Simp	KR_DMA_WRITE_REG(KR_DMA_RXCHAN, DMA_S, ~status);
1549178173Simp
1550178173Simp	/* Enable F, H, E interrupts */
1551178173Simp	KR_DMA_CLEARBITS_REG(KR_DMA_RXCHAN, DMA_SM,
1552178173Simp	    DMA_SM_D | DMA_SM_H | DMA_SM_E);
1553178173Simp
1554178173Simp	KR_UNLOCK(sc);
1555178173Simp}
1556178173Simp
1557178173Simpstatic void
1558178173Simpkr_tx_intr(void *arg)
1559178173Simp{
1560178173Simp	struct kr_softc		*sc = arg;
1561178173Simp	uint32_t		status;
1562178173Simp
1563178173Simp	KR_LOCK(sc);
1564178173Simp
1565178173Simp	/* mask out interrupts */
1566178173Simp	KR_DMA_SETBITS_REG(KR_DMA_TXCHAN, DMA_SM,
1567178173Simp	    DMA_SM_F | DMA_SM_E);
1568178173Simp
1569178173Simp	status = KR_DMA_READ_REG(KR_DMA_TXCHAN, DMA_S);
1570178173Simp	if (status & (DMA_S_F | DMA_S_E)) {
1571178173Simp		kr_tx(sc);
1572178173Simp		if (status & DMA_S_E)
1573178173Simp			device_printf(sc->kr_dev, "DMA error\n");
1574178173Simp	}
1575178173Simp
1576178173Simp	KR_DMA_WRITE_REG(KR_DMA_TXCHAN, DMA_S, ~status);
1577178173Simp
1578178173Simp	/* Enable F, E interrupts */
1579178173Simp	KR_DMA_CLEARBITS_REG(KR_DMA_TXCHAN, DMA_SM,
1580178173Simp	    DMA_SM_F | DMA_SM_E);
1581178173Simp
1582178173Simp	KR_UNLOCK(sc);
1583178173Simp
1584178173Simp}
1585178173Simp
1586178173Simpstatic void
1587178173Simpkr_rx_und_intr(void *arg)
1588178173Simp{
1589178173Simp
1590178173Simp	panic("interrupt: %s\n", __func__);
1591178173Simp}
1592178173Simp
1593178173Simpstatic void
1594178173Simpkr_tx_ovr_intr(void *arg)
1595178173Simp{
1596178173Simp
1597178173Simp	panic("interrupt: %s\n", __func__);
1598178173Simp}
1599178173Simp
1600178173Simpstatic void
1601178173Simpkr_tick(void *xsc)
1602178173Simp{
1603178173Simp	struct kr_softc		*sc = xsc;
1604178173Simp	struct mii_data		*mii;
1605178173Simp
1606178173Simp	KR_LOCK_ASSERT(sc);
1607178173Simp
1608178173Simp	mii = device_get_softc(sc->kr_miibus);
1609178173Simp	mii_tick(mii);
1610178173Simp	callout_reset(&sc->kr_stat_callout, hz, kr_tick, sc);
1611178173Simp}
1612