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(®s, sizeof (regs));
257748Sdmick regs.eax.word.ax = (PCI_FUNCTION_ID << 8) | PCI_BIOS_PRESENT;
258748Sdmick
259748Sdmick BOP_DOINT(bootops, 0x1a, ®s);
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