1 /* $NetBSD: if_ne_pci.c,v 1.33 2009/05/06 09:25:15 cegger Exp $ */
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: if_ne_pci.c,v 1.33 2009/05/06 09:25:15 cegger Exp $");
36 #include "opt_ipkdb.h"
38 #include <sys/param.h>
39 #include <sys/systm.h>
41 #include <sys/syslog.h>
42 #include <sys/socket.h>
43 #include <sys/device.h>
46 #include <net/if_ether.h>
47 #include <net/if_media.h>
53 #include <ipkdb/ipkdb.h>
56 #include <dev/pci/pcireg.h>
57 #include <dev/pci/pcivar.h>
58 #include <dev/pci/pcidevs.h>
60 #include <dev/ic/dp8390reg.h>
61 #include <dev/ic/dp8390var.h>
63 #include <dev/ic/ne2000reg.h>
64 #include <dev/ic/ne2000var.h>
66 #include <dev/ic/rtl80x9reg.h>
67 #include <dev/ic/rtl80x9var.h>
70 struct ne2000_softc sc_ne2000
; /* real "ne2000" softc */
72 /* PCI-specific goo */
73 void *sc_ih
; /* interrupt handle */
76 static int ne_pci_match(device_t
, cfdata_t
, void *);
77 static void ne_pci_attach(device_t
, device_t
, void *);
79 CFATTACH_DECL_NEW(ne_pci
, sizeof(struct ne_pci_softc
),
80 ne_pci_match
, ne_pci_attach
, NULL
, NULL
);
83 static struct ne_pci_softc ipkdb_softc
;
84 static pci_chipset_tag_t ipkdb_pc
;
85 static pcitag_t ipkdb_tag
;
86 static struct ipkdb_if
*ne_kip
;
88 int ne_pci_ipkdb_attach(struct ipkdb_if
*, bus_space_tag_t
, /* XXX */
89 pci_chipset_tag_t
, int, int);
91 static int ne_pci_isipkdb(pci_chipset_tag_t
, pcitag_t
);
94 static const struct ne_pci_product
{
95 pci_vendor_id_t npp_vendor
;
96 pci_product_id_t npp_product
;
97 int (*npp_mediachange
)(struct dp8390_softc
*);
98 void (*npp_mediastatus
)(struct dp8390_softc
*, struct ifmediareq
*);
99 void (*npp_init_card
)(struct dp8390_softc
*);
100 void (*npp_media_init
)(struct dp8390_softc
*);
101 const char *npp_name
;
102 } ne_pci_products
[] = {
103 { PCI_VENDOR_REALTEK
, PCI_PRODUCT_REALTEK_RT8029
,
104 rtl80x9_mediachange
, rtl80x9_mediastatus
,
105 rtl80x9_init_card
, rtl80x9_media_init
,
108 { PCI_VENDOR_WINBOND
, PCI_PRODUCT_WINBOND_W89C940F
,
113 { PCI_VENDOR_WINBOND
, PCI_PRODUCT_WINBOND_W89C940F_1
,
118 { PCI_VENDOR_VIATECH
, PCI_PRODUCT_VIATECH_VT86C926
,
121 "VIA Technologies VT86C926" },
123 { PCI_VENDOR_SURECOM
, PCI_PRODUCT_SURECOM_NE34
,
128 { PCI_VENDOR_NETVIN
, PCI_PRODUCT_NETVIN_5000
,
133 /* XXX The following entries need sanity checking in pcidevs */
134 { PCI_VENDOR_COMPEX
, PCI_PRODUCT_COMPEX_NE2KETHER
,
139 { PCI_VENDOR_PROLAN
, PCI_PRODUCT_PROLAN_NE2KETHER
,
144 { PCI_VENDOR_KTI
, PCI_PRODUCT_KTI_NE2KETHER
,
155 static const struct ne_pci_product
*
156 ne_pci_lookup(const struct pci_attach_args
*pa
)
158 const struct ne_pci_product
*npp
;
160 for (npp
= ne_pci_products
; npp
->npp_name
!= NULL
; npp
++) {
161 if (PCI_VENDOR(pa
->pa_id
) == npp
->npp_vendor
&&
162 PCI_PRODUCT(pa
->pa_id
) == npp
->npp_product
)
170 * XXX These should be in a common file!
172 #define PCI_CBIO 0x10 /* Configuration Base IO Address */
175 ne_pci_match(device_t parent
, cfdata_t match
, void *aux
)
177 struct pci_attach_args
*pa
= aux
;
179 if (ne_pci_lookup(pa
) != NULL
)
186 ne_pci_attach(device_t parent
, device_t self
, void *aux
)
188 struct ne_pci_softc
*psc
= device_private(self
);
189 struct ne2000_softc
*nsc
= &psc
->sc_ne2000
;
190 struct dp8390_softc
*dsc
= &nsc
->sc_dp8390
;
191 struct pci_attach_args
*pa
= aux
;
192 pci_chipset_tag_t pc
= pa
->pa_pc
;
193 bus_space_tag_t nict
;
194 bus_space_handle_t nich
;
195 bus_space_tag_t asict
;
196 bus_space_handle_t asich
;
198 const struct ne_pci_product
*npp
;
199 pci_intr_handle_t ih
;
202 npp
= ne_pci_lookup(pa
);
205 panic("ne_pci_attach: impossible");
210 printf(": %s Ethernet\n", npp
->npp_name
);
213 if (ne_pci_isipkdb(pc
, pa
->pa_tag
)) {
214 nict
= ipkdb_softc
.sc_ne2000
.sc_dp8390
.sc_regt
;
215 nich
= ipkdb_softc
.sc_ne2000
.sc_dp8390
.sc_regh
;
219 if (pci_mapreg_map(pa
, PCI_CBIO
, PCI_MAPREG_TYPE_IO
, 0,
220 &nict
, &nich
, NULL
, NULL
)) {
221 aprint_error_dev(dsc
->sc_dev
, "can't map i/o space\n");
226 if (bus_space_subregion(nict
, nich
, NE2000_ASIC_OFFSET
,
227 NE2000_ASIC_NPORTS
, &asich
)) {
228 aprint_error_dev(dsc
->sc_dev
, "can't subregion i/o space\n");
235 nsc
->sc_asict
= asict
;
236 nsc
->sc_asich
= asich
;
238 /* Enable the card. */
239 csr
= pci_conf_read(pc
, pa
->pa_tag
,
240 PCI_COMMAND_STATUS_REG
);
241 pci_conf_write(pc
, pa
->pa_tag
, PCI_COMMAND_STATUS_REG
,
242 csr
| PCI_COMMAND_MASTER_ENABLE
);
244 /* This interface is always enabled. */
247 dsc
->sc_mediachange
= npp
->npp_mediachange
;
248 dsc
->sc_mediastatus
= npp
->npp_mediastatus
;
249 dsc
->sc_media_init
= npp
->npp_media_init
;
250 dsc
->init_card
= npp
->npp_init_card
;
253 * Do generic NE2000 attach. This will read the station address
256 ne2000_attach(nsc
, NULL
);
258 /* Map and establish the interrupt. */
259 if (pci_intr_map(pa
, &ih
)) {
260 aprint_error_dev(dsc
->sc_dev
, "couldn't map interrupt\n");
263 intrstr
= pci_intr_string(pc
, ih
);
264 psc
->sc_ih
= pci_intr_establish(pc
, ih
, IPL_NET
, dp8390_intr
, dsc
);
265 if (psc
->sc_ih
== NULL
) {
266 aprint_error_dev(dsc
->sc_dev
, "couldn't establish interrupt");
268 aprint_error(" at %s", intrstr
);
272 aprint_normal_dev(dsc
->sc_dev
, "interrupting at %s\n", intrstr
);
277 ne_pci_isipkdb(pci_chipset_tag_t pc
, pcitag_t tag
)
279 return !memcmp(&pc
, &ipkdb_pc
, sizeof pc
)
280 && !memcmp(&tag
, &ipkdb_tag
, sizeof tag
);
284 ne_pci_ipkdb_attach(struct ipkdb_if
*kip
, bus_space_tag_t iot
,
285 pci_chipset_tag_t pc
, int bus
, int dev
)
287 struct pci_attach_args pa
;
288 bus_space_tag_t nict
, asict
;
289 bus_space_handle_t nich
, asich
;
296 pa
.pa_flags
= PCI_FLAGS_IO_ENABLED
;
297 pa
.pa_tag
= pci_make_tag(pc
, bus
, dev
, /*func*/0);
298 pa
.pa_id
= pci_conf_read(pc
, pa
.pa_tag
, PCI_ID_REG
);
299 pa
.pa_class
= pci_conf_read(pc
, pa
.pa_tag
, PCI_CLASS_REG
);
300 if (ne_pci_lookup(&pa
) == NULL
)
303 if (pci_mapreg_map(&pa
, PCI_CBIO
, PCI_MAPREG_TYPE_IO
, 0,
304 &nict
, &nich
, NULL
, NULL
))
308 if (bus_space_subregion(nict
, nich
, NE2000_ASIC_OFFSET
,
309 NE2000_ASIC_NPORTS
, &asich
)) {
310 bus_space_unmap(nict
, nich
, NE2000_NPORTS
);
315 csr
= pci_conf_read(pc
, pa
.pa_tag
, PCI_COMMAND_STATUS_REG
);
316 pci_conf_write(pc
, pa
.pa_tag
, PCI_COMMAND_STATUS_REG
,
317 csr
| PCI_COMMAND_MASTER_ENABLE
);
319 ipkdb_softc
.sc_ne2000
.sc_dp8390
.sc_regt
= nict
;
320 ipkdb_softc
.sc_ne2000
.sc_dp8390
.sc_regh
= nich
;
321 ipkdb_softc
.sc_ne2000
.sc_asict
= asict
;
322 ipkdb_softc
.sc_ne2000
.sc_asich
= asich
;
324 kip
->port
= &ipkdb_softc
;
326 ipkdb_tag
= pa
.pa_tag
;
329 if (ne2000_ipkdb_attach(kip
) < 0) {
330 bus_space_unmap(nict
, nich
, NE2000_NPORTS
);
336 #endif /* IPKDB_NE_PCI */