1 /* $NetBSD: if_gem_pci.c,v 1.38 2009/11/26 15:17:09 njoly Exp $ */
5 * Copyright (C) 2001 Eduardo Horvath.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * PCI bindings for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: if_gem_pci.c,v 1.38 2009/11/26 15:17:09 njoly Exp $");
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/kernel.h>
43 #include <sys/socket.h>
44 #include <sys/errno.h>
45 #include <sys/device.h>
47 #include <machine/endian.h>
49 #include <uvm/uvm_extern.h>
52 #include <net/if_dl.h>
53 #include <net/if_media.h>
54 #include <net/if_ether.h>
63 #include <dev/mii/mii.h>
64 #include <dev/mii/miivar.h>
65 #include <dev/mii/mii_bitbang.h>
67 #include <dev/ic/gemreg.h>
68 #include <dev/ic/gemvar.h>
70 #include <dev/pci/pcivar.h>
71 #include <dev/pci/pcireg.h>
72 #include <dev/pci/pcidevs.h>
74 /* XXX Should use Properties when that's fleshed out. */
76 #include <dev/ofw/openfirm.h>
79 #include <machine/promlib.h>
82 #ifndef GEM_USE_LOCAL_MAC_ADDRESS
83 #if defined (macppc) || defined (__sparc__)
84 #define GEM_USE_LOCAL_MAC_ADDRESS 0 /* use system-wide address */
86 #define GEM_USE_LOCAL_MAC_ADDRESS 1
91 struct gem_pci_softc
{
92 struct gem_softc gsc_gem
; /* GEM device */
94 pci_chipset_tag_t gsc_pc
;
95 pci_intr_handle_t gsc_handle
;
98 static bool gem_pci_estintr(struct gem_pci_softc
*);
99 static bool gem_pci_suspend(device_t
, pmf_qual_t
);
100 static bool gem_pci_resume(device_t
, pmf_qual_t
);
101 static int gem_pci_detach(device_t
, int);
103 int gem_pci_match(device_t
, cfdata_t
, void *);
104 void gem_pci_attach(device_t
, device_t
, void *);
106 CFATTACH_DECL3_NEW(gem_pci
, sizeof(struct gem_pci_softc
),
107 gem_pci_match
, gem_pci_attach
, gem_pci_detach
, NULL
, NULL
, NULL
,
108 DVF_DETACH_SHUTDOWN
);
111 * Attach routines need to be split out to different bus-specific files.
115 gem_pci_match(device_t parent
, cfdata_t cf
, void *aux
)
117 struct pci_attach_args
*pa
= aux
;
119 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_SUN
&&
120 (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_SUN_ERINETWORK
||
121 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_SUN_GEMNETWORK
))
124 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_APPLE
&&
125 (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_GMAC
||
126 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_GMAC2
||
127 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_GMAC3
||
128 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_SHASTA_GMAC
||
129 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_K2_GMAC
||
130 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_SHASTA_GMAC
||
131 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_INTREPID2_GMAC
))
138 #if GEM_USE_LOCAL_MAC_ADDRESS
140 gempromvalid(u_int8_t
* buf
)
142 return buf
[0] == 0x18 && buf
[1] == 0x00 && /* structure length */
143 buf
[2] == 0x00 && /* revision */
144 (buf
[3] == 0x00 || /* hme */
145 buf
[3] == 0x80) && /* qfe */
146 buf
[4] == PCI_SUBCLASS_NETWORK_ETHERNET
&& /* subclass code */
147 buf
[5] == PCI_CLASS_NETWORK
; /* class code */
151 isshared_pins(u_int8_t
* buf
)
153 return buf
[0] == 's' && buf
[1] == 'h' && buf
[2] == 'a' &&
154 buf
[3] == 'r' && buf
[4] == 'e' && buf
[5] == 'd' &&
155 buf
[6] == '-' && buf
[7] == 'p' && buf
[8] == 'i' &&
156 buf
[9] == 'n' && buf
[10] == 's';
161 isserdes(u_int8_t
* buf
)
163 return buf
[0] == 's' && buf
[1] == 'e' && buf
[2] == 'r' &&
164 buf
[3] == 'd' && buf
[4] == 'e' && buf
[5] == 's';
168 gem_pci_attach(device_t parent
, device_t self
, void *aux
)
170 struct pci_attach_args
*pa
= aux
;
171 struct gem_pci_softc
*gsc
= device_private(self
);
172 struct gem_softc
*sc
= &gsc
->gsc_gem
;
174 uint8_t enaddr
[ETHER_ADDR_LEN
];
175 #if GEM_USE_LOCAL_MAC_ADDRESS
177 bus_space_handle_t romh
;
178 u_int8_t buf
[0x0800];
179 int dataoff
, vpdoff
, serdes
;
180 #if GEM_USE_LOCAL_MAC_ADDRESS || defined(GEM_DEBUG)
187 static const u_int8_t promhdr
[] = { 0x55, 0xaa };
188 #define PROMHDR_PTR_DATA 0x18
189 static const u_int8_t promdat
[] = {
190 0x50, 0x43, 0x49, 0x52, /* "PCIR" */
191 PCI_VENDOR_SUN
& 0xff, PCI_VENDOR_SUN
>> 8,
192 PCI_PRODUCT_SUN_GEMNETWORK
& 0xff,
193 PCI_PRODUCT_SUN_GEMNETWORK
>> 8
195 #define PROMDATA_PTR_VPD 0x08
196 #define PROMDATA_DATA2 0x0a
197 #endif /* GEM_USE_LOCAL_MAC_ADDRESS */
199 aprint_naive(": Ethernet controller\n");
202 pci_devinfo(pa
->pa_id
, pa
->pa_class
, 0, devinfo
, sizeof(devinfo
));
203 sc
->sc_chiprev
= PCI_REVISION(pa
->pa_class
);
204 aprint_normal(": %s (rev. 0x%02x)\n", devinfo
, sc
->sc_chiprev
);
207 * Some Sun GEMs/ERIs do have their intpin register bogusly set to 0,
208 * although it should be 1. correct that.
210 if (pa
->pa_intrpin
== 0)
213 sc
->sc_variant
= GEM_UNKNOWN
;
215 sc
->sc_dmatag
= pa
->pa_dmat
;
217 sc
->sc_flags
|= GEM_PCI
;
219 if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_SUN
) {
220 if (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_SUN_GEMNETWORK
)
221 sc
->sc_variant
= GEM_SUN_GEM
;
222 if (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_SUN_ERINETWORK
)
223 sc
->sc_variant
= GEM_SUN_ERI
;
224 } else if (PCI_VENDOR(pa
->pa_id
) == PCI_VENDOR_APPLE
) {
225 if (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_GMAC
||
226 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_GMAC2
||
227 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_GMAC3
||
228 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_SHASTA_GMAC
||
229 PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_INTREPID2_GMAC
)
230 sc
->sc_variant
= GEM_APPLE_GMAC
;
231 if (PCI_PRODUCT(pa
->pa_id
) == PCI_PRODUCT_APPLE_K2_GMAC
)
232 sc
->sc_variant
= GEM_APPLE_K2_GMAC
;
235 if (sc
->sc_variant
== GEM_UNKNOWN
) {
236 aprint_error_dev(sc
->sc_dev
, "unknown adaptor\n");
240 #define PCI_GEM_BASEADDR (PCI_MAPREG_START + 0x00)
242 /* XXX Need to check for a 64-bit mem BAR? */
243 if (pci_mapreg_map(pa
, PCI_GEM_BASEADDR
,
244 PCI_MAPREG_TYPE_MEM
| PCI_MAPREG_MEM_TYPE_32BIT
, 0,
245 &sc
->sc_bustag
, &sc
->sc_h1
, NULL
, &sc
->sc_size
) != 0)
247 aprint_error_dev(sc
->sc_dev
, "unable to map device registers\n");
250 if (bus_space_subregion(sc
->sc_bustag
, sc
->sc_h1
,
251 GEM_PCI_BANK2_OFFSET
, GEM_PCI_BANK2_SIZE
, &sc
->sc_h2
)) {
252 aprint_error_dev(sc
->sc_dev
, "unable to create bank 2 subregion\n");
256 #if GEM_USE_LOCAL_MAC_ADDRESS
258 * Dig out VPD (vital product data) and acquire Ethernet address.
259 * The VPD of gem resides in the PCI PROM (PCI FCode).
262 * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later)
263 * chapter 2 describes the data structure.
268 if (sc
->sc_variant
== GEM_SUN_GEM
&&
269 (bus_space_subregion(sc
->sc_bustag
, sc
->sc_h1
,
270 GEM_PCI_ROM_OFFSET
, GEM_PCI_ROM_SIZE
, &romh
)) == 0) {
272 /* read PCI Expansion PROM Header */
273 bus_space_read_region_1(sc
->sc_bustag
,
274 romh
, 0, buf
, sizeof buf
);
276 /* Check for "shared-pins = serdes" in FCode. */
279 while (i
< (sizeof buf
) - sizeof "serdes") {
281 if (isserdes(&buf
[i
]))
284 if (isshared_pins(&buf
[i
]))
288 sc
->sc_flags
|= GEM_SERDES
;
295 printf("%s: PROM dump (0x0000 to %04lx)\n", device_xname(sc
->sc_dev
),
300 while (i
< sizeof buf
) {
301 printf("%02x ", buf
[i
]);
304 if (i
&& !(i
% 16)) {
307 if (buf
[j
] > 31 && buf
[j
] < 128)
308 printf("%c", buf
[j
]);
314 printf("\n %04x ", i
);
321 if (memcmp(buf
, promhdr
, sizeof promhdr
) == 0 &&
322 (dataoff
= (buf
[PROMHDR_PTR_DATA
] |
323 (buf
[PROMHDR_PTR_DATA
+ 1] << 8))) >= 0x1c) {
325 /* read PCI Expansion PROM Data */
326 bus_space_read_region_1(sc
->sc_bustag
, romh
, dataoff
,
328 if (memcmp(buf
, promdat
, sizeof promdat
) == 0 &&
329 gempromvalid(buf
+ PROMDATA_DATA2
) &&
330 (vpdoff
= (buf
[PROMDATA_PTR_VPD
] |
331 (buf
[PROMDATA_PTR_VPD
+ 1] << 8))) >= 0x1c) {
334 * The VPD of gem is not in PCI 2.2 standard
335 * format. The length in the resource header
336 * is in big endian, and resources are not
337 * properly terminated (only one resource
341 bus_space_read_region_1(sc
->sc_bustag
, romh
,
343 vpd
= (void *)(buf
+ 3);
344 if (PCI_VPDRES_ISLARGE(buf
[0]) &&
345 PCI_VPDRES_LARGE_NAME(buf
[0])
346 == PCI_VPDRES_TYPE_VPD
&&
347 vpd
->vpd_key0
== 0x4e /* N */ &&
348 vpd
->vpd_key1
== 0x41 /* A */ &&
349 vpd
->vpd_len
== ETHER_ADDR_LEN
) {
351 * Ethernet address found
360 memcpy(enaddr
, enp
, ETHER_ADDR_LEN
);
362 #endif /* GEM_USE_LOCAL_MAC_ADDRESS */
365 if (strcmp(prom_getpropstring(PCITAG_NODE(pa
->pa_tag
),
366 "shared-pins"), "serdes") == 0)
367 sc
->sc_flags
|= GEM_SERDES
;
368 prom_getether(PCITAG_NODE(pa
->pa_tag
), enaddr
);
374 char sp
[6]; /* "serdes" */
376 node
= pcidev_to_ofdev(pa
->pa_pc
, pa
->pa_tag
);
378 aprint_error_dev(sc
->sc_dev
, "unable to locate OpenFirmware node\n");
382 OF_getprop(node
, "shared-pins", sp
, sizeof(sp
));
384 sc
->sc_flags
|= GEM_SERDES
;
385 OF_getprop(node
, "local-mac-address", enaddr
, sizeof(enaddr
));
388 printf("%s: no Ethernet address found\n", device_xname(sc
->sc_dev
));
390 #endif /* __sparc__ */
392 if (pci_intr_map(pa
, &gsc
->gsc_handle
) != 0) {
393 aprint_error_dev(sc
->sc_dev
, "unable to map interrupt\n");
396 gsc
->gsc_pc
= pa
->pa_pc
;
397 gem_pci_estintr(gsc
);
399 /* Finish off the attach. */
400 gem_attach(sc
, enaddr
);
402 if (pmf_device_register1(sc
->sc_dev
,
403 gem_pci_suspend
, gem_pci_resume
, gem_shutdown
))
404 pmf_class_network_register(sc
->sc_dev
, &sc
->sc_ethercom
.ec_if
);
406 aprint_error_dev(sc
->sc_dev
,
407 "could not establish power handlers\n");
411 gem_pci_suspend(device_t self
, pmf_qual_t qual
)
413 struct gem_pci_softc
*gsc
= device_private(self
);
415 if (gsc
->gsc_ih
!= NULL
) {
416 pci_intr_disestablish(gsc
->gsc_pc
, gsc
->gsc_ih
);
424 gem_pci_estintr(struct gem_pci_softc
*gsc
)
426 struct gem_softc
*sc
= &gsc
->gsc_gem
;
429 intrstr
= pci_intr_string(gsc
->gsc_pc
, gsc
->gsc_handle
);
430 gsc
->gsc_ih
= pci_intr_establish(gsc
->gsc_pc
, gsc
->gsc_handle
, IPL_NET
,
432 if (gsc
->gsc_ih
== NULL
) {
433 aprint_error_dev(sc
->sc_dev
, "unable to establish interrupt");
435 aprint_error(" at %s", intrstr
);
439 aprint_normal_dev(sc
->sc_dev
, "interrupting at %s\n", intrstr
);
444 gem_pci_resume(device_t self
, pmf_qual_t qual
)
446 struct gem_pci_softc
*gsc
= device_private(self
);
448 return gem_pci_estintr(gsc
);
452 gem_pci_detach(device_t self
, int flags
)
455 struct gem_pci_softc
*gsc
= device_private(self
);
456 struct gem_softc
*sc
= &gsc
->gsc_gem
;
458 switch (sc
->sc_att_stage
) {
459 case GEM_ATT_BACKEND_2
:
460 pmf_device_deregister(self
);
461 sc
->sc_att_stage
= GEM_ATT_FINISHED
;
464 if ((rc
= gem_detach(sc
, flags
)) != 0)
467 case GEM_ATT_BACKEND_1
:
468 if (gsc
->gsc_ih
!= NULL
)
469 pci_intr_disestablish(gsc
->gsc_pc
, gsc
->gsc_ih
);
471 bus_space_unmap(sc
->sc_bustag
, sc
->sc_h1
, sc
->sc_size
);
473 case GEM_ATT_BACKEND_0
:
474 sc
->sc_att_stage
= GEM_ATT_BACKEND_0
;