FreeBSD/Linux Kernel Cross Reference
sys/dev/pci/iavc_pci.c
1 /* $NetBSD: iavc_pci.c,v 1.2 2003/10/03 16:38:44 pooka 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.2 2003/10/03 16:38:44 pooka 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 <machine/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
59 struct 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
76 static const struct iavc_pci_product *find_cardname(struct pci_attach_args *);
77
78 static int iavc_pci_probe(struct device *, struct cfdata *, void *);
79 static void iavc_pci_attach(struct device *, struct device *, void *);
80
81 int iavc_pci_intr(void *);
82
83 CFATTACH_DECL(iavc_pci, sizeof(struct iavc_softc),
84 iavc_pci_probe, iavc_pci_attach, NULL, NULL);
85
86 static 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
96 static const struct iavc_pci_product *
97 find_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
110 static int
111 iavc_pci_probe(struct device * parent, struct cfdata * 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
121 static void
122 iavc_pci_attach(struct device * parent, struct device * self, void *aux)
123 {
124 struct iavc_pci_softc *psc = (void *) self;
125 struct iavc_softc *sc = (void *) self;
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("%s: sorry, PRI not yet supported\n",
158 sc->sc_dev.dv_xname);
159 return;
160
161 #if 0
162 sc->sc_capi.card_type = CARD_TYPEC_AVM_T1_PCI;
163 sc->sc_capi.sc_nbch = NBCH_PRI;
164 ret = iavc_t1_detect(sc);
165 if (ret) {
166 if (ret < 6) {
167 aprint_error("%s: no card detected?\n",
168 sc->sc_dev.dv_xname);
169 } else {
170 aprint_error("%s: black box not on\n",
171 sc->sc_dev.dv_xname);
172 }
173 return;
174 } else {
175 sc->sc_dma = 1;
176 sc->sc_t1 = 1;
177 }
178 #endif
179
180 } else if (pp->npp_product == PCI_PRODUCT_AVM_B1) {
181 sc->sc_capi.card_type = CARD_TYPEC_AVM_B1_PCI;
182 sc->sc_capi.sc_nbch = NBCH_BRI;
183 ret = iavc_b1dma_detect(sc);
184 if (ret) {
185 ret = iavc_b1_detect(sc);
186 if (ret) {
187 aprint_error("%s: no card detected?\n",
188 sc->sc_dev.dv_xname);
189 return;
190 }
191 } else {
192 sc->sc_dma = 1;
193 }
194 }
195 if (sc->sc_dma)
196 iavc_b1dma_reset(sc);
197
198 #if 0
199 /*
200 * XXX: should really be done this way, but this freezes the card
201 */
202 if (sc->sc_t1)
203 iavc_t1_reset(sc);
204 else
205 iavc_b1_reset(sc);
206 #endif
207
208 if (pci_intr_map(pa, &ih)) {
209 aprint_error("%s: couldn't map interrupt\n",
210 sc->sc_dev.dv_xname);
211 return;
212 }
213
214 intrstr = pci_intr_string(pc, ih);
215 psc->sc_ih = pci_intr_establish(pc, ih, IPL_NET, iavc_pci_intr, psc);
216 if (psc->sc_ih == NULL) {
217 aprint_error("%s: couldn't establish interrupt",
218 sc->sc_dev.dv_xname);
219 if (intrstr != NULL)
220 aprint_normal(" at %s", intrstr);
221 aprint_normal("\n");
222 return;
223 }
224 psc->sc_pc = pc;
225 aprint_normal("%s: interrupting at %s\n", sc->sc_dev.dv_xname, intrstr);
226
227 memset(&sc->sc_txq, 0, sizeof(struct ifqueue));
228 sc->sc_txq.ifq_maxlen = sc->sc_capi.sc_nbch * 4;
229
230 sc->sc_intr = 0;
231 sc->sc_state = IAVC_DOWN;
232 sc->sc_blocked = 0;
233
234 /* setup capi link */
235 sc->sc_capi.load = iavc_load;
236 sc->sc_capi.reg_appl = iavc_register;
237 sc->sc_capi.rel_appl = iavc_release;
238 sc->sc_capi.send = iavc_send;
239 sc->sc_capi.ctx = (void *) sc;
240
241 /* lock & load DMA for TX */
242 if ((ret = bus_dmamem_alloc(sc->dmat, IAVC_DMA_SIZE, PAGE_SIZE, 0,
243 &sc->txseg, 1, &sc->ntxsegs, BUS_DMA_ALLOCNOW)) != 0) {
244 aprint_error("%s: can't allocate tx DMA memory, error = %d\n",
245 sc->sc_dev.dv_xname, ret);
246 goto fail1;
247 }
248
249 if ((ret = bus_dmamem_map(sc->dmat, &sc->txseg, sc->ntxsegs,
250 IAVC_DMA_SIZE, &sc->sc_sendbuf, BUS_DMA_NOWAIT)) != 0) {
251 aprint_error("%s: can't map tx DMA memory, error = %d\n",
252 sc->sc_dev.dv_xname, ret);
253 goto fail2;
254 }
255
256 if ((ret = bus_dmamap_create(sc->dmat, IAVC_DMA_SIZE, 1,
257 IAVC_DMA_SIZE, 0, BUS_DMA_ALLOCNOW | BUS_DMA_NOWAIT,
258 &sc->tx_map)) != 0) {
259 aprint_error("%s: can't create tx DMA map, error = %d\n",
260 sc->sc_dev.dv_xname, ret);
261 goto fail3;
262 }
263
264 if ((ret = bus_dmamap_load(sc->dmat, sc->tx_map, sc->sc_sendbuf,
265 IAVC_DMA_SIZE, NULL, BUS_DMA_WRITE | BUS_DMA_NOWAIT)) != 0) {
266 aprint_error("%s: can't load tx DMA map, error = %d\n",
267 sc->sc_dev.dv_xname, ret);
268 goto fail4;
269 }
270
271 /* do the same for RX */
272 if ((ret = bus_dmamem_alloc(sc->dmat, IAVC_DMA_SIZE, PAGE_SIZE, 0,
273 &sc->rxseg, 1, &sc->nrxsegs, BUS_DMA_ALLOCNOW)) != 0) {
274 aprint_error("%s: can't allocate rx DMA memory, error = %d\n",
275 sc->sc_dev.dv_xname, ret);
276 goto fail5;
277 }
278
279 if ((ret = bus_dmamem_map(sc->dmat, &sc->rxseg, sc->nrxsegs,
280 IAVC_DMA_SIZE, &sc->sc_recvbuf, BUS_DMA_NOWAIT)) != 0) {
281 aprint_error("%s: can't map rx DMA memory, error = %d\n",
282 sc->sc_dev.dv_xname, ret);
283 goto fail6;
284 }
285
286 if ((ret = bus_dmamap_create(sc->dmat, IAVC_DMA_SIZE, 1, IAVC_DMA_SIZE,
287 0, BUS_DMA_ALLOCNOW | BUS_DMA_NOWAIT, &sc->rx_map)) != 0) {
288 aprint_error("%s: can't create rx DMA map, error = %d\n",
289 sc->sc_dev.dv_xname, ret);
290 goto fail7;
291 }
292
293 if ((ret = bus_dmamap_load(sc->dmat, sc->rx_map, sc->sc_recvbuf,
294 IAVC_DMA_SIZE, NULL, BUS_DMA_READ | BUS_DMA_NOWAIT)) != 0) {
295 aprint_error("%s: can't load rx DMA map, error = %d\n",
296 sc->sc_dev.dv_xname, ret);
297 goto fail8;
298 }
299
300 if (capi_ll_attach(&sc->sc_capi, sc->sc_dev.dv_xname, pp->name)) {
301 aprint_error("%s: capi attach failed\n", sc->sc_dev.dv_xname);
302 goto fail9;
303 }
304 return;
305
306 /* release resources in case of failed attach */
307 fail9:
308 bus_dmamap_unload(sc->dmat, sc->rx_map);
309 fail8:
310 bus_dmamap_destroy(sc->dmat, sc->rx_map);
311 fail7:
312 bus_dmamem_unmap(sc->dmat, sc->sc_recvbuf, IAVC_DMA_SIZE);
313 fail6:
314 bus_dmamem_free(sc->dmat, &sc->rxseg, sc->nrxsegs);
315 fail5:
316 bus_dmamap_unload(sc->dmat, sc->tx_map);
317 fail4:
318 bus_dmamap_destroy(sc->dmat, sc->tx_map);
319 fail3:
320 bus_dmamem_unmap(sc->dmat, sc->sc_sendbuf, IAVC_DMA_SIZE);
321 fail2:
322 bus_dmamem_free(sc->dmat, &sc->txseg, sc->ntxsegs);
323 fail1:
324 pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
325
326 return;
327 }
328
329 int
330 iavc_pci_intr(void *arg)
331 {
332 struct iavc_softc *sc = arg;
333
334 return iavc_handle_intr(sc);
335 }
336
337 #if 0
338 static int
339 iavc_pci_detach(struct device * self, int flags)
340 {
341 struct iavc_pci_softc *psc = (void *) self;
342
343 bus_space_unmap(psc->sc_iavc.sc_mem_bt, psc->sc_iavc.sc_mem_bh,
344 psc->mem_size);
345 bus_space_free(psc->sc_iavc.sc_mem_bt, psc->sc_iavc.sc_mem_bh,
346 psc->mem_size);
347 bus_space_unmap(psc->sc_iavc.sc_io_bt, psc->sc_iavc.sc_io_bh,
348 psc->io_size);
349 bus_space_free(psc->sc_iavc.sc_io_bt, psc->sc_iavc.sc_io_bh,
350 psc->io_size);
351
352 pci_intr_disestablish(psc->sc_pc, psc->sc_ih);
353
354 /* XXX: capi detach?!? */
355
356 return 0;
357 }
358
359 static int
360 iavc_pci_activate(struct device * self, enum devact act)
361 {
362 struct iavc_softc *psc = (struct iavc_softc *) self;
363 int error, s;
364
365 error = 0;
366
367 s = splnet();
368 switch (act) {
369 case DVACT_ACTIVATE:
370 error = EOPNOTSUPP;
371 break;
372 case DVACT_DEACTIVATE:
373 /* XXX */
374 break;
375 }
376
377 splx(s);
378
379 return error;
380 }
381 #endif
Cache object: d052e89b9ccf05cf16a7200069b2a0b4
|