1/*	$NetBSD: iavc_pci.c,v 1.12 2009/11/26 15:17:09 njoly Exp $	*/
2
3/*
4 * Copyright (c) 2001-2003 Cubical Solutions Ltd.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * capi/iavc/iavc_pci.c
29 *		The AVM ISDN controllers' PCI bus attachment handling.
30 *
31 * $FreeBSD: src/sys/i4b/capi/iavc/iavc_pci.c,v 1.1.2.1 2001/08/10 14:08:34 obrien Exp $
32 */
33
34#include <sys/cdefs.h>
35__KERNEL_RCSID(0, "$NetBSD: iavc_pci.c,v 1.12 2009/11/26 15:17:09 njoly Exp $");
36
37#include <sys/param.h>
38#include <sys/kernel.h>
39#include <sys/systm.h>
40#include <sys/mbuf.h>
41#include <sys/callout.h>
42#include <sys/socket.h>
43#include <sys/device.h>
44#include <net/if.h>
45
46#include <sys/bus.h>
47
48#include <dev/pci/pcireg.h>
49#include <dev/pci/pcivar.h>
50#include <dev/pci/pcidevs.h>
51
52#include <netisdn/i4b_ioctl.h>
53#include <netisdn/i4b_l3l4.h>
54#include <netisdn/i4b_capi.h>
55
56#include <dev/ic/iavcvar.h>
57#include <dev/ic/iavcreg.h>
58
59struct iavc_pci_softc {
60	struct iavc_softc sc_iavc;
61
62	bus_addr_t mem_base;
63	bus_size_t mem_size;
64	bus_addr_t io_base;
65	bus_size_t io_size;
66
67	pci_chipset_tag_t sc_pc;
68
69	void *sc_ih;		/* interrupt handler */
70};
71#define IAVC_PCI_IOBA	0x14
72#define IAVC_PCI_MMBA	0x10
73
74/* PCI driver linkage */
75
76static const struct iavc_pci_product *find_cardname(struct pci_attach_args *);
77
78static int iavc_pci_probe(device_t, cfdata_t, void *);
79static void iavc_pci_attach(device_t, device_t, void *);
80
81int iavc_pci_intr(void *);
82
83CFATTACH_DECL(iavc_pci, sizeof(struct iavc_pci_softc),
84    iavc_pci_probe, iavc_pci_attach, NULL, NULL);
85
86static const struct iavc_pci_product {
87	pci_vendor_id_t npp_vendor;
88	pci_product_id_t npp_product;
89	const char *name;
90} iavc_pci_products[] = {
91	{ PCI_VENDOR_AVM, PCI_PRODUCT_AVM_B1, "AVM B1 PCI" },
92	{ PCI_VENDOR_AVM, PCI_PRODUCT_AVM_T1, "AVM T1 PCI" },
93	{ 0, 0, NULL },
94};
95
96static const struct iavc_pci_product *
97find_cardname(struct pci_attach_args * pa)
98{
99	const struct iavc_pci_product *pp = NULL;
100
101	for (pp = iavc_pci_products; pp->npp_vendor; pp++) {
102		if (PCI_VENDOR(pa->pa_id) == pp->npp_vendor &&
103		    PCI_PRODUCT(pa->pa_id) == pp->npp_product)
104			return pp;
105	}
106
107	return NULL;
108}
109
110static int
111iavc_pci_probe(device_t parent, cfdata_t match, void *aux)
112{
113	struct pci_attach_args *pa = aux;
114
115	if (find_cardname(pa))
116		return 1;
117
118	return 0;
119}
120
121static void
122iavc_pci_attach(device_t parent, device_t self, void *aux)
123{
124	struct iavc_pci_softc *psc = device_private(self);
125	struct iavc_softc *sc = &psc->sc_iavc;
126	struct pci_attach_args *pa = aux;
127	pci_chipset_tag_t pc = pa->pa_pc;
128	const struct iavc_pci_product *pp;
129	pci_intr_handle_t ih;
130	const char *intrstr;
131	int ret;
132
133	pp = find_cardname(pa);
134	if (pp == NULL)
135		return;
136
137	sc->sc_t1 = 0;
138	sc->sc_dma = 0;
139	sc->dmat = pa->pa_dmat;
140
141	iavc_b1dma_reset(sc);
142
143	if (pci_mapreg_map(pa, IAVC_PCI_IOBA, PCI_MAPREG_TYPE_IO, 0,
144		&sc->sc_io_bt, &sc->sc_io_bh, &psc->io_base, &psc->io_size)) {
145		aprint_error(": unable to map i/o registers\n");
146		return;
147	}
148
149	if (pci_mapreg_map(pa, IAVC_PCI_MMBA, PCI_MAPREG_TYPE_MEM, 0,
150	     &sc->sc_mem_bt, &sc->sc_mem_bh, &psc->mem_base, &psc->mem_size)) {
151		aprint_error(": unable to map mem registers\n");
152		return;
153	}
154	aprint_normal(": %s\n", pp->name);
155
156	if (pp->npp_product == PCI_PRODUCT_AVM_T1) {
157		aprint_error_dev(&sc->sc_dev, "sorry, PRI not yet supported\n");
158		return;
159
160#if 0
161		sc->sc_capi.card_type = CARD_TYPEC_AVM_T1_PCI;
162		sc->sc_capi.sc_nbch = NBCH_PRI;
163		ret = iavc_t1_detect(sc);
164		if (ret) {
165			if (ret < 6) {
166				aprint_error_dev(&sc->sc_dev, "no card detected?\n");
167			} else {
168				aprint_error_dev(&sc->sc_dev, "black box not on\n");
169			}
170			return;
171		} else {
172			sc->sc_dma = 1;
173			sc->sc_t1 = 1;
174		}
175#endif
176
177	} else if (pp->npp_product == PCI_PRODUCT_AVM_B1) {
178		sc->sc_capi.card_type = CARD_TYPEC_AVM_B1_PCI;
179		sc->sc_capi.sc_nbch = NBCH_BRI;
180		ret = iavc_b1dma_detect(sc);
181		if (ret) {
182			ret = iavc_b1_detect(sc);
183			if (ret) {
184				aprint_error_dev(&sc->sc_dev, "no card detected?\n");
185				return;
186			}
187		} else {
188			sc->sc_dma = 1;
189		}
190	}
191	if (sc->sc_dma)
192		iavc_b1dma_reset(sc);
193
194#if 0
195	/*
196         * XXX: should really be done this way, but this freezes the card
197         */
198	if (sc->sc_t1)
199		iavc_t1_reset(sc);
200	else
201		iavc_b1_reset(sc);
202#endif
203
204	if (pci_intr_map(pa, &ih)) {
205		aprint_error_dev(&sc->sc_dev, "couldn't map interrupt\n");
206		return;
207	}
208
209	intrstr = pci_intr_string(pc, ih);
210	psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, iavc_pci_intr, psc);
211	if (psc->sc_ih == NULL) {
212		aprint_error_dev(&sc->sc_dev, "couldn't establish interrupt");
213		if (intrstr != NULL)
214			aprint_error(" at %s", intrstr);
215		aprint_error("\n");
216		return;
217	}
218	psc->sc_pc = pc;
219	aprint_normal("%s: interrupting at %s\n", device_xname(&sc->sc_dev), intrstr);
220
221	memset(&sc->sc_txq, 0, sizeof(struct ifqueue));
222	sc->sc_txq.ifq_maxlen = sc->sc_capi.sc_nbch * 4;
223
224	sc->sc_intr = 0;
225	sc->sc_state = IAVC_DOWN;
226	sc->sc_blocked = 0;
227
228	/* setup capi link */
229	sc->sc_capi.load = iavc_load;
230	sc->sc_capi.reg_appl = iavc_register;
231	sc->sc_capi.rel_appl = iavc_release;
232	sc->sc_capi.send = iavc_send;
233	sc->sc_capi.ctx = (void *) sc;
234
235	/* lock & load DMA for TX */
236	if ((ret = bus_dmamem_alloc(sc->dmat, IAVC_DMA_SIZE, PAGE_SIZE, 0,
237	    &sc->txseg, 1, &sc->ntxsegs, BUS_DMA_ALLOCNOW)) != 0) {
238		aprint_error_dev(&sc->sc_dev, "can't allocate tx DMA memory, error = %d\n",
239		    ret);
240		goto fail1;
241	}
242
243	if ((ret = bus_dmamem_map(sc->dmat, &sc->txseg, sc->ntxsegs,
244	    IAVC_DMA_SIZE, &sc->sc_sendbuf, BUS_DMA_NOWAIT)) != 0) {
245		aprint_error_dev(&sc->sc_dev, "can't map tx DMA memory, error = %d\n",
246		    ret);
247		goto fail2;
248	}
249
250	if ((ret = bus_dmamap_create(sc->dmat, IAVC_DMA_SIZE, 1,
251	    IAVC_DMA_SIZE, 0, BUS_DMA_ALLOCNOW | BUS_DMA_NOWAIT,
252	    &sc->tx_map)) != 0) {
253		aprint_error_dev(&sc->sc_dev, "can't create tx DMA map, error = %d\n",
254		    ret);
255		goto fail3;
256	}
257
258	if ((ret = bus_dmamap_load(sc->dmat, sc->tx_map, sc->sc_sendbuf,
259	    IAVC_DMA_SIZE, NULL, BUS_DMA_WRITE | BUS_DMA_NOWAIT)) != 0) {
260		aprint_error_dev(&sc->sc_dev, "can't load tx DMA map, error = %d\n",
261		    ret);
262		goto fail4;
263	}
264
265	/* do the same for RX */
266	if ((ret = bus_dmamem_alloc(sc->dmat, IAVC_DMA_SIZE, PAGE_SIZE, 0,
267	    &sc->rxseg, 1, &sc->nrxsegs, BUS_DMA_ALLOCNOW)) != 0) {
268		aprint_error_dev(&sc->sc_dev, "can't allocate rx DMA memory, error = %d\n",
269		    ret);
270		goto fail5;
271	}
272
273	if ((ret = bus_dmamem_map(sc->dmat, &sc->rxseg, sc->nrxsegs,
274	    IAVC_DMA_SIZE, &sc->sc_recvbuf, BUS_DMA_NOWAIT)) != 0) {
275		aprint_error_dev(&sc->sc_dev, "can't map rx DMA memory, error = %d\n",
276		    ret);
277		goto fail6;
278	}
279
280	if ((ret = bus_dmamap_create(sc->dmat, IAVC_DMA_SIZE, 1, IAVC_DMA_SIZE,
281	    0, BUS_DMA_ALLOCNOW | BUS_DMA_NOWAIT, &sc->rx_map)) != 0) {
282		aprint_error_dev(&sc->sc_dev, "can't create rx DMA map, error = %d\n",
283		    ret);
284		goto fail7;
285	}
286
287	if ((ret = bus_dmamap_load(sc->dmat, sc->rx_map, sc->sc_recvbuf,
288	    IAVC_DMA_SIZE, NULL, BUS_DMA_READ | BUS_DMA_NOWAIT)) != 0) {
289		aprint_error_dev(&sc->sc_dev, "can't load rx DMA map, error = %d\n",
290		    ret);
291		goto fail8;
292	}
293
294	if (capi_ll_attach(&sc->sc_capi, device_xname(&sc->sc_dev), pp->name)) {
295		aprint_error_dev(&sc->sc_dev, "capi attach failed\n");
296		goto fail9;
297	}
298	return;
299
300	/* release resources in case of failed attach */
301fail9:
302	bus_dmamap_unload(sc->dmat, sc->rx_map);
303fail8:
304	bus_dmamap_destroy(sc->dmat, sc->rx_map);
305fail7:
306	bus_dmamem_unmap(sc->dmat, sc->sc_recvbuf, IAVC_DMA_SIZE);
307fail6:
308	bus_dmamem_free(sc->dmat, &sc->rxseg, sc->nrxsegs);
309fail5:
310	bus_dmamap_unload(sc->dmat, sc->tx_map);
311fail4:
312	bus_dmamap_destroy(sc->dmat, sc->tx_map);
313fail3:
314	bus_dmamem_unmap(sc->dmat, sc->sc_sendbuf, IAVC_DMA_SIZE);
315fail2:
316	bus_dmamem_free(sc->dmat, &sc->txseg, sc->ntxsegs);
317fail1:
318	pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
319
320	return;
321}
322
323int
324iavc_pci_intr(void *arg)
325{
326	struct iavc_softc *sc = arg;
327
328	return iavc_handle_intr(sc);
329}
330
331#if 0
332static int
333iavc_pci_detach(device_t self, int flags)
334{
335	struct iavc_pci_softc *psc = device_private(self);
336
337	bus_space_unmap(psc->sc_iavc.sc_mem_bt, psc->sc_iavc.sc_mem_bh,
338	    psc->mem_size);
339	bus_space_free(psc->sc_iavc.sc_mem_bt, psc->sc_iavc.sc_mem_bh,
340	    psc->mem_size);
341	bus_space_unmap(psc->sc_iavc.sc_io_bt, psc->sc_iavc.sc_io_bh,
342	    psc->io_size);
343	bus_space_free(psc->sc_iavc.sc_io_bt, psc->sc_iavc.sc_io_bh,
344	    psc->io_size);
345
346	pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
347
348	/* XXX: capi detach?!? */
349
350	return 0;
351}
352#endif
353