Line data Source code
1 : /* $OpenBSD: pchb.c,v 1.43 2018/04/28 15:44:59 jasper Exp $ */
2 : /* $NetBSD: pchb.c,v 1.1 2003/04/26 18:39:50 fvdl Exp $ */
3 : /*
4 : * Copyright (c) 2000 Michael Shalayeff
5 : * All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : *
16 : * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 : * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 : * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 : * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20 : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 : * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22 : * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24 : * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25 : * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26 : * THE POSSIBILITY OF SUCH DAMAGE.
27 : */
28 : /*-
29 : * Copyright (c) 1996, 1998, 2000 The NetBSD Foundation, Inc.
30 : * All rights reserved.
31 : *
32 : * This code is derived from software contributed to The NetBSD Foundation
33 : * by Jason R. Thorpe.
34 : *
35 : * Redistribution and use in source and binary forms, with or without
36 : * modification, are permitted provided that the following conditions
37 : * are met:
38 : * 1. Redistributions of source code must retain the above copyright
39 : * notice, this list of conditions and the following disclaimer.
40 : * 2. Redistributions in binary form must reproduce the above copyright
41 : * notice, this list of conditions and the following disclaimer in the
42 : * documentation and/or other materials provided with the distribution.
43 : *
44 : * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
45 : * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
46 : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47 : * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
48 : * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 : * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 : * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 : * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 : * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54 : * POSSIBILITY OF SUCH DAMAGE.
55 : */
56 :
57 : #include <sys/param.h>
58 : #include <sys/systm.h>
59 : #include <sys/device.h>
60 : #include <sys/timeout.h>
61 :
62 : #include <machine/bus.h>
63 :
64 : #include <dev/pci/pcivar.h>
65 : #include <dev/pci/pcireg.h>
66 : #include <dev/pci/pcidevs.h>
67 :
68 : #include <dev/pci/agpvar.h>
69 : #include <dev/pci/ppbreg.h>
70 :
71 : #include <dev/rndvar.h>
72 :
73 : #include <dev/ic/i82802reg.h>
74 :
75 : #include "agp.h"
76 :
77 : /* XXX should be in dev/ic/i82424{reg.var}.h */
78 : #define I82424_CPU_BCTL_REG 0x53
79 : #define I82424_PCI_BCTL_REG 0x54
80 :
81 : #define I82424_BCTL_CPUMEM_POSTEN 0x01
82 : #define I82424_BCTL_CPUPCI_POSTEN 0x02
83 : #define I82424_BCTL_PCIMEM_BURSTEN 0x01
84 : #define I82424_BCTL_PCI_BURSTEN 0x02
85 :
86 : /* XXX should be in dev/ic/amd64htreg.h */
87 : #define AMD64HT_LDT0_BUS 0x94
88 : #define AMD64HT_LDT0_TYPE 0x98
89 : #define AMD64HT_LDT1_BUS 0xb4
90 : #define AMD64HT_LDT1_TYPE 0xb8
91 : #define AMD64HT_LDT2_BUS 0xd4
92 : #define AMD64HT_LDT2_TYPE 0xd8
93 : #define AMD64HT_LDT3_BUS 0xf4
94 : #define AMD64HT_LDT3_TYPE 0xf8
95 :
96 : #define AMD64HT_NUM_LDT 4
97 :
98 : #define AMD64HT_LDT_TYPE_MASK 0x0000001f
99 : #define AMD64HT_LDT_INIT_COMPLETE 0x00000002
100 : #define AMD64HT_LDT_NC 0x00000004
101 :
102 : #define AMD64HT_LDT_SEC_BUS_NUM(reg) (((reg) >> 8) & 0xff)
103 :
104 : struct pchb_softc {
105 : struct device sc_dev;
106 :
107 : bus_space_tag_t sc_bt;
108 : bus_space_handle_t sc_bh;
109 :
110 : /* rng stuff */
111 : int sc_rng_active;
112 : int sc_rng_ax;
113 : int sc_rng_i;
114 : struct timeout sc_rng_to;
115 : };
116 :
117 : int pchbmatch(struct device *, void *, void *);
118 : void pchbattach(struct device *, struct device *, void *);
119 : int pchbactivate(struct device *, int);
120 :
121 : struct cfattach pchb_ca = {
122 : sizeof(struct pchb_softc), pchbmatch, pchbattach, NULL,
123 : pchbactivate
124 : };
125 :
126 : struct cfdriver pchb_cd = {
127 : NULL, "pchb", DV_DULL
128 : };
129 :
130 : int pchb_print(void *, const char *);
131 : void pchb_rnd(void *);
132 : void pchb_amd64ht_attach(struct device *, struct pci_attach_args *, int);
133 :
134 : int
135 0 : pchbmatch(struct device *parent, void *match, void *aux)
136 : {
137 0 : struct pci_attach_args *pa = aux;
138 :
139 0 : if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
140 0 : PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
141 0 : return (1);
142 :
143 0 : return (0);
144 0 : }
145 :
146 : void
147 0 : pchbattach(struct device *parent, struct device *self, void *aux)
148 : {
149 0 : struct pchb_softc *sc = (struct pchb_softc *)self;
150 0 : struct pci_attach_args *pa = aux;
151 0 : struct pcibus_attach_args pba;
152 : pcireg_t bcreg, bir;
153 : u_char pbnum;
154 : pcitag_t tag;
155 : int i, r;
156 : int doattach = 0;
157 :
158 0 : switch (PCI_VENDOR(pa->pa_id)) {
159 : case PCI_VENDOR_AMD:
160 0 : printf("\n");
161 0 : switch (PCI_PRODUCT(pa->pa_id)) {
162 : case PCI_PRODUCT_AMD_AMD64_0F_HT:
163 : case PCI_PRODUCT_AMD_AMD64_10_HT:
164 0 : for (i = 0; i < AMD64HT_NUM_LDT; i++)
165 0 : pchb_amd64ht_attach(self, pa, i);
166 : break;
167 : }
168 : break;
169 : case PCI_VENDOR_INTEL:
170 0 : switch (PCI_PRODUCT(pa->pa_id)) {
171 : case PCI_PRODUCT_INTEL_82915G_HB:
172 : case PCI_PRODUCT_INTEL_82945G_HB:
173 : case PCI_PRODUCT_INTEL_82925X_HB:
174 : case PCI_PRODUCT_INTEL_82955X_HB:
175 0 : sc->sc_bt = pa->pa_memt;
176 0 : if (bus_space_map(sc->sc_bt, I82802_IOBASE,
177 0 : I82802_IOSIZE, 0, &sc->sc_bh))
178 : break;
179 :
180 : /* probe and init rng */
181 0 : if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh,
182 0 : I82802_RNG_HWST) & I82802_RNG_HWST_PRESENT))
183 : break;
184 :
185 : /* enable RNG */
186 0 : bus_space_write_1(sc->sc_bt, sc->sc_bh,
187 : I82802_RNG_HWST,
188 : bus_space_read_1(sc->sc_bt, sc->sc_bh,
189 : I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE);
190 :
191 : /* see if we can read anything */
192 0 : for (i = 1000; i-- &&
193 0 : !(bus_space_read_1(sc->sc_bt, sc->sc_bh,
194 0 : I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV); )
195 0 : DELAY(10);
196 :
197 0 : if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh,
198 0 : I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV))
199 : break;
200 :
201 0 : r = bus_space_read_1(sc->sc_bt, sc->sc_bh,
202 : I82802_RNG_DATA);
203 :
204 0 : timeout_set(&sc->sc_rng_to, pchb_rnd, sc);
205 0 : sc->sc_rng_i = 4;
206 0 : pchb_rnd(sc);
207 0 : sc->sc_rng_active = 1;
208 0 : break;
209 : }
210 0 : printf("\n");
211 0 : break;
212 : case PCI_VENDOR_VIATECH:
213 0 : switch (PCI_PRODUCT(pa->pa_id)) {
214 : case PCI_PRODUCT_VIATECH_VT8251_PCIE_0:
215 : /*
216 : * Bump the host bridge into PCI-PCI bridge
217 : * mode by clearing magic bit on the VLINK
218 : * device. This allows us to read the bus
219 : * number for the PCI bus attached to this
220 : * host bridge.
221 : */
222 0 : tag = pci_make_tag(pa->pa_pc, 0, 17, 7);
223 0 : bcreg = pci_conf_read(pa->pa_pc, tag, 0xfc);
224 0 : bcreg &= ~0x00000004; /* XXX Magic */
225 0 : pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg);
226 :
227 0 : bir = pci_conf_read(pa->pa_pc,
228 0 : pa->pa_tag, PPB_REG_BUSINFO);
229 0 : pbnum = PPB_BUSINFO_PRIMARY(bir);
230 0 : if (pbnum > 0)
231 0 : doattach = 1;
232 :
233 : /* Switch back to host bridge mode. */
234 0 : bcreg |= 0x00000004; /* XXX Magic */
235 0 : pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg);
236 0 : break;
237 : }
238 0 : printf("\n");
239 0 : break;
240 : default:
241 0 : printf("\n");
242 0 : break;
243 : }
244 :
245 : #if NAGP > 0
246 : /*
247 : * Intel IGD have an odd interface and attach at vga, however,
248 : * in that mode they don't have the AGP cap bit, so this
249 : * test should be sufficient
250 : */
251 0 : if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
252 0 : NULL, NULL) != 0) {
253 0 : struct agp_attach_args aa;
254 0 : aa.aa_busname = "agp";
255 0 : aa.aa_pa = pa;
256 :
257 0 : config_found(self, &aa, agpdev_print);
258 0 : }
259 : #endif /* NAGP > 0 */
260 :
261 0 : if (doattach == 0)
262 0 : return;
263 :
264 0 : bzero(&pba, sizeof(pba));
265 0 : pba.pba_busname = "pci";
266 0 : pba.pba_iot = pa->pa_iot;
267 0 : pba.pba_memt = pa->pa_memt;
268 0 : pba.pba_dmat = pa->pa_dmat;
269 0 : pba.pba_busex = pa->pa_busex;
270 0 : pba.pba_domain = pa->pa_domain;
271 0 : pba.pba_bus = pbnum;
272 0 : pba.pba_pc = pa->pa_pc;
273 0 : config_found(self, &pba, pchb_print);
274 0 : }
275 :
276 : int
277 0 : pchbactivate(struct device *self, int act)
278 : {
279 0 : struct pchb_softc *sc = (struct pchb_softc *)self;
280 : int rv = 0;
281 :
282 0 : switch (act) {
283 : case DVACT_RESUME:
284 : /* re-enable RNG, if we have it */
285 0 : if (sc->sc_rng_active)
286 0 : bus_space_write_1(sc->sc_bt, sc->sc_bh,
287 : I82802_RNG_HWST,
288 : bus_space_read_1(sc->sc_bt, sc->sc_bh,
289 : I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE);
290 0 : rv = config_activate_children(self, act);
291 0 : break;
292 : default:
293 0 : rv = config_activate_children(self, act);
294 0 : break;
295 : }
296 0 : return (rv);
297 : }
298 :
299 : int
300 0 : pchb_print(void *aux, const char *pnp)
301 : {
302 0 : struct pcibus_attach_args *pba = aux;
303 :
304 0 : if (pnp)
305 0 : printf("%s at %s", pba->pba_busname, pnp);
306 0 : printf(" bus %d", pba->pba_bus);
307 0 : return (UNCONF);
308 : }
309 :
310 : /*
311 : * Should do FIPS testing as per:
312 : * http://csrc.nist.gov/publications/fips/fips140-1/fips1401.pdf
313 : */
314 : void
315 0 : pchb_rnd(void *v)
316 : {
317 0 : struct pchb_softc *sc = v;
318 :
319 : /*
320 : * Don't wait for data to be ready. If it's not there, we'll check
321 : * next time.
322 : */
323 0 : if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_RNGST) &
324 : I82802_RNG_RNGST_DATAV)) {
325 :
326 0 : sc->sc_rng_ax = (sc->sc_rng_ax << 8) |
327 0 : bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_DATA);
328 :
329 0 : if (!sc->sc_rng_i--) {
330 0 : sc->sc_rng_i = 4;
331 0 : enqueue_randomness(sc->sc_rng_ax);
332 0 : }
333 : }
334 :
335 0 : timeout_add(&sc->sc_rng_to, 1);
336 0 : }
337 :
338 : void
339 0 : pchb_amd64ht_attach(struct device *self, struct pci_attach_args *pa, int i)
340 : {
341 0 : struct pcibus_attach_args pba;
342 : pcireg_t type, bus;
343 : int reg;
344 :
345 0 : reg = AMD64HT_LDT0_TYPE + i * 0x20;
346 0 : type = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
347 0 : if ((type & AMD64HT_LDT_INIT_COMPLETE) == 0 ||
348 0 : (type & AMD64HT_LDT_NC) == 0)
349 0 : return;
350 :
351 0 : reg = AMD64HT_LDT0_BUS + i * 0x20;
352 0 : bus = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
353 0 : if (AMD64HT_LDT_SEC_BUS_NUM(bus) > 0) {
354 0 : bzero(&pba, sizeof(pba));
355 0 : pba.pba_busname = "pci";
356 0 : pba.pba_iot = pa->pa_iot;
357 0 : pba.pba_memt = pa->pa_memt;
358 0 : pba.pba_dmat = pa->pa_dmat;
359 0 : pba.pba_busex = pa->pa_busex;
360 0 : pba.pba_domain = pa->pa_domain;
361 0 : pba.pba_bus = AMD64HT_LDT_SEC_BUS_NUM(bus);
362 0 : pba.pba_pc = pa->pa_pc;
363 0 : config_found(self, &pba, pchb_print);
364 0 : }
365 0 : }
|