xref: /onnv-gate/usr/src/uts/i86pc/os/pci_cfgspace.c (revision 11787:92f11db549bc)
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*11787SKerry.Shu@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
24748Sdmick  * Use is subject to license terms.
25748Sdmick  */
26748Sdmick 
27748Sdmick /*
28748Sdmick  * PCI configuration space access routines
29748Sdmick  */
30748Sdmick 
31748Sdmick #include <sys/systm.h>
32748Sdmick #include <sys/psw.h>
33748Sdmick #include <sys/bootconf.h>
34748Sdmick #include <sys/reboot.h>
35748Sdmick #include <sys/pci_impl.h>
36748Sdmick #include <sys/pci_cfgspace.h>
37748Sdmick #include <sys/pci_cfgspace_impl.h>
3811245SZhijun.Fu@Sun.COM #include <sys/pci_cfgacc.h>
395084Sjohnlev #if defined(__xpv)
405084Sjohnlev #include <sys/hypervisor.h>
4111245SZhijun.Fu@Sun.COM #endif
4211245SZhijun.Fu@Sun.COM 
4311245SZhijun.Fu@Sun.COM #if defined(__xpv)
445084Sjohnlev int pci_max_nbus = 0xFE;
455084Sjohnlev #endif
46748Sdmick int pci_bios_cfg_type = PCI_MECHANISM_UNKNOWN;
4710804SDana.Myers@Sun.COM int pci_bios_maxbus;
48748Sdmick int pci_bios_mech;
49748Sdmick int pci_bios_vers;
50748Sdmick 
51748Sdmick /*
52748Sdmick  * These two variables can be used to force a configuration mechanism or
53748Sdmick  * to force which function is used to probe for the presence of the PCI bus.
54748Sdmick  */
55748Sdmick int	PCI_CFG_TYPE = 0;
56748Sdmick int	PCI_PROBE_TYPE = 0;
57748Sdmick 
58748Sdmick /*
5911245SZhijun.Fu@Sun.COM  * No valid mcfg_mem_base by default, and accessing pci config space
6011245SZhijun.Fu@Sun.COM  * in mem-mapped way is disabled.
6111245SZhijun.Fu@Sun.COM  */
6211245SZhijun.Fu@Sun.COM uint64_t mcfg_mem_base = 0;
6311245SZhijun.Fu@Sun.COM uint8_t mcfg_bus_start = 0;
6411245SZhijun.Fu@Sun.COM uint8_t mcfg_bus_end = 0xff;
6511245SZhijun.Fu@Sun.COM 
6611245SZhijun.Fu@Sun.COM /*
67748Sdmick  * These function pointers lead to the actual implementation routines
68748Sdmick  * for configuration space access.  Normally they lead to either the
69748Sdmick  * pci_mech1_* or pci_mech2_* routines, but they can also lead to
70748Sdmick  * routines that work around chipset bugs.
7111245SZhijun.Fu@Sun.COM  * These functions are accessing pci config space via I/O way.
7211245SZhijun.Fu@Sun.COM  * Pci_cfgacc_get/put functions shoul be used as more common interfaces,
7311245SZhijun.Fu@Sun.COM  * which also provide accessing pci config space via mem-mapped way.
74748Sdmick  */
75748Sdmick uint8_t (*pci_getb_func)(int bus, int dev, int func, int reg);
76748Sdmick uint16_t (*pci_getw_func)(int bus, int dev, int func, int reg);
77748Sdmick uint32_t (*pci_getl_func)(int bus, int dev, int func, int reg);
78748Sdmick void (*pci_putb_func)(int bus, int dev, int func, int reg, uint8_t val);
79748Sdmick void (*pci_putw_func)(int bus, int dev, int func, int reg, uint16_t val);
80748Sdmick void (*pci_putl_func)(int bus, int dev, int func, int reg, uint32_t val);
81748Sdmick 
8211245SZhijun.Fu@Sun.COM extern void (*pci_cfgacc_acc_p)(pci_cfgacc_req_t *req);
8311245SZhijun.Fu@Sun.COM 
84748Sdmick /*
85748Sdmick  * Internal routines
86748Sdmick  */
87748Sdmick static int pci_check(void);
885084Sjohnlev 
895084Sjohnlev #if !defined(__xpv)
90748Sdmick static int pci_check_bios(void);
91748Sdmick static int pci_get_cfg_type(void);
925084Sjohnlev #endif
93748Sdmick 
94*11787SKerry.Shu@Sun.COM /* for legacy io-based config space access */
95748Sdmick kmutex_t pcicfg_mutex;
96748Sdmick 
97*11787SKerry.Shu@Sun.COM /* for mmio-based config space access */
98*11787SKerry.Shu@Sun.COM kmutex_t pcicfg_mmio_mutex;
99*11787SKerry.Shu@Sun.COM 
100748Sdmick /* ..except Orion and Neptune, which have to have their own */
101748Sdmick kmutex_t pcicfg_chipset_mutex;
102748Sdmick 
103748Sdmick void
104748Sdmick pci_cfgspace_init(void)
105748Sdmick {
1061901Sdilpreet 	mutex_init(&pcicfg_mutex, NULL, MUTEX_SPIN,
1071901Sdilpreet 	    (ddi_iblock_cookie_t)ipltospl(15));
108*11787SKerry.Shu@Sun.COM 	mutex_init(&pcicfg_mmio_mutex, NULL, MUTEX_SPIN,
109*11787SKerry.Shu@Sun.COM 	    (ddi_iblock_cookie_t)ipltospl(DISP_LEVEL));
1101901Sdilpreet 	mutex_init(&pcicfg_chipset_mutex, NULL, MUTEX_SPIN,
1111901Sdilpreet 	    (ddi_iblock_cookie_t)ipltospl(15));
112748Sdmick 	if (!pci_check()) {
113748Sdmick 		mutex_destroy(&pcicfg_mutex);
114*11787SKerry.Shu@Sun.COM 		mutex_destroy(&pcicfg_mmio_mutex);
115748Sdmick 		mutex_destroy(&pcicfg_chipset_mutex);
116748Sdmick 	}
117748Sdmick }
118748Sdmick 
119748Sdmick /*
12011245SZhijun.Fu@Sun.COM  * This code determines if this system supports PCI/PCIE and which
121748Sdmick  * type of configuration access method is used
122748Sdmick  */
123748Sdmick static int
124748Sdmick pci_check(void)
125748Sdmick {
12611245SZhijun.Fu@Sun.COM 	uint64_t ecfginfo[4];
12711245SZhijun.Fu@Sun.COM 
128748Sdmick 	/*
129748Sdmick 	 * Only do this once.  NB:  If this is not a PCI system, and we
130748Sdmick 	 * get called twice, we can't detect it and will probably die
131748Sdmick 	 * horribly when we try to ask the BIOS whether PCI is present.
132748Sdmick 	 * This code is safe *ONLY* during system startup when the
133748Sdmick 	 * BIOS is still available.
134748Sdmick 	 */
135748Sdmick 	if (pci_bios_cfg_type != PCI_MECHANISM_UNKNOWN)
136748Sdmick 		return (TRUE);
137748Sdmick 
1385084Sjohnlev #if defined(__xpv)
1395084Sjohnlev 	/*
1405084Sjohnlev 	 * only support PCI config mechanism 1 in i86xpv. This should be fine
1415084Sjohnlev 	 * since the other ones are workarounds for old broken H/W which won't
1425084Sjohnlev 	 * be supported in i86xpv anyway.
1435084Sjohnlev 	 */
1445084Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info)) {
1455084Sjohnlev 		pci_bios_cfg_type = PCI_MECHANISM_1;
1465084Sjohnlev 		pci_getb_func = pci_mech1_getb;
1475084Sjohnlev 		pci_getw_func = pci_mech1_getw;
1485084Sjohnlev 		pci_getl_func = pci_mech1_getl;
1495084Sjohnlev 		pci_putb_func = pci_mech1_putb;
1505084Sjohnlev 		pci_putw_func = pci_mech1_putw;
1515084Sjohnlev 		pci_putl_func = pci_mech1_putl;
1525084Sjohnlev 
1535084Sjohnlev 		/*
1545084Sjohnlev 		 * Since we can't get the BIOS info in i86xpv, we will do an
1555084Sjohnlev 		 * exhaustive search of all PCI buses. We have to do this until
1565084Sjohnlev 		 * we start using the PCI information in ACPI.
1575084Sjohnlev 		 */
15810804SDana.Myers@Sun.COM 		pci_bios_maxbus = pci_max_nbus;
1595084Sjohnlev 	}
1605084Sjohnlev #else /* !__xpv */
1615084Sjohnlev 
162748Sdmick 	pci_bios_cfg_type = pci_check_bios();
163748Sdmick 
164748Sdmick 	if (pci_bios_cfg_type == PCI_MECHANISM_NONE)
1652123Sszhou 		pci_bios_cfg_type = PCI_MECHANISM_1;	/* default to mech 1 */
166748Sdmick 
167748Sdmick 	switch (pci_get_cfg_type()) {
168748Sdmick 	case PCI_MECHANISM_1:
169748Sdmick 		if (pci_is_broken_orion()) {
170748Sdmick 			pci_getb_func = pci_orion_getb;
171748Sdmick 			pci_getw_func = pci_orion_getw;
172748Sdmick 			pci_getl_func = pci_orion_getl;
173748Sdmick 			pci_putb_func = pci_orion_putb;
174748Sdmick 			pci_putw_func = pci_orion_putw;
175748Sdmick 			pci_putl_func = pci_orion_putl;
176748Sdmick 		} else {
177748Sdmick 			pci_getb_func = pci_mech1_getb;
178748Sdmick 			pci_getw_func = pci_mech1_getw;
179748Sdmick 			pci_getl_func = pci_mech1_getl;
180748Sdmick 			pci_putb_func = pci_mech1_putb;
181748Sdmick 			pci_putw_func = pci_mech1_putw;
182748Sdmick 			pci_putl_func = pci_mech1_putl;
183748Sdmick 		}
184748Sdmick 		break;
185748Sdmick 
186748Sdmick 	case PCI_MECHANISM_2:
187748Sdmick 		if (pci_check_neptune()) {
188748Sdmick 			/*
189748Sdmick 			 * The BIOS for some systems with the Intel
190748Sdmick 			 * Neptune chipset seem to default to #2 even
191748Sdmick 			 * though the chipset can do #1.  Override
192748Sdmick 			 * the BIOS so that MP systems will work
193748Sdmick 			 * correctly.
194748Sdmick 			 */
195748Sdmick 
196748Sdmick 			pci_getb_func = pci_neptune_getb;
197748Sdmick 			pci_getw_func = pci_neptune_getw;
198748Sdmick 			pci_getl_func = pci_neptune_getl;
199748Sdmick 			pci_putb_func = pci_neptune_putb;
200748Sdmick 			pci_putw_func = pci_neptune_putw;
201748Sdmick 			pci_putl_func = pci_neptune_putl;
202748Sdmick 		} else {
203748Sdmick 			pci_getb_func = pci_mech2_getb;
204748Sdmick 			pci_getw_func = pci_mech2_getw;
205748Sdmick 			pci_getl_func = pci_mech2_getl;
206748Sdmick 			pci_putb_func = pci_mech2_putb;
207748Sdmick 			pci_putw_func = pci_mech2_putw;
208748Sdmick 			pci_putl_func = pci_mech2_putl;
209748Sdmick 		}
210748Sdmick 		break;
211748Sdmick 
212748Sdmick 	default:
213748Sdmick 		return (FALSE);
214748Sdmick 	}
21511245SZhijun.Fu@Sun.COM #endif /* __xpv */
21611245SZhijun.Fu@Sun.COM 
21711245SZhijun.Fu@Sun.COM 	/*
21811245SZhijun.Fu@Sun.COM 	 * Try to get a valid mcfg_mem_base in early boot
21911245SZhijun.Fu@Sun.COM 	 * If failed, leave mem-mapped pci config space accessing disabled
22011245SZhijun.Fu@Sun.COM 	 * until pci boot code (pci_autoconfig) makes sure this is a PCIE
22111245SZhijun.Fu@Sun.COM 	 * platform.
22211245SZhijun.Fu@Sun.COM 	 */
22311245SZhijun.Fu@Sun.COM 	if (do_bsys_getprop(NULL, MCFG_PROPNAME, ecfginfo) != -1) {
22411245SZhijun.Fu@Sun.COM 		mcfg_mem_base = ecfginfo[0];
22511245SZhijun.Fu@Sun.COM 		mcfg_bus_start = ecfginfo[2];
22611245SZhijun.Fu@Sun.COM 		mcfg_bus_end = ecfginfo[3];
22711245SZhijun.Fu@Sun.COM 	}
22811245SZhijun.Fu@Sun.COM 
22911245SZhijun.Fu@Sun.COM 	/* See pci_cfgacc.c */
23011245SZhijun.Fu@Sun.COM 	pci_cfgacc_acc_p = pci_cfgacc_acc;
231748Sdmick 
232748Sdmick 	return (TRUE);
233748Sdmick }
234748Sdmick 
2355084Sjohnlev #if !defined(__xpv)
236748Sdmick 
237748Sdmick static int
238748Sdmick pci_check_bios(void)
239748Sdmick {
240748Sdmick 	struct bop_regs regs;
241748Sdmick 	uint32_t	carryflag;
242748Sdmick 	uint16_t	ax, dx;
243748Sdmick 
244748Sdmick 	bzero(&regs, sizeof (regs));
245748Sdmick 	regs.eax.word.ax = (PCI_FUNCTION_ID << 8) | PCI_BIOS_PRESENT;
246748Sdmick 
247748Sdmick 	BOP_DOINT(bootops, 0x1a, &regs);
248748Sdmick 	carryflag = regs.eflags & PS_C;
249748Sdmick 	ax = regs.eax.word.ax;
250748Sdmick 	dx = regs.edx.word.dx;
251748Sdmick 
252748Sdmick 	/* the carry flag must not be set */
253748Sdmick 	if (carryflag != 0)
254748Sdmick 		return (PCI_MECHANISM_NONE);
255748Sdmick 
256748Sdmick 	if (dx != ('P' | 'C'<<8))
257748Sdmick 		return (PCI_MECHANISM_NONE);
258748Sdmick 
259748Sdmick 	/* ah (the high byte of ax) must be zero */
260748Sdmick 	if ((ax & 0xff00) != 0)
261748Sdmick 		return (PCI_MECHANISM_NONE);
262748Sdmick 
263748Sdmick 	pci_bios_mech = (ax & 0x3);
264748Sdmick 	pci_bios_vers = regs.ebx.word.bx;
26510804SDana.Myers@Sun.COM 	pci_bios_maxbus = (regs.ecx.word.cx & 0xff);
266748Sdmick 
267748Sdmick 	switch (pci_bios_mech) {
268748Sdmick 	default:	/* ?!? */
269748Sdmick 	case 0:		/* supports neither? */
270748Sdmick 		return (PCI_MECHANISM_NONE);
271748Sdmick 
272748Sdmick 	case 1:
273748Sdmick 	case 3:		/* supports both */
274748Sdmick 		return (PCI_MECHANISM_1);
275748Sdmick 
276748Sdmick 	case 2:
277748Sdmick 		return (PCI_MECHANISM_2);
278748Sdmick 	}
279748Sdmick }
280748Sdmick 
281748Sdmick static int
282748Sdmick pci_get_cfg_type(void)
283748Sdmick {
284748Sdmick 	/* Check to see if the config mechanism has been set in /etc/system */
285748Sdmick 	switch (PCI_CFG_TYPE) {
286748Sdmick 	default:
287748Sdmick 	case 0:
288748Sdmick 		break;
289748Sdmick 	case 1:
290748Sdmick 		return (PCI_MECHANISM_1);
291748Sdmick 	case 2:
292748Sdmick 		return (PCI_MECHANISM_2);
293748Sdmick 	case -1:
294748Sdmick 		return (PCI_MECHANISM_NONE);
295748Sdmick 	}
296748Sdmick 
297748Sdmick 	/* call one of the PCI detection algorithms */
298748Sdmick 	switch (PCI_PROBE_TYPE) {
299748Sdmick 	default:
300748Sdmick 	case 0:
301748Sdmick 		/* From pci_check() and pci_check_bios() */
302748Sdmick 		return (pci_bios_cfg_type);
303748Sdmick 	case -1:
304748Sdmick 		return (PCI_MECHANISM_NONE);
305748Sdmick 	}
306748Sdmick }
3075084Sjohnlev 
3085084Sjohnlev #endif	/* __xpv */
309