1139749Simp/*-
2116491Sharti * Copyright (c) 2001-2003
3116491Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4116491Sharti * 	All rights reserved.
5116491Sharti *
6116491Sharti * Redistribution and use in source and binary forms, with or without
7116491Sharti * modification, are permitted provided that the following conditions
8116491Sharti * are met:
9116491Sharti * 1. Redistributions of source code must retain the above copyright
10116491Sharti *    notice, this list of conditions and the following disclaimer.
11116491Sharti * 2. Redistributions in binary form must reproduce the above copyright
12116491Sharti *    notice, this list of conditions and the following disclaimer in the
13116491Sharti *    documentation and/or other materials provided with the distribution.
14116491Sharti *
15116491Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16116491Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17116491Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18116491Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19116491Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20116491Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21116491Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22116491Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23116491Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24116491Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25116491Sharti * SUCH DAMAGE.
26116491Sharti *
27116491Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28116491Sharti *
29116491Sharti * ForeHE driver.
30116491Sharti *
31116491Sharti * This file contains the module and driver infrastructure stuff as well
32116491Sharti * as a couple of utility functions and the entire initialisation.
33116491Sharti */
34116519Sharti
35116519Sharti#include <sys/cdefs.h>
36116519Sharti__FBSDID("$FreeBSD$");
37116519Sharti
38116491Sharti#include "opt_inet.h"
39116491Sharti#include "opt_natm.h"
40116491Sharti
41116491Sharti#include <sys/types.h>
42116491Sharti#include <sys/param.h>
43116491Sharti#include <sys/systm.h>
44116491Sharti#include <sys/malloc.h>
45116491Sharti#include <sys/kernel.h>
46116491Sharti#include <sys/bus.h>
47116491Sharti#include <sys/errno.h>
48116491Sharti#include <sys/conf.h>
49116491Sharti#include <sys/module.h>
50116491Sharti#include <sys/queue.h>
51116491Sharti#include <sys/syslog.h>
52116491Sharti#include <sys/lock.h>
53116491Sharti#include <sys/mutex.h>
54116491Sharti#include <sys/condvar.h>
55116491Sharti#include <sys/sysctl.h>
56116491Sharti#include <vm/uma.h>
57116491Sharti
58116491Sharti#include <sys/sockio.h>
59116491Sharti#include <sys/mbuf.h>
60116491Sharti#include <sys/socket.h>
61116491Sharti
62116491Sharti#include <net/if.h>
63116491Sharti#include <net/if_media.h>
64116491Sharti#include <net/if_atm.h>
65147256Sbrooks#include <net/if_types.h>
66116491Sharti#include <net/route.h>
67116491Sharti#ifdef ENABLE_BPF
68116491Sharti#include <net/bpf.h>
69116491Sharti#endif
70116491Sharti#include <netinet/in.h>
71116491Sharti#include <netinet/if_atm.h>
72116491Sharti
73116491Sharti#include <machine/bus.h>
74116491Sharti#include <machine/resource.h>
75116491Sharti#include <sys/bus.h>
76116491Sharti#include <sys/rman.h>
77119280Simp#include <dev/pci/pcireg.h>
78119280Simp#include <dev/pci/pcivar.h>
79116491Sharti
80116491Sharti#include <dev/utopia/utopia.h>
81116491Sharti#include <dev/hatm/if_hatmconf.h>
82116491Sharti#include <dev/hatm/if_hatmreg.h>
83116491Sharti#include <dev/hatm/if_hatmvar.h>
84116491Sharti
85116491Shartistatic const struct {
86116491Sharti	uint16_t	vid;
87116491Sharti	uint16_t	did;
88116491Sharti	const char	*name;
89116491Sharti} hatm_devs[] = {
90116491Sharti	{ 0x1127, 0x400,
91116491Sharti	  "FORE HE" },
92116491Sharti	{ 0, 0, NULL }
93116491Sharti};
94116491Sharti
95116491ShartiSYSCTL_DECL(_hw_atm);
96116491Sharti
97116491ShartiMODULE_DEPEND(hatm, utopia, 1, 1, 1);
98116491ShartiMODULE_DEPEND(hatm, pci, 1, 1, 1);
99116491ShartiMODULE_DEPEND(hatm, atm, 1, 1, 1);
100116491Sharti
101116491Sharti#define EEPROM_DELAY	400 /* microseconds */
102116491Sharti
103116491Sharti/* Read from EEPROM 0000 0011b */
104116491Shartistatic const uint32_t readtab[] = {
105116491Sharti	HE_REGM_HOST_PROM_SEL | HE_REGM_HOST_PROM_CLOCK,
106116491Sharti	0,
107116491Sharti	HE_REGM_HOST_PROM_CLOCK,
108116491Sharti	0,				/* 0 */
109116491Sharti	HE_REGM_HOST_PROM_CLOCK,
110116491Sharti	0,				/* 0 */
111116491Sharti	HE_REGM_HOST_PROM_CLOCK,
112116491Sharti	0,				/* 0 */
113116491Sharti	HE_REGM_HOST_PROM_CLOCK,
114116491Sharti	0,				/* 0 */
115116491Sharti	HE_REGM_HOST_PROM_CLOCK,
116116491Sharti	0,				/* 0 */
117116491Sharti	HE_REGM_HOST_PROM_CLOCK,
118116491Sharti	HE_REGM_HOST_PROM_DATA_IN,	/* 0 */
119116491Sharti	HE_REGM_HOST_PROM_CLOCK | HE_REGM_HOST_PROM_DATA_IN,
120116491Sharti	HE_REGM_HOST_PROM_DATA_IN,	/* 1 */
121116491Sharti	HE_REGM_HOST_PROM_CLOCK | HE_REGM_HOST_PROM_DATA_IN,
122116491Sharti	HE_REGM_HOST_PROM_DATA_IN,	/* 1 */
123116491Sharti};
124116491Shartistatic const uint32_t clocktab[] = {
125116491Sharti	0, HE_REGM_HOST_PROM_CLOCK,
126116491Sharti	0, HE_REGM_HOST_PROM_CLOCK,
127116491Sharti	0, HE_REGM_HOST_PROM_CLOCK,
128116491Sharti	0, HE_REGM_HOST_PROM_CLOCK,
129116491Sharti	0, HE_REGM_HOST_PROM_CLOCK,
130116491Sharti	0, HE_REGM_HOST_PROM_CLOCK,
131116491Sharti	0, HE_REGM_HOST_PROM_CLOCK,
132116491Sharti	0, HE_REGM_HOST_PROM_CLOCK,
133116491Sharti	0
134116491Sharti};
135116491Sharti
136116491Sharti/*
137116491Sharti * Convert cell rate to ATM Forum format
138116491Sharti */
139116491Shartiu_int
140116491Shartihatm_cps2atmf(uint32_t pcr)
141116491Sharti{
142116491Sharti	u_int e;
143116491Sharti
144116491Sharti	if (pcr == 0)
145116491Sharti		return (0);
146116491Sharti	pcr <<= 9;
147116491Sharti	e = 0;
148116491Sharti	while (pcr > (1024 - 1)) {
149116491Sharti		e++;
150116491Sharti		pcr >>= 1;
151116491Sharti	}
152116491Sharti	return ((1 << 14) | (e << 9) | (pcr & 0x1ff));
153116491Sharti}
154116491Shartiu_int
155116491Shartihatm_atmf2cps(uint32_t fcr)
156116491Sharti{
157116491Sharti	fcr &= 0x7fff;
158116491Sharti
159116491Sharti	return ((1 << ((fcr >> 9) & 0x1f)) * (512 + (fcr & 0x1ff)) / 512
160116491Sharti	  * (fcr >> 14));
161116491Sharti}
162116491Sharti
163116491Sharti/************************************************************
164116491Sharti *
165116491Sharti * Initialisation
166116491Sharti */
167116491Sharti/*
168116491Sharti * Probe for a HE controller
169116491Sharti */
170116491Shartistatic int
171116491Shartihatm_probe(device_t dev)
172116491Sharti{
173116491Sharti	int i;
174116491Sharti
175116491Sharti	for (i = 0; hatm_devs[i].name; i++)
176116491Sharti		if (pci_get_vendor(dev) == hatm_devs[i].vid &&
177116491Sharti		    pci_get_device(dev) == hatm_devs[i].did) {
178116491Sharti			device_set_desc(dev, hatm_devs[i].name);
179143161Simp			return (BUS_PROBE_DEFAULT);
180116491Sharti		}
181116491Sharti	return (ENXIO);
182116491Sharti}
183116491Sharti
184116491Sharti/*
185116491Sharti * Allocate and map DMA-able memory. We support only contiguous mappings.
186116491Sharti */
187116491Shartistatic void
188116491Shartidmaload_helper(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
189116491Sharti{
190116491Sharti	if (error)
191116491Sharti		return;
192116491Sharti	KASSERT(nsegs == 1, ("too many segments for DMA: %d", nsegs));
193116491Sharti	KASSERT(segs[0].ds_addr <= 0xffffffffUL,
194116491Sharti	    ("phys addr too large %lx", (u_long)segs[0].ds_addr));
195116491Sharti
196116491Sharti	*(bus_addr_t *)arg = segs[0].ds_addr;
197116491Sharti}
198116491Shartistatic int
199116491Shartihatm_alloc_dmamem(struct hatm_softc *sc, const char *what, struct dmamem *mem)
200116491Sharti{
201116491Sharti	int error;
202116491Sharti
203116491Sharti	mem->base = NULL;
204116491Sharti
205116491Sharti	/*
206116491Sharti	 * Alignement does not work in the bus_dmamem_alloc function below
207116491Sharti	 * on FreeBSD. malloc seems to align objects at least to the object
208116491Sharti	 * size so increase the size to the alignment if the size is lesser
209116491Sharti	 * than the alignemnt.
210116491Sharti	 * XXX on sparc64 this is (probably) not needed.
211116491Sharti	 */
212116491Sharti	if (mem->size < mem->align)
213116491Sharti		mem->size = mem->align;
214116491Sharti
215116491Sharti	error = bus_dma_tag_create(sc->parent_tag, mem->align, 0,
216116491Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
217116491Sharti	    NULL, NULL, mem->size, 1,
218117126Sscottl	    BUS_SPACE_MAXSIZE_32BIT, BUS_DMA_ALLOCNOW,
219117382Sharti	    NULL, NULL, &mem->tag);
220116491Sharti	if (error) {
221147256Sbrooks		if_printf(sc->ifp, "DMA tag create (%s)\n", what);
222116491Sharti		return (error);
223116491Sharti	}
224116491Sharti
225116491Sharti	error = bus_dmamem_alloc(mem->tag, &mem->base, 0, &mem->map);
226116491Sharti	if (error) {
227147256Sbrooks		if_printf(sc->ifp, "DMA mem alloc (%s): %d\n",
228116491Sharti		    what, error);
229116491Sharti		bus_dma_tag_destroy(mem->tag);
230116491Sharti		mem->base = NULL;
231116491Sharti		return (error);
232116491Sharti	}
233116491Sharti
234116491Sharti	error = bus_dmamap_load(mem->tag, mem->map, mem->base, mem->size,
235117382Sharti	    dmaload_helper, &mem->paddr, BUS_DMA_NOWAIT);
236116491Sharti	if (error) {
237147256Sbrooks		if_printf(sc->ifp, "DMA map load (%s): %d\n",
238116491Sharti		    what, error);
239116491Sharti		bus_dmamem_free(mem->tag, mem->base, mem->map);
240116491Sharti		bus_dma_tag_destroy(mem->tag);
241116491Sharti		mem->base = NULL;
242116491Sharti		return (error);
243116491Sharti	}
244116491Sharti
245116491Sharti	DBG(sc, DMA, ("%s S/A/V/P 0x%x 0x%x %p 0x%lx", what, mem->size,
246116491Sharti	    mem->align, mem->base, (u_long)mem->paddr));
247116491Sharti
248116491Sharti	return (0);
249116491Sharti}
250116491Sharti
251116491Sharti/*
252116491Sharti * Destroy all the resources of an DMA-able memory region.
253116491Sharti */
254116491Shartistatic void
255116491Shartihatm_destroy_dmamem(struct dmamem *mem)
256116491Sharti{
257116491Sharti	if (mem->base != NULL) {
258116491Sharti		bus_dmamap_unload(mem->tag, mem->map);
259116491Sharti		bus_dmamem_free(mem->tag, mem->base, mem->map);
260116491Sharti		(void)bus_dma_tag_destroy(mem->tag);
261116491Sharti		mem->base = NULL;
262116491Sharti	}
263116491Sharti}
264116491Sharti
265116491Sharti/*
266116491Sharti * Initialize/destroy DMA maps for the large pool 0
267116491Sharti */
268116491Shartistatic void
269116491Shartihatm_destroy_rmaps(struct hatm_softc *sc)
270116491Sharti{
271116491Sharti	u_int b;
272116491Sharti
273116491Sharti	DBG(sc, ATTACH, ("destroying rmaps and lbuf pointers..."));
274116491Sharti	if (sc->rmaps != NULL) {
275116491Sharti		for (b = 0; b < sc->lbufs_size; b++)
276116491Sharti			bus_dmamap_destroy(sc->mbuf_tag, sc->rmaps[b]);
277116491Sharti		free(sc->rmaps, M_DEVBUF);
278116491Sharti	}
279116491Sharti	if (sc->lbufs != NULL)
280116491Sharti		free(sc->lbufs, M_DEVBUF);
281116491Sharti}
282116491Sharti
283116491Shartistatic void
284116491Shartihatm_init_rmaps(struct hatm_softc *sc)
285116491Sharti{
286116491Sharti	u_int b;
287116491Sharti	int err;
288116491Sharti
289116491Sharti	DBG(sc, ATTACH, ("allocating rmaps and lbuf pointers..."));
290116491Sharti	sc->lbufs = malloc(sizeof(sc->lbufs[0]) * sc->lbufs_size,
291116491Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
292116491Sharti
293116491Sharti	/* allocate and create the DMA maps for the large pool */
294116491Sharti	sc->rmaps = malloc(sizeof(sc->rmaps[0]) * sc->lbufs_size,
295116491Sharti	    M_DEVBUF, M_WAITOK);
296116491Sharti	for (b = 0; b < sc->lbufs_size; b++) {
297116491Sharti		err = bus_dmamap_create(sc->mbuf_tag, 0, &sc->rmaps[b]);
298116491Sharti		if (err != 0)
299116491Sharti			panic("bus_dmamap_create: %d\n", err);
300116491Sharti	}
301116491Sharti}
302116491Sharti
303116491Sharti/*
304116491Sharti * Initialize and destroy small mbuf page pointers and pages
305116491Sharti */
306116491Shartistatic void
307116491Shartihatm_destroy_smbufs(struct hatm_softc *sc)
308116491Sharti{
309116491Sharti	u_int i, b;
310116491Sharti	struct mbuf_page *pg;
311121729Sharti	struct mbuf_chunk_hdr *h;
312116491Sharti
313116491Sharti	if (sc->mbuf_pages != NULL) {
314116491Sharti		for (i = 0; i < sc->mbuf_npages; i++) {
315116491Sharti			pg = sc->mbuf_pages[i];
316116491Sharti			for (b = 0; b < pg->hdr.nchunks; b++) {
317121729Sharti				h = (struct mbuf_chunk_hdr *) ((char *)pg +
318121729Sharti				    b * pg->hdr.chunksize + pg->hdr.hdroff);
319121729Sharti				if (h->flags & MBUF_CARD)
320147256Sbrooks					if_printf(sc->ifp,
321116491Sharti					    "%s -- mbuf page=%u card buf %u\n",
322116491Sharti					    __func__, i, b);
323121729Sharti				if (h->flags & MBUF_USED)
324147256Sbrooks					if_printf(sc->ifp,
325121729Sharti					    "%s -- mbuf page=%u used buf %u\n",
326121729Sharti					    __func__, i, b);
327116491Sharti			}
328116491Sharti			bus_dmamap_unload(sc->mbuf_tag, pg->hdr.map);
329116491Sharti			bus_dmamap_destroy(sc->mbuf_tag, pg->hdr.map);
330116491Sharti			free(pg, M_DEVBUF);
331116491Sharti		}
332116491Sharti		free(sc->mbuf_pages, M_DEVBUF);
333116491Sharti	}
334116491Sharti}
335116491Sharti
336116491Shartistatic void
337116491Shartihatm_init_smbufs(struct hatm_softc *sc)
338116491Sharti{
339116491Sharti	sc->mbuf_pages = malloc(sizeof(sc->mbuf_pages[0]) *
340121685Sharti	    sc->mbuf_max_pages, M_DEVBUF, M_WAITOK);
341116491Sharti	sc->mbuf_npages = 0;
342116491Sharti}
343116491Sharti
344116491Sharti/*
345116491Sharti * Initialize/destroy TPDs. This is called from attach/detach.
346116491Sharti */
347116491Shartistatic void
348116491Shartihatm_destroy_tpds(struct hatm_softc *sc)
349116491Sharti{
350116491Sharti	struct tpd *t;
351116491Sharti
352116491Sharti	if (sc->tpds.base == NULL)
353116491Sharti		return;
354116491Sharti
355116491Sharti	DBG(sc, ATTACH, ("releasing TPDs ..."));
356116491Sharti	if (sc->tpd_nfree != sc->tpd_total)
357147256Sbrooks		if_printf(sc->ifp, "%u tpds still in use from %u\n",
358116491Sharti		    sc->tpd_total - sc->tpd_nfree, sc->tpd_total);
359116491Sharti	while ((t = SLIST_FIRST(&sc->tpd_free)) != NULL) {
360116491Sharti		SLIST_REMOVE_HEAD(&sc->tpd_free, link);
361116491Sharti		bus_dmamap_destroy(sc->tx_tag, t->map);
362116491Sharti	}
363116491Sharti	hatm_destroy_dmamem(&sc->tpds);
364116491Sharti	free(sc->tpd_used, M_DEVBUF);
365116491Sharti	DBG(sc, ATTACH, ("... done"));
366116491Sharti}
367116491Shartistatic int
368116491Shartihatm_init_tpds(struct hatm_softc *sc)
369116491Sharti{
370116491Sharti	int error;
371116491Sharti	u_int i;
372116491Sharti	struct tpd *t;
373116491Sharti
374116491Sharti	DBG(sc, ATTACH, ("allocating %u TPDs and maps ...", sc->tpd_total));
375116491Sharti	error = hatm_alloc_dmamem(sc, "TPD memory", &sc->tpds);
376116491Sharti	if (error != 0) {
377116491Sharti		DBG(sc, ATTACH, ("... dmamem error=%d", error));
378116491Sharti		return (error);
379116491Sharti	}
380116491Sharti
381116491Sharti	/* put all the TPDs on the free list and allocate DMA maps */
382116491Sharti	for (i = 0; i < sc->tpd_total; i++) {
383116491Sharti		t = TPD_ADDR(sc, i);
384116491Sharti		t->no = i;
385116491Sharti		t->mbuf = NULL;
386116491Sharti		error = bus_dmamap_create(sc->tx_tag, 0, &t->map);
387116491Sharti		if (error != 0) {
388116491Sharti			DBG(sc, ATTACH, ("... dmamap error=%d", error));
389116491Sharti			while ((t = SLIST_FIRST(&sc->tpd_free)) != NULL) {
390116491Sharti				SLIST_REMOVE_HEAD(&sc->tpd_free, link);
391116491Sharti				bus_dmamap_destroy(sc->tx_tag, t->map);
392116491Sharti			}
393116491Sharti			hatm_destroy_dmamem(&sc->tpds);
394116491Sharti			return (error);
395116491Sharti		}
396116491Sharti
397116491Sharti		SLIST_INSERT_HEAD(&sc->tpd_free, t, link);
398116491Sharti	}
399116491Sharti
400116491Sharti	/* allocate and zero bitmap */
401116491Sharti	sc->tpd_used = malloc(sizeof(uint8_t) * (sc->tpd_total + 7) / 8,
402116491Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
403116491Sharti	sc->tpd_nfree = sc->tpd_total;
404116491Sharti
405116491Sharti	DBG(sc, ATTACH, ("... done"));
406116491Sharti
407116491Sharti	return (0);
408116491Sharti}
409116491Sharti
410116491Sharti/*
411116491Sharti * Free all the TPDs that where given to the card.
412116491Sharti * An mbuf chain may be attached to a TPD - free it also and
413116491Sharti * unload its associated DMA map.
414116491Sharti */
415116491Shartistatic void
416116491Shartihatm_stop_tpds(struct hatm_softc *sc)
417116491Sharti{
418116491Sharti	u_int i;
419116491Sharti	struct tpd *t;
420116491Sharti
421116491Sharti	DBG(sc, ATTACH, ("free TPDs ..."));
422116491Sharti	for (i = 0; i < sc->tpd_total; i++) {
423116491Sharti		if (TPD_TST_USED(sc, i)) {
424116491Sharti			t = TPD_ADDR(sc, i);
425116491Sharti			if (t->mbuf) {
426116491Sharti				m_freem(t->mbuf);
427116491Sharti				t->mbuf = NULL;
428116491Sharti				bus_dmamap_unload(sc->tx_tag, t->map);
429116491Sharti			}
430116491Sharti			TPD_CLR_USED(sc, i);
431116491Sharti			SLIST_INSERT_HEAD(&sc->tpd_free, t, link);
432116491Sharti			sc->tpd_nfree++;
433116491Sharti		}
434116491Sharti	}
435116491Sharti}
436116491Sharti
437116491Sharti/*
438116491Sharti * This frees ALL resources of this interface and leaves the structure
439116491Sharti * in an indeterminate state. This is called just before detaching or
440116491Sharti * on a failed attach. No lock should be held.
441116491Sharti */
442116491Shartistatic void
443116491Shartihatm_destroy(struct hatm_softc *sc)
444116491Sharti{
445118598Sharti	u_int cid;
446118598Sharti
447116491Sharti	bus_teardown_intr(sc->dev, sc->irqres, sc->ih);
448116491Sharti
449116491Sharti	hatm_destroy_rmaps(sc);
450116491Sharti	hatm_destroy_smbufs(sc);
451116491Sharti	hatm_destroy_tpds(sc);
452116491Sharti
453118598Sharti	if (sc->vcc_zone != NULL) {
454118598Sharti		for (cid = 0; cid < HE_MAX_VCCS; cid++)
455118598Sharti			if (sc->vccs[cid] != NULL)
456118598Sharti				uma_zfree(sc->vcc_zone, sc->vccs[cid]);
457116491Sharti		uma_zdestroy(sc->vcc_zone);
458118598Sharti	}
459116491Sharti
460116491Sharti	/*
461116491Sharti	 * Release all memory allocated to the various queues and
462116491Sharti	 * Status pages. These have there own flag which shows whether
463116491Sharti	 * they are really allocated.
464116491Sharti	 */
465116491Sharti	hatm_destroy_dmamem(&sc->irq_0.mem);
466116491Sharti	hatm_destroy_dmamem(&sc->rbp_s0.mem);
467116491Sharti	hatm_destroy_dmamem(&sc->rbp_l0.mem);
468116491Sharti	hatm_destroy_dmamem(&sc->rbp_s1.mem);
469116491Sharti	hatm_destroy_dmamem(&sc->rbrq_0.mem);
470116491Sharti	hatm_destroy_dmamem(&sc->rbrq_1.mem);
471116491Sharti	hatm_destroy_dmamem(&sc->tbrq.mem);
472116491Sharti	hatm_destroy_dmamem(&sc->tpdrq.mem);
473116491Sharti	hatm_destroy_dmamem(&sc->hsp_mem);
474116491Sharti
475116491Sharti	if (sc->irqres != NULL)
476116491Sharti		bus_release_resource(sc->dev, SYS_RES_IRQ,
477116491Sharti		    sc->irqid, sc->irqres);
478116491Sharti
479116491Sharti	if (sc->tx_tag != NULL)
480116491Sharti		if (bus_dma_tag_destroy(sc->tx_tag))
481147256Sbrooks			if_printf(sc->ifp, "mbuf DMA tag busy\n");
482116491Sharti
483116491Sharti	if (sc->mbuf_tag != NULL)
484116491Sharti		if (bus_dma_tag_destroy(sc->mbuf_tag))
485147256Sbrooks			if_printf(sc->ifp, "mbuf DMA tag busy\n");
486116491Sharti
487116491Sharti	if (sc->parent_tag != NULL)
488116491Sharti		if (bus_dma_tag_destroy(sc->parent_tag))
489147256Sbrooks			if_printf(sc->ifp, "parent DMA tag busy\n");
490116491Sharti
491116491Sharti	if (sc->memres != NULL)
492116491Sharti		bus_release_resource(sc->dev, SYS_RES_MEMORY,
493116491Sharti		    sc->memid, sc->memres);
494116491Sharti
495116491Sharti	sysctl_ctx_free(&sc->sysctl_ctx);
496116491Sharti
497116491Sharti	cv_destroy(&sc->cv_rcclose);
498116491Sharti	cv_destroy(&sc->vcc_cv);
499116491Sharti	mtx_destroy(&sc->mtx);
500150215Sru
501150215Sru	if (sc->ifp != NULL)
502150215Sru		if_free(sc->ifp);
503116491Sharti}
504116491Sharti
505116491Sharti/*
506116491Sharti * 4.4 Card reset
507116491Sharti */
508116491Shartistatic int
509116491Shartihatm_reset(struct hatm_softc *sc)
510116491Sharti{
511116491Sharti	u_int v, count;
512116491Sharti
513116491Sharti	WRITE4(sc, HE_REGO_RESET_CNTL, 0x00);
514116491Sharti	BARRIER_W(sc);
515116491Sharti	WRITE4(sc, HE_REGO_RESET_CNTL, 0xff);
516116491Sharti	BARRIER_RW(sc);
517116491Sharti	count = 0;
518116491Sharti	while (((v = READ4(sc, HE_REGO_RESET_CNTL)) & HE_REGM_RESET_STATE) == 0) {
519116491Sharti		BARRIER_R(sc);
520116491Sharti		if (++count == 100) {
521147256Sbrooks			if_printf(sc->ifp, "reset failed\n");
522116491Sharti			return (ENXIO);
523116491Sharti		}
524116491Sharti		DELAY(1000);
525116491Sharti	}
526116491Sharti	return (0);
527116491Sharti}
528116491Sharti
529116491Sharti/*
530116491Sharti * 4.5 Set Bus Width
531116491Sharti */
532116491Shartistatic void
533116491Shartihatm_init_bus_width(struct hatm_softc *sc)
534116491Sharti{
535116491Sharti	uint32_t v, v1;
536116491Sharti
537116491Sharti	v = READ4(sc, HE_REGO_HOST_CNTL);
538116491Sharti	BARRIER_R(sc);
539116491Sharti	if (v & HE_REGM_HOST_BUS64) {
540116491Sharti		sc->pci64 = 1;
541116491Sharti		v1 = pci_read_config(sc->dev, HE_PCIR_GEN_CNTL_0, 4);
542116491Sharti		v1 |= HE_PCIM_CTL0_64BIT;
543116491Sharti		pci_write_config(sc->dev, HE_PCIR_GEN_CNTL_0, v1, 4);
544116491Sharti
545116491Sharti		v |= HE_REGM_HOST_DESC_RD64
546116491Sharti		    | HE_REGM_HOST_DATA_RD64
547116491Sharti		    | HE_REGM_HOST_DATA_WR64;
548116491Sharti		WRITE4(sc, HE_REGO_HOST_CNTL, v);
549116491Sharti		BARRIER_W(sc);
550116491Sharti	} else {
551116491Sharti		sc->pci64 = 0;
552116491Sharti		v = pci_read_config(sc->dev, HE_PCIR_GEN_CNTL_0, 4);
553116491Sharti		v &= ~HE_PCIM_CTL0_64BIT;
554116491Sharti		pci_write_config(sc->dev, HE_PCIR_GEN_CNTL_0, v, 4);
555116491Sharti	}
556116491Sharti}
557116491Sharti
558116491Sharti/*
559116491Sharti * 4.6 Set Host Endianess
560116491Sharti */
561116491Shartistatic void
562116491Shartihatm_init_endianess(struct hatm_softc *sc)
563116491Sharti{
564116491Sharti	uint32_t v;
565116491Sharti
566116491Sharti	v = READ4(sc, HE_REGO_LB_SWAP);
567116491Sharti	BARRIER_R(sc);
568116491Sharti#if BYTE_ORDER == BIG_ENDIAN
569116491Sharti	v |= HE_REGM_LBSWAP_INTR_SWAP |
570116491Sharti	    HE_REGM_LBSWAP_DESC_WR_SWAP |
571116491Sharti	    HE_REGM_LBSWAP_BIG_ENDIAN;
572116491Sharti	v &= ~(HE_REGM_LBSWAP_DATA_WR_SWAP |
573116491Sharti	    HE_REGM_LBSWAP_DESC_RD_SWAP |
574116491Sharti	    HE_REGM_LBSWAP_DATA_RD_SWAP);
575116491Sharti#else
576116491Sharti	v &= ~(HE_REGM_LBSWAP_DATA_WR_SWAP |
577116491Sharti	    HE_REGM_LBSWAP_DESC_RD_SWAP |
578116491Sharti	    HE_REGM_LBSWAP_DATA_RD_SWAP |
579116491Sharti	    HE_REGM_LBSWAP_INTR_SWAP |
580116491Sharti	    HE_REGM_LBSWAP_DESC_WR_SWAP |
581116491Sharti	    HE_REGM_LBSWAP_BIG_ENDIAN);
582116491Sharti#endif
583116491Sharti
584116491Sharti	if (sc->he622)
585116491Sharti		v |= HE_REGM_LBSWAP_XFER_SIZE;
586116491Sharti
587116491Sharti	WRITE4(sc, HE_REGO_LB_SWAP, v);
588116491Sharti	BARRIER_W(sc);
589116491Sharti}
590116491Sharti
591116491Sharti/*
592116491Sharti * 4.7 Read EEPROM
593116491Sharti */
594116491Shartistatic uint8_t
595116491Shartihatm_read_prom_byte(struct hatm_softc *sc, u_int addr)
596116491Sharti{
597116491Sharti	uint32_t val, tmp_read, byte_read;
598116491Sharti	u_int i, j;
599116491Sharti	int n;
600116491Sharti
601116491Sharti	val = READ4(sc, HE_REGO_HOST_CNTL);
602116491Sharti	val &= HE_REGM_HOST_PROM_BITS;
603116491Sharti	BARRIER_R(sc);
604116491Sharti
605116491Sharti	val |= HE_REGM_HOST_PROM_WREN;
606116491Sharti	WRITE4(sc, HE_REGO_HOST_CNTL, val);
607116491Sharti	BARRIER_W(sc);
608116491Sharti
609116491Sharti	/* send READ */
610116491Sharti	for (i = 0; i < sizeof(readtab) / sizeof(readtab[0]); i++) {
611116491Sharti		WRITE4(sc, HE_REGO_HOST_CNTL, val | readtab[i]);
612116491Sharti		BARRIER_W(sc);
613116491Sharti		DELAY(EEPROM_DELAY);
614116491Sharti	}
615116491Sharti
616116491Sharti	/* send ADDRESS */
617116491Sharti	for (n = 7, j = 0; n >= 0; n--) {
618116491Sharti		WRITE4(sc, HE_REGO_HOST_CNTL, val | clocktab[j++] |
619116491Sharti		    (((addr >> n) & 1 ) << HE_REGS_HOST_PROM_DATA_IN));
620116491Sharti		BARRIER_W(sc);
621116491Sharti		DELAY(EEPROM_DELAY);
622116491Sharti		WRITE4(sc, HE_REGO_HOST_CNTL, val | clocktab[j++] |
623116491Sharti		    (((addr >> n) & 1 ) << HE_REGS_HOST_PROM_DATA_IN));
624116491Sharti		BARRIER_W(sc);
625116491Sharti		DELAY(EEPROM_DELAY);
626116491Sharti	}
627116491Sharti
628116491Sharti	val &= ~HE_REGM_HOST_PROM_WREN;
629116491Sharti	WRITE4(sc, HE_REGO_HOST_CNTL, val);
630116491Sharti	BARRIER_W(sc);
631116491Sharti
632116491Sharti	/* read DATA */
633116491Sharti	byte_read = 0;
634116491Sharti	for (n = 7, j = 0; n >= 0; n--) {
635116491Sharti		WRITE4(sc, HE_REGO_HOST_CNTL, val | clocktab[j++]);
636116491Sharti		BARRIER_W(sc);
637116491Sharti		DELAY(EEPROM_DELAY);
638116491Sharti		tmp_read = READ4(sc, HE_REGO_HOST_CNTL);
639116491Sharti		byte_read |= (uint8_t)(((tmp_read & HE_REGM_HOST_PROM_DATA_OUT)
640116491Sharti				>> HE_REGS_HOST_PROM_DATA_OUT) << n);
641116491Sharti		WRITE4(sc, HE_REGO_HOST_CNTL, val | clocktab[j++]);
642116491Sharti		BARRIER_W(sc);
643116491Sharti		DELAY(EEPROM_DELAY);
644116491Sharti	}
645116491Sharti	WRITE4(sc, HE_REGO_HOST_CNTL, val | clocktab[j++]);
646116491Sharti	BARRIER_W(sc);
647116491Sharti	DELAY(EEPROM_DELAY);
648116491Sharti
649116491Sharti	return (byte_read);
650116491Sharti}
651116491Sharti
652116491Shartistatic void
653116491Shartihatm_init_read_eeprom(struct hatm_softc *sc)
654116491Sharti{
655116491Sharti	u_int n, count;
656116491Sharti	u_char byte;
657116491Sharti	uint32_t v;
658116491Sharti
659116491Sharti	for (n = count = 0; count < HE_EEPROM_PROD_ID_LEN; count++) {
660116491Sharti		byte = hatm_read_prom_byte(sc, HE_EEPROM_PROD_ID + count);
661116491Sharti		if (n > 0 || byte != ' ')
662116491Sharti			sc->prod_id[n++] = byte;
663116491Sharti	}
664116491Sharti	while (n > 0 && sc->prod_id[n-1] == ' ')
665116491Sharti		n--;
666116491Sharti	sc->prod_id[n] = '\0';
667116491Sharti
668116491Sharti	for (n = count = 0; count < HE_EEPROM_REV_LEN; count++) {
669116491Sharti		byte = hatm_read_prom_byte(sc, HE_EEPROM_REV + count);
670116491Sharti		if (n > 0 || byte != ' ')
671116491Sharti			sc->rev[n++] = byte;
672116491Sharti	}
673116491Sharti	while (n > 0 && sc->rev[n-1] == ' ')
674116491Sharti		n--;
675116491Sharti	sc->rev[n] = '\0';
676147256Sbrooks	IFP2IFATM(sc->ifp)->mib.hw_version = sc->rev[0];
677116491Sharti
678147256Sbrooks	IFP2IFATM(sc->ifp)->mib.serial =  hatm_read_prom_byte(sc, HE_EEPROM_M_SN + 0) << 0;
679147256Sbrooks	IFP2IFATM(sc->ifp)->mib.serial |= hatm_read_prom_byte(sc, HE_EEPROM_M_SN + 1) << 8;
680147256Sbrooks	IFP2IFATM(sc->ifp)->mib.serial |= hatm_read_prom_byte(sc, HE_EEPROM_M_SN + 2) << 16;
681147256Sbrooks	IFP2IFATM(sc->ifp)->mib.serial |= hatm_read_prom_byte(sc, HE_EEPROM_M_SN + 3) << 24;
682116491Sharti
683116491Sharti	v =  hatm_read_prom_byte(sc, HE_EEPROM_MEDIA + 0) << 0;
684116491Sharti	v |= hatm_read_prom_byte(sc, HE_EEPROM_MEDIA + 1) << 8;
685116491Sharti	v |= hatm_read_prom_byte(sc, HE_EEPROM_MEDIA + 2) << 16;
686116491Sharti	v |= hatm_read_prom_byte(sc, HE_EEPROM_MEDIA + 3) << 24;
687116491Sharti
688116491Sharti	switch (v) {
689116491Sharti	  case HE_MEDIA_UTP155:
690147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UTP_155;
691147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_155M;
692116491Sharti		break;
693116491Sharti
694116491Sharti	  case HE_MEDIA_MMF155:
695147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_155;
696147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_155M;
697116491Sharti		break;
698116491Sharti
699116491Sharti	  case HE_MEDIA_MMF622:
700147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_622;
701147256Sbrooks		IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_HE622;
702147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_622M;
703116491Sharti		sc->he622 = 1;
704116491Sharti		break;
705116491Sharti
706116491Sharti	  case HE_MEDIA_SMF155:
707147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_SM_155;
708147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_155M;
709116491Sharti		break;
710116491Sharti
711116491Sharti	  case HE_MEDIA_SMF622:
712147256Sbrooks		IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_SM_622;
713147256Sbrooks		IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_HE622;
714147256Sbrooks		IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_622M;
715116491Sharti		sc->he622 = 1;
716116491Sharti		break;
717116491Sharti	}
718116491Sharti
719147256Sbrooks	IFP2IFATM(sc->ifp)->mib.esi[0] = hatm_read_prom_byte(sc, HE_EEPROM_MAC + 0);
720147256Sbrooks	IFP2IFATM(sc->ifp)->mib.esi[1] = hatm_read_prom_byte(sc, HE_EEPROM_MAC + 1);
721147256Sbrooks	IFP2IFATM(sc->ifp)->mib.esi[2] = hatm_read_prom_byte(sc, HE_EEPROM_MAC + 2);
722147256Sbrooks	IFP2IFATM(sc->ifp)->mib.esi[3] = hatm_read_prom_byte(sc, HE_EEPROM_MAC + 3);
723147256Sbrooks	IFP2IFATM(sc->ifp)->mib.esi[4] = hatm_read_prom_byte(sc, HE_EEPROM_MAC + 4);
724147256Sbrooks	IFP2IFATM(sc->ifp)->mib.esi[5] = hatm_read_prom_byte(sc, HE_EEPROM_MAC + 5);
725116491Sharti}
726116491Sharti
727116491Sharti/*
728116491Sharti * Clear unused interrupt queue
729116491Sharti */
730116491Shartistatic void
731116491Shartihatm_clear_irq(struct hatm_softc *sc, u_int group)
732116491Sharti{
733116491Sharti	WRITE4(sc, HE_REGO_IRQ_BASE(group), 0);
734116491Sharti	WRITE4(sc, HE_REGO_IRQ_HEAD(group), 0);
735116491Sharti	WRITE4(sc, HE_REGO_IRQ_CNTL(group), 0);
736116491Sharti	WRITE4(sc, HE_REGO_IRQ_DATA(group), 0);
737116491Sharti}
738116491Sharti
739116491Sharti/*
740116491Sharti * 4.10 Initialize interrupt queues
741116491Sharti */
742116491Shartistatic void
743116491Shartihatm_init_irq(struct hatm_softc *sc, struct heirq *q, u_int group)
744116491Sharti{
745116491Sharti	u_int i;
746116491Sharti
747116491Sharti	if (q->size == 0) {
748116491Sharti		hatm_clear_irq(sc, group);
749116491Sharti		return;
750116491Sharti	}
751116491Sharti
752116491Sharti	q->group = group;
753116491Sharti	q->sc = sc;
754116491Sharti	q->irq = q->mem.base;
755116491Sharti	q->head = 0;
756116491Sharti	q->tailp = q->irq + (q->size - 1);
757116491Sharti	*q->tailp = 0;
758116491Sharti
759116491Sharti	for (i = 0; i < q->size; i++)
760116491Sharti		q->irq[i] = HE_REGM_ITYPE_INVALID;
761116491Sharti
762116491Sharti	WRITE4(sc, HE_REGO_IRQ_BASE(group), q->mem.paddr);
763116491Sharti	WRITE4(sc, HE_REGO_IRQ_HEAD(group),
764116491Sharti	    ((q->size - 1) << HE_REGS_IRQ_HEAD_SIZE) |
765116491Sharti	    (q->thresh << HE_REGS_IRQ_HEAD_THRESH));
766116491Sharti	WRITE4(sc, HE_REGO_IRQ_CNTL(group), q->line);
767116491Sharti	WRITE4(sc, HE_REGO_IRQ_DATA(group), 0);
768116491Sharti}
769116491Sharti
770116491Sharti/*
771116491Sharti * 5.1.3 Initialize connection memory
772116491Sharti */
773116491Shartistatic void
774116491Shartihatm_init_cm(struct hatm_softc *sc)
775116491Sharti{
776116491Sharti	u_int rsra, mlbm, rabr, numbuffs;
777116491Sharti	u_int tsra, tabr, mtpd;
778116491Sharti	u_int n;
779116491Sharti
780116491Sharti	for (n = 0; n < HE_CONFIG_TXMEM; n++)
781116491Sharti		WRITE_TCM4(sc, n, 0);
782116491Sharti	for (n = 0; n < HE_CONFIG_RXMEM; n++)
783116491Sharti		WRITE_RCM4(sc, n, 0);
784116491Sharti
785116491Sharti	numbuffs = sc->r0_numbuffs + sc->r1_numbuffs + sc->tx_numbuffs;
786116491Sharti
787116491Sharti	rsra = 0;
788147256Sbrooks	mlbm = ((rsra + IFP2IFATM(sc->ifp)->mib.max_vccs * 8) + 0x7ff) & ~0x7ff;
789116491Sharti	rabr = ((mlbm + numbuffs * 2) + 0x7ff) & ~0x7ff;
790147256Sbrooks	sc->rsrb = ((rabr + 2048) + (2 * IFP2IFATM(sc->ifp)->mib.max_vccs - 1)) &
791147256Sbrooks	    ~(2 * IFP2IFATM(sc->ifp)->mib.max_vccs - 1);
792116491Sharti
793116491Sharti	tsra = 0;
794147256Sbrooks	sc->tsrb = tsra + IFP2IFATM(sc->ifp)->mib.max_vccs * 8;
795147256Sbrooks	sc->tsrc = sc->tsrb + IFP2IFATM(sc->ifp)->mib.max_vccs * 4;
796147256Sbrooks	sc->tsrd = sc->tsrc + IFP2IFATM(sc->ifp)->mib.max_vccs * 2;
797147256Sbrooks	tabr = sc->tsrd + IFP2IFATM(sc->ifp)->mib.max_vccs * 1;
798147256Sbrooks	mtpd = ((tabr + 1024) + (16 * IFP2IFATM(sc->ifp)->mib.max_vccs - 1)) &
799147256Sbrooks	    ~(16 * IFP2IFATM(sc->ifp)->mib.max_vccs - 1);
800116491Sharti
801116491Sharti	DBG(sc, ATTACH, ("rsra=%x mlbm=%x rabr=%x rsrb=%x",
802116491Sharti	    rsra, mlbm, rabr, sc->rsrb));
803116491Sharti	DBG(sc, ATTACH, ("tsra=%x tsrb=%x tsrc=%x tsrd=%x tabr=%x mtpd=%x",
804116491Sharti	    tsra, sc->tsrb, sc->tsrc, sc->tsrd, tabr, mtpd));
805116491Sharti
806116491Sharti	WRITE4(sc, HE_REGO_TSRB_BA, sc->tsrb);
807116491Sharti	WRITE4(sc, HE_REGO_TSRC_BA, sc->tsrc);
808116491Sharti	WRITE4(sc, HE_REGO_TSRD_BA, sc->tsrd);
809116491Sharti	WRITE4(sc, HE_REGO_TMABR_BA, tabr);
810116491Sharti	WRITE4(sc, HE_REGO_TPD_BA, mtpd);
811116491Sharti
812116491Sharti	WRITE4(sc, HE_REGO_RCMRSRB_BA, sc->rsrb);
813116491Sharti	WRITE4(sc, HE_REGO_RCMLBM_BA, mlbm);
814116491Sharti	WRITE4(sc, HE_REGO_RCMABR_BA, rabr);
815116491Sharti
816116491Sharti	BARRIER_W(sc);
817116491Sharti}
818116491Sharti
819116491Sharti/*
820116491Sharti * 5.1.4 Initialize Local buffer Pools
821116491Sharti */
822116491Shartistatic void
823116491Shartihatm_init_rx_buffer_pool(struct hatm_softc *sc,
824116491Sharti	u_int num,		/* bank */
825116491Sharti	u_int start,		/* start row */
826116491Sharti	u_int numbuffs		/* number of entries */
827116491Sharti)
828116491Sharti{
829116491Sharti	u_int row_size;		/* bytes per row */
830116491Sharti	uint32_t row_addr;	/* start address of this row */
831116491Sharti	u_int lbuf_size;	/* bytes per lbuf */
832116491Sharti	u_int lbufs_per_row;	/* number of lbufs per memory row */
833116491Sharti	uint32_t lbufd_index;	/* index of lbuf descriptor */
834116491Sharti	uint32_t lbufd_addr;	/* address of lbuf descriptor */
835116491Sharti	u_int lbuf_row_cnt;	/* current lbuf in current row */
836116491Sharti	uint32_t lbuf_addr;	/* address of current buffer */
837116491Sharti	u_int i;
838116491Sharti
839201758Smbr	row_size = sc->bytes_per_row;
840116491Sharti	row_addr = start * row_size;
841116491Sharti	lbuf_size = sc->cells_per_lbuf * 48;
842116491Sharti	lbufs_per_row = sc->cells_per_row / sc->cells_per_lbuf;
843116491Sharti
844116491Sharti	/* descriptor index */
845116491Sharti	lbufd_index = num;
846116491Sharti
847116491Sharti	/* 2 words per entry */
848116491Sharti	lbufd_addr = READ4(sc, HE_REGO_RCMLBM_BA) + lbufd_index * 2;
849116491Sharti
850116491Sharti	/* write head of queue */
851116491Sharti	WRITE4(sc, HE_REGO_RLBF_H(num), lbufd_index);
852116491Sharti
853116491Sharti	lbuf_row_cnt = 0;
854116491Sharti	for (i = 0; i < numbuffs; i++) {
855116491Sharti		lbuf_addr = (row_addr + lbuf_row_cnt * lbuf_size) / 32;
856116491Sharti
857116491Sharti		WRITE_RCM4(sc, lbufd_addr, lbuf_addr);
858116491Sharti
859116491Sharti		lbufd_index += 2;
860116491Sharti		WRITE_RCM4(sc, lbufd_addr + 1, lbufd_index);
861116491Sharti
862116491Sharti		if (++lbuf_row_cnt == lbufs_per_row) {
863116491Sharti			lbuf_row_cnt = 0;
864116491Sharti			row_addr += row_size;
865116491Sharti		}
866116491Sharti
867116491Sharti		lbufd_addr += 2 * 2;
868116491Sharti	}
869116491Sharti
870116491Sharti	WRITE4(sc, HE_REGO_RLBF_T(num), lbufd_index - 2);
871116491Sharti	WRITE4(sc, HE_REGO_RLBF_C(num), numbuffs);
872116491Sharti
873116491Sharti	BARRIER_W(sc);
874116491Sharti}
875116491Sharti
876116491Shartistatic void
877116491Shartihatm_init_tx_buffer_pool(struct hatm_softc *sc,
878116491Sharti	u_int start,		/* start row */
879116491Sharti	u_int numbuffs		/* number of entries */
880116491Sharti)
881116491Sharti{
882116491Sharti	u_int row_size;		/* bytes per row */
883116491Sharti	uint32_t row_addr;	/* start address of this row */
884116491Sharti	u_int lbuf_size;	/* bytes per lbuf */
885116491Sharti	u_int lbufs_per_row;	/* number of lbufs per memory row */
886116491Sharti	uint32_t lbufd_index;	/* index of lbuf descriptor */
887116491Sharti	uint32_t lbufd_addr;	/* address of lbuf descriptor */
888116491Sharti	u_int lbuf_row_cnt;	/* current lbuf in current row */
889116491Sharti	uint32_t lbuf_addr;	/* address of current buffer */
890116491Sharti	u_int i;
891116491Sharti
892201758Smbr	row_size = sc->bytes_per_row;
893116491Sharti	row_addr = start * row_size;
894116491Sharti	lbuf_size = sc->cells_per_lbuf * 48;
895116491Sharti	lbufs_per_row = sc->cells_per_row / sc->cells_per_lbuf;
896116491Sharti
897116491Sharti	/* descriptor index */
898116491Sharti	lbufd_index = sc->r0_numbuffs + sc->r1_numbuffs;
899116491Sharti
900116491Sharti	/* 2 words per entry */
901116491Sharti	lbufd_addr = READ4(sc, HE_REGO_RCMLBM_BA) + lbufd_index * 2;
902116491Sharti
903116491Sharti	/* write head of queue */
904116491Sharti	WRITE4(sc, HE_REGO_TLBF_H, lbufd_index);
905116491Sharti
906116491Sharti	lbuf_row_cnt = 0;
907116491Sharti	for (i = 0; i < numbuffs; i++) {
908116491Sharti		lbuf_addr = (row_addr + lbuf_row_cnt * lbuf_size) / 32;
909116491Sharti
910116491Sharti		WRITE_RCM4(sc, lbufd_addr, lbuf_addr);
911116491Sharti		lbufd_index++;
912116491Sharti		WRITE_RCM4(sc, lbufd_addr + 1, lbufd_index);
913116491Sharti
914116491Sharti		if (++lbuf_row_cnt == lbufs_per_row) {
915116491Sharti			lbuf_row_cnt = 0;
916116491Sharti			row_addr += row_size;
917116491Sharti		}
918116491Sharti
919116491Sharti		lbufd_addr += 2;
920116491Sharti	}
921116491Sharti
922116491Sharti	WRITE4(sc, HE_REGO_TLBF_T, lbufd_index - 1);
923116491Sharti	BARRIER_W(sc);
924116491Sharti}
925116491Sharti
926116491Sharti/*
927116491Sharti * 5.1.5 Initialize Intermediate Receive Queues
928116491Sharti */
929116491Shartistatic void
930116491Shartihatm_init_imed_queues(struct hatm_softc *sc)
931116491Sharti{
932116491Sharti	u_int n;
933116491Sharti
934116491Sharti	if (sc->he622) {
935116491Sharti		for (n = 0; n < 8; n++) {
936116491Sharti			WRITE4(sc, HE_REGO_INMQ_S(n), 0x10*n+0x000f);
937116491Sharti			WRITE4(sc, HE_REGO_INMQ_L(n), 0x10*n+0x200f);
938116491Sharti		}
939116491Sharti	} else {
940116491Sharti		for (n = 0; n < 8; n++) {
941116491Sharti			WRITE4(sc, HE_REGO_INMQ_S(n), n);
942116491Sharti			WRITE4(sc, HE_REGO_INMQ_L(n), n+0x8);
943116491Sharti		}
944116491Sharti	}
945116491Sharti}
946116491Sharti
947116491Sharti/*
948116491Sharti * 5.1.7 Init CS block
949116491Sharti */
950116491Shartistatic void
951116491Shartihatm_init_cs_block(struct hatm_softc *sc)
952116491Sharti{
953116491Sharti	u_int n, i;
954116491Sharti	u_int clkfreg, cellrate, decr, tmp;
955116491Sharti	static const uint32_t erthr[2][5][3] = HE_REGT_CS_ERTHR;
956116491Sharti	static const uint32_t erctl[2][3] = HE_REGT_CS_ERCTL;
957116491Sharti	static const uint32_t erstat[2][2] = HE_REGT_CS_ERSTAT;
958116491Sharti	static const uint32_t rtfwr[2] = HE_REGT_CS_RTFWR;
959116491Sharti	static const uint32_t rtatr[2] = HE_REGT_CS_RTATR;
960116491Sharti	static const uint32_t bwalloc[2][6] = HE_REGT_CS_BWALLOC;
961116491Sharti	static const uint32_t orcf[2][2] = HE_REGT_CS_ORCF;
962116491Sharti
963116491Sharti	/* Clear Rate Controller Start Times and Occupied Flags */
964116491Sharti	for (n = 0; n < 32; n++)
965116491Sharti		WRITE_MBOX4(sc, HE_REGO_CS_STTIM(n), 0);
966116491Sharti
967116491Sharti	clkfreg = sc->he622 ? HE_622_CLOCK : HE_155_CLOCK;
968116491Sharti	cellrate = sc->he622 ? ATM_RATE_622M : ATM_RATE_155M;
969116491Sharti	decr = cellrate / 32;
970116491Sharti
971116491Sharti	for (n = 0; n < 16; n++) {
972116491Sharti		tmp = clkfreg / cellrate;
973116491Sharti		WRITE_MBOX4(sc, HE_REGO_CS_TGRLD(n), tmp - 1);
974116491Sharti		cellrate -= decr;
975116491Sharti	}
976116491Sharti
977116491Sharti	i = (sc->cells_per_lbuf == 2) ? 0
978116491Sharti	   :(sc->cells_per_lbuf == 4) ? 1
979116491Sharti	   :                            2;
980116491Sharti
981116491Sharti	/* table 5.2 */
982116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERTHR0, erthr[sc->he622][0][i]);
983116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERTHR1, erthr[sc->he622][1][i]);
984116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERTHR2, erthr[sc->he622][2][i]);
985116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERTHR3, erthr[sc->he622][3][i]);
986116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERTHR4, erthr[sc->he622][4][i]);
987116491Sharti
988116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERCTL0, erctl[sc->he622][0]);
989116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERCTL1, erctl[sc->he622][1]);
990116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERCTL2, erctl[sc->he622][2]);
991116491Sharti
992116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERSTAT0, erstat[sc->he622][0]);
993116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERSTAT1, erstat[sc->he622][1]);
994116491Sharti
995116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_RTFWR, rtfwr[sc->he622]);
996116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_RTATR, rtatr[sc->he622]);
997116491Sharti
998116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_TFBSET, bwalloc[sc->he622][0]);
999116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_WCRMAX, bwalloc[sc->he622][1]);
1000116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_WCRMIN, bwalloc[sc->he622][2]);
1001116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_WCRINC, bwalloc[sc->he622][3]);
1002116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_WCRDEC, bwalloc[sc->he622][4]);
1003116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_WCRCEIL, bwalloc[sc->he622][5]);
1004116491Sharti
1005116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_OTPPER, orcf[sc->he622][0]);
1006116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_OTWPER, orcf[sc->he622][1]);
1007116491Sharti
1008116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_OTTLIM, 8);
1009116491Sharti
1010116491Sharti	for (n = 0; n < 8; n++)
1011116491Sharti		WRITE_MBOX4(sc, HE_REGO_CS_HGRRT(n), 0);
1012116491Sharti}
1013116491Sharti
1014116491Sharti/*
1015116491Sharti * 5.1.8 CS Block Connection Memory Initialisation
1016116491Sharti */
1017116491Shartistatic void
1018116491Shartihatm_init_cs_block_cm(struct hatm_softc *sc)
1019116491Sharti{
1020116491Sharti	u_int n, i;
1021116491Sharti	u_int expt, mant, etrm, wcr, ttnrm, tnrm;
1022116491Sharti	uint32_t rate;
1023116491Sharti	uint32_t clkfreq, cellrate, decr;
1024116491Sharti	uint32_t *rg, rtg, val = 0;
1025116491Sharti	uint64_t drate;
1026116491Sharti	u_int buf, buf_limit;
1027116491Sharti	uint32_t base = READ4(sc, HE_REGO_RCMABR_BA);
1028116491Sharti
1029116491Sharti	for (n = 0; n < HE_REGL_CM_GQTBL; n++)
1030116491Sharti		WRITE_RCM4(sc, base + HE_REGO_CM_GQTBL + n, 0);
1031116491Sharti	for (n = 0; n < HE_REGL_CM_RGTBL; n++)
1032116491Sharti		WRITE_RCM4(sc, base + HE_REGO_CM_RGTBL + n, 0);
1033116491Sharti
1034116491Sharti	tnrm = 0;
1035116491Sharti	for (n = 0; n < HE_REGL_CM_TNRMTBL * 4; n++) {
1036116491Sharti		expt = (n >> 5) & 0x1f;
1037116491Sharti		mant = ((n & 0x18) << 4) | 0x7f;
1038116491Sharti		wcr = (1 << expt) * (mant + 512) / 512;
1039116491Sharti		etrm = n & 0x7;
1040116491Sharti		ttnrm = wcr / 10 / (1 << etrm);
1041116491Sharti		if (ttnrm > 255)
1042116491Sharti			ttnrm = 255;
1043116491Sharti		else if(ttnrm < 2)
1044116491Sharti			ttnrm = 2;
1045116491Sharti		tnrm = (tnrm << 8) | (ttnrm & 0xff);
1046116491Sharti		if (n % 4 == 0)
1047116491Sharti			WRITE_RCM4(sc, base + HE_REGO_CM_TNRMTBL + (n/4), tnrm);
1048116491Sharti	}
1049116491Sharti
1050116491Sharti	clkfreq = sc->he622 ? HE_622_CLOCK : HE_155_CLOCK;
1051116491Sharti	buf_limit = 4;
1052116491Sharti
1053116491Sharti	cellrate = sc->he622 ? ATM_RATE_622M : ATM_RATE_155M;
1054116491Sharti	decr = cellrate / 32;
1055116491Sharti
1056116491Sharti	/* compute GRID top row in 1000 * cps */
1057116491Sharti	for (n = 0; n < 16; n++) {
1058116491Sharti		u_int interval = clkfreq / cellrate;
1059116491Sharti		sc->rate_grid[0][n] = (u_int64_t)clkfreq * 1000 / interval;
1060116491Sharti		cellrate -= decr;
1061116491Sharti	}
1062116491Sharti
1063116491Sharti	/* compute the other rows according to 2.4 */
1064116491Sharti	for (i = 1; i < 16; i++)
1065116491Sharti		for (n = 0; n < 16; n++)
1066116491Sharti			sc->rate_grid[i][n] = sc->rate_grid[i-1][n] /
1067116491Sharti			    ((i < 14) ? 2 : 4);
1068116491Sharti
1069116491Sharti	/* first entry is line rate */
1070116491Sharti	n = hatm_cps2atmf(sc->he622 ? ATM_RATE_622M : ATM_RATE_155M);
1071116491Sharti	expt = (n >> 9) & 0x1f;
1072116491Sharti	mant = n & 0x1f0;
1073116491Sharti	sc->rate_grid[0][0] = (u_int64_t)(1<<expt) * 1000 * (mant+512) / 512;
1074116491Sharti
1075116491Sharti	/* now build the conversion table - each 32 bit word contains
1076116491Sharti	 * two entries - this gives a total of 0x400 16 bit entries.
1077116491Sharti	 * This table maps the truncated ATMF rate version into a grid index */
1078116491Sharti	cellrate = sc->he622 ? ATM_RATE_622M : ATM_RATE_155M;
1079116491Sharti	rg = &sc->rate_grid[15][15];
1080116491Sharti
1081116491Sharti	for (rate = 0; rate < 2 * HE_REGL_CM_RTGTBL; rate++) {
1082116491Sharti		/* unpack the ATMF rate */
1083116491Sharti		expt = rate >> 5;
1084116491Sharti		mant = (rate & 0x1f) << 4;
1085116491Sharti
1086116491Sharti		/* get the cell rate - minimum is 10 per second */
1087116491Sharti		drate = (uint64_t)(1 << expt) * 1000 * (mant + 512) / 512;
1088116491Sharti		if (drate < 10 * 1000)
1089116491Sharti			drate = 10 * 1000;
1090116491Sharti
1091116491Sharti		/* now look up the grid index */
1092116491Sharti		while (drate >= *rg && rg-- > &sc->rate_grid[0][0])
1093116491Sharti			;
1094116491Sharti		rg++;
1095116491Sharti		rtg = rg - &sc->rate_grid[0][0];
1096116491Sharti
1097116491Sharti		/* now compute the buffer limit */
1098116491Sharti		buf = drate * sc->tx_numbuffs / (cellrate * 2) / 1000;
1099116491Sharti		if (buf == 0)
1100116491Sharti			buf = 1;
1101116491Sharti		else if (buf > buf_limit)
1102116491Sharti			buf = buf_limit;
1103116491Sharti
1104116491Sharti		/* make value */
1105116491Sharti		val = (val << 16) | (rtg << 8) | buf;
1106116491Sharti
1107116491Sharti		/* write */
1108116491Sharti		if (rate % 2 == 1)
1109116491Sharti			WRITE_RCM4(sc, base + HE_REGO_CM_RTGTBL + rate/2, val);
1110116491Sharti	}
1111116491Sharti}
1112116491Sharti
1113116491Sharti/*
1114116491Sharti * Clear an unused receive group buffer pool
1115116491Sharti */
1116116491Shartistatic void
1117116491Shartihatm_clear_rpool(struct hatm_softc *sc, u_int group, u_int large)
1118116491Sharti{
1119116491Sharti	WRITE4(sc, HE_REGO_RBP_S(large, group), 0);
1120116491Sharti	WRITE4(sc, HE_REGO_RBP_T(large, group), 0);
1121116491Sharti	WRITE4(sc, HE_REGO_RBP_QI(large, group), 1);
1122116491Sharti	WRITE4(sc, HE_REGO_RBP_BL(large, group), 0);
1123116491Sharti}
1124116491Sharti
1125116491Sharti/*
1126116491Sharti * Initialize a receive group buffer pool
1127116491Sharti */
1128116491Shartistatic void
1129116491Shartihatm_init_rpool(struct hatm_softc *sc, struct herbp *q, u_int group,
1130116491Sharti    u_int large)
1131116491Sharti{
1132116491Sharti	if (q->size == 0) {
1133116491Sharti		hatm_clear_rpool(sc, group, large);
1134116491Sharti		return;
1135116491Sharti	}
1136116491Sharti
1137116491Sharti	bzero(q->mem.base, q->mem.size);
1138116491Sharti	q->rbp = q->mem.base;
1139116491Sharti	q->head = q->tail = 0;
1140116491Sharti
1141116491Sharti	DBG(sc, ATTACH, ("RBP%u%c=0x%lx", group, "SL"[large],
1142116491Sharti	    (u_long)q->mem.paddr));
1143116491Sharti
1144116491Sharti	WRITE4(sc, HE_REGO_RBP_S(large, group), q->mem.paddr);
1145116491Sharti	WRITE4(sc, HE_REGO_RBP_T(large, group), 0);
1146116491Sharti	WRITE4(sc, HE_REGO_RBP_QI(large, group),
1147116491Sharti	    ((q->size - 1) << HE_REGS_RBP_SIZE) |
1148116491Sharti	    HE_REGM_RBP_INTR_ENB |
1149116491Sharti	    (q->thresh << HE_REGS_RBP_THRESH));
1150116491Sharti	WRITE4(sc, HE_REGO_RBP_BL(large, group), (q->bsize >> 2) & ~1);
1151116491Sharti}
1152116491Sharti
1153116491Sharti/*
1154116491Sharti * Clear an unused receive buffer return queue
1155116491Sharti */
1156116491Shartistatic void
1157116491Shartihatm_clear_rbrq(struct hatm_softc *sc, u_int group)
1158116491Sharti{
1159116491Sharti	WRITE4(sc, HE_REGO_RBRQ_ST(group), 0);
1160116491Sharti	WRITE4(sc, HE_REGO_RBRQ_H(group), 0);
1161116491Sharti	WRITE4(sc, HE_REGO_RBRQ_Q(group), (1 << HE_REGS_RBRQ_THRESH));
1162116491Sharti	WRITE4(sc, HE_REGO_RBRQ_I(group), 0);
1163116491Sharti}
1164116491Sharti
1165116491Sharti/*
1166116491Sharti * Initialize receive buffer return queue
1167116491Sharti */
1168116491Shartistatic void
1169116491Shartihatm_init_rbrq(struct hatm_softc *sc, struct herbrq *rq, u_int group)
1170116491Sharti{
1171116491Sharti	if (rq->size == 0) {
1172116491Sharti		hatm_clear_rbrq(sc, group);
1173116491Sharti		return;
1174116491Sharti	}
1175116491Sharti
1176116491Sharti	rq->rbrq = rq->mem.base;
1177116491Sharti	rq->head = 0;
1178116491Sharti
1179116491Sharti	DBG(sc, ATTACH, ("RBRQ%u=0x%lx", group, (u_long)rq->mem.paddr));
1180116491Sharti
1181116491Sharti	WRITE4(sc, HE_REGO_RBRQ_ST(group), rq->mem.paddr);
1182116491Sharti	WRITE4(sc, HE_REGO_RBRQ_H(group), 0);
1183116491Sharti	WRITE4(sc, HE_REGO_RBRQ_Q(group),
1184116491Sharti	    (rq->thresh << HE_REGS_RBRQ_THRESH) |
1185116491Sharti	    ((rq->size - 1) << HE_REGS_RBRQ_SIZE));
1186116491Sharti	WRITE4(sc, HE_REGO_RBRQ_I(group),
1187116491Sharti	    (rq->tout << HE_REGS_RBRQ_TIME) |
1188116491Sharti	    (rq->pcnt << HE_REGS_RBRQ_COUNT));
1189116491Sharti}
1190116491Sharti
1191116491Sharti/*
1192116491Sharti * Clear an unused transmit buffer return queue N
1193116491Sharti */
1194116491Shartistatic void
1195116491Shartihatm_clear_tbrq(struct hatm_softc *sc, u_int group)
1196116491Sharti{
1197116491Sharti	WRITE4(sc, HE_REGO_TBRQ_B_T(group), 0);
1198116491Sharti	WRITE4(sc, HE_REGO_TBRQ_H(group), 0);
1199116491Sharti	WRITE4(sc, HE_REGO_TBRQ_S(group), 0);
1200116491Sharti	WRITE4(sc, HE_REGO_TBRQ_THRESH(group), 1);
1201116491Sharti}
1202116491Sharti
1203116491Sharti/*
1204116491Sharti * Initialize transmit buffer return queue N
1205116491Sharti */
1206116491Shartistatic void
1207116491Shartihatm_init_tbrq(struct hatm_softc *sc, struct hetbrq *tq, u_int group)
1208116491Sharti{
1209116491Sharti	if (tq->size == 0) {
1210116491Sharti		hatm_clear_tbrq(sc, group);
1211116491Sharti		return;
1212116491Sharti	}
1213116491Sharti
1214116491Sharti	tq->tbrq = tq->mem.base;
1215116491Sharti	tq->head = 0;
1216116491Sharti
1217116491Sharti	DBG(sc, ATTACH, ("TBRQ%u=0x%lx", group, (u_long)tq->mem.paddr));
1218116491Sharti
1219116491Sharti	WRITE4(sc, HE_REGO_TBRQ_B_T(group), tq->mem.paddr);
1220116491Sharti	WRITE4(sc, HE_REGO_TBRQ_H(group), 0);
1221116491Sharti	WRITE4(sc, HE_REGO_TBRQ_S(group), tq->size - 1);
1222116491Sharti	WRITE4(sc, HE_REGO_TBRQ_THRESH(group), tq->thresh);
1223116491Sharti}
1224116491Sharti
1225116491Sharti/*
1226116491Sharti * Initialize TPDRQ
1227116491Sharti */
1228116491Shartistatic void
1229116491Shartihatm_init_tpdrq(struct hatm_softc *sc)
1230116491Sharti{
1231116491Sharti	struct hetpdrq *tq;
1232116491Sharti
1233116491Sharti	tq = &sc->tpdrq;
1234116491Sharti	tq->tpdrq = tq->mem.base;
1235116491Sharti	tq->tail = tq->head = 0;
1236116491Sharti
1237116491Sharti	DBG(sc, ATTACH, ("TPDRQ=0x%lx", (u_long)tq->mem.paddr));
1238116491Sharti
1239116491Sharti	WRITE4(sc, HE_REGO_TPDRQ_H, tq->mem.paddr);
1240116491Sharti	WRITE4(sc, HE_REGO_TPDRQ_T, 0);
1241116491Sharti	WRITE4(sc, HE_REGO_TPDRQ_S, tq->size - 1);
1242116491Sharti}
1243116491Sharti
1244116491Sharti/*
1245116491Sharti * Function can be called by the infrastructure to start the card.
1246116491Sharti */
1247116491Shartistatic void
1248116491Shartihatm_init(void *p)
1249116491Sharti{
1250116491Sharti	struct hatm_softc *sc = p;
1251116491Sharti
1252116491Sharti	mtx_lock(&sc->mtx);
1253116491Sharti	hatm_stop(sc);
1254116491Sharti	hatm_initialize(sc);
1255116491Sharti	mtx_unlock(&sc->mtx);
1256116491Sharti}
1257116491Sharti
1258116491Shartienum {
1259116491Sharti	CTL_ISTATS,
1260116491Sharti};
1261116491Sharti
1262116491Sharti/*
1263116491Sharti * Sysctl handler
1264116491Sharti */
1265116491Shartistatic int
1266116491Shartihatm_sysctl(SYSCTL_HANDLER_ARGS)
1267116491Sharti{
1268116491Sharti	struct hatm_softc *sc = arg1;
1269116491Sharti	uint32_t *ret;
1270116491Sharti	int error;
1271116491Sharti	size_t len;
1272116491Sharti
1273116491Sharti	switch (arg2) {
1274116491Sharti
1275116491Sharti	  case CTL_ISTATS:
1276116491Sharti		len = sizeof(sc->istats);
1277116491Sharti		break;
1278116491Sharti
1279116491Sharti	  default:
1280116491Sharti		panic("bad control code");
1281116491Sharti	}
1282116491Sharti
1283116491Sharti	ret = malloc(len, M_TEMP, M_WAITOK);
1284116491Sharti	mtx_lock(&sc->mtx);
1285116491Sharti
1286116491Sharti	switch (arg2) {
1287116491Sharti
1288116491Sharti	  case CTL_ISTATS:
1289118169Sharti		sc->istats.mcc += READ4(sc, HE_REGO_MCC);
1290118169Sharti		sc->istats.oec += READ4(sc, HE_REGO_OEC);
1291118169Sharti		sc->istats.dcc += READ4(sc, HE_REGO_DCC);
1292118169Sharti		sc->istats.cec += READ4(sc, HE_REGO_CEC);
1293116491Sharti		bcopy(&sc->istats, ret, sizeof(sc->istats));
1294116491Sharti		break;
1295116491Sharti	}
1296116491Sharti	mtx_unlock(&sc->mtx);
1297116491Sharti
1298116491Sharti	error = SYSCTL_OUT(req, ret, len);
1299116491Sharti	free(ret, M_TEMP);
1300116491Sharti
1301116491Sharti	return (error);
1302116491Sharti}
1303116491Sharti
1304116491Shartistatic int
1305116491Shartikenv_getuint(struct hatm_softc *sc, const char *var,
1306116491Sharti    u_int *ptr, u_int def, int rw)
1307116491Sharti{
1308116491Sharti	char full[IFNAMSIZ + 3 + 20];
1309116491Sharti	char *val, *end;
1310116491Sharti	u_int u;
1311116491Sharti
1312116491Sharti	*ptr = def;
1313116491Sharti
1314116491Sharti	if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
1315116491Sharti	    OID_AUTO, var, rw ? CTLFLAG_RW : CTLFLAG_RD, ptr, 0, "") == NULL)
1316116491Sharti		return (ENOMEM);
1317116491Sharti
1318116491Sharti	snprintf(full, sizeof(full), "hw.%s.%s",
1319116491Sharti	    device_get_nameunit(sc->dev), var);
1320116491Sharti
1321116491Sharti	if ((val = getenv(full)) == NULL)
1322116491Sharti		return (0);
1323116491Sharti	u = strtoul(val, &end, 0);
1324116491Sharti	if (end == val || *end != '\0') {
1325116491Sharti		freeenv(val);
1326116491Sharti		return (EINVAL);
1327116491Sharti	}
1328199970Semaste	freeenv(val);
1329116491Sharti	if (bootverbose)
1330147256Sbrooks		if_printf(sc->ifp, "%s=%u\n", full, u);
1331116491Sharti	*ptr = u;
1332116491Sharti	return (0);
1333116491Sharti}
1334116491Sharti
1335116491Sharti/*
1336116491Sharti * Set configurable parameters. Many of these are configurable via
1337116491Sharti * kenv.
1338116491Sharti */
1339116491Shartistatic int
1340116491Shartihatm_configure(struct hatm_softc *sc)
1341116491Sharti{
1342116491Sharti	/* Receive buffer pool 0 small */
1343121469Sharti	kenv_getuint(sc, "rbps0_size", &sc->rbp_s0.size,
1344116491Sharti	    HE_CONFIG_RBPS0_SIZE, 0);
1345121469Sharti	kenv_getuint(sc, "rbps0_thresh", &sc->rbp_s0.thresh,
1346116491Sharti	    HE_CONFIG_RBPS0_THRESH, 0);
1347116491Sharti	sc->rbp_s0.bsize = MBUF0_SIZE;
1348116491Sharti
1349116491Sharti	/* Receive buffer pool 0 large */
1350121469Sharti	kenv_getuint(sc, "rbpl0_size", &sc->rbp_l0.size,
1351116491Sharti	    HE_CONFIG_RBPL0_SIZE, 0);
1352121469Sharti	kenv_getuint(sc, "rbpl0_thresh", &sc->rbp_l0.thresh,
1353116491Sharti	    HE_CONFIG_RBPL0_THRESH, 0);
1354116491Sharti	sc->rbp_l0.bsize = MCLBYTES - MBUFL_OFFSET;
1355116491Sharti
1356116491Sharti	/* Receive buffer return queue 0 */
1357121469Sharti	kenv_getuint(sc, "rbrq0_size", &sc->rbrq_0.size,
1358116491Sharti	    HE_CONFIG_RBRQ0_SIZE, 0);
1359121469Sharti	kenv_getuint(sc, "rbrq0_thresh", &sc->rbrq_0.thresh,
1360116491Sharti	    HE_CONFIG_RBRQ0_THRESH, 0);
1361121469Sharti	kenv_getuint(sc, "rbrq0_tout", &sc->rbrq_0.tout,
1362116491Sharti	    HE_CONFIG_RBRQ0_TOUT, 0);
1363121469Sharti	kenv_getuint(sc, "rbrq0_pcnt", &sc->rbrq_0.pcnt,
1364116491Sharti	    HE_CONFIG_RBRQ0_PCNT, 0);
1365116491Sharti
1366116491Sharti	/* Receive buffer pool 1 small */
1367121469Sharti	kenv_getuint(sc, "rbps1_size", &sc->rbp_s1.size,
1368116491Sharti	    HE_CONFIG_RBPS1_SIZE, 0);
1369121469Sharti	kenv_getuint(sc, "rbps1_thresh", &sc->rbp_s1.thresh,
1370116491Sharti	    HE_CONFIG_RBPS1_THRESH, 0);
1371116491Sharti	sc->rbp_s1.bsize = MBUF1_SIZE;
1372116491Sharti
1373116491Sharti	/* Receive buffer return queue 1 */
1374121469Sharti	kenv_getuint(sc, "rbrq1_size", &sc->rbrq_1.size,
1375116491Sharti	    HE_CONFIG_RBRQ1_SIZE, 0);
1376121469Sharti	kenv_getuint(sc, "rbrq1_thresh", &sc->rbrq_1.thresh,
1377116491Sharti	    HE_CONFIG_RBRQ1_THRESH, 0);
1378121469Sharti	kenv_getuint(sc, "rbrq1_tout", &sc->rbrq_1.tout,
1379116491Sharti	    HE_CONFIG_RBRQ1_TOUT, 0);
1380121469Sharti	kenv_getuint(sc, "rbrq1_pcnt", &sc->rbrq_1.pcnt,
1381116491Sharti	    HE_CONFIG_RBRQ1_PCNT, 0);
1382116491Sharti
1383116491Sharti	/* Interrupt queue 0 */
1384121469Sharti	kenv_getuint(sc, "irq0_size", &sc->irq_0.size,
1385116491Sharti	    HE_CONFIG_IRQ0_SIZE, 0);
1386121469Sharti	kenv_getuint(sc, "irq0_thresh", &sc->irq_0.thresh,
1387116491Sharti	    HE_CONFIG_IRQ0_THRESH, 0);
1388116491Sharti	sc->irq_0.line = HE_CONFIG_IRQ0_LINE;
1389116491Sharti
1390116491Sharti	/* Transmit buffer return queue 0 */
1391121469Sharti	kenv_getuint(sc, "tbrq0_size", &sc->tbrq.size,
1392116491Sharti	    HE_CONFIG_TBRQ_SIZE, 0);
1393121469Sharti	kenv_getuint(sc, "tbrq0_thresh", &sc->tbrq.thresh,
1394116491Sharti	    HE_CONFIG_TBRQ_THRESH, 0);
1395116491Sharti
1396116491Sharti	/* Transmit buffer ready queue */
1397121469Sharti	kenv_getuint(sc, "tpdrq_size", &sc->tpdrq.size,
1398116491Sharti	    HE_CONFIG_TPDRQ_SIZE, 0);
1399116491Sharti	/* Max TPDs per VCC */
1400116491Sharti	kenv_getuint(sc, "tpdmax", &sc->max_tpd,
1401116491Sharti	    HE_CONFIG_TPD_MAXCC, 0);
1402116491Sharti
1403121685Sharti	/* external mbuf pages */
1404121685Sharti	kenv_getuint(sc, "max_mbuf_pages", &sc->mbuf_max_pages,
1405121685Sharti	    HE_CONFIG_MAX_MBUF_PAGES, 0);
1406121685Sharti
1407122113Sharti	/* mpsafe */
1408122113Sharti	kenv_getuint(sc, "mpsafe", &sc->mpsafe, 0, 0);
1409122113Sharti	if (sc->mpsafe != 0)
1410122113Sharti		sc->mpsafe = INTR_MPSAFE;
1411122113Sharti
1412116491Sharti	return (0);
1413116491Sharti}
1414116491Sharti
1415116491Sharti#ifdef HATM_DEBUG
1416116491Sharti
1417116491Sharti/*
1418116491Sharti * Get TSRs from connection memory
1419116491Sharti */
1420116491Shartistatic int
1421116491Shartihatm_sysctl_tsr(SYSCTL_HANDLER_ARGS)
1422116491Sharti{
1423116491Sharti	struct hatm_softc *sc = arg1;
1424116491Sharti	int error, i, j;
1425116491Sharti	uint32_t *val;
1426116491Sharti
1427116491Sharti	val = malloc(sizeof(uint32_t) * HE_MAX_VCCS * 15, M_TEMP, M_WAITOK);
1428116491Sharti
1429116491Sharti	mtx_lock(&sc->mtx);
1430116491Sharti	for (i = 0; i < HE_MAX_VCCS; i++)
1431116491Sharti		for (j = 0; j <= 14; j++)
1432116491Sharti			val[15 * i + j] = READ_TSR(sc, i, j);
1433116491Sharti	mtx_unlock(&sc->mtx);
1434116491Sharti
1435116491Sharti	error = SYSCTL_OUT(req, val, sizeof(uint32_t) * HE_MAX_VCCS * 15);
1436116491Sharti	free(val, M_TEMP);
1437116491Sharti	if (error != 0 || req->newptr == NULL)
1438116491Sharti		return (error);
1439116491Sharti
1440116491Sharti	return (EPERM);
1441116491Sharti}
1442116491Sharti
1443116491Sharti/*
1444116491Sharti * Get TPDs from connection memory
1445116491Sharti */
1446116491Shartistatic int
1447116491Shartihatm_sysctl_tpd(SYSCTL_HANDLER_ARGS)
1448116491Sharti{
1449116491Sharti	struct hatm_softc *sc = arg1;
1450116491Sharti	int error, i, j;
1451116491Sharti	uint32_t *val;
1452116491Sharti
1453116491Sharti	val = malloc(sizeof(uint32_t) * HE_MAX_VCCS * 16, M_TEMP, M_WAITOK);
1454116491Sharti
1455116491Sharti	mtx_lock(&sc->mtx);
1456116491Sharti	for (i = 0; i < HE_MAX_VCCS; i++)
1457116491Sharti		for (j = 0; j < 16; j++)
1458116491Sharti			val[16 * i + j] = READ_TCM4(sc, 16 * i + j);
1459116491Sharti	mtx_unlock(&sc->mtx);
1460116491Sharti
1461116491Sharti	error = SYSCTL_OUT(req, val, sizeof(uint32_t) * HE_MAX_VCCS * 16);
1462116491Sharti	free(val, M_TEMP);
1463116491Sharti	if (error != 0 || req->newptr == NULL)
1464116491Sharti		return (error);
1465116491Sharti
1466116491Sharti	return (EPERM);
1467116491Sharti}
1468116491Sharti
1469116491Sharti/*
1470116491Sharti * Get mbox registers
1471116491Sharti */
1472116491Shartistatic int
1473116491Shartihatm_sysctl_mbox(SYSCTL_HANDLER_ARGS)
1474116491Sharti{
1475116491Sharti	struct hatm_softc *sc = arg1;
1476116491Sharti	int error, i;
1477116491Sharti	uint32_t *val;
1478116491Sharti
1479116491Sharti	val = malloc(sizeof(uint32_t) * HE_REGO_CS_END, M_TEMP, M_WAITOK);
1480116491Sharti
1481116491Sharti	mtx_lock(&sc->mtx);
1482116491Sharti	for (i = 0; i < HE_REGO_CS_END; i++)
1483116491Sharti		val[i] = READ_MBOX4(sc, i);
1484116491Sharti	mtx_unlock(&sc->mtx);
1485116491Sharti
1486116491Sharti	error = SYSCTL_OUT(req, val, sizeof(uint32_t) * HE_REGO_CS_END);
1487116491Sharti	free(val, M_TEMP);
1488116491Sharti	if (error != 0 || req->newptr == NULL)
1489116491Sharti		return (error);
1490116491Sharti
1491116491Sharti	return (EPERM);
1492116491Sharti}
1493116491Sharti
1494116491Sharti/*
1495116491Sharti * Get connection memory
1496116491Sharti */
1497116491Shartistatic int
1498116491Shartihatm_sysctl_cm(SYSCTL_HANDLER_ARGS)
1499116491Sharti{
1500116491Sharti	struct hatm_softc *sc = arg1;
1501116491Sharti	int error, i;
1502116491Sharti	uint32_t *val;
1503116491Sharti
1504116491Sharti	val = malloc(sizeof(uint32_t) * (HE_CONFIG_RXMEM + 1), M_TEMP, M_WAITOK);
1505116491Sharti
1506116491Sharti	mtx_lock(&sc->mtx);
1507116491Sharti	val[0] = READ4(sc, HE_REGO_RCMABR_BA);
1508116491Sharti	for (i = 0; i < HE_CONFIG_RXMEM; i++)
1509116491Sharti		val[i + 1] = READ_RCM4(sc, i);
1510116491Sharti	mtx_unlock(&sc->mtx);
1511116491Sharti
1512116491Sharti	error = SYSCTL_OUT(req, val, sizeof(uint32_t) * (HE_CONFIG_RXMEM + 1));
1513116491Sharti	free(val, M_TEMP);
1514116491Sharti	if (error != 0 || req->newptr == NULL)
1515116491Sharti		return (error);
1516116491Sharti
1517116491Sharti	return (EPERM);
1518116491Sharti}
1519116491Sharti
1520116491Sharti/*
1521116491Sharti * Get local buffer memory
1522116491Sharti */
1523116491Shartistatic int
1524116491Shartihatm_sysctl_lbmem(SYSCTL_HANDLER_ARGS)
1525116491Sharti{
1526116491Sharti	struct hatm_softc *sc = arg1;
1527116491Sharti	int error, i;
1528116491Sharti	uint32_t *val;
1529116491Sharti	u_int bytes = (1 << 21);
1530116491Sharti
1531116491Sharti	val = malloc(bytes, M_TEMP, M_WAITOK);
1532116491Sharti
1533116491Sharti	mtx_lock(&sc->mtx);
1534116491Sharti	for (i = 0; i < bytes / 4; i++)
1535116491Sharti		val[i] = READ_LB4(sc, i);
1536116491Sharti	mtx_unlock(&sc->mtx);
1537116491Sharti
1538116491Sharti	error = SYSCTL_OUT(req, val, bytes);
1539116491Sharti	free(val, M_TEMP);
1540116491Sharti	if (error != 0 || req->newptr == NULL)
1541116491Sharti		return (error);
1542116491Sharti
1543116491Sharti	return (EPERM);
1544116491Sharti}
1545116491Sharti
1546116491Sharti/*
1547116491Sharti * Get all card registers
1548116491Sharti */
1549116491Shartistatic int
1550116491Shartihatm_sysctl_heregs(SYSCTL_HANDLER_ARGS)
1551116491Sharti{
1552116491Sharti	struct hatm_softc *sc = arg1;
1553116491Sharti	int error, i;
1554116491Sharti	uint32_t *val;
1555116491Sharti
1556116491Sharti	val = malloc(HE_REGO_END, M_TEMP, M_WAITOK);
1557116491Sharti
1558116491Sharti	mtx_lock(&sc->mtx);
1559116491Sharti	for (i = 0; i < HE_REGO_END; i += 4)
1560116491Sharti		val[i / 4] = READ4(sc, i);
1561116491Sharti	mtx_unlock(&sc->mtx);
1562116491Sharti
1563116491Sharti	error = SYSCTL_OUT(req, val, HE_REGO_END);
1564116491Sharti	free(val, M_TEMP);
1565116491Sharti	if (error != 0 || req->newptr == NULL)
1566116491Sharti		return (error);
1567116491Sharti
1568116491Sharti	return (EPERM);
1569116491Sharti}
1570116491Sharti#endif
1571116491Sharti
1572116491Sharti/*
1573116491Sharti * Suni register access
1574116491Sharti */
1575116491Sharti/*
1576116491Sharti * read at most n SUNI registers starting at reg into val
1577116491Sharti */
1578116491Shartistatic int
1579116491Shartihatm_utopia_readregs(struct ifatm *ifatm, u_int reg, uint8_t *val, u_int *n)
1580116491Sharti{
1581116491Sharti	u_int i;
1582147721Sharti	struct hatm_softc *sc = ifatm->ifp->if_softc;
1583116491Sharti
1584116491Sharti	if (reg >= (HE_REGO_SUNI_END - HE_REGO_SUNI) / 4)
1585116491Sharti		return (EINVAL);
1586116491Sharti	if (reg + *n > (HE_REGO_SUNI_END - HE_REGO_SUNI) / 4)
1587116491Sharti		*n = reg - (HE_REGO_SUNI_END - HE_REGO_SUNI) / 4;
1588116491Sharti
1589116491Sharti	mtx_assert(&sc->mtx, MA_OWNED);
1590116491Sharti	for (i = 0; i < *n; i++)
1591116491Sharti		val[i] = READ4(sc, HE_REGO_SUNI + 4 * (reg + i));
1592116491Sharti
1593116491Sharti	return (0);
1594116491Sharti}
1595116491Sharti
1596116491Sharti/*
1597116491Sharti * change the bits given by mask to them in val in register reg
1598116491Sharti */
1599116491Shartistatic int
1600116491Shartihatm_utopia_writereg(struct ifatm *ifatm, u_int reg, u_int mask, u_int val)
1601116491Sharti{
1602116491Sharti	uint32_t regval;
1603147721Sharti	struct hatm_softc *sc = ifatm->ifp->if_softc;
1604116491Sharti
1605116491Sharti	if (reg >= (HE_REGO_SUNI_END - HE_REGO_SUNI) / 4)
1606116491Sharti		return (EINVAL);
1607116491Sharti
1608116491Sharti	mtx_assert(&sc->mtx, MA_OWNED);
1609116491Sharti	regval = READ4(sc, HE_REGO_SUNI + 4 * reg);
1610116491Sharti	regval = (regval & ~mask) | (val & mask);
1611116491Sharti	WRITE4(sc, HE_REGO_SUNI + 4 * reg, regval);
1612116491Sharti
1613116491Sharti	return (0);
1614116491Sharti}
1615116491Sharti
1616116491Shartistatic struct utopia_methods hatm_utopia_methods = {
1617116491Sharti	hatm_utopia_readregs,
1618116491Sharti	hatm_utopia_writereg,
1619116491Sharti};
1620116491Sharti
1621116491Sharti/*
1622116491Sharti * Detach - if it is running, stop. Destroy.
1623116491Sharti */
1624116491Shartistatic int
1625116491Shartihatm_detach(device_t dev)
1626116491Sharti{
1627147721Sharti	struct hatm_softc *sc = device_get_softc(dev);
1628116491Sharti
1629116491Sharti	mtx_lock(&sc->mtx);
1630116491Sharti	hatm_stop(sc);
1631116491Sharti	if (sc->utopia.state & UTP_ST_ATTACHED) {
1632116491Sharti		utopia_stop(&sc->utopia);
1633116491Sharti		utopia_detach(&sc->utopia);
1634116491Sharti	}
1635116491Sharti	mtx_unlock(&sc->mtx);
1636116491Sharti
1637147256Sbrooks	atm_ifdetach(sc->ifp);
1638116491Sharti
1639116491Sharti	hatm_destroy(sc);
1640116491Sharti
1641116491Sharti	return (0);
1642116491Sharti}
1643116491Sharti
1644116491Sharti/*
1645116491Sharti * Attach to the device. Assume that no locking is needed here.
1646116491Sharti * All resource we allocate here are freed by calling hatm_destroy.
1647116491Sharti */
1648116491Shartistatic int
1649116491Shartihatm_attach(device_t dev)
1650116491Sharti{
1651116491Sharti	struct hatm_softc *sc;
1652116491Sharti	int error;
1653116491Sharti	uint32_t v;
1654116491Sharti	struct ifnet *ifp;
1655116491Sharti
1656116491Sharti	sc = device_get_softc(dev);
1657116491Sharti
1658147256Sbrooks	ifp = sc->ifp = if_alloc(IFT_ATM);
1659147256Sbrooks	if (ifp == NULL) {
1660147256Sbrooks		device_printf(dev, "could not if_alloc()\n");
1661150215Sru		return (ENOSPC);
1662147256Sbrooks	}
1663147256Sbrooks
1664116491Sharti	sc->dev = dev;
1665147256Sbrooks	IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_HE155;
1666147256Sbrooks	IFP2IFATM(sc->ifp)->mib.serial = 0;
1667147256Sbrooks	IFP2IFATM(sc->ifp)->mib.hw_version = 0;
1668147256Sbrooks	IFP2IFATM(sc->ifp)->mib.sw_version = 0;
1669147256Sbrooks	IFP2IFATM(sc->ifp)->mib.vpi_bits = HE_CONFIG_VPI_BITS;
1670147256Sbrooks	IFP2IFATM(sc->ifp)->mib.vci_bits = HE_CONFIG_VCI_BITS;
1671147256Sbrooks	IFP2IFATM(sc->ifp)->mib.max_vpcs = 0;
1672147256Sbrooks	IFP2IFATM(sc->ifp)->mib.max_vccs = HE_MAX_VCCS;
1673147256Sbrooks	IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UNKNOWN;
1674116491Sharti	sc->he622 = 0;
1675147256Sbrooks	IFP2IFATM(sc->ifp)->phy = &sc->utopia;
1676116491Sharti
1677116491Sharti	SLIST_INIT(&sc->tpd_free);
1678116491Sharti
1679116491Sharti	mtx_init(&sc->mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, MTX_DEF);
1680116491Sharti	cv_init(&sc->vcc_cv, "HEVCCcv");
1681116491Sharti	cv_init(&sc->cv_rcclose, "RCClose");
1682116491Sharti
1683116491Sharti	sysctl_ctx_init(&sc->sysctl_ctx);
1684116491Sharti
1685116491Sharti	/*
1686116491Sharti	 * 4.2 BIOS Configuration
1687116491Sharti	 */
1688116491Sharti	v = pci_read_config(dev, PCIR_COMMAND, 2);
1689254263Sscottl	v |= PCIM_CMD_BUSMASTEREN | PCIM_CMD_MWRICEN;
1690116491Sharti	pci_write_config(dev, PCIR_COMMAND, v, 2);
1691116491Sharti
1692116491Sharti	/*
1693116491Sharti	 * 4.3 PCI Bus Controller-Specific Initialisation
1694116491Sharti	 */
1695116491Sharti	v = pci_read_config(dev, HE_PCIR_GEN_CNTL_0, 4);
1696116491Sharti	v |= HE_PCIM_CTL0_MRL | HE_PCIM_CTL0_MRM | HE_PCIM_CTL0_IGNORE_TIMEOUT;
1697116491Sharti#if BYTE_ORDER == BIG_ENDIAN && 0
1698116491Sharti	v |= HE_PCIM_CTL0_BIGENDIAN;
1699116491Sharti#endif
1700116491Sharti	pci_write_config(dev, HE_PCIR_GEN_CNTL_0, v, 4);
1701116491Sharti
1702116491Sharti	/*
1703116491Sharti	 * Map memory
1704116491Sharti	 */
1705119690Sjhb	sc->memid = PCIR_BAR(0);
1706127135Snjl	sc->memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->memid,
1707127135Snjl	    RF_ACTIVE);
1708116491Sharti	if (sc->memres == NULL) {
1709116491Sharti		device_printf(dev, "could not map memory\n");
1710116491Sharti		error = ENXIO;
1711116491Sharti		goto failed;
1712116491Sharti	}
1713116491Sharti	sc->memh = rman_get_bushandle(sc->memres);
1714116491Sharti	sc->memt = rman_get_bustag(sc->memres);
1715116491Sharti
1716116491Sharti	/*
1717116491Sharti	 * ALlocate a DMA tag for subsequent allocations
1718116491Sharti	 */
1719232874Sscottl	if (bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0,
1720116491Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
1721116491Sharti	    NULL, NULL,
1722116491Sharti	    BUS_SPACE_MAXSIZE_32BIT, 1,
1723117126Sscottl	    BUS_SPACE_MAXSIZE_32BIT, 0,
1724117382Sharti	    NULL, NULL, &sc->parent_tag)) {
1725116491Sharti		device_printf(dev, "could not allocate DMA tag\n");
1726116491Sharti		error = ENOMEM;
1727116491Sharti		goto failed;
1728116491Sharti	}
1729116491Sharti
1730116491Sharti	if (bus_dma_tag_create(sc->parent_tag, 1, 0,
1731116491Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
1732116491Sharti	    NULL, NULL,
1733116491Sharti	    MBUF_ALLOC_SIZE, 1,
1734117126Sscottl	    MBUF_ALLOC_SIZE, 0,
1735117382Sharti	    NULL, NULL, &sc->mbuf_tag)) {
1736116491Sharti		device_printf(dev, "could not allocate mbuf DMA tag\n");
1737116491Sharti		error = ENOMEM;
1738116491Sharti		goto failed;
1739116491Sharti	}
1740116491Sharti
1741116491Sharti	/*
1742116491Sharti	 * Allocate a DMA tag for packets to send. Here we have a problem with
1743116491Sharti	 * the specification of the maximum number of segments. Theoretically
1744116491Sharti	 * this would be the size of the transmit ring - 1 multiplied by 3,
1745116491Sharti	 * but this would not work. So make the maximum number of TPDs
1746116491Sharti	 * occupied by one packet a configuration parameter.
1747116491Sharti	 */
1748232874Sscottl	if (bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0,
1749116491Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
1750116491Sharti	    HE_MAX_PDU, 3 * HE_CONFIG_MAX_TPD_PER_PACKET, HE_MAX_PDU, 0,
1751117382Sharti	    NULL, NULL, &sc->tx_tag)) {
1752116491Sharti		device_printf(dev, "could not allocate TX tag\n");
1753116491Sharti		error = ENOMEM;
1754116491Sharti		goto failed;
1755116491Sharti	}
1756116491Sharti
1757116491Sharti	/*
1758116491Sharti	 * Setup the interrupt
1759116491Sharti	 */
1760116491Sharti	sc->irqid = 0;
1761127135Snjl	sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
1762127135Snjl	    RF_SHAREABLE | RF_ACTIVE);
1763116491Sharti	if (sc->irqres == 0) {
1764116491Sharti		device_printf(dev, "could not allocate irq\n");
1765116491Sharti		error = ENXIO;
1766116491Sharti		goto failed;
1767116491Sharti	}
1768116491Sharti
1769116491Sharti	ifp->if_softc = sc;
1770121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1771116491Sharti
1772116491Sharti	/*
1773116491Sharti	 * Make the sysctl tree
1774116491Sharti	 */
1775116491Sharti	error = ENOMEM;
1776116491Sharti	if ((sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
1777116491Sharti	    SYSCTL_STATIC_CHILDREN(_hw_atm), OID_AUTO,
1778116491Sharti	    device_get_nameunit(dev), CTLFLAG_RD, 0, "")) == NULL)
1779116491Sharti		goto failed;
1780116491Sharti
1781116491Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
1782116491Sharti	    OID_AUTO, "istats", CTLFLAG_RD | CTLTYPE_OPAQUE, sc, CTL_ISTATS,
1783116491Sharti	    hatm_sysctl, "LU", "internal statistics") == NULL)
1784116491Sharti		goto failed;
1785116491Sharti
1786116491Sharti#ifdef HATM_DEBUG
1787116491Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
1788116491Sharti	    OID_AUTO, "tsr", CTLFLAG_RD | CTLTYPE_OPAQUE, sc, 0,
1789116491Sharti	    hatm_sysctl_tsr, "S", "transmission status registers") == NULL)
1790116491Sharti		goto failed;
1791116491Sharti
1792116491Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
1793116491Sharti	    OID_AUTO, "tpd", CTLFLAG_RD | CTLTYPE_OPAQUE, sc, 0,
1794116491Sharti	    hatm_sysctl_tpd, "S", "transmission packet descriptors") == NULL)
1795116491Sharti		goto failed;
1796116491Sharti
1797116491Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
1798116491Sharti	    OID_AUTO, "mbox", CTLFLAG_RD | CTLTYPE_OPAQUE, sc, 0,
1799116491Sharti	    hatm_sysctl_mbox, "S", "mbox registers") == NULL)
1800116491Sharti		goto failed;
1801116491Sharti
1802116491Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
1803116491Sharti	    OID_AUTO, "cm", CTLFLAG_RD | CTLTYPE_OPAQUE, sc, 0,
1804116491Sharti	    hatm_sysctl_cm, "S", "connection memory") == NULL)
1805116491Sharti		goto failed;
1806116491Sharti
1807116491Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
1808116491Sharti	    OID_AUTO, "heregs", CTLFLAG_RD | CTLTYPE_OPAQUE, sc, 0,
1809116491Sharti	    hatm_sysctl_heregs, "S", "card registers") == NULL)
1810116491Sharti		goto failed;
1811116491Sharti
1812116491Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
1813116491Sharti	    OID_AUTO, "lbmem", CTLFLAG_RD | CTLTYPE_OPAQUE, sc, 0,
1814116491Sharti	    hatm_sysctl_lbmem, "S", "local memory") == NULL)
1815116491Sharti		goto failed;
1816116491Sharti
1817121681Sharti	kenv_getuint(sc, "debug", &sc->debug, HATM_DEBUG, 1);
1818116491Sharti#endif
1819116491Sharti
1820116491Sharti	/*
1821116491Sharti	 * Configure
1822116491Sharti	 */
1823116491Sharti	if ((error = hatm_configure(sc)) != 0)
1824116491Sharti		goto failed;
1825116491Sharti
1826116491Sharti	/*
1827116491Sharti	 * Compute memory parameters
1828116491Sharti	 */
1829116491Sharti	if (sc->rbp_s0.size != 0) {
1830116491Sharti		sc->rbp_s0.mask = (sc->rbp_s0.size - 1) << 3;
1831116491Sharti		sc->rbp_s0.mem.size = sc->rbp_s0.size * 8;
1832116491Sharti		sc->rbp_s0.mem.align = sc->rbp_s0.mem.size;
1833116491Sharti	}
1834116491Sharti	if (sc->rbp_l0.size != 0) {
1835116491Sharti		sc->rbp_l0.mask = (sc->rbp_l0.size - 1) << 3;
1836116491Sharti		sc->rbp_l0.mem.size = sc->rbp_l0.size * 8;
1837116491Sharti		sc->rbp_l0.mem.align = sc->rbp_l0.mem.size;
1838116491Sharti	}
1839116491Sharti	if (sc->rbp_s1.size != 0) {
1840116491Sharti		sc->rbp_s1.mask = (sc->rbp_s1.size - 1) << 3;
1841116491Sharti		sc->rbp_s1.mem.size = sc->rbp_s1.size * 8;
1842116491Sharti		sc->rbp_s1.mem.align = sc->rbp_s1.mem.size;
1843116491Sharti	}
1844116491Sharti	if (sc->rbrq_0.size != 0) {
1845116491Sharti		sc->rbrq_0.mem.size = sc->rbrq_0.size * 8;
1846116491Sharti		sc->rbrq_0.mem.align = sc->rbrq_0.mem.size;
1847116491Sharti	}
1848116491Sharti	if (sc->rbrq_1.size != 0) {
1849116491Sharti		sc->rbrq_1.mem.size = sc->rbrq_1.size * 8;
1850116491Sharti		sc->rbrq_1.mem.align = sc->rbrq_1.mem.size;
1851116491Sharti	}
1852116491Sharti
1853116491Sharti	sc->irq_0.mem.size = sc->irq_0.size * sizeof(uint32_t);
1854116491Sharti	sc->irq_0.mem.align = 4 * 1024;
1855116491Sharti
1856116491Sharti	sc->tbrq.mem.size = sc->tbrq.size * 4;
1857116491Sharti	sc->tbrq.mem.align = 2 * sc->tbrq.mem.size; /* ZZZ */
1858116491Sharti
1859116491Sharti	sc->tpdrq.mem.size = sc->tpdrq.size * 8;
1860116491Sharti	sc->tpdrq.mem.align = sc->tpdrq.mem.size;
1861116491Sharti
1862116491Sharti	sc->hsp_mem.size = sizeof(struct he_hsp);
1863116491Sharti	sc->hsp_mem.align = 1024;
1864116491Sharti
1865116491Sharti	sc->lbufs_size = sc->rbp_l0.size + sc->rbrq_0.size;
1866116491Sharti	sc->tpd_total = sc->tbrq.size + sc->tpdrq.size;
1867116491Sharti	sc->tpds.align = 64;
1868116491Sharti	sc->tpds.size = sc->tpd_total * HE_TPD_SIZE;
1869116491Sharti
1870116491Sharti	hatm_init_rmaps(sc);
1871116491Sharti	hatm_init_smbufs(sc);
1872116491Sharti	if ((error = hatm_init_tpds(sc)) != 0)
1873116491Sharti		goto failed;
1874116491Sharti
1875116491Sharti	/*
1876116491Sharti	 * Allocate memory
1877116491Sharti	 */
1878116491Sharti	if ((error = hatm_alloc_dmamem(sc, "IRQ", &sc->irq_0.mem)) != 0 ||
1879116491Sharti	    (error = hatm_alloc_dmamem(sc, "TBRQ0", &sc->tbrq.mem)) != 0 ||
1880116491Sharti	    (error = hatm_alloc_dmamem(sc, "TPDRQ", &sc->tpdrq.mem)) != 0 ||
1881116491Sharti	    (error = hatm_alloc_dmamem(sc, "HSP", &sc->hsp_mem)) != 0)
1882116491Sharti		goto failed;
1883116491Sharti
1884116491Sharti	if (sc->rbp_s0.mem.size != 0 &&
1885116491Sharti	    (error = hatm_alloc_dmamem(sc, "RBPS0", &sc->rbp_s0.mem)))
1886116491Sharti		goto failed;
1887116491Sharti	if (sc->rbp_l0.mem.size != 0 &&
1888116491Sharti	    (error = hatm_alloc_dmamem(sc, "RBPL0", &sc->rbp_l0.mem)))
1889116491Sharti		goto failed;
1890116491Sharti	if (sc->rbp_s1.mem.size != 0 &&
1891116491Sharti	    (error = hatm_alloc_dmamem(sc, "RBPS1", &sc->rbp_s1.mem)))
1892116491Sharti		goto failed;
1893116491Sharti
1894116491Sharti	if (sc->rbrq_0.mem.size != 0 &&
1895116491Sharti	    (error = hatm_alloc_dmamem(sc, "RBRQ0", &sc->rbrq_0.mem)))
1896116491Sharti		goto failed;
1897116491Sharti	if (sc->rbrq_1.mem.size != 0 &&
1898116491Sharti	    (error = hatm_alloc_dmamem(sc, "RBRQ1", &sc->rbrq_1.mem)))
1899116491Sharti		goto failed;
1900116491Sharti
1901116491Sharti	if ((sc->vcc_zone = uma_zcreate("HE vccs", sizeof(struct hevcc),
1902116491Sharti	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0)) == NULL) {
1903116491Sharti		device_printf(dev, "cannot allocate zone for vccs\n");
1904116491Sharti		goto failed;
1905116491Sharti	}
1906116491Sharti
1907116491Sharti	/*
1908116491Sharti	 * 4.4 Reset the card.
1909116491Sharti	 */
1910116491Sharti	if ((error = hatm_reset(sc)) != 0)
1911116491Sharti		goto failed;
1912116491Sharti
1913116491Sharti	/*
1914116491Sharti	 * Read the prom.
1915116491Sharti	 */
1916116491Sharti	hatm_init_bus_width(sc);
1917116491Sharti	hatm_init_read_eeprom(sc);
1918116491Sharti	hatm_init_endianess(sc);
1919116491Sharti
1920116491Sharti	/*
1921116491Sharti	 * Initialize interface
1922116491Sharti	 */
1923116491Sharti	ifp->if_flags = IFF_SIMPLEX;
1924116491Sharti	ifp->if_ioctl = hatm_ioctl;
1925116491Sharti	ifp->if_start = hatm_start;
1926116491Sharti	ifp->if_init = hatm_init;
1927116491Sharti
1928147256Sbrooks	utopia_attach(&sc->utopia, IFP2IFATM(sc->ifp), &sc->media, &sc->mtx,
1929116491Sharti	    &sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
1930116491Sharti	    &hatm_utopia_methods);
1931116491Sharti	utopia_init_media(&sc->utopia);
1932116491Sharti
1933116491Sharti	/* these two SUNI routines need the lock */
1934116491Sharti	mtx_lock(&sc->mtx);
1935116491Sharti	/* poll while we are not running */
1936116491Sharti	sc->utopia.flags |= UTP_FL_POLL_CARRIER;
1937116491Sharti	utopia_start(&sc->utopia);
1938116491Sharti	utopia_reset(&sc->utopia);
1939116491Sharti	mtx_unlock(&sc->mtx);
1940116491Sharti
1941116491Sharti	atm_ifattach(ifp);
1942116491Sharti
1943116491Sharti#ifdef ENABLE_BPF
1944116491Sharti	bpfattach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
1945116491Sharti#endif
1946116491Sharti
1947122113Sharti	error = bus_setup_intr(dev, sc->irqres, sc->mpsafe | INTR_TYPE_NET,
1948166901Spiso	    NULL, hatm_intr, &sc->irq_0, &sc->ih);
1949116491Sharti	if (error != 0) {
1950116491Sharti		device_printf(dev, "could not setup interrupt\n");
1951116491Sharti		hatm_detach(dev);
1952116491Sharti		return (error);
1953116491Sharti	}
1954116491Sharti
1955116491Sharti	return (0);
1956116491Sharti
1957116491Sharti  failed:
1958116491Sharti	hatm_destroy(sc);
1959116491Sharti	return (error);
1960116491Sharti}
1961116491Sharti
1962116491Sharti/*
1963116491Sharti * Start the interface. Assume a state as from attach().
1964116491Sharti */
1965116491Shartivoid
1966116491Shartihatm_initialize(struct hatm_softc *sc)
1967116491Sharti{
1968116491Sharti	uint32_t v;
1969118598Sharti	u_int cid;
1970116491Sharti	static const u_int layout[2][7] = HE_CONFIG_MEM_LAYOUT;
1971116491Sharti
1972148887Srwatson	if (sc->ifp->if_drv_flags & IFF_DRV_RUNNING)
1973116491Sharti		return;
1974116491Sharti
1975116491Sharti	hatm_init_bus_width(sc);
1976116491Sharti	hatm_init_endianess(sc);
1977116491Sharti
1978147256Sbrooks	if_printf(sc->ifp, "%s, Rev. %s, S/N %u, "
1979116491Sharti	    "MAC=%02x:%02x:%02x:%02x:%02x:%02x (%ubit PCI)\n",
1980147256Sbrooks	    sc->prod_id, sc->rev, IFP2IFATM(sc->ifp)->mib.serial,
1981147256Sbrooks	    IFP2IFATM(sc->ifp)->mib.esi[0], IFP2IFATM(sc->ifp)->mib.esi[1], IFP2IFATM(sc->ifp)->mib.esi[2],
1982147256Sbrooks	    IFP2IFATM(sc->ifp)->mib.esi[3], IFP2IFATM(sc->ifp)->mib.esi[4], IFP2IFATM(sc->ifp)->mib.esi[5],
1983116491Sharti	    sc->pci64 ? 64 : 32);
1984116491Sharti
1985116491Sharti	/*
1986116491Sharti	 * 4.8 SDRAM Controller Initialisation
1987116491Sharti	 * 4.9 Initialize RNUM value
1988116491Sharti	 */
1989116491Sharti	if (sc->he622)
1990116491Sharti		WRITE4(sc, HE_REGO_SDRAM_CNTL, HE_REGM_SDRAM_64BIT);
1991116491Sharti	else
1992116491Sharti		WRITE4(sc, HE_REGO_SDRAM_CNTL, 0);
1993116491Sharti	BARRIER_W(sc);
1994116491Sharti
1995116491Sharti	v = READ4(sc, HE_REGO_LB_SWAP);
1996116491Sharti	BARRIER_R(sc);
1997116491Sharti	v |= 0xf << HE_REGS_LBSWAP_RNUM;
1998116491Sharti	WRITE4(sc, HE_REGO_LB_SWAP, v);
1999116491Sharti	BARRIER_W(sc);
2000116491Sharti
2001116491Sharti	hatm_init_irq(sc, &sc->irq_0, 0);
2002116491Sharti	hatm_clear_irq(sc, 1);
2003116491Sharti	hatm_clear_irq(sc, 2);
2004116491Sharti	hatm_clear_irq(sc, 3);
2005116491Sharti
2006116491Sharti	WRITE4(sc, HE_REGO_GRP_1_0_MAP, 0);
2007116491Sharti	WRITE4(sc, HE_REGO_GRP_3_2_MAP, 0);
2008116491Sharti	WRITE4(sc, HE_REGO_GRP_5_4_MAP, 0);
2009116491Sharti	WRITE4(sc, HE_REGO_GRP_7_6_MAP, 0);
2010116491Sharti	BARRIER_W(sc);
2011116491Sharti
2012116491Sharti	/*
2013116491Sharti	 * 4.11 Enable PCI Bus Controller State Machine
2014116491Sharti	 */
2015116491Sharti	v = READ4(sc, HE_REGO_HOST_CNTL);
2016116491Sharti	BARRIER_R(sc);
2017116491Sharti	v |= HE_REGM_HOST_OUTFF_ENB | HE_REGM_HOST_CMDFF_ENB |
2018116491Sharti	    HE_REGM_HOST_QUICK_RD | HE_REGM_HOST_QUICK_WR;
2019116491Sharti	WRITE4(sc, HE_REGO_HOST_CNTL, v);
2020116491Sharti	BARRIER_W(sc);
2021116491Sharti
2022116491Sharti	/*
2023116491Sharti	 * 5.1.1 Generic configuration state
2024116491Sharti	 */
2025116491Sharti	sc->cells_per_row = layout[sc->he622][0];
2026116491Sharti	sc->bytes_per_row = layout[sc->he622][1];
2027116491Sharti	sc->r0_numrows = layout[sc->he622][2];
2028116491Sharti	sc->tx_numrows = layout[sc->he622][3];
2029116491Sharti	sc->r1_numrows = layout[sc->he622][4];
2030116491Sharti	sc->r0_startrow = layout[sc->he622][5];
2031116491Sharti	sc->tx_startrow = sc->r0_startrow + sc->r0_numrows;
2032116491Sharti	sc->r1_startrow = sc->tx_startrow + sc->tx_numrows;
2033116491Sharti	sc->cells_per_lbuf = layout[sc->he622][6];
2034116491Sharti
2035116491Sharti	sc->r0_numbuffs = sc->r0_numrows * (sc->cells_per_row /
2036116491Sharti	    sc->cells_per_lbuf);
2037116491Sharti	sc->r1_numbuffs = sc->r1_numrows * (sc->cells_per_row /
2038116491Sharti	    sc->cells_per_lbuf);
2039116491Sharti	sc->tx_numbuffs = sc->tx_numrows * (sc->cells_per_row /
2040116491Sharti	    sc->cells_per_lbuf);
2041116491Sharti
2042116491Sharti	if (sc->r0_numbuffs > 2560)
2043116491Sharti		sc->r0_numbuffs = 2560;
2044116491Sharti	if (sc->r1_numbuffs > 2560)
2045116491Sharti		sc->r1_numbuffs = 2560;
2046116491Sharti	if (sc->tx_numbuffs > 5120)
2047116491Sharti		sc->tx_numbuffs = 5120;
2048116491Sharti
2049116491Sharti	DBG(sc, ATTACH, ("cells_per_row=%u bytes_per_row=%u r0_numrows=%u "
2050116491Sharti	    "tx_numrows=%u r1_numrows=%u r0_startrow=%u tx_startrow=%u "
2051116491Sharti	    "r1_startrow=%u cells_per_lbuf=%u\nr0_numbuffs=%u r1_numbuffs=%u "
2052116491Sharti	    "tx_numbuffs=%u\n", sc->cells_per_row, sc->bytes_per_row,
2053116491Sharti	    sc->r0_numrows, sc->tx_numrows, sc->r1_numrows, sc->r0_startrow,
2054116491Sharti	    sc->tx_startrow, sc->r1_startrow, sc->cells_per_lbuf,
2055116491Sharti	    sc->r0_numbuffs, sc->r1_numbuffs, sc->tx_numbuffs));
2056116491Sharti
2057116491Sharti	/*
2058116491Sharti	 * 5.1.2 Configure Hardware dependend registers
2059116491Sharti	 */
2060116491Sharti	if (sc->he622) {
2061116491Sharti		WRITE4(sc, HE_REGO_LBARB,
2062116491Sharti		    (0x2 << HE_REGS_LBARB_SLICE) |
2063116491Sharti		    (0xf << HE_REGS_LBARB_RNUM) |
2064116491Sharti		    (0x3 << HE_REGS_LBARB_THPRI) |
2065116491Sharti		    (0x3 << HE_REGS_LBARB_RHPRI) |
2066116491Sharti		    (0x2 << HE_REGS_LBARB_TLPRI) |
2067116491Sharti		    (0x1 << HE_REGS_LBARB_RLPRI) |
2068116491Sharti		    (0x28 << HE_REGS_LBARB_BUS_MULT) |
2069116491Sharti		    (0x50 << HE_REGS_LBARB_NET_PREF));
2070116491Sharti		BARRIER_W(sc);
2071116491Sharti		WRITE4(sc, HE_REGO_SDRAMCON,
2072116491Sharti		    /* HW bug: don't use banking */
2073116491Sharti		    /* HE_REGM_SDRAMCON_BANK | */
2074116491Sharti		    HE_REGM_SDRAMCON_WIDE |
2075116491Sharti		    (0x384 << HE_REGS_SDRAMCON_REF));
2076116491Sharti		BARRIER_W(sc);
2077116491Sharti		WRITE4(sc, HE_REGO_RCMCONFIG,
2078116491Sharti		    (0x1 << HE_REGS_RCMCONFIG_BANK_WAIT) |
2079116491Sharti		    (0x1 << HE_REGS_RCMCONFIG_RW_WAIT) |
2080116491Sharti		    (0x0 << HE_REGS_RCMCONFIG_TYPE));
2081116491Sharti		WRITE4(sc, HE_REGO_TCMCONFIG,
2082116491Sharti		    (0x2 << HE_REGS_TCMCONFIG_BANK_WAIT) |
2083116491Sharti		    (0x1 << HE_REGS_TCMCONFIG_RW_WAIT) |
2084116491Sharti		    (0x0 << HE_REGS_TCMCONFIG_TYPE));
2085116491Sharti	} else {
2086116491Sharti		WRITE4(sc, HE_REGO_LBARB,
2087116491Sharti		    (0x2 << HE_REGS_LBARB_SLICE) |
2088116491Sharti		    (0xf << HE_REGS_LBARB_RNUM) |
2089116491Sharti		    (0x3 << HE_REGS_LBARB_THPRI) |
2090116491Sharti		    (0x3 << HE_REGS_LBARB_RHPRI) |
2091116491Sharti		    (0x2 << HE_REGS_LBARB_TLPRI) |
2092116491Sharti		    (0x1 << HE_REGS_LBARB_RLPRI) |
2093116491Sharti		    (0x46 << HE_REGS_LBARB_BUS_MULT) |
2094116491Sharti		    (0x8C << HE_REGS_LBARB_NET_PREF));
2095116491Sharti		BARRIER_W(sc);
2096116491Sharti		WRITE4(sc, HE_REGO_SDRAMCON,
2097116491Sharti		    /* HW bug: don't use banking */
2098116491Sharti		    /* HE_REGM_SDRAMCON_BANK | */
2099116491Sharti		    (0x150 << HE_REGS_SDRAMCON_REF));
2100116491Sharti		BARRIER_W(sc);
2101116491Sharti		WRITE4(sc, HE_REGO_RCMCONFIG,
2102116491Sharti		    (0x0 << HE_REGS_RCMCONFIG_BANK_WAIT) |
2103116491Sharti		    (0x1 << HE_REGS_RCMCONFIG_RW_WAIT) |
2104116491Sharti		    (0x0 << HE_REGS_RCMCONFIG_TYPE));
2105116491Sharti		WRITE4(sc, HE_REGO_TCMCONFIG,
2106116491Sharti		    (0x1 << HE_REGS_TCMCONFIG_BANK_WAIT) |
2107116491Sharti		    (0x1 << HE_REGS_TCMCONFIG_RW_WAIT) |
2108116491Sharti		    (0x0 << HE_REGS_TCMCONFIG_TYPE));
2109116491Sharti	}
2110116491Sharti	WRITE4(sc, HE_REGO_LBCONFIG, (sc->cells_per_lbuf * 48));
2111116491Sharti
2112116491Sharti	WRITE4(sc, HE_REGO_RLBC_H, 0);
2113116491Sharti	WRITE4(sc, HE_REGO_RLBC_T, 0);
2114116491Sharti	WRITE4(sc, HE_REGO_RLBC_H2, 0);
2115116491Sharti
2116116491Sharti	WRITE4(sc, HE_REGO_RXTHRSH, 512);
2117116491Sharti	WRITE4(sc, HE_REGO_LITHRSH, 256);
2118116491Sharti
2119116491Sharti	WRITE4(sc, HE_REGO_RLBF0_C, sc->r0_numbuffs);
2120116491Sharti	WRITE4(sc, HE_REGO_RLBF1_C, sc->r1_numbuffs);
2121116491Sharti
2122116491Sharti	if (sc->he622) {
2123116491Sharti		WRITE4(sc, HE_REGO_RCCONFIG,
2124116491Sharti		    (8 << HE_REGS_RCCONFIG_UTDELAY) |
2125147256Sbrooks		    (IFP2IFATM(sc->ifp)->mib.vpi_bits << HE_REGS_RCCONFIG_VP) |
2126147256Sbrooks		    (IFP2IFATM(sc->ifp)->mib.vci_bits << HE_REGS_RCCONFIG_VC));
2127116491Sharti		WRITE4(sc, HE_REGO_TXCONFIG,
2128116491Sharti		    (32 << HE_REGS_TXCONFIG_THRESH) |
2129147256Sbrooks		    (IFP2IFATM(sc->ifp)->mib.vci_bits << HE_REGS_TXCONFIG_VCI_MASK) |
2130116491Sharti		    (sc->tx_numbuffs << HE_REGS_TXCONFIG_LBFREE));
2131116491Sharti	} else {
2132116491Sharti		WRITE4(sc, HE_REGO_RCCONFIG,
2133116491Sharti		    (0 << HE_REGS_RCCONFIG_UTDELAY) |
2134116491Sharti		    HE_REGM_RCCONFIG_UT_MODE |
2135147256Sbrooks		    (IFP2IFATM(sc->ifp)->mib.vpi_bits << HE_REGS_RCCONFIG_VP) |
2136147256Sbrooks		    (IFP2IFATM(sc->ifp)->mib.vci_bits << HE_REGS_RCCONFIG_VC));
2137116491Sharti		WRITE4(sc, HE_REGO_TXCONFIG,
2138116491Sharti		    (32 << HE_REGS_TXCONFIG_THRESH) |
2139116491Sharti		    HE_REGM_TXCONFIG_UTMODE |
2140147256Sbrooks		    (IFP2IFATM(sc->ifp)->mib.vci_bits << HE_REGS_TXCONFIG_VCI_MASK) |
2141116491Sharti		    (sc->tx_numbuffs << HE_REGS_TXCONFIG_LBFREE));
2142116491Sharti	}
2143116491Sharti
2144116491Sharti	WRITE4(sc, HE_REGO_TXAAL5_PROTO, 0);
2145116491Sharti
2146117382Sharti	if (sc->rbp_s1.size != 0) {
2147117382Sharti		WRITE4(sc, HE_REGO_RHCONFIG,
2148117382Sharti		    HE_REGM_RHCONFIG_PHYENB |
2149117382Sharti		    ((sc->he622 ? 0x41 : 0x31) << HE_REGS_RHCONFIG_PTMR_PRE) |
2150117382Sharti		    (1 << HE_REGS_RHCONFIG_OAM_GID));
2151117382Sharti	} else {
2152117382Sharti		WRITE4(sc, HE_REGO_RHCONFIG,
2153117382Sharti		    HE_REGM_RHCONFIG_PHYENB |
2154117382Sharti		    ((sc->he622 ? 0x41 : 0x31) << HE_REGS_RHCONFIG_PTMR_PRE) |
2155117382Sharti		    (0 << HE_REGS_RHCONFIG_OAM_GID));
2156117382Sharti	}
2157116491Sharti	BARRIER_W(sc);
2158116491Sharti
2159116491Sharti	hatm_init_cm(sc);
2160116491Sharti
2161116491Sharti	hatm_init_rx_buffer_pool(sc, 0, sc->r0_startrow, sc->r0_numbuffs);
2162116491Sharti	hatm_init_rx_buffer_pool(sc, 1, sc->r1_startrow, sc->r1_numbuffs);
2163116491Sharti	hatm_init_tx_buffer_pool(sc, sc->tx_startrow, sc->tx_numbuffs);
2164116491Sharti
2165116491Sharti	hatm_init_imed_queues(sc);
2166116491Sharti
2167116491Sharti	/*
2168116491Sharti	 * 5.1.6 Application tunable Parameters
2169116491Sharti	 */
2170116491Sharti	WRITE4(sc, HE_REGO_MCC, 0);
2171116491Sharti	WRITE4(sc, HE_REGO_OEC, 0);
2172116491Sharti	WRITE4(sc, HE_REGO_DCC, 0);
2173116491Sharti	WRITE4(sc, HE_REGO_CEC, 0);
2174116491Sharti
2175116491Sharti	hatm_init_cs_block(sc);
2176116491Sharti	hatm_init_cs_block_cm(sc);
2177116491Sharti
2178116491Sharti	hatm_init_rpool(sc, &sc->rbp_s0, 0, 0);
2179116491Sharti	hatm_init_rpool(sc, &sc->rbp_l0, 0, 1);
2180116491Sharti	hatm_init_rpool(sc, &sc->rbp_s1, 1, 0);
2181116491Sharti	hatm_clear_rpool(sc, 1, 1);
2182116491Sharti	hatm_clear_rpool(sc, 2, 0);
2183116491Sharti	hatm_clear_rpool(sc, 2, 1);
2184116491Sharti	hatm_clear_rpool(sc, 3, 0);
2185116491Sharti	hatm_clear_rpool(sc, 3, 1);
2186116491Sharti	hatm_clear_rpool(sc, 4, 0);
2187116491Sharti	hatm_clear_rpool(sc, 4, 1);
2188116491Sharti	hatm_clear_rpool(sc, 5, 0);
2189116491Sharti	hatm_clear_rpool(sc, 5, 1);
2190116491Sharti	hatm_clear_rpool(sc, 6, 0);
2191116491Sharti	hatm_clear_rpool(sc, 6, 1);
2192116491Sharti	hatm_clear_rpool(sc, 7, 0);
2193116491Sharti	hatm_clear_rpool(sc, 7, 1);
2194116491Sharti	hatm_init_rbrq(sc, &sc->rbrq_0, 0);
2195116491Sharti	hatm_init_rbrq(sc, &sc->rbrq_1, 1);
2196116491Sharti	hatm_clear_rbrq(sc, 2);
2197116491Sharti	hatm_clear_rbrq(sc, 3);
2198116491Sharti	hatm_clear_rbrq(sc, 4);
2199116491Sharti	hatm_clear_rbrq(sc, 5);
2200116491Sharti	hatm_clear_rbrq(sc, 6);
2201116491Sharti	hatm_clear_rbrq(sc, 7);
2202116491Sharti
2203116491Sharti	sc->lbufs_next = 0;
2204116491Sharti	bzero(sc->lbufs, sizeof(sc->lbufs[0]) * sc->lbufs_size);
2205116491Sharti
2206116491Sharti	hatm_init_tbrq(sc, &sc->tbrq, 0);
2207116491Sharti	hatm_clear_tbrq(sc, 1);
2208116491Sharti	hatm_clear_tbrq(sc, 2);
2209116491Sharti	hatm_clear_tbrq(sc, 3);
2210116491Sharti	hatm_clear_tbrq(sc, 4);
2211116491Sharti	hatm_clear_tbrq(sc, 5);
2212116491Sharti	hatm_clear_tbrq(sc, 6);
2213116491Sharti	hatm_clear_tbrq(sc, 7);
2214116491Sharti
2215116491Sharti	hatm_init_tpdrq(sc);
2216116491Sharti
2217116491Sharti	WRITE4(sc, HE_REGO_UBUFF_BA, (sc->he622 ? 0x104780 : 0x800));
2218116491Sharti
2219116491Sharti	/*
2220116491Sharti	 * Initialize HSP
2221116491Sharti	 */
2222116491Sharti	bzero(sc->hsp_mem.base, sc->hsp_mem.size);
2223116491Sharti	sc->hsp = sc->hsp_mem.base;
2224116491Sharti	WRITE4(sc, HE_REGO_HSP_BA, sc->hsp_mem.paddr);
2225116491Sharti
2226116491Sharti	/*
2227116491Sharti	 * 5.1.12 Enable transmit and receive
2228116491Sharti	 * Enable bus master and interrupts
2229116491Sharti	 */
2230116491Sharti	v = READ_MBOX4(sc, HE_REGO_CS_ERCTL0);
2231116491Sharti	v |= 0x18000000;
2232116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERCTL0, v);
2233116491Sharti
2234116491Sharti	v = READ4(sc, HE_REGO_RCCONFIG);
2235116491Sharti	v |= HE_REGM_RCCONFIG_RXENB;
2236116491Sharti	WRITE4(sc, HE_REGO_RCCONFIG, v);
2237116491Sharti
2238116491Sharti	v = pci_read_config(sc->dev, HE_PCIR_GEN_CNTL_0, 4);
2239116491Sharti	v |= HE_PCIM_CTL0_INIT_ENB | HE_PCIM_CTL0_INT_PROC_ENB;
2240116491Sharti	pci_write_config(sc->dev, HE_PCIR_GEN_CNTL_0, v, 4);
2241116491Sharti
2242148887Srwatson	sc->ifp->if_drv_flags |= IFF_DRV_RUNNING;
2243147256Sbrooks	sc->ifp->if_baudrate = 53 * 8 * IFP2IFATM(sc->ifp)->mib.pcr;
2244116491Sharti
2245116491Sharti	sc->utopia.flags &= ~UTP_FL_POLL_CARRIER;
2246118170Sharti
2247118598Sharti	/* reopen vccs */
2248118598Sharti	for (cid = 0; cid < HE_MAX_VCCS; cid++)
2249118598Sharti		if (sc->vccs[cid] != NULL)
2250118598Sharti			hatm_load_vc(sc, cid, 1);
2251118598Sharti
2252147256Sbrooks	ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp),
2253118170Sharti	    sc->utopia.carrier == UTP_CARR_OK);
2254116491Sharti}
2255116491Sharti
2256116491Sharti/*
2257116491Sharti * This functions stops the card and frees all resources allocated after
2258116491Sharti * the attach. Must have the global lock.
2259116491Sharti */
2260116491Shartivoid
2261116491Shartihatm_stop(struct hatm_softc *sc)
2262116491Sharti{
2263116491Sharti	uint32_t v;
2264116491Sharti	u_int i, p, cid;
2265116491Sharti	struct mbuf_chunk_hdr *ch;
2266116491Sharti	struct mbuf_page *pg;
2267116491Sharti
2268116491Sharti	mtx_assert(&sc->mtx, MA_OWNED);
2269116491Sharti
2270148887Srwatson	if (!(sc->ifp->if_drv_flags & IFF_DRV_RUNNING))
2271116491Sharti		return;
2272148887Srwatson	sc->ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2273116491Sharti
2274147256Sbrooks	ATMEV_SEND_IFSTATE_CHANGED(IFP2IFATM(sc->ifp),
2275118170Sharti	    sc->utopia.carrier == UTP_CARR_OK);
2276118170Sharti
2277116491Sharti	sc->utopia.flags |= UTP_FL_POLL_CARRIER;
2278116491Sharti
2279116491Sharti	/*
2280116491Sharti	 * Stop and reset the hardware so that everything remains
2281116491Sharti	 * stable.
2282116491Sharti	 */
2283116491Sharti	v = READ_MBOX4(sc, HE_REGO_CS_ERCTL0);
2284116491Sharti	v &= ~0x18000000;
2285116491Sharti	WRITE_MBOX4(sc, HE_REGO_CS_ERCTL0, v);
2286116491Sharti
2287116491Sharti	v = READ4(sc, HE_REGO_RCCONFIG);
2288116491Sharti	v &= ~HE_REGM_RCCONFIG_RXENB;
2289116491Sharti	WRITE4(sc, HE_REGO_RCCONFIG, v);
2290116491Sharti
2291116491Sharti	WRITE4(sc, HE_REGO_RHCONFIG, (0x2 << HE_REGS_RHCONFIG_PTMR_PRE));
2292116491Sharti	BARRIER_W(sc);
2293116491Sharti
2294116491Sharti	v = READ4(sc, HE_REGO_HOST_CNTL);
2295116491Sharti	BARRIER_R(sc);
2296116491Sharti	v &= ~(HE_REGM_HOST_OUTFF_ENB | HE_REGM_HOST_CMDFF_ENB);
2297116491Sharti	WRITE4(sc, HE_REGO_HOST_CNTL, v);
2298116491Sharti	BARRIER_W(sc);
2299116491Sharti
2300116491Sharti	/*
2301116491Sharti	 * Disable bust master and interrupts
2302116491Sharti	 */
2303116491Sharti	v = pci_read_config(sc->dev, HE_PCIR_GEN_CNTL_0, 4);
2304116491Sharti	v &= ~(HE_PCIM_CTL0_INIT_ENB | HE_PCIM_CTL0_INT_PROC_ENB);
2305116491Sharti	pci_write_config(sc->dev, HE_PCIR_GEN_CNTL_0, v, 4);
2306116491Sharti
2307116491Sharti	(void)hatm_reset(sc);
2308116491Sharti
2309116491Sharti	/*
2310117687Sharti	 * Card resets the SUNI when resetted, so re-initialize it
2311117687Sharti	 */
2312117687Sharti	utopia_reset(&sc->utopia);
2313117687Sharti
2314117687Sharti	/*
2315116491Sharti	 * Give any waiters on closing a VCC a chance. They will stop
2316148887Srwatson	 * to wait if they see that IFF_DRV_RUNNING disappeared.
2317116491Sharti	 */
2318126396Sscottl	cv_broadcast(&sc->vcc_cv);
2319126396Sscottl	cv_broadcast(&sc->cv_rcclose);
2320116491Sharti
2321116491Sharti	/*
2322116491Sharti	 * Now free all resources.
2323116491Sharti	 */
2324116491Sharti
2325116491Sharti	/*
2326116491Sharti	 * Free the large mbufs that are given to the card.
2327116491Sharti	 */
2328116491Sharti	for (i = 0 ; i < sc->lbufs_size; i++) {
2329116491Sharti		if (sc->lbufs[i] != NULL) {
2330116491Sharti			bus_dmamap_unload(sc->mbuf_tag, sc->rmaps[i]);
2331116491Sharti			m_freem(sc->lbufs[i]);
2332116491Sharti			sc->lbufs[i] = NULL;
2333116491Sharti		}
2334116491Sharti	}
2335116491Sharti
2336116491Sharti	/*
2337116491Sharti	 * Free small buffers
2338116491Sharti	 */
2339116491Sharti	for (p = 0; p < sc->mbuf_npages; p++) {
2340116491Sharti		pg = sc->mbuf_pages[p];
2341116491Sharti		for (i = 0; i < pg->hdr.nchunks; i++) {
2342121729Sharti			ch = (struct mbuf_chunk_hdr *) ((char *)pg +
2343121729Sharti			    i * pg->hdr.chunksize + pg->hdr.hdroff);
2344121729Sharti			if (ch->flags & MBUF_CARD) {
2345121729Sharti				ch->flags &= ~MBUF_CARD;
2346121729Sharti				ch->flags |= MBUF_USED;
2347121729Sharti				hatm_ext_free(&sc->mbuf_list[pg->hdr.pool],
2348121729Sharti				    (struct mbufx_free *)((u_char *)ch -
2349121729Sharti				    pg->hdr.hdroff));
2350116491Sharti			}
2351116491Sharti		}
2352116491Sharti	}
2353116491Sharti
2354116491Sharti	hatm_stop_tpds(sc);
2355116491Sharti
2356116491Sharti	/*
2357116491Sharti	 * Free all partial reassembled PDUs on any VCC.
2358116491Sharti	 */
2359116491Sharti	for (cid = 0; cid < HE_MAX_VCCS; cid++) {
2360116491Sharti		if (sc->vccs[cid] != NULL) {
2361118598Sharti			if (sc->vccs[cid]->chain != NULL) {
2362116491Sharti				m_freem(sc->vccs[cid]->chain);
2363118598Sharti				sc->vccs[cid]->chain = NULL;
2364118598Sharti				sc->vccs[cid]->last = NULL;
2365118598Sharti			}
2366118598Sharti			if (!(sc->vccs[cid]->vflags & (HE_VCC_RX_OPEN |
2367118598Sharti			    HE_VCC_TX_OPEN))) {
2368118598Sharti				hatm_tx_vcc_closed(sc, cid);
2369118598Sharti				uma_zfree(sc->vcc_zone, sc->vccs[cid]);
2370118598Sharti				sc->vccs[cid] = NULL;
2371118598Sharti				sc->open_vccs--;
2372118598Sharti			} else {
2373118598Sharti				sc->vccs[cid]->vflags = 0;
2374118598Sharti				sc->vccs[cid]->ntpds = 0;
2375118598Sharti			}
2376116491Sharti		}
2377116491Sharti	}
2378116491Sharti
2379116491Sharti	if (sc->rbp_s0.size != 0)
2380116491Sharti		bzero(sc->rbp_s0.mem.base, sc->rbp_s0.mem.size);
2381116491Sharti	if (sc->rbp_l0.size != 0)
2382116491Sharti		bzero(sc->rbp_l0.mem.base, sc->rbp_l0.mem.size);
2383116491Sharti	if (sc->rbp_s1.size != 0)
2384116491Sharti		bzero(sc->rbp_s1.mem.base, sc->rbp_s1.mem.size);
2385116491Sharti	if (sc->rbrq_0.size != 0)
2386116491Sharti		bzero(sc->rbrq_0.mem.base, sc->rbrq_0.mem.size);
2387116491Sharti	if (sc->rbrq_1.size != 0)
2388116491Sharti		bzero(sc->rbrq_1.mem.base, sc->rbrq_1.mem.size);
2389116491Sharti
2390116491Sharti	bzero(sc->tbrq.mem.base, sc->tbrq.mem.size);
2391116491Sharti	bzero(sc->tpdrq.mem.base, sc->tpdrq.mem.size);
2392116491Sharti	bzero(sc->hsp_mem.base, sc->hsp_mem.size);
2393116491Sharti}
2394116491Sharti
2395116491Sharti/************************************************************
2396116491Sharti *
2397116491Sharti * Driver infrastructure
2398116491Sharti */
2399116491Shartidevclass_t hatm_devclass;
2400116491Sharti
2401116491Shartistatic device_method_t hatm_methods[] = {
2402116491Sharti	DEVMETHOD(device_probe,		hatm_probe),
2403116491Sharti	DEVMETHOD(device_attach,	hatm_attach),
2404116491Sharti	DEVMETHOD(device_detach,	hatm_detach),
2405116491Sharti	{0,0}
2406116491Sharti};
2407116491Shartistatic driver_t hatm_driver = {
2408116491Sharti	"hatm",
2409116491Sharti	hatm_methods,
2410116491Sharti	sizeof(struct hatm_softc),
2411116491Sharti};
2412116491ShartiDRIVER_MODULE(hatm, pci, hatm_driver, hatm_devclass, NULL, 0);
2413