| @@ -1,1145 +1,1149 @@ | | | @@ -1,1145 +1,1149 @@ |
1 | /* $NetBSD: pci.c,v 1.150 2015/11/02 09:29:08 knakahara Exp $ */ | | 1 | /* $NetBSD: pci.c,v 1.151 2016/01/23 17:09:51 macallan 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.150 2015/11/02 09:29:08 knakahara Exp $"); | | 39 | __KERNEL_RCSID(0, "$NetBSD: pci.c,v 1.151 2016/01/23 17:09:51 macallan Exp $"); |
40 | | | 40 | |
41 | #ifdef _KERNEL_OPT | | 41 | #ifdef _KERNEL_OPT |
42 | #include "opt_pci.h" | | 42 | #include "opt_pci.h" |
43 | #endif | | 43 | #endif |
44 | | | 44 | |
45 | #include <sys/param.h> | | 45 | #include <sys/param.h> |
46 | #include <sys/malloc.h> | | 46 | #include <sys/malloc.h> |
47 | #include <sys/systm.h> | | 47 | #include <sys/systm.h> |
48 | #include <sys/device.h> | | 48 | #include <sys/device.h> |
49 | #include <sys/module.h> | | 49 | #include <sys/module.h> |
50 | | | 50 | |
51 | #include <dev/pci/pcireg.h> | | 51 | #include <dev/pci/pcireg.h> |
52 | #include <dev/pci/pcivar.h> | | 52 | #include <dev/pci/pcivar.h> |
53 | #include <dev/pci/pcidevs.h> | | 53 | #include <dev/pci/pcidevs.h> |
54 | | | 54 | |
55 | #include <net/if.h> | | 55 | #include <net/if.h> |
56 | | | 56 | |
57 | #include "locators.h" | | 57 | #include "locators.h" |
58 | | | 58 | |
59 | static bool pci_child_register(device_t); | | 59 | static bool pci_child_register(device_t); |
60 | | | 60 | |
61 | #ifdef PCI_CONFIG_DUMP | | 61 | #ifdef PCI_CONFIG_DUMP |
62 | int pci_config_dump = 1; | | 62 | int pci_config_dump = 1; |
63 | #else | | 63 | #else |
64 | int pci_config_dump = 0; | | 64 | int pci_config_dump = 0; |
65 | #endif | | 65 | #endif |
66 | | | 66 | |
67 | int pciprint(void *, const char *); | | 67 | int pciprint(void *, const char *); |
68 | | | 68 | |
69 | #ifdef PCI_MACHDEP_ENUMERATE_BUS | | 69 | #ifdef PCI_MACHDEP_ENUMERATE_BUS |
70 | #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS | | 70 | #define pci_enumerate_bus PCI_MACHDEP_ENUMERATE_BUS |
71 | #endif | | 71 | #endif |
72 | | | 72 | |
73 | /* | | 73 | /* |
74 | * Important note about PCI-ISA bridges: | | 74 | * Important note about PCI-ISA bridges: |
75 | * | | 75 | * |
76 | * Callbacks are used to configure these devices so that ISA/EISA bridges | | 76 | * Callbacks are used to configure these devices so that ISA/EISA bridges |
77 | * can attach their child busses after PCI configuration is done. | | 77 | * can attach their child busses after PCI configuration is done. |
78 | * | | 78 | * |
79 | * This works because: | | 79 | * This works because: |
80 | * (1) there can be at most one ISA/EISA bridge per PCI bus, and | | 80 | * (1) there can be at most one ISA/EISA bridge per PCI bus, and |
81 | * (2) any ISA/EISA bridges must be attached to primary PCI | | 81 | * (2) any ISA/EISA bridges must be attached to primary PCI |
82 | * busses (i.e. bus zero). | | 82 | * busses (i.e. bus zero). |
83 | * | | 83 | * |
84 | * That boils down to: there can only be one of these outstanding | | 84 | * That boils down to: there can only be one of these outstanding |
85 | * at a time, it is cleared when configuring PCI bus 0 before any | | 85 | * at a time, it is cleared when configuring PCI bus 0 before any |
86 | * subdevices have been found, and it is run after all subdevices | | 86 | * subdevices have been found, and it is run after all subdevices |
87 | * of PCI bus 0 have been found. | | 87 | * of PCI bus 0 have been found. |
88 | * | | 88 | * |
89 | * This is needed because there are some (legacy) PCI devices which | | 89 | * This is needed because there are some (legacy) PCI devices which |
90 | * can show up as ISA/EISA devices as well (the prime example of which | | 90 | * can show up as ISA/EISA devices as well (the prime example of which |
91 | * are VGA controllers). If you attach ISA from a PCI-ISA/EISA bridge, | | 91 | * are VGA controllers). If you attach ISA from a PCI-ISA/EISA bridge, |
92 | * and the bridge is seen before the video board is, the board can show | | 92 | * and the bridge is seen before the video board is, the board can show |
93 | * up as an ISA device, and that can (bogusly) complicate the PCI device's | | 93 | * up as an ISA device, and that can (bogusly) complicate the PCI device's |
94 | * attach code, or make the PCI device not be properly attached at all. | | 94 | * attach code, or make the PCI device not be properly attached at all. |
95 | * | | 95 | * |
96 | * We use the generic config_defer() facility to achieve this. | | 96 | * We use the generic config_defer() facility to achieve this. |
97 | */ | | 97 | */ |
98 | | | 98 | |
99 | int | | 99 | int |
100 | pcirescan(device_t self, const char *ifattr, const int *locators) | | 100 | pcirescan(device_t self, const char *ifattr, const int *locators) |
101 | { | | 101 | { |
102 | struct pci_softc *sc = device_private(self); | | 102 | struct pci_softc *sc = device_private(self); |
103 | | | 103 | |
104 | KASSERT(ifattr && !strcmp(ifattr, "pci")); | | 104 | KASSERT(ifattr && !strcmp(ifattr, "pci")); |
105 | KASSERT(locators); | | 105 | KASSERT(locators); |
106 | | | 106 | |
107 | pci_enumerate_bus(sc, locators, NULL, NULL); | | 107 | pci_enumerate_bus(sc, locators, NULL, NULL); |
108 | | | 108 | |
109 | return 0; | | 109 | return 0; |
110 | } | | 110 | } |
111 | | | 111 | |
112 | int | | 112 | int |
113 | pcimatch(device_t parent, cfdata_t cf, void *aux) | | 113 | pcimatch(device_t parent, cfdata_t cf, void *aux) |
114 | { | | 114 | { |
115 | struct pcibus_attach_args *pba = aux; | | 115 | struct pcibus_attach_args *pba = aux; |
116 | | | 116 | |
117 | /* Check the locators */ | | 117 | /* Check the locators */ |
118 | if (cf->cf_loc[PCIBUSCF_BUS] != PCIBUSCF_BUS_DEFAULT && | | 118 | if (cf->cf_loc[PCIBUSCF_BUS] != PCIBUSCF_BUS_DEFAULT && |
119 | cf->cf_loc[PCIBUSCF_BUS] != pba->pba_bus) | | 119 | cf->cf_loc[PCIBUSCF_BUS] != pba->pba_bus) |
120 | return 0; | | 120 | return 0; |
121 | | | 121 | |
122 | /* sanity */ | | 122 | /* sanity */ |
123 | if (pba->pba_bus < 0 || pba->pba_bus > 255) | | 123 | if (pba->pba_bus < 0 || pba->pba_bus > 255) |
124 | return 0; | | 124 | return 0; |
125 | | | 125 | |
126 | /* | | 126 | /* |
127 | * XXX check other (hardware?) indicators | | 127 | * XXX check other (hardware?) indicators |
128 | */ | | 128 | */ |
129 | | | 129 | |
130 | return 1; | | 130 | return 1; |
131 | } | | 131 | } |
132 | | | 132 | |
133 | void | | 133 | void |
134 | pciattach(device_t parent, device_t self, void *aux) | | 134 | pciattach(device_t parent, device_t self, void *aux) |
135 | { | | 135 | { |
136 | struct pcibus_attach_args *pba = aux; | | 136 | struct pcibus_attach_args *pba = aux; |
137 | struct pci_softc *sc = device_private(self); | | 137 | struct pci_softc *sc = device_private(self); |
138 | int io_enabled, mem_enabled, mrl_enabled, mrm_enabled, mwi_enabled; | | 138 | int io_enabled, mem_enabled, mrl_enabled, mrm_enabled, mwi_enabled; |
139 | const char *sep = ""; | | 139 | const char *sep = ""; |
140 | static const int wildcard[PCICF_NLOCS] = { | | 140 | static const int wildcard[PCICF_NLOCS] = { |
141 | PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT | | 141 | PCICF_DEV_DEFAULT, PCICF_FUNCTION_DEFAULT |
142 | }; | | 142 | }; |
143 | | | 143 | |
144 | sc->sc_dev = self; | | 144 | sc->sc_dev = self; |
145 | | | 145 | |
146 | pci_attach_hook(parent, self, pba); | | 146 | pci_attach_hook(parent, self, pba); |
147 | | | 147 | |
148 | aprint_naive("\n"); | | 148 | aprint_naive("\n"); |
149 | aprint_normal("\n"); | | 149 | aprint_normal("\n"); |
150 | | | 150 | |
151 | io_enabled = (pba->pba_flags & PCI_FLAGS_IO_OKAY); | | 151 | io_enabled = (pba->pba_flags & PCI_FLAGS_IO_OKAY); |
152 | mem_enabled = (pba->pba_flags & PCI_FLAGS_MEM_OKAY); | | 152 | mem_enabled = (pba->pba_flags & PCI_FLAGS_MEM_OKAY); |
153 | mrl_enabled = (pba->pba_flags & PCI_FLAGS_MRL_OKAY); | | 153 | mrl_enabled = (pba->pba_flags & PCI_FLAGS_MRL_OKAY); |
154 | mrm_enabled = (pba->pba_flags & PCI_FLAGS_MRM_OKAY); | | 154 | mrm_enabled = (pba->pba_flags & PCI_FLAGS_MRM_OKAY); |
155 | mwi_enabled = (pba->pba_flags & PCI_FLAGS_MWI_OKAY); | | 155 | mwi_enabled = (pba->pba_flags & PCI_FLAGS_MWI_OKAY); |
156 | | | 156 | |
157 | if (io_enabled == 0 && mem_enabled == 0) { | | 157 | if (io_enabled == 0 && mem_enabled == 0) { |
158 | aprint_error_dev(self, "no spaces enabled!\n"); | | 158 | aprint_error_dev(self, "no spaces enabled!\n"); |
159 | goto fail; | | 159 | goto fail; |
160 | } | | 160 | } |
161 | | | 161 | |
162 | #define PRINT(str) \ | | 162 | #define PRINT(str) \ |
163 | do { \ | | 163 | do { \ |
164 | aprint_verbose("%s%s", sep, str); \ | | 164 | aprint_verbose("%s%s", sep, str); \ |
165 | sep = ", "; \ | | 165 | sep = ", "; \ |
166 | } while (/*CONSTCOND*/0) | | 166 | } while (/*CONSTCOND*/0) |
167 | | | 167 | |
168 | aprint_verbose_dev(self, ""); | | 168 | aprint_verbose_dev(self, ""); |
169 | | | 169 | |
170 | if (io_enabled) | | 170 | if (io_enabled) |
171 | PRINT("i/o space"); | | 171 | PRINT("i/o space"); |
172 | if (mem_enabled) | | 172 | if (mem_enabled) |
173 | PRINT("memory space"); | | 173 | PRINT("memory space"); |
174 | aprint_verbose(" enabled"); | | 174 | aprint_verbose(" enabled"); |
175 | | | 175 | |
176 | if (mrl_enabled || mrm_enabled || mwi_enabled) { | | 176 | if (mrl_enabled || mrm_enabled || mwi_enabled) { |
177 | if (mrl_enabled) | | 177 | if (mrl_enabled) |
178 | PRINT("rd/line"); | | 178 | PRINT("rd/line"); |
179 | if (mrm_enabled) | | 179 | if (mrm_enabled) |
180 | PRINT("rd/mult"); | | 180 | PRINT("rd/mult"); |
181 | if (mwi_enabled) | | 181 | if (mwi_enabled) |
182 | PRINT("wr/inv"); | | 182 | PRINT("wr/inv"); |
183 | aprint_verbose(" ok"); | | 183 | aprint_verbose(" ok"); |
184 | } | | 184 | } |
185 | | | 185 | |
186 | aprint_verbose("\n"); | | 186 | aprint_verbose("\n"); |
187 | | | 187 | |
188 | #undef PRINT | | 188 | #undef PRINT |
189 | | | 189 | |
190 | sc->sc_iot = pba->pba_iot; | | 190 | sc->sc_iot = pba->pba_iot; |
191 | sc->sc_memt = pba->pba_memt; | | 191 | sc->sc_memt = pba->pba_memt; |
192 | sc->sc_dmat = pba->pba_dmat; | | 192 | sc->sc_dmat = pba->pba_dmat; |
193 | sc->sc_dmat64 = pba->pba_dmat64; | | 193 | sc->sc_dmat64 = pba->pba_dmat64; |
194 | sc->sc_pc = pba->pba_pc; | | 194 | sc->sc_pc = pba->pba_pc; |
195 | sc->sc_bus = pba->pba_bus; | | 195 | sc->sc_bus = pba->pba_bus; |
196 | sc->sc_bridgetag = pba->pba_bridgetag; | | 196 | sc->sc_bridgetag = pba->pba_bridgetag; |
197 | sc->sc_maxndevs = pci_bus_maxdevs(pba->pba_pc, pba->pba_bus); | | 197 | sc->sc_maxndevs = pci_bus_maxdevs(pba->pba_pc, pba->pba_bus); |
198 | sc->sc_intrswiz = pba->pba_intrswiz; | | 198 | sc->sc_intrswiz = pba->pba_intrswiz; |
199 | sc->sc_intrtag = pba->pba_intrtag; | | 199 | sc->sc_intrtag = pba->pba_intrtag; |
200 | sc->sc_flags = pba->pba_flags; | | 200 | sc->sc_flags = pba->pba_flags; |
201 | | | 201 | |
202 | device_pmf_driver_set_child_register(sc->sc_dev, pci_child_register); | | 202 | device_pmf_driver_set_child_register(sc->sc_dev, pci_child_register); |
203 | | | 203 | |
204 | pcirescan(sc->sc_dev, "pci", wildcard); | | 204 | pcirescan(sc->sc_dev, "pci", wildcard); |
205 | | | 205 | |
206 | fail: | | 206 | fail: |
207 | if (!pmf_device_register(self, NULL, NULL)) | | 207 | if (!pmf_device_register(self, NULL, NULL)) |
208 | aprint_error_dev(self, "couldn't establish power handler\n"); | | 208 | aprint_error_dev(self, "couldn't establish power handler\n"); |
209 | } | | 209 | } |
210 | | | 210 | |
211 | int | | 211 | int |
212 | pcidetach(device_t self, int flags) | | 212 | pcidetach(device_t self, int flags) |
213 | { | | 213 | { |
214 | int rc; | | 214 | int rc; |
215 | | | 215 | |
216 | if ((rc = config_detach_children(self, flags)) != 0) | | 216 | if ((rc = config_detach_children(self, flags)) != 0) |
217 | return rc; | | 217 | return rc; |
218 | pmf_device_deregister(self); | | 218 | pmf_device_deregister(self); |
219 | return 0; | | 219 | return 0; |
220 | } | | 220 | } |
221 | | | 221 | |
222 | int | | 222 | int |
223 | pciprint(void *aux, const char *pnp) | | 223 | pciprint(void *aux, const char *pnp) |
224 | { | | 224 | { |
225 | struct pci_attach_args *pa = aux; | | 225 | struct pci_attach_args *pa = aux; |
226 | char devinfo[256]; | | 226 | char devinfo[256]; |
227 | const struct pci_quirkdata *qd; | | 227 | const struct pci_quirkdata *qd; |
228 | | | 228 | |
229 | if (pnp) { | | 229 | if (pnp) { |
230 | pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); | | 230 | pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); |
231 | aprint_normal("%s at %s", devinfo, pnp); | | 231 | aprint_normal("%s at %s", devinfo, pnp); |
232 | } | | 232 | } |
233 | aprint_normal(" dev %d function %d", pa->pa_device, pa->pa_function); | | 233 | aprint_normal(" dev %d function %d", pa->pa_device, pa->pa_function); |
234 | if (pci_config_dump) { | | 234 | if (pci_config_dump) { |
235 | printf(": "); | | 235 | printf(": "); |
236 | pci_conf_print(pa->pa_pc, pa->pa_tag, NULL); | | 236 | pci_conf_print(pa->pa_pc, pa->pa_tag, NULL); |
237 | if (!pnp) | | 237 | if (!pnp) |
238 | pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); | | 238 | pci_devinfo(pa->pa_id, pa->pa_class, 1, devinfo, sizeof(devinfo)); |
239 | printf("%s at %s", devinfo, pnp ? pnp : "?"); | | 239 | printf("%s at %s", devinfo, pnp ? pnp : "?"); |
240 | printf(" dev %d function %d (", pa->pa_device, pa->pa_function); | | 240 | printf(" dev %d function %d (", pa->pa_device, pa->pa_function); |
241 | #ifdef __i386__ | | 241 | #ifdef __i386__ |
242 | printf("tag %#lx, intrtag %#lx, intrswiz %#lx, intrpin %#lx", | | 242 | printf("tag %#lx, intrtag %#lx, intrswiz %#lx, intrpin %#lx", |
243 | *(long *)&pa->pa_tag, *(long *)&pa->pa_intrtag, | | 243 | *(long *)&pa->pa_tag, *(long *)&pa->pa_intrtag, |
244 | (long)pa->pa_intrswiz, (long)pa->pa_intrpin); | | 244 | (long)pa->pa_intrswiz, (long)pa->pa_intrpin); |
245 | #else | | 245 | #else |
246 | printf("intrswiz %#lx, intrpin %#lx", | | 246 | printf("intrswiz %#lx, intrpin %#lx", |
247 | (long)pa->pa_intrswiz, (long)pa->pa_intrpin); | | 247 | (long)pa->pa_intrswiz, (long)pa->pa_intrpin); |
248 | #endif | | 248 | #endif |
249 | printf(", i/o %s, mem %s,", | | 249 | printf(", i/o %s, mem %s,", |
250 | pa->pa_flags & PCI_FLAGS_IO_OKAY ? "on" : "off", | | 250 | pa->pa_flags & PCI_FLAGS_IO_OKAY ? "on" : "off", |
251 | pa->pa_flags & PCI_FLAGS_MEM_OKAY ? "on" : "off"); | | 251 | pa->pa_flags & PCI_FLAGS_MEM_OKAY ? "on" : "off"); |
252 | qd = pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id), | | 252 | qd = pci_lookup_quirkdata(PCI_VENDOR(pa->pa_id), |
253 | PCI_PRODUCT(pa->pa_id)); | | 253 | PCI_PRODUCT(pa->pa_id)); |
254 | if (qd == NULL) { | | 254 | if (qd == NULL) { |
255 | printf(" no quirks"); | | 255 | printf(" no quirks"); |
256 | } else { | | 256 | } else { |
257 | snprintb(devinfo, sizeof (devinfo), | | 257 | snprintb(devinfo, sizeof (devinfo), |
258 | "\002\001multifn\002singlefn\003skipfunc0" | | 258 | "\002\001multifn\002singlefn\003skipfunc0" |
259 | "\004skipfunc1\005skipfunc2\006skipfunc3" | | 259 | "\004skipfunc1\005skipfunc2\006skipfunc3" |
260 | "\007skipfunc4\010skipfunc5\011skipfunc6" | | 260 | "\007skipfunc4\010skipfunc5\011skipfunc6" |
261 | "\012skipfunc7", qd->quirks); | | 261 | "\012skipfunc7", qd->quirks); |
262 | printf(" quirks %s", devinfo); | | 262 | printf(" quirks %s", devinfo); |
263 | } | | 263 | } |
264 | printf(")"); | | 264 | printf(")"); |
265 | } | | 265 | } |
266 | return UNCONF; | | 266 | return UNCONF; |
267 | } | | 267 | } |
268 | | | 268 | |
269 | int | | 269 | int |
270 | pci_probe_device(struct pci_softc *sc, pcitag_t tag, | | 270 | pci_probe_device(struct pci_softc *sc, pcitag_t tag, |
271 | int (*match)(const struct pci_attach_args *), | | 271 | int (*match)(const struct pci_attach_args *), |
272 | struct pci_attach_args *pap) | | 272 | struct pci_attach_args *pap) |
273 | { | | 273 | { |
274 | pci_chipset_tag_t pc = sc->sc_pc; | | 274 | pci_chipset_tag_t pc = sc->sc_pc; |
275 | struct pci_attach_args pa; | | 275 | struct pci_attach_args pa; |
276 | pcireg_t id, /* csr, */ pciclass, intr, bhlcr, bar, endbar; | | 276 | pcireg_t id, /* csr, */ pciclass, intr, bhlcr, bar, endbar; |
277 | #ifdef __HAVE_PCI_MSI_MSIX | | 277 | #ifdef __HAVE_PCI_MSI_MSIX |
278 | pcireg_t cap; | | 278 | pcireg_t cap; |
279 | int off; | | 279 | int off; |
280 | #endif | | 280 | #endif |
281 | int ret, pin, bus, device, function, i, width; | | 281 | int ret, pin, bus, device, function, i, width; |
282 | int locs[PCICF_NLOCS]; | | 282 | int locs[PCICF_NLOCS]; |
283 | | | 283 | |
284 | pci_decompose_tag(pc, tag, &bus, &device, &function); | | 284 | pci_decompose_tag(pc, tag, &bus, &device, &function); |
285 | | | 285 | |
286 | /* a driver already attached? */ | | 286 | /* a driver already attached? */ |
287 | if (sc->PCI_SC_DEVICESC(device, function).c_dev != NULL && !match) | | 287 | if (sc->PCI_SC_DEVICESC(device, function).c_dev != NULL && !match) |
288 | return 0; | | 288 | return 0; |
289 | | | 289 | |
290 | bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); | | 290 | bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); |
291 | if (PCI_HDRTYPE_TYPE(bhlcr) > 2) | | 291 | if (PCI_HDRTYPE_TYPE(bhlcr) > 2) |
292 | return 0; | | 292 | return 0; |
293 | | | 293 | |
294 | id = pci_conf_read(pc, tag, PCI_ID_REG); | | 294 | id = pci_conf_read(pc, tag, PCI_ID_REG); |
295 | /* csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); */ | | 295 | /* csr = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); */ |
296 | pciclass = pci_conf_read(pc, tag, PCI_CLASS_REG); | | 296 | pciclass = pci_conf_read(pc, tag, PCI_CLASS_REG); |
297 | | | 297 | |
298 | /* Invalid vendor ID value? */ | | 298 | /* Invalid vendor ID value? */ |
299 | if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) | | 299 | if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) |
300 | return 0; | | 300 | return 0; |
301 | /* XXX Not invalid, but we've done this ~forever. */ | | 301 | /* XXX Not invalid, but we've done this ~forever. */ |
302 | if (PCI_VENDOR(id) == 0) | | 302 | if (PCI_VENDOR(id) == 0) |
303 | return 0; | | 303 | return 0; |
304 | | | 304 | |
305 | /* Collect memory range info */ | | 305 | /* Collect memory range info */ |
306 | memset(sc->PCI_SC_DEVICESC(device, function).c_range, 0, | | 306 | memset(sc->PCI_SC_DEVICESC(device, function).c_range, 0, |
307 | sizeof(sc->PCI_SC_DEVICESC(device, function).c_range)); | | 307 | sizeof(sc->PCI_SC_DEVICESC(device, function).c_range)); |
308 | i = 0; | | 308 | i = 0; |
309 | switch (PCI_HDRTYPE_TYPE(bhlcr)) { | | 309 | switch (PCI_HDRTYPE_TYPE(bhlcr)) { |
310 | case PCI_HDRTYPE_PPB: | | 310 | case PCI_HDRTYPE_PPB: |
311 | endbar = PCI_MAPREG_PPB_END; | | 311 | endbar = PCI_MAPREG_PPB_END; |
312 | break; | | 312 | break; |
313 | case PCI_HDRTYPE_PCB: | | 313 | case PCI_HDRTYPE_PCB: |
314 | endbar = PCI_MAPREG_PCB_END; | | 314 | endbar = PCI_MAPREG_PCB_END; |
315 | break; | | 315 | break; |
316 | default: | | 316 | default: |
317 | endbar = PCI_MAPREG_END; | | 317 | endbar = PCI_MAPREG_END; |
318 | break; | | 318 | break; |
319 | } | | 319 | } |
320 | for (bar = PCI_MAPREG_START; bar < endbar; bar += width) { | | 320 | for (bar = PCI_MAPREG_START; bar < endbar; bar += width) { |
321 | struct pci_range *r; | | 321 | struct pci_range *r; |
322 | pcireg_t type; | | 322 | pcireg_t type; |
323 | | | 323 | |
324 | width = 4; | | 324 | width = 4; |
325 | if (pci_mapreg_probe(pc, tag, bar, &type) == 0) | | 325 | if (pci_mapreg_probe(pc, tag, bar, &type) == 0) |
326 | continue; | | 326 | continue; |
327 | | | 327 | |
328 | if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) { | | 328 | if (PCI_MAPREG_TYPE(type) == PCI_MAPREG_TYPE_MEM) { |
329 | if (PCI_MAPREG_MEM_TYPE(type) == | | 329 | if (PCI_MAPREG_MEM_TYPE(type) == |
330 | PCI_MAPREG_MEM_TYPE_64BIT) | | 330 | PCI_MAPREG_MEM_TYPE_64BIT) |
331 | width = 8; | | 331 | width = 8; |
332 | | | 332 | |
333 | r = &sc->PCI_SC_DEVICESC(device, function).c_range[i++]; | | 333 | r = &sc->PCI_SC_DEVICESC(device, function).c_range[i++]; |
334 | if (pci_mapreg_info(pc, tag, bar, type, | | 334 | if (pci_mapreg_info(pc, tag, bar, type, |
335 | &r->r_offset, &r->r_size, &r->r_flags) != 0) | | 335 | &r->r_offset, &r->r_size, &r->r_flags) != 0) |
336 | break; | | 336 | break; |
337 | if ((PCI_VENDOR(id) == PCI_VENDOR_ATI) && (bar == 0x10) | | 337 | if ((PCI_VENDOR(id) == PCI_VENDOR_ATI) && (bar == 0x10) |
338 | && (r->r_size == 0x1000000)) { | | 338 | && (r->r_size == 0x1000000)) { |
339 | struct pci_range *nr; | | 339 | struct pci_range *nr; |
340 | /* | | 340 | /* |
341 | * this has to be a mach64 | | 341 | * this has to be a mach64 |
342 | * split things up so each half-aperture can | | 342 | * split things up so each half-aperture can |
343 | * be mapped PREFETCHABLE except the last page | | 343 | * be mapped PREFETCHABLE except the last page |
344 | * which may contain registers | | 344 | * which may contain registers |
345 | */ | | 345 | */ |
346 | r->r_size = 0x7ff000; | | 346 | r->r_size = 0x7ff000; |
347 | r->r_flags = BUS_SPACE_MAP_LINEAR | | | 347 | r->r_flags = BUS_SPACE_MAP_LINEAR | |
348 | BUS_SPACE_MAP_PREFETCHABLE; | | 348 | BUS_SPACE_MAP_PREFETCHABLE; |
349 | nr = &sc->PCI_SC_DEVICESC(device, | | 349 | nr = &sc->PCI_SC_DEVICESC(device, |
350 | function).c_range[i++]; | | 350 | function).c_range[i++]; |
351 | nr->r_offset = r->r_offset + 0x800000; | | 351 | nr->r_offset = r->r_offset + 0x800000; |
352 | nr->r_size = 0x7ff000; | | 352 | nr->r_size = 0x7ff000; |
353 | nr->r_flags = BUS_SPACE_MAP_LINEAR | | | 353 | nr->r_flags = BUS_SPACE_MAP_LINEAR | |
354 | BUS_SPACE_MAP_PREFETCHABLE; | | 354 | BUS_SPACE_MAP_PREFETCHABLE; |
| | | 355 | } else if ((PCI_VENDOR(id) == PCI_VENDOR_SILMOTION) && |
| | | 356 | (PCI_PRODUCT(id) == PCI_PRODUCT_SILMOTION_SM502) && |
| | | 357 | (bar == 0x10)) { |
| | | 358 | r->r_flags = BUS_SPACE_MAP_LINEAR | |
| | | 359 | BUS_SPACE_MAP_PREFETCHABLE; |
355 | } | | 360 | } |
356 | | | | |
357 | } | | 361 | } |
358 | } | | 362 | } |
359 | | | 363 | |
360 | pa.pa_iot = sc->sc_iot; | | 364 | pa.pa_iot = sc->sc_iot; |
361 | pa.pa_memt = sc->sc_memt; | | 365 | pa.pa_memt = sc->sc_memt; |
362 | pa.pa_dmat = sc->sc_dmat; | | 366 | pa.pa_dmat = sc->sc_dmat; |
363 | pa.pa_dmat64 = sc->sc_dmat64; | | 367 | pa.pa_dmat64 = sc->sc_dmat64; |
364 | pa.pa_pc = pc; | | 368 | pa.pa_pc = pc; |
365 | pa.pa_bus = bus; | | 369 | pa.pa_bus = bus; |
366 | pa.pa_device = device; | | 370 | pa.pa_device = device; |
367 | pa.pa_function = function; | | 371 | pa.pa_function = function; |
368 | pa.pa_tag = tag; | | 372 | pa.pa_tag = tag; |
369 | pa.pa_id = id; | | 373 | pa.pa_id = id; |
370 | pa.pa_class = pciclass; | | 374 | pa.pa_class = pciclass; |
371 | | | 375 | |
372 | /* | | 376 | /* |
373 | * Set up memory, I/O enable, and PCI command flags | | 377 | * Set up memory, I/O enable, and PCI command flags |
374 | * as appropriate. | | 378 | * as appropriate. |
375 | */ | | 379 | */ |
376 | pa.pa_flags = sc->sc_flags; | | 380 | pa.pa_flags = sc->sc_flags; |
377 | | | 381 | |
378 | /* | | 382 | /* |
379 | * If the cache line size is not configured, then | | 383 | * If the cache line size is not configured, then |
380 | * clear the MRL/MRM/MWI command-ok flags. | | 384 | * clear the MRL/MRM/MWI command-ok flags. |
381 | */ | | 385 | */ |
382 | if (PCI_CACHELINE(bhlcr) == 0) { | | 386 | if (PCI_CACHELINE(bhlcr) == 0) { |
383 | pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY| | | 387 | pa.pa_flags &= ~(PCI_FLAGS_MRL_OKAY| |
384 | PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY); | | 388 | PCI_FLAGS_MRM_OKAY|PCI_FLAGS_MWI_OKAY); |
385 | } | | 389 | } |
386 | | | 390 | |
387 | if (sc->sc_bridgetag == NULL) { | | 391 | if (sc->sc_bridgetag == NULL) { |
388 | pa.pa_intrswiz = 0; | | 392 | pa.pa_intrswiz = 0; |
389 | pa.pa_intrtag = tag; | | 393 | pa.pa_intrtag = tag; |
390 | } else { | | 394 | } else { |
391 | pa.pa_intrswiz = sc->sc_intrswiz + device; | | 395 | pa.pa_intrswiz = sc->sc_intrswiz + device; |
392 | pa.pa_intrtag = sc->sc_intrtag; | | 396 | pa.pa_intrtag = sc->sc_intrtag; |
393 | } | | 397 | } |
394 | | | 398 | |
395 | intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); | | 399 | intr = pci_conf_read(pc, tag, PCI_INTERRUPT_REG); |
396 | | | 400 | |
397 | pin = PCI_INTERRUPT_PIN(intr); | | 401 | pin = PCI_INTERRUPT_PIN(intr); |
398 | pa.pa_rawintrpin = pin; | | 402 | pa.pa_rawintrpin = pin; |
399 | if (pin == PCI_INTERRUPT_PIN_NONE) { | | 403 | if (pin == PCI_INTERRUPT_PIN_NONE) { |
400 | /* no interrupt */ | | 404 | /* no interrupt */ |
401 | pa.pa_intrpin = 0; | | 405 | pa.pa_intrpin = 0; |
402 | } else { | | 406 | } else { |
403 | /* | | 407 | /* |
404 | * swizzle it based on the number of busses we're | | 408 | * swizzle it based on the number of busses we're |
405 | * behind and our device number. | | 409 | * behind and our device number. |
406 | */ | | 410 | */ |
407 | pa.pa_intrpin = /* XXX */ | | 411 | pa.pa_intrpin = /* XXX */ |
408 | ((pin + pa.pa_intrswiz - 1) % 4) + 1; | | 412 | ((pin + pa.pa_intrswiz - 1) % 4) + 1; |
409 | } | | 413 | } |
410 | pa.pa_intrline = PCI_INTERRUPT_LINE(intr); | | 414 | pa.pa_intrline = PCI_INTERRUPT_LINE(intr); |
411 | | | 415 | |
412 | #ifdef __HAVE_PCI_MSI_MSIX | | 416 | #ifdef __HAVE_PCI_MSI_MSIX |
413 | if (pci_get_ht_capability(pc, tag, PCI_HT_CAP_MSIMAP, &off, &cap)) { | | 417 | if (pci_get_ht_capability(pc, tag, PCI_HT_CAP_MSIMAP, &off, &cap)) { |
414 | /* | | 418 | /* |
415 | * XXX Should we enable MSI mapping ourselves on | | 419 | * XXX Should we enable MSI mapping ourselves on |
416 | * systems that have it disabled? | | 420 | * systems that have it disabled? |
417 | */ | | 421 | */ |
418 | if (cap & PCI_HT_MSI_ENABLED) { | | 422 | if (cap & PCI_HT_MSI_ENABLED) { |
419 | uint64_t addr; | | 423 | uint64_t addr; |
420 | if ((cap & PCI_HT_MSI_FIXED) == 0) { | | 424 | if ((cap & PCI_HT_MSI_FIXED) == 0) { |
421 | addr = pci_conf_read(pc, tag, | | 425 | addr = pci_conf_read(pc, tag, |
422 | off + PCI_HT_MSI_ADDR_LO); | | 426 | off + PCI_HT_MSI_ADDR_LO); |
423 | addr |= (uint64_t)pci_conf_read(pc, tag, | | 427 | addr |= (uint64_t)pci_conf_read(pc, tag, |
424 | off + PCI_HT_MSI_ADDR_HI) << 32; | | 428 | off + PCI_HT_MSI_ADDR_HI) << 32; |
425 | } else | | 429 | } else |
426 | addr = PCI_HT_MSI_FIXED_ADDR; | | 430 | addr = PCI_HT_MSI_FIXED_ADDR; |
427 | | | 431 | |
428 | /* | | 432 | /* |
429 | * XXX This will fail to enable MSI on systems | | 433 | * XXX This will fail to enable MSI on systems |
430 | * that don't use the canonical address. | | 434 | * that don't use the canonical address. |
431 | */ | | 435 | */ |
432 | if (addr == PCI_HT_MSI_FIXED_ADDR) { | | 436 | if (addr == PCI_HT_MSI_FIXED_ADDR) { |
433 | pa.pa_flags |= PCI_FLAGS_MSI_OKAY; | | 437 | pa.pa_flags |= PCI_FLAGS_MSI_OKAY; |
434 | pa.pa_flags |= PCI_FLAGS_MSIX_OKAY; | | 438 | pa.pa_flags |= PCI_FLAGS_MSIX_OKAY; |
435 | } else | | 439 | } else |
436 | aprint_verbose_dev(sc->sc_dev, | | 440 | aprint_verbose_dev(sc->sc_dev, |
437 | "HyperTransport MSI mapping is not supported yet. Disable MSI/MSI-X.\n"); | | 441 | "HyperTransport MSI mapping is not supported yet. Disable MSI/MSI-X.\n"); |
438 | } | | 442 | } |
439 | } | | 443 | } |
440 | #endif | | 444 | #endif |
441 | | | 445 | |
442 | if (match != NULL) { | | 446 | if (match != NULL) { |
443 | ret = (*match)(&pa); | | 447 | ret = (*match)(&pa); |
444 | if (ret != 0 && pap != NULL) | | 448 | if (ret != 0 && pap != NULL) |
445 | *pap = pa; | | 449 | *pap = pa; |
446 | } else { | | 450 | } else { |
447 | struct pci_child *c; | | 451 | struct pci_child *c; |
448 | locs[PCICF_DEV] = device; | | 452 | locs[PCICF_DEV] = device; |
449 | locs[PCICF_FUNCTION] = function; | | 453 | locs[PCICF_FUNCTION] = function; |
450 | | | 454 | |
451 | c = &sc->PCI_SC_DEVICESC(device, function); | | 455 | c = &sc->PCI_SC_DEVICESC(device, function); |
452 | pci_conf_capture(pc, tag, &c->c_conf); | | 456 | pci_conf_capture(pc, tag, &c->c_conf); |
453 | if (pci_get_powerstate(pc, tag, &c->c_powerstate) == 0) | | 457 | if (pci_get_powerstate(pc, tag, &c->c_powerstate) == 0) |
454 | c->c_psok = true; | | 458 | c->c_psok = true; |
455 | else | | 459 | else |
456 | c->c_psok = false; | | 460 | c->c_psok = false; |
457 | | | 461 | |
458 | c->c_dev = config_found_sm_loc(sc->sc_dev, "pci", locs, &pa, | | 462 | c->c_dev = config_found_sm_loc(sc->sc_dev, "pci", locs, &pa, |
459 | pciprint, config_stdsubmatch); | | 463 | pciprint, config_stdsubmatch); |
460 | | | 464 | |
461 | ret = (c->c_dev != NULL); | | 465 | ret = (c->c_dev != NULL); |
462 | } | | 466 | } |
463 | | | 467 | |
464 | return ret; | | 468 | return ret; |
465 | } | | 469 | } |
466 | | | 470 | |
467 | void | | 471 | void |
468 | pcidevdetached(device_t self, device_t child) | | 472 | pcidevdetached(device_t self, device_t child) |
469 | { | | 473 | { |
470 | struct pci_softc *sc = device_private(self); | | 474 | struct pci_softc *sc = device_private(self); |
471 | int d, f; | | 475 | int d, f; |
472 | pcitag_t tag; | | 476 | pcitag_t tag; |
473 | struct pci_child *c; | | 477 | struct pci_child *c; |
474 | | | 478 | |
475 | d = device_locator(child, PCICF_DEV); | | 479 | d = device_locator(child, PCICF_DEV); |
476 | f = device_locator(child, PCICF_FUNCTION); | | 480 | f = device_locator(child, PCICF_FUNCTION); |
477 | | | 481 | |
478 | c = &sc->PCI_SC_DEVICESC(d, f); | | 482 | c = &sc->PCI_SC_DEVICESC(d, f); |
479 | | | 483 | |
480 | KASSERT(c->c_dev == child); | | 484 | KASSERT(c->c_dev == child); |
481 | | | 485 | |
482 | tag = pci_make_tag(sc->sc_pc, sc->sc_bus, d, f); | | 486 | tag = pci_make_tag(sc->sc_pc, sc->sc_bus, d, f); |
483 | if (c->c_psok) | | 487 | if (c->c_psok) |
484 | pci_set_powerstate(sc->sc_pc, tag, c->c_powerstate); | | 488 | pci_set_powerstate(sc->sc_pc, tag, c->c_powerstate); |
485 | pci_conf_restore(sc->sc_pc, tag, &c->c_conf); | | 489 | pci_conf_restore(sc->sc_pc, tag, &c->c_conf); |
486 | c->c_dev = NULL; | | 490 | c->c_dev = NULL; |
487 | } | | 491 | } |
488 | | | 492 | |
489 | CFATTACH_DECL3_NEW(pci, sizeof(struct pci_softc), | | 493 | CFATTACH_DECL3_NEW(pci, sizeof(struct pci_softc), |
490 | pcimatch, pciattach, pcidetach, NULL, pcirescan, pcidevdetached, | | 494 | pcimatch, pciattach, pcidetach, NULL, pcirescan, pcidevdetached, |
491 | DVF_DETACH_SHUTDOWN); | | 495 | DVF_DETACH_SHUTDOWN); |
492 | | | 496 | |
493 | int | | 497 | int |
494 | pci_get_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid, | | 498 | pci_get_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid, |
495 | int *offset, pcireg_t *value) | | 499 | int *offset, pcireg_t *value) |
496 | { | | 500 | { |
497 | pcireg_t reg; | | 501 | pcireg_t reg; |
498 | unsigned int ofs; | | 502 | unsigned int ofs; |
499 | | | 503 | |
500 | reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); | | 504 | reg = pci_conf_read(pc, tag, PCI_COMMAND_STATUS_REG); |
501 | if (!(reg & PCI_STATUS_CAPLIST_SUPPORT)) | | 505 | if (!(reg & PCI_STATUS_CAPLIST_SUPPORT)) |
502 | return 0; | | 506 | return 0; |
503 | | | 507 | |
504 | /* Determine the Capability List Pointer register to start with. */ | | 508 | /* Determine the Capability List Pointer register to start with. */ |
505 | reg = pci_conf_read(pc, tag, PCI_BHLC_REG); | | 509 | reg = pci_conf_read(pc, tag, PCI_BHLC_REG); |
506 | switch (PCI_HDRTYPE_TYPE(reg)) { | | 510 | switch (PCI_HDRTYPE_TYPE(reg)) { |
507 | case 0: /* standard device header */ | | 511 | case 0: /* standard device header */ |
508 | case 1: /* PCI-PCI bridge header */ | | 512 | case 1: /* PCI-PCI bridge header */ |
509 | ofs = PCI_CAPLISTPTR_REG; | | 513 | ofs = PCI_CAPLISTPTR_REG; |
510 | break; | | 514 | break; |
511 | case 2: /* PCI-CardBus Bridge header */ | | 515 | case 2: /* PCI-CardBus Bridge header */ |
512 | ofs = PCI_CARDBUS_CAPLISTPTR_REG; | | 516 | ofs = PCI_CARDBUS_CAPLISTPTR_REG; |
513 | break; | | 517 | break; |
514 | default: | | 518 | default: |
515 | return 0; | | 519 | return 0; |
516 | } | | 520 | } |
517 | | | 521 | |
518 | ofs = PCI_CAPLIST_PTR(pci_conf_read(pc, tag, ofs)); | | 522 | ofs = PCI_CAPLIST_PTR(pci_conf_read(pc, tag, ofs)); |
519 | while (ofs != 0) { | | 523 | while (ofs != 0) { |
520 | if ((ofs & 3) || (ofs < 0x40)) { | | 524 | if ((ofs & 3) || (ofs < 0x40)) { |
521 | int bus, device, function; | | 525 | int bus, device, function; |
522 | | | 526 | |
523 | pci_decompose_tag(pc, tag, &bus, &device, &function); | | 527 | pci_decompose_tag(pc, tag, &bus, &device, &function); |
524 | | | 528 | |
525 | printf("Skipping broken PCI header on %d:%d:%d\n", | | 529 | printf("Skipping broken PCI header on %d:%d:%d\n", |
526 | bus, device, function); | | 530 | bus, device, function); |
527 | break; | | 531 | break; |
528 | } | | 532 | } |
529 | reg = pci_conf_read(pc, tag, ofs); | | 533 | reg = pci_conf_read(pc, tag, ofs); |
530 | if (PCI_CAPLIST_CAP(reg) == capid) { | | 534 | if (PCI_CAPLIST_CAP(reg) == capid) { |
531 | if (offset) | | 535 | if (offset) |
532 | *offset = ofs; | | 536 | *offset = ofs; |
533 | if (value) | | 537 | if (value) |
534 | *value = reg; | | 538 | *value = reg; |
535 | return 1; | | 539 | return 1; |
536 | } | | 540 | } |
537 | ofs = PCI_CAPLIST_NEXT(reg); | | 541 | ofs = PCI_CAPLIST_NEXT(reg); |
538 | } | | 542 | } |
539 | | | 543 | |
540 | return 0; | | 544 | return 0; |
541 | } | | 545 | } |
542 | | | 546 | |
543 | int | | 547 | int |
544 | pci_get_ht_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid, | | 548 | pci_get_ht_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid, |
545 | int *offset, pcireg_t *value) | | 549 | int *offset, pcireg_t *value) |
546 | { | | 550 | { |
547 | pcireg_t reg; | | 551 | pcireg_t reg; |
548 | unsigned int ofs; | | 552 | unsigned int ofs; |
549 | | | 553 | |
550 | if (pci_get_capability(pc, tag, PCI_CAP_LDT, &ofs, NULL) == 0) | | 554 | if (pci_get_capability(pc, tag, PCI_CAP_LDT, &ofs, NULL) == 0) |
551 | return 0; | | 555 | return 0; |
552 | | | 556 | |
553 | while (ofs != 0) { | | 557 | while (ofs != 0) { |
554 | #ifdef DIAGNOSTIC | | 558 | #ifdef DIAGNOSTIC |
555 | if ((ofs & 3) || (ofs < 0x40)) | | 559 | if ((ofs & 3) || (ofs < 0x40)) |
556 | panic("pci_get_ht_capability"); | | 560 | panic("pci_get_ht_capability"); |
557 | #endif | | 561 | #endif |
558 | reg = pci_conf_read(pc, tag, ofs); | | 562 | reg = pci_conf_read(pc, tag, ofs); |
559 | if (PCI_HT_CAP(reg) == capid) { | | 563 | if (PCI_HT_CAP(reg) == capid) { |
560 | if (offset) | | 564 | if (offset) |
561 | *offset = ofs; | | 565 | *offset = ofs; |
562 | if (value) | | 566 | if (value) |
563 | *value = reg; | | 567 | *value = reg; |
564 | return 1; | | 568 | return 1; |
565 | } | | 569 | } |
566 | ofs = PCI_CAPLIST_NEXT(reg); | | 570 | ofs = PCI_CAPLIST_NEXT(reg); |
567 | } | | 571 | } |
568 | | | 572 | |
569 | return 0; | | 573 | return 0; |
570 | } | | 574 | } |
571 | | | 575 | |
572 | /* | | 576 | /* |
573 | * return number of the devices's MSI vectors | | 577 | * return number of the devices's MSI vectors |
574 | * return 0 if the device does not support MSI | | 578 | * return 0 if the device does not support MSI |
575 | */ | | 579 | */ |
576 | int | | 580 | int |
577 | pci_msi_count(pci_chipset_tag_t pc, pcitag_t tag) | | 581 | pci_msi_count(pci_chipset_tag_t pc, pcitag_t tag) |
578 | { | | 582 | { |
579 | pcireg_t reg; | | 583 | pcireg_t reg; |
580 | uint32_t mmc; | | 584 | uint32_t mmc; |
581 | int count, offset; | | 585 | int count, offset; |
582 | | | 586 | |
583 | if (pci_get_capability(pc, tag, PCI_CAP_MSI, &offset, NULL) == 0) | | 587 | if (pci_get_capability(pc, tag, PCI_CAP_MSI, &offset, NULL) == 0) |
584 | return 0; | | 588 | return 0; |
585 | | | 589 | |
586 | reg = pci_conf_read(pc, tag, offset + PCI_MSI_CTL); | | 590 | reg = pci_conf_read(pc, tag, offset + PCI_MSI_CTL); |
587 | mmc = PCI_MSI_CTL_MMC(reg); | | 591 | mmc = PCI_MSI_CTL_MMC(reg); |
588 | count = 1 << mmc; | | 592 | count = 1 << mmc; |
589 | if (count > PCI_MSI_MAX_VECTORS) { | | 593 | if (count > PCI_MSI_MAX_VECTORS) { |
590 | aprint_error("detect an illegal device! The device use reserved MMC values.\n"); | | 594 | aprint_error("detect an illegal device! The device use reserved MMC values.\n"); |
591 | return 0; | | 595 | return 0; |
592 | } | | 596 | } |
593 | | | 597 | |
594 | return count; | | 598 | return count; |
595 | } | | 599 | } |
596 | | | 600 | |
597 | /* | | 601 | /* |
598 | * return number of the devices's MSI-X vectors | | 602 | * return number of the devices's MSI-X vectors |
599 | * return 0 if the device does not support MSI-X | | 603 | * return 0 if the device does not support MSI-X |
600 | */ | | 604 | */ |
601 | int | | 605 | int |
602 | pci_msix_count(pci_chipset_tag_t pc, pcitag_t tag) | | 606 | pci_msix_count(pci_chipset_tag_t pc, pcitag_t tag) |
603 | { | | 607 | { |
604 | pcireg_t reg; | | 608 | pcireg_t reg; |
605 | int offset; | | 609 | int offset; |
606 | | | 610 | |
607 | if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &offset, NULL) == 0) | | 611 | if (pci_get_capability(pc, tag, PCI_CAP_MSIX, &offset, NULL) == 0) |
608 | return 0; | | 612 | return 0; |
609 | | | 613 | |
610 | reg = pci_conf_read(pc, tag, offset + PCI_MSIX_CTL); | | 614 | reg = pci_conf_read(pc, tag, offset + PCI_MSIX_CTL); |
611 | | | 615 | |
612 | return PCI_MSIX_CTL_TBLSIZE(reg); | | 616 | return PCI_MSIX_CTL_TBLSIZE(reg); |
613 | } | | 617 | } |
614 | | | 618 | |
615 | int | | 619 | int |
616 | pci_get_ext_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid, | | 620 | pci_get_ext_capability(pci_chipset_tag_t pc, pcitag_t tag, int capid, |
617 | int *offset, pcireg_t *value) | | 621 | int *offset, pcireg_t *value) |
618 | { | | 622 | { |
619 | pcireg_t reg; | | 623 | pcireg_t reg; |
620 | unsigned int ofs; | | 624 | unsigned int ofs; |
621 | | | 625 | |
622 | /* Only supported for PCI-express devices */ | | 626 | /* Only supported for PCI-express devices */ |
623 | if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, NULL, NULL)) | | 627 | if (!pci_get_capability(pc, tag, PCI_CAP_PCIEXPRESS, NULL, NULL)) |
624 | return 0; | | 628 | return 0; |
625 | | | 629 | |
626 | ofs = PCI_EXTCAPLIST_BASE; | | 630 | ofs = PCI_EXTCAPLIST_BASE; |
627 | reg = pci_conf_read(pc, tag, ofs); | | 631 | reg = pci_conf_read(pc, tag, ofs); |
628 | if (reg == 0xffffffff || reg == 0) | | 632 | if (reg == 0xffffffff || reg == 0) |
629 | return 0; | | 633 | return 0; |
630 | | | 634 | |
631 | for (;;) { | | 635 | for (;;) { |
632 | #ifdef DIAGNOSTIC | | 636 | #ifdef DIAGNOSTIC |
633 | if ((ofs & 3) || ofs < PCI_EXTCAPLIST_BASE) | | 637 | if ((ofs & 3) || ofs < PCI_EXTCAPLIST_BASE) |
634 | panic("%s: invalid offset %u", __func__, ofs); | | 638 | panic("%s: invalid offset %u", __func__, ofs); |
635 | #endif | | 639 | #endif |
636 | if (PCI_EXTCAPLIST_CAP(reg) == capid) { | | 640 | if (PCI_EXTCAPLIST_CAP(reg) == capid) { |
637 | if (offset != NULL) | | 641 | if (offset != NULL) |
638 | *offset = ofs; | | 642 | *offset = ofs; |
639 | if (value != NULL) | | 643 | if (value != NULL) |
640 | *value = reg; | | 644 | *value = reg; |
641 | return 1; | | 645 | return 1; |
642 | } | | 646 | } |
643 | ofs = PCI_EXTCAPLIST_NEXT(reg); | | 647 | ofs = PCI_EXTCAPLIST_NEXT(reg); |
644 | if (ofs == 0) | | 648 | if (ofs == 0) |
645 | break; | | 649 | break; |
646 | reg = pci_conf_read(pc, tag, ofs); | | 650 | reg = pci_conf_read(pc, tag, ofs); |
647 | } | | 651 | } |
648 | | | 652 | |
649 | return 0; | | 653 | return 0; |
650 | } | | 654 | } |
651 | | | 655 | |
652 | int | | 656 | int |
653 | pci_find_device(struct pci_attach_args *pa, | | 657 | pci_find_device(struct pci_attach_args *pa, |
654 | int (*match)(const struct pci_attach_args *)) | | 658 | int (*match)(const struct pci_attach_args *)) |
655 | { | | 659 | { |
656 | extern struct cfdriver pci_cd; | | 660 | extern struct cfdriver pci_cd; |
657 | device_t pcidev; | | 661 | device_t pcidev; |
658 | int i; | | 662 | int i; |
659 | static const int wildcard[2] = { | | 663 | static const int wildcard[2] = { |
660 | PCICF_DEV_DEFAULT, | | 664 | PCICF_DEV_DEFAULT, |
661 | PCICF_FUNCTION_DEFAULT | | 665 | PCICF_FUNCTION_DEFAULT |
662 | }; | | 666 | }; |
663 | | | 667 | |
664 | for (i = 0; i < pci_cd.cd_ndevs; i++) { | | 668 | for (i = 0; i < pci_cd.cd_ndevs; i++) { |
665 | pcidev = device_lookup(&pci_cd, i); | | 669 | pcidev = device_lookup(&pci_cd, i); |
666 | if (pcidev != NULL && | | 670 | if (pcidev != NULL && |
667 | pci_enumerate_bus(device_private(pcidev), wildcard, | | 671 | pci_enumerate_bus(device_private(pcidev), wildcard, |
668 | match, pa) != 0) | | 672 | match, pa) != 0) |
669 | return 1; | | 673 | return 1; |
670 | } | | 674 | } |
671 | return 0; | | 675 | return 0; |
672 | } | | 676 | } |
673 | | | 677 | |
674 | #ifndef PCI_MACHDEP_ENUMERATE_BUS | | 678 | #ifndef PCI_MACHDEP_ENUMERATE_BUS |
675 | /* | | 679 | /* |
676 | * Generic PCI bus enumeration routine. Used unless machine-dependent | | 680 | * Generic PCI bus enumeration routine. Used unless machine-dependent |
677 | * code needs to provide something else. | | 681 | * code needs to provide something else. |
678 | */ | | 682 | */ |
679 | int | | 683 | int |
680 | pci_enumerate_bus(struct pci_softc *sc, const int *locators, | | 684 | pci_enumerate_bus(struct pci_softc *sc, const int *locators, |
681 | int (*match)(const struct pci_attach_args *), struct pci_attach_args *pap) | | 685 | int (*match)(const struct pci_attach_args *), struct pci_attach_args *pap) |
682 | { | | 686 | { |
683 | pci_chipset_tag_t pc = sc->sc_pc; | | 687 | pci_chipset_tag_t pc = sc->sc_pc; |
684 | int device, function, nfunctions, ret; | | 688 | int device, function, nfunctions, ret; |
685 | const struct pci_quirkdata *qd; | | 689 | const struct pci_quirkdata *qd; |
686 | pcireg_t id, bhlcr; | | 690 | pcireg_t id, bhlcr; |
687 | pcitag_t tag; | | 691 | pcitag_t tag; |
688 | uint8_t devs[32]; | | 692 | uint8_t devs[32]; |
689 | int i, n; | | 693 | int i, n; |
690 | | | 694 | |
691 | n = pci_bus_devorder(sc->sc_pc, sc->sc_bus, devs, __arraycount(devs)); | | 695 | n = pci_bus_devorder(sc->sc_pc, sc->sc_bus, devs, __arraycount(devs)); |
692 | for (i = 0; i < n; i++) { | | 696 | for (i = 0; i < n; i++) { |
693 | device = devs[i]; | | 697 | device = devs[i]; |
694 | | | 698 | |
695 | if ((locators[PCICF_DEV] != PCICF_DEV_DEFAULT) && | | 699 | if ((locators[PCICF_DEV] != PCICF_DEV_DEFAULT) && |
696 | (locators[PCICF_DEV] != device)) | | 700 | (locators[PCICF_DEV] != device)) |
697 | continue; | | 701 | continue; |
698 | | | 702 | |
699 | tag = pci_make_tag(pc, sc->sc_bus, device, 0); | | 703 | tag = pci_make_tag(pc, sc->sc_bus, device, 0); |
700 | | | 704 | |
701 | bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); | | 705 | bhlcr = pci_conf_read(pc, tag, PCI_BHLC_REG); |
702 | if (PCI_HDRTYPE_TYPE(bhlcr) > 2) | | 706 | if (PCI_HDRTYPE_TYPE(bhlcr) > 2) |
703 | continue; | | 707 | continue; |
704 | | | 708 | |
705 | id = pci_conf_read(pc, tag, PCI_ID_REG); | | 709 | id = pci_conf_read(pc, tag, PCI_ID_REG); |
706 | | | 710 | |
707 | /* Invalid vendor ID value? */ | | 711 | /* Invalid vendor ID value? */ |
708 | if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) | | 712 | if (PCI_VENDOR(id) == PCI_VENDOR_INVALID) |
709 | continue; | | 713 | continue; |
710 | /* XXX Not invalid, but we've done this ~forever. */ | | 714 | /* XXX Not invalid, but we've done this ~forever. */ |
711 | if (PCI_VENDOR(id) == 0) | | 715 | if (PCI_VENDOR(id) == 0) |
712 | continue; | | 716 | continue; |
713 | | | 717 | |
714 | qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); | | 718 | qd = pci_lookup_quirkdata(PCI_VENDOR(id), PCI_PRODUCT(id)); |
715 | | | 719 | |
716 | if (qd != NULL && | | 720 | if (qd != NULL && |
717 | (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0) | | 721 | (qd->quirks & PCI_QUIRK_MULTIFUNCTION) != 0) |
718 | nfunctions = 8; | | 722 | nfunctions = 8; |
719 | else if (qd != NULL && | | 723 | else if (qd != NULL && |
720 | (qd->quirks & PCI_QUIRK_MONOFUNCTION) != 0) | | 724 | (qd->quirks & PCI_QUIRK_MONOFUNCTION) != 0) |
721 | nfunctions = 1; | | 725 | nfunctions = 1; |
722 | else | | 726 | else |
723 | nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; | | 727 | nfunctions = PCI_HDRTYPE_MULTIFN(bhlcr) ? 8 : 1; |
724 | | | 728 | |
725 | #ifdef __PCI_DEV_FUNCORDER | | 729 | #ifdef __PCI_DEV_FUNCORDER |
726 | char funcs[8]; | | 730 | char funcs[8]; |
727 | int j; | | 731 | int j; |
728 | for (j = 0; j < nfunctions; j++) { | | 732 | for (j = 0; j < nfunctions; j++) { |
729 | funcs[j] = j; | | 733 | funcs[j] = j; |
730 | } | | 734 | } |
731 | if (j < __arraycount(funcs)) | | 735 | if (j < __arraycount(funcs)) |
732 | funcs[j] = -1; | | 736 | funcs[j] = -1; |
733 | if (nfunctions > 1) { | | 737 | if (nfunctions > 1) { |
734 | pci_dev_funcorder(sc->sc_pc, sc->sc_bus, device, | | 738 | pci_dev_funcorder(sc->sc_pc, sc->sc_bus, device, |
735 | nfunctions, funcs); | | 739 | nfunctions, funcs); |
736 | } | | 740 | } |
737 | for (j = 0; | | 741 | for (j = 0; |
738 | j < 8 && (function = funcs[j]) < 8 && function >= 0; | | 742 | j < 8 && (function = funcs[j]) < 8 && function >= 0; |
739 | j++) { | | 743 | j++) { |
740 | #else | | 744 | #else |
741 | for (function = 0; function < nfunctions; function++) { | | 745 | for (function = 0; function < nfunctions; function++) { |
742 | #endif | | 746 | #endif |
743 | if ((locators[PCICF_FUNCTION] != PCICF_FUNCTION_DEFAULT) | | 747 | if ((locators[PCICF_FUNCTION] != PCICF_FUNCTION_DEFAULT) |
744 | && (locators[PCICF_FUNCTION] != function)) | | 748 | && (locators[PCICF_FUNCTION] != function)) |
745 | continue; | | 749 | continue; |
746 | | | 750 | |
747 | if (qd != NULL && | | 751 | if (qd != NULL && |
748 | (qd->quirks & PCI_QUIRK_SKIP_FUNC(function)) != 0) | | 752 | (qd->quirks & PCI_QUIRK_SKIP_FUNC(function)) != 0) |
749 | continue; | | 753 | continue; |
750 | tag = pci_make_tag(pc, sc->sc_bus, device, function); | | 754 | tag = pci_make_tag(pc, sc->sc_bus, device, function); |
751 | ret = pci_probe_device(sc, tag, match, pap); | | 755 | ret = pci_probe_device(sc, tag, match, pap); |
752 | if (match != NULL && ret != 0) | | 756 | if (match != NULL && ret != 0) |
753 | return ret; | | 757 | return ret; |
754 | } | | 758 | } |
755 | } | | 759 | } |
756 | return 0; | | 760 | return 0; |
757 | } | | 761 | } |
758 | #endif /* PCI_MACHDEP_ENUMERATE_BUS */ | | 762 | #endif /* PCI_MACHDEP_ENUMERATE_BUS */ |
759 | | | 763 | |
760 | | | 764 | |
761 | /* | | 765 | /* |
762 | * Vital Product Data (PCI 2.2) | | 766 | * Vital Product Data (PCI 2.2) |
763 | */ | | 767 | */ |
764 | | | 768 | |
765 | int | | 769 | int |
766 | pci_vpd_read(pci_chipset_tag_t pc, pcitag_t tag, int offset, int count, | | 770 | pci_vpd_read(pci_chipset_tag_t pc, pcitag_t tag, int offset, int count, |
767 | pcireg_t *data) | | 771 | pcireg_t *data) |
768 | { | | 772 | { |
769 | uint32_t reg; | | 773 | uint32_t reg; |
770 | int ofs, i, j; | | 774 | int ofs, i, j; |
771 | | | 775 | |
772 | KASSERT(data != NULL); | | 776 | KASSERT(data != NULL); |
773 | KASSERT((offset + count) < 0x7fff); | | 777 | KASSERT((offset + count) < 0x7fff); |
774 | | | 778 | |
775 | if (pci_get_capability(pc, tag, PCI_CAP_VPD, &ofs, ®) == 0) | | 779 | if (pci_get_capability(pc, tag, PCI_CAP_VPD, &ofs, ®) == 0) |
776 | return 1; | | 780 | return 1; |
777 | | | 781 | |
778 | for (i = 0; i < count; offset += sizeof(*data), i++) { | | 782 | for (i = 0; i < count; offset += sizeof(*data), i++) { |
779 | reg &= 0x0000ffff; | | 783 | reg &= 0x0000ffff; |
780 | reg &= ~PCI_VPD_OPFLAG; | | 784 | reg &= ~PCI_VPD_OPFLAG; |
781 | reg |= PCI_VPD_ADDRESS(offset); | | 785 | reg |= PCI_VPD_ADDRESS(offset); |
782 | pci_conf_write(pc, tag, ofs, reg); | | 786 | pci_conf_write(pc, tag, ofs, reg); |
783 | | | 787 | |
784 | /* | | 788 | /* |
785 | * PCI 2.2 does not specify how long we should poll | | 789 | * PCI 2.2 does not specify how long we should poll |
786 | * for completion nor whether the operation can fail. | | 790 | * for completion nor whether the operation can fail. |
787 | */ | | 791 | */ |
788 | j = 0; | | 792 | j = 0; |
789 | do { | | 793 | do { |
790 | if (j++ == 20) | | 794 | if (j++ == 20) |
791 | return 1; | | 795 | return 1; |
792 | delay(4); | | 796 | delay(4); |
793 | reg = pci_conf_read(pc, tag, ofs); | | 797 | reg = pci_conf_read(pc, tag, ofs); |
794 | } while ((reg & PCI_VPD_OPFLAG) == 0); | | 798 | } while ((reg & PCI_VPD_OPFLAG) == 0); |
795 | data[i] = pci_conf_read(pc, tag, PCI_VPD_DATAREG(ofs)); | | 799 | data[i] = pci_conf_read(pc, tag, PCI_VPD_DATAREG(ofs)); |
796 | } | | 800 | } |
797 | | | 801 | |
798 | return 0; | | 802 | return 0; |
799 | } | | 803 | } |
800 | | | 804 | |
801 | int | | 805 | int |
802 | pci_vpd_write(pci_chipset_tag_t pc, pcitag_t tag, int offset, int count, | | 806 | pci_vpd_write(pci_chipset_tag_t pc, pcitag_t tag, int offset, int count, |
803 | pcireg_t *data) | | 807 | pcireg_t *data) |
804 | { | | 808 | { |
805 | pcireg_t reg; | | 809 | pcireg_t reg; |
806 | int ofs, i, j; | | 810 | int ofs, i, j; |
807 | | | 811 | |
808 | KASSERT(data != NULL); | | 812 | KASSERT(data != NULL); |
809 | KASSERT((offset + count) < 0x7fff); | | 813 | KASSERT((offset + count) < 0x7fff); |
810 | | | 814 | |
811 | if (pci_get_capability(pc, tag, PCI_CAP_VPD, &ofs, ®) == 0) | | 815 | if (pci_get_capability(pc, tag, PCI_CAP_VPD, &ofs, ®) == 0) |
812 | return 1; | | 816 | return 1; |
813 | | | 817 | |
814 | for (i = 0; i < count; offset += sizeof(*data), i++) { | | 818 | for (i = 0; i < count; offset += sizeof(*data), i++) { |
815 | pci_conf_write(pc, tag, PCI_VPD_DATAREG(ofs), data[i]); | | 819 | pci_conf_write(pc, tag, PCI_VPD_DATAREG(ofs), data[i]); |
816 | | | 820 | |
817 | reg &= 0x0000ffff; | | 821 | reg &= 0x0000ffff; |
818 | reg |= PCI_VPD_OPFLAG; | | 822 | reg |= PCI_VPD_OPFLAG; |
819 | reg |= PCI_VPD_ADDRESS(offset); | | 823 | reg |= PCI_VPD_ADDRESS(offset); |
820 | pci_conf_write(pc, tag, ofs, reg); | | 824 | pci_conf_write(pc, tag, ofs, reg); |
821 | | | 825 | |
822 | /* | | 826 | /* |
823 | * PCI 2.2 does not specify how long we should poll | | 827 | * PCI 2.2 does not specify how long we should poll |
824 | * for completion nor whether the operation can fail. | | 828 | * for completion nor whether the operation can fail. |
825 | */ | | 829 | */ |
826 | j = 0; | | 830 | j = 0; |
827 | do { | | 831 | do { |
828 | if (j++ == 20) | | 832 | if (j++ == 20) |
829 | return 1; | | 833 | return 1; |
830 | delay(1); | | 834 | delay(1); |
831 | reg = pci_conf_read(pc, tag, ofs); | | 835 | reg = pci_conf_read(pc, tag, ofs); |
832 | } while (reg & PCI_VPD_OPFLAG); | | 836 | } while (reg & PCI_VPD_OPFLAG); |
833 | } | | 837 | } |
834 | | | 838 | |
835 | return 0; | | 839 | return 0; |
836 | } | | 840 | } |
837 | | | 841 | |
838 | int | | 842 | int |
839 | pci_dma64_available(const struct pci_attach_args *pa) | | 843 | pci_dma64_available(const struct pci_attach_args *pa) |
840 | { | | 844 | { |
841 | #ifdef _PCI_HAVE_DMA64 | | 845 | #ifdef _PCI_HAVE_DMA64 |
842 | if (BUS_DMA_TAG_VALID(pa->pa_dmat64)) | | 846 | if (BUS_DMA_TAG_VALID(pa->pa_dmat64)) |
843 | return 1; | | 847 | return 1; |
844 | #endif | | 848 | #endif |
845 | return 0; | | 849 | return 0; |
846 | } | | 850 | } |
847 | | | 851 | |
848 | void | | 852 | void |
849 | pci_conf_capture(pci_chipset_tag_t pc, pcitag_t tag, | | 853 | pci_conf_capture(pci_chipset_tag_t pc, pcitag_t tag, |
850 | struct pci_conf_state *pcs) | | 854 | struct pci_conf_state *pcs) |
851 | { | | 855 | { |
852 | int off; | | 856 | int off; |
853 | | | 857 | |
854 | for (off = 0; off < 16; off++) | | 858 | for (off = 0; off < 16; off++) |
855 | pcs->reg[off] = pci_conf_read(pc, tag, (off * 4)); | | 859 | pcs->reg[off] = pci_conf_read(pc, tag, (off * 4)); |
856 | | | 860 | |
857 | return; | | 861 | return; |
858 | } | | 862 | } |
859 | | | 863 | |
860 | void | | 864 | void |
861 | pci_conf_restore(pci_chipset_tag_t pc, pcitag_t tag, | | 865 | pci_conf_restore(pci_chipset_tag_t pc, pcitag_t tag, |
862 | struct pci_conf_state *pcs) | | 866 | struct pci_conf_state *pcs) |
863 | { | | 867 | { |
864 | int off; | | 868 | int off; |
865 | pcireg_t val; | | 869 | pcireg_t val; |
866 | | | 870 | |
867 | for (off = 15; off >= 0; off--) { | | 871 | for (off = 15; off >= 0; off--) { |
868 | val = pci_conf_read(pc, tag, (off * 4)); | | 872 | val = pci_conf_read(pc, tag, (off * 4)); |
869 | if (val != pcs->reg[off]) | | 873 | if (val != pcs->reg[off]) |
870 | pci_conf_write(pc, tag, (off * 4), pcs->reg[off]); | | 874 | pci_conf_write(pc, tag, (off * 4), pcs->reg[off]); |
871 | } | | 875 | } |
872 | | | 876 | |
873 | return; | | 877 | return; |
874 | } | | 878 | } |
875 | | | 879 | |
876 | /* | | 880 | /* |
877 | * Power Management Capability (Rev 2.2) | | 881 | * Power Management Capability (Rev 2.2) |
878 | */ | | 882 | */ |
879 | static int | | 883 | static int |
880 | pci_get_powerstate_int(pci_chipset_tag_t pc, pcitag_t tag , pcireg_t *state, | | 884 | pci_get_powerstate_int(pci_chipset_tag_t pc, pcitag_t tag , pcireg_t *state, |
881 | int offset) | | 885 | int offset) |
882 | { | | 886 | { |
883 | pcireg_t value, now; | | 887 | pcireg_t value, now; |
884 | | | 888 | |
885 | value = pci_conf_read(pc, tag, offset + PCI_PMCSR); | | 889 | value = pci_conf_read(pc, tag, offset + PCI_PMCSR); |
886 | now = value & PCI_PMCSR_STATE_MASK; | | 890 | now = value & PCI_PMCSR_STATE_MASK; |
887 | switch (now) { | | 891 | switch (now) { |
888 | case PCI_PMCSR_STATE_D0: | | 892 | case PCI_PMCSR_STATE_D0: |
889 | case PCI_PMCSR_STATE_D1: | | 893 | case PCI_PMCSR_STATE_D1: |
890 | case PCI_PMCSR_STATE_D2: | | 894 | case PCI_PMCSR_STATE_D2: |
891 | case PCI_PMCSR_STATE_D3: | | 895 | case PCI_PMCSR_STATE_D3: |
892 | *state = now; | | 896 | *state = now; |
893 | return 0; | | 897 | return 0; |
894 | default: | | 898 | default: |
895 | return EINVAL; | | 899 | return EINVAL; |
896 | } | | 900 | } |
897 | } | | 901 | } |
898 | | | 902 | |
899 | int | | 903 | int |
900 | pci_get_powerstate(pci_chipset_tag_t pc, pcitag_t tag , pcireg_t *state) | | 904 | pci_get_powerstate(pci_chipset_tag_t pc, pcitag_t tag , pcireg_t *state) |
901 | { | | 905 | { |
902 | int offset; | | 906 | int offset; |
903 | pcireg_t value; | | 907 | pcireg_t value; |
904 | | | 908 | |
905 | if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value)) | | 909 | if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value)) |
906 | return EOPNOTSUPP; | | 910 | return EOPNOTSUPP; |
907 | | | 911 | |
908 | return pci_get_powerstate_int(pc, tag, state, offset); | | 912 | return pci_get_powerstate_int(pc, tag, state, offset); |
909 | } | | 913 | } |
910 | | | 914 | |
911 | static int | | 915 | static int |
912 | pci_set_powerstate_int(pci_chipset_tag_t pc, pcitag_t tag, pcireg_t state, | | 916 | pci_set_powerstate_int(pci_chipset_tag_t pc, pcitag_t tag, pcireg_t state, |
913 | int offset, pcireg_t cap_reg) | | 917 | int offset, pcireg_t cap_reg) |
914 | { | | 918 | { |
915 | pcireg_t value, cap, now; | | 919 | pcireg_t value, cap, now; |
916 | | | 920 | |
917 | cap = cap_reg >> PCI_PMCR_SHIFT; | | 921 | cap = cap_reg >> PCI_PMCR_SHIFT; |
918 | value = pci_conf_read(pc, tag, offset + PCI_PMCSR); | | 922 | value = pci_conf_read(pc, tag, offset + PCI_PMCSR); |
919 | now = value & PCI_PMCSR_STATE_MASK; | | 923 | now = value & PCI_PMCSR_STATE_MASK; |
920 | value &= ~PCI_PMCSR_STATE_MASK; | | 924 | value &= ~PCI_PMCSR_STATE_MASK; |
921 | | | 925 | |
922 | if (now == state) | | 926 | if (now == state) |
923 | return 0; | | 927 | return 0; |
924 | switch (state) { | | 928 | switch (state) { |
925 | case PCI_PMCSR_STATE_D0: | | 929 | case PCI_PMCSR_STATE_D0: |
926 | break; | | 930 | break; |
927 | case PCI_PMCSR_STATE_D1: | | 931 | case PCI_PMCSR_STATE_D1: |
928 | if (now == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D3) { | | 932 | if (now == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D3) { |
929 | printf("invalid transition from %d to D1\n", (int)now); | | 933 | printf("invalid transition from %d to D1\n", (int)now); |
930 | return EINVAL; | | 934 | return EINVAL; |
931 | } | | 935 | } |
932 | if (!(cap & PCI_PMCR_D1SUPP)) { | | 936 | if (!(cap & PCI_PMCR_D1SUPP)) { |
933 | printf("D1 not supported\n"); | | 937 | printf("D1 not supported\n"); |
934 | return EOPNOTSUPP; | | 938 | return EOPNOTSUPP; |
935 | } | | 939 | } |
936 | break; | | 940 | break; |
937 | case PCI_PMCSR_STATE_D2: | | 941 | case PCI_PMCSR_STATE_D2: |
938 | if (now == PCI_PMCSR_STATE_D3) { | | 942 | if (now == PCI_PMCSR_STATE_D3) { |
939 | printf("invalid transition from %d to D2\n", (int)now); | | 943 | printf("invalid transition from %d to D2\n", (int)now); |
940 | return EINVAL; | | 944 | return EINVAL; |
941 | } | | 945 | } |
942 | if (!(cap & PCI_PMCR_D2SUPP)) { | | 946 | if (!(cap & PCI_PMCR_D2SUPP)) { |
943 | printf("D2 not supported\n"); | | 947 | printf("D2 not supported\n"); |
944 | return EOPNOTSUPP; | | 948 | return EOPNOTSUPP; |
945 | } | | 949 | } |
946 | break; | | 950 | break; |
947 | case PCI_PMCSR_STATE_D3: | | 951 | case PCI_PMCSR_STATE_D3: |
948 | break; | | 952 | break; |
949 | default: | | 953 | default: |
950 | return EINVAL; | | 954 | return EINVAL; |
951 | } | | 955 | } |
952 | value |= state; | | 956 | value |= state; |
953 | pci_conf_write(pc, tag, offset + PCI_PMCSR, value); | | 957 | pci_conf_write(pc, tag, offset + PCI_PMCSR, value); |
954 | /* delay according to pcipm1.2, ch. 5.6.1 */ | | 958 | /* delay according to pcipm1.2, ch. 5.6.1 */ |
955 | if (state == PCI_PMCSR_STATE_D3 || now == PCI_PMCSR_STATE_D3) | | 959 | if (state == PCI_PMCSR_STATE_D3 || now == PCI_PMCSR_STATE_D3) |
956 | DELAY(10000); | | 960 | DELAY(10000); |
957 | else if (state == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D2) | | 961 | else if (state == PCI_PMCSR_STATE_D2 || now == PCI_PMCSR_STATE_D2) |
958 | DELAY(200); | | 962 | DELAY(200); |
959 | | | 963 | |
960 | return 0; | | 964 | return 0; |
961 | } | | 965 | } |
962 | | | 966 | |
963 | int | | 967 | int |
964 | pci_set_powerstate(pci_chipset_tag_t pc, pcitag_t tag, pcireg_t state) | | 968 | pci_set_powerstate(pci_chipset_tag_t pc, pcitag_t tag, pcireg_t state) |
965 | { | | 969 | { |
966 | int offset; | | 970 | int offset; |
967 | pcireg_t value; | | 971 | pcireg_t value; |
968 | | | 972 | |
969 | if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value)) { | | 973 | if (!pci_get_capability(pc, tag, PCI_CAP_PWRMGMT, &offset, &value)) { |
970 | printf("pci_set_powerstate not supported\n"); | | 974 | printf("pci_set_powerstate not supported\n"); |
971 | return EOPNOTSUPP; | | 975 | return EOPNOTSUPP; |
972 | } | | 976 | } |
973 | | | 977 | |
974 | return pci_set_powerstate_int(pc, tag, state, offset, value); | | 978 | return pci_set_powerstate_int(pc, tag, state, offset, value); |
975 | } | | 979 | } |
976 | | | 980 | |
977 | int | | 981 | int |
978 | pci_activate(pci_chipset_tag_t pc, pcitag_t tag, device_t dev, | | 982 | pci_activate(pci_chipset_tag_t pc, pcitag_t tag, device_t dev, |
979 | int (*wakefun)(pci_chipset_tag_t, pcitag_t, device_t, pcireg_t)) | | 983 | int (*wakefun)(pci_chipset_tag_t, pcitag_t, device_t, pcireg_t)) |
980 | { | | 984 | { |
981 | pcireg_t pmode; | | 985 | pcireg_t pmode; |
982 | int error; | | 986 | int error; |
983 | | | 987 | |
984 | if ((error = pci_get_powerstate(pc, tag, &pmode))) | | 988 | if ((error = pci_get_powerstate(pc, tag, &pmode))) |
985 | return error; | | 989 | return error; |
986 | | | 990 | |
987 | switch (pmode) { | | 991 | switch (pmode) { |
988 | case PCI_PMCSR_STATE_D0: | | 992 | case PCI_PMCSR_STATE_D0: |
989 | break; | | 993 | break; |
990 | case PCI_PMCSR_STATE_D3: | | 994 | case PCI_PMCSR_STATE_D3: |
991 | if (wakefun == NULL) { | | 995 | if (wakefun == NULL) { |
992 | /* | | 996 | /* |
993 | * The card has lost all configuration data in | | 997 | * The card has lost all configuration data in |
994 | * this state, so punt. | | 998 | * this state, so punt. |
995 | */ | | 999 | */ |
996 | aprint_error_dev(dev, | | 1000 | aprint_error_dev(dev, |
997 | "unable to wake up from power state D3\n"); | | 1001 | "unable to wake up from power state D3\n"); |
998 | return EOPNOTSUPP; | | 1002 | return EOPNOTSUPP; |
999 | } | | 1003 | } |
1000 | /*FALLTHROUGH*/ | | 1004 | /*FALLTHROUGH*/ |
1001 | default: | | 1005 | default: |
1002 | if (wakefun) { | | 1006 | if (wakefun) { |
1003 | error = (*wakefun)(pc, tag, dev, pmode); | | 1007 | error = (*wakefun)(pc, tag, dev, pmode); |
1004 | if (error) | | 1008 | if (error) |
1005 | return error; | | 1009 | return error; |
1006 | } | | 1010 | } |
1007 | aprint_normal_dev(dev, "waking up from power state D%d\n", | | 1011 | aprint_normal_dev(dev, "waking up from power state D%d\n", |
1008 | pmode); | | 1012 | pmode); |
1009 | if ((error = pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0))) | | 1013 | if ((error = pci_set_powerstate(pc, tag, PCI_PMCSR_STATE_D0))) |
1010 | return error; | | 1014 | return error; |
1011 | } | | 1015 | } |
1012 | return 0; | | 1016 | return 0; |
1013 | } | | 1017 | } |
1014 | | | 1018 | |
1015 | int | | 1019 | int |
1016 | pci_activate_null(pci_chipset_tag_t pc, pcitag_t tag, | | 1020 | pci_activate_null(pci_chipset_tag_t pc, pcitag_t tag, |
1017 | device_t dev, pcireg_t state) | | 1021 | device_t dev, pcireg_t state) |
1018 | { | | 1022 | { |
1019 | return 0; | | 1023 | return 0; |
1020 | } | | 1024 | } |
1021 | | | 1025 | |
1022 | struct pci_child_power { | | 1026 | struct pci_child_power { |
1023 | struct pci_conf_state p_pciconf; | | 1027 | struct pci_conf_state p_pciconf; |
1024 | pci_chipset_tag_t p_pc; | | 1028 | pci_chipset_tag_t p_pc; |
1025 | pcitag_t p_tag; | | 1029 | pcitag_t p_tag; |
1026 | bool p_has_pm; | | 1030 | bool p_has_pm; |
1027 | int p_pm_offset; | | 1031 | int p_pm_offset; |
1028 | pcireg_t p_pm_cap; | | 1032 | pcireg_t p_pm_cap; |
1029 | pcireg_t p_class; | | 1033 | pcireg_t p_class; |
1030 | pcireg_t p_csr; | | 1034 | pcireg_t p_csr; |
1031 | }; | | 1035 | }; |
1032 | | | 1036 | |
1033 | static bool | | 1037 | static bool |
1034 | pci_child_suspend(device_t dv, const pmf_qual_t *qual) | | 1038 | pci_child_suspend(device_t dv, const pmf_qual_t *qual) |
1035 | { | | 1039 | { |
1036 | struct pci_child_power *priv = device_pmf_bus_private(dv); | | 1040 | struct pci_child_power *priv = device_pmf_bus_private(dv); |
1037 | pcireg_t ocsr, csr; | | 1041 | pcireg_t ocsr, csr; |
1038 | | | 1042 | |
1039 | pci_conf_capture(priv->p_pc, priv->p_tag, &priv->p_pciconf); | | 1043 | pci_conf_capture(priv->p_pc, priv->p_tag, &priv->p_pciconf); |
1040 | | | 1044 | |
1041 | if (!priv->p_has_pm) | | 1045 | if (!priv->p_has_pm) |
1042 | return true; /* ??? hopefully handled by ACPI */ | | 1046 | return true; /* ??? hopefully handled by ACPI */ |
1043 | if (PCI_CLASS(priv->p_class) == PCI_CLASS_DISPLAY) | | 1047 | if (PCI_CLASS(priv->p_class) == PCI_CLASS_DISPLAY) |
1044 | return true; /* XXX */ | | 1048 | return true; /* XXX */ |
1045 | | | 1049 | |
1046 | /* disable decoding and busmastering, see pcipm1.2 ch. 8.2.1 */ | | 1050 | /* disable decoding and busmastering, see pcipm1.2 ch. 8.2.1 */ |
1047 | ocsr = pci_conf_read(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG); | | 1051 | ocsr = pci_conf_read(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG); |
1048 | csr = ocsr & ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE | | 1052 | csr = ocsr & ~(PCI_COMMAND_IO_ENABLE | PCI_COMMAND_MEM_ENABLE |
1049 | | PCI_COMMAND_MASTER_ENABLE); | | 1053 | | PCI_COMMAND_MASTER_ENABLE); |
1050 | pci_conf_write(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG, csr); | | 1054 | pci_conf_write(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG, csr); |
1051 | if (pci_set_powerstate_int(priv->p_pc, priv->p_tag, | | 1055 | if (pci_set_powerstate_int(priv->p_pc, priv->p_tag, |
1052 | PCI_PMCSR_STATE_D3, priv->p_pm_offset, priv->p_pm_cap)) { | | 1056 | PCI_PMCSR_STATE_D3, priv->p_pm_offset, priv->p_pm_cap)) { |
1053 | pci_conf_write(priv->p_pc, priv->p_tag, | | 1057 | pci_conf_write(priv->p_pc, priv->p_tag, |
1054 | PCI_COMMAND_STATUS_REG, ocsr); | | 1058 | PCI_COMMAND_STATUS_REG, ocsr); |
1055 | aprint_error_dev(dv, "unsupported state, continuing.\n"); | | 1059 | aprint_error_dev(dv, "unsupported state, continuing.\n"); |
1056 | return false; | | 1060 | return false; |
1057 | } | | 1061 | } |
1058 | return true; | | 1062 | return true; |
1059 | } | | 1063 | } |
1060 | | | 1064 | |
1061 | static bool | | 1065 | static bool |
1062 | pci_child_resume(device_t dv, const pmf_qual_t *qual) | | 1066 | pci_child_resume(device_t dv, const pmf_qual_t *qual) |
1063 | { | | 1067 | { |
1064 | struct pci_child_power *priv = device_pmf_bus_private(dv); | | 1068 | struct pci_child_power *priv = device_pmf_bus_private(dv); |
1065 | | | 1069 | |
1066 | if (priv->p_has_pm && | | 1070 | if (priv->p_has_pm && |
1067 | pci_set_powerstate_int(priv->p_pc, priv->p_tag, | | 1071 | pci_set_powerstate_int(priv->p_pc, priv->p_tag, |
1068 | PCI_PMCSR_STATE_D0, priv->p_pm_offset, priv->p_pm_cap)) { | | 1072 | PCI_PMCSR_STATE_D0, priv->p_pm_offset, priv->p_pm_cap)) { |
1069 | aprint_error_dev(dv, "unsupported state, continuing.\n"); | | 1073 | aprint_error_dev(dv, "unsupported state, continuing.\n"); |
1070 | return false; | | 1074 | return false; |
1071 | } | | 1075 | } |
1072 | | | 1076 | |
1073 | pci_conf_restore(priv->p_pc, priv->p_tag, &priv->p_pciconf); | | 1077 | pci_conf_restore(priv->p_pc, priv->p_tag, &priv->p_pciconf); |
1074 | | | 1078 | |
1075 | return true; | | 1079 | return true; |
1076 | } | | 1080 | } |
1077 | | | 1081 | |
1078 | static bool | | 1082 | static bool |
1079 | pci_child_shutdown(device_t dv, int how) | | 1083 | pci_child_shutdown(device_t dv, int how) |
1080 | { | | 1084 | { |
1081 | struct pci_child_power *priv = device_pmf_bus_private(dv); | | 1085 | struct pci_child_power *priv = device_pmf_bus_private(dv); |
1082 | pcireg_t csr; | | 1086 | pcireg_t csr; |
1083 | | | 1087 | |
1084 | /* restore original bus-mastering state */ | | 1088 | /* restore original bus-mastering state */ |
1085 | csr = pci_conf_read(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG); | | 1089 | csr = pci_conf_read(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG); |
1086 | csr &= ~PCI_COMMAND_MASTER_ENABLE; | | 1090 | csr &= ~PCI_COMMAND_MASTER_ENABLE; |
1087 | csr |= priv->p_csr & PCI_COMMAND_MASTER_ENABLE; | | 1091 | csr |= priv->p_csr & PCI_COMMAND_MASTER_ENABLE; |
1088 | pci_conf_write(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG, csr); | | 1092 | pci_conf_write(priv->p_pc, priv->p_tag, PCI_COMMAND_STATUS_REG, csr); |
1089 | return true; | | 1093 | return true; |
1090 | } | | 1094 | } |
1091 | | | 1095 | |
1092 | static void | | 1096 | static void |
1093 | pci_child_deregister(device_t dv) | | 1097 | pci_child_deregister(device_t dv) |
1094 | { | | 1098 | { |
1095 | struct pci_child_power *priv = device_pmf_bus_private(dv); | | 1099 | struct pci_child_power *priv = device_pmf_bus_private(dv); |
1096 | | | 1100 | |
1097 | free(priv, M_DEVBUF); | | 1101 | free(priv, M_DEVBUF); |
1098 | } | | 1102 | } |
1099 | | | 1103 | |
1100 | static bool | | 1104 | static bool |
1101 | pci_child_register(device_t child) | | 1105 | pci_child_register(device_t child) |
1102 | { | | 1106 | { |
1103 | device_t self = device_parent(child); | | 1107 | device_t self = device_parent(child); |
1104 | struct pci_softc *sc = device_private(self); | | 1108 | struct pci_softc *sc = device_private(self); |
1105 | struct pci_child_power *priv; | | 1109 | struct pci_child_power *priv; |
1106 | int device, function, off; | | 1110 | int device, function, off; |
1107 | pcireg_t reg; | | 1111 | pcireg_t reg; |
1108 | | | 1112 | |
1109 | priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK); | | 1113 | priv = malloc(sizeof(*priv), M_DEVBUF, M_WAITOK); |
1110 | | | 1114 | |
1111 | device = device_locator(child, PCICF_DEV); | | 1115 | device = device_locator(child, PCICF_DEV); |
1112 | function = device_locator(child, PCICF_FUNCTION); | | 1116 | function = device_locator(child, PCICF_FUNCTION); |
1113 | | | 1117 | |
1114 | priv->p_pc = sc->sc_pc; | | 1118 | priv->p_pc = sc->sc_pc; |
1115 | priv->p_tag = pci_make_tag(priv->p_pc, sc->sc_bus, device, | | 1119 | priv->p_tag = pci_make_tag(priv->p_pc, sc->sc_bus, device, |
1116 | function); | | 1120 | function); |
1117 | priv->p_class = pci_conf_read(priv->p_pc, priv->p_tag, PCI_CLASS_REG); | | 1121 | priv->p_class = pci_conf_read(priv->p_pc, priv->p_tag, PCI_CLASS_REG); |
1118 | priv->p_csr = pci_conf_read(priv->p_pc, priv->p_tag, | | 1122 | priv->p_csr = pci_conf_read(priv->p_pc, priv->p_tag, |
1119 | PCI_COMMAND_STATUS_REG); | | 1123 | PCI_COMMAND_STATUS_REG); |
1120 | | | 1124 | |
1121 | if (pci_get_capability(priv->p_pc, priv->p_tag, | | 1125 | if (pci_get_capability(priv->p_pc, priv->p_tag, |
1122 | PCI_CAP_PWRMGMT, &off, ®)) { | | 1126 | PCI_CAP_PWRMGMT, &off, ®)) { |
1123 | priv->p_has_pm = true; | | 1127 | priv->p_has_pm = true; |
1124 | priv->p_pm_offset = off; | | 1128 | priv->p_pm_offset = off; |
1125 | priv->p_pm_cap = reg; | | 1129 | priv->p_pm_cap = reg; |
1126 | } else { | | 1130 | } else { |
1127 | priv->p_has_pm = false; | | 1131 | priv->p_has_pm = false; |
1128 | priv->p_pm_offset = -1; | | 1132 | priv->p_pm_offset = -1; |
1129 | } | | 1133 | } |
1130 | | | 1134 | |
1131 | device_pmf_bus_register(child, priv, pci_child_suspend, | | 1135 | device_pmf_bus_register(child, priv, pci_child_suspend, |
1132 | pci_child_resume, pci_child_shutdown, pci_child_deregister); | | 1136 | pci_child_resume, pci_child_shutdown, pci_child_deregister); |
1133 | | | 1137 | |
1134 | return true; | | 1138 | return true; |
1135 | } | | 1139 | } |
1136 | | | 1140 | |
1137 | MODULE(MODULE_CLASS_DRIVER, pci, NULL); | | 1141 | MODULE(MODULE_CLASS_DRIVER, pci, NULL); |
1138 | | | 1142 | |
1139 | static int | | 1143 | static int |
1140 | pci_modcmd(modcmd_t cmd, void *priv) | | 1144 | pci_modcmd(modcmd_t cmd, void *priv) |
1141 | { | | 1145 | { |
1142 | if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI) | | 1146 | if (cmd == MODULE_CMD_INIT || cmd == MODULE_CMD_FINI) |
1143 | return 0; | | 1147 | return 0; |
1144 | return ENOTTY; | | 1148 | return ENOTTY; |
1145 | } | | 1149 | } |