1c88420b3Sdmick /* 2c88420b3Sdmick * CDDL HEADER START 3c88420b3Sdmick * 4c88420b3Sdmick * The contents of this file are subject to the terms of the 5c88420b3Sdmick * Common Development and Distribution License (the "License"). 6c88420b3Sdmick * You may not use this file except in compliance with the License. 7c88420b3Sdmick * 8c88420b3Sdmick * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9c88420b3Sdmick * or http://www.opensolaris.org/os/licensing. 10c88420b3Sdmick * See the License for the specific language governing permissions 11c88420b3Sdmick * and limitations under the License. 12c88420b3Sdmick * 13c88420b3Sdmick * When distributing Covered Code, include this CDDL HEADER in each 14c88420b3Sdmick * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15c88420b3Sdmick * If applicable, add the following below this CDDL HEADER, with the 16c88420b3Sdmick * fields enclosed by brackets "[]" replaced with your own identifying 17c88420b3Sdmick * information: Portions Copyright [yyyy] [name of copyright owner] 18c88420b3Sdmick * 19c88420b3Sdmick * CDDL HEADER END 20c88420b3Sdmick */ 21c88420b3Sdmick 22c88420b3Sdmick /* 23*8d7fafffSZhi-Jun Robin Fu * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24c88420b3Sdmick */ 25c88420b3Sdmick 26c88420b3Sdmick /* 27c88420b3Sdmick * PCI configuration space access routines 28c88420b3Sdmick */ 29c88420b3Sdmick 30c88420b3Sdmick #include <sys/systm.h> 31c88420b3Sdmick #include <sys/psw.h> 32c88420b3Sdmick #include <sys/bootconf.h> 33c88420b3Sdmick #include <sys/reboot.h> 34c88420b3Sdmick #include <sys/pci_impl.h> 35c88420b3Sdmick #include <sys/pci_cfgspace.h> 36c88420b3Sdmick #include <sys/pci_cfgspace_impl.h> 37c0da6274SZhi-Jun Robin Fu #include <sys/pci_cfgacc.h> 38843e1988Sjohnlev #if defined(__xpv) 39843e1988Sjohnlev #include <sys/hypervisor.h> 40843e1988Sjohnlev #endif 41843e1988Sjohnlev 42c0da6274SZhi-Jun Robin Fu #if defined(__xpv) 43c0da6274SZhi-Jun Robin Fu int pci_max_nbus = 0xFE; 44c0da6274SZhi-Jun Robin Fu #endif 45c88420b3Sdmick int pci_bios_cfg_type = PCI_MECHANISM_UNKNOWN; 4647310cedSDana Myers int pci_bios_maxbus; 47c88420b3Sdmick int pci_bios_mech; 48c88420b3Sdmick int pci_bios_vers; 49c88420b3Sdmick 50c88420b3Sdmick /* 51c88420b3Sdmick * These two variables can be used to force a configuration mechanism or 52c88420b3Sdmick * to force which function is used to probe for the presence of the PCI bus. 53c88420b3Sdmick */ 54c88420b3Sdmick int PCI_CFG_TYPE = 0; 55c88420b3Sdmick int PCI_PROBE_TYPE = 0; 56c88420b3Sdmick 57c88420b3Sdmick /* 58c0da6274SZhi-Jun Robin Fu * No valid mcfg_mem_base by default, and accessing pci config space 59c0da6274SZhi-Jun Robin Fu * in mem-mapped way is disabled. 60c0da6274SZhi-Jun Robin Fu */ 61c0da6274SZhi-Jun Robin Fu uint64_t mcfg_mem_base = 0; 62c0da6274SZhi-Jun Robin Fu uint8_t mcfg_bus_start = 0; 63c0da6274SZhi-Jun Robin Fu uint8_t mcfg_bus_end = 0xff; 64c0da6274SZhi-Jun Robin Fu 65c0da6274SZhi-Jun Robin Fu /* 66*8d7fafffSZhi-Jun Robin Fu * Maximum offset in config space when not using MMIO 67*8d7fafffSZhi-Jun Robin Fu */ 68*8d7fafffSZhi-Jun Robin Fu uint_t pci_iocfg_max_offset = 0xff; 69*8d7fafffSZhi-Jun Robin Fu 70*8d7fafffSZhi-Jun Robin Fu /* 71c88420b3Sdmick * These function pointers lead to the actual implementation routines 72c88420b3Sdmick * for configuration space access. Normally they lead to either the 73c88420b3Sdmick * pci_mech1_* or pci_mech2_* routines, but they can also lead to 74c88420b3Sdmick * routines that work around chipset bugs. 75c0da6274SZhi-Jun Robin Fu * These functions are accessing pci config space via I/O way. 76c0da6274SZhi-Jun Robin Fu * Pci_cfgacc_get/put functions shoul be used as more common interfaces, 77c0da6274SZhi-Jun Robin Fu * which also provide accessing pci config space via mem-mapped way. 78c88420b3Sdmick */ 79c88420b3Sdmick uint8_t (*pci_getb_func)(int bus, int dev, int func, int reg); 80c88420b3Sdmick uint16_t (*pci_getw_func)(int bus, int dev, int func, int reg); 81c88420b3Sdmick uint32_t (*pci_getl_func)(int bus, int dev, int func, int reg); 82c88420b3Sdmick void (*pci_putb_func)(int bus, int dev, int func, int reg, uint8_t val); 83c88420b3Sdmick void (*pci_putw_func)(int bus, int dev, int func, int reg, uint16_t val); 84c88420b3Sdmick void (*pci_putl_func)(int bus, int dev, int func, int reg, uint32_t val); 85c88420b3Sdmick 86c0da6274SZhi-Jun Robin Fu extern void (*pci_cfgacc_acc_p)(pci_cfgacc_req_t *req); 87c0da6274SZhi-Jun Robin Fu 88c88420b3Sdmick /* 89c88420b3Sdmick * Internal routines 90c88420b3Sdmick */ 91c88420b3Sdmick static int pci_check(void); 92843e1988Sjohnlev 93843e1988Sjohnlev #if !defined(__xpv) 94c88420b3Sdmick static int pci_check_bios(void); 95c88420b3Sdmick static int pci_get_cfg_type(void); 96843e1988Sjohnlev #endif 97c88420b3Sdmick 9813763277SGuoli Shu /* for legacy io-based config space access */ 99c88420b3Sdmick kmutex_t pcicfg_mutex; 100c88420b3Sdmick 10113763277SGuoli Shu /* for mmio-based config space access */ 10213763277SGuoli Shu kmutex_t pcicfg_mmio_mutex; 10313763277SGuoli Shu 104c88420b3Sdmick /* ..except Orion and Neptune, which have to have their own */ 105c88420b3Sdmick kmutex_t pcicfg_chipset_mutex; 106c88420b3Sdmick 107c88420b3Sdmick void 108c88420b3Sdmick pci_cfgspace_init(void) 109c88420b3Sdmick { 1107f58d724Sdilpreet mutex_init(&pcicfg_mutex, NULL, MUTEX_SPIN, 1117f58d724Sdilpreet (ddi_iblock_cookie_t)ipltospl(15)); 11213763277SGuoli Shu mutex_init(&pcicfg_mmio_mutex, NULL, MUTEX_SPIN, 11313763277SGuoli Shu (ddi_iblock_cookie_t)ipltospl(DISP_LEVEL)); 1147f58d724Sdilpreet mutex_init(&pcicfg_chipset_mutex, NULL, MUTEX_SPIN, 1157f58d724Sdilpreet (ddi_iblock_cookie_t)ipltospl(15)); 116c88420b3Sdmick if (!pci_check()) { 117c88420b3Sdmick mutex_destroy(&pcicfg_mutex); 11813763277SGuoli Shu mutex_destroy(&pcicfg_mmio_mutex); 119c88420b3Sdmick mutex_destroy(&pcicfg_chipset_mutex); 120c88420b3Sdmick } 121c88420b3Sdmick } 122c88420b3Sdmick 123c88420b3Sdmick /* 124c0da6274SZhi-Jun Robin Fu * This code determines if this system supports PCI/PCIE and which 125c88420b3Sdmick * type of configuration access method is used 126c88420b3Sdmick */ 127c88420b3Sdmick static int 128c88420b3Sdmick pci_check(void) 129c88420b3Sdmick { 130c0da6274SZhi-Jun Robin Fu uint64_t ecfginfo[4]; 131c0da6274SZhi-Jun Robin Fu 132c88420b3Sdmick /* 133c88420b3Sdmick * Only do this once. NB: If this is not a PCI system, and we 134c88420b3Sdmick * get called twice, we can't detect it and will probably die 135c88420b3Sdmick * horribly when we try to ask the BIOS whether PCI is present. 136c88420b3Sdmick * This code is safe *ONLY* during system startup when the 137c88420b3Sdmick * BIOS is still available. 138c88420b3Sdmick */ 139c88420b3Sdmick if (pci_bios_cfg_type != PCI_MECHANISM_UNKNOWN) 140c88420b3Sdmick return (TRUE); 141c88420b3Sdmick 142843e1988Sjohnlev #if defined(__xpv) 143843e1988Sjohnlev /* 144843e1988Sjohnlev * only support PCI config mechanism 1 in i86xpv. This should be fine 145843e1988Sjohnlev * since the other ones are workarounds for old broken H/W which won't 146843e1988Sjohnlev * be supported in i86xpv anyway. 147843e1988Sjohnlev */ 148843e1988Sjohnlev if (DOMAIN_IS_INITDOMAIN(xen_info)) { 149843e1988Sjohnlev pci_bios_cfg_type = PCI_MECHANISM_1; 150843e1988Sjohnlev pci_getb_func = pci_mech1_getb; 151843e1988Sjohnlev pci_getw_func = pci_mech1_getw; 152843e1988Sjohnlev pci_getl_func = pci_mech1_getl; 153843e1988Sjohnlev pci_putb_func = pci_mech1_putb; 154843e1988Sjohnlev pci_putw_func = pci_mech1_putw; 155843e1988Sjohnlev pci_putl_func = pci_mech1_putl; 156843e1988Sjohnlev 157843e1988Sjohnlev /* 158843e1988Sjohnlev * Since we can't get the BIOS info in i86xpv, we will do an 159843e1988Sjohnlev * exhaustive search of all PCI buses. We have to do this until 160843e1988Sjohnlev * we start using the PCI information in ACPI. 161843e1988Sjohnlev */ 16247310cedSDana Myers pci_bios_maxbus = pci_max_nbus; 163843e1988Sjohnlev } 164843e1988Sjohnlev #else /* !__xpv */ 165843e1988Sjohnlev 166c88420b3Sdmick pci_bios_cfg_type = pci_check_bios(); 167c88420b3Sdmick 168c88420b3Sdmick if (pci_bios_cfg_type == PCI_MECHANISM_NONE) 1697b3700d1Sszhou pci_bios_cfg_type = PCI_MECHANISM_1; /* default to mech 1 */ 170c88420b3Sdmick 171c88420b3Sdmick switch (pci_get_cfg_type()) { 172c88420b3Sdmick case PCI_MECHANISM_1: 173c88420b3Sdmick if (pci_is_broken_orion()) { 174c88420b3Sdmick pci_getb_func = pci_orion_getb; 175c88420b3Sdmick pci_getw_func = pci_orion_getw; 176c88420b3Sdmick pci_getl_func = pci_orion_getl; 177c88420b3Sdmick pci_putb_func = pci_orion_putb; 178c88420b3Sdmick pci_putw_func = pci_orion_putw; 179c88420b3Sdmick pci_putl_func = pci_orion_putl; 180*8d7fafffSZhi-Jun Robin Fu } else if (pci_check_amd_ioecs()) { 181*8d7fafffSZhi-Jun Robin Fu pci_getb_func = pci_mech1_amd_getb; 182*8d7fafffSZhi-Jun Robin Fu pci_getw_func = pci_mech1_amd_getw; 183*8d7fafffSZhi-Jun Robin Fu pci_getl_func = pci_mech1_amd_getl; 184*8d7fafffSZhi-Jun Robin Fu pci_putb_func = pci_mech1_amd_putb; 185*8d7fafffSZhi-Jun Robin Fu pci_putw_func = pci_mech1_amd_putw; 186*8d7fafffSZhi-Jun Robin Fu pci_putl_func = pci_mech1_amd_putl; 187*8d7fafffSZhi-Jun Robin Fu pci_iocfg_max_offset = 0xfff; 188c88420b3Sdmick } else { 189c88420b3Sdmick pci_getb_func = pci_mech1_getb; 190c88420b3Sdmick pci_getw_func = pci_mech1_getw; 191c88420b3Sdmick pci_getl_func = pci_mech1_getl; 192c88420b3Sdmick pci_putb_func = pci_mech1_putb; 193c88420b3Sdmick pci_putw_func = pci_mech1_putw; 194c88420b3Sdmick pci_putl_func = pci_mech1_putl; 195c88420b3Sdmick } 196c88420b3Sdmick break; 197c88420b3Sdmick 198c88420b3Sdmick case PCI_MECHANISM_2: 199c88420b3Sdmick if (pci_check_neptune()) { 200c88420b3Sdmick /* 201c88420b3Sdmick * The BIOS for some systems with the Intel 202c88420b3Sdmick * Neptune chipset seem to default to #2 even 203c88420b3Sdmick * though the chipset can do #1. Override 204c88420b3Sdmick * the BIOS so that MP systems will work 205c88420b3Sdmick * correctly. 206c88420b3Sdmick */ 207c88420b3Sdmick 208c88420b3Sdmick pci_getb_func = pci_neptune_getb; 209c88420b3Sdmick pci_getw_func = pci_neptune_getw; 210c88420b3Sdmick pci_getl_func = pci_neptune_getl; 211c88420b3Sdmick pci_putb_func = pci_neptune_putb; 212c88420b3Sdmick pci_putw_func = pci_neptune_putw; 213c88420b3Sdmick pci_putl_func = pci_neptune_putl; 214c88420b3Sdmick } else { 215c88420b3Sdmick pci_getb_func = pci_mech2_getb; 216c88420b3Sdmick pci_getw_func = pci_mech2_getw; 217c88420b3Sdmick pci_getl_func = pci_mech2_getl; 218c88420b3Sdmick pci_putb_func = pci_mech2_putb; 219c88420b3Sdmick pci_putw_func = pci_mech2_putw; 220c88420b3Sdmick pci_putl_func = pci_mech2_putl; 221c88420b3Sdmick } 222c88420b3Sdmick break; 223c88420b3Sdmick 224c88420b3Sdmick default: 225c88420b3Sdmick return (FALSE); 226c88420b3Sdmick } 227c0da6274SZhi-Jun Robin Fu #endif /* __xpv */ 228c0da6274SZhi-Jun Robin Fu 229c0da6274SZhi-Jun Robin Fu /* 230c0da6274SZhi-Jun Robin Fu * Try to get a valid mcfg_mem_base in early boot 231c0da6274SZhi-Jun Robin Fu * If failed, leave mem-mapped pci config space accessing disabled 232c0da6274SZhi-Jun Robin Fu * until pci boot code (pci_autoconfig) makes sure this is a PCIE 233c0da6274SZhi-Jun Robin Fu * platform. 234c0da6274SZhi-Jun Robin Fu */ 235c0da6274SZhi-Jun Robin Fu if (do_bsys_getprop(NULL, MCFG_PROPNAME, ecfginfo) != -1) { 236c0da6274SZhi-Jun Robin Fu mcfg_mem_base = ecfginfo[0]; 237c0da6274SZhi-Jun Robin Fu mcfg_bus_start = ecfginfo[2]; 238c0da6274SZhi-Jun Robin Fu mcfg_bus_end = ecfginfo[3]; 239c0da6274SZhi-Jun Robin Fu } 240c0da6274SZhi-Jun Robin Fu 241c0da6274SZhi-Jun Robin Fu /* See pci_cfgacc.c */ 242c0da6274SZhi-Jun Robin Fu pci_cfgacc_acc_p = pci_cfgacc_acc; 243c88420b3Sdmick 244c88420b3Sdmick return (TRUE); 245c88420b3Sdmick } 246c88420b3Sdmick 247843e1988Sjohnlev #if !defined(__xpv) 248c88420b3Sdmick 249c88420b3Sdmick static int 250c88420b3Sdmick pci_check_bios(void) 251c88420b3Sdmick { 252c88420b3Sdmick struct bop_regs regs; 253c88420b3Sdmick uint32_t carryflag; 254c88420b3Sdmick uint16_t ax, dx; 255c88420b3Sdmick 256c88420b3Sdmick bzero(®s, sizeof (regs)); 257c88420b3Sdmick regs.eax.word.ax = (PCI_FUNCTION_ID << 8) | PCI_BIOS_PRESENT; 258c88420b3Sdmick 259c88420b3Sdmick BOP_DOINT(bootops, 0x1a, ®s); 260c88420b3Sdmick carryflag = regs.eflags & PS_C; 261c88420b3Sdmick ax = regs.eax.word.ax; 262c88420b3Sdmick dx = regs.edx.word.dx; 263c88420b3Sdmick 264c88420b3Sdmick /* the carry flag must not be set */ 265c88420b3Sdmick if (carryflag != 0) 266c88420b3Sdmick return (PCI_MECHANISM_NONE); 267c88420b3Sdmick 268c88420b3Sdmick if (dx != ('P' | 'C'<<8)) 269c88420b3Sdmick return (PCI_MECHANISM_NONE); 270c88420b3Sdmick 271c88420b3Sdmick /* ah (the high byte of ax) must be zero */ 272c88420b3Sdmick if ((ax & 0xff00) != 0) 273c88420b3Sdmick return (PCI_MECHANISM_NONE); 274c88420b3Sdmick 275c88420b3Sdmick pci_bios_mech = (ax & 0x3); 276c88420b3Sdmick pci_bios_vers = regs.ebx.word.bx; 27747310cedSDana Myers pci_bios_maxbus = (regs.ecx.word.cx & 0xff); 278c88420b3Sdmick 279c88420b3Sdmick switch (pci_bios_mech) { 280c88420b3Sdmick default: /* ?!? */ 281c88420b3Sdmick case 0: /* supports neither? */ 282c88420b3Sdmick return (PCI_MECHANISM_NONE); 283c88420b3Sdmick 284c88420b3Sdmick case 1: 285c88420b3Sdmick case 3: /* supports both */ 286c88420b3Sdmick return (PCI_MECHANISM_1); 287c88420b3Sdmick 288c88420b3Sdmick case 2: 289c88420b3Sdmick return (PCI_MECHANISM_2); 290c88420b3Sdmick } 291c88420b3Sdmick } 292c88420b3Sdmick 293c88420b3Sdmick static int 294c88420b3Sdmick pci_get_cfg_type(void) 295c88420b3Sdmick { 296c88420b3Sdmick /* Check to see if the config mechanism has been set in /etc/system */ 297c88420b3Sdmick switch (PCI_CFG_TYPE) { 298c88420b3Sdmick default: 299c88420b3Sdmick case 0: 300c88420b3Sdmick break; 301c88420b3Sdmick case 1: 302c88420b3Sdmick return (PCI_MECHANISM_1); 303c88420b3Sdmick case 2: 304c88420b3Sdmick return (PCI_MECHANISM_2); 305c88420b3Sdmick case -1: 306c88420b3Sdmick return (PCI_MECHANISM_NONE); 307c88420b3Sdmick } 308c88420b3Sdmick 309c88420b3Sdmick /* call one of the PCI detection algorithms */ 310c88420b3Sdmick switch (PCI_PROBE_TYPE) { 311c88420b3Sdmick default: 312c88420b3Sdmick case 0: 313c88420b3Sdmick /* From pci_check() and pci_check_bios() */ 314c88420b3Sdmick return (pci_bios_cfg_type); 315c88420b3Sdmick case -1: 316c88420b3Sdmick return (PCI_MECHANISM_NONE); 317c88420b3Sdmick } 318c88420b3Sdmick } 319843e1988Sjohnlev 320843e1988Sjohnlev #endif /* __xpv */ 321