xref: /openbsd/sys/arch/amd64/pci/pchb.c (revision 274d7c50)
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 pchbmatch(struct device *parent, void *match, void *aux)
136 {
137 	struct pci_attach_args *pa = aux;
138 
139 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
140 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
141 		return (1);
142 
143 	return (0);
144 }
145 
146 void
147 pchbattach(struct device *parent, struct device *self, void *aux)
148 {
149 	struct pchb_softc *sc = (struct pchb_softc *)self;
150 	struct pci_attach_args *pa = aux;
151 	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 	switch (PCI_VENDOR(pa->pa_id)) {
159 	case PCI_VENDOR_AMD:
160 		printf("\n");
161 		switch (PCI_PRODUCT(pa->pa_id)) {
162 		case PCI_PRODUCT_AMD_AMD64_0F_HT:
163 		case PCI_PRODUCT_AMD_AMD64_10_HT:
164 			for (i = 0; i < AMD64HT_NUM_LDT; i++)
165 				pchb_amd64ht_attach(self, pa, i);
166 			break;
167 		}
168 		break;
169 	case PCI_VENDOR_INTEL:
170 		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 			sc->sc_bt = pa->pa_memt;
176 			if (bus_space_map(sc->sc_bt, I82802_IOBASE,
177 			    I82802_IOSIZE, 0, &sc->sc_bh))
178 				break;
179 
180 			/* probe and init rng */
181 			if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh,
182 			    I82802_RNG_HWST) & I82802_RNG_HWST_PRESENT))
183 				break;
184 
185 			/* enable RNG */
186 			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 			for (i = 1000; i-- &&
193 			    !(bus_space_read_1(sc->sc_bt, sc->sc_bh,
194 			    I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV); )
195 				DELAY(10);
196 
197 			if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh,
198 			    I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV))
199 				break;
200 
201 			r = bus_space_read_1(sc->sc_bt, sc->sc_bh,
202 			    I82802_RNG_DATA);
203 
204 			timeout_set(&sc->sc_rng_to, pchb_rnd, sc);
205 			sc->sc_rng_i = 4;
206 			pchb_rnd(sc);
207 			sc->sc_rng_active = 1;
208 			break;
209 		}
210 		printf("\n");
211 		break;
212 	case PCI_VENDOR_VIATECH:
213 		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 			tag = pci_make_tag(pa->pa_pc, 0, 17, 7);
223 			bcreg = pci_conf_read(pa->pa_pc, tag, 0xfc);
224 			bcreg &= ~0x00000004; /* XXX Magic */
225 			pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg);
226 
227 			bir = pci_conf_read(pa->pa_pc,
228 			    pa->pa_tag, PPB_REG_BUSINFO);
229 			pbnum = PPB_BUSINFO_PRIMARY(bir);
230 			if (pbnum > 0)
231 				doattach = 1;
232 
233 			/* Switch back to host bridge mode. */
234 			bcreg |= 0x00000004; /* XXX Magic */
235 			pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg);
236 			break;
237 		}
238 		printf("\n");
239 		break;
240 	default:
241 		printf("\n");
242 		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 	if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
252 	    NULL, NULL) != 0) {
253 		struct agp_attach_args	aa;
254 		aa.aa_busname = "agp";
255 		aa.aa_pa = pa;
256 
257 		config_found(self, &aa, agpdev_print);
258 	}
259 #endif /* NAGP > 0 */
260 
261 	if (doattach == 0)
262 		return;
263 
264 	bzero(&pba, sizeof(pba));
265 	pba.pba_busname = "pci";
266 	pba.pba_iot = pa->pa_iot;
267 	pba.pba_memt = pa->pa_memt;
268 	pba.pba_dmat = pa->pa_dmat;
269 	pba.pba_busex = pa->pa_busex;
270 	pba.pba_domain = pa->pa_domain;
271 	pba.pba_bus = pbnum;
272 	pba.pba_pc = pa->pa_pc;
273 	config_found(self, &pba, pchb_print);
274 }
275 
276 int
277 pchbactivate(struct device *self, int act)
278 {
279 	struct pchb_softc *sc = (struct pchb_softc *)self;
280 	int rv = 0;
281 
282 	switch (act) {
283 	case DVACT_RESUME:
284 		/* re-enable RNG, if we have it */
285 		if (sc->sc_rng_active)
286 			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 		rv = config_activate_children(self, act);
291 		break;
292 	default:
293 		rv = config_activate_children(self, act);
294 		break;
295 	}
296 	return (rv);
297 }
298 
299 int
300 pchb_print(void *aux, const char *pnp)
301 {
302 	struct pcibus_attach_args *pba = aux;
303 
304 	if (pnp)
305 		printf("%s at %s", pba->pba_busname, pnp);
306 	printf(" bus %d", pba->pba_bus);
307 	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 pchb_rnd(void *v)
316 {
317 	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 	if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_RNGST) &
324 	    I82802_RNG_RNGST_DATAV)) {
325 
326 		sc->sc_rng_ax = (sc->sc_rng_ax << 8) |
327 		    bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_DATA);
328 
329 		if (!sc->sc_rng_i--) {
330 			sc->sc_rng_i = 4;
331 			enqueue_randomness(sc->sc_rng_ax);
332 		}
333 	}
334 
335 	timeout_add(&sc->sc_rng_to, 1);
336 }
337 
338 void
339 pchb_amd64ht_attach(struct device *self, struct pci_attach_args *pa, int i)
340 {
341 	struct pcibus_attach_args pba;
342 	pcireg_t type, bus;
343 	int reg;
344 
345 	reg = AMD64HT_LDT0_TYPE + i * 0x20;
346 	type = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
347 	if ((type & AMD64HT_LDT_INIT_COMPLETE) == 0 ||
348 	    (type & AMD64HT_LDT_NC) == 0)
349 		return;
350 
351 	reg = AMD64HT_LDT0_BUS + i * 0x20;
352 	bus = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
353 	if (AMD64HT_LDT_SEC_BUS_NUM(bus) > 0) {
354 		bzero(&pba, sizeof(pba));
355 		pba.pba_busname = "pci";
356 		pba.pba_iot = pa->pa_iot;
357 		pba.pba_memt = pa->pa_memt;
358 		pba.pba_dmat = pa->pa_dmat;
359 		pba.pba_busex = pa->pa_busex;
360 		pba.pba_domain = pa->pa_domain;
361 		pba.pba_bus = AMD64HT_LDT_SEC_BUS_NUM(bus);
362 		pba.pba_pc = pa->pa_pc;
363 		config_found(self, &pba, pchb_print);
364 	}
365 }
366