xref: /freebsd/sys/x86/pci/qpi.c (revision 179fa75e6e218d71a85a6b17ccc231036a148543)
1c2175767SJohn Baldwin /*-
2*179fa75eSJohn Baldwin  * Copyright (c) 2010 Hudson River Trading LLC
3c2175767SJohn Baldwin  * Written by: John H. Baldwin <jhb@FreeBSD.org>
4c2175767SJohn Baldwin  * All rights reserved.
5c2175767SJohn Baldwin  *
6c2175767SJohn Baldwin  * Redistribution and use in source and binary forms, with or without
7c2175767SJohn Baldwin  * modification, are permitted provided that the following conditions
8c2175767SJohn Baldwin  * are met:
9c2175767SJohn Baldwin  * 1. Redistributions of source code must retain the above copyright
10c2175767SJohn Baldwin  *    notice, this list of conditions and the following disclaimer.
11c2175767SJohn Baldwin  * 2. Redistributions in binary form must reproduce the above copyright
12c2175767SJohn Baldwin  *    notice, this list of conditions and the following disclaimer in the
13c2175767SJohn Baldwin  *    documentation and/or other materials provided with the distribution.
14c2175767SJohn Baldwin  *
15c2175767SJohn Baldwin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16c2175767SJohn Baldwin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17c2175767SJohn Baldwin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18c2175767SJohn Baldwin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19c2175767SJohn Baldwin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20c2175767SJohn Baldwin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21c2175767SJohn Baldwin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22c2175767SJohn Baldwin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23c2175767SJohn Baldwin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24c2175767SJohn Baldwin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25c2175767SJohn Baldwin  * SUCH DAMAGE.
26c2175767SJohn Baldwin  */
27c2175767SJohn Baldwin 
28c2175767SJohn Baldwin /*
29c2175767SJohn Baldwin  * This driver provides a psuedo-bus to enumerate the PCI buses
30c2175767SJohn Baldwin  * present on a sytem using a QPI chipset.  It creates a qpi0 bus that
31c2175767SJohn Baldwin  * is a child of nexus0 and then creates two Host-PCI bridges as a
32c2175767SJohn Baldwin  * child of that.
33c2175767SJohn Baldwin  */
34c2175767SJohn Baldwin 
35c2175767SJohn Baldwin #include <sys/cdefs.h>
36c2175767SJohn Baldwin __FBSDID("$FreeBSD$");
37c2175767SJohn Baldwin 
38c2175767SJohn Baldwin #include <sys/param.h>
39c2175767SJohn Baldwin #include <sys/bus.h>
40c2175767SJohn Baldwin #include <sys/kernel.h>
41c2175767SJohn Baldwin #include <sys/malloc.h>
42c2175767SJohn Baldwin #include <sys/module.h>
4383c41143SJohn Baldwin #include <sys/rman.h>
44c2175767SJohn Baldwin #include <sys/systm.h>
45c2175767SJohn Baldwin 
46c2175767SJohn Baldwin #include <machine/cputypes.h>
47c2175767SJohn Baldwin #include <machine/md_var.h>
4884ca9aadSJohn Baldwin #include <x86/legacyvar.h>
4984ca9aadSJohn Baldwin #include <x86/pci_cfgreg.h>
5084ca9aadSJohn Baldwin #include <x86/specialreg.h>
51c2175767SJohn Baldwin 
52e83ea624SJohn Baldwin #include <dev/pci/pcireg.h>
53c2175767SJohn Baldwin #include <dev/pci/pcivar.h>
54c2175767SJohn Baldwin #include <dev/pci/pcib_private.h>
55c2175767SJohn Baldwin #include "pcib_if.h"
56c2175767SJohn Baldwin 
57c2175767SJohn Baldwin struct qpi_device {
58c2175767SJohn Baldwin 	int	qd_pcibus;
59c2175767SJohn Baldwin };
60c2175767SJohn Baldwin 
61c2175767SJohn Baldwin static MALLOC_DEFINE(M_QPI, "qpidrv", "qpi system device");
62c2175767SJohn Baldwin 
63c2175767SJohn Baldwin static void
64c2175767SJohn Baldwin qpi_identify(driver_t *driver, device_t parent)
65c2175767SJohn Baldwin {
66c2175767SJohn Baldwin 
67c2175767SJohn Baldwin         /* Check CPUID to ensure this is an i7 CPU of some sort. */
688bddaf90SJohn Baldwin         if (!(cpu_vendor_id == CPU_VENDOR_INTEL &&
698bddaf90SJohn Baldwin 	    CPUID_TO_FAMILY(cpu_id) == 0x6 &&
70c2175767SJohn Baldwin 	    (CPUID_TO_MODEL(cpu_id) == 0x1a || CPUID_TO_MODEL(cpu_id) == 0x2c)))
71c2175767SJohn Baldwin                 return;
72c2175767SJohn Baldwin 
73c2175767SJohn Baldwin         /* PCI config register access is required. */
74c2175767SJohn Baldwin         if (pci_cfgregopen() == 0)
75c2175767SJohn Baldwin                 return;
76c2175767SJohn Baldwin 
77c2175767SJohn Baldwin 	/* Add a qpi bus device. */
78c2175767SJohn Baldwin 	if (BUS_ADD_CHILD(parent, 20, "qpi", -1) == NULL)
79c2175767SJohn Baldwin 		panic("Failed to add qpi bus");
80c2175767SJohn Baldwin }
81c2175767SJohn Baldwin 
82c2175767SJohn Baldwin static int
83c2175767SJohn Baldwin qpi_probe(device_t dev)
84c2175767SJohn Baldwin {
85c2175767SJohn Baldwin 
86c2175767SJohn Baldwin 	device_set_desc(dev, "QPI system bus");
87c2175767SJohn Baldwin 	return (BUS_PROBE_SPECIFIC);
88c2175767SJohn Baldwin }
89c2175767SJohn Baldwin 
90e83ea624SJohn Baldwin /*
91e83ea624SJohn Baldwin  * Look for a PCI bus with the specified bus address.  If one is found,
92e83ea624SJohn Baldwin  * add a pcib device and return 0.  Otherwise, return an error code.
93e83ea624SJohn Baldwin  */
94c2175767SJohn Baldwin static int
95e83ea624SJohn Baldwin qpi_probe_pcib(device_t dev, int bus)
96c2175767SJohn Baldwin {
97c2175767SJohn Baldwin 	struct qpi_device *qdev;
98c2175767SJohn Baldwin 	device_t child;
99e83ea624SJohn Baldwin 	uint32_t devid;
100c2175767SJohn Baldwin 
101c2175767SJohn Baldwin 	/*
102e83ea624SJohn Baldwin 	 * If a PCI bus already exists for this bus number, then
103e83ea624SJohn Baldwin 	 * fail.
104c2175767SJohn Baldwin 	 */
105e83ea624SJohn Baldwin 	if (pci_find_bsf(bus, 0, 0) != NULL)
106e83ea624SJohn Baldwin 		return (EEXIST);
107e83ea624SJohn Baldwin 
108e83ea624SJohn Baldwin 	/*
109e83ea624SJohn Baldwin 	 * Attempt to read the device id for device 0, function 0 on
110e83ea624SJohn Baldwin 	 * the bus.  A value of 0xffffffff means that the bus is not
111e83ea624SJohn Baldwin 	 * present.
112e83ea624SJohn Baldwin 	 */
113e83ea624SJohn Baldwin 	devid = pci_cfgregread(bus, 0, 0, PCIR_DEVVENDOR, 4);
114e83ea624SJohn Baldwin 	if (devid == 0xffffffff)
115e83ea624SJohn Baldwin 		return (ENOENT);
116e83ea624SJohn Baldwin 
117e83ea624SJohn Baldwin 	if ((devid & 0xffff) != 0x8086) {
118e83ea624SJohn Baldwin 		device_printf(dev,
119e83ea624SJohn Baldwin 		    "Device at pci%d.0.0 has non-Intel vendor 0x%x\n", bus,
120e83ea624SJohn Baldwin 		    devid & 0xffff);
121e83ea624SJohn Baldwin 		return (ENXIO);
122e83ea624SJohn Baldwin 	}
123c2175767SJohn Baldwin 
124c2175767SJohn Baldwin 	child = BUS_ADD_CHILD(dev, 0, "pcib", -1);
125c2175767SJohn Baldwin 	if (child == NULL)
126e83ea624SJohn Baldwin 		panic("%s: failed to add pci bus %d", device_get_nameunit(dev),
127e83ea624SJohn Baldwin 		    bus);
128c2175767SJohn Baldwin 	qdev = malloc(sizeof(struct qpi_device), M_QPI, M_WAITOK);
129e83ea624SJohn Baldwin 	qdev->qd_pcibus = bus;
130c2175767SJohn Baldwin 	device_set_ivars(child, qdev);
131e83ea624SJohn Baldwin 	return (0);
132e83ea624SJohn Baldwin }
133e83ea624SJohn Baldwin 
134e83ea624SJohn Baldwin static int
135e83ea624SJohn Baldwin qpi_attach(device_t dev)
136e83ea624SJohn Baldwin {
137e83ea624SJohn Baldwin 	int bus;
138e83ea624SJohn Baldwin 
139e83ea624SJohn Baldwin 	/*
140e83ea624SJohn Baldwin 	 * Each processor socket has a dedicated PCI bus counting down from
141e83ea624SJohn Baldwin 	 * 255.  We keep probing buses until one fails.
142e83ea624SJohn Baldwin 	 */
143e83ea624SJohn Baldwin 	for (bus = 255;; bus--)
144e83ea624SJohn Baldwin 		if (qpi_probe_pcib(dev, bus) != 0)
145e83ea624SJohn Baldwin 			break;
146c2175767SJohn Baldwin 
147c2175767SJohn Baldwin 	return (bus_generic_attach(dev));
148c2175767SJohn Baldwin }
149c2175767SJohn Baldwin 
150c2175767SJohn Baldwin static int
151c2175767SJohn Baldwin qpi_print_child(device_t bus, device_t child)
152c2175767SJohn Baldwin {
153c2175767SJohn Baldwin 	struct qpi_device *qdev;
154c2175767SJohn Baldwin 	int retval = 0;
155c2175767SJohn Baldwin 
156c2175767SJohn Baldwin 	qdev = device_get_ivars(child);
157c2175767SJohn Baldwin 	retval += bus_print_child_header(bus, child);
158c2175767SJohn Baldwin 	if (qdev->qd_pcibus != -1)
159c2175767SJohn Baldwin 		retval += printf(" pcibus %d", qdev->qd_pcibus);
160c2175767SJohn Baldwin 	retval += bus_print_child_footer(bus, child);
161c2175767SJohn Baldwin 
162c2175767SJohn Baldwin 	return (retval);
163c2175767SJohn Baldwin }
164c2175767SJohn Baldwin 
165c2175767SJohn Baldwin static int
166c2175767SJohn Baldwin qpi_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
167c2175767SJohn Baldwin {
168c2175767SJohn Baldwin 	struct qpi_device *qdev;
169c2175767SJohn Baldwin 
170c2175767SJohn Baldwin 	qdev = device_get_ivars(child);
171c2175767SJohn Baldwin 	switch (which) {
172c2175767SJohn Baldwin 	case PCIB_IVAR_BUS:
173c2175767SJohn Baldwin 		*result = qdev->qd_pcibus;
174c2175767SJohn Baldwin 		break;
175c2175767SJohn Baldwin 	default:
176c2175767SJohn Baldwin 		return (ENOENT);
177c2175767SJohn Baldwin 	}
178c2175767SJohn Baldwin 	return (0);
179c2175767SJohn Baldwin }
180c2175767SJohn Baldwin 
181c2175767SJohn Baldwin static device_method_t qpi_methods[] = {
182c2175767SJohn Baldwin 	/* Device interface */
183c2175767SJohn Baldwin 	DEVMETHOD(device_identify,	qpi_identify),
184c2175767SJohn Baldwin 	DEVMETHOD(device_probe,		qpi_probe),
185c2175767SJohn Baldwin 	DEVMETHOD(device_attach,	qpi_attach),
186c2175767SJohn Baldwin 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
187c2175767SJohn Baldwin 	DEVMETHOD(device_suspend,	bus_generic_suspend),
188c2175767SJohn Baldwin 	DEVMETHOD(device_resume,	bus_generic_resume),
189c2175767SJohn Baldwin 
190c2175767SJohn Baldwin 	/* Bus interface */
191c2175767SJohn Baldwin 	DEVMETHOD(bus_print_child,	qpi_print_child),
192c2175767SJohn Baldwin 	DEVMETHOD(bus_add_child,	bus_generic_add_child),
193c2175767SJohn Baldwin 	DEVMETHOD(bus_read_ivar,	qpi_read_ivar),
194c2175767SJohn Baldwin 	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
195c2175767SJohn Baldwin 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
196c2175767SJohn Baldwin 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
197c2175767SJohn Baldwin 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
198c2175767SJohn Baldwin 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
199c2175767SJohn Baldwin 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
200c2175767SJohn Baldwin 
201c2175767SJohn Baldwin 	{ 0, 0 }
202c2175767SJohn Baldwin };
203c2175767SJohn Baldwin 
204c2175767SJohn Baldwin static devclass_t qpi_devclass;
205c2175767SJohn Baldwin 
206c2175767SJohn Baldwin DEFINE_CLASS_0(qpi, qpi_driver, qpi_methods, 0);
207c2175767SJohn Baldwin DRIVER_MODULE(qpi, nexus, qpi_driver, qpi_devclass, 0, 0);
208c2175767SJohn Baldwin 
209c2175767SJohn Baldwin static int
210c2175767SJohn Baldwin qpi_pcib_probe(device_t dev)
211c2175767SJohn Baldwin {
212c2175767SJohn Baldwin 
213c2175767SJohn Baldwin 	device_set_desc(dev, "QPI Host-PCI bridge");
214c2175767SJohn Baldwin 	return (BUS_PROBE_SPECIFIC);
215c2175767SJohn Baldwin }
216c2175767SJohn Baldwin 
217c2175767SJohn Baldwin static int
218c2175767SJohn Baldwin qpi_pcib_attach(device_t dev)
219c2175767SJohn Baldwin {
220c2175767SJohn Baldwin 
221c2175767SJohn Baldwin 	device_add_child(dev, "pci", pcib_get_bus(dev));
222c2175767SJohn Baldwin         return (bus_generic_attach(dev));
223c2175767SJohn Baldwin }
224c2175767SJohn Baldwin 
225c2175767SJohn Baldwin static int
226c2175767SJohn Baldwin qpi_pcib_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
227c2175767SJohn Baldwin {
228c2175767SJohn Baldwin 
229c2175767SJohn Baldwin 	switch (which) {
230c2175767SJohn Baldwin 	case PCIB_IVAR_DOMAIN:
231c2175767SJohn Baldwin 		*result = 0;
232c2175767SJohn Baldwin 		return (0);
233c2175767SJohn Baldwin 	case PCIB_IVAR_BUS:
234c2175767SJohn Baldwin 		*result = pcib_get_bus(dev);
235c2175767SJohn Baldwin 		return (0);
236c2175767SJohn Baldwin 	default:
237c2175767SJohn Baldwin 		return (ENOENT);
238c2175767SJohn Baldwin 	}
239c2175767SJohn Baldwin }
240c2175767SJohn Baldwin 
2414edef187SJohn Baldwin #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
2424edef187SJohn Baldwin static struct resource *
2434edef187SJohn Baldwin qpi_pcib_alloc_resource(device_t dev, device_t child, int type, int *rid,
2444edef187SJohn Baldwin     u_long start, u_long end, u_long count, u_int flags)
2454edef187SJohn Baldwin {
2464edef187SJohn Baldwin 
2474edef187SJohn Baldwin 	if (type == PCI_RES_BUS)
2484edef187SJohn Baldwin 		return (pci_domain_alloc_bus(0, child, rid, start, end, count,
2494edef187SJohn Baldwin 		    flags));
2504edef187SJohn Baldwin 	return (bus_generic_alloc_resource(dev, child, type, rid, start, end,
2514edef187SJohn Baldwin 	    count, flags));
2524edef187SJohn Baldwin }
2534edef187SJohn Baldwin #endif
2544edef187SJohn Baldwin 
255c2175767SJohn Baldwin static int
256c2175767SJohn Baldwin qpi_pcib_map_msi(device_t pcib, device_t dev, int irq, uint64_t *addr,
257c2175767SJohn Baldwin     uint32_t *data)
258c2175767SJohn Baldwin {
259c2175767SJohn Baldwin 	device_t bus;
260c2175767SJohn Baldwin 
261c2175767SJohn Baldwin 	bus = device_get_parent(pcib);
262c2175767SJohn Baldwin 	return (PCIB_MAP_MSI(device_get_parent(bus), dev, irq, addr, data));
263c2175767SJohn Baldwin }
264c2175767SJohn Baldwin 
265c2175767SJohn Baldwin static device_method_t qpi_pcib_methods[] = {
266c2175767SJohn Baldwin 	/* Device interface */
267c2175767SJohn Baldwin 	DEVMETHOD(device_probe,		qpi_pcib_probe),
268c2175767SJohn Baldwin 	DEVMETHOD(device_attach,	qpi_pcib_attach),
269c2175767SJohn Baldwin 	DEVMETHOD(device_shutdown,	bus_generic_shutdown),
270c2175767SJohn Baldwin 	DEVMETHOD(device_suspend,	bus_generic_suspend),
271c2175767SJohn Baldwin 	DEVMETHOD(device_resume,	bus_generic_resume),
272c2175767SJohn Baldwin 
273c2175767SJohn Baldwin 	/* Bus interface */
274c2175767SJohn Baldwin 	DEVMETHOD(bus_read_ivar,	qpi_pcib_read_ivar),
2754edef187SJohn Baldwin #if defined(NEW_PCIB) && defined(PCI_RES_BUS)
2764edef187SJohn Baldwin 	DEVMETHOD(bus_alloc_resource,	qpi_pcib_alloc_resource),
2774edef187SJohn Baldwin 	DEVMETHOD(bus_adjust_resource,	legacy_pcib_adjust_resource),
2784edef187SJohn Baldwin 	DEVMETHOD(bus_release_resource,	legacy_pcib_release_resource),
2794edef187SJohn Baldwin #else
280c2175767SJohn Baldwin 	DEVMETHOD(bus_alloc_resource,	bus_generic_alloc_resource),
281c2175767SJohn Baldwin 	DEVMETHOD(bus_release_resource,	bus_generic_release_resource),
2824edef187SJohn Baldwin #endif
283c2175767SJohn Baldwin 	DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
284c2175767SJohn Baldwin 	DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
285c2175767SJohn Baldwin 	DEVMETHOD(bus_setup_intr,	bus_generic_setup_intr),
286c2175767SJohn Baldwin 	DEVMETHOD(bus_teardown_intr,	bus_generic_teardown_intr),
287c2175767SJohn Baldwin 
288c2175767SJohn Baldwin 	/* pcib interface */
289c2175767SJohn Baldwin 	DEVMETHOD(pcib_maxslots,	pcib_maxslots),
29084ca9aadSJohn Baldwin 	DEVMETHOD(pcib_read_config,	legacy_pcib_read_config),
29184ca9aadSJohn Baldwin 	DEVMETHOD(pcib_write_config,	legacy_pcib_write_config),
29284ca9aadSJohn Baldwin 	DEVMETHOD(pcib_alloc_msi,	legacy_pcib_alloc_msi),
293c2175767SJohn Baldwin 	DEVMETHOD(pcib_release_msi,	pcib_release_msi),
29484ca9aadSJohn Baldwin 	DEVMETHOD(pcib_alloc_msix,	legacy_pcib_alloc_msix),
295c2175767SJohn Baldwin 	DEVMETHOD(pcib_release_msix,	pcib_release_msix),
296c2175767SJohn Baldwin 	DEVMETHOD(pcib_map_msi,		qpi_pcib_map_msi),
297c2175767SJohn Baldwin 
2984b7ec270SMarius Strobl 	DEVMETHOD_END
299c2175767SJohn Baldwin };
300c2175767SJohn Baldwin 
301c2175767SJohn Baldwin static devclass_t qpi_pcib_devclass;
302c2175767SJohn Baldwin 
303c2175767SJohn Baldwin DEFINE_CLASS_0(pcib, qpi_pcib_driver, qpi_pcib_methods, 0);
304c2175767SJohn Baldwin DRIVER_MODULE(pcib, qpi, qpi_pcib_driver, qpi_pcib_devclass, 0, 0);
305