| @@ -1,969 +1,974 @@ | | | @@ -1,969 +1,974 @@ |
1 | /* $NetBSD: pci.c,v 1.118 2008/06/12 22:44:47 cegger Exp $ */ | | 1 | /* $NetBSD: pci.c,v 1.119 2008/09/19 14:37:13 joerg Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 1995, 1996, 1997, 1998 | | 4 | * Copyright (c) 1995, 1996, 1997, 1998 |
5 | * Christopher G. Demetriou. All rights reserved. | | 5 | * Christopher G. Demetriou. All rights reserved. |
6 | * Copyright (c) 1994 Charles M. Hannum. All rights reserved. | | 6 | * Copyright (c) 1994 Charles M. Hannum. All rights reserved. |
7 | * | | 7 | * |
8 | * Redistribution and use in source and binary forms, with or without | | 8 | * Redistribution and use in source and binary forms, with or without |
9 | * modification, are permitted provided that the following conditions | | 9 | * modification, are permitted provided that the following conditions |
10 | * are met: | | 10 | * are met: |
11 | * 1. Redistributions of source code must retain the above copyright | | 11 | * 1. Redistributions of source code must retain the above copyright |
12 | * notice, this list of conditions and the following disclaimer. | | 12 | * notice, this list of conditions and the following disclaimer. |
13 | * 2. Redistributions in binary form must reproduce the above copyright | | 13 | * 2. Redistributions in binary form must reproduce the above copyright |
14 | * notice, this list of conditions and the following disclaimer in the | | 14 | * notice, this list of conditions and the following disclaimer in the |
15 | * documentation and/or other materials provided with the distribution. | | 15 | * documentation and/or other materials provided with the distribution. |
16 | * 3. All advertising materials mentioning features or use of this software | | 16 | * 3. All advertising materials mentioning features or use of this software |
17 | * must display the following acknowledgement: | | 17 | * must display the following acknowledgement: |
18 | * This product includes software developed by Charles M. Hannum. | | 18 | * This product includes software developed by Charles M. Hannum. |
19 | * 4. The name of the author may not be used to endorse or promote products | | 19 | * 4. The name of the author may not be used to endorse or promote products |
20 | * derived from this software without specific prior written permission. | | 20 | * derived from this software without specific prior written permission. |
21 | * | | 21 | * |
22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | | 22 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | | 23 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
24 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | | 24 | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
25 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | | 25 | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | | 26 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
27 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | | 27 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | | 28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | | 29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | | 30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
31 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | | 31 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
32 | */ | | 32 | */ |
33 | | | 33 | |
34 | /* | | 34 | /* |
35 | * PCI bus autoconfiguration. | | 35 | * PCI bus autoconfiguration. |
36 | */ | | 36 | */ |
37 | | | 37 | |
38 | #include <sys/cdefs.h> | | 38 | #include <sys/cdefs.h> |
39 | __KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.118 2008/06/12 22:44:47 cegger Exp $"); | | 39 | __KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.119 2008/09/19 14:37:13 joerg Exp $"); |
40 | | | 40 | |
41 | #include "opt_pci.h" | | 41 | #include "opt_pci.h" |
42 | | | 42 | |
43 | #include <sys/param.h> | | 43 | #include <sys/param.h> |
44 | #include <sys/malloc.h> | | 44 | #include <sys/malloc.h> |
45 | #include <sys/systm.h> | | 45 | #include <sys/systm.h> |
46 | #include <sys/device.h> | | 46 | #include <sys/device.h> |
47 | | | 47 | |
48 | #include <dev/pci/pcireg.h> | | 48 | #include <dev/pci/pcireg.h> |
49 | #include <dev/pci/pcivar.h> | | 49 | #include <dev/pci/pcivar.h> |
50 | #include <dev/pci/pcidevs.h> | | 50 | #include <dev/pci/pcidevs.h> |
51 | | | 51 | |
52 | #include <uvm/uvm_extern.h> | | 52 | #include <uvm/uvm_extern.h> |
53 | | | 53 | |
54 | #include <net/if.h> | | 54 | #include <net/if.h> |
55 | | | 55 | |
56 | #include "locators.h" | | 56 | #include "locators.h" |
57 | | | 57 | |
58 | static bool pci_child_register(device_t); | | 58 | static bool pci_child_register(device_t); |
59 | | | 59 | |
60 | #ifdef PCI_CONFIG_DUMP | | 60 | #ifdef PCI_CONFIG_DUMP |
61 | int pci_config_dump = 1; | | 61 | int pci_config_dump = 1; |
62 | #else | | 62 | #else |
63 | int pci_config_dump = 0; | | 63 | int pci_config_dump = 0; |
64 | #endif | | 64 | #endif |
65 | | | 65 | |
66 | int pciprint(void *, const char *); | | 66 | int pciprint(void *, const char *); |
67 | | | 67 | |
68 | #ifdef PCI_MACHDEP_ENUMERATE_BUS | | 68 | #ifdef PCI_MACHDEP_ENUMERATE_BUS |
69 | #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS | | 69 | #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS |
70 | #else | | 70 | #else |
71 | int pci_enumerate_bus(struct pci_softc *, const int *, | | 71 | int pci_enumerate_bus(struct pci_softc *, const int *, |
72 | int (*)(struct pci_attach_args *), struct pci_attach_args *); | | 72 | int (*)(struct pci_attach_args *), struct pci_attach_args *); |
73 | #endif | | 73 | #endif |
74 | | | 74 | |
75 | /* | | 75 | /* |
76 | * Important note about PCI-ISA bridges: | | 76 | * Important note about PCI-ISA bridges: |
77 | * | | 77 | * |
78 | * Callbacks are used to configure these devices so that ISA/EISA bridges | | 78 | * Callbacks are used to configure these devices so that ISA/EISA bridges |
79 | * can attach their child busses after PCI configuration is done. | | 79 | * can attach their child busses after PCI configuration is done. |
80 | * | | 80 | * |
81 | * This works because: | | 81 | * This works because: |
82 | * (1) there can be at most one ISA/EISA bridge per PCI bus, and | | 82 | * (1) there can be at most one ISA/EISA bridge per PCI bus, and |
83 | * (2) any ISA/EISA bridges must be attached to primary PCI | | 83 | * (2) any ISA/EISA bridges must be attached to primary PCI |
84 | * busses (i.e. bus zero). | | 84 | * busses (i.e. bus zero). |
85 | * | | 85 | * |
86 | * That boils down to: there can only be one of these outstanding | | 86 | * That boils down to: there can only be one of these outstanding |
87 | * at a time, it is cleared when configuring PCI bus 0 before any | | 87 | * at a time, it is cleared when configuring PCI bus 0 before any |
88 | * subdevices have been found, and it is run after all subdevices | | 88 | * subdevices have been found, and it is run after all subdevices |
89 | * of PCI bus 0 have been found. | | 89 | * of PCI bus 0 have been found. |
90 | * | | 90 | * |
91 | * This is needed because there are some (legacy) PCI devices which | | 91 | * This is needed because there are some (legacy) PCI devices which |
92 | * can show up as ISA/EISA devices as well (the prime example of which | | 92 | * can show up as ISA/EISA devices as well (the prime example of which |
93 | * are VGA controllers). If you attach ISA from a PCI-ISA/EISA bridge, | | 93 | * are VGA controllers). If you attach ISA from a PCI-ISA/EISA bridge, |
94 | * and the bridge is seen before the video board is, the board can show | | 94 | * and the bridge is seen before the video board is, the board can show |
95 | * up as an ISA device, and that can (bogusly) complicate the PCI device's | | 95 | * up as an ISA device, and that can (bogusly) complicate the PCI device's |
96 | * attach code, or make the PCI device not be properly attached at all. | | 96 | * attach code, or make the PCI device not be properly attached at all. |
97 | * | | 97 | * |
98 | * We use the generic config_defer() facility to achieve this. | | 98 | * We use the generic config_defer() facility to achieve this. |
99 | */ | | 99 | */ |
100 | | | 100 | |
101 | int | | 101 | int |
102 | pcirescan(device_t self, const char *ifattr, const int *locators) | | 102 | pcirescan(device_t self, const char *ifattr, const int *locators) |
103 | { | | 103 | { |
104 | struct pci_softc *sc = device_private(self); | | 104 | struct pci_softc *sc = device_private(self); |
105 | | | 105 | |
106 | KASSERT(ifattr && !strcmp(ifattr, "pci")); | | 106 | KASSERT(ifattr && !strcmp(ifattr, "pci")); |
107 | KASSERT(locators); | | 107 | KASSERT(locators); |
108 | | | 108 | |
109 | pci_enumerate_bus(sc, locators, NULL, NULL); | | 109 | pci_enumerate_bus(sc, locators, NULL, NULL); |
110 | return 0; | | 110 | return 0; |
111 | } | | 111 | } |
112 | | | 112 | |
113 | int | | 113 | int |
114 | pcimatch(device_t parent, cfdata_t cf, void *aux) | | 114 | pcimatch(device_t parent, cfdata_t cf, void *aux) |
115 | { | | 115 | { |
116 | struct pcibus_attach_args *pba = aux; | | 116 | struct pcibus_attach_args *pba = aux; |
117 | | | 117 | |
118 | /* Check the locators */ | | 118 | /* Check the locators */ |
119 | if (cf->cf_loc[PCIBUSCF_BUS] != PCIBUSCF_BUS_DEFAULT && | | 119 | if (cf->cf_loc[PCIBUSCF_BUS] != PCIBUSCF_BUS_DEFAULT && |
120 | cf->cf_loc[PCIBUSCF_BUS] != pba->pba_bus) | | 120 | cf->cf_loc[PCIBUSCF_BUS] != pba->pba_bus) |
121 | return (0); | | 121 | return (0); |
122 | | | 122 | |
123 | /* sanity */ | | 123 | /* sanity */ |
124 | if (pba->pba_bus < 0 || pba->pba_bus > 255) | | 124 | if (pba->pba_bus < 0 || pba->pba_bus > 255) |
125 | return (0); | | 125 | return (0); |
126 | | | 126 | |
127 | /* | | 127 | /* |
128 | * XXX check other (hardware?) indicators | | 128 | * XXX check other (hardware?) indicators |
129 | */ | | 129 | */ |
130 | | | 130 | |
131 | return (1); | | 131 | return (1); |
132 | } | | 132 | } |
133 | | | 133 | |
134 | void | | 134 | void |
135 | pciattach(device_t parent, device_t self, void *aux) | | 135 | pciattach(device_t parent, device_t self, void *aux) |
136 | { | | 136 | { |
137 | struct pcibus_attach_args *pba = aux; | | 137 | struct pcibus_attach_args *pba = aux; |
138 | struct pci_softc *sc = device_private(self); | | 138 | struct pci_softc *sc = device_private(self); |
139 | int io_enabled, mem_enabled, mrl_enabled, mrm_enabled, mwi_enabled; | | 139 | int io_enabled, mem_enabled, mrl_enabled, mrm_enabled, mwi_enabled; |
140 | const char *sep = ""; | | 140 | const char *sep = ""; |
141 | static const int wildcard[PCICF_NLOCS] = { | | 141 | static const int wildcard[PCICF_NLOCS] = { |
142 | PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT | | 142 | PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT |
143 | }; | | 143 | }; |
144 | | | 144 | |
145 | sc->sc_dev = self; | | 145 | sc->sc_dev = self; |
146 | | | 146 | |
147 | pci_attach_hook(parent, self, pba); | | 147 | pci_attach_hook(parent, self, pba); |
148 | | | 148 | |
149 | aprint_naive("\n"); | | 149 | aprint_naive("\n"); |
150 | aprint_normal("\n"); | | 150 | aprint_normal("\n"); |
151 | | | 151 | |
152 | io_enabled = (pba->pba_flags & PCI_FLAGS_IO_ENABLED); | | 152 | io_enabled = (pba->pba_flags & PCI_FLAGS_IO_ENABLED); |
153 | mem_enabled = (pba->pba_flags & PCI_FLAGS_MEM_ENABLED); | | 153 | mem_enabled = (pba->pba_flags & PCI_FLAGS_MEM_ENABLED); |
154 | mrl_enabled = (pba->pba_flags & PCI_FLAGS_MRL_OKAY); | | 154 | mrl_enabled = (pba->pba_flags & PCI_FLAGS_MRL_OKAY); |
155 | mrm_enabled = (pba->pba_flags & PCI_FLAGS_MRM_OKAY); | | 155 | mrm_enabled = (pba->pba_flags & PCI_FLAGS_MRM_OKAY); |
156 | mwi_enabled = (pba->pba_flags & PCI_FLAGS_MWI_OKAY); | | 156 | mwi_enabled = (pba->pba_flags & PCI_FLAGS_MWI_OKAY); |
157 | | | 157 | |
158 | if (io_enabled == 0 && mem_enabled == 0) { | | 158 | if (io_enabled == 0 && mem_enabled == 0) { |
159 | aprint_error_dev(self, "no spaces enabled!\n"); | | 159 | aprint_error_dev(self, "no spaces enabled!\n"); |
160 | goto fail; | | 160 | goto fail; |
161 | } | | 161 | } |
162 | | | 162 | |
163 | #define PRINT(str) \ | | 163 | #define PRINT(str) \ |
164 | do { \ | | 164 | do { \ |
165 | aprint_verbose("%s%s", sep, str); \ | | 165 | aprint_verbose("%s%s", sep, str); \ |
166 | sep = ", "; \ | | 166 | sep = ", "; \ |
167 | } while (/*CONSTCOND*/0) | | 167 | } while (/*CONSTCOND*/0) |
168 | | | 168 | |
169 | aprint_verbose_dev(self, ""); | | 169 | aprint_verbose_dev(self, ""); |
170 | | | 170 | |
171 | if (io_enabled) | | 171 | if (io_enabled) |
172 | PRINT("i/o space"); | | 172 | PRINT("i/o space"); |
173 | if (mem_enabled) | | 173 | if (mem_enabled) |
174 | PRINT("memory space"); | | 174 | PRINT("memory space"); |
175 | aprint_verbose(" enabled"); | | 175 | aprint_verbose(" enabled"); |
176 | | | 176 | |
177 | if (mrl_enabled || mrm_enabled || mwi_enabled) { | | 177 | if (mrl_enabled || mrm_enabled || mwi_enabled) { |
178 | if (mrl_enabled) | | 178 | if (mrl_enabled) |
179 | PRINT("rd/line"); | | 179 | PRINT("rd/line"); |
180 | if (mrm_enabled) | | 180 | if (mrm_enabled) |
181 | PRINT("rd/mult"); | | 181 | PRINT("rd/mult"); |
182 | if (mwi_enabled) | | 182 | if (mwi_enabled) |
183 | PRINT("wr/inv"); | | 183 | PRINT("wr/inv"); |
184 | aprint_verbose(" ok"); | | 184 | aprint_verbose(" ok"); |
185 | } | | 185 | } |
186 | | | 186 | |
187 | aprint_verbose("\n"); | | 187 | aprint_verbose("\n"); |
188 | | | 188 | |
189 | #undef PRINT | | 189 | #undef PRINT |
190 | | | 190 | |
191 | sc->sc_iot = pba->pba_iot; | | 191 | sc->sc_iot = pba->pba_iot; |
192 | sc->sc_memt = pba->pba_memt; | | 192 | sc->sc_memt = pba->pba_memt; |
193 | sc->sc_dmat = pba->pba_dmat; | | 193 | sc->sc_dmat = pba->pba_dmat; |
194 | sc->sc_dmat64 = pba->pba_dmat64; | | 194 | sc->sc_dmat64 = pba->pba_dmat64; |
195 | sc->sc_pc = pba->pba_pc; | | 195 | sc->sc_pc = pba->pba_pc; |
196 | sc->sc_bus = pba->pba_bus; | | 196 | sc->sc_bus = pba->pba_bus; |
197 | sc->sc_bridgetag = pba->pba_bridgetag; | | 197 | sc->sc_bridgetag = pba->pba_bridgetag; |
198 | sc->sc_maxndevs = pci_bus_maxdevs(pba->pba_pc, pba->pba_bus); | | 198 | sc->sc_maxndevs = pci_bus_maxdevs(pba->pba_pc, pba->pba_bus); |
199 | sc->sc_intrswiz = pba->pba_intrswiz; | | 199 | sc->sc_intrswiz = pba->pba_intrswiz; |
200 | sc->sc_intrtag = pba->pba_intrtag; | | 200 | sc->sc_intrtag = pba->pba_intrtag; |
201 | sc->sc_flags = pba->pba_flags; | | 201 | sc->sc_flags = pba->pba_flags; |
202 | | | 202 | |
203 | device_pmf_driver_set_child_register(sc->sc_dev, pci_child_register); | | 203 | device_pmf_driver_set_child_register(sc->sc_dev, pci_child_register); |
204 | | | 204 | |
205 | pcirescan(sc->sc_dev, "pci", wildcard); | | 205 | pcirescan(sc->sc_dev, "pci", wildcard); |
206 | | | 206 | |
207 | fail: | | 207 | fail: |
208 | if (!pmf_device_register(self, NULL, NULL)) | | 208 | if (!pmf_device_register(self, NULL, NULL)) |
209 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 209 | aprint_error_dev(self, "couldn't establish power handler\n"); |
210 | } | | 210 | } |
211 | | | 211 | |
212 | int | | 212 | int |
213 | pcidetach(device_t self, int flags) | | 213 | pcidetach(device_t self, int flags) |
214 | { | | 214 | { |
215 | int rc; | | 215 | int rc; |
216 | | | 216 | |
217 | if ((rc = config_detach_children(self, flags)) != 0) | | 217 | if ((rc = config_detach_children(self, flags)) != 0) |
218 | return rc; | | 218 | return rc; |
219 | pmf_device_deregister(self); | | 219 | pmf_device_deregister(self); |
220 | return 0; | | 220 | return 0; |
221 | } | | 221 | } |
222 | | | 222 | |
223 | int | | 223 | int |
224 | pciprint(void *aux, const char *pnp) | | 224 | pciprint(void *aux, const char *pnp) |
225 | { | | 225 | { |
226 | struct pci_attach_args *pa = aux; | | 226 | struct pci_attach_args *pa = aux; |
227 | char devinfo[256]; | | 227 | char devinfo[256]; |
228 | const struct pci_quirkdata *qd; | | 228 | const struct pci_quirkdata *qd; |
229 | | | 229 | |
230 | if (pnp) { | | 230 | if (pnp) { |
231 | pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); | | 231 | pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); |
232 | aprint_normal("%s at %s", devinfo, pnp); | | 232 | aprint_normal("%s at %s", devinfo, pnp); |
233 | } | | 233 | } |
234 | aprint_normal(" dev %d function %d", pa->pa_device, pa->pa_function); | | 234 | aprint_normal(" dev %d function %d", pa->pa_device, pa->pa_function); |
235 | if (pci_config_dump) { | | 235 | if (pci_config_dump) { |
236 | printf(": "); | | 236 | printf(": "); |
237 | pci_conf_print(pa->pa_pc, pa->pa_tag, NULL); | | 237 | pci_conf_print(pa->pa_pc, pa->pa_tag, NULL); |
238 | if (!pnp) | | 238 | if (!pnp) |
239 | pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); | | 239 | pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); |
240 | printf("%s at %s", devinfo, pnp ? pnp : "?"); | | 240 | printf("%s at %s", devinfo, pnp ? pnp : "?"); |
241 | printf(" dev %d function %d (", pa->pa_device, pa->pa_function); | | 241 | printf(" dev %d function %d (", pa->pa_device, pa->pa_function); |
242 | #ifdef __i386__ | | 242 | #ifdef __i386__ |
243 | printf("tag %#lx, intrtag %#lx, intrswiz %#lx, intrpin %#lx", | | 243 | printf("tag %#lx, intrtag %#lx, intrswiz %#lx, intrpin %#lx", |
244 | *(long *)&pa->pa_tag, *(long *)&pa->pa_intrtag, | | 244 | *(long *)&pa->pa_tag, *(long *)&pa->pa_intrtag, |
245 | (long)pa->pa_intrswiz, (long)pa->pa_intrpin); | | 245 | (long)pa->pa_intrswiz, (long)pa->pa_intrpin); |
246 | #else | | 246 | #else |
247 | printf("intrswiz %#lx, intrpin %#lx", | | 247 | printf("intrswiz %#lx, intrpin %#lx", |
248 | (long)pa->pa_intrswiz, (long)pa->pa_intrpin); | | 248 | (long)pa->pa_intrswiz, (long)pa->pa_intrpin); |
249 | #endif | | 249 | #endif |
250 | printf(", i/o %s, mem %s,", | | 250 | printf(", i/o %s, mem %s,", |
251 | pa->pa_flags & PCI_FLAGS_IO_ENABLED ? "on" : "off", | | 251 | pa->pa_flags & PCI_FLAGS_IO_ENABLED ? "on" : "off", |
252 | pa->pa_flags & PCI_FLAGS_MEM_ENABLED ? "on" : "off"); | | 252 | pa->pa_flags & PCI_FLAGS_MEM_ENABLED ? "on" : "off"); |
253 | qd = pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id), | | 253 | qd = pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id), |
254 | PCI_PRODUCT(pa->pa_id)); | | 254 | PCI_PRODUCT(pa->pa_id)); |
255 | if (qd == NULL) { | | 255 | if (qd == NULL) { |
256 | printf(" no quirks"); | | 256 | printf(" no quirks"); |
257 | } else { | | 257 | } else { |
258 | bitmask_snprintf(qd->quirks, | | 258 | bitmask_snprintf(qd->quirks, |
259 | "\002\001multifn\002singlefn\003skipfunc0" | | 259 | "\002\001multifn\002singlefn\003skipfunc0" |
260 | "\004skipfunc1\005skipfunc2\006skipfunc3" | | 260 | "\004skipfunc1\005skipfunc2\006skipfunc3" |
261 | "\007skipfunc4\010skipfunc5\011skipfunc6" | | 261 | "\007skipfunc4\010skipfunc5\011skipfunc6" |
262 | "\012skipfunc7", | | 262 | "\012skipfunc7", |
263 | devinfo, sizeof (devinfo)); | | 263 | devinfo, sizeof (devinfo)); |
264 | printf(" quirks %s", devinfo); | | 264 | printf(" quirks %s", devinfo); |
265 | } | | 265 | } |
266 | printf(")"); | | 266 | printf(")"); |
267 | } | | 267 | } |
268 | return (UNCONF); | | 268 | return (UNCONF); |
269 | } | | 269 | } |
270 | | | 270 | |
271 | int | | 271 | int |
272 | pci_probe_device(struct pci_softc *sc, pcitag_t tag, | | 272 | pci_probe_device(struct pci_softc *sc, pcitag_t tag, |
273 | int (*match)(struct pci_attach_args *), struct pci_attach_args *pap) | | 273 | int (*match)(struct pci_attach_args *), struct pci_attach_args *pap) |
274 | { | | 274 | { |
275 | pci_chipset_tag_t pc = sc->sc_pc; | | 275 | pci_chipset_tag_t pc = sc->sc_pc; |
276 | struct pci_attach_args pa; | | 276 | struct pci_attach_args pa; |
277 | pcireg_t id, csr, class, intr, bhlcr; | | 277 | pcireg_t id, csr, class, intr, bhlcr; |
278 | int ret, pin, bus, device, function; | | 278 | int ret, pin, bus, device, function; |
279 | int locs[PCICF_NLOCS]; | | 279 | int locs[PCICF_NLOCS]; |
280 | device_t subdev; | | 280 | device_t subdev; |
281 | | | 281 | |
282 | pci_decompose_tag(pc, tag, &bus, &device, &function); | | 282 | pci_decompose_tag(pc, tag, &bus, &device, &function); |
283 | | | 283 | |
284 | /* a driver already attached? */ | | 284 | /* a driver already attached? */ |
285 | if (sc->PCI_SC_DEVICESC(device, function).c_dev != NULL && !match) | | 285 | if (sc->PCI_SC_DEVICESC(device, function).c_dev != NULL && !match) |
286 | return (0); | | 286 | return (0); |
287 | | | 287 | |
288 | bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); | | 288 | bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); |
289 | if (PCI_HDRTYPE_TYPE(bhlcr) > 2) | | 289 | if (PCI_HDRTYPE_TYPE(bhlcr) > 2) |
290 | return (0); | | 290 | return (0); |
291 | | | 291 | |
292 | id = pci_conf_read(pc, tag, PCI_ID_REG); | | 292 | id = pci_conf_read(pc, tag, PCI_ID_REG); |
293 | csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); | | 293 | csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); |
294 | class = pci_conf_read(pc, tag, PCI_CLASS_REG); | | 294 | class = pci_conf_read(pc, tag, PCI_CLASS_REG); |
295 | | | 295 | |
296 | /* Invalid vendor ID value? */ | | 296 | /* Invalid vendor ID value? */ |
297 | if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) | | 297 | if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) |
298 | return (0); | | 298 | return (0); |
299 | /* XXX Not invalid, but we've done this ~forever. */ | | 299 | /* XXX Not invalid, but we've done this ~forever. */ |
300 | if (PCI_VENDOR(id) == 0) | | 300 | if (PCI_VENDOR(id) == 0) |
301 | return (0); | | 301 | return (0); |
302 | | | 302 | |
303 | pa.pa_iot = sc->sc_iot; | | 303 | pa.pa_iot = sc->sc_iot; |
304 | pa.pa_memt = sc->sc_memt; | | 304 | pa.pa_memt = sc->sc_memt; |
305 | pa.pa_dmat = sc->sc_dmat; | | 305 | pa.pa_dmat = sc->sc_dmat; |
306 | pa.pa_dmat64 = sc->sc_dmat64; | | 306 | pa.pa_dmat64 = sc->sc_dmat64; |
307 | pa.pa_pc = pc; | | 307 | pa.pa_pc = pc; |
308 | pa.pa_bus = bus; | | 308 | pa.pa_bus = bus; |
309 | pa.pa_device = device; | | 309 | pa.pa_device = device; |
310 | pa.pa_function = function; | | 310 | pa.pa_function = function; |
311 | pa.pa_tag = tag; | | 311 | pa.pa_tag = tag; |
312 | pa.pa_id = id; | | 312 | pa.pa_id = id; |
313 | pa.pa_class = class; | | 313 | pa.pa_class = class; |
314 | | | 314 | |
315 | /* | | 315 | /* |
316 | * Set up memory, I/O enable, and PCI command flags | | 316 | * Set up memory, I/O enable, and PCI command flags |
317 | * as appropriate. | | 317 | * as appropriate. |
318 | */ | | 318 | */ |
319 | pa.pa_flags = sc->sc_flags; | | 319 | pa.pa_flags = sc->sc_flags; |
320 | if ((csr & PCI_COMMAND_IO_ENABLE) == 0) | | 320 | if ((csr & PCI_COMMAND_IO_ENABLE) == 0) |
321 | pa.pa_flags &= ~PCI_FLAGS_IO_ENABLED; | | 321 | pa.pa_flags &= ~PCI_FLAGS_IO_ENABLED; |
322 | if ((csr & PCI_COMMAND_MEM_ENABLE) == 0) | | 322 | if ((csr & PCI_COMMAND_MEM_ENABLE) == 0) |
323 | pa.pa_flags &= ~PCI_FLAGS_MEM_ENABLED; | | 323 | pa.pa_flags &= ~PCI_FLAGS_MEM_ENABLED; |
324 | | | 324 | |
325 | /* | | 325 | /* |
326 | * If the cache line size is not configured, then | | 326 | * If the cache line size is not configured, then |
327 | * clear the MRL/MRM/MWI command-ok flags. | | 327 | * clear the MRL/MRM/MWI command-ok flags. |
328 | */ | | 328 | */ |
329 | if (PCI_CACHELINE(bhlcr) == 0) | | 329 | if (PCI_CACHELINE(bhlcr) == 0) |
330 | pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY| | | 330 | pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY| |
331 | PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY); | | 331 | PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY); |
332 | | | 332 | |
333 | if (sc->sc_bridgetag == NULL) { | | 333 | if (sc->sc_bridgetag == NULL) { |
334 | pa.pa_intrswiz = 0; | | 334 | pa.pa_intrswiz = 0; |
335 | pa.pa_intrtag = tag; | | 335 | pa.pa_intrtag = tag; |
336 | } else { | | 336 | } else { |
337 | pa.pa_intrswiz = sc->sc_intrswiz + device; | | 337 | pa.pa_intrswiz = sc->sc_intrswiz + device; |
338 | pa.pa_intrtag = sc->sc_intrtag; | | 338 | pa.pa_intrtag = sc->sc_intrtag; |
339 | } | | 339 | } |
340 | | | 340 | |
341 | intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); | | 341 | intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); |
342 | | | 342 | |
343 | pin = PCI_INTERRUPT_PIN(intr); | | 343 | pin = PCI_INTERRUPT_PIN(intr); |
344 | pa.pa_rawintrpin = pin; | | 344 | pa.pa_rawintrpin = pin; |
345 | if (pin == PCI_INTERRUPT_PIN_NONE) { | | 345 | if (pin == PCI_INTERRUPT_PIN_NONE) { |
346 | /* no interrupt */ | | 346 | /* no interrupt */ |
347 | pa.pa_intrpin = 0; | | 347 | pa.pa_intrpin = 0; |
348 | } else { | | 348 | } else { |
349 | /* | | 349 | /* |
350 | * swizzle it based on the number of busses we're | | 350 | * swizzle it based on the number of busses we're |
351 | * behind and our device number. | | 351 | * behind and our device number. |
352 | */ | | 352 | */ |
353 | pa.pa_intrpin = /* XXX */ | | 353 | pa.pa_intrpin = /* XXX */ |
354 | ((pin + pa.pa_intrswiz - 1) % 4) + 1; | | 354 | ((pin + pa.pa_intrswiz - 1) % 4) + 1; |
355 | } | | 355 | } |
356 | pa.pa_intrline = PCI_INTERRUPT_LINE(intr); | | 356 | pa.pa_intrline = PCI_INTERRUPT_LINE(intr); |
357 | | | 357 | |
358 | if (match != NULL) { | | 358 | if (match != NULL) { |
359 | ret = (*match)(&pa); | | 359 | ret = (*match)(&pa); |
360 | if (ret != 0 && pap != NULL) | | 360 | if (ret != 0 && pap != NULL) |
361 | *pap = pa; | | 361 | *pap = pa; |
362 | } else { | | 362 | } else { |
363 | struct pci_child *c; | | 363 | struct pci_child *c; |
364 | locs[PCICF_DEV] = device; | | 364 | locs[PCICF_DEV] = device; |
365 | locs[PCICF_FUNCTION] = function; | | 365 | locs[PCICF_FUNCTION] = function; |
366 | | | 366 | |
367 | subdev = config_found_sm_loc(sc->sc_dev, "pci", locs, &pa, | | 367 | subdev = config_found_sm_loc(sc->sc_dev, "pci", locs, &pa, |
368 | pciprint, config_stdsubmatch); | | 368 | pciprint, config_stdsubmatch); |
369 | | | 369 | |
370 | c = &sc->PCI_SC_DEVICESC(device, function); | | 370 | c = &sc->PCI_SC_DEVICESC(device, function); |
371 | c->c_dev = subdev; | | 371 | c->c_dev = subdev; |
372 | pci_conf_capture(pc, tag, &c->c_conf); | | 372 | pci_conf_capture(pc, tag, &c->c_conf); |
373 | if (pci_get_powerstate(pc, tag, &c->c_powerstate) == 0) | | 373 | if (pci_get_powerstate(pc, tag, &c->c_powerstate) == 0) |
374 | c->c_psok = true; | | 374 | c->c_psok = true; |
375 | else | | 375 | else |
376 | c->c_psok = false; | | 376 | c->c_psok = false; |
377 | ret = (subdev != NULL); | | 377 | ret = (subdev != NULL); |
378 | } | | 378 | } |
379 | | | 379 | |
380 | return (ret); | | 380 | return (ret); |
381 | } | | 381 | } |
382 | | | 382 | |
383 | void | | 383 | void |
384 | pcidevdetached(device_t self, device_t child) | | 384 | pcidevdetached(device_t self, device_t child) |
385 | { | | 385 | { |
386 | struct pci_softc *sc = device_private(self); | | 386 | struct pci_softc *sc = device_private(self); |
387 | int d, f; | | 387 | int d, f; |
388 | pcitag_t tag; | | 388 | pcitag_t tag; |
389 | struct pci_child *c; | | 389 | struct pci_child *c; |
390 | | | 390 | |
391 | d = device_locator(child, PCICF_DEV); | | 391 | d = device_locator(child, PCICF_DEV); |
392 | f = device_locator(child, PCICF_FUNCTION); | | 392 | f = device_locator(child, PCICF_FUNCTION); |
393 | | | 393 | |
394 | c = &sc->PCI_SC_DEVICESC(d, f); | | 394 | c = &sc->PCI_SC_DEVICESC(d, f); |
395 | | | 395 | |
396 | KASSERT(c->c_dev == child); | | 396 | KASSERT(c->c_dev == child); |
397 | | | 397 | |
398 | tag = pci_make_tag(sc->sc_pc, sc->sc_bus, d, f); | | 398 | tag = pci_make_tag(sc->sc_pc, sc->sc_bus, d, f); |
399 | if (c->c_psok) | | 399 | if (c->c_psok) |
400 | pci_set_powerstate(sc->sc_pc, tag, c->c_powerstate); | | 400 | pci_set_powerstate(sc->sc_pc, tag, c->c_powerstate); |
401 | pci_conf_restore(sc->sc_pc, tag, &c->c_conf); | | 401 | pci_conf_restore(sc->sc_pc, tag, &c->c_conf); |
402 | c->c_dev = NULL; | | 402 | c->c_dev = NULL; |
403 | } | | 403 | } |
404 | | | 404 | |
405 | CFATTACH_DECL2_NEW(pci, sizeof(struct pci_softc), | | 405 | CFATTACH_DECL2_NEW(pci, sizeof(struct pci_softc), |
406 | pcimatch, pciattach, pcidetach, NULL, pcirescan, pcidevdetached); | | 406 | pcimatch, pciattach, pcidetach, NULL, pcirescan, pcidevdetached); |
407 | | | 407 | |
408 | int | | 408 | int |
409 | pci_get_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid, | | 409 | pci_get_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid, |
410 | int *offset, pcireg_t *value) | | 410 | int *offset, pcireg_t *value) |
411 | { | | 411 | { |
412 | pcireg_t reg; | | 412 | pcireg_t reg; |
413 | unsigned int ofs; | | 413 | unsigned int ofs; |
414 | | | 414 | |
415 | reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); | | 415 | reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); |
416 | if (!(reg & PCI_STATUS_CAPLIST_SUPPORT)) | | 416 | if (!(reg & PCI_STATUS_CAPLIST_SUPPORT)) |
417 | return (0); | | 417 | return (0); |
418 | | | 418 | |
419 | /* Determine the Capability List Pointer register to start with. */ | | 419 | /* Determine the Capability List Pointer register to start with. */ |
420 | reg = pci_conf_read(pc, tag, PCI_BHLC_REG); | | 420 | reg = pci_conf_read(pc, tag, PCI_BHLC_REG); |
421 | switch (PCI_HDRTYPE_TYPE(reg)) { | | 421 | switch (PCI_HDRTYPE_TYPE(reg)) { |
422 | case 0: /* standard device header */ | | 422 | case 0: /* standard device header */ |
423 | case 1: /* PCI-PCI bridge header */ | | 423 | case 1: /* PCI-PCI bridge header */ |
424 | ofs = PCI_CAPLISTPTR_REG; | | 424 | ofs = PCI_CAPLISTPTR_REG; |
425 | break; | | 425 | break; |
426 | case 2: /* PCI-CardBus Bridge header */ | | 426 | case 2: /* PCI-CardBus Bridge header */ |
427 | ofs = PCI_CARDBUS_CAPLISTPTR_REG; | | 427 | ofs = PCI_CARDBUS_CAPLISTPTR_REG; |
428 | break; | | 428 | break; |
429 | default: | | 429 | default: |
430 | return (0); | | 430 | return (0); |
431 | } | | 431 | } |
432 | | | 432 | |
433 | ofs = PCI_CAPLIST_PTR(pci_conf_read(pc, tag, ofs)); | | 433 | ofs = PCI_CAPLIST_PTR(pci_conf_read(pc, tag, ofs)); |
434 | while (ofs != 0) { | | 434 | while (ofs != 0) { |
435 | #ifdef DIAGNOSTIC | | 435 | if ((ofs & 3) || (ofs < 0x40)) { |
436 | if ((ofs & 3) || (ofs < 0x40)) | | 436 | int bus, device, function; |
437 | panic("pci_get_capability"); | | 437 | |
438 | #endif | | 438 | pci_decompose_tag(pc, tag, &bus, &device, &function); |
| | | 439 | |
| | | 440 | printf("Skipping broken PCI header on %d:%d:%d\n", |
| | | 441 | bus, device, function); |
| | | 442 | break; |
| | | 443 | } |
439 | reg = pci_conf_read(pc, tag, ofs); | | 444 | reg = pci_conf_read(pc, tag, ofs); |
440 | if (PCI_CAPLIST_CAP(reg) == capid) { | | 445 | if (PCI_CAPLIST_CAP(reg) == capid) { |
441 | if (offset) | | 446 | if (offset) |
442 | *offset = ofs; | | 447 | *offset = ofs; |
443 | if (value) | | 448 | if (value) |
444 | *value = reg; | | 449 | *value = reg; |
445 | return (1); | | 450 | return (1); |
446 | } | | 451 | } |
447 | ofs = PCI_CAPLIST_NEXT(reg); | | 452 | ofs = PCI_CAPLIST_NEXT(reg); |
448 | } | | 453 | } |
449 | | | 454 | |
450 | return (0); | | 455 | return (0); |
451 | } | | 456 | } |
452 | | | 457 | |
453 | int | | 458 | int |
454 | pci_find_device(struct pci_attach_args *pa, | | 459 | pci_find_device(struct pci_attach_args *pa, |
455 | int (*match)(struct pci_attach_args *)) | | 460 | int (*match)(struct pci_attach_args *)) |
456 | { | | 461 | { |
457 | extern struct cfdriver pci_cd; | | 462 | extern struct cfdriver pci_cd; |
458 | device_t pcidev; | | 463 | device_t pcidev; |
459 | int i; | | 464 | int i; |
460 | static const int wildcard[2] = { | | 465 | static const int wildcard[2] = { |
461 | PCICF_DEV_DEFAULT, | | 466 | PCICF_DEV_DEFAULT, |
462 | PCICF_FUNCTION_DEFAULT | | 467 | PCICF_FUNCTION_DEFAULT |
463 | }; | | 468 | }; |
464 | | | 469 | |
465 | for (i = 0; i < pci_cd.cd_ndevs; i++) { | | 470 | for (i = 0; i < pci_cd.cd_ndevs; i++) { |
466 | pcidev = device_lookup(&pci_cd, i); | | 471 | pcidev = device_lookup(&pci_cd, i); |
467 | if (pcidev != NULL && | | 472 | if (pcidev != NULL && |
468 | pci_enumerate_bus(device_private(pcidev), wildcard, | | 473 | pci_enumerate_bus(device_private(pcidev), wildcard, |
469 | match, pa) != 0) | | 474 | match, pa) != 0) |
470 | return (1); | | 475 | return (1); |
471 | } | | 476 | } |
472 | return (0); | | 477 | return (0); |
473 | } | | 478 | } |
474 | | | 479 | |
475 | #ifndef PCI_MACHDEP_ENUMERATE_BUS | | 480 | #ifndef PCI_MACHDEP_ENUMERATE_BUS |
476 | /* | | 481 | /* |
477 | * Generic PCI bus enumeration routine. Used unless machine-dependent | | 482 | * Generic PCI bus enumeration routine. Used unless machine-dependent |
478 | * code needs to provide something else. | | 483 | * code needs to provide something else. |
479 | */ | | 484 | */ |
480 | int | | 485 | int |
481 | pci_enumerate_bus(struct pci_softc *sc, const int *locators, | | 486 | pci_enumerate_bus(struct pci_softc *sc, const int *locators, |
482 | int (*match)(struct pci_attach_args *), struct pci_attach_args *pap) | | 487 | int (*match)(struct pci_attach_args *), struct pci_attach_args *pap) |
483 | { | | 488 | { |
484 | pci_chipset_tag_t pc = sc->sc_pc; | | 489 | pci_chipset_tag_t pc = sc->sc_pc; |
485 | int device, function, nfunctions, ret; | | 490 | int device, function, nfunctions, ret; |
486 | const struct pci_quirkdata *qd; | | 491 | const struct pci_quirkdata *qd; |
487 | pcireg_t id, bhlcr; | | 492 | pcireg_t id, bhlcr; |
488 | pcitag_t tag; | | 493 | pcitag_t tag; |
489 | #ifdef __PCI_BUS_DEVORDER | | 494 | #ifdef __PCI_BUS_DEVORDER |
490 | char devs[32]; | | 495 | char devs[32]; |
491 | int i; | | 496 | int i; |
492 | #endif | | 497 | #endif |
493 | | | 498 | |
494 | #ifdef __PCI_BUS_DEVORDER | | 499 | #ifdef __PCI_BUS_DEVORDER |
495 | pci_bus_devorder(sc->sc_pc, sc->sc_bus, devs); | | 500 | pci_bus_devorder(sc->sc_pc, sc->sc_bus, devs); |
496 | for (i = 0; (device = devs[i]) < 32 && device >= 0; i++) | | 501 | for (i = 0; (device = devs[i]) < 32 && device >= 0; i++) |
497 | #else | | 502 | #else |
498 | for (device = 0; device < sc->sc_maxndevs; device++) | | 503 | for (device = 0; device < sc->sc_maxndevs; device++) |
499 | #endif | | 504 | #endif |
500 | { | | 505 | { |
501 | if ((locators[PCICF_DEV] != PCICF_DEV_DEFAULT) && | | 506 | if ((locators[PCICF_DEV] != PCICF_DEV_DEFAULT) && |
502 | (locators[PCICF_DEV] != device)) | | 507 | (locators[PCICF_DEV] != device)) |
503 | continue; | | 508 | continue; |
504 | | | 509 | |
505 | tag = pci_make_tag(pc, sc->sc_bus, device, 0); | | 510 | tag = pci_make_tag(pc, sc->sc_bus, device, 0); |
506 | | | 511 | |
507 | bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); | | 512 | bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); |
508 | if (PCI_HDRTYPE_TYPE(bhlcr) > 2) | | 513 | if (PCI_HDRTYPE_TYPE(bhlcr) > 2) |
509 | continue; | | 514 | continue; |
510 | | | 515 | |
511 | id = pci_conf_read(pc, tag, PCI_ID_REG); | | 516 | id = pci_conf_read(pc, tag, PCI_ID_REG); |
512 | | | 517 | |
513 | /* Invalid vendor ID value? */ | | 518 | /* Invalid vendor ID value? */ |
514 | if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) | | 519 | if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) |
515 | continue; | | 520 | continue; |
516 | /* XXX Not invalid, but we've done this ~forever. */ | | 521 | /* XXX Not invalid, but we've done this ~forever. */ |
517 | if (PCI_VENDOR(id) == 0) | | 522 | if (PCI_VENDOR(id) == 0) |
518 | continue; | | 523 | continue; |
519 | | | 524 | |
520 | qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); | | 525 | qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); |
521 | | | 526 | |
522 | if (qd != NULL && | | 527 | if (qd != NULL && |
523 | (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0) | | 528 | (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0) |
524 | nfunctions = 8; | | 529 | nfunctions = 8; |
525 | else if (qd != NULL && | | 530 | else if (qd != NULL && |
526 | (qd->quirks & PCI_QUIRK_MONOFUNCTION) != 0) | | 531 | (qd->quirks & PCI_QUIRK_MONOFUNCTION) != 0) |
527 | nfunctions = 1; | | 532 | nfunctions = 1; |
528 | else | | 533 | else |
529 | nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; | | 534 | nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; |
530 | | | 535 | |
531 | for (function = 0; function < nfunctions; function++) { | | 536 | for (function = 0; function < nfunctions; function++) { |
532 | if ((locators[PCICF_FUNCTION] != PCICF_FUNCTION_DEFAULT) | | 537 | if ((locators[PCICF_FUNCTION] != PCICF_FUNCTION_DEFAULT) |
533 | && (locators[PCICF_FUNCTION] != function)) | | 538 | && (locators[PCICF_FUNCTION] != function)) |
534 | continue; | | 539 | continue; |
535 | | | 540 | |
536 | if (qd != NULL && | | 541 | if (qd != NULL && |
537 | (qd->quirks & PCI_QUIRK_SKIP_FUNC(function)) != 0) | | 542 | (qd->quirks & PCI_QUIRK_SKIP_FUNC(function)) != 0) |
538 | continue; | | 543 | continue; |
539 | tag = pci_make_tag(pc, sc->sc_bus, device, function); | | 544 | tag = pci_make_tag(pc, sc->sc_bus, device, function); |
540 | ret = pci_probe_device(sc, tag, match, pap); | | 545 | ret = pci_probe_device(sc, tag, match, pap); |
541 | if (match != NULL && ret != 0) | | 546 | if (match != NULL && ret != 0) |
542 | return (ret); | | 547 | return (ret); |
543 | } | | 548 | } |
544 | } | | 549 | } |
545 | return (0); | | 550 | return (0); |
546 | } | | 551 | } |
547 | #endif /* PCI_MACHDEP_ENUMERATE_BUS */ | | 552 | #endif /* PCI_MACHDEP_ENUMERATE_BUS */ |
548 | | | 553 | |
549 | | | 554 | |
550 | /* | | 555 | /* |
551 | * Vital Product Data (PCI 2.2) | | 556 | * Vital Product Data (PCI 2.2) |
552 | */ | | 557 | */ |
553 | | | 558 | |
554 | int | | 559 | int |
555 | pci_vpd_read(pci_chipset_tag_t pc, pcitag_t tag, int offset, int count, | | 560 | pci_vpd_read(pci_chipset_tag_t pc, pcitag_t tag, int offset, int count, |
556 | pcireg_t *data) | | 561 | pcireg_t *data) |
557 | { | | 562 | { |
558 | uint32_t reg; | | 563 | uint32_t reg; |
559 | int ofs, i, j; | | 564 | int ofs, i, j; |
560 | | | 565 | |
561 | KASSERT(data != NULL); | | 566 | KASSERT(data != NULL); |
562 | KASSERT((offset + count) < 0x7fff); | | 567 | KASSERT((offset + count) < 0x7fff); |
563 | | | 568 | |
564 | if (pci_get_capability(pc, tag, PCI_CAP_VPD, &ofs, ®) == 0) | | 569 | if (pci_get_capability(pc, tag, PCI_CAP_VPD, &ofs, ®) == 0) |
565 | return (1); | | 570 | return (1); |
566 | | | 571 | |
567 | for (i = 0; i < count; offset += sizeof(*data), i++) { | | 572 | for (i = 0; i < count; offset += sizeof(*data), i++) { |
568 | reg &= 0x0000ffff; | | 573 | reg &= 0x0000ffff; |
569 | reg &= ~PCI_VPD_OPFLAG; | | 574 | reg &= ~PCI_VPD_OPFLAG; |
570 | reg |= PCI_VPD_ADDRESS(offset); | | 575 | reg |= PCI_VPD_ADDRESS(offset); |
571 | pci_conf_write(pc, tag, ofs, reg); | | 576 | pci_conf_write(pc, tag, ofs, reg); |
572 | | | 577 | |
573 | /* | | 578 | /* |
574 | * PCI 2.2 does not specify how long we should poll | | 579 | * PCI 2.2 does not specify how long we should poll |
575 | * for completion nor whether the operation can fail. | | 580 | * for completion nor whether the operation can fail. |
576 | */ | | 581 | */ |
577 | j = 0; | | 582 | j = 0; |
578 | do { | | 583 | do { |
579 | if (j++ == 20) | | 584 | if (j++ == 20) |
580 | return (1); | | 585 | return (1); |
581 | delay(4); | | 586 | delay(4); |
582 | reg = pci_conf_read(pc, tag, ofs); | | 587 | reg = pci_conf_read(pc, tag, ofs); |
583 | } while ((reg & PCI_VPD_OPFLAG) == 0); | | 588 | } while ((reg & PCI_VPD_OPFLAG) == 0); |
584 | data[i] = pci_conf_read(pc, tag, PCI_VPD_DATAREG(ofs)); | | 589 | data[i] = pci_conf_read(pc, tag, PCI_VPD_DATAREG(ofs)); |
585 | } | | 590 | } |
586 | | | 591 | |
587 | return (0); | | 592 | return (0); |
588 | } | | 593 | } |
589 | | | 594 | |
590 | int | | 595 | int |
591 | pci_vpd_write(pci_chipset_tag_t pc, pcitag_t tag, int offset, int count, | | 596 | pci_vpd_write(pci_chipset_tag_t pc, pcitag_t tag, int offset, int count, |
592 | pcireg_t *data) | | 597 | pcireg_t *data) |
593 | { | | 598 | { |
594 | pcireg_t reg; | | 599 | pcireg_t reg; |
595 | int ofs, i, j; | | 600 | int ofs, i, j; |
596 | | | 601 | |
597 | KASSERT(data != NULL); | | 602 | KASSERT(data != NULL); |
598 | KASSERT((offset + count) < 0x7fff); | | 603 | KASSERT((offset + count) < 0x7fff); |
599 | | | 604 | |
600 | if (pci_get_capability(pc, tag, PCI_CAP_VPD, &ofs, ®) == 0) | | 605 | if (pci_get_capability(pc, tag, PCI_CAP_VPD, &ofs, ®) == 0) |
601 | return (1); | | 606 | return (1); |
602 | | | 607 | |
603 | for (i = 0; i < count; offset += sizeof(*data), i++) { | | 608 | for (i = 0; i < count; offset += sizeof(*data), i++) { |
604 | pci_conf_write(pc, tag, PCI_VPD_DATAREG(ofs), data[i]); | | 609 | pci_conf_write(pc, tag, PCI_VPD_DATAREG(ofs), data[i]); |
605 | | | 610 | |
606 | reg &= 0x0000ffff; | | 611 | reg &= 0x0000ffff; |
607 | reg |= PCI_VPD_OPFLAG; | | 612 | reg |= PCI_VPD_OPFLAG; |
608 | reg |= PCI_VPD_ADDRESS(offset); | | 613 | reg |= PCI_VPD_ADDRESS(offset); |
609 | pci_conf_write(pc, tag, ofs, reg); | | 614 | pci_conf_write(pc, tag, ofs, reg); |
610 | | | 615 | |
611 | /* | | 616 | /* |
612 | * PCI 2.2 does not specify how long we should poll | | 617 | * PCI 2.2 does not specify how long we should poll |
613 | * for completion nor whether the operation can fail. | | 618 | * for completion nor whether the operation can fail. |
614 | */ | | 619 | */ |
615 | j = 0; | | 620 | j = 0; |
616 | do { | | 621 | do { |
617 | if (j++ == 20) | | 622 | if (j++ == 20) |
618 | return (1); | | 623 | return (1); |
619 | delay(1); | | 624 | delay(1); |
620 | reg = pci_conf_read(pc, tag, ofs); | | 625 | reg = pci_conf_read(pc, tag, ofs); |
621 | } while (reg & PCI_VPD_OPFLAG); | | 626 | } while (reg & PCI_VPD_OPFLAG); |
622 | } | | 627 | } |
623 | | | 628 | |
624 | return (0); | | 629 | return (0); |
625 | } | | 630 | } |
626 | | | 631 | |
627 | int | | 632 | int |
628 | pci_dma64_available(struct pci_attach_args *pa) | | 633 | pci_dma64_available(struct pci_attach_args *pa) |
629 | { | | 634 | { |
630 | #ifdef _PCI_HAVE_DMA64 | | 635 | #ifdef _PCI_HAVE_DMA64 |
631 | if (BUS_DMA_TAG_VALID(pa->pa_dmat64) && | | 636 | if (BUS_DMA_TAG_VALID(pa->pa_dmat64) && |
632 | ((uint64_t)physmem << PAGE_SHIFT) > 0xffffffffULL) | | 637 | ((uint64_t)physmem << PAGE_SHIFT) > 0xffffffffULL) |
633 | return 1; | | 638 | return 1; |
634 | #endif | | 639 | #endif |
635 | return 0; | | 640 | return 0; |
636 | } | | 641 | } |
637 | | | 642 | |
638 | void | | 643 | void |
639 | pci_conf_capture(pci_chipset_tag_t pc, pcitag_t tag, | | 644 | pci_conf_capture(pci_chipset_tag_t pc, pcitag_t tag, |
640 | struct pci_conf_state *pcs) | | 645 | struct pci_conf_state *pcs) |
641 | { | | 646 | { |
642 | int off; | | 647 | int off; |
643 | | | 648 | |
644 | for (off = 0; off < 16; off++) | | 649 | for (off = 0; off < 16; off++) |
645 | pcs->reg[off] = pci_conf_read(pc, tag, (off * 4)); | | 650 | pcs->reg[off] = pci_conf_read(pc, tag, (off * 4)); |
646 | | | 651 | |
647 | return; | | 652 | return; |
648 | } | | 653 | } |
649 | | | 654 | |
650 | void | | 655 | void |
651 | pci_conf_restore(pci_chipset_tag_t pc, pcitag_t tag, | | 656 | pci_conf_restore(pci_chipset_tag_t pc, pcitag_t tag, |
652 | struct pci_conf_state *pcs) | | 657 | struct pci_conf_state *pcs) |
653 | { | | 658 | { |
654 | int off; | | 659 | int off; |
655 | pcireg_t val; | | 660 | pcireg_t val; |
656 | | | 661 | |
657 | for (off = 15; off >= 0; off--) { | | 662 | for (off = 15; off >= 0; off--) { |
658 | val = pci_conf_read(pc, tag, (off * 4)); | | 663 | val = pci_conf_read(pc, tag, (off * 4)); |
659 | if (val != pcs->reg[off]) | | 664 | if (val != pcs->reg[off]) |
660 | pci_conf_write(pc, tag, (off * 4), pcs->reg[off]); | | 665 | pci_conf_write(pc, tag, (off * 4), pcs->reg[off]); |
661 | } | | 666 | } |
662 | | | 667 | |
663 | return; | | 668 | return; |
664 | } | | 669 | } |
665 | | | 670 | |
666 | /* | | 671 | /* |
667 | * Power Management Capability (Rev 2.2) | | 672 | * Power Management Capability (Rev 2.2) |
668 | */ | | 673 | */ |
669 | static int | | 674 | static int |
670 | pci_get_powerstate_int(pci_chipset_tag_t pc, pcitag_t tag , pcireg_t *state, | | 675 | pci_get_powerstate_int(pci_chipset_tag_t pc, pcitag_t tag , pcireg_t *state, |
671 | int offset) | | 676 | int offset) |
672 | { | | 677 | { |
673 | pcireg_t value, now; | | 678 | pcireg_t value, now; |
674 | | | 679 | |
675 | value = pci_conf_read(pc, tag, offset + PCI_PMCSR); | | 680 | value = pci_conf_read(pc, tag, offset + PCI_PMCSR); |
676 | now = value & PCI_PMCSR_STATE_MASK; | | 681 | now = value & PCI_PMCSR_STATE_MASK; |
677 | switch (now) { | | 682 | switch (now) { |
678 | case PCI_PMCSR_STATE_D0: | | 683 | case PCI_PMCSR_STATE_D0: |
679 | case PCI_PMCSR_STATE_D1: | | 684 | case PCI_PMCSR_STATE_D1: |
680 | case PCI_PMCSR_STATE_D2: | | 685 | case PCI_PMCSR_STATE_D2: |
681 | case PCI_PMCSR_STATE_D3: | | 686 | case PCI_PMCSR_STATE_D3: |
682 | *state = now; | | 687 | *state = now; |
683 | return 0; | | 688 | return 0; |
684 | default: | | 689 | default: |
685 | return EINVAL; | | 690 | return EINVAL; |
686 | } | | 691 | } |
687 | } | | 692 | } |
688 | | | 693 | |
689 | int | | 694 | int |
690 | pci_get_powerstate(pci_chipset_tag_t pc, pcitag_t tag , pcireg_t *state) | | 695 | pci_get_powerstate(pci_chipset_tag_t pc, pcitag_t tag , pcireg_t *state) |
691 | { | | 696 | { |
692 | int offset; | | 697 | int offset; |
693 | pcireg_t value; | | 698 | pcireg_t value; |
694 | | | 699 | |
695 | if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value)) | | 700 | if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value)) |
696 | return EOPNOTSUPP; | | 701 | return EOPNOTSUPP; |
697 | | | 702 | |
698 | return pci_get_powerstate_int(pc, tag, state, offset); | | 703 | return pci_get_powerstate_int(pc, tag, state, offset); |
699 | } | | 704 | } |
700 | | | 705 | |
701 | static int | | 706 | static int |
702 | pci_set_powerstate_int(pci_chipset_tag_t pc, pcitag_t tag, pcireg_t state, | | 707 | pci_set_powerstate_int(pci_chipset_tag_t pc, pcitag_t tag, pcireg_t state, |
703 | int offset, pcireg_t cap_reg) | | 708 | int offset, pcireg_t cap_reg) |
704 | { | | 709 | { |
705 | pcireg_t value, cap, now; | | 710 | pcireg_t value, cap, now; |
706 | | | 711 | |
707 | cap = cap_reg >> PCI_PMCR_SHIFT; | | 712 | cap = cap_reg >> PCI_PMCR_SHIFT; |
708 | value = pci_conf_read(pc, tag, offset + PCI_PMCSR); | | 713 | value = pci_conf_read(pc, tag, offset + PCI_PMCSR); |
709 | now = value & PCI_PMCSR_STATE_MASK; | | 714 | now = value & PCI_PMCSR_STATE_MASK; |
710 | value &= ~PCI_PMCSR_STATE_MASK; | | 715 | value &= ~PCI_PMCSR_STATE_MASK; |
711 | | | 716 | |
712 | if (now == state) | | 717 | if (now == state) |
713 | return 0; | | 718 | return 0; |
714 | switch (state) { | | 719 | switch (state) { |
715 | case PCI_PMCSR_STATE_D0: | | 720 | case PCI_PMCSR_STATE_D0: |
716 | break; | | 721 | break; |
717 | case PCI_PMCSR_STATE_D1: | | 722 | case PCI_PMCSR_STATE_D1: |
718 | if (now == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D3) { | | 723 | if (now == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D3) { |
719 | printf("invalid transition from %d to D1\n", (int)now); | | 724 | printf("invalid transition from %d to D1\n", (int)now); |
720 | return EINVAL; | | 725 | return EINVAL; |
721 | } | | 726 | } |
722 | if (!(cap & PCI_PMCR_D1SUPP)) { | | 727 | if (!(cap & PCI_PMCR_D1SUPP)) { |
723 | printf("D1 not supported\n"); | | 728 | printf("D1 not supported\n"); |
724 | return EOPNOTSUPP; | | 729 | return EOPNOTSUPP; |
725 | } | | 730 | } |
726 | break; | | 731 | break; |
727 | case PCI_PMCSR_STATE_D2: | | 732 | case PCI_PMCSR_STATE_D2: |
728 | if (now == PCI_PMCSR_STATE_D3) { | | 733 | if (now == PCI_PMCSR_STATE_D3) { |
729 | printf("invalid transition from %d to D2\n", (int)now); | | 734 | printf("invalid transition from %d to D2\n", (int)now); |
730 | return EINVAL; | | 735 | return EINVAL; |
731 | } | | 736 | } |
732 | if (!(cap & PCI_PMCR_D2SUPP)) { | | 737 | if (!(cap & PCI_PMCR_D2SUPP)) { |
733 | printf("D2 not supported\n"); | | 738 | printf("D2 not supported\n"); |
734 | return EOPNOTSUPP; | | 739 | return EOPNOTSUPP; |
735 | } | | 740 | } |
736 | break; | | 741 | break; |
737 | case PCI_PMCSR_STATE_D3: | | 742 | case PCI_PMCSR_STATE_D3: |
738 | break; | | 743 | break; |
739 | default: | | 744 | default: |
740 | return EINVAL; | | 745 | return EINVAL; |
741 | } | | 746 | } |
742 | value |= state; | | 747 | value |= state; |
743 | pci_conf_write(pc, tag, offset + PCI_PMCSR, value); | | 748 | pci_conf_write(pc, tag, offset + PCI_PMCSR, value); |
744 | /* delay according to pcipm1.2, ch. 5.6.1 */ | | 749 | /* delay according to pcipm1.2, ch. 5.6.1 */ |
745 | if (state == PCI_PMCSR_STATE_D3 || now == PCI_PMCSR_STATE_D3) | | 750 | if (state == PCI_PMCSR_STATE_D3 || now == PCI_PMCSR_STATE_D3) |
746 | DELAY(10000); | | 751 | DELAY(10000); |
747 | else if (state == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D2) | | 752 | else if (state == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D2) |
748 | DELAY(200); | | 753 | DELAY(200); |
749 | | | 754 | |
750 | return 0; | | 755 | return 0; |
751 | } | | 756 | } |
752 | | | 757 | |
753 | int | | 758 | int |
754 | pci_set_powerstate(pci_chipset_tag_t pc, pcitag_t tag, pcireg_t state) | | 759 | pci_set_powerstate(pci_chipset_tag_t pc, pcitag_t tag, pcireg_t state) |
755 | { | | 760 | { |
756 | int offset; | | 761 | int offset; |
757 | pcireg_t value; | | 762 | pcireg_t value; |
758 | | | 763 | |
759 | if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value)) { | | 764 | if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value)) { |
760 | printf("pci_set_powerstate not supported\n"); | | 765 | printf("pci_set_powerstate not supported\n"); |
761 | return EOPNOTSUPP; | | 766 | return EOPNOTSUPP; |
762 | } | | 767 | } |
763 | | | 768 | |
764 | return pci_set_powerstate_int(pc, tag, state, offset, value); | | 769 | return pci_set_powerstate_int(pc, tag, state, offset, value); |
765 | } | | 770 | } |
766 | | | 771 | |
767 | int | | 772 | int |
768 | pci_activate(pci_chipset_tag_t pc, pcitag_t tag, device_t dev, | | 773 | pci_activate(pci_chipset_tag_t pc, pcitag_t tag, device_t dev, |
769 | int (*wakefun)(pci_chipset_tag_t, pcitag_t, device_t, pcireg_t)) | | 774 | int (*wakefun)(pci_chipset_tag_t, pcitag_t, device_t, pcireg_t)) |
770 | { | | 775 | { |
771 | pcireg_t pmode; | | 776 | pcireg_t pmode; |
772 | int error; | | 777 | int error; |
773 | | | 778 | |
774 | if ((error = pci_get_powerstate(pc, tag, &pmode))) | | 779 | if ((error = pci_get_powerstate(pc, tag, &pmode))) |
775 | return error; | | 780 | return error; |
776 | | | 781 | |
777 | switch (pmode) { | | 782 | switch (pmode) { |
778 | case PCI_PMCSR_STATE_D0: | | 783 | case PCI_PMCSR_STATE_D0: |
779 | break; | | 784 | break; |
780 | case PCI_PMCSR_STATE_D3: | | 785 | case PCI_PMCSR_STATE_D3: |
781 | if (wakefun == NULL) { | | 786 | if (wakefun == NULL) { |
782 | /* | | 787 | /* |
783 | * The card has lost all configuration data in | | 788 | * The card has lost all configuration data in |
784 | * this state, so punt. | | 789 | * this state, so punt. |
785 | */ | | 790 | */ |
786 | aprint_error_dev(dev, | | 791 | aprint_error_dev(dev, |
787 | "unable to wake up from power state D3\n"); | | 792 | "unable to wake up from power state D3\n"); |
788 | return EOPNOTSUPP; | | 793 | return EOPNOTSUPP; |
789 | } | | 794 | } |
790 | /*FALLTHROUGH*/ | | 795 | /*FALLTHROUGH*/ |
791 | default: | | 796 | default: |
792 | if (wakefun) { | | 797 | if (wakefun) { |
793 | error = (*wakefun)(pc, tag, dev, pmode); | | 798 | error = (*wakefun)(pc, tag, dev, pmode); |
794 | if (error) | | 799 | if (error) |
795 | return error; | | 800 | return error; |
796 | } | | 801 | } |
797 | aprint_normal_dev(dev, "waking up from power state D%d\n", | | 802 | aprint_normal_dev(dev, "waking up from power state D%d\n", |
798 | pmode); | | 803 | pmode); |
799 | if ((error = pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0))) | | 804 | if ((error = pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0))) |
800 | return error; | | 805 | return error; |
801 | } | | 806 | } |
802 | return 0; | | 807 | return 0; |
803 | } | | 808 | } |
804 | | | 809 | |
805 | int | | 810 | int |
806 | pci_activate_null(pci_chipset_tag_t pc, pcitag_t tag, | | 811 | pci_activate_null(pci_chipset_tag_t pc, pcitag_t tag, |
807 | device_t dev, pcireg_t state) | | 812 | device_t dev, pcireg_t state) |
808 | { | | 813 | { |
809 | return 0; | | 814 | return 0; |
810 | } | | 815 | } |
811 | | | 816 | |
812 | /* I have disabled this code for now. --dyoung | | 817 | /* I have disabled this code for now. --dyoung |
813 | * | | 818 | * |
814 | * Insofar as I understand what the PCI retry timeout is [1], | | 819 | * Insofar as I understand what the PCI retry timeout is [1], |
815 | * I see no justification for any driver to disable when it | | 820 | * I see no justification for any driver to disable when it |
816 | * attaches/resumes a device. | | 821 | * attaches/resumes a device. |
817 | * | | 822 | * |
818 | * A PCI bus bridge may tell a bus master to retry its transaction | | 823 | * A PCI bus bridge may tell a bus master to retry its transaction |
819 | * at a later time if the resources to complete the transaction | | 824 | * at a later time if the resources to complete the transaction |
820 | * are not immediately available. Taking a guess, PCI bus masters | | 825 | * are not immediately available. Taking a guess, PCI bus masters |
821 | * that implement a PCI retry timeout register count down from the | | 826 | * that implement a PCI retry timeout register count down from the |
822 | * retry timeout to 0 while it retries a delayed PCI transaction. | | 827 | * retry timeout to 0 while it retries a delayed PCI transaction. |
823 | * When it reaches 0, it stops retrying. A PCI master is *never* | | 828 | * When it reaches 0, it stops retrying. A PCI master is *never* |
824 | * supposed to stop retrying a delayed transaction, though. | | 829 | * supposed to stop retrying a delayed transaction, though. |
825 | * | | 830 | * |
826 | * Incidentally, I initially suspected that writing 0 to the register | | 831 | * Incidentally, I initially suspected that writing 0 to the register |
827 | * would not disable *retries*, but would disable the timeout. | | 832 | * would not disable *retries*, but would disable the timeout. |
828 | * That is, any device whose retry timeout was set to 0 would | | 833 | * That is, any device whose retry timeout was set to 0 would |
829 | * *never* timeout. However, I found out, by using PCI debug | | 834 | * *never* timeout. However, I found out, by using PCI debug |
830 | * facilities on the AMD Elan SC520, that if I write 0 to the retry | | 835 | * facilities on the AMD Elan SC520, that if I write 0 to the retry |
831 | * timeout register on an ath(4) MiniPCI card, the card really does | | 836 | * timeout register on an ath(4) MiniPCI card, the card really does |
832 | * not retry transactions. | | 837 | * not retry transactions. |
833 | * | | 838 | * |
834 | * Some uses of this register have mentioned "interference" with | | 839 | * Some uses of this register have mentioned "interference" with |
835 | * a CPU's "C3 sleep state." It seems to me that if a bus master | | 840 | * a CPU's "C3 sleep state." It seems to me that if a bus master |
836 | * is properly put to sleep, it will neither initiate new transactions, | | 841 | * is properly put to sleep, it will neither initiate new transactions, |
837 | * nor retry delayed transactions, so disabling retries should not | | 842 | * nor retry delayed transactions, so disabling retries should not |
838 | * be necessary. | | 843 | * be necessary. |
839 | * | | 844 | * |
840 | * [1] The timeout does not appear to be documented in any PCI | | 845 | * [1] The timeout does not appear to be documented in any PCI |
841 | * standard, and we have no documentation of it for the devices by | | 846 | * standard, and we have no documentation of it for the devices by |
842 | * Atheros, and others, that supposedly implement it. | | 847 | * Atheros, and others, that supposedly implement it. |
843 | */ | | 848 | */ |
844 | void | | 849 | void |
845 | pci_disable_retry(pci_chipset_tag_t pc, pcitag_t tag) | | 850 | pci_disable_retry(pci_chipset_tag_t pc, pcitag_t tag) |
846 | { | | 851 | { |
847 | #if 0 | | 852 | #if 0 |
848 | pcireg_t retry; | | 853 | pcireg_t retry; |
849 | | | 854 | |
850 | /* | | 855 | /* |
851 | * Disable retry timeout to keep PCI Tx retries from | | 856 | * Disable retry timeout to keep PCI Tx retries from |
852 | * interfering with ACPI C3 CPU state. | | 857 | * interfering with ACPI C3 CPU state. |
853 | */ | | 858 | */ |
854 | retry = pci_conf_read(pc, tag, PCI_RETRY_TIMEOUT_REG); | | 859 | retry = pci_conf_read(pc, tag, PCI_RETRY_TIMEOUT_REG); |
855 | retry &= ~PCI_RETRY_TIMEOUT_REG_MASK; | | 860 | retry &= ~PCI_RETRY_TIMEOUT_REG_MASK; |
856 | pci_conf_write(pc, tag, PCI_RETRY_TIMEOUT_REG, retry); | | 861 | pci_conf_write(pc, tag, PCI_RETRY_TIMEOUT_REG, retry); |
857 | #endif | | 862 | #endif |
858 | } | | 863 | } |
859 | | | 864 | |
860 | struct pci_child_power { | | 865 | struct pci_child_power { |
861 | struct pci_conf_state p_pciconf; | | 866 | struct pci_conf_state p_pciconf; |
862 | pci_chipset_tag_t p_pc; | | 867 | pci_chipset_tag_t p_pc; |
863 | pcitag_t p_tag; | | 868 | pcitag_t p_tag; |
864 | bool p_has_pm; | | 869 | bool p_has_pm; |
865 | int p_pm_offset; | | 870 | int p_pm_offset; |
866 | pcireg_t p_pm_cap; | | 871 | pcireg_t p_pm_cap; |
867 | pcireg_t p_class; | | 872 | pcireg_t p_class; |
868 | }; | | 873 | }; |
869 | | | 874 | |
870 | static bool | | 875 | static bool |
871 | pci_child_suspend(device_t dv PMF_FN_ARGS) | | 876 | pci_child_suspend(device_t dv PMF_FN_ARGS) |
872 | { | | 877 | { |
873 | struct pci_child_power *priv = device_pmf_bus_private(dv); | | 878 | struct pci_child_power *priv = device_pmf_bus_private(dv); |
874 | pcireg_t ocsr, csr; | | 879 | pcireg_t ocsr, csr; |
875 | | | 880 | |
876 | pci_conf_capture(priv->p_pc, priv->p_tag, &priv->p_pciconf); | | 881 | pci_conf_capture(priv->p_pc, priv->p_tag, &priv->p_pciconf); |
877 | | | 882 | |
878 | if (!priv->p_has_pm) | | 883 | if (!priv->p_has_pm) |
879 | return true; /* ??? hopefully handled by ACPI */ | | 884 | return true; /* ??? hopefully handled by ACPI */ |
880 | if (PCI_CLASS(priv->p_class) == PCI_CLASS_DISPLAY) | | 885 | if (PCI_CLASS(priv->p_class) == PCI_CLASS_DISPLAY) |
881 | return true; /* XXX */ | | 886 | return true; /* XXX */ |
882 | | | 887 | |
883 | /* disable decoding and busmastering, see pcipm1.2 ch. 8.2.1 */ | | 888 | /* disable decoding and busmastering, see pcipm1.2 ch. 8.2.1 */ |
884 | ocsr = pci_conf_read(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG); | | 889 | ocsr = pci_conf_read(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG); |
885 | csr = ocsr & ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | | 890 | csr = ocsr & ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
886 | | PCI_COMMAND_MASTER_ENABLE); | | 891 | | PCI_COMMAND_MASTER_ENABLE); |
887 | pci_conf_write(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG, csr); | | 892 | pci_conf_write(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG, csr); |
888 | if (pci_set_powerstate_int(priv->p_pc, priv->p_tag, | | 893 | if (pci_set_powerstate_int(priv->p_pc, priv->p_tag, |
889 | PCI_PMCSR_STATE_D3, priv->p_pm_offset, priv->p_pm_cap)) { | | 894 | PCI_PMCSR_STATE_D3, priv->p_pm_offset, priv->p_pm_cap)) { |
890 | pci_conf_write(priv->p_pc, priv->p_tag, | | 895 | pci_conf_write(priv->p_pc, priv->p_tag, |
891 | PCI_COMMAND_STATUS_REG, ocsr); | | 896 | PCI_COMMAND_STATUS_REG, ocsr); |
892 | aprint_error_dev(dv, "unsupported state, continuing.\n"); | | 897 | aprint_error_dev(dv, "unsupported state, continuing.\n"); |
893 | return false; | | 898 | return false; |
894 | } | | 899 | } |
895 | return true; | | 900 | return true; |
896 | } | | 901 | } |
897 | | | 902 | |
898 | static bool | | 903 | static bool |
899 | pci_child_resume(device_t dv PMF_FN_ARGS) | | 904 | pci_child_resume(device_t dv PMF_FN_ARGS) |
900 | { | | 905 | { |
901 | struct pci_child_power *priv = device_pmf_bus_private(dv); | | 906 | struct pci_child_power *priv = device_pmf_bus_private(dv); |
902 | | | 907 | |
903 | if (priv->p_has_pm && | | 908 | if (priv->p_has_pm && |
904 | pci_set_powerstate_int(priv->p_pc, priv->p_tag, | | 909 | pci_set_powerstate_int(priv->p_pc, priv->p_tag, |
905 | PCI_PMCSR_STATE_D0, priv->p_pm_offset, priv->p_pm_cap)) { | | 910 | PCI_PMCSR_STATE_D0, priv->p_pm_offset, priv->p_pm_cap)) { |
906 | aprint_error_dev(dv, "unsupported state, continuing.\n"); | | 911 | aprint_error_dev(dv, "unsupported state, continuing.\n"); |
907 | return false; | | 912 | return false; |
908 | } | | 913 | } |
909 | | | 914 | |
910 | pci_conf_restore(priv->p_pc, priv->p_tag, &priv->p_pciconf); | | 915 | pci_conf_restore(priv->p_pc, priv->p_tag, &priv->p_pciconf); |
911 | | | 916 | |
912 | return true; | | 917 | return true; |
913 | } | | 918 | } |
914 | | | 919 | |
915 | static bool | | 920 | static bool |
916 | pci_child_shutdown(device_t dv, int how) | | 921 | pci_child_shutdown(device_t dv, int how) |
917 | { | | 922 | { |
918 | struct pci_child_power *priv = device_pmf_bus_private(dv); | | 923 | struct pci_child_power *priv = device_pmf_bus_private(dv); |
919 | pcireg_t csr; | | 924 | pcireg_t csr; |
920 | | | 925 | |
921 | /* disable busmastering */ | | 926 | /* disable busmastering */ |
922 | csr = pci_conf_read(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG); | | 927 | csr = pci_conf_read(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG); |
923 | csr &= ~PCI_COMMAND_MASTER_ENABLE; | | 928 | csr &= ~PCI_COMMAND_MASTER_ENABLE; |
924 | pci_conf_write(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG, csr); | | 929 | pci_conf_write(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG, csr); |
925 | return true; | | 930 | return true; |
926 | } | | 931 | } |
927 | | | 932 | |
928 | static void | | 933 | static void |
929 | pci_child_deregister(device_t dv) | | 934 | pci_child_deregister(device_t dv) |
930 | { | | 935 | { |
931 | struct pci_child_power *priv = device_pmf_bus_private(dv); | | 936 | struct pci_child_power *priv = device_pmf_bus_private(dv); |
932 | | | 937 | |
933 | free(priv, M_DEVBUF); | | 938 | free(priv, M_DEVBUF); |
934 | } | | 939 | } |
935 | | | 940 | |
936 | static bool | | 941 | static bool |
937 | pci_child_register(device_t child) | | 942 | pci_child_register(device_t child) |
938 | { | | 943 | { |
939 | device_t self = device_parent(child); | | 944 | device_t self = device_parent(child); |
940 | struct pci_softc *sc = device_private(self); | | 945 | struct pci_softc *sc = device_private(self); |
941 | struct pci_child_power *priv; | | 946 | struct pci_child_power *priv; |
942 | int device, function, off; | | 947 | int device, function, off; |
943 | pcireg_t reg; | | 948 | pcireg_t reg; |
944 | | | 949 | |
945 | priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK); | | 950 | priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK); |
946 | | | 951 | |
947 | device = device_locator(child, PCICF_DEV); | | 952 | device = device_locator(child, PCICF_DEV); |
948 | function = device_locator(child, PCICF_FUNCTION); | | 953 | function = device_locator(child, PCICF_FUNCTION); |
949 | | | 954 | |
950 | priv->p_pc = sc->sc_pc; | | 955 | priv->p_pc = sc->sc_pc; |
951 | priv->p_tag = pci_make_tag(priv->p_pc, sc->sc_bus, device, | | 956 | priv->p_tag = pci_make_tag(priv->p_pc, sc->sc_bus, device, |
952 | function); | | 957 | function); |
953 | priv->p_class = pci_conf_read(priv->p_pc, priv->p_tag, PCI_CLASS_REG); | | 958 | priv->p_class = pci_conf_read(priv->p_pc, priv->p_tag, PCI_CLASS_REG); |
954 | | | 959 | |
955 | if (pci_get_capability(priv->p_pc, priv->p_tag, | | 960 | if (pci_get_capability(priv->p_pc, priv->p_tag, |
956 | PCI_CAP_PWRMGMT, &off, ®)) { | | 961 | PCI_CAP_PWRMGMT, &off, ®)) { |
957 | priv->p_has_pm = true; | | 962 | priv->p_has_pm = true; |
958 | priv->p_pm_offset = off; | | 963 | priv->p_pm_offset = off; |
959 | priv->p_pm_cap = reg; | | 964 | priv->p_pm_cap = reg; |
960 | } else { | | 965 | } else { |
961 | priv->p_has_pm = false; | | 966 | priv->p_has_pm = false; |
962 | priv->p_pm_offset = -1; | | 967 | priv->p_pm_offset = -1; |
963 | } | | 968 | } |
964 | | | 969 | |
965 | device_pmf_bus_register(child, priv, pci_child_suspend, | | 970 | device_pmf_bus_register(child, priv, pci_child_suspend, |
966 | pci_child_resume, pci_child_shutdown, pci_child_deregister); | | 971 | pci_child_resume, pci_child_shutdown, pci_child_deregister); |
967 | | | 972 | |
968 | return true; | | 973 | return true; |
969 | } | | 974 | } |