1 /* $NetBSD: if_fpa.c,v 1.55 2009/05/12 08:23:00 cegger Exp $ */
4 * Copyright (c) 1995, 1996 Matt Thomas <matt@3am-software.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. The name of the author may not be used to endorse or promote products
13 * derived from this software without specific prior written permission
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 * Id: if_fpa.c,v 1.11 1997/06/05 01:56:35 thomas Exp
31 * DEC PDQ FDDI Controller; code for BSD derived operating systems
33 * This module supports the DEC DEFPA PCI FDDI Controller
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: if_fpa.c,v 1.55 2009/05/12 08:23:00 cegger Exp $");
43 #include <sys/param.h>
44 #include <sys/kernel.h>
46 #include <sys/protosw.h>
47 #include <sys/socket.h>
48 #include <sys/ioctl.h>
49 #include <sys/errno.h>
50 #include <sys/malloc.h>
51 #if defined(__FreeBSD__) && BSD < 199401
52 #include <sys/devconf.h>
53 #elif defined(__bsdi__) || defined(__NetBSD__)
54 #include <sys/device.h>
58 #include <net/if_types.h>
59 #include <net/if_dl.h>
60 #include <net/route.h>
65 #include <net/bpfdesc.h>
68 #if defined(__FreeBSD__)
69 #include <netinet/if_fddi.h>
71 #include <net/if_fddi.h>
74 #if defined(__FreeBSD__)
77 #include <netinet/if_ether.h>
78 #include <pci/pcivar.h>
79 #include <i386/isa/icu.h>
80 #include <dev/pdq/pdqvar.h>
81 #include <dev/pdq/pdqreg.h>
82 #elif defined(__bsdi__)
83 #include <netinet/if_ether.h>
84 #include <i386/isa/isavar.h>
85 #include <i386/isa/icu.h>
89 #if _BSDI_VERSION < 199401
92 #include <i386/pci/pci.h>
93 #include <dev/pdq/pdqvar.h>
94 #include <dev/pdq/pdqreg.h>
95 #elif defined(__NetBSD__)
96 #include <dev/pci/pcidevs.h>
97 #include <dev/pci/pcivar.h>
98 #include <dev/ic/pdqvar.h>
99 #include <dev/ic/pdqreg.h>
100 #endif /* __NetBSD__ */
103 #define DEC_VENDORID 0x1011
104 #define DEFPA_CHIPID 0x000F
105 #define PCI_VENDORID(x) ((x) & 0xFFFF)
106 #define PCI_CHIPID(x) (((x) >> 16) & 0xFFFF)
108 #define DEFPA_LATENCY 0x88
110 #define PCI_CFLT 0x0C /* Configuration Latency */
111 #define PCI_CBMA 0x10 /* Configuration Base Memory Address */
112 #define PCI_CBIO 0x14 /* Configuration Base I/O Address */
114 #if defined(__FreeBSD__)
119 static pdq_softc_t
*pdqs_pci
[NFPA
];
120 #define PDQ_PCI_UNIT_TO_SOFTC(unit) (pdqs_pci[unit])
122 #define pdq_pci_ifwatchdog NULL
123 static void pdq_pci_shutdown(int howto
, void *sc
);
126 #elif defined(__bsdi__)
127 extern struct cfdriver fpacd
;
128 #define PDQ_PCI_UNIT_TO_SOFTC(unit) ((pdq_softc_t *)device_lookup_private(&fpa_cd, unit))
130 #elif defined(__NetBSD__)
131 extern struct cfdriver fpa_cd
;
132 #define PDQ_PCI_UNIT_TO_SOFTC(unit) ((pdq_softc_t *)device_lookup_private(&fpa_cd, unit))
133 #define pdq_pci_ifwatchdog NULL
136 #ifndef pdq_pci_ifwatchdog
141 pdq_ifwatchdog(&PDQ_PCI_UNIT_TO_SOFTC(unit
)->sc_if
);
145 #if defined(__FreeBSD__) && BSD >= 199506
150 (void) pdq_interrupt(((pdq_softc_t
*) arg
)->sc_pdq
);
157 pdq_softc_t
* const sc
= (pdq_softc_t
*) arg
;
159 return pdq_interrupt(sc
->sc_pdq
);
160 #elif defined(__bsdi__) || defined(__NetBSD__)
161 (void) pdq_interrupt(sc
->sc_pdq
);
165 #endif /* __FreeBSD && BSD */
167 #if defined(__FreeBSD__)
169 * This is the PCI configuration support. Since the PDQ is available
170 * on both EISA and PCI boards, one must be careful in how defines the
171 * PDQ in the config file.
178 if (PCI_VENDORID(device_id
) == DEC_VENDORID
&&
179 PCI_CHIPID(device_id
) == DEFPA_CHIPID
)
180 return "Digital DEFPA PCI FDDI Controller";
195 printf("fpa%d: not configured; kernel is built for only %d device%s.\n",
196 unit
, NFPA
, NFPA
== 1 ? "" : "s");
200 data
= pci_conf_read(config_id
, PCI_CFLT
);
201 if ((data
& 0xFF00) < (DEFPA_LATENCY
<< 8)) {
203 data
|= DEFPA_LATENCY
<< 8;
204 pci_conf_write(config_id
, PCI_CFLT
, data
);
207 sc
= (pdq_softc_t
*) malloc(sizeof(*sc
), M_DEVBUF
, M_NOWAIT
|M_ZERO
);
211 if (!pci_map_mem(config_id
, PCI_CBMA
, &va_csrs
, &pa_csrs
)) {
212 free((void *) sc
, M_DEVBUF
);
216 sc
->sc_if
.if_name
= "fpa";
217 sc
->sc_if
.if_unit
= unit
;
218 sc
->sc_membase
= (pdq_bus_memaddr_t
) va_csrs
;
219 sc
->sc_pdq
= pdq_initialize(PDQ_BUS_PCI
, sc
->sc_membase
,
220 sc
->sc_if
.if_name
, sc
->sc_if
.if_unit
,
221 (void *) sc
, PDQ_DEFPA
);
222 if (sc
->sc_pdq
== NULL
) {
223 free((void *) sc
, M_DEVBUF
);
226 memcpy(sc
->sc_ac
.ac_enaddr
, (void *) sc
->sc_pdq
->pdq_hwaddr
.lanaddr_bytes
, 6);
228 pdq_ifattach(sc
, pdq_pci_ifwatchdog
);
229 pci_map_int(config_id
, pdq_pci_ifintr
, (void*) sc
, &net_imask
);
231 at_shutdown(pdq_pci_shutdown
, (void *) sc
, SHUTDOWN_POST_SYNC
);
238 struct kern_devconf
*kdc
,
241 if (kdc
->kdc_unit
< NFPA
)
242 pdq_hwreset(PDQ_PCI_UNIT_TO_SOFTC(kdc
->kdc_unit
)->sc_pdq
);
243 (void) dev_detach(kdc
);
252 pdq_hwreset(((pdq_softc_t
*)sc
)->sc_pdq
);
256 static u_long pdq_pci_count
;
258 struct pci_device fpadevice
= {
269 DATA_SET (pcidevice_set
, fpadevice
);
271 #elif defined(__bsdi__)
280 id
= pci_inl(pa
, PCI_VENDOR_ID
);
281 if (PCI_VENDORID(id
) != DEC_VENDORID
|| PCI_CHIPID(id
) != DEFPA_CHIPID
)
284 irq
= pci_inl(pa
, PCI_I_LINE
) & 0xFF;
285 if (irq
== 0 || irq
>= 16)
292 pdq_pci_probe(device_t parent
, cfdata_t cf
, void *aux
)
294 struct isa_attach_args
*ia
= (struct isa_attach_args
*) aux
;
295 pdq_uint32_t irq
, data
;
298 pa
= pci_scan(pdq_pci_match
);
302 irq
= (1 << (pci_inl(pa
, PCI_I_LINE
) & 0xFF));
304 if (ia
->ia_irq
!= IRQUNK
&& irq
!= ia
->ia_irq
) {
305 printf("fpa%d: error: desired IRQ of %d does not match device's actual IRQ of %d\n",
307 ffs(ia
->ia_irq
) - 1, ffs(irq
) - 1);
310 if (ia
->ia_irq
== IRQUNK
) {
311 (void) isa_irqalloc(irq
);
315 /* PCI bus masters don't use host DMA channels */
316 ia
->ia_drq
= DRQNONE
;
318 /* Get the memory base address; assume the BIOS set it up correctly */
319 ia
->ia_maddr
= (void *) (pci_inl(pa
, PCI_CBMA
) & ~7);
320 pci_outl(pa
, PCI_CBMA
, 0xFFFFFFFF);
321 ia
->ia_msize
= ((~pci_inl(pa
, PCI_CBMA
)) | 7) + 1;
322 pci_outl(pa
, PCI_CBMA
, (int) ia
->ia_maddr
);
324 /* Disable I/O space access */
325 pci_outl(pa
, PCI_COMMAND
, pci_inl(pa
, PCI_COMMAND
) & ~1);
329 /* Make sure the latency timer is what the DEFPA likes */
330 data
= pci_inl(pa
, PCI_CFLT
);
331 if ((data
& 0xFF00) < (DEFPA_LATENCY
<< 8)) {
333 data
|= DEFPA_LATENCY
<< 8;
334 pci_outl(pa
, PCI_CFLT
, data
);
336 ia
->ia_irq
|= IRQSHARE
;
342 pdq_pci_attach(device_t parent
, device_t self
, void *aux
)
344 pdq_softc_t
*sc
= device_private(self
);
345 struct isa_attach_args
*ia
= (struct isa_attach_args
*) aux
;
346 struct ifnet
*ifp
= &sc
->sc_if
;
349 sc
->sc_if
.if_unit
= sc
->sc_dev
.dv_unit
;
350 sc
->sc_if
.if_name
= "fpa";
351 sc
->sc_if
.if_flags
= 0;
352 sc
->sc_membase
= (pdq_bus_memaddr_t
) mapphys((vaddr_t
)ia
->ia_maddr
, ia
->ia_msize
);
354 sc
->sc_pdq
= pdq_initialize(PDQ_BUS_PCI
, sc
->sc_membase
,
355 sc
->sc_if
.if_name
, sc
->sc_if
.if_unit
,
356 (void *) sc
, PDQ_DEFPA
);
357 if (sc
->sc_pdq
== NULL
) {
358 printf("fpa%d: initialization failed\n", sc
->sc_if
.if_unit
);
362 memcpy(sc
->sc_ac
.ac_enaddr
, (void *) sc
->sc_pdq
->pdq_hwaddr
.lanaddr_bytes
, 6);
364 pdq_ifattach(sc
, pdq_pci_ifwatchdog
);
366 isa_establish(&sc
->sc_id
, &sc
->sc_dev
);
368 sc
->sc_ih
.ih_fun
= pdq_pci_ifintr
;
369 sc
->sc_ih
.ih_arg
= (void *)sc
;
370 intr_establish(ia
->ia_irq
, &sc
->sc_ih
, DV_NET
);
372 sc
->sc_ats
.func
= (void (*)(void *)) pdq_hwreset
;
373 sc
->sc_ats
.arg
= (void *) sc
->sc_pdq
;
374 atshutdown(&sc
->sc_ats
, ATSH_ADD
);
377 struct cfdriver fpacd
= {
378 0, "fpa", pdq_pci_probe
, pdq_pci_attach
,
379 #if _BSDI_VERSION >= 199401
385 #elif defined(__NetBSD__)
388 pdq_pci_match(device_t parent
, cfdata_t match
, void *aux
)
390 struct pci_attach_args
*pa
= (struct pci_attach_args
*) aux
;
392 if (PCI_VENDOR(pa
->pa_id
) != PCI_VENDOR_DEC
)
394 if (PCI_PRODUCT(pa
->pa_id
) != PCI_PRODUCT_DEC_DEFPA
)
401 pdq_pci_attach(device_t
const parent
, device_t
const self
, void *const aux
)
403 pdq_softc_t
* const sc
= device_private(self
);
404 struct pci_attach_args
* const pa
= (struct pci_attach_args
*) aux
;
406 pci_intr_handle_t intrhandle
;
408 bus_space_tag_t iot
, memt
;
409 bus_space_handle_t ioh
, memh
;
410 int ioh_valid
, memh_valid
;
412 aprint_naive(": FDDI controller\n");
414 data
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, PCI_CFLT
);
415 if ((data
& 0xFF00) < (DEFPA_LATENCY
<< 8)) {
417 data
|= DEFPA_LATENCY
<< 8;
418 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, PCI_CFLT
, data
);
421 strlcpy(sc
->sc_if
.if_xname
, device_xname(&sc
->sc_dev
), IFNAMSIZ
);
422 sc
->sc_if
.if_flags
= 0;
423 sc
->sc_if
.if_softc
= sc
;
425 ioh_valid
= (pci_mapreg_map(pa
, PCI_CBIO
, PCI_MAPREG_TYPE_IO
, 0,
426 &iot
, &ioh
, NULL
, NULL
) == 0);
427 memh_valid
= (pci_mapreg_map(pa
, PCI_CBMA
,
428 PCI_MAPREG_TYPE_MEM
| PCI_MAPREG_MEM_TYPE_32BIT
, 0,
429 &memt
, &memh
, NULL
, NULL
) == 0);
431 #if defined(DEFPA_IOMAPED)
434 sc
->sc_membase
= ioh
;
435 } else if (memh_valid
) {
436 sc
->sc_csrtag
= memt
;
437 sc
->sc_membase
= memh
;
439 #else /* defined(DEFPA_IOMAPPED) */
441 sc
->sc_csrtag
= memt
;
442 sc
->sc_membase
= memh
;
443 } else if (ioh_valid
) {
445 sc
->sc_membase
= ioh
;
447 #endif /* DEFPA_IOMAPPED */
449 aprint_error(": unable to map device registers\n");
453 sc
->sc_dmatag
= pa
->pa_dmat
;
455 /* Make sure bus mastering is enabled. */
456 pci_conf_write(pa
->pa_pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
,
457 pci_conf_read(pa
->pa_pc
, pa
->pa_tag
,
458 PCI_COMMAND_STATUS_REG
) |
459 PCI_COMMAND_MASTER_ENABLE
);
461 sc
->sc_pdq
= pdq_initialize(sc
->sc_csrtag
, sc
->sc_membase
,
462 sc
->sc_if
.if_xname
, 0,
463 (void *) sc
, PDQ_DEFPA
);
464 if (sc
->sc_pdq
== NULL
) {
465 aprint_error_dev(&sc
->sc_dev
, "initialization failed\n");
469 pdq_ifattach(sc
, pdq_pci_ifwatchdog
);
471 if (pci_intr_map(pa
, &intrhandle
)) {
472 aprint_error_dev(self
, "couldn't map interrupt\n");
475 intrstr
= pci_intr_string(pa
->pa_pc
, intrhandle
);
476 sc
->sc_ih
= pci_intr_establish(pa
->pa_pc
, intrhandle
, IPL_NET
, pdq_pci_ifintr
, sc
);
477 if (sc
->sc_ih
== NULL
) {
478 aprint_error_dev(self
, "couldn't establish interrupt");
480 aprint_error(" at %s", intrstr
);
485 sc
->sc_ats
= shutdownhook_establish((void (*)(void *)) pdq_hwreset
, sc
->sc_pdq
);
486 if (sc
->sc_ats
== NULL
)
487 aprint_error_dev(self
, "warning: couldn't establish shutdown hook\n");
489 aprint_normal_dev(self
, "interrupting at %s\n", intrstr
);
492 CFATTACH_DECL(fpa
, sizeof(pdq_softc_t
),
493 pdq_pci_match
, pdq_pci_attach
, NULL
, NULL
);
495 #endif /* __NetBSD__ */