| @@ -1,439 +1,439 @@ | | | @@ -1,439 +1,439 @@ |
1 | /* $NetBSD: if_gem_pci.c,v 1.44 2012/01/30 19:41:20 drochner Exp $ */ | | 1 | /* $NetBSD: if_gem_pci.c,v 1.45 2012/09/23 01:11:14 chs Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * | | 4 | * |
5 | * Copyright (C) 2001 Eduardo Horvath. | | 5 | * Copyright (C) 2001 Eduardo Horvath. |
6 | * All rights reserved. | | 6 | * All rights reserved. |
7 | * | | 7 | * |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
15 | * notice, this list of conditions and the following disclaimer in the | | 15 | * notice, this list of conditions and the following disclaimer in the |
16 | * documentation and/or other materials provided with the distribution. | | 16 | * documentation and/or other materials provided with the distribution. |
17 | * | | 17 | * |
18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND | | 18 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND |
19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | | 19 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | | 20 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE | | 21 | * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE |
22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | | 22 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | | 23 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
24 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | | 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 | | 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 | | 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 | | 27 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 | * SUCH DAMAGE. | | 28 | * SUCH DAMAGE. |
29 | * | | 29 | * |
30 | */ | | 30 | */ |
31 | | | 31 | |
32 | /* | | 32 | /* |
33 | * PCI bindings for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers | | 33 | * PCI bindings for Apple GMAC, Sun ERI and Sun GEM Ethernet controllers |
34 | */ | | 34 | */ |
35 | | | 35 | |
36 | #include <sys/cdefs.h> | | 36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: if_gem_pci.c,v 1.44 2012/01/30 19:41:20 drochner Exp $"); | | 37 | __KERNEL_RCSID(0, "$NetBSD: if_gem_pci.c,v 1.45 2012/09/23 01:11:14 chs Exp $"); |
38 | | | 38 | |
39 | #include <sys/param.h> | | 39 | #include <sys/param.h> |
40 | #include <sys/systm.h> | | 40 | #include <sys/systm.h> |
41 | #include <sys/malloc.h> | | 41 | #include <sys/malloc.h> |
42 | #include <sys/kernel.h> | | 42 | #include <sys/kernel.h> |
43 | #include <sys/socket.h> | | 43 | #include <sys/socket.h> |
44 | #include <sys/errno.h> | | 44 | #include <sys/errno.h> |
45 | #include <sys/device.h> | | 45 | #include <sys/device.h> |
46 | | | 46 | |
47 | #include <machine/endian.h> | | 47 | #include <machine/endian.h> |
48 | | | 48 | |
49 | #include <net/if.h> | | 49 | #include <net/if.h> |
50 | #include <net/if_dl.h> | | 50 | #include <net/if_dl.h> |
51 | #include <net/if_media.h> | | 51 | #include <net/if_media.h> |
52 | #include <net/if_ether.h> | | 52 | #include <net/if_ether.h> |
53 | | | 53 | |
54 | #include <net/bpf.h> | | 54 | #include <net/bpf.h> |
55 | | | 55 | |
56 | #include <sys/bus.h> | | 56 | #include <sys/bus.h> |
57 | #include <sys/intr.h> | | 57 | #include <sys/intr.h> |
58 | | | 58 | |
59 | #include <dev/mii/mii.h> | | 59 | #include <dev/mii/mii.h> |
60 | #include <dev/mii/miivar.h> | | 60 | #include <dev/mii/miivar.h> |
61 | #include <dev/mii/mii_bitbang.h> | | 61 | #include <dev/mii/mii_bitbang.h> |
62 | | | 62 | |
63 | #include <dev/ic/gemreg.h> | | 63 | #include <dev/ic/gemreg.h> |
64 | #include <dev/ic/gemvar.h> | | 64 | #include <dev/ic/gemvar.h> |
65 | | | 65 | |
66 | #include <dev/pci/pcivar.h> | | 66 | #include <dev/pci/pcivar.h> |
67 | #include <dev/pci/pcireg.h> | | 67 | #include <dev/pci/pcireg.h> |
68 | #include <dev/pci/pcidevs.h> | | 68 | #include <dev/pci/pcidevs.h> |
69 | #include <prop/proplib.h> | | 69 | #include <prop/proplib.h> |
70 | | | 70 | |
71 | struct gem_pci_softc { | | 71 | struct gem_pci_softc { |
72 | struct gem_softc gsc_gem; /* GEM device */ | | 72 | struct gem_softc gsc_gem; /* GEM device */ |
73 | void *gsc_ih; | | 73 | void *gsc_ih; |
74 | pci_chipset_tag_t gsc_pc; | | 74 | pci_chipset_tag_t gsc_pc; |
75 | pci_intr_handle_t gsc_handle; | | 75 | pci_intr_handle_t gsc_handle; |
76 | }; | | 76 | }; |
77 | | | 77 | |
78 | static bool gem_pci_estintr(struct gem_pci_softc *); | | 78 | static bool gem_pci_estintr(struct gem_pci_softc *); |
79 | static bool gem_pci_suspend(device_t, const pmf_qual_t *); | | 79 | static bool gem_pci_suspend(device_t, const pmf_qual_t *); |
80 | static bool gem_pci_resume(device_t, const pmf_qual_t *); | | 80 | static bool gem_pci_resume(device_t, const pmf_qual_t *); |
81 | static int gem_pci_detach(device_t, int); | | 81 | static int gem_pci_detach(device_t, int); |
82 | | | 82 | |
83 | int gem_pci_match(device_t, cfdata_t, void *); | | 83 | int gem_pci_match(device_t, cfdata_t, void *); |
84 | void gem_pci_attach(device_t, device_t, void *); | | 84 | void gem_pci_attach(device_t, device_t, void *); |
85 | | | 85 | |
86 | CFATTACH_DECL3_NEW(gem_pci, sizeof(struct gem_pci_softc), | | 86 | CFATTACH_DECL3_NEW(gem_pci, sizeof(struct gem_pci_softc), |
87 | gem_pci_match, gem_pci_attach, gem_pci_detach, NULL, NULL, NULL, | | 87 | gem_pci_match, gem_pci_attach, gem_pci_detach, NULL, NULL, NULL, |
88 | DVF_DETACH_SHUTDOWN); | | 88 | DVF_DETACH_SHUTDOWN); |
89 | | | 89 | |
90 | /* | | 90 | /* |
91 | * Attach routines need to be split out to different bus-specific files. | | 91 | * Attach routines need to be split out to different bus-specific files. |
92 | */ | | 92 | */ |
93 | | | 93 | |
94 | int | | 94 | int |
95 | gem_pci_match(device_t parent, cfdata_t cf, void *aux) | | 95 | gem_pci_match(device_t parent, cfdata_t cf, void *aux) |
96 | { | | 96 | { |
97 | struct pci_attach_args *pa = aux; | | 97 | struct pci_attach_args *pa = aux; |
98 | | | 98 | |
99 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN && | | 99 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN && |
100 | (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK || | | 100 | (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK || |
101 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_GEMNETWORK)) | | 101 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_GEMNETWORK)) |
102 | return (1); | | 102 | return (1); |
103 | | | 103 | |
104 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE && | | 104 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE && |
105 | (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC || | | 105 | (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC || |
106 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC2 || | | 106 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC2 || |
107 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC3 || | | 107 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC3 || |
108 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC || | | 108 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC || |
109 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC || | | 109 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC || |
110 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC || | | 110 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC || |
111 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_INTREPID2_GMAC)) | | 111 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_INTREPID2_GMAC)) |
112 | return (1); | | 112 | return (1); |
113 | | | 113 | |
114 | | | 114 | |
115 | return (0); | | 115 | return (0); |
116 | } | | 116 | } |
117 | | | 117 | |
118 | static inline int | | 118 | static inline int |
119 | gempromvalid(u_int8_t* buf) | | 119 | gempromvalid(u_int8_t* buf) |
120 | { | | 120 | { |
121 | return buf[0] == 0x18 && buf[1] == 0x00 && /* structure length */ | | 121 | return buf[0] == 0x18 && buf[1] == 0x00 && /* structure length */ |
122 | buf[2] == 0x00 && /* revision */ | | 122 | buf[2] == 0x00 && /* revision */ |
123 | (buf[3] == 0x00 || /* hme */ | | 123 | (buf[3] == 0x00 || /* hme */ |
124 | buf[3] == 0x80) && /* qfe */ | | 124 | buf[3] == 0x80) && /* qfe */ |
125 | buf[4] == PCI_SUBCLASS_NETWORK_ETHERNET && /* subclass code */ | | 125 | buf[4] == PCI_SUBCLASS_NETWORK_ETHERNET && /* subclass code */ |
126 | buf[5] == PCI_CLASS_NETWORK; /* class code */ | | 126 | buf[5] == PCI_CLASS_NETWORK; /* class code */ |
127 | } | | 127 | } |
128 | | | 128 | |
129 | static inline int | | 129 | static inline int |
130 | isshared_pins(u_int8_t* buf) | | 130 | isshared_pins(u_int8_t* buf) |
131 | { | | 131 | { |
132 | return buf[0] == 's' && buf[1] == 'h' && buf[2] == 'a' && | | 132 | return buf[0] == 's' && buf[1] == 'h' && buf[2] == 'a' && |
133 | buf[3] == 'r' && buf[4] == 'e' && buf[5] == 'd' && | | 133 | buf[3] == 'r' && buf[4] == 'e' && buf[5] == 'd' && |
134 | buf[6] == '-' && buf[7] == 'p' && buf[8] == 'i' && | | 134 | buf[6] == '-' && buf[7] == 'p' && buf[8] == 'i' && |
135 | buf[9] == 'n' && buf[10] == 's'; | | 135 | buf[9] == 'n' && buf[10] == 's'; |
136 | } | | 136 | } |
137 | | | 137 | |
138 | static inline int | | 138 | static inline int |
139 | isserdes(u_int8_t* buf) | | 139 | isserdes(u_int8_t* buf) |
140 | { | | 140 | { |
141 | return buf[0] == 's' && buf[1] == 'e' && buf[2] == 'r' && | | 141 | return buf[0] == 's' && buf[1] == 'e' && buf[2] == 'r' && |
142 | buf[3] == 'd' && buf[4] == 'e' && buf[5] == 's'; | | 142 | buf[3] == 'd' && buf[4] == 'e' && buf[5] == 's'; |
143 | } | | 143 | } |
144 | | | 144 | |
145 | void | | 145 | void |
146 | gem_pci_attach(device_t parent, device_t self, void *aux) | | 146 | gem_pci_attach(device_t parent, device_t self, void *aux) |
147 | { | | 147 | { |
148 | struct pci_attach_args *pa = aux; | | 148 | struct pci_attach_args *pa = aux; |
149 | struct gem_pci_softc *gsc = device_private(self); | | 149 | struct gem_pci_softc *gsc = device_private(self); |
150 | struct gem_softc *sc = &gsc->gsc_gem; | | 150 | struct gem_softc *sc = &gsc->gsc_gem; |
151 | prop_data_t data; | | 151 | prop_data_t data; |
152 | uint8_t enaddr[ETHER_ADDR_LEN]; | | 152 | uint8_t enaddr[ETHER_ADDR_LEN]; |
153 | u_int8_t *enp; | | 153 | u_int8_t *enp; |
154 | bus_space_handle_t romh; | | 154 | bus_space_handle_t romh; |
155 | u_int8_t buf[0x0800]; | | 155 | u_int8_t buf[0x0800]; |
156 | int dataoff, vpdoff, serdes; | | 156 | int dataoff, vpdoff, serdes; |
157 | int i, got_addr = 0; | | 157 | int i, got_addr = 0; |
158 | #ifdef GEM_DEBUG | | 158 | #ifdef GEM_DEBUG |
159 | int j; | | 159 | int j; |
160 | #endif | | 160 | #endif |
161 | struct pci_vpd *vpd; | | 161 | struct pci_vpd *vpd; |
162 | static const u_int8_t promhdr[] = { 0x55, 0xaa }; | | 162 | static const u_int8_t promhdr[] = { 0x55, 0xaa }; |
163 | #define PROMHDR_PTR_DATA 0x18 | | 163 | #define PROMHDR_PTR_DATA 0x18 |
164 | static const u_int8_t promdat[] = { | | 164 | static const u_int8_t promdat[] = { |
165 | 0x50, 0x43, 0x49, 0x52, /* "PCIR" */ | | 165 | 0x50, 0x43, 0x49, 0x52, /* "PCIR" */ |
166 | PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8, | | 166 | PCI_VENDOR_SUN & 0xff, PCI_VENDOR_SUN >> 8, |
167 | PCI_PRODUCT_SUN_GEMNETWORK & 0xff, | | 167 | PCI_PRODUCT_SUN_GEMNETWORK & 0xff, |
168 | PCI_PRODUCT_SUN_GEMNETWORK >> 8 | | 168 | PCI_PRODUCT_SUN_GEMNETWORK >> 8 |
169 | }; | | 169 | }; |
170 | #define PROMDATA_PTR_VPD 0x08 | | 170 | #define PROMDATA_PTR_VPD 0x08 |
171 | #define PROMDATA_DATA2 0x0a | | 171 | #define PROMDATA_DATA2 0x0a |
172 | | | 172 | |
173 | pci_aprint_devinfo(pa, "Ethernet controller"); | | 173 | pci_aprint_devinfo(pa, "Ethernet controller"); |
174 | | | 174 | |
175 | sc->sc_dev = self; | | 175 | sc->sc_dev = self; |
176 | sc->sc_chiprev = PCI_REVISION(pa->pa_class); | | 176 | sc->sc_chiprev = PCI_REVISION(pa->pa_class); |
177 | | | 177 | |
178 | /* | | 178 | /* |
179 | * Some Sun GEMs/ERIs do have their intpin register bogusly set to 0, | | 179 | * Some Sun GEMs/ERIs do have their intpin register bogusly set to 0, |
180 | * although it should be 1. correct that. | | 180 | * although it should be 1. correct that. |
181 | */ | | 181 | */ |
182 | if (pa->pa_intrpin == 0) | | 182 | if (pa->pa_intrpin == 0) |
183 | pa->pa_intrpin = 1; | | 183 | pa->pa_intrpin = 1; |
184 | | | 184 | |
185 | sc->sc_variant = GEM_UNKNOWN; | | 185 | sc->sc_variant = GEM_UNKNOWN; |
186 | | | 186 | |
187 | sc->sc_dmatag = pa->pa_dmat; | | 187 | sc->sc_dmatag = pa->pa_dmat; |
188 | | | 188 | |
189 | sc->sc_flags |= GEM_PCI; | | 189 | sc->sc_flags |= GEM_PCI; |
190 | | | 190 | |
191 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN) { | | 191 | if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_SUN) { |
192 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_GEMNETWORK) | | 192 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_GEMNETWORK) |
193 | sc->sc_variant = GEM_SUN_GEM; | | 193 | sc->sc_variant = GEM_SUN_GEM; |
194 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK) | | 194 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_SUN_ERINETWORK) |
195 | sc->sc_variant = GEM_SUN_ERI; | | 195 | sc->sc_variant = GEM_SUN_ERI; |
196 | } else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE) { | | 196 | } else if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_APPLE) { |
197 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC || | | 197 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC || |
198 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC2 || | | 198 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC2 || |
199 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC3 || | | 199 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_GMAC3 || |
200 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC || | | 200 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_SHASTA_GMAC || |
201 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_INTREPID2_GMAC) | | 201 | PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_INTREPID2_GMAC) |
202 | sc->sc_variant = GEM_APPLE_GMAC; | | 202 | sc->sc_variant = GEM_APPLE_GMAC; |
203 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC) | | 203 | if (PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_APPLE_K2_GMAC) |
204 | sc->sc_variant = GEM_APPLE_K2_GMAC; | | 204 | sc->sc_variant = GEM_APPLE_K2_GMAC; |
205 | } | | 205 | } |
206 | | | 206 | |
207 | if (sc->sc_variant == GEM_UNKNOWN) { | | 207 | if (sc->sc_variant == GEM_UNKNOWN) { |
208 | aprint_error_dev(sc->sc_dev, "unknown adaptor\n"); | | 208 | aprint_error_dev(sc->sc_dev, "unknown adaptor\n"); |
209 | return; | | 209 | return; |
210 | } | | 210 | } |
211 | | | 211 | |
212 | #define PCI_GEM_BASEADDR (PCI_MAPREG_START + 0x00) | | 212 | #define PCI_GEM_BASEADDR (PCI_MAPREG_START + 0x00) |
213 | | | 213 | |
214 | /* XXX Need to check for a 64-bit mem BAR? */ | | 214 | /* XXX Need to check for a 64-bit mem BAR? */ |
215 | if (pci_mapreg_map(pa, PCI_GEM_BASEADDR, | | 215 | if (pci_mapreg_map(pa, PCI_GEM_BASEADDR, |
216 | PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, | | 216 | PCI_MAPREG_TYPE_MEM | PCI_MAPREG_MEM_TYPE_32BIT, 0, |
217 | &sc->sc_bustag, &sc->sc_h1, NULL, &sc->sc_size) != 0) | | 217 | &sc->sc_bustag, &sc->sc_h1, NULL, &sc->sc_size) != 0) |
218 | { | | 218 | { |
219 | aprint_error_dev(sc->sc_dev, "unable to map device registers\n"); | | 219 | aprint_error_dev(sc->sc_dev, "unable to map device registers\n"); |
220 | return; | | 220 | return; |
221 | } | | 221 | } |
222 | if (bus_space_subregion(sc->sc_bustag, sc->sc_h1, | | 222 | if (bus_space_subregion(sc->sc_bustag, sc->sc_h1, |
223 | GEM_PCI_BANK2_OFFSET, GEM_PCI_BANK2_SIZE, &sc->sc_h2)) { | | 223 | GEM_PCI_BANK2_OFFSET, GEM_PCI_BANK2_SIZE, &sc->sc_h2)) { |
224 | aprint_error_dev(sc->sc_dev, "unable to create bank 2 subregion\n"); | | 224 | aprint_error_dev(sc->sc_dev, "unable to create bank 2 subregion\n"); |
225 | return; | | 225 | return; |
226 | } | | 226 | } |
227 | | | 227 | |
228 | if ((data = prop_dictionary_get(device_properties(sc->sc_dev), | | 228 | if ((data = prop_dictionary_get(device_properties(sc->sc_dev), |
229 | "mac-address")) != NULL) { | | 229 | "mac-address")) != NULL) { |
230 | memcpy(enaddr, prop_data_data_nocopy(data), ETHER_ADDR_LEN); | | 230 | memcpy(enaddr, prop_data_data_nocopy(data), ETHER_ADDR_LEN); |
231 | got_addr = 1; | | 231 | got_addr = 1; |
232 | if ((data = prop_dictionary_get(device_properties(sc->sc_dev), | | 232 | if ((data = prop_dictionary_get(device_properties(sc->sc_dev), |
233 | "shared-pins")) != NULL) { | | 233 | "shared-pins")) != NULL) { |
234 | memcpy(buf, prop_data_data_nocopy(data), | | 234 | memcpy(buf, prop_data_data_nocopy(data), |
235 | prop_data_size(data)); | | 235 | prop_data_size(data)); |
236 | if (isserdes(buf)) { | | 236 | if (isserdes(buf)) { |
237 | sc->sc_flags |= GEM_SERDES; | | 237 | sc->sc_flags |= GEM_SERDES; |
238 | } | | 238 | } |
239 | } | | 239 | } |
240 | } else { | | 240 | } else { |
241 | /* | | 241 | /* |
242 | * Dig out VPD (vital product data) and acquire Ethernet address. | | 242 | * Dig out VPD (vital product data) and acquire Ethernet address. |
243 | * The VPD of gem resides in the PCI PROM (PCI FCode). | | 243 | * The VPD of gem resides in the PCI PROM (PCI FCode). |
244 | */ | | 244 | */ |
245 | /* | | 245 | /* |
246 | * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) | | 246 | * ``Writing FCode 3.x Programs'' (newer ones, dated 1997 and later) |
247 | * chapter 2 describes the data structure. | | 247 | * chapter 2 describes the data structure. |
248 | */ | | 248 | */ |
249 | | | 249 | |
250 | enp = NULL; | | 250 | enp = NULL; |
251 | | | 251 | |
252 | if (sc->sc_variant == GEM_SUN_GEM && | | 252 | if (sc->sc_variant == GEM_SUN_GEM && |
253 | (bus_space_subregion(sc->sc_bustag, sc->sc_h1, | | 253 | (bus_space_subregion(sc->sc_bustag, sc->sc_h1, |
254 | GEM_PCI_ROM_OFFSET, GEM_PCI_ROM_SIZE, &romh)) == 0) { | | 254 | GEM_PCI_ROM_OFFSET, GEM_PCI_ROM_SIZE, &romh)) == 0) { |
255 | | | 255 | |
256 | /* read PCI Expansion PROM Header */ | | 256 | /* read PCI Expansion PROM Header */ |
257 | bus_space_read_region_1(sc->sc_bustag, | | 257 | bus_space_read_region_1(sc->sc_bustag, |
258 | romh, 0, buf, sizeof buf); | | 258 | romh, 0, buf, sizeof buf); |
259 | | | 259 | |
260 | /* Check for "shared-pins = serdes" in FCode. */ | | 260 | /* Check for "shared-pins = serdes" in FCode. */ |
261 | i = 0; | | 261 | i = 0; |
262 | serdes = 0; | | 262 | serdes = 0; |
263 | while (i < (sizeof buf) - sizeof "serdes") { | | 263 | while (i < (sizeof buf) - sizeof "serdes") { |
264 | if (!serdes) { | | 264 | if (!serdes) { |
265 | if (isserdes(&buf[i])) | | 265 | if (isserdes(&buf[i])) |
266 | serdes = 1; | | 266 | serdes = 1; |
267 | } else { | | 267 | } else { |
268 | if (isshared_pins(&buf[i])) | | 268 | if (isshared_pins(&buf[i])) |
269 | serdes = 2; | | 269 | serdes = 2; |
270 | } | | 270 | } |
271 | if (serdes == 2) { | | 271 | if (serdes == 2) { |
272 | sc->sc_flags |= GEM_SERDES; | | 272 | sc->sc_flags |= GEM_SERDES; |
273 | break; | | 273 | break; |
274 | } | | 274 | } |
275 | i++; | | 275 | i++; |
276 | } | | 276 | } |
277 | #ifdef GEM_DEBUG | | 277 | #ifdef GEM_DEBUG |
278 | /* PROM dump */ | | 278 | /* PROM dump */ |
279 | printf("%s: PROM dump (0x0000 to %04lx)\n", device_xname(sc->sc_dev), | | 279 | printf("%s: PROM dump (0x0000 to %04zx)\n", device_xname(sc->sc_dev), |
280 | (sizeof buf) - 1); | | 280 | (sizeof buf) - 1); |
281 | i = 0; | | 281 | i = 0; |
282 | j = 0; | | 282 | j = 0; |
283 | printf(" %04x ", i); | | 283 | printf(" %04x ", i); |
284 | while (i < sizeof buf) { | | 284 | while (i < sizeof buf) { |
285 | printf("%02x ", buf[i]); | | 285 | printf("%02x ", buf[i]); |
286 | if (i && !(i % 8)) | | 286 | if (i && !(i % 8)) |
287 | printf(" "); | | 287 | printf(" "); |
288 | if (i && !(i % 16)) { | | 288 | if (i && !(i % 16)) { |
289 | printf(" "); | | 289 | printf(" "); |
290 | while (j < i) { | | 290 | while (j < i) { |
291 | if (buf[j] > 31 && buf[j] < 128) | | 291 | if (buf[j] > 31 && buf[j] < 128) |
292 | printf("%c", buf[j]); | | 292 | printf("%c", buf[j]); |
293 | else | | 293 | else |
294 | printf("."); | | 294 | printf("."); |
295 | j++; | | 295 | j++; |
296 | } | | 296 | } |
297 | j = i; | | 297 | j = i; |
298 | printf("\n %04x ", i); | | 298 | printf("\n %04x ", i); |
299 | } | | 299 | } |
300 | i++; | | 300 | i++; |
301 | } | | 301 | } |
302 | printf("\n"); | | 302 | printf("\n"); |
303 | #endif | | 303 | #endif |
304 | | | 304 | |
305 | if (memcmp(buf, promhdr, sizeof promhdr) == 0 && | | 305 | if (memcmp(buf, promhdr, sizeof promhdr) == 0 && |
306 | (dataoff = (buf[PROMHDR_PTR_DATA] | | | 306 | (dataoff = (buf[PROMHDR_PTR_DATA] | |
307 | (buf[PROMHDR_PTR_DATA + 1] << 8))) >= 0x1c) { | | 307 | (buf[PROMHDR_PTR_DATA + 1] << 8))) >= 0x1c) { |
308 | | | 308 | |
309 | /* read PCI Expansion PROM Data */ | | 309 | /* read PCI Expansion PROM Data */ |
310 | bus_space_read_region_1(sc->sc_bustag, romh, dataoff, | | 310 | bus_space_read_region_1(sc->sc_bustag, romh, dataoff, |
311 | buf, 64); | | 311 | buf, 64); |
312 | if (memcmp(buf, promdat, sizeof promdat) == 0 && | | 312 | if (memcmp(buf, promdat, sizeof promdat) == 0 && |
313 | gempromvalid(buf + PROMDATA_DATA2) && | | 313 | gempromvalid(buf + PROMDATA_DATA2) && |
314 | (vpdoff = (buf[PROMDATA_PTR_VPD] | | | 314 | (vpdoff = (buf[PROMDATA_PTR_VPD] | |
315 | (buf[PROMDATA_PTR_VPD + 1] << 8))) >= 0x1c) { | | 315 | (buf[PROMDATA_PTR_VPD + 1] << 8))) >= 0x1c) { |
316 | | | 316 | |
317 | /* | | 317 | /* |
318 | * The VPD of gem is not in PCI 2.2 standard | | 318 | * The VPD of gem is not in PCI 2.2 standard |
319 | * format. The length in the resource header | | 319 | * format. The length in the resource header |
320 | * is in big endian, and resources are not | | 320 | * is in big endian, and resources are not |
321 | * properly terminated (only one resource | | 321 | * properly terminated (only one resource |
322 | * and no end tag). | | 322 | * and no end tag). |
323 | */ | | 323 | */ |
324 | /* read PCI VPD */ | | 324 | /* read PCI VPD */ |
325 | bus_space_read_region_1(sc->sc_bustag, romh, | | 325 | bus_space_read_region_1(sc->sc_bustag, romh, |
326 | vpdoff, buf, 64); | | 326 | vpdoff, buf, 64); |
327 | vpd = (void *)(buf + 3); | | 327 | vpd = (void *)(buf + 3); |
328 | if (PCI_VPDRES_ISLARGE(buf[0]) && | | 328 | if (PCI_VPDRES_ISLARGE(buf[0]) && |
329 | PCI_VPDRES_LARGE_NAME(buf[0]) | | 329 | PCI_VPDRES_LARGE_NAME(buf[0]) |
330 | == PCI_VPDRES_TYPE_VPD && | | 330 | == PCI_VPDRES_TYPE_VPD && |
331 | vpd->vpd_key0 == 0x4e /* N */ && | | 331 | vpd->vpd_key0 == 0x4e /* N */ && |
332 | vpd->vpd_key1 == 0x41 /* A */ && | | 332 | vpd->vpd_key1 == 0x41 /* A */ && |
333 | vpd->vpd_len == ETHER_ADDR_LEN) { | | 333 | vpd->vpd_len == ETHER_ADDR_LEN) { |
334 | /* | | 334 | /* |
335 | * Ethernet address found | | 335 | * Ethernet address found |
336 | */ | | 336 | */ |
337 | enp = buf + 6; | | 337 | enp = buf + 6; |
338 | } | | 338 | } |
339 | } | | 339 | } |
340 | } | | 340 | } |
341 | } | | 341 | } |
342 | | | 342 | |
343 | if (enp) { | | 343 | if (enp) { |
344 | memcpy(enaddr, enp, ETHER_ADDR_LEN); | | 344 | memcpy(enaddr, enp, ETHER_ADDR_LEN); |
345 | got_addr = 1; | | 345 | got_addr = 1; |
346 | } | | 346 | } |
347 | } | | 347 | } |
348 | if (!got_addr) { | | 348 | if (!got_addr) { |
349 | printf("%s: no Ethernet address found\n", device_xname(sc->sc_dev)); | | 349 | printf("%s: no Ethernet address found\n", device_xname(sc->sc_dev)); |
350 | /* should we bail here? */ | | 350 | /* should we bail here? */ |
351 | } | | 351 | } |
352 | | | 352 | |
353 | if (pci_intr_map(pa, &gsc->gsc_handle) != 0) { | | 353 | if (pci_intr_map(pa, &gsc->gsc_handle) != 0) { |
354 | aprint_error_dev(sc->sc_dev, "unable to map interrupt\n"); | | 354 | aprint_error_dev(sc->sc_dev, "unable to map interrupt\n"); |
355 | return; | | 355 | return; |
356 | } | | 356 | } |
357 | gsc->gsc_pc = pa->pa_pc; | | 357 | gsc->gsc_pc = pa->pa_pc; |
358 | gem_pci_estintr(gsc); | | 358 | gem_pci_estintr(gsc); |
359 | | | 359 | |
360 | /* Finish off the attach. */ | | 360 | /* Finish off the attach. */ |
361 | gem_attach(sc, enaddr); | | 361 | gem_attach(sc, enaddr); |
362 | | | 362 | |
363 | if (pmf_device_register1(sc->sc_dev, | | 363 | if (pmf_device_register1(sc->sc_dev, |
364 | gem_pci_suspend, gem_pci_resume, gem_shutdown)) | | 364 | gem_pci_suspend, gem_pci_resume, gem_shutdown)) |
365 | pmf_class_network_register(sc->sc_dev, &sc->sc_ethercom.ec_if); | | 365 | pmf_class_network_register(sc->sc_dev, &sc->sc_ethercom.ec_if); |
366 | else | | 366 | else |
367 | aprint_error_dev(sc->sc_dev, | | 367 | aprint_error_dev(sc->sc_dev, |
368 | "could not establish power handlers\n"); | | 368 | "could not establish power handlers\n"); |
369 | } | | 369 | } |
370 | | | 370 | |
371 | static bool | | 371 | static bool |
372 | gem_pci_suspend(device_t self, const pmf_qual_t *qual) | | 372 | gem_pci_suspend(device_t self, const pmf_qual_t *qual) |
373 | { | | 373 | { |
374 | struct gem_pci_softc *gsc = device_private(self); | | 374 | struct gem_pci_softc *gsc = device_private(self); |
375 | | | 375 | |
376 | if (gsc->gsc_ih != NULL) { | | 376 | if (gsc->gsc_ih != NULL) { |
377 | pci_intr_disestablish(gsc->gsc_pc, gsc->gsc_ih); | | 377 | pci_intr_disestablish(gsc->gsc_pc, gsc->gsc_ih); |
378 | gsc->gsc_ih = NULL; | | 378 | gsc->gsc_ih = NULL; |
379 | } | | 379 | } |
380 | | | 380 | |
381 | return true; | | 381 | return true; |
382 | } | | 382 | } |
383 | | | 383 | |
384 | static bool | | 384 | static bool |
385 | gem_pci_estintr(struct gem_pci_softc *gsc) | | 385 | gem_pci_estintr(struct gem_pci_softc *gsc) |
386 | { | | 386 | { |
387 | struct gem_softc *sc = &gsc->gsc_gem; | | 387 | struct gem_softc *sc = &gsc->gsc_gem; |
388 | const char *intrstr; | | 388 | const char *intrstr; |
389 | | | 389 | |
390 | intrstr = pci_intr_string(gsc->gsc_pc, gsc->gsc_handle); | | 390 | intrstr = pci_intr_string(gsc->gsc_pc, gsc->gsc_handle); |
391 | gsc->gsc_ih = pci_intr_establish(gsc->gsc_pc, gsc->gsc_handle, IPL_NET, | | 391 | gsc->gsc_ih = pci_intr_establish(gsc->gsc_pc, gsc->gsc_handle, IPL_NET, |
392 | gem_intr, sc); | | 392 | gem_intr, sc); |
393 | if (gsc->gsc_ih == NULL) { | | 393 | if (gsc->gsc_ih == NULL) { |
394 | aprint_error_dev(sc->sc_dev, "unable to establish interrupt"); | | 394 | aprint_error_dev(sc->sc_dev, "unable to establish interrupt"); |
395 | if (intrstr != NULL) | | 395 | if (intrstr != NULL) |
396 | aprint_error(" at %s", intrstr); | | 396 | aprint_error(" at %s", intrstr); |
397 | aprint_error("\n"); | | 397 | aprint_error("\n"); |
398 | return false; | | 398 | return false; |
399 | } | | 399 | } |
400 | aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); | | 400 | aprint_normal_dev(sc->sc_dev, "interrupting at %s\n", intrstr); |
401 | return true; | | 401 | return true; |
402 | } | | 402 | } |
403 | | | 403 | |
404 | static bool | | 404 | static bool |
405 | gem_pci_resume(device_t self, const pmf_qual_t *qual) | | 405 | gem_pci_resume(device_t self, const pmf_qual_t *qual) |
406 | { | | 406 | { |
407 | struct gem_pci_softc *gsc = device_private(self); | | 407 | struct gem_pci_softc *gsc = device_private(self); |
408 | | | 408 | |
409 | return gem_pci_estintr(gsc); | | 409 | return gem_pci_estintr(gsc); |
410 | } | | 410 | } |
411 | | | 411 | |
412 | static int | | 412 | static int |
413 | gem_pci_detach(device_t self, int flags) | | 413 | gem_pci_detach(device_t self, int flags) |
414 | { | | 414 | { |
415 | int rc; | | 415 | int rc; |
416 | struct gem_pci_softc *gsc = device_private(self); | | 416 | struct gem_pci_softc *gsc = device_private(self); |
417 | struct gem_softc *sc = &gsc->gsc_gem; | | 417 | struct gem_softc *sc = &gsc->gsc_gem; |
418 | | | 418 | |
419 | switch (sc->sc_att_stage) { | | 419 | switch (sc->sc_att_stage) { |
420 | case GEM_ATT_BACKEND_2: | | 420 | case GEM_ATT_BACKEND_2: |
421 | pmf_device_deregister(self); | | 421 | pmf_device_deregister(self); |
422 | sc->sc_att_stage = GEM_ATT_FINISHED; | | 422 | sc->sc_att_stage = GEM_ATT_FINISHED; |
423 | /*FALLTHROUGH*/ | | 423 | /*FALLTHROUGH*/ |
424 | default: | | 424 | default: |
425 | if ((rc = gem_detach(sc, flags)) != 0) | | 425 | if ((rc = gem_detach(sc, flags)) != 0) |
426 | return rc; | | 426 | return rc; |
427 | /*FALLTHROUGH*/ | | 427 | /*FALLTHROUGH*/ |
428 | case GEM_ATT_BACKEND_1: | | 428 | case GEM_ATT_BACKEND_1: |
429 | if (gsc->gsc_ih != NULL) | | 429 | if (gsc->gsc_ih != NULL) |
430 | pci_intr_disestablish(gsc->gsc_pc, gsc->gsc_ih); | | 430 | pci_intr_disestablish(gsc->gsc_pc, gsc->gsc_ih); |
431 | | | 431 | |
432 | bus_space_unmap(sc->sc_bustag, sc->sc_h1, sc->sc_size); | | 432 | bus_space_unmap(sc->sc_bustag, sc->sc_h1, sc->sc_size); |
433 | /*FALLTHROUGH*/ | | 433 | /*FALLTHROUGH*/ |
434 | case GEM_ATT_BACKEND_0: | | 434 | case GEM_ATT_BACKEND_0: |
435 | sc->sc_att_stage = GEM_ATT_BACKEND_0; | | 435 | sc->sc_att_stage = GEM_ATT_BACKEND_0; |
436 | break; | | 436 | break; |
437 | } | | 437 | } |
438 | return 0; | | 438 | return 0; |
439 | } | | 439 | } |