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