xref: /onnv-gate/usr/src/uts/i86pc/os/pci_cfgspace.c (revision 12212:cfffd5b09e1f)
1748Sdmick /*
2748Sdmick  * CDDL HEADER START
3748Sdmick  *
4748Sdmick  * The contents of this file are subject to the terms of the
5748Sdmick  * Common Development and Distribution License (the "License").
6748Sdmick  * You may not use this file except in compliance with the License.
7748Sdmick  *
8748Sdmick  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9748Sdmick  * or http://www.opensolaris.org/os/licensing.
10748Sdmick  * See the License for the specific language governing permissions
11748Sdmick  * and limitations under the License.
12748Sdmick  *
13748Sdmick  * When distributing Covered Code, include this CDDL HEADER in each
14748Sdmick  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15748Sdmick  * If applicable, add the following below this CDDL HEADER, with the
16748Sdmick  * fields enclosed by brackets "[]" replaced with your own identifying
17748Sdmick  * information: Portions Copyright [yyyy] [name of copyright owner]
18748Sdmick  *
19748Sdmick  * CDDL HEADER END
20748Sdmick  */
21748Sdmick 
22748Sdmick /*
23*12212SZhijun.Fu@Sun.COM  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
24748Sdmick  */
25748Sdmick 
26748Sdmick /*
27748Sdmick  * PCI configuration space access routines
28748Sdmick  */
29748Sdmick 
30748Sdmick #include <sys/systm.h>
31748Sdmick #include <sys/psw.h>
32748Sdmick #include <sys/bootconf.h>
33748Sdmick #include <sys/reboot.h>
34748Sdmick #include <sys/pci_impl.h>
35748Sdmick #include <sys/pci_cfgspace.h>
36748Sdmick #include <sys/pci_cfgspace_impl.h>
3711245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h>
385084Sjohnlev #if defined(__xpv)
395084Sjohnlev #include <sys/hypervisor.h>
4011245SZhijun.Fu@Sun.COM #endif
4111245SZhijun.Fu@Sun.COM 
4211245SZhijun.Fu@Sun.COM #if defined(__xpv)
435084Sjohnlev int pci_max_nbus = 0xFE;
445084Sjohnlev #endif
45748Sdmick int pci_bios_cfg_type = PCI_MECHANISM_UNKNOWN;
4610804SDana.Myers@Sun.COM int pci_bios_maxbus;
47748Sdmick int pci_bios_mech;
48748Sdmick int pci_bios_vers;
49748Sdmick 
50748Sdmick /*
51748Sdmick  * These two variables can be used to force a configuration mechanism or
52748Sdmick  * to force which function is used to probe for the presence of the PCI bus.
53748Sdmick  */
54748Sdmick int	PCI_CFG_TYPE = 0;
55748Sdmick int	PCI_PROBE_TYPE = 0;
56748Sdmick 
57748Sdmick /*
5811245SZhijun.Fu@Sun.COM  * No valid mcfg_mem_base by default, and accessing pci config space
5911245SZhijun.Fu@Sun.COM  * in mem-mapped way is disabled.
6011245SZhijun.Fu@Sun.COM  */
6111245SZhijun.Fu@Sun.COM uint64_t mcfg_mem_base = 0;
6211245SZhijun.Fu@Sun.COM uint8_t mcfg_bus_start = 0;
6311245SZhijun.Fu@Sun.COM uint8_t mcfg_bus_end = 0xff;
6411245SZhijun.Fu@Sun.COM 
6511245SZhijun.Fu@Sun.COM /*
66*12212SZhijun.Fu@Sun.COM  * Maximum offset in config space when not using MMIO
67*12212SZhijun.Fu@Sun.COM  */
68*12212SZhijun.Fu@Sun.COM uint_t pci_iocfg_max_offset = 0xff;
69*12212SZhijun.Fu@Sun.COM 
70*12212SZhijun.Fu@Sun.COM /*
71748Sdmick  * These function pointers lead to the actual implementation routines
72748Sdmick  * for configuration space access.  Normally they lead to either the
73748Sdmick  * pci_mech1_* or pci_mech2_* routines, but they can also lead to
74748Sdmick  * routines that work around chipset bugs.
7511245SZhijun.Fu@Sun.COM  * These functions are accessing pci config space via I/O way.
7611245SZhijun.Fu@Sun.COM  * Pci_cfgacc_get/put functions shoul be used as more common interfaces,
7711245SZhijun.Fu@Sun.COM  * which also provide accessing pci config space via mem-mapped way.
78748Sdmick  */
79748Sdmick uint8_t (*pci_getb_func)(int bus, int dev, int func, int reg);
80748Sdmick uint16_t (*pci_getw_func)(int bus, int dev, int func, int reg);
81748Sdmick uint32_t (*pci_getl_func)(int bus, int dev, int func, int reg);
82748Sdmick void (*pci_putb_func)(int bus, int dev, int func, int reg, uint8_t val);
83748Sdmick void (*pci_putw_func)(int bus, int dev, int func, int reg, uint16_t val);
84748Sdmick void (*pci_putl_func)(int bus, int dev, int func, int reg, uint32_t val);
85748Sdmick 
8611245SZhijun.Fu@Sun.COM extern void (*pci_cfgacc_acc_p)(pci_cfgacc_req_t *req);
8711245SZhijun.Fu@Sun.COM 
88748Sdmick /*
89748Sdmick  * Internal routines
90748Sdmick  */
91748Sdmick static int pci_check(void);
925084Sjohnlev 
935084Sjohnlev #if !defined(__xpv)
94748Sdmick static int pci_check_bios(void);
95748Sdmick static int pci_get_cfg_type(void);
965084Sjohnlev #endif
97748Sdmick 
9811787SKerry.Shu@Sun.COM /* for legacy io-based config space access */
99748Sdmick kmutex_t pcicfg_mutex;
100748Sdmick 
10111787SKerry.Shu@Sun.COM /* for mmio-based config space access */
10211787SKerry.Shu@Sun.COM kmutex_t pcicfg_mmio_mutex;
10311787SKerry.Shu@Sun.COM 
104748Sdmick /* ..except Orion and Neptune, which have to have their own */
105748Sdmick kmutex_t pcicfg_chipset_mutex;
106748Sdmick 
107748Sdmick void
pci_cfgspace_init(void)108748Sdmick pci_cfgspace_init(void)
109748Sdmick {
1101901Sdilpreet 	mutex_init(&pcicfg_mutex, NULL, MUTEX_SPIN,
1111901Sdilpreet 	    (ddi_iblock_cookie_t)ipltospl(15));
11211787SKerry.Shu@Sun.COM 	mutex_init(&pcicfg_mmio_mutex, NULL, MUTEX_SPIN,
11311787SKerry.Shu@Sun.COM 	    (ddi_iblock_cookie_t)ipltospl(DISP_LEVEL));
1141901Sdilpreet 	mutex_init(&pcicfg_chipset_mutex, NULL, MUTEX_SPIN,
1151901Sdilpreet 	    (ddi_iblock_cookie_t)ipltospl(15));
116748Sdmick 	if (!pci_check()) {
117748Sdmick 		mutex_destroy(&pcicfg_mutex);
11811787SKerry.Shu@Sun.COM 		mutex_destroy(&pcicfg_mmio_mutex);
119748Sdmick 		mutex_destroy(&pcicfg_chipset_mutex);
120748Sdmick 	}
121748Sdmick }
122748Sdmick 
123748Sdmick /*
12411245SZhijun.Fu@Sun.COM  * This code determines if this system supports PCI/PCIE and which
125748Sdmick  * type of configuration access method is used
126748Sdmick  */
127748Sdmick static int
pci_check(void)128748Sdmick pci_check(void)
129748Sdmick {
13011245SZhijun.Fu@Sun.COM 	uint64_t ecfginfo[4];
13111245SZhijun.Fu@Sun.COM 
132748Sdmick 	/*
133748Sdmick 	 * Only do this once.  NB:  If this is not a PCI system, and we
134748Sdmick 	 * get called twice, we can't detect it and will probably die
135748Sdmick 	 * horribly when we try to ask the BIOS whether PCI is present.
136748Sdmick 	 * This code is safe *ONLY* during system startup when the
137748Sdmick 	 * BIOS is still available.
138748Sdmick 	 */
139748Sdmick 	if (pci_bios_cfg_type != PCI_MECHANISM_UNKNOWN)
140748Sdmick 		return (TRUE);
141748Sdmick 
1425084Sjohnlev #if defined(__xpv)
1435084Sjohnlev 	/*
1445084Sjohnlev 	 * only support PCI config mechanism 1 in i86xpv. This should be fine
1455084Sjohnlev 	 * since the other ones are workarounds for old broken H/W which won't
1465084Sjohnlev 	 * be supported in i86xpv anyway.
1475084Sjohnlev 	 */
1485084Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
1495084Sjohnlev 		pci_bios_cfg_type = PCI_MECHANISM_1;
1505084Sjohnlev 		pci_getb_func = pci_mech1_getb;
1515084Sjohnlev 		pci_getw_func = pci_mech1_getw;
1525084Sjohnlev 		pci_getl_func = pci_mech1_getl;
1535084Sjohnlev 		pci_putb_func = pci_mech1_putb;
1545084Sjohnlev 		pci_putw_func = pci_mech1_putw;
1555084Sjohnlev 		pci_putl_func = pci_mech1_putl;
1565084Sjohnlev 
1575084Sjohnlev 		/*
1585084Sjohnlev 		 * Since we can't get the BIOS info in i86xpv, we will do an
1595084Sjohnlev 		 * exhaustive search of all PCI buses. We have to do this until
1605084Sjohnlev 		 * we start using the PCI information in ACPI.
1615084Sjohnlev 		 */
16210804SDana.Myers@Sun.COM 		pci_bios_maxbus = pci_max_nbus;
1635084Sjohnlev 	}
1645084Sjohnlev #else /* !__xpv */
1655084Sjohnlev 
166748Sdmick 	pci_bios_cfg_type = pci_check_bios();
167748Sdmick 
168748Sdmick 	if (pci_bios_cfg_type == PCI_MECHANISM_NONE)
1692123Sszhou 		pci_bios_cfg_type = PCI_MECHANISM_1;	/* default to mech 1 */
170748Sdmick 
171748Sdmick 	switch (pci_get_cfg_type()) {
172748Sdmick 	case PCI_MECHANISM_1:
173748Sdmick 		if (pci_is_broken_orion()) {
174748Sdmick 			pci_getb_func = pci_orion_getb;
175748Sdmick 			pci_getw_func = pci_orion_getw;
176748Sdmick 			pci_getl_func = pci_orion_getl;
177748Sdmick 			pci_putb_func = pci_orion_putb;
178748Sdmick 			pci_putw_func = pci_orion_putw;
179748Sdmick 			pci_putl_func = pci_orion_putl;
180*12212SZhijun.Fu@Sun.COM 		} else if (pci_check_amd_ioecs()) {
181*12212SZhijun.Fu@Sun.COM 			pci_getb_func = pci_mech1_amd_getb;
182*12212SZhijun.Fu@Sun.COM 			pci_getw_func = pci_mech1_amd_getw;
183*12212SZhijun.Fu@Sun.COM 			pci_getl_func = pci_mech1_amd_getl;
184*12212SZhijun.Fu@Sun.COM 			pci_putb_func = pci_mech1_amd_putb;
185*12212SZhijun.Fu@Sun.COM 			pci_putw_func = pci_mech1_amd_putw;
186*12212SZhijun.Fu@Sun.COM 			pci_putl_func = pci_mech1_amd_putl;
187*12212SZhijun.Fu@Sun.COM 			pci_iocfg_max_offset = 0xfff;
188748Sdmick 		} else {
189748Sdmick 			pci_getb_func = pci_mech1_getb;
190748Sdmick 			pci_getw_func = pci_mech1_getw;
191748Sdmick 			pci_getl_func = pci_mech1_getl;
192748Sdmick 			pci_putb_func = pci_mech1_putb;
193748Sdmick 			pci_putw_func = pci_mech1_putw;
194748Sdmick 			pci_putl_func = pci_mech1_putl;
195748Sdmick 		}
196748Sdmick 		break;
197748Sdmick 
198748Sdmick 	case PCI_MECHANISM_2:
199748Sdmick 		if (pci_check_neptune()) {
200748Sdmick 			/*
201748Sdmick 			 * The BIOS for some systems with the Intel
202748Sdmick 			 * Neptune chipset seem to default to #2 even
203748Sdmick 			 * though the chipset can do #1.  Override
204748Sdmick 			 * the BIOS so that MP systems will work
205748Sdmick 			 * correctly.
206748Sdmick 			 */
207748Sdmick 
208748Sdmick 			pci_getb_func = pci_neptune_getb;
209748Sdmick 			pci_getw_func = pci_neptune_getw;
210748Sdmick 			pci_getl_func = pci_neptune_getl;
211748Sdmick 			pci_putb_func = pci_neptune_putb;
212748Sdmick 			pci_putw_func = pci_neptune_putw;
213748Sdmick 			pci_putl_func = pci_neptune_putl;
214748Sdmick 		} else {
215748Sdmick 			pci_getb_func = pci_mech2_getb;
216748Sdmick 			pci_getw_func = pci_mech2_getw;
217748Sdmick 			pci_getl_func = pci_mech2_getl;
218748Sdmick 			pci_putb_func = pci_mech2_putb;
219748Sdmick 			pci_putw_func = pci_mech2_putw;
220748Sdmick 			pci_putl_func = pci_mech2_putl;
221748Sdmick 		}
222748Sdmick 		break;
223748Sdmick 
224748Sdmick 	default:
225748Sdmick 		return (FALSE);
226748Sdmick 	}
22711245SZhijun.Fu@Sun.COM #endif /* __xpv */
22811245SZhijun.Fu@Sun.COM 
22911245SZhijun.Fu@Sun.COM 	/*
23011245SZhijun.Fu@Sun.COM 	 * Try to get a valid mcfg_mem_base in early boot
23111245SZhijun.Fu@Sun.COM 	 * If failed, leave mem-mapped pci config space accessing disabled
23211245SZhijun.Fu@Sun.COM 	 * until pci boot code (pci_autoconfig) makes sure this is a PCIE
23311245SZhijun.Fu@Sun.COM 	 * platform.
23411245SZhijun.Fu@Sun.COM 	 */
23511245SZhijun.Fu@Sun.COM 	if (do_bsys_getprop(NULL, MCFG_PROPNAME, ecfginfo) != -1) {
23611245SZhijun.Fu@Sun.COM 		mcfg_mem_base = ecfginfo[0];
23711245SZhijun.Fu@Sun.COM 		mcfg_bus_start = ecfginfo[2];
23811245SZhijun.Fu@Sun.COM 		mcfg_bus_end = ecfginfo[3];
23911245SZhijun.Fu@Sun.COM 	}
24011245SZhijun.Fu@Sun.COM 
24111245SZhijun.Fu@Sun.COM 	/* See pci_cfgacc.c */
24211245SZhijun.Fu@Sun.COM 	pci_cfgacc_acc_p = pci_cfgacc_acc;
243748Sdmick 
244748Sdmick 	return (TRUE);
245748Sdmick }
246748Sdmick 
2475084Sjohnlev #if !defined(__xpv)
248748Sdmick 
249748Sdmick static int
pci_check_bios(void)250748Sdmick pci_check_bios(void)
251748Sdmick {
252748Sdmick 	struct bop_regs regs;
253748Sdmick 	uint32_t	carryflag;
254748Sdmick 	uint16_t	ax, dx;
255748Sdmick 
256748Sdmick 	bzero(&regs, sizeof (regs));
257748Sdmick 	regs.eax.word.ax = (PCI_FUNCTION_ID << 8) | PCI_BIOS_PRESENT;
258748Sdmick 
259748Sdmick 	BOP_DOINT(bootops, 0x1a, &regs);
260748Sdmick 	carryflag = regs.eflags & PS_C;
261748Sdmick 	ax = regs.eax.word.ax;
262748Sdmick 	dx = regs.edx.word.dx;
263748Sdmick 
264748Sdmick 	/* the carry flag must not be set */
265748Sdmick 	if (carryflag != 0)
266748Sdmick 		return (PCI_MECHANISM_NONE);
267748Sdmick 
268748Sdmick 	if (dx != ('P' | 'C'<<8))
269748Sdmick 		return (PCI_MECHANISM_NONE);
270748Sdmick 
271748Sdmick 	/* ah (the high byte of ax) must be zero */
272748Sdmick 	if ((ax & 0xff00) != 0)
273748Sdmick 		return (PCI_MECHANISM_NONE);
274748Sdmick 
275748Sdmick 	pci_bios_mech = (ax & 0x3);
276748Sdmick 	pci_bios_vers = regs.ebx.word.bx;
27710804SDana.Myers@Sun.COM 	pci_bios_maxbus = (regs.ecx.word.cx & 0xff);
278748Sdmick 
279748Sdmick 	switch (pci_bios_mech) {
280748Sdmick 	default:	/* ?!? */
281748Sdmick 	case 0:		/* supports neither? */
282748Sdmick 		return (PCI_MECHANISM_NONE);
283748Sdmick 
284748Sdmick 	case 1:
285748Sdmick 	case 3:		/* supports both */
286748Sdmick 		return (PCI_MECHANISM_1);
287748Sdmick 
288748Sdmick 	case 2:
289748Sdmick 		return (PCI_MECHANISM_2);
290748Sdmick 	}
291748Sdmick }
292748Sdmick 
293748Sdmick static int
pci_get_cfg_type(void)294748Sdmick pci_get_cfg_type(void)
295748Sdmick {
296748Sdmick 	/* Check to see if the config mechanism has been set in /etc/system */
297748Sdmick 	switch (PCI_CFG_TYPE) {
298748Sdmick 	default:
299748Sdmick 	case 0:
300748Sdmick 		break;
301748Sdmick 	case 1:
302748Sdmick 		return (PCI_MECHANISM_1);
303748Sdmick 	case 2:
304748Sdmick 		return (PCI_MECHANISM_2);
305748Sdmick 	case -1:
306748Sdmick 		return (PCI_MECHANISM_NONE);
307748Sdmick 	}
308748Sdmick 
309748Sdmick 	/* call one of the PCI detection algorithms */
310748Sdmick 	switch (PCI_PROBE_TYPE) {
311748Sdmick 	default:
312748Sdmick 	case 0:
313748Sdmick 		/* From pci_check() and pci_check_bios() */
314748Sdmick 		return (pci_bios_cfg_type);
315748Sdmick 	case -1:
316748Sdmick 		return (PCI_MECHANISM_NONE);
317748Sdmick 	}
318748Sdmick }
3195084Sjohnlev 
3205084Sjohnlev #endif	/* __xpv */
321