1139749Simp/*-
2117632Sharti * Copyright (c) 2003
3117632Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4117632Sharti * 	All rights reserved.
5117632Sharti *
6117632Sharti * Redistribution and use in source and binary forms, with or without
7117632Sharti * modification, are permitted provided that the following conditions
8117632Sharti * are met:
9117632Sharti * 1. Redistributions of source code must retain the above copyright
10117632Sharti *    notice, this list of conditions and the following disclaimer.
11117632Sharti * 2. Redistributions in binary form must reproduce the above copyright
12117632Sharti *    notice, this list of conditions and the following disclaimer in the
13117632Sharti *    documentation and/or other materials provided with the distribution.
14117632Sharti *
15117632Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16117632Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17117632Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18117632Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19117632Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20117632Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21117632Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22117632Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23117632Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24117632Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25117632Sharti * SUCH DAMAGE.
26117632Sharti *
27117632Sharti * Author: Hartmut Brandt <harti@freebsd.org>
28117632Sharti *
29117632Sharti * Driver for IDT77252 based cards like ProSum's.
30117632Sharti */
31119418Sobrien
32117632Sharti#include <sys/cdefs.h>
33117632Sharti__FBSDID("$FreeBSD: releng/10.2/sys/dev/patm/if_patm_attach.c 232874 2012-03-12 18:15:08Z scottl $");
34117632Sharti
35117632Sharti#include "opt_inet.h"
36117632Sharti#include "opt_natm.h"
37117632Sharti
38117632Sharti#include <sys/types.h>
39117632Sharti#include <sys/param.h>
40117632Sharti#include <sys/systm.h>
41117632Sharti#include <sys/malloc.h>
42117632Sharti#include <sys/kernel.h>
43117632Sharti#include <sys/bus.h>
44117632Sharti#include <sys/errno.h>
45117632Sharti#include <sys/conf.h>
46117632Sharti#include <sys/module.h>
47117632Sharti#include <sys/lock.h>
48117632Sharti#include <sys/mutex.h>
49117632Sharti#include <sys/sysctl.h>
50117632Sharti#include <sys/queue.h>
51117632Sharti#include <sys/condvar.h>
52117632Sharti#include <vm/uma.h>
53117632Sharti
54117632Sharti#include <sys/sockio.h>
55117632Sharti#include <sys/mbuf.h>
56117632Sharti#include <sys/socket.h>
57117632Sharti
58117632Sharti#include <net/if.h>
59117632Sharti#include <net/if_media.h>
60147256Sbrooks#include <net/if_types.h>
61117632Sharti#include <net/if_atm.h>
62117632Sharti#include <net/route.h>
63117632Sharti#ifdef ENABLE_BPF
64117632Sharti#include <net/bpf.h>
65117632Sharti#endif
66117632Sharti#include <netinet/in.h>
67117632Sharti#include <netinet/if_atm.h>
68117632Sharti
69117632Sharti#include <machine/bus.h>
70117632Sharti#include <machine/resource.h>
71117632Sharti#include <sys/bus.h>
72117632Sharti#include <sys/rman.h>
73117632Sharti#include <sys/mbpool.h>
74119285Simp#include <dev/pci/pcireg.h>
75119285Simp#include <dev/pci/pcivar.h>
76117632Sharti
77117632Sharti#include <dev/utopia/utopia.h>
78117632Sharti#include <dev/patm/idt77252reg.h>
79117632Sharti#include <dev/patm/if_patmvar.h>
80117632Sharti
81117632ShartiMODULE_DEPEND(patm, utopia, 1, 1, 1);
82117632ShartiMODULE_DEPEND(patm, pci, 1, 1, 1);
83117632ShartiMODULE_DEPEND(patm, atm, 1, 1, 1);
84117632ShartiMODULE_DEPEND(patm, libmbpool, 1, 1, 1);
85117632Sharti
86117632Shartidevclass_t patm_devclass;
87117632Sharti
88117632Shartistatic int patm_probe(device_t dev);
89117632Shartistatic int patm_attach(device_t dev);
90117632Shartistatic int patm_detach(device_t dev);
91117632Shartistatic device_method_t patm_methods[] = {
92117632Sharti	DEVMETHOD(device_probe,		patm_probe),
93117632Sharti	DEVMETHOD(device_attach,	patm_attach),
94117632Sharti	DEVMETHOD(device_detach,	patm_detach),
95117632Sharti	{0,0}
96117632Sharti};
97117632Shartistatic driver_t patm_driver = {
98117632Sharti	"patm",
99117632Sharti	patm_methods,
100117632Sharti	sizeof(struct patm_softc),
101117632Sharti};
102117632ShartiDRIVER_MODULE(patm, pci, patm_driver, patm_devclass, NULL, 0);
103117632Sharti
104117632Shartistatic const struct {
105117632Sharti	u_int	devid;
106117632Sharti	const char *desc;
107117632Sharti} devs[] = {
108117632Sharti	{ PCI_DEVICE_IDT77252,	"NICStAR (77222/77252) ATM adapter" },
109117632Sharti	{ PCI_DEVICE_IDT77v252,	"NICStAR (77v252) ATM adapter" },
110117632Sharti	{ PCI_DEVICE_IDT77v222,	"NICStAR (77v222) ATM adapter" },
111117632Sharti	{ 0, NULL }
112117632Sharti};
113117632Sharti
114117632ShartiSYSCTL_DECL(_hw_atm);
115117632Sharti
116117632Shartistatic int patm_phy_readregs(struct ifatm *, u_int, uint8_t *, u_int *);
117117632Shartistatic int patm_phy_writereg(struct ifatm *, u_int, u_int, u_int);
118117632Shartistatic const struct utopia_methods patm_utopia_methods = {
119117632Sharti	patm_phy_readregs,
120117632Sharti	patm_phy_writereg
121117632Sharti};
122117632Sharti
123117632Shartistatic void patm_destroy(struct patm_softc *sc);
124117632Sharti
125117632Shartistatic int patm_sysctl_istats(SYSCTL_HANDLER_ARGS);
126117632Shartistatic int patm_sysctl_eeprom(SYSCTL_HANDLER_ARGS);
127117632Sharti
128117632Shartistatic void patm_read_eeprom(struct patm_softc *sc);
129117632Shartistatic int patm_sq_init(struct patm_softc *sc);
130117632Shartistatic int patm_rbuf_init(struct patm_softc *sc);
131117632Shartistatic int patm_txmap_init(struct patm_softc *sc);
132117632Sharti
133117632Shartistatic void patm_env_getuint(struct patm_softc *, u_int *, const char *);
134117632Sharti
135117632Sharti#ifdef PATM_DEBUG
136117632Shartistatic int patm_sysctl_regs(SYSCTL_HANDLER_ARGS);
137117632Shartistatic int patm_sysctl_tsq(SYSCTL_HANDLER_ARGS);
138117632Shartiint patm_dump_vc(u_int unit, u_int vc) __unused;
139117632Shartiint patm_dump_regs(u_int unit) __unused;
140117632Shartiint patm_dump_sram(u_int unit, u_int from, u_int words) __unused;
141117632Sharti#endif
142117632Sharti
143117632Sharti/*
144117632Sharti * Probe for a IDT77252 controller
145117632Sharti */
146117632Shartistatic int
147117632Shartipatm_probe(device_t dev)
148117632Sharti{
149117632Sharti	u_int i;
150117632Sharti
151117632Sharti	if (pci_get_vendor(dev) == PCI_VENDOR_IDT) {
152117632Sharti		for (i = 0; devs[i].desc != NULL; i++)
153117632Sharti			if (pci_get_device(dev) == devs[i].devid) {
154117632Sharti				device_set_desc(dev, devs[i].desc);
155143158Simp				return (BUS_PROBE_DEFAULT);
156117632Sharti			}
157117632Sharti	}
158117632Sharti	return (ENXIO);
159117632Sharti}
160117632Sharti
161117632Sharti/*
162117632Sharti * Attach
163117632Sharti */
164117632Shartistatic int
165117632Shartipatm_attach(device_t dev)
166117632Sharti{
167117632Sharti	struct patm_softc *sc;
168117632Sharti	int error;
169117632Sharti	struct ifnet *ifp;
170117632Sharti	int rid;
171117632Sharti	u_int a;
172117632Sharti
173117632Sharti	static const struct idt_mmap idt_mmap[4] = IDT_MMAP;
174117632Sharti
175117632Sharti	sc = device_get_softc(dev);
176117632Sharti
177117632Sharti	sc->dev = dev;
178117632Sharti#ifdef IATM_DEBUG
179117632Sharti	sc->debug = IATM_DEBUG;
180117632Sharti#endif
181147256Sbrooks	ifp = sc->ifp = if_alloc(IFT_ATM);
182147256Sbrooks	if (ifp == NULL) {
183147256Sbrooks		return (ENOSPC);
184147256Sbrooks	}
185117632Sharti
186147256Sbrooks	IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_IDTABR25;
187147256Sbrooks	IFP2IFATM(sc->ifp)->mib.serial = 0;
188147256Sbrooks	IFP2IFATM(sc->ifp)->mib.hw_version = 0;
189147256Sbrooks	IFP2IFATM(sc->ifp)->mib.sw_version = 0;
190147256Sbrooks	IFP2IFATM(sc->ifp)->mib.vpi_bits = PATM_VPI_BITS;
191147256Sbrooks	IFP2IFATM(sc->ifp)->mib.vci_bits = 0;	/* set below */;
192147256Sbrooks	IFP2IFATM(sc->ifp)->mib.max_vpcs = 0;
193147256Sbrooks	IFP2IFATM(sc->ifp)->mib.max_vccs = 0;	/* set below */
194147256Sbrooks	IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UNKNOWN;
195147256Sbrooks	IFP2IFATM(sc->ifp)->phy = &sc->utopia;
196147256Sbrooks
197117632Sharti	ifp->if_softc = sc;
198121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
199117632Sharti	ifp->if_flags = IFF_SIMPLEX;
200117632Sharti	ifp->if_init = patm_init;
201117632Sharti	ifp->if_ioctl = patm_ioctl;
202117632Sharti	ifp->if_start = patm_start;
203117632Sharti
204117632Sharti	/* do this early so we can destroy unconditionally */
205117632Sharti	mtx_init(&sc->mtx, device_get_nameunit(dev),
206117632Sharti	    MTX_NETWORK_LOCK, MTX_DEF);
207117632Sharti	mtx_init(&sc->tst_lock, "tst lock", NULL, MTX_DEF);
208117632Sharti	cv_init(&sc->vcc_cv, "vcc_close");
209117632Sharti
210119137Ssam	callout_init(&sc->tst_callout, CALLOUT_MPSAFE);
211117632Sharti
212117632Sharti	sysctl_ctx_init(&sc->sysctl_ctx);
213117632Sharti
214117632Sharti	/*
215117632Sharti	 * Get revision
216117632Sharti	 */
217117632Sharti	sc->revision = pci_read_config(dev, PCIR_REVID, 4) & 0xf;
218117632Sharti
219117632Sharti	/*
220117632Sharti	 * Enable PCI bus master and memory
221117632Sharti	 */
222117632Sharti	pci_enable_busmaster(dev);
223117632Sharti
224117632Sharti	rid = IDT_PCI_REG_MEMBASE;
225127135Snjl	sc->memres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
226127135Snjl	    RF_ACTIVE);
227117632Sharti	if (sc->memres == NULL) {
228117632Sharti		patm_printf(sc, "could not map memory\n");
229117632Sharti		error = ENXIO;
230117632Sharti		goto fail;
231117632Sharti	}
232117632Sharti	sc->memh = rman_get_bushandle(sc->memres);
233117632Sharti	sc->memt = rman_get_bustag(sc->memres);
234117632Sharti
235117632Sharti	/*
236117632Sharti	 * Allocate the interrupt (enable it later)
237117632Sharti	 */
238117632Sharti	sc->irqid = 0;
239127135Snjl	sc->irqres = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->irqid,
240127135Snjl	    RF_SHAREABLE | RF_ACTIVE);
241117632Sharti	if (sc->irqres == 0) {
242117632Sharti		patm_printf(sc, "could not allocate irq\n");
243117632Sharti		error = ENXIO;
244117632Sharti		goto fail;
245117632Sharti	}
246117632Sharti
247117632Sharti	/*
248117632Sharti	 * Construct the sysctl tree
249117632Sharti	 */
250117632Sharti	error = ENOMEM;
251117632Sharti	if ((sc->sysctl_tree = SYSCTL_ADD_NODE(&sc->sysctl_ctx,
252117632Sharti	    SYSCTL_STATIC_CHILDREN(_hw_atm), OID_AUTO,
253117632Sharti	    device_get_nameunit(dev), CTLFLAG_RD, 0, "")) == NULL)
254117632Sharti		goto fail;
255117632Sharti
256117632Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
257217556Smdf	    OID_AUTO, "istats", CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0,
258217556Smdf	    patm_sysctl_istats, "S", "internal statistics") == NULL)
259117632Sharti		goto fail;
260117632Sharti
261117632Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
262217556Smdf	    OID_AUTO, "eeprom", CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0,
263217556Smdf	    patm_sysctl_eeprom, "S", "EEPROM contents") == NULL)
264117632Sharti		goto fail;
265117632Sharti
266117632Sharti	if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
267117632Sharti	    OID_AUTO, "lbuf_max", CTLFLAG_RD, &sc->lbuf_max,
268117632Sharti	    0, "maximum number of large receive buffers") == NULL)
269117632Sharti		goto fail;
270117632Sharti	patm_env_getuint(sc, &sc->lbuf_max, "lbuf_max");
271117632Sharti
272117632Sharti	if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
273117632Sharti	    OID_AUTO, "max_txmaps", CTLFLAG_RW, &sc->tx_maxmaps,
274117632Sharti	    0, "maximum number of TX DMA maps") == NULL)
275117632Sharti		goto fail;
276117632Sharti	patm_env_getuint(sc, &sc->tx_maxmaps, "tx_maxmaps");
277117632Sharti
278117632Sharti#ifdef PATM_DEBUG
279117632Sharti	if (SYSCTL_ADD_UINT(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
280117632Sharti	    OID_AUTO, "debug", CTLFLAG_RW, &sc->debug,
281117632Sharti	    0, "debug flags") == NULL)
282117632Sharti		goto fail;
283117632Sharti	sc->debug = PATM_DEBUG;
284117632Sharti	patm_env_getuint(sc, &sc->debug, "debug");
285117632Sharti
286117632Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
287217566Smdf	    OID_AUTO, "regs", CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0,
288217566Smdf	    patm_sysctl_regs, "S", "registers") == NULL)
289117632Sharti		goto fail;
290117632Sharti
291117632Sharti	if (SYSCTL_ADD_PROC(&sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
292217566Smdf	    OID_AUTO, "tsq", CTLTYPE_OPAQUE | CTLFLAG_RD, sc, 0,
293217566Smdf	    patm_sysctl_tsq, "S", "TSQ") == NULL)
294117632Sharti		goto fail;
295117632Sharti#endif
296117632Sharti
297117632Sharti	patm_reset(sc);
298117632Sharti
299117632Sharti	/*
300117632Sharti	 * Detect and attach the phy.
301117632Sharti	 */
302117632Sharti	patm_debug(sc, ATTACH, "attaching utopia");
303147256Sbrooks	IFP2IFATM(sc->ifp)->phy = &sc->utopia;
304147256Sbrooks	utopia_attach(&sc->utopia, IFP2IFATM(sc->ifp), &sc->media, &sc->mtx,
305117632Sharti	    &sc->sysctl_ctx, SYSCTL_CHILDREN(sc->sysctl_tree),
306117632Sharti	    &patm_utopia_methods);
307117632Sharti
308117632Sharti	/*
309117632Sharti	 * Start the PHY because we need the autodetection
310117632Sharti	 */
311117632Sharti	patm_debug(sc, ATTACH, "starting utopia");
312117632Sharti	mtx_lock(&sc->mtx);
313117632Sharti	utopia_start(&sc->utopia);
314117632Sharti	utopia_reset(&sc->utopia);
315117632Sharti	mtx_unlock(&sc->mtx);
316117632Sharti
317117632Sharti	/* Read EEPROM */
318117632Sharti	patm_read_eeprom(sc);
319117632Sharti
320117632Sharti	/* analyze it */
321117632Sharti	if (strncmp(sc->eeprom + PATM_PROATM_NAME_OFFSET, PATM_PROATM_NAME,
322117632Sharti	    strlen(PATM_PROATM_NAME)) == 0) {
323117632Sharti		if (sc->utopia.chip->type == UTP_TYPE_IDT77105) {
324147256Sbrooks			IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_PROATM25;
325147256Sbrooks			IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_25_6M;
326147256Sbrooks			IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UTP_25;
327117632Sharti			sc->flags |= PATM_25M;
328117632Sharti			patm_printf(sc, "ProATM 25 interface; ");
329117632Sharti
330117632Sharti		} else {
331117632Sharti			/* cannot really know which media */
332147256Sbrooks			IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_PROATM155;
333147256Sbrooks			IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_155M;
334147256Sbrooks			IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_155;
335117632Sharti			patm_printf(sc, "ProATM 155 interface; ");
336117632Sharti		}
337117632Sharti
338147256Sbrooks		bcopy(sc->eeprom + PATM_PROATM_MAC_OFFSET, IFP2IFATM(sc->ifp)->mib.esi,
339147256Sbrooks		    sizeof(IFP2IFATM(sc->ifp)->mib.esi));
340117632Sharti
341117632Sharti	} else {
342117632Sharti		if (sc->utopia.chip->type == UTP_TYPE_IDT77105) {
343147256Sbrooks			IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_IDTABR25;
344147256Sbrooks			IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_25_6M;
345147256Sbrooks			IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_UTP_25;
346117632Sharti			sc->flags |= PATM_25M;
347117632Sharti			patm_printf(sc, "IDT77252 25MBit interface; ");
348117632Sharti
349117632Sharti		} else {
350117632Sharti			/* cannot really know which media */
351147256Sbrooks			IFP2IFATM(sc->ifp)->mib.device = ATM_DEVICE_IDTABR155;
352147256Sbrooks			IFP2IFATM(sc->ifp)->mib.pcr = ATM_RATE_155M;
353147256Sbrooks			IFP2IFATM(sc->ifp)->mib.media = IFM_ATM_MM_155;
354117632Sharti			patm_printf(sc, "IDT77252 155MBit interface; ");
355117632Sharti		}
356117632Sharti
357147256Sbrooks		bcopy(sc->eeprom + PATM_IDT_MAC_OFFSET, IFP2IFATM(sc->ifp)->mib.esi,
358147256Sbrooks		    sizeof(IFP2IFATM(sc->ifp)->mib.esi));
359117632Sharti	}
360117632Sharti	printf("idt77252 Rev. %c; %s PHY\n", 'A' + sc->revision,
361117632Sharti	    sc->utopia.chip->name);
362117632Sharti
363117632Sharti	utopia_reset_media(&sc->utopia);
364117632Sharti	utopia_init_media(&sc->utopia);
365117632Sharti
366117632Sharti	/*
367117632Sharti	 * Determine RAM size
368117632Sharti	 */
369117632Sharti	for (a = 0; a < 0x20000; a++)
370117632Sharti		patm_sram_write(sc, a, 0);
371117632Sharti	patm_sram_write(sc, 0, 0xdeadbeef);
372117632Sharti	if (patm_sram_read(sc, 0x4004) == 0xdeadbeef)
373117632Sharti		sc->mmap = &idt_mmap[0];
374117632Sharti	else if (patm_sram_read(sc, 0x8000) == 0xdeadbeef)
375117632Sharti		sc->mmap = &idt_mmap[1];
376117632Sharti	else if (patm_sram_read(sc, 0x20000) == 0xdeadbeef)
377117632Sharti		sc->mmap = &idt_mmap[2];
378117632Sharti	else
379117632Sharti		sc->mmap = &idt_mmap[3];
380117632Sharti
381147256Sbrooks	IFP2IFATM(sc->ifp)->mib.vci_bits = sc->mmap->vcbits - IFP2IFATM(sc->ifp)->mib.vpi_bits;
382147256Sbrooks	IFP2IFATM(sc->ifp)->mib.max_vccs = sc->mmap->max_conn;
383117632Sharti	patm_sram_write(sc, 0, 0);
384117632Sharti	patm_printf(sc, "%uK x 32 SRAM; %u connections\n", sc->mmap->sram,
385117632Sharti	    sc->mmap->max_conn);
386117632Sharti
387117632Sharti	/* initialize status queues */
388117632Sharti	error = patm_sq_init(sc);
389117632Sharti	if (error != 0)
390117632Sharti		goto fail;
391117632Sharti
392117632Sharti	/* get TST */
393117632Sharti	sc->tst_soft = malloc(sizeof(uint32_t) * sc->mmap->tst_size,
394117632Sharti	    M_DEVBUF, M_WAITOK);
395117632Sharti
396117632Sharti	/* allocate all the receive buffer stuff */
397117632Sharti	error = patm_rbuf_init(sc);
398117632Sharti	if (error != 0)
399117632Sharti		goto fail;
400117632Sharti
401117632Sharti	/*
402117632Sharti	 * Allocate SCD tag
403117632Sharti	 *
404117632Sharti	 * Don't use BUS_DMA_ALLOCNOW, because we never need bouncing with
405117632Sharti	 * bus_dmamem_alloc()
406117632Sharti	 */
407232874Sscottl	error = bus_dma_tag_create(bus_get_dma_tag(dev), PAGE_SIZE, 0,
408117632Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
409117632Sharti	    NULL, NULL, sizeof(struct patm_scd), 1,
410117632Sharti	    sizeof(struct patm_scd), 0, NULL, NULL, &sc->scd_tag);
411117632Sharti	if (error) {
412117632Sharti		patm_printf(sc, "SCD DMA tag create %d\n", error);
413117632Sharti		goto fail;
414117632Sharti	}
415117632Sharti	LIST_INIT(&sc->scd_list);
416117632Sharti
417117632Sharti	/* allocate VCC zone and pointers */
418117632Sharti	if ((sc->vcc_zone = uma_zcreate("PATM vccs", sizeof(struct patm_vcc),
419117632Sharti	    NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0)) == NULL) {
420117632Sharti		patm_printf(sc, "cannot allocate zone for vccs\n");
421117632Sharti		goto fail;
422117632Sharti	}
423117632Sharti	sc->vccs = malloc(sizeof(sc->vccs[0]) * sc->mmap->max_conn,
424117632Sharti	    M_DEVBUF, M_WAITOK | M_ZERO);
425117632Sharti
426117632Sharti	/* allocate transmission resources */
427117632Sharti	error = patm_txmap_init(sc);
428117632Sharti	if (error != 0)
429117632Sharti		goto fail;
430117632Sharti
431117632Sharti	/* poll while we are not running */
432117632Sharti	sc->utopia.flags |= UTP_FL_POLL_CARRIER;
433117632Sharti
434117632Sharti	patm_debug(sc, ATTACH, "attaching interface");
435117632Sharti	atm_ifattach(ifp);
436117632Sharti
437117632Sharti#ifdef ENABLE_BPF
438117632Sharti	bpfattach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
439117632Sharti#endif
440117632Sharti
441117632Sharti	patm_debug(sc, ATTACH, "attaching interrupt handler");
442156949Sharti	error = bus_setup_intr(dev, sc->irqres, INTR_TYPE_NET | INTR_MPSAFE,
443166901Spiso	    NULL, patm_intr, sc, &sc->ih);
444117632Sharti	if (error != 0) {
445117632Sharti		patm_printf(sc, "could not setup interrupt\n");
446147256Sbrooks		atm_ifdetach(sc->ifp);
447147256Sbrooks		if_free(sc->ifp);
448117632Sharti		goto fail;
449117632Sharti	}
450117632Sharti
451117632Sharti	return (0);
452117632Sharti
453117632Sharti  fail:
454117632Sharti	patm_destroy(sc);
455117632Sharti	return (error);
456117632Sharti}
457117632Sharti
458117632Sharti/*
459117632Sharti * Detach
460117632Sharti */
461117632Shartistatic int
462117632Shartipatm_detach(device_t dev)
463117632Sharti{
464117632Sharti	struct patm_softc *sc;
465117632Sharti
466147721Sharti	sc = device_get_softc(dev);
467117632Sharti
468117632Sharti	mtx_lock(&sc->mtx);
469117632Sharti	patm_stop(sc);
470117632Sharti	if (sc->utopia.state & UTP_ST_ATTACHED) {
471117632Sharti		patm_debug(sc, ATTACH, "detaching utopia");
472117632Sharti		utopia_stop(&sc->utopia);
473117632Sharti		utopia_detach(&sc->utopia);
474117632Sharti	}
475117632Sharti	mtx_unlock(&sc->mtx);
476117632Sharti
477147256Sbrooks	atm_ifdetach(sc->ifp);
478117632Sharti
479117632Sharti	patm_destroy(sc);
480117632Sharti
481117632Sharti	return (0);
482117632Sharti}
483117632Sharti
484117632Sharti/*
485117632Sharti * Destroy everything. Assume we are stopped.
486117632Sharti */
487117632Shartistatic void
488117632Shartipatm_destroy(struct patm_softc *sc)
489117632Sharti{
490117632Sharti	u_int i;
491117632Sharti	struct patm_txmap *map;
492117632Sharti
493117632Sharti	if (sc->ih != NULL)
494117632Sharti		bus_teardown_intr(sc->dev, sc->irqres, sc->ih);
495117632Sharti
496117632Sharti	if (sc->tx_mapzone != NULL) {
497117632Sharti		/* all maps must be free */
498117632Sharti		while ((map = SLIST_FIRST(&sc->tx_maps_free)) != NULL) {
499117632Sharti			bus_dmamap_destroy(sc->tx_tag, map->map);
500117632Sharti			SLIST_REMOVE_HEAD(&sc->tx_maps_free, link);
501117632Sharti			uma_zfree(sc->tx_mapzone, map);
502117632Sharti		}
503117632Sharti		uma_zdestroy(sc->tx_mapzone);
504117632Sharti	}
505117632Sharti
506117632Sharti	if (sc->scd_tag != NULL)
507117632Sharti		bus_dma_tag_destroy(sc->scd_tag);
508117632Sharti
509117632Sharti	if (sc->tx_tag != NULL)
510117632Sharti		bus_dma_tag_destroy(sc->scd_tag);
511117632Sharti
512117632Sharti	if (sc->vccs != NULL) {
513117632Sharti		for (i = 0; i < sc->mmap->max_conn; i++)
514117632Sharti			if (sc->vccs[i] != NULL)
515117632Sharti				uma_zfree(sc->vcc_zone, sc->vccs[i]);
516117632Sharti		free(sc->vccs, M_DEVBUF);
517117632Sharti	}
518117632Sharti	if (sc->vcc_zone != NULL)
519117632Sharti		uma_zdestroy(sc->vcc_zone);
520117632Sharti
521117632Sharti	if (sc->lbufs != NULL) {
522117632Sharti		for (i = 0; i < sc->lbuf_max; i++)
523117632Sharti			bus_dmamap_destroy(sc->lbuf_tag, sc->lbufs[i].map);
524117632Sharti		free(sc->lbufs, M_DEVBUF);
525117632Sharti	}
526117632Sharti
527117632Sharti	if (sc->lbuf_tag != NULL)
528117632Sharti		bus_dma_tag_destroy(sc->lbuf_tag);
529117632Sharti
530117632Sharti	if (sc->sbuf_pool != NULL)
531117632Sharti		mbp_destroy(sc->sbuf_pool);
532117632Sharti	if (sc->vbuf_pool != NULL)
533117632Sharti		mbp_destroy(sc->vbuf_pool);
534117632Sharti
535117632Sharti	if (sc->sbuf_tag != NULL)
536117632Sharti		bus_dma_tag_destroy(sc->sbuf_tag);
537117632Sharti
538117632Sharti	if (sc->tst_soft != NULL)
539117632Sharti		free(sc->tst_soft, M_DEVBUF);
540117632Sharti
541117632Sharti	/*
542117632Sharti	 * Free all status queue memory resources
543117632Sharti	 */
544117632Sharti	if (sc->tsq != NULL) {
545117632Sharti		bus_dmamap_unload(sc->sq_tag, sc->sq_map);
546117632Sharti		bus_dmamem_free(sc->sq_tag, sc->tsq, sc->sq_map);
547117632Sharti		bus_dma_tag_destroy(sc->sq_tag);
548117632Sharti	}
549117632Sharti
550117632Sharti	if (sc->irqres != NULL)
551117632Sharti		bus_release_resource(sc->dev, SYS_RES_IRQ,
552117632Sharti		    sc->irqid, sc->irqres);
553117632Sharti	if (sc->memres != NULL)
554117632Sharti		bus_release_resource(sc->dev, SYS_RES_MEMORY,
555117632Sharti		    IDT_PCI_REG_MEMBASE, sc->memres);
556117632Sharti
557117632Sharti	/* this was initialize unconditionally */
558117632Sharti	sysctl_ctx_free(&sc->sysctl_ctx);
559117632Sharti	cv_destroy(&sc->vcc_cv);
560117632Sharti	mtx_destroy(&sc->tst_lock);
561117632Sharti	mtx_destroy(&sc->mtx);
562150220Sru
563150220Sru	if (sc->ifp != NULL)
564150220Sru		if_free(sc->ifp);
565117632Sharti}
566117632Sharti
567117632Sharti/*
568117632Sharti * Try to find a variable in the environment and parse it as an unsigned
569117632Sharti * integer.
570117632Sharti */
571117632Shartistatic void
572117632Shartipatm_env_getuint(struct patm_softc *sc, u_int *var, const char *name)
573117632Sharti{
574117632Sharti	char full[IFNAMSIZ + 3 + 20];
575117632Sharti	char *val, *end;
576117632Sharti	u_long u;
577117632Sharti
578117632Sharti	snprintf(full, sizeof(full), "hw.%s.%s",
579117632Sharti	    device_get_nameunit(sc->dev), name);
580117632Sharti
581117632Sharti	if ((val = getenv(full)) != NULL) {
582117632Sharti		u = strtoul(val, &end, 0);
583117632Sharti		if (end > val && *end == '\0') {
584117632Sharti			if (bootverbose)
585117632Sharti				patm_printf(sc, "%s=%lu\n", full, u);
586117632Sharti			*var = u;
587117632Sharti		}
588117632Sharti		freeenv(val);
589117632Sharti	}
590117632Sharti}
591117632Sharti
592117632Sharti/*
593117632Sharti * Sysctl handler for internal statistics
594117632Sharti *
595117632Sharti * LOCK: unlocked, needed
596117632Sharti */
597117632Shartistatic int
598117632Shartipatm_sysctl_istats(SYSCTL_HANDLER_ARGS)
599117632Sharti{
600117632Sharti	struct patm_softc *sc = arg1;
601117632Sharti	uint32_t *ret;
602117632Sharti	int error;
603117632Sharti
604117632Sharti	ret = malloc(sizeof(sc->stats), M_TEMP, M_WAITOK);
605117632Sharti
606117632Sharti	mtx_lock(&sc->mtx);
607117632Sharti	bcopy(&sc->stats, ret, sizeof(sc->stats));
608117632Sharti	mtx_unlock(&sc->mtx);
609117632Sharti
610117632Sharti	error = SYSCTL_OUT(req, ret, sizeof(sc->stats));
611117632Sharti	free(ret, M_TEMP);
612117632Sharti
613117632Sharti	return (error);
614117632Sharti}
615117632Sharti
616117632Sharti/*
617117632Sharti * Sysctl handler for EEPROM
618117632Sharti *
619117632Sharti * LOCK: unlocked, needed
620117632Sharti */
621117632Shartistatic int
622117632Shartipatm_sysctl_eeprom(SYSCTL_HANDLER_ARGS)
623117632Sharti{
624117632Sharti	struct patm_softc *sc = arg1;
625117632Sharti	void *ret;
626117632Sharti	int error;
627117632Sharti
628117632Sharti	ret = malloc(sizeof(sc->eeprom), M_TEMP, M_WAITOK);
629117632Sharti
630117632Sharti	mtx_lock(&sc->mtx);
631117632Sharti	bcopy(sc->eeprom, ret, sizeof(sc->eeprom));
632117632Sharti	mtx_unlock(&sc->mtx);
633117632Sharti
634117632Sharti	error = SYSCTL_OUT(req, ret, sizeof(sc->eeprom));
635117632Sharti	free(ret, M_TEMP);
636117632Sharti
637117632Sharti	return (error);
638117632Sharti}
639117632Sharti
640117632Sharti/*
641117632Sharti * Read the EEPROM. We assume that this is a XIRCOM 25020
642117632Sharti */
643117632Shartistatic void
644117632Shartipatm_read_eeprom(struct patm_softc *sc)
645117632Sharti{
646117632Sharti	u_int gp;
647117632Sharti	uint8_t byte;
648117632Sharti	int i, addr;
649117632Sharti
650117632Sharti	static const uint32_t tab[] = {
651117632Sharti		/* CS transition to reset the chip */
652117632Sharti		IDT_GP_EECS | IDT_GP_EESCLK,	0,
653117632Sharti		/* read command 0x03 */
654117632Sharti		IDT_GP_EESCLK,			0,
655117632Sharti		IDT_GP_EESCLK,			0,
656117632Sharti		IDT_GP_EESCLK,			0,
657117632Sharti		IDT_GP_EESCLK,			0,
658117632Sharti		IDT_GP_EESCLK,			0,
659117632Sharti		IDT_GP_EESCLK,			IDT_GP_EEDO,
660117632Sharti		IDT_GP_EESCLK | IDT_GP_EEDO,	IDT_GP_EEDO,
661117632Sharti		IDT_GP_EESCLK | IDT_GP_EEDO,	0,
662117632Sharti		/* address 0x00 */
663117632Sharti		IDT_GP_EESCLK,			0,
664117632Sharti		IDT_GP_EESCLK,			0,
665117632Sharti		IDT_GP_EESCLK,			0,
666117632Sharti		IDT_GP_EESCLK,			0,
667117632Sharti		IDT_GP_EESCLK,			0,
668117632Sharti		IDT_GP_EESCLK,			0,
669117632Sharti		IDT_GP_EESCLK,			0,
670117632Sharti		IDT_GP_EESCLK,			0,
671117632Sharti	};
672117632Sharti
673117632Sharti	/* go to a known state (chip enabled) */
674117632Sharti	gp = patm_nor_read(sc, IDT_NOR_GP);
675117632Sharti	gp &= ~(IDT_GP_EESCLK | IDT_GP_EECS | IDT_GP_EEDO);
676117632Sharti
677117632Sharti	for (i = 0; i < sizeof(tab) / sizeof(tab[0]); i++) {
678117632Sharti		patm_nor_write(sc, IDT_NOR_GP, gp | tab[i]);
679117632Sharti		DELAY(40);
680117632Sharti	}
681117632Sharti
682117632Sharti	/* read out the prom */
683117632Sharti	for (addr = 0; addr < 256; addr++) {
684117632Sharti		byte = 0;
685117632Sharti		for (i = 0; i < 8; i++) {
686117632Sharti			byte <<= 1;
687117632Sharti			if (patm_nor_read(sc, IDT_NOR_GP) & IDT_GP_EEDI)
688117632Sharti				byte |= 1;
689117632Sharti			/* rising CLK */
690117632Sharti			patm_nor_write(sc, IDT_NOR_GP, gp | IDT_GP_EESCLK);
691117632Sharti			DELAY(40);
692117632Sharti			/* falling clock */
693117632Sharti			patm_nor_write(sc, IDT_NOR_GP, gp);
694117632Sharti			DELAY(40);
695117632Sharti		}
696117632Sharti		sc->eeprom[addr] = byte;
697117632Sharti	}
698117632Sharti}
699117632Sharti
700117632Sharti/*
701117632Sharti * PHY access read
702117632Sharti */
703117632Shartistatic int
704117632Shartipatm_phy_readregs(struct ifatm *ifatm, u_int reg, uint8_t *val, u_int *n)
705117632Sharti{
706147256Sbrooks	struct patm_softc *sc = ifatm->ifp->if_softc;
707117632Sharti	u_int cnt = *n;
708117632Sharti
709117632Sharti	if (reg >= 0x100)
710117632Sharti		return (EINVAL);
711117632Sharti
712117632Sharti	patm_cmd_wait(sc);
713117632Sharti	while (reg < 0x100 && cnt > 0) {
714117632Sharti		patm_nor_write(sc, IDT_NOR_CMD, IDT_MKCMD_RUTIL(1, 0, reg));
715117632Sharti		patm_cmd_wait(sc);
716117632Sharti		*val = patm_nor_read(sc, IDT_NOR_D0);
717117632Sharti		patm_debug(sc, PHY, "phy(%02x)=%02x", reg, *val);
718117632Sharti		val++;
719117632Sharti		reg++;
720117632Sharti		cnt--;
721117632Sharti	}
722117632Sharti	*n = *n - cnt;
723117632Sharti	return (0);
724117632Sharti}
725117632Sharti
726117632Sharti/*
727117632Sharti * Write PHY reg
728117632Sharti */
729117632Shartistatic int
730117632Shartipatm_phy_writereg(struct ifatm *ifatm, u_int reg, u_int mask, u_int val)
731117632Sharti{
732147256Sbrooks	struct patm_softc *sc = ifatm->ifp->if_softc;
733117632Sharti	u_int old, new;
734117632Sharti
735117632Sharti	if (reg >= 0x100)
736117632Sharti		return (EINVAL);
737117632Sharti
738117632Sharti	patm_cmd_wait(sc);
739117632Sharti	patm_nor_write(sc, IDT_NOR_CMD, IDT_MKCMD_RUTIL(1, 0, reg));
740117632Sharti	patm_cmd_wait(sc);
741117632Sharti
742117632Sharti	old = patm_nor_read(sc, IDT_NOR_D0);
743117632Sharti	new = (old & ~mask) | (val & mask);
744117632Sharti	patm_debug(sc, PHY, "phy(%02x) %02x -> %02x", reg, old, new);
745117632Sharti
746117632Sharti	patm_nor_write(sc, IDT_NOR_D0, new);
747117632Sharti	patm_nor_write(sc, IDT_NOR_CMD, IDT_MKCMD_WUTIL(1, 0, reg));
748117632Sharti	patm_cmd_wait(sc);
749117632Sharti
750117632Sharti	return (0);
751117632Sharti}
752117632Sharti
753117632Sharti/*
754117632Sharti * Allocate a large chunk of DMA able memory for the transmit
755117632Sharti * and receive status queues. We align this to a page boundary
756117632Sharti * to ensure the alignment.
757117632Sharti */
758117632Shartistatic int
759117632Shartipatm_sq_init(struct patm_softc *sc)
760117632Sharti{
761117632Sharti	int error;
762117632Sharti	void *p;
763117632Sharti
764117632Sharti	/* compute size of the two queues */
765117632Sharti	sc->sq_size = IDT_TSQ_SIZE * IDT_TSQE_SIZE +
766117632Sharti	    PATM_RSQ_SIZE * IDT_RSQE_SIZE +
767117632Sharti	    IDT_RAWHND_SIZE;
768117632Sharti
769117632Sharti	patm_debug(sc, ATTACH,
770117632Sharti	    "allocating status queues (%zu) ...", sc->sq_size);
771117632Sharti
772117632Sharti	/*
773117632Sharti	 * allocate tag
774117632Sharti	 * Don't use BUS_DMA_ALLOCNOW, because we never need bouncing with
775117632Sharti	 * bus_dmamem_alloc()
776117632Sharti	 */
777232874Sscottl	error = bus_dma_tag_create(bus_get_dma_tag(sc->dev),
778232874Sscottl	    PATM_SQ_ALIGNMENT, 0,
779117632Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
780117632Sharti	    NULL, NULL, sc->sq_size, 1, sc->sq_size,
781117632Sharti	    0, NULL, NULL, &sc->sq_tag);
782117632Sharti	if (error) {
783117632Sharti		patm_printf(sc, "memory DMA tag create %d\n", error);
784117632Sharti		return (error);
785117632Sharti	}
786117632Sharti
787117632Sharti	/* allocate memory */
788117632Sharti	error = bus_dmamem_alloc(sc->sq_tag, &p, 0, &sc->sq_map);
789117632Sharti	if (error) {
790117632Sharti		patm_printf(sc, "memory DMA alloc %d\n", error);
791117632Sharti		bus_dma_tag_destroy(sc->sq_tag);
792117632Sharti		return (error);
793117632Sharti	}
794117632Sharti
795117632Sharti	/* map it */
796117632Sharti	sc->tsq_phy = 0x1fff;
797117632Sharti	error = bus_dmamap_load(sc->sq_tag, sc->sq_map, p,
798117632Sharti	    sc->sq_size, patm_load_callback, &sc->tsq_phy, BUS_DMA_NOWAIT);
799117632Sharti	if (error) {
800117632Sharti		patm_printf(sc, "memory DMA map load %d\n", error);
801117632Sharti		bus_dmamem_free(sc->sq_tag, p, sc->sq_map);
802117632Sharti		bus_dma_tag_destroy(sc->sq_tag);
803117632Sharti		return (error);
804117632Sharti	}
805117632Sharti
806117632Sharti	/* set queue start */
807117632Sharti	sc->tsq = p;
808117632Sharti	sc->rsq = (void *)((char *)p + IDT_TSQ_SIZE * IDT_TSQE_SIZE);
809117632Sharti	sc->rsq_phy = sc->tsq_phy + IDT_TSQ_SIZE * IDT_TSQE_SIZE;
810117632Sharti	sc->rawhnd = (void *)((char *)sc->rsq + PATM_RSQ_SIZE * IDT_RSQE_SIZE);
811117632Sharti	sc->rawhnd_phy = sc->rsq_phy + PATM_RSQ_SIZE * IDT_RSQE_SIZE;
812117632Sharti
813117632Sharti	return (0);
814117632Sharti}
815117632Sharti
816117632Sharti/*
817117632Sharti * Initialize all receive buffer stuff
818117632Sharti */
819117632Shartistatic int
820117632Shartipatm_rbuf_init(struct patm_softc *sc)
821117632Sharti{
822117632Sharti	u_int i;
823117632Sharti	int error;
824117632Sharti
825117632Sharti	patm_debug(sc, ATTACH, "allocating Rx buffer resources ...");
826117632Sharti	/*
827117632Sharti	 * Create a tag for small buffers. We allocate these page wise.
828117632Sharti	 * Don't use BUS_DMA_ALLOCNOW, because we never need bouncing with
829117632Sharti	 * bus_dmamem_alloc()
830117632Sharti	 */
831232874Sscottl	if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), PAGE_SIZE, 0,
832117632Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
833117632Sharti	    SMBUF_PAGE_SIZE, 1, SMBUF_PAGE_SIZE, 0,
834117632Sharti	    NULL, NULL, &sc->sbuf_tag)) != 0) {
835117632Sharti		patm_printf(sc, "sbuf DMA tag create %d\n", error);
836117632Sharti		return (error);
837117632Sharti	}
838117632Sharti
839117632Sharti	error = mbp_create(&sc->sbuf_pool, "patm sbufs", sc->sbuf_tag,
840117632Sharti	    SMBUF_MAX_PAGES, SMBUF_PAGE_SIZE, SMBUF_CHUNK_SIZE);
841117632Sharti	if (error != 0) {
842117632Sharti		patm_printf(sc, "smbuf pool create %d\n", error);
843117632Sharti		return (error);
844117632Sharti	}
845117632Sharti
846117632Sharti	error = mbp_create(&sc->vbuf_pool, "patm vbufs", sc->sbuf_tag,
847117632Sharti	    VMBUF_MAX_PAGES, SMBUF_PAGE_SIZE, VMBUF_CHUNK_SIZE);
848117632Sharti	if (error != 0) {
849117632Sharti		patm_printf(sc, "vmbuf pool create %d\n", error);
850117632Sharti		return (error);
851117632Sharti	}
852117632Sharti
853117632Sharti	/*
854117632Sharti	 * Create a tag for large buffers.
855117632Sharti	 * Don't use BUS_DMA_ALLOCNOW, because it makes no sense with multiple
856117632Sharti	 * maps using one tag. Rather use BUS_DMA_NOWAIT when loading the map
857117632Sharti	 * to prevent EINPROGRESS.
858117632Sharti	 */
859232874Sscottl	if ((error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 4, 0,
860117632Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
861117632Sharti	    MCLBYTES, 1, MCLBYTES, 0,
862117632Sharti	    NULL, NULL, &sc->lbuf_tag)) != 0) {
863117632Sharti		patm_printf(sc, "lbuf DMA tag create %d\n", error);
864117632Sharti		return (error);
865117632Sharti	}
866117632Sharti
867117632Sharti	if (sc->lbuf_max < IDT_FBQ_SIZE)
868117632Sharti		sc->lbuf_max = LMBUF_MAX;
869117632Sharti	sc->lbufs = malloc(sizeof(sc->lbufs[0]) * sc->lbuf_max,
870117632Sharti	    M_DEVBUF, M_ZERO | M_WAITOK);
871117632Sharti
872117632Sharti	SLIST_INIT(&sc->lbuf_free_list);
873117632Sharti	for (i = 0; i < sc->lbuf_max; i++) {
874117632Sharti		struct lmbuf *b = &sc->lbufs[i];
875117632Sharti
876117632Sharti		error = bus_dmamap_create(sc->lbuf_tag, 0, &b->map);
877117632Sharti		if (error) {
878117632Sharti			/* must deallocate here, because a test for NULL
879117632Sharti			 * does not work on most archs */
880117632Sharti			while (i-- > 0)
881117632Sharti				bus_dmamap_destroy(sc->lbuf_tag,
882117632Sharti				    sc->lbufs[i].map);
883117632Sharti			free(sc->lbufs, M_DEVBUF);
884117632Sharti			sc->lbufs = NULL;
885117632Sharti			return (error);
886117632Sharti		}
887117632Sharti		b->handle = i;
888117632Sharti		SLIST_INSERT_HEAD(&sc->lbuf_free_list, b, link);
889117632Sharti	}
890117632Sharti
891117632Sharti	return (0);
892117632Sharti}
893117632Sharti
894117632Sharti/*
895117632Sharti * Allocate everything needed for the transmission maps.
896117632Sharti */
897117632Shartistatic int
898117632Shartipatm_txmap_init(struct patm_softc *sc)
899117632Sharti{
900117632Sharti	int error;
901117632Sharti	struct patm_txmap *map;
902117632Sharti
903117632Sharti	/* get transmission tag */
904232874Sscottl	error = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 1, 0,
905117632Sharti	    BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR,
906117632Sharti	    NULL, NULL, 65536, IDT_SCQ_SIZE - 1, 65536,
907117632Sharti	    0, NULL, NULL, &sc->tx_tag);
908117632Sharti	if (error) {
909117632Sharti		patm_printf(sc, "cannot allocate TX tag %d\n", error);
910117632Sharti		return (error);
911117632Sharti	}
912117632Sharti
913117632Sharti	if ((sc->tx_mapzone = uma_zcreate("PATM tx maps",
914117632Sharti	    sizeof(struct patm_txmap), NULL, NULL, NULL, NULL,
915117632Sharti	    UMA_ALIGN_PTR, 0)) == NULL)
916117632Sharti		return (ENOMEM);
917117632Sharti
918117632Sharti	if (sc->tx_maxmaps < PATM_CFG_TXMAPS_MAX)
919117632Sharti		sc->tx_maxmaps = PATM_CFG_TXMAPS_MAX;
920117632Sharti	sc->tx_nmaps = PATM_CFG_TXMAPS_INIT;
921117632Sharti
922117632Sharti	for (sc->tx_nmaps = 0; sc->tx_nmaps < PATM_CFG_TXMAPS_INIT;
923117632Sharti	    sc->tx_nmaps++) {
924117632Sharti		map = uma_zalloc(sc->tx_mapzone, M_WAITOK);
925117632Sharti		error = bus_dmamap_create(sc->tx_tag, 0, &map->map);
926117632Sharti		if (error) {
927117632Sharti			uma_zfree(sc->tx_mapzone, map);
928117632Sharti			return (ENOMEM);
929117632Sharti		}
930117632Sharti		SLIST_INSERT_HEAD(&sc->tx_maps_free, map, link);
931117632Sharti	}
932117632Sharti
933117632Sharti	return (0);
934117632Sharti}
935117632Sharti
936117632Sharti#ifdef PATM_DEBUG
937117632Sharti
938117632Sharti/*
939117632Sharti * Sysctl handler for REGS
940117632Sharti *
941117632Sharti * LOCK: unlocked, needed
942117632Sharti */
943117632Shartistatic int
944117632Shartipatm_sysctl_regs(SYSCTL_HANDLER_ARGS)
945117632Sharti{
946117632Sharti	struct patm_softc *sc = arg1;
947117632Sharti	uint32_t *ret;
948117632Sharti	int error, i;
949117632Sharti
950117632Sharti	ret = malloc(IDT_NOR_END, M_TEMP, M_WAITOK);
951117632Sharti
952117632Sharti	mtx_lock(&sc->mtx);
953117632Sharti	for (i = 0; i < IDT_NOR_END; i += 4)
954117632Sharti		ret[i / 4] = patm_nor_read(sc, i);
955117632Sharti	mtx_unlock(&sc->mtx);
956117632Sharti
957117632Sharti	error = SYSCTL_OUT(req, ret, IDT_NOR_END);
958117632Sharti	free(ret, M_TEMP);
959117632Sharti
960117632Sharti	return (error);
961117632Sharti}
962117632Sharti
963117632Sharti/*
964117632Sharti * Sysctl handler for TSQ
965117632Sharti *
966117632Sharti * LOCK: unlocked, needed
967117632Sharti */
968117632Shartistatic int
969117632Shartipatm_sysctl_tsq(SYSCTL_HANDLER_ARGS)
970117632Sharti{
971117632Sharti	struct patm_softc *sc = arg1;
972117632Sharti	void *ret;
973117632Sharti	int error;
974117632Sharti
975117632Sharti	ret = malloc(IDT_TSQ_SIZE * IDT_TSQE_SIZE, M_TEMP, M_WAITOK);
976117632Sharti
977117632Sharti	mtx_lock(&sc->mtx);
978117632Sharti	memcpy(ret, sc->tsq, IDT_TSQ_SIZE * IDT_TSQE_SIZE);
979117632Sharti	mtx_unlock(&sc->mtx);
980117632Sharti
981117632Sharti	error = SYSCTL_OUT(req, ret, IDT_TSQ_SIZE * IDT_TSQE_SIZE);
982117632Sharti	free(ret, M_TEMP);
983117632Sharti
984117632Sharti	return (error);
985117632Sharti}
986117632Sharti
987117632Sharti/*
988117632Sharti * debugging
989117632Sharti */
990117632Shartistatic struct patm_softc *
991117632Shartipatm_dump_unit(u_int unit)
992117632Sharti{
993117632Sharti	devclass_t dc;
994117632Sharti	struct patm_softc *sc;
995117632Sharti
996117632Sharti	dc = devclass_find("patm");
997117632Sharti	if (dc == NULL) {
998117632Sharti		printf("%s: can't find devclass\n", __func__);
999117632Sharti		return (NULL);
1000117632Sharti	}
1001117632Sharti	sc = devclass_get_softc(dc, unit);
1002117632Sharti	if (sc == NULL) {
1003117632Sharti		printf("%s: invalid unit number: %d\n", __func__, unit);
1004117632Sharti		return (NULL);
1005117632Sharti	}
1006117632Sharti	return (sc);
1007117632Sharti}
1008117632Sharti
1009117632Shartiint
1010117632Shartipatm_dump_vc(u_int unit, u_int vc)
1011117632Sharti{
1012117632Sharti	struct patm_softc *sc;
1013117632Sharti	uint32_t tct[8];
1014117632Sharti	uint32_t rct[4];
1015117632Sharti	uint32_t scd[12];
1016117632Sharti	u_int i;
1017117632Sharti
1018117632Sharti	if ((sc = patm_dump_unit(unit)) == NULL)
1019117632Sharti		return (0);
1020117632Sharti
1021117632Sharti	for (i = 0; i < 8; i++)
1022117632Sharti		tct[i] = patm_sram_read(sc, vc * 8 + i);
1023117632Sharti	for (i = 0; i < 4; i++)
1024117632Sharti		rct[i] = patm_sram_read(sc, sc->mmap->rct + vc * 4 + i);
1025117632Sharti	for (i = 0; i < 12; i++)
1026117632Sharti		scd[i] = patm_sram_read(sc, (tct[0] & 0x7ffff) + i);
1027117632Sharti
1028117632Sharti	printf("TCT%3u: %08x %08x %08x %08x  %08x %08x %08x %08x\n", vc,
1029117632Sharti	    tct[0], tct[1], tct[2], tct[3], tct[4], tct[5], tct[6], tct[7]);
1030117632Sharti	printf("RCT%3u: %08x %08x %08x %08x\n", vc,
1031117632Sharti	    rct[0], rct[1], rct[2], rct[3]);
1032117632Sharti	printf("SCD%3u: %08x %08x %08x %08x  %08x %08x %08x %08x\n", vc,
1033117632Sharti	    scd[0], scd[1], scd[2], scd[3], scd[4], scd[5], scd[6], scd[7]);
1034117632Sharti	printf("        %08x %08x %08x %08x\n",
1035117632Sharti	    scd[8], scd[9], scd[10], scd[11]);
1036117632Sharti
1037117632Sharti	return (0);
1038117632Sharti}
1039117632Sharti
1040117632Shartiint
1041117632Shartipatm_dump_regs(u_int unit)
1042117632Sharti{
1043117632Sharti	struct patm_softc *sc;
1044117632Sharti	u_int i;
1045117632Sharti
1046117632Sharti	if ((sc = patm_dump_unit(unit)) == NULL)
1047117632Sharti		return (0);
1048117632Sharti
1049117632Sharti	for (i = 0; i <= IDT_NOR_DNOW; i += 4)
1050117632Sharti		printf("%x: %08x\n", i, patm_nor_read(sc, i));
1051117632Sharti
1052117632Sharti	return (0);
1053117632Sharti}
1054117632Sharti
1055117632Shartiint
1056117632Shartipatm_dump_sram(u_int unit, u_int from, u_int words)
1057117632Sharti{
1058117632Sharti	struct patm_softc *sc;
1059117632Sharti	u_int i;
1060117632Sharti
1061117632Sharti	if ((sc = patm_dump_unit(unit)) == NULL)
1062117632Sharti		return (0);
1063117632Sharti
1064117632Sharti	for (i = 0; i < words; i++) {
1065117632Sharti		if (i % 8 == 0)
1066117632Sharti			printf("%05x:", from + i);
1067117632Sharti		printf(" %08x", patm_sram_read(sc, from + i));
1068117632Sharti		if (i % 8 == 7)
1069117632Sharti			printf("\n");
1070117632Sharti	}
1071117632Sharti	if (i % 8 != 0)
1072117632Sharti		printf("\n");
1073117632Sharti	return (0);
1074117632Sharti}
1075117632Sharti#endif
1076