pci_cfgreg.c revision 330897
1/*-
2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3 *
4 * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
5 * Copyright (c) 2000, Michael Smith <msmith@freebsd.org>
6 * Copyright (c) 2000, BSDi
7 * Copyright (c) 2004, Scott Long <scottl@freebsd.org>
8 * All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice unmodified, this list of conditions, and the following
15 *    disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32#include <sys/cdefs.h>
33__FBSDID("$FreeBSD: stable/11/sys/i386/pci/pci_cfgreg.c 330897 2018-03-14 03:19:51Z eadler $");
34
35#include "opt_xbox.h"
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/bus.h>
40#include <sys/lock.h>
41#include <sys/kernel.h>
42#include <sys/mutex.h>
43#include <sys/malloc.h>
44#include <sys/queue.h>
45#include <sys/sysctl.h>
46#include <dev/pci/pcivar.h>
47#include <dev/pci/pcireg.h>
48#include <machine/pci_cfgreg.h>
49#include <machine/pc/bios.h>
50
51#include <vm/vm.h>
52#include <vm/vm_param.h>
53#include <vm/vm_kern.h>
54#include <vm/vm_extern.h>
55#include <vm/pmap.h>
56
57#ifdef XBOX
58#include <machine/xbox.h>
59#endif
60
61#define PRVERB(a) do {							\
62	if (bootverbose)						\
63		printf a ;						\
64} while(0)
65
66#define PCIE_CACHE 8
67struct pcie_cfg_elem {
68	TAILQ_ENTRY(pcie_cfg_elem)	elem;
69	vm_offset_t	vapage;
70	vm_paddr_t	papage;
71};
72
73enum {
74	CFGMECH_NONE = 0,
75	CFGMECH_1,
76	CFGMECH_2,
77	CFGMECH_PCIE,
78};
79
80SYSCTL_DECL(_hw_pci);
81
82static TAILQ_HEAD(pcie_cfg_list, pcie_cfg_elem) pcie_list[MAXCPU];
83static uint64_t pcie_base;
84static int pcie_minbus, pcie_maxbus;
85static uint32_t pcie_badslots;
86static int cfgmech;
87static int devmax;
88static struct mtx pcicfg_mtx;
89static int mcfg_enable = 1;
90SYSCTL_INT(_hw_pci, OID_AUTO, mcfg, CTLFLAG_RDTUN, &mcfg_enable, 0,
91    "Enable support for PCI-e memory mapped config access");
92
93static uint32_t	pci_docfgregread(int bus, int slot, int func, int reg,
94		    int bytes);
95static int	pcireg_cfgread(int bus, int slot, int func, int reg, int bytes);
96static void	pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes);
97static int	pcireg_cfgopen(void);
98static int	pciereg_cfgread(int bus, unsigned slot, unsigned func,
99		    unsigned reg, unsigned bytes);
100static void	pciereg_cfgwrite(int bus, unsigned slot, unsigned func,
101		    unsigned reg, int data, unsigned bytes);
102
103/*
104 * Some BIOS writers seem to want to ignore the spec and put
105 * 0 in the intline rather than 255 to indicate none.  Some use
106 * numbers in the range 128-254 to indicate something strange and
107 * apparently undocumented anywhere.  Assume these are completely bogus
108 * and map them to 255, which means "none".
109 */
110static __inline int
111pci_i386_map_intline(int line)
112{
113	if (line == 0 || line >= 128)
114		return (PCI_INVALID_IRQ);
115	return (line);
116}
117
118static u_int16_t
119pcibios_get_version(void)
120{
121	struct bios_regs args;
122
123	if (PCIbios.ventry == 0) {
124		PRVERB(("pcibios: No call entry point\n"));
125		return (0);
126	}
127	args.eax = PCIBIOS_BIOS_PRESENT;
128	if (bios32(&args, PCIbios.ventry, GSEL(GCODE_SEL, SEL_KPL))) {
129		PRVERB(("pcibios: BIOS_PRESENT call failed\n"));
130		return (0);
131	}
132	if (args.edx != 0x20494350) {
133		PRVERB(("pcibios: BIOS_PRESENT didn't return 'PCI ' in edx\n"));
134		return (0);
135	}
136	return (args.ebx & 0xffff);
137}
138
139/*
140 * Initialise access to PCI configuration space
141 */
142int
143pci_cfgregopen(void)
144{
145	static int		opened = 0;
146	uint64_t		pciebar;
147	u_int16_t		vid, did;
148	u_int16_t		v;
149
150	if (opened)
151		return (1);
152
153	if (cfgmech == CFGMECH_NONE && pcireg_cfgopen() == 0)
154		return (0);
155
156	v = pcibios_get_version();
157	if (v > 0)
158		PRVERB(("pcibios: BIOS version %x.%02x\n", (v & 0xff00) >> 8,
159		    v & 0xff));
160	mtx_init(&pcicfg_mtx, "pcicfg", NULL, MTX_SPIN);
161	opened = 1;
162
163	/* $PIR requires PCI BIOS 2.10 or greater. */
164	if (v >= 0x0210)
165		pci_pir_open();
166
167	if (cfgmech == CFGMECH_PCIE)
168		return (1);
169
170	/*
171	 * Grope around in the PCI config space to see if this is a
172	 * chipset that is capable of doing memory-mapped config cycles.
173	 * This also implies that it can do PCIe extended config cycles.
174	 */
175
176	/* Check for supported chipsets */
177	vid = pci_cfgregread(0, 0, 0, PCIR_VENDOR, 2);
178	did = pci_cfgregread(0, 0, 0, PCIR_DEVICE, 2);
179	switch (vid) {
180	case 0x8086:
181		switch (did) {
182		case 0x3590:
183		case 0x3592:
184			/* Intel 7520 or 7320 */
185			pciebar = pci_cfgregread(0, 0, 0, 0xce, 2) << 16;
186			pcie_cfgregopen(pciebar, 0, 255);
187			break;
188		case 0x2580:
189		case 0x2584:
190		case 0x2590:
191			/* Intel 915, 925, or 915GM */
192			pciebar = pci_cfgregread(0, 0, 0, 0x48, 4);
193			pcie_cfgregopen(pciebar, 0, 255);
194			break;
195		}
196	}
197
198	return(1);
199}
200
201static uint32_t
202pci_docfgregread(int bus, int slot, int func, int reg, int bytes)
203{
204
205	if (cfgmech == CFGMECH_PCIE &&
206	    (bus >= pcie_minbus && bus <= pcie_maxbus) &&
207	    (bus != 0 || !(1 << slot & pcie_badslots)))
208		return (pciereg_cfgread(bus, slot, func, reg, bytes));
209	else
210		return (pcireg_cfgread(bus, slot, func, reg, bytes));
211}
212
213/*
214 * Read configuration space register
215 */
216u_int32_t
217pci_cfgregread(int bus, int slot, int func, int reg, int bytes)
218{
219	uint32_t line;
220
221	/*
222	 * Some BIOS writers seem to want to ignore the spec and put
223	 * 0 in the intline rather than 255 to indicate none.  The rest of
224	 * the code uses 255 as an invalid IRQ.
225	 */
226	if (reg == PCIR_INTLINE && bytes == 1) {
227		line = pci_docfgregread(bus, slot, func, PCIR_INTLINE, 1);
228		return (pci_i386_map_intline(line));
229	}
230	return (pci_docfgregread(bus, slot, func, reg, bytes));
231}
232
233/*
234 * Write configuration space register
235 */
236void
237pci_cfgregwrite(int bus, int slot, int func, int reg, u_int32_t data, int bytes)
238{
239
240	if (cfgmech == CFGMECH_PCIE &&
241	    (bus >= pcie_minbus && bus <= pcie_maxbus) &&
242	    (bus != 0 || !(1 << slot & pcie_badslots)))
243		pciereg_cfgwrite(bus, slot, func, reg, data, bytes);
244	else
245		pcireg_cfgwrite(bus, slot, func, reg, data, bytes);
246}
247
248/*
249 * Configuration space access using direct register operations
250 */
251
252/* enable configuration space accesses and return data port address */
253static int
254pci_cfgenable(unsigned bus, unsigned slot, unsigned func, int reg, int bytes)
255{
256	int dataport = 0;
257
258#ifdef XBOX
259	if (arch_i386_is_xbox) {
260		/*
261		 * The Xbox MCPX chipset is a derivative of the nForce 1
262		 * chipset. It almost has the same bus layout; some devices
263		 * cannot be used, because they have been removed.
264		 */
265
266		/*
267		 * Devices 00:00.1 and 00:00.2 used to be memory controllers on
268		 * the nForce chipset, but on the Xbox, using them will lockup
269		 * the chipset.
270		 */
271		if (bus == 0 && slot == 0 && (func == 1 || func == 2))
272			return dataport;
273
274		/*
275		 * Bus 1 only contains a VGA controller at 01:00.0. When you try
276		 * to probe beyond that device, you only get garbage, which
277		 * could cause lockups.
278		 */
279		if (bus == 1 && (slot != 0 || func != 0))
280			return dataport;
281
282		/*
283		 * Bus 2 used to contain the AGP controller, but the Xbox MCPX
284		 * doesn't have one. Probing it can cause lockups.
285		 */
286		if (bus >= 2)
287			return dataport;
288	}
289#endif
290
291	if (bus <= PCI_BUSMAX
292	    && slot < devmax
293	    && func <= PCI_FUNCMAX
294	    && (unsigned)reg <= PCI_REGMAX
295	    && bytes != 3
296	    && (unsigned)bytes <= 4
297	    && (reg & (bytes - 1)) == 0) {
298		switch (cfgmech) {
299		case CFGMECH_PCIE:
300		case CFGMECH_1:
301			outl(CONF1_ADDR_PORT, (1U << 31)
302			    | (bus << 16) | (slot << 11)
303			    | (func << 8) | (reg & ~0x03));
304			dataport = CONF1_DATA_PORT + (reg & 0x03);
305			break;
306		case CFGMECH_2:
307			outb(CONF2_ENABLE_PORT, 0xf0 | (func << 1));
308			outb(CONF2_FORWARD_PORT, bus);
309			dataport = 0xc000 | (slot << 8) | reg;
310			break;
311		}
312	}
313	return (dataport);
314}
315
316/* disable configuration space accesses */
317static void
318pci_cfgdisable(void)
319{
320	switch (cfgmech) {
321	case CFGMECH_PCIE:
322	case CFGMECH_1:
323		/*
324		 * Do nothing for the config mechanism 1 case.
325		 * Writing a 0 to the address port can apparently
326		 * confuse some bridges and cause spurious
327		 * access failures.
328		 */
329		break;
330	case CFGMECH_2:
331		outb(CONF2_ENABLE_PORT, 0);
332		break;
333	}
334}
335
336static int
337pcireg_cfgread(int bus, int slot, int func, int reg, int bytes)
338{
339	int data = -1;
340	int port;
341
342	mtx_lock_spin(&pcicfg_mtx);
343	port = pci_cfgenable(bus, slot, func, reg, bytes);
344	if (port != 0) {
345		switch (bytes) {
346		case 1:
347			data = inb(port);
348			break;
349		case 2:
350			data = inw(port);
351			break;
352		case 4:
353			data = inl(port);
354			break;
355		}
356		pci_cfgdisable();
357	}
358	mtx_unlock_spin(&pcicfg_mtx);
359	return (data);
360}
361
362static void
363pcireg_cfgwrite(int bus, int slot, int func, int reg, int data, int bytes)
364{
365	int port;
366
367	mtx_lock_spin(&pcicfg_mtx);
368	port = pci_cfgenable(bus, slot, func, reg, bytes);
369	if (port != 0) {
370		switch (bytes) {
371		case 1:
372			outb(port, data);
373			break;
374		case 2:
375			outw(port, data);
376			break;
377		case 4:
378			outl(port, data);
379			break;
380		}
381		pci_cfgdisable();
382	}
383	mtx_unlock_spin(&pcicfg_mtx);
384}
385
386/* check whether the configuration mechanism has been correctly identified */
387static int
388pci_cfgcheck(int maxdev)
389{
390	uint32_t id, class;
391	uint8_t header;
392	uint8_t device;
393	int port;
394
395	if (bootverbose)
396		printf("pci_cfgcheck:\tdevice ");
397
398	for (device = 0; device < maxdev; device++) {
399		if (bootverbose)
400			printf("%d ", device);
401
402		port = pci_cfgenable(0, device, 0, 0, 4);
403		id = inl(port);
404		if (id == 0 || id == 0xffffffff)
405			continue;
406
407		port = pci_cfgenable(0, device, 0, 8, 4);
408		class = inl(port) >> 8;
409		if (bootverbose)
410			printf("[class=%06x] ", class);
411		if (class == 0 || (class & 0xf870ff) != 0)
412			continue;
413
414		port = pci_cfgenable(0, device, 0, 14, 1);
415		header = inb(port);
416		if (bootverbose)
417			printf("[hdr=%02x] ", header);
418		if ((header & 0x7e) != 0)
419			continue;
420
421		if (bootverbose)
422			printf("is there (id=%08x)\n", id);
423
424		pci_cfgdisable();
425		return (1);
426	}
427	if (bootverbose)
428		printf("-- nothing found\n");
429
430	pci_cfgdisable();
431	return (0);
432}
433
434static int
435pcireg_cfgopen(void)
436{
437	uint32_t mode1res, oldval1;
438	uint8_t mode2res, oldval2;
439
440	/* Check for type #1 first. */
441	oldval1 = inl(CONF1_ADDR_PORT);
442
443	if (bootverbose) {
444		printf("pci_open(1):\tmode 1 addr port (0x0cf8) is 0x%08x\n",
445		    oldval1);
446	}
447
448	cfgmech = CFGMECH_1;
449	devmax = 32;
450
451	outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK);
452	DELAY(1);
453	mode1res = inl(CONF1_ADDR_PORT);
454	outl(CONF1_ADDR_PORT, oldval1);
455
456	if (bootverbose)
457		printf("pci_open(1a):\tmode1res=0x%08x (0x%08lx)\n",  mode1res,
458		    CONF1_ENABLE_CHK);
459
460	if (mode1res) {
461		if (pci_cfgcheck(32))
462			return (cfgmech);
463	}
464
465	outl(CONF1_ADDR_PORT, CONF1_ENABLE_CHK1);
466	mode1res = inl(CONF1_ADDR_PORT);
467	outl(CONF1_ADDR_PORT, oldval1);
468
469	if (bootverbose)
470		printf("pci_open(1b):\tmode1res=0x%08x (0x%08lx)\n",  mode1res,
471		    CONF1_ENABLE_CHK1);
472
473	if ((mode1res & CONF1_ENABLE_MSK1) == CONF1_ENABLE_RES1) {
474		if (pci_cfgcheck(32))
475			return (cfgmech);
476	}
477
478	/* Type #1 didn't work, so try type #2. */
479	oldval2 = inb(CONF2_ENABLE_PORT);
480
481	if (bootverbose) {
482		printf("pci_open(2):\tmode 2 enable port (0x0cf8) is 0x%02x\n",
483		    oldval2);
484	}
485
486	if ((oldval2 & 0xf0) == 0) {
487
488		cfgmech = CFGMECH_2;
489		devmax = 16;
490
491		outb(CONF2_ENABLE_PORT, CONF2_ENABLE_CHK);
492		mode2res = inb(CONF2_ENABLE_PORT);
493		outb(CONF2_ENABLE_PORT, oldval2);
494
495		if (bootverbose)
496			printf("pci_open(2a):\tmode2res=0x%02x (0x%02x)\n",
497			    mode2res, CONF2_ENABLE_CHK);
498
499		if (mode2res == CONF2_ENABLE_RES) {
500			if (bootverbose)
501				printf("pci_open(2a):\tnow trying mechanism 2\n");
502
503			if (pci_cfgcheck(16))
504				return (cfgmech);
505		}
506	}
507
508	/* Nothing worked, so punt. */
509	cfgmech = CFGMECH_NONE;
510	devmax = 0;
511	return (cfgmech);
512}
513
514int
515pcie_cfgregopen(uint64_t base, uint8_t minbus, uint8_t maxbus)
516{
517	struct pcie_cfg_list *pcielist;
518	struct pcie_cfg_elem *pcie_array, *elem;
519#ifdef SMP
520	struct pcpu *pc;
521#endif
522	vm_offset_t va;
523	uint32_t val1, val2;
524	int i, slot;
525
526	if (!mcfg_enable)
527		return (0);
528
529	if (minbus != 0)
530		return (0);
531
532#ifndef PAE
533	if (base >= 0x100000000) {
534		if (bootverbose)
535			printf(
536	    "PCI: Memory Mapped PCI configuration area base 0x%jx too high\n",
537			    (uintmax_t)base);
538		return (0);
539	}
540#endif
541
542	if (bootverbose)
543		printf("PCIe: Memory Mapped configuration base @ 0x%jx\n",
544		    (uintmax_t)base);
545
546#ifdef SMP
547	STAILQ_FOREACH(pc, &cpuhead, pc_allcpu)
548#endif
549	{
550
551		pcie_array = malloc(sizeof(struct pcie_cfg_elem) * PCIE_CACHE,
552		    M_DEVBUF, M_NOWAIT);
553		if (pcie_array == NULL)
554			return (0);
555
556		va = kva_alloc(PCIE_CACHE * PAGE_SIZE);
557		if (va == 0) {
558			free(pcie_array, M_DEVBUF);
559			return (0);
560		}
561
562#ifdef SMP
563		pcielist = &pcie_list[pc->pc_cpuid];
564#else
565		pcielist = &pcie_list[0];
566#endif
567		TAILQ_INIT(pcielist);
568		for (i = 0; i < PCIE_CACHE; i++) {
569			elem = &pcie_array[i];
570			elem->vapage = va + (i * PAGE_SIZE);
571			elem->papage = 0;
572			TAILQ_INSERT_HEAD(pcielist, elem, elem);
573		}
574	}
575
576	pcie_base = base;
577	pcie_minbus = minbus;
578	pcie_maxbus = maxbus;
579	cfgmech = CFGMECH_PCIE;
580	devmax = 32;
581
582	/*
583	 * On some AMD systems, some of the devices on bus 0 are
584	 * inaccessible using memory-mapped PCI config access.  Walk
585	 * bus 0 looking for such devices.  For these devices, we will
586	 * fall back to using type 1 config access instead.
587	 */
588	if (pci_cfgregopen() != 0) {
589		for (slot = 0; slot <= PCI_SLOTMAX; slot++) {
590			val1 = pcireg_cfgread(0, slot, 0, 0, 4);
591			if (val1 == 0xffffffff)
592				continue;
593
594			val2 = pciereg_cfgread(0, slot, 0, 0, 4);
595			if (val2 != val1)
596				pcie_badslots |= (1 << slot);
597		}
598	}
599
600	return (1);
601}
602
603#define PCIE_PADDR(base, reg, bus, slot, func)	\
604	((base)				+	\
605	((((bus) & 0xff) << 20)		|	\
606	(((slot) & 0x1f) << 15)		|	\
607	(((func) & 0x7) << 12)		|	\
608	((reg) & 0xfff)))
609
610static __inline vm_offset_t
611pciereg_findaddr(int bus, unsigned slot, unsigned func, unsigned reg)
612{
613	struct pcie_cfg_list *pcielist;
614	struct pcie_cfg_elem *elem;
615	vm_paddr_t pa, papage;
616
617	pa = PCIE_PADDR(pcie_base, reg, bus, slot, func);
618	papage = pa & ~PAGE_MASK;
619
620	/*
621	 * Find an element in the cache that matches the physical page desired,
622	 * or create a new mapping from the least recently used element.
623	 * A very simple LRU algorithm is used here, does it need to be more
624	 * efficient?
625	 */
626	pcielist = &pcie_list[PCPU_GET(cpuid)];
627	TAILQ_FOREACH(elem, pcielist, elem) {
628		if (elem->papage == papage)
629			break;
630	}
631
632	if (elem == NULL) {
633		elem = TAILQ_LAST(pcielist, pcie_cfg_list);
634		if (elem->papage != 0) {
635			pmap_kremove(elem->vapage);
636			invlpg(elem->vapage);
637		}
638		pmap_kenter(elem->vapage, papage);
639		elem->papage = papage;
640	}
641
642	if (elem != TAILQ_FIRST(pcielist)) {
643		TAILQ_REMOVE(pcielist, elem, elem);
644		TAILQ_INSERT_HEAD(pcielist, elem, elem);
645	}
646	return (elem->vapage | (pa & PAGE_MASK));
647}
648
649/*
650 * AMD BIOS And Kernel Developer's Guides for CPU families starting with 10h
651 * have a requirement that all accesses to the memory mapped PCI configuration
652 * space are done using AX class of registers.
653 * Since other vendors do not currently have any contradicting requirements
654 * the AMD access pattern is applied universally.
655 */
656
657static int
658pciereg_cfgread(int bus, unsigned slot, unsigned func, unsigned reg,
659    unsigned bytes)
660{
661	vm_offset_t va;
662	int data = -1;
663
664	if (bus < pcie_minbus || bus > pcie_maxbus || slot > PCI_SLOTMAX ||
665	    func > PCI_FUNCMAX || reg > PCIE_REGMAX)
666		return (-1);
667
668	critical_enter();
669	va = pciereg_findaddr(bus, slot, func, reg);
670
671	switch (bytes) {
672	case 4:
673		__asm("movl %1, %0" : "=a" (data)
674		    : "m" (*(volatile uint32_t *)va));
675		break;
676	case 2:
677		__asm("movzwl %1, %0" : "=a" (data)
678		    : "m" (*(volatile uint16_t *)va));
679		break;
680	case 1:
681		__asm("movzbl %1, %0" : "=a" (data)
682		    : "m" (*(volatile uint8_t *)va));
683		break;
684	}
685
686	critical_exit();
687	return (data);
688}
689
690static void
691pciereg_cfgwrite(int bus, unsigned slot, unsigned func, unsigned reg, int data,
692    unsigned bytes)
693{
694	vm_offset_t va;
695
696	if (bus < pcie_minbus || bus > pcie_maxbus || slot > PCI_SLOTMAX ||
697	    func > PCI_FUNCMAX || reg > PCIE_REGMAX)
698		return;
699
700	critical_enter();
701	va = pciereg_findaddr(bus, slot, func, reg);
702
703	switch (bytes) {
704	case 4:
705		__asm("movl %1, %0" : "=m" (*(volatile uint32_t *)va)
706		    : "a" (data));
707		break;
708	case 2:
709		__asm("movw %1, %0" : "=m" (*(volatile uint16_t *)va)
710		    : "a" ((uint16_t)data));
711		break;
712	case 1:
713		__asm("movb %1, %0" : "=m" (*(volatile uint8_t *)va)
714		    : "a" ((uint8_t)data));
715		break;
716	}
717
718	critical_exit();
719}
720