xref: /openbsd/sys/arch/amd64/pci/pchb.c (revision 4bdff4be)
1 /*	$OpenBSD: pchb.c,v 1.46 2022/02/21 11:03:39 mpi 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/ic/i82802reg.h>
72 
73 #include "agp.h"
74 
75 /* XXX should be in dev/ic/i82424{reg.var}.h */
76 #define I82424_CPU_BCTL_REG		0x53
77 #define I82424_PCI_BCTL_REG		0x54
78 
79 #define I82424_BCTL_CPUMEM_POSTEN	0x01
80 #define I82424_BCTL_CPUPCI_POSTEN	0x02
81 #define I82424_BCTL_PCIMEM_BURSTEN	0x01
82 #define I82424_BCTL_PCI_BURSTEN		0x02
83 
84 /* XXX should be in dev/ic/amd64htreg.h */
85 #define AMD64HT_LDT0_BUS	0x94
86 #define AMD64HT_LDT0_TYPE	0x98
87 #define AMD64HT_LDT1_BUS	0xb4
88 #define AMD64HT_LDT1_TYPE	0xb8
89 #define AMD64HT_LDT2_BUS	0xd4
90 #define AMD64HT_LDT2_TYPE	0xd8
91 #define AMD64HT_LDT3_BUS	0xf4
92 #define AMD64HT_LDT3_TYPE	0xf8
93 
94 #define AMD64HT_NUM_LDT		4
95 
96 #define AMD64HT_LDT_TYPE_MASK		0x0000001f
97 #define  AMD64HT_LDT_INIT_COMPLETE	0x00000002
98 #define  AMD64HT_LDT_NC			0x00000004
99 
100 #define AMD64HT_LDT_SEC_BUS_NUM(reg)	(((reg) >> 8) & 0xff)
101 
102 struct pchb_softc {
103 	struct device sc_dev;
104 
105 	bus_space_tag_t sc_bt;
106 	bus_space_handle_t sc_bh;
107 
108 	/* rng stuff */
109 	int sc_rng_active;
110 	int sc_rng_ax;
111 	int sc_rng_i;
112 	struct timeout sc_rng_to;
113 };
114 
115 int	pchbmatch(struct device *, void *, void *);
116 void	pchbattach(struct device *, struct device *, void *);
117 int	pchbactivate(struct device *, int);
118 
119 const struct cfattach pchb_ca = {
120 	sizeof(struct pchb_softc), pchbmatch, pchbattach, NULL,
121 	pchbactivate
122 };
123 
124 struct cfdriver pchb_cd = {
125 	NULL, "pchb", DV_DULL
126 };
127 
128 int	pchb_print(void *, const char *);
129 void	pchb_rnd(void *);
130 void	pchb_amd64ht_attach(struct device *, struct pci_attach_args *, int);
131 
132 int
133 pchbmatch(struct device *parent, void *match, void *aux)
134 {
135 	struct pci_attach_args *pa = aux;
136 
137 	if (PCI_CLASS(pa->pa_class) == PCI_CLASS_BRIDGE &&
138 	    PCI_SUBCLASS(pa->pa_class) == PCI_SUBCLASS_BRIDGE_HOST)
139 		return (1);
140 
141 	return (0);
142 }
143 
144 void
145 pchbattach(struct device *parent, struct device *self, void *aux)
146 {
147 	struct pchb_softc *sc = (struct pchb_softc *)self;
148 	struct pci_attach_args *pa = aux;
149 	struct pcibus_attach_args pba;
150 	pcireg_t bcreg, bir;
151 	u_char pbnum;
152 	pcitag_t tag;
153 	int i, r;
154 	int doattach = 0;
155 
156 	switch (PCI_VENDOR(pa->pa_id)) {
157 	case PCI_VENDOR_AMD:
158 		printf("\n");
159 		switch (PCI_PRODUCT(pa->pa_id)) {
160 		case PCI_PRODUCT_AMD_0F_HT:
161 		case PCI_PRODUCT_AMD_10_HT:
162 			for (i = 0; i < AMD64HT_NUM_LDT; i++)
163 				pchb_amd64ht_attach(self, pa, i);
164 			break;
165 		}
166 		break;
167 	case PCI_VENDOR_INTEL:
168 		switch (PCI_PRODUCT(pa->pa_id)) {
169 		case PCI_PRODUCT_INTEL_82915G_HB:
170 		case PCI_PRODUCT_INTEL_82945G_HB:
171 		case PCI_PRODUCT_INTEL_82925X_HB:
172 		case PCI_PRODUCT_INTEL_82955X_HB:
173 			sc->sc_bt = pa->pa_memt;
174 			if (bus_space_map(sc->sc_bt, I82802_IOBASE,
175 			    I82802_IOSIZE, 0, &sc->sc_bh))
176 				break;
177 
178 			/* probe and init rng */
179 			if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh,
180 			    I82802_RNG_HWST) & I82802_RNG_HWST_PRESENT))
181 				break;
182 
183 			/* enable RNG */
184 			bus_space_write_1(sc->sc_bt, sc->sc_bh,
185 			    I82802_RNG_HWST,
186 			    bus_space_read_1(sc->sc_bt, sc->sc_bh,
187 			    I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE);
188 
189 			/* see if we can read anything */
190 			for (i = 1000; i-- &&
191 			    !(bus_space_read_1(sc->sc_bt, sc->sc_bh,
192 			    I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV); )
193 				DELAY(10);
194 
195 			if (!(bus_space_read_1(sc->sc_bt, sc->sc_bh,
196 			    I82802_RNG_RNGST) & I82802_RNG_RNGST_DATAV))
197 				break;
198 
199 			r = bus_space_read_1(sc->sc_bt, sc->sc_bh,
200 			    I82802_RNG_DATA);
201 
202 			timeout_set(&sc->sc_rng_to, pchb_rnd, sc);
203 			sc->sc_rng_i = 4;
204 			pchb_rnd(sc);
205 			sc->sc_rng_active = 1;
206 			break;
207 		}
208 		printf("\n");
209 		break;
210 	case PCI_VENDOR_VIATECH:
211 		switch (PCI_PRODUCT(pa->pa_id)) {
212 		case PCI_PRODUCT_VIATECH_VT8251_PCIE_0:
213 			/*
214 			 * Bump the host bridge into PCI-PCI bridge
215 			 * mode by clearing magic bit on the VLINK
216 			 * device.  This allows us to read the bus
217 			 * number for the PCI bus attached to this
218 			 * host bridge.
219 			 */
220 			tag = pci_make_tag(pa->pa_pc, 0, 17, 7);
221 			bcreg = pci_conf_read(pa->pa_pc, tag, 0xfc);
222 			bcreg &= ~0x00000004; /* XXX Magic */
223 			pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg);
224 
225 			bir = pci_conf_read(pa->pa_pc,
226 			    pa->pa_tag, PPB_REG_BUSINFO);
227 			pbnum = PPB_BUSINFO_PRIMARY(bir);
228 			if (pbnum > 0)
229 				doattach = 1;
230 
231 			/* Switch back to host bridge mode. */
232 			bcreg |= 0x00000004; /* XXX Magic */
233 			pci_conf_write(pa->pa_pc, tag, 0xfc, bcreg);
234 			break;
235 		}
236 		printf("\n");
237 		break;
238 	default:
239 		printf("\n");
240 		break;
241 	}
242 
243 #if NAGP > 0
244 	/*
245 	 * Intel IGD have an odd interface and attach at vga, however,
246 	 * in that mode they don't have the AGP cap bit, so this
247 	 * test should be sufficient
248 	 */
249 	if (pci_get_capability(pa->pa_pc, pa->pa_tag, PCI_CAP_AGP,
250 	    NULL, NULL) != 0) {
251 		struct agp_attach_args	aa;
252 		aa.aa_busname = "agp";
253 		aa.aa_pa = pa;
254 
255 		config_found(self, &aa, agpdev_print);
256 	}
257 #endif /* NAGP > 0 */
258 
259 	if (doattach == 0)
260 		return;
261 
262 	bzero(&pba, sizeof(pba));
263 	pba.pba_busname = "pci";
264 	pba.pba_iot = pa->pa_iot;
265 	pba.pba_memt = pa->pa_memt;
266 	pba.pba_dmat = pa->pa_dmat;
267 	pba.pba_busex = pa->pa_busex;
268 	pba.pba_domain = pa->pa_domain;
269 	pba.pba_bus = pbnum;
270 	pba.pba_pc = pa->pa_pc;
271 	config_found(self, &pba, pchb_print);
272 }
273 
274 int
275 pchbactivate(struct device *self, int act)
276 {
277 	struct pchb_softc *sc = (struct pchb_softc *)self;
278 	int rv = 0;
279 
280 	switch (act) {
281 	case DVACT_RESUME:
282 		/* re-enable RNG, if we have it */
283 		if (sc->sc_rng_active)
284 			bus_space_write_1(sc->sc_bt, sc->sc_bh,
285 			    I82802_RNG_HWST,
286 			    bus_space_read_1(sc->sc_bt, sc->sc_bh,
287 			    I82802_RNG_HWST) | I82802_RNG_HWST_ENABLE);
288 		rv = config_activate_children(self, act);
289 		break;
290 	default:
291 		rv = config_activate_children(self, act);
292 		break;
293 	}
294 	return (rv);
295 }
296 
297 int
298 pchb_print(void *aux, const char *pnp)
299 {
300 	struct pcibus_attach_args *pba = aux;
301 
302 	if (pnp)
303 		printf("%s at %s", pba->pba_busname, pnp);
304 	printf(" bus %d", pba->pba_bus);
305 	return (UNCONF);
306 }
307 
308 /*
309  * Should do FIPS testing as per:
310  *	http://csrc.nist.gov/publications/fips/fips140-1/fips1401.pdf
311  */
312 void
313 pchb_rnd(void *v)
314 {
315 	struct pchb_softc *sc = v;
316 
317 	/*
318 	 * Don't wait for data to be ready. If it's not there, we'll check
319 	 * next time.
320 	 */
321 	if ((bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_RNGST) &
322 	    I82802_RNG_RNGST_DATAV)) {
323 
324 		sc->sc_rng_ax = (sc->sc_rng_ax << 8) |
325 		    bus_space_read_1(sc->sc_bt, sc->sc_bh, I82802_RNG_DATA);
326 
327 		if (!sc->sc_rng_i--) {
328 			sc->sc_rng_i = 4;
329 			enqueue_randomness(sc->sc_rng_ax);
330 		}
331 	}
332 
333 	timeout_add(&sc->sc_rng_to, 1);
334 }
335 
336 void
337 pchb_amd64ht_attach(struct device *self, struct pci_attach_args *pa, int i)
338 {
339 	struct pcibus_attach_args pba;
340 	pcireg_t type, bus;
341 	int reg;
342 
343 	reg = AMD64HT_LDT0_TYPE + i * 0x20;
344 	type = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
345 	if ((type & AMD64HT_LDT_INIT_COMPLETE) == 0 ||
346 	    (type & AMD64HT_LDT_NC) == 0)
347 		return;
348 
349 	reg = AMD64HT_LDT0_BUS + i * 0x20;
350 	bus = pci_conf_read(pa->pa_pc, pa->pa_tag, reg);
351 	if (AMD64HT_LDT_SEC_BUS_NUM(bus) > 0) {
352 		bzero(&pba, sizeof(pba));
353 		pba.pba_busname = "pci";
354 		pba.pba_iot = pa->pa_iot;
355 		pba.pba_memt = pa->pa_memt;
356 		pba.pba_dmat = pa->pa_dmat;
357 		pba.pba_busex = pa->pa_busex;
358 		pba.pba_domain = pa->pa_domain;
359 		pba.pba_bus = AMD64HT_LDT_SEC_BUS_NUM(bus);
360 		pba.pba_pc = pa->pa_pc;
361 		config_found(self, &pba, pchb_print);
362 	}
363 }
364