pci.c revision 191069
1244769Sglebius/*- 2126258Smlaier * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3223637Sbz * Copyright (c) 2000, Michael Smith <msmith@freebsd.org> 4244769Sglebius * Copyright (c) 2000, BSDi 5126258Smlaier * All rights reserved. 6126258Smlaier * 7126258Smlaier * Redistribution and use in source and binary forms, with or without 8126258Smlaier * modification, are permitted provided that the following conditions 9126258Smlaier * are met: 10126258Smlaier * 1. Redistributions of source code must retain the above copyright 11126258Smlaier * notice unmodified, this list of conditions, and the following 12126258Smlaier * disclaimer. 13126258Smlaier * 2. Redistributions in binary form must reproduce the above copyright 14126258Smlaier * notice, this list of conditions and the following disclaimer in the 15126258Smlaier * documentation and/or other materials provided with the distribution. 16126258Smlaier * 17126258Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18126258Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19126258Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20126258Smlaier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21126258Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22126258Smlaier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23126258Smlaier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24126258Smlaier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25126258Smlaier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26126258Smlaier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27126258Smlaier */ 28126258Smlaier 29126258Smlaier#include <sys/cdefs.h> 30126258Smlaier__FBSDID("$FreeBSD: head/sys/dev/pci/pci.c 191069 2009-04-14 18:32:37Z jhb $"); 31126258Smlaier 32126258Smlaier#include "opt_bus.h" 33126258Smlaier 34126258Smlaier#include <sys/param.h> 35244769Sglebius#include <sys/systm.h> 36126258Smlaier#include <sys/malloc.h> 37126258Smlaier#include <sys/module.h> 38240233Sglebius#include <sys/linker.h> 39171168Smlaier#include <sys/fcntl.h> 40126261Smlaier#include <sys/conf.h> 41240233Sglebius#include <sys/kernel.h> 42240233Sglebius#include <sys/queue.h> 43126261Smlaier#include <sys/sysctl.h> 44126261Smlaier#include <sys/endian.h> 45153110Sru 46126258Smlaier#include <vm/vm.h> 47240233Sglebius#include <vm/pmap.h> 48240233Sglebius#include <vm/vm_extern.h> 49240233Sglebius 50240233Sglebius#include <sys/bus.h> 51240233Sglebius#include <machine/bus.h> 52240233Sglebius#include <sys/rman.h> 53240233Sglebius#include <machine/resource.h> 54126258Smlaier 55240233Sglebius#if defined(__i386__) || defined(__amd64__) 56240233Sglebius#include <machine/intr_machdep.h> 57240233Sglebius#endif 58126258Smlaier 59126261Smlaier#include <sys/pciio.h> 60240233Sglebius#include <dev/pci/pcireg.h> 61240233Sglebius#include <dev/pci/pcivar.h> 62126258Smlaier#include <dev/pci/pci_private.h> 63126258Smlaier 64126258Smlaier#include "pcib_if.h" 65126258Smlaier#include "pci_if.h" 66171168Smlaier 67240233Sglebius#ifdef __HAVE_ACPI 68126258Smlaier#include <contrib/dev/acpica/acpi.h> 69240233Sglebius#include "acpi_if.h" 70240233Sglebius#else 71240233Sglebius#define ACPI_PWR_FOR_SLEEP(x, y, z) 72240233Sglebius#endif 73240233Sglebius 74126258Smlaierstatic pci_addr_t pci_mapbase(uint64_t mapreg); 75126258Smlaierstatic const char *pci_maptype(uint64_t mapreg); 76240233Sglebiusstatic int pci_mapsize(uint64_t testval); 77240233Sglebiusstatic int pci_maprange(uint64_t mapreg); 78240233Sglebiusstatic void pci_fixancient(pcicfgregs *cfg); 79126258Smlaier 80126258Smlaierstatic int pci_porten(device_t dev); 81240233Sglebiusstatic int pci_memen(device_t dev); 82126258Smlaierstatic void pci_assign_interrupt(device_t bus, device_t dev, 83126258Smlaier int force_route); 84126258Smlaierstatic int pci_add_map(device_t bus, device_t dev, int reg, 85240233Sglebius struct resource_list *rl, int force, int prefetch); 86126258Smlaierstatic int pci_probe(device_t dev); 87126258Smlaierstatic int pci_attach(device_t dev); 88240494Sglebiusstatic void pci_load_vendor_data(void); 89240494Sglebiusstatic int pci_describe_parse_line(char **ptr, int *vendor, 90126258Smlaier int *device, char **desc); 91126258Smlaierstatic char *pci_describe_device(device_t dev); 92126258Smlaierstatic int pci_modevent(module_t mod, int what, void *arg); 93126258Smlaierstatic void pci_hdrtypedata(device_t pcib, int b, int s, int f, 94126261Smlaier pcicfgregs *cfg); 95126261Smlaierstatic void pci_read_extcap(device_t pcib, pcicfgregs *cfg); 96126258Smlaierstatic int pci_read_vpd_reg(device_t pcib, pcicfgregs *cfg, 97126258Smlaier int reg, uint32_t *data); 98126261Smlaier#if 0 99163606Srwatsonstatic int pci_write_vpd_reg(device_t pcib, pcicfgregs *cfg, 100126258Smlaier int reg, uint32_t data); 101223637Sbz#endif 102126258Smlaierstatic void pci_read_vpd(device_t pcib, pcicfgregs *cfg); 103126258Smlaierstatic void pci_disable_msi(device_t dev); 104126258Smlaierstatic void pci_enable_msi(device_t dev, uint64_t address, 105126258Smlaier uint16_t data); 106126258Smlaierstatic void pci_enable_msix(device_t dev, u_int index, 107223637Sbz uint64_t address, uint32_t data); 108223637Sbzstatic void pci_mask_msix(device_t dev, u_int index); 109223637Sbzstatic void pci_unmask_msix(device_t dev, u_int index); 110223637Sbzstatic int pci_msi_blacklisted(void); 111223637Sbzstatic void pci_resume_msi(device_t dev); 112270574Sglebiusstatic void pci_resume_msix(device_t dev); 113223637Sbz 114223637Sbzstatic device_method_t pci_methods[] = { 115223637Sbz /* Device interface */ 116223637Sbz DEVMETHOD(device_probe, pci_probe), 117223637Sbz DEVMETHOD(device_attach, pci_attach), 118223637Sbz DEVMETHOD(device_detach, bus_generic_detach), 119223637Sbz DEVMETHOD(device_shutdown, bus_generic_shutdown), 120223637Sbz DEVMETHOD(device_suspend, pci_suspend), 121223637Sbz DEVMETHOD(device_resume, pci_resume), 122223637Sbz 123223637Sbz /* Bus interface */ 124223637Sbz DEVMETHOD(bus_print_child, pci_print_child), 125223637Sbz DEVMETHOD(bus_probe_nomatch, pci_probe_nomatch), 126223637Sbz DEVMETHOD(bus_read_ivar, pci_read_ivar), 127223637Sbz DEVMETHOD(bus_write_ivar, pci_write_ivar), 128240233Sglebius DEVMETHOD(bus_driver_added, pci_driver_added), 129240233Sglebius DEVMETHOD(bus_setup_intr, pci_setup_intr), 130240233Sglebius DEVMETHOD(bus_teardown_intr, pci_teardown_intr), 131240233Sglebius 132240233Sglebius DEVMETHOD(bus_get_resource_list,pci_get_resource_list), 133240233Sglebius DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 134240233Sglebius DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 135240233Sglebius DEVMETHOD(bus_delete_resource, pci_delete_resource), 136240233Sglebius DEVMETHOD(bus_alloc_resource, pci_alloc_resource), 137240233Sglebius DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 138240233Sglebius DEVMETHOD(bus_activate_resource, pci_activate_resource), 139240233Sglebius DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 140240233Sglebius DEVMETHOD(bus_child_pnpinfo_str, pci_child_pnpinfo_str_method), 141240233Sglebius DEVMETHOD(bus_child_location_str, pci_child_location_str_method), 142240233Sglebius 143240233Sglebius /* PCI interface */ 144240233Sglebius DEVMETHOD(pci_read_config, pci_read_config_method), 145240233Sglebius DEVMETHOD(pci_write_config, pci_write_config_method), 146240233Sglebius DEVMETHOD(pci_enable_busmaster, pci_enable_busmaster_method), 147240233Sglebius DEVMETHOD(pci_disable_busmaster, pci_disable_busmaster_method), 148240233Sglebius DEVMETHOD(pci_enable_io, pci_enable_io_method), 149240233Sglebius DEVMETHOD(pci_disable_io, pci_disable_io_method), 150240233Sglebius DEVMETHOD(pci_get_vpd_ident, pci_get_vpd_ident_method), 151240233Sglebius DEVMETHOD(pci_get_vpd_readonly, pci_get_vpd_readonly_method), 152240233Sglebius DEVMETHOD(pci_get_powerstate, pci_get_powerstate_method), 153240233Sglebius DEVMETHOD(pci_set_powerstate, pci_set_powerstate_method), 154223637Sbz DEVMETHOD(pci_assign_interrupt, pci_assign_interrupt_method), 155240233Sglebius DEVMETHOD(pci_find_extcap, pci_find_extcap_method), 156240233Sglebius DEVMETHOD(pci_alloc_msi, pci_alloc_msi_method), 157240233Sglebius DEVMETHOD(pci_alloc_msix, pci_alloc_msix_method), 158126258Smlaier DEVMETHOD(pci_remap_msix, pci_remap_msix_method), 159240233Sglebius DEVMETHOD(pci_release_msi, pci_release_msi_method), 160240233Sglebius DEVMETHOD(pci_msi_count, pci_msi_count_method), 161240233Sglebius DEVMETHOD(pci_msix_count, pci_msix_count_method), 162126258Smlaier 163240233Sglebius { 0, 0 } 164240811Sglebius}; 165240233Sglebius 166240811SglebiusDEFINE_CLASS_0(pci, pci_driver, pci_methods, 0); 167240811Sglebius 168240233Sglebiusstatic devclass_t pci_devclass; 169240233SglebiusDRIVER_MODULE(pci, pcib, pci_driver, pci_devclass, pci_modevent, 0); 170240233SglebiusMODULE_VERSION(pci, 1); 171240811Sglebius 172240233Sglebiusstatic char *pci_vendordata; 173223637Sbzstatic size_t pci_vendordata_size; 174240811Sglebius 175240811Sglebius 176240811Sglebiusstruct pci_quirk { 177240811Sglebius uint32_t devid; /* Vendor/device of the card */ 178240811Sglebius int type; 179126261Smlaier#define PCI_QUIRK_MAP_REG 1 /* PCI map register in weird place */ 180240811Sglebius#define PCI_QUIRK_DISABLE_MSI 2 /* MSI/MSI-X doesn't work */ 181240811Sglebius int arg1; 182240811Sglebius int arg2; 183126258Smlaier}; 184240233Sglebius 185240233Sglebiusstruct pci_quirk pci_quirks[] = { 186240233Sglebius /* The Intel 82371AB and 82443MX has a map register at offset 0x90. */ 187240233Sglebius { 0x71138086, PCI_QUIRK_MAP_REG, 0x90, 0 }, 188240233Sglebius { 0x719b8086, PCI_QUIRK_MAP_REG, 0x90, 0 }, 189265008Smm /* As does the Serverworks OSB4 (the SMBus mapping register) */ 190240233Sglebius { 0x02001166, PCI_QUIRK_MAP_REG, 0x90, 0 }, 191240233Sglebius 192240233Sglebius /* 193240233Sglebius * MSI doesn't work with the ServerWorks CNB20-HE Host Bridge 194240233Sglebius * or the CMIC-SL (AKA ServerWorks GC_LE). 195240233Sglebius */ 196240233Sglebius { 0x00141166, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 197240233Sglebius { 0x00171166, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 198283303Sjhb 199240233Sglebius /* 200240233Sglebius * MSI doesn't work on earlier Intel chipsets including 201240233Sglebius * E7500, E7501, E7505, 845, 865, 875/E7210, and 855. 202145836Smlaier */ 203240233Sglebius { 0x25408086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 204240233Sglebius { 0x254c8086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 205145836Smlaier { 0x25508086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 206289703Skp { 0x25608086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 207126258Smlaier { 0x25708086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 208126258Smlaier { 0x25788086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 209240233Sglebius { 0x35808086, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 210171168Smlaier 211240233Sglebius /* 212126258Smlaier * MSI doesn't work with devices behind the AMD 8131 HT-PCIX 213126258Smlaier * bridge. 214126258Smlaier */ 215240233Sglebius { 0x74501022, PCI_QUIRK_DISABLE_MSI, 0, 0 }, 216162238Scsjp 217126258Smlaier { 0 } 218126258Smlaier}; 219145836Smlaier 220240233Sglebius/* map register information */ 221223637Sbz#define PCI_MAPMEM 0x01 /* memory map */ 222126258Smlaier#define PCI_MAPMEMP 0x02 /* prefetchable memory map */ 223240233Sglebius#define PCI_MAPPORT 0x04 /* port map */ 224240233Sglebius 225240233Sglebiusstruct devlist pci_devq; 226240233Sglebiusuint32_t pci_generation; 227240233Sglebiusuint32_t pci_numdevs = 0; 228240233Sglebiusstatic int pcie_chipset, pcix_chipset; 229240233Sglebius 230130613Smlaier/* sysctl vars */ 231240233SglebiusSYSCTL_NODE(_hw, OID_AUTO, pci, CTLFLAG_RD, 0, "PCI bus tuning parameters"); 232240233Sglebius 233240233Sglebiusstatic int pci_enable_io_modes = 1; 234223637SbzTUNABLE_INT("hw.pci.enable_io_modes", &pci_enable_io_modes); 235223637SbzSYSCTL_INT(_hw_pci, OID_AUTO, enable_io_modes, CTLFLAG_RW, 236223637Sbz &pci_enable_io_modes, 1, 237223637Sbz "Enable I/O and memory bits in the config register. Some BIOSes do not\n\ 238223637Sbzenable these bits correctly. We'd like to do this all the time, but there\n\ 239223637Sbzare some peripherals that this causes problems with."); 240240233Sglebius 241130613Smlaierstatic int pci_do_power_nodriver = 0; 242126258SmlaierTUNABLE_INT("hw.pci.do_power_nodriver", &pci_do_power_nodriver); 243126258SmlaierSYSCTL_INT(_hw_pci, OID_AUTO, do_power_nodriver, CTLFLAG_RW, 244240233Sglebius &pci_do_power_nodriver, 0, 245200930Sdelphij "Place a function into D3 state when no driver attaches to it. 0 means\n\ 246200930Sdelphijdisable. 1 means conservatively place devices into D3 state. 2 means\n\ 247200930Sdelphijagressively place devices into D3 state. 3 means put absolutely everything\n\ 248240233Sglebiusin D3 state."); 249200930Sdelphij 250200930Sdelphijstatic int pci_do_power_resume = 1; 251240233SglebiusTUNABLE_INT("hw.pci.do_power_resume", &pci_do_power_resume); 252130613SmlaierSYSCTL_INT(_hw_pci, OID_AUTO, do_power_resume, CTLFLAG_RW, 253126258Smlaier &pci_do_power_resume, 1, 254240233Sglebius "Transition from D3 -> D0 on resume."); 255130613Smlaier 256126258Smlaierstatic int pci_do_msi = 1; 257240233SglebiusTUNABLE_INT("hw.pci.enable_msi", &pci_do_msi); 258130613SmlaierSYSCTL_INT(_hw_pci, OID_AUTO, enable_msi, CTLFLAG_RW, &pci_do_msi, 1, 259145836Smlaier "Enable support for MSI interrupts"); 260240233Sglebius 261223637Sbzstatic int pci_do_msix = 1; 262240233SglebiusTUNABLE_INT("hw.pci.enable_msix", &pci_do_msix); 263126258SmlaierSYSCTL_INT(_hw_pci, OID_AUTO, enable_msix, CTLFLAG_RW, &pci_do_msix, 1, 264240233Sglebius "Enable support for MSI-X interrupts"); 265126258Smlaier 266240233Sglebiusstatic int pci_honor_msi_blacklist = 1; 267231852SbzTUNABLE_INT("hw.pci.honor_msi_blacklist", &pci_honor_msi_blacklist); 268240233SglebiusSYSCTL_INT(_hw_pci, OID_AUTO, honor_msi_blacklist, CTLFLAG_RD, 269126258Smlaier &pci_honor_msi_blacklist, 1, "Honor chipset blacklist for MSI"); 270240233Sglebius 271223637Sbz/* Find a device_t by bus/slot/function in domain 0 */ 272240233Sglebius 273126258Smlaierdevice_t 274240233Sglebiuspci_find_bsf(uint8_t bus, uint8_t slot, uint8_t func) 275240233Sglebius{ 276240233Sglebius 277264454Smm return (pci_find_dbsf(0, bus, slot, func)); 278240233Sglebius} 279240233Sglebius 280241039Sglebius/* Find a device_t by domain/bus/slot/function */ 281240233Sglebius 282265008Smmdevice_t 283240233Sglebiuspci_find_dbsf(uint32_t domain, uint8_t bus, uint8_t slot, uint8_t func) 284240233Sglebius{ 285240233Sglebius struct pci_devinfo *dinfo; 286240233Sglebius 287240233Sglebius STAILQ_FOREACH(dinfo, &pci_devq, pci_links) { 288240233Sglebius if ((dinfo->cfg.domain == domain) && 289240233Sglebius (dinfo->cfg.bus == bus) && 290240233Sglebius (dinfo->cfg.slot == slot) && 291240233Sglebius (dinfo->cfg.func == func)) { 292240233Sglebius return (dinfo->cfg.dev); 293240233Sglebius } 294240233Sglebius } 295240233Sglebius 296126258Smlaier return (NULL); 297126261Smlaier} 298126258Smlaier 299223637Sbz/* Find a device_t by vendor/device ID */ 300171168Smlaier 301240233Sglebiusdevice_t 302145836Smlaierpci_find_device(uint16_t vendor, uint16_t device) 303240233Sglebius{ 304240233Sglebius struct pci_devinfo *dinfo; 305126258Smlaier 306240233Sglebius STAILQ_FOREACH(dinfo, &pci_devq, pci_links) { 307126258Smlaier if ((dinfo->cfg.vendor == vendor) && 308240233Sglebius (dinfo->cfg.device == device)) { 309261018Sglebius return (dinfo->cfg.dev); 310126258Smlaier } 311240233Sglebius } 312126258Smlaier 313240233Sglebius return (NULL); 314223637Sbz} 315223637Sbz 316223637Sbz/* return base address of memory or port map */ 317223637Sbz 318223637Sbzstatic pci_addr_t 319240233Sglebiuspci_mapbase(uint64_t mapreg) 320223637Sbz{ 321126258Smlaier 322126258Smlaier if (PCI_BAR_MEM(mapreg)) 323223637Sbz return (mapreg & PCIM_BAR_MEM_BASE); 324223637Sbz else 325126258Smlaier return (mapreg & PCIM_BAR_IO_BASE); 326263029Sglebius} 327263029Sglebius 328263029Sglebius/* return map type of memory or port map */ 329263029Sglebius 330263029Sglebiusstatic const char * 331263029Sglebiuspci_maptype(uint64_t mapreg) 332263029Sglebius{ 333263029Sglebius 334263029Sglebius if (PCI_BAR_IO(mapreg)) 335263029Sglebius return ("I/O Port"); 336263029Sglebius if (mapreg & PCIM_BAR_MEM_PREFETCH) 337263029Sglebius return ("Prefetchable Memory"); 338145836Smlaier return ("Memory"); 339145836Smlaier} 340263029Sglebius 341263029Sglebius/* return log2 of map size decoded for memory or port map */ 342263029Sglebius 343263029Sglebiusstatic int 344263029Sglebiuspci_mapsize(uint64_t testval) 345263029Sglebius{ 346263029Sglebius int ln2size; 347145836Smlaier 348145836Smlaier testval = pci_mapbase(testval); 349240233Sglebius ln2size = 0; 350240233Sglebius if (testval != 0) { 351240233Sglebius while ((testval & 1) == 0) 352240233Sglebius { 353223637Sbz ln2size++; 354240233Sglebius testval >>= 1; 355223637Sbz } 356273736Shselasky } 357273736Shselasky return (ln2size); 358273736Shselasky} 359273736Shselasky 360130613Smlaier/* return log2 of address range supported by map register */ 361273736Shselasky 362273736Shselaskystatic int 363273736Shselaskypci_maprange(uint64_t mapreg) 364273736Shselasky{ 365171168Smlaier int ln2range = 0; 366240233Sglebius 367130613Smlaier if (PCI_BAR_IO(mapreg)) 368240233Sglebius ln2range = 32; 369240233Sglebius else 370240233Sglebius switch (mapreg & PCIM_BAR_MEM_TYPE) { 371284569Skp case PCIM_BAR_MEM_32: 372284569Skp ln2range = 32; 373284569Skp break; 374284569Skp case PCIM_BAR_MEM_1MB: 375284569Skp ln2range = 20; 376284569Skp break; 377284569Skp case PCIM_BAR_MEM_64: 378284569Skp ln2range = 64; 379284569Skp break; 380284569Skp } 381284569Skp return (ln2range); 382284569Skp} 383284569Skp 384284569Skp/* adjust some values from PCI 1.0 devices to match 2.0 standards ... */ 385284569Skp 386284569Skpstatic void 387284569Skppci_fixancient(pcicfgregs *cfg) 388284569Skp{ 389284569Skp if (cfg->hdrtype != 0) 390284569Skp return; 391284569Skp 392284569Skp /* PCI to PCI bridges use header type 1 */ 393284569Skp if (cfg->baseclass == PCIC_BRIDGE && cfg->subclass == PCIS_BRIDGE_PCI) 394284569Skp cfg->hdrtype = 1; 395284569Skp} 396284569Skp 397284569Skp/* extract header type specific config data */ 398284569Skp 399284569Skpstatic void 400284569Skppci_hdrtypedata(device_t pcib, int b, int s, int f, pcicfgregs *cfg) 401284569Skp{ 402284569Skp#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) 403284569Skp switch (cfg->hdrtype) { 404284569Skp case 0: 405284569Skp cfg->subvendor = REG(PCIR_SUBVEND_0, 2); 406284569Skp cfg->subdevice = REG(PCIR_SUBDEV_0, 2); 407284569Skp cfg->nummaps = PCI_MAXMAPS_0; 408284569Skp break; 409284569Skp case 1: 410240233Sglebius cfg->nummaps = PCI_MAXMAPS_1; 411240233Sglebius break; 412126258Smlaier case 2: 413240233Sglebius cfg->subvendor = REG(PCIR_SUBVEND_2, 2); 414126258Smlaier cfg->subdevice = REG(PCIR_SUBDEV_2, 2); 415274486Sgnn cfg->nummaps = PCI_MAXMAPS_2; 416274486Sgnn break; 417274486Sgnn } 418240233Sglebius#undef REG 419273736Shselasky} 420130613Smlaier 421130613Smlaier/* read configuration header into pcicfgregs structure */ 422240736Sglebiusstruct pci_devinfo * 423240736Sglebiuspci_read_device(device_t pcib, int d, int b, int s, int f, size_t size) 424240736Sglebius{ 425240736Sglebius#define REG(n, w) PCIB_READ_CONFIG(pcib, b, s, f, n, w) 426240736Sglebius pcicfgregs *cfg = NULL; 427240736Sglebius struct pci_devinfo *devlist_entry; 428240736Sglebius struct devlist *devlist_head; 429274486Sgnn 430274486Sgnn devlist_head = &pci_devq; 431240736Sglebius 432240736Sglebius devlist_entry = NULL; 433274486Sgnn 434274486Sgnn if (REG(PCIR_DEVVENDOR, 4) != 0xfffffffful) { 435240736Sglebius devlist_entry = malloc(size, M_DEVBUF, M_WAITOK | M_ZERO); 436240736Sglebius if (devlist_entry == NULL) 437240736Sglebius return (NULL); 438240736Sglebius 439240736Sglebius cfg = &devlist_entry->cfg; 440273736Shselasky 441240736Sglebius cfg->domain = d; 442240736Sglebius cfg->bus = b; 443126258Smlaier cfg->slot = s; 444126258Smlaier cfg->func = f; 445126258Smlaier cfg->vendor = REG(PCIR_VENDOR, 2); 446126258Smlaier cfg->device = REG(PCIR_DEVICE, 2); 447126258Smlaier cfg->cmdreg = REG(PCIR_COMMAND, 2); 448126258Smlaier cfg->statreg = REG(PCIR_STATUS, 2); 449126258Smlaier cfg->baseclass = REG(PCIR_CLASS, 1); 450126258Smlaier cfg->subclass = REG(PCIR_SUBCLASS, 1); 451126258Smlaier cfg->progif = REG(PCIR_PROGIF, 1); 452126258Smlaier cfg->revid = REG(PCIR_REVID, 1); 453126258Smlaier cfg->hdrtype = REG(PCIR_HDRTYPE, 1); 454126258Smlaier cfg->cachelnsz = REG(PCIR_CACHELNSZ, 1); 455126258Smlaier cfg->lattimer = REG(PCIR_LATTIMER, 1); 456126258Smlaier cfg->intpin = REG(PCIR_INTPIN, 1); 457126258Smlaier cfg->intline = REG(PCIR_INTLINE, 1); 458126258Smlaier 459126258Smlaier cfg->mingnt = REG(PCIR_MINGNT, 1); 460126258Smlaier cfg->maxlat = REG(PCIR_MAXLAT, 1); 461145836Smlaier 462126258Smlaier cfg->mfdev = (cfg->hdrtype & PCIM_MFDEV) != 0; 463240233Sglebius cfg->hdrtype &= ~PCIM_MFDEV; 464145836Smlaier 465145836Smlaier pci_fixancient(cfg); 466145836Smlaier pci_hdrtypedata(pcib, b, s, f, cfg); 467145836Smlaier 468145836Smlaier if (REG(PCIR_STATUS, 2) & PCIM_STATUS_CAPPRESENT) 469145836Smlaier pci_read_extcap(pcib, cfg); 470240233Sglebius 471145836Smlaier STAILQ_INSERT_TAIL(devlist_head, devlist_entry, pci_links); 472145836Smlaier 473240233Sglebius devlist_entry->conf.pc_sel.pc_domain = cfg->domain; 474145836Smlaier devlist_entry->conf.pc_sel.pc_bus = cfg->bus; 475145836Smlaier devlist_entry->conf.pc_sel.pc_dev = cfg->slot; 476240233Sglebius devlist_entry->conf.pc_sel.pc_func = cfg->func; 477145836Smlaier devlist_entry->conf.pc_hdr = cfg->hdrtype; 478145836Smlaier 479145836Smlaier devlist_entry->conf.pc_subvendor = cfg->subvendor; 480145836Smlaier devlist_entry->conf.pc_subdevice = cfg->subdevice; 481145836Smlaier devlist_entry->conf.pc_vendor = cfg->vendor; 482145836Smlaier devlist_entry->conf.pc_device = cfg->device; 483145836Smlaier 484145836Smlaier devlist_entry->conf.pc_class = cfg->baseclass; 485145836Smlaier devlist_entry->conf.pc_subclass = cfg->subclass; 486145836Smlaier devlist_entry->conf.pc_progif = cfg->progif; 487240233Sglebius devlist_entry->conf.pc_revid = cfg->revid; 488145836Smlaier 489145836Smlaier pci_numdevs++; 490145836Smlaier pci_generation++; 491145836Smlaier } 492145836Smlaier return (devlist_entry); 493240233Sglebius#undef REG 494145836Smlaier} 495145836Smlaier 496240811Sglebiusstatic void 497145836Smlaierpci_read_extcap(device_t pcib, pcicfgregs *cfg) 498145836Smlaier{ 499240233Sglebius#define REG(n, w) PCIB_READ_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, w) 500240233Sglebius#define WREG(n, v, w) PCIB_WRITE_CONFIG(pcib, cfg->bus, cfg->slot, cfg->func, n, v, w) 501145836Smlaier#if defined(__i386__) || defined(__amd64__) 502171168Smlaier uint64_t addr; 503145836Smlaier#endif 504145836Smlaier uint32_t val; 505145836Smlaier int ptr, nextptr, ptrptr; 506145836Smlaier 507145836Smlaier switch (cfg->hdrtype & PCIM_HDRTYPE) { 508270574Sglebius case 0: 509145836Smlaier case 1: 510145836Smlaier ptrptr = PCIR_CAP_PTR; 511145836Smlaier break; 512145836Smlaier case 2: 513145836Smlaier ptrptr = PCIR_CAP_PTR_2; /* cardbus capabilities ptr */ 514270574Sglebius break; 515145836Smlaier default: 516145836Smlaier return; /* no extended capabilities support */ 517145836Smlaier } 518145836Smlaier nextptr = REG(ptrptr, 1); /* sanity check? */ 519145836Smlaier 520145836Smlaier /* 521240233Sglebius * Read capability entries. 522240233Sglebius */ 523240233Sglebius while (nextptr != 0) { 524145836Smlaier /* Sanity check */ 525240233Sglebius if (nextptr > 255) { 526240233Sglebius printf("illegal PCI extended capability offset %d\n", 527145836Smlaier nextptr); 528240811Sglebius return; 529240811Sglebius } 530240811Sglebius /* Find the next entry */ 531240233Sglebius ptr = nextptr; 532240233Sglebius nextptr = REG(ptr + PCICAP_NEXTPTR, 1); 533240811Sglebius 534240811Sglebius /* Process this entry */ 535240811Sglebius switch (REG(ptr + PCICAP_ID, 1)) { 536240811Sglebius case PCIY_PMG: /* PCI power management */ 537240811Sglebius if (cfg->pp.pp_cap == 0) { 538240811Sglebius cfg->pp.pp_cap = REG(ptr + PCIR_POWER_CAP, 2); 539240811Sglebius cfg->pp.pp_status = ptr + PCIR_POWER_STATUS; 540240811Sglebius cfg->pp.pp_pmcsr = ptr + PCIR_POWER_PMCSR; 541240233Sglebius if ((nextptr - ptr) > PCIR_POWER_DATA) 542240233Sglebius cfg->pp.pp_data = ptr + PCIR_POWER_DATA; 543240233Sglebius } 544240233Sglebius break; 545240233Sglebius#if defined(__i386__) || defined(__amd64__) 546264454Smm case PCIY_HT: /* HyperTransport */ 547240233Sglebius /* Determine HT-specific capability type. */ 548240811Sglebius val = REG(ptr + PCIR_HT_COMMAND, 2); 549240811Sglebius switch (val & PCIM_HTCMD_CAP_MASK) { 550240811Sglebius case PCIM_HTCAP_MSI_MAPPING: 551240233Sglebius if (!(val & PCIM_HTCMD_MSI_FIXED)) { 552240233Sglebius /* Sanity check the mapping window. */ 553264454Smm addr = REG(ptr + PCIR_HTMSI_ADDRESS_HI, 554264454Smm 4); 555240811Sglebius addr <<= 32; 556264454Smm addr |= REG(ptr + PCIR_HTMSI_ADDRESS_LO, 557264454Smm 4); 558240811Sglebius if (addr != MSI_INTEL_ADDR_BASE) 559240233Sglebius device_printf(pcib, 560240811Sglebius "HT Bridge at pci%d:%d:%d:%d has non-default MSI window 0x%llx\n", 561240811Sglebius cfg->domain, cfg->bus, 562270574Sglebius cfg->slot, cfg->func, 563240811Sglebius (long long)addr); 564240811Sglebius } else 565240811Sglebius addr = MSI_INTEL_ADDR_BASE; 566240811Sglebius 567240811Sglebius cfg->ht.ht_msimap = ptr; 568240233Sglebius cfg->ht.ht_msictrl = val; 569240811Sglebius cfg->ht.ht_msiaddr = addr; 570240811Sglebius break; 571240811Sglebius } 572240811Sglebius break; 573240811Sglebius#endif 574240811Sglebius case PCIY_MSI: /* PCI MSI */ 575240811Sglebius cfg->msi.msi_location = ptr; 576240811Sglebius cfg->msi.msi_ctrl = REG(ptr + PCIR_MSI_CTRL, 2); 577240811Sglebius cfg->msi.msi_msgnum = 1 << ((cfg->msi.msi_ctrl & 578240811Sglebius PCIM_MSICTRL_MMC_MASK)>>1); 579240811Sglebius break; 580240811Sglebius case PCIY_MSIX: /* PCI MSI-X */ 581240811Sglebius cfg->msix.msix_location = ptr; 582240811Sglebius cfg->msix.msix_ctrl = REG(ptr + PCIR_MSIX_CTRL, 2); 583240811Sglebius cfg->msix.msix_msgnum = (cfg->msix.msix_ctrl & 584240811Sglebius PCIM_MSIXCTRL_TABLE_SIZE) + 1; 585240811Sglebius val = REG(ptr + PCIR_MSIX_TABLE, 4); 586240811Sglebius cfg->msix.msix_table_bar = PCIR_BAR(val & 587240811Sglebius PCIM_MSIX_BIR_MASK); 588240811Sglebius cfg->msix.msix_table_offset = val & ~PCIM_MSIX_BIR_MASK; 589240811Sglebius val = REG(ptr + PCIR_MSIX_PBA, 4); 590240811Sglebius cfg->msix.msix_pba_bar = PCIR_BAR(val & 591240811Sglebius PCIM_MSIX_BIR_MASK); 592240811Sglebius cfg->msix.msix_pba_offset = val & ~PCIM_MSIX_BIR_MASK; 593240811Sglebius break; 594240811Sglebius case PCIY_VPD: /* PCI Vital Product Data */ 595240811Sglebius cfg->vpd.vpd_reg = ptr; 596240811Sglebius break; 597240811Sglebius case PCIY_SUBVENDOR: 598270574Sglebius /* Should always be true. */ 599270574Sglebius if ((cfg->hdrtype & PCIM_HDRTYPE) == 1) { 600240811Sglebius val = REG(ptr + PCIR_SUBVENDCAP_ID, 4); 601240811Sglebius cfg->subvendor = val & 0xffff; 602264454Smm cfg->subdevice = val >> 16; 603264454Smm } 604240811Sglebius break; 605264454Smm case PCIY_PCIX: /* PCI-X */ 606240811Sglebius /* 607273736Shselasky * Assume we have a PCI-X chipset if we have 608240233Sglebius * at least one PCI-PCI bridge with a PCI-X 609240233Sglebius * capability. Note that some systems with 610240233Sglebius * PCI-express or HT chipsets might match on 611240233Sglebius * this check as well. 612240233Sglebius */ 613240233Sglebius if ((cfg->hdrtype & PCIM_HDRTYPE) == 1) 614240233Sglebius pcix_chipset = 1; 615240811Sglebius break; 616240811Sglebius case PCIY_EXPRESS: /* PCI-express */ 617240811Sglebius /* 618240811Sglebius * Assume we have a PCI-express chipset if we have 619240811Sglebius * at least one PCI-express device. 620240811Sglebius */ 621240811Sglebius pcie_chipset = 1; 622240811Sglebius break; 623240233Sglebius default: 624240233Sglebius break; 625240233Sglebius } 626145836Smlaier } 627145836Smlaier/* REG and WREG use carry through to next functions */ 628240233Sglebius} 629145836Smlaier 630240811Sglebius/* 631240811Sglebius * PCI Vital Product Data 632240233Sglebius */ 633240233Sglebius 634264454Smm#define PCI_VPD_TIMEOUT 1000000 635264454Smm 636240233Sglebiusstatic int 637145836Smlaierpci_read_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t *data) 638240233Sglebius{ 639240233Sglebius int count = PCI_VPD_TIMEOUT; 640240233Sglebius 641240233Sglebius KASSERT((reg & 3) == 0, ("VPD register must by 4 byte aligned")); 642240233Sglebius 643240233Sglebius WREG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, reg, 2); 644240233Sglebius 645240233Sglebius while ((REG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, 2) & 0x8000) != 0x8000) { 646240233Sglebius if (--count < 0) 647240233Sglebius return (ENXIO); 648240233Sglebius DELAY(1); /* limit looping */ 649270574Sglebius } 650240233Sglebius *data = (REG(cfg->vpd.vpd_reg + PCIR_VPD_DATA, 4)); 651240233Sglebius 652240233Sglebius return (0); 653240233Sglebius} 654240233Sglebius 655240233Sglebius#if 0 656240233Sglebiusstatic int 657240233Sglebiuspci_write_vpd_reg(device_t pcib, pcicfgregs *cfg, int reg, uint32_t data) 658285940Sglebius{ 659285940Sglebius int count = PCI_VPD_TIMEOUT; 660240233Sglebius 661285940Sglebius KASSERT((reg & 3) == 0, ("VPD register must by 4 byte aligned")); 662285940Sglebius 663240233Sglebius WREG(cfg->vpd.vpd_reg + PCIR_VPD_DATA, data, 4); 664240233Sglebius WREG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, reg | 0x8000, 2); 665145836Smlaier while ((REG(cfg->vpd.vpd_reg + PCIR_VPD_ADDR, 2) & 0x8000) == 0x8000) { 666145836Smlaier if (--count < 0) 667240233Sglebius return (ENXIO); 668130613Smlaier DELAY(1); /* limit looping */ 669130613Smlaier } 670126258Smlaier 671126258Smlaier return (0); 672240233Sglebius} 673240233Sglebius#endif 674240233Sglebius 675240233Sglebius#undef PCI_VPD_TIMEOUT 676240233Sglebius 677240233Sglebiusstruct vpd_readstate { 678240233Sglebius device_t pcib; 679130613Smlaier pcicfgregs *cfg; 680240233Sglebius uint32_t val; 681240233Sglebius int bytesinval; 682240233Sglebius int off; 683240233Sglebius uint8_t cksum; 684130613Smlaier}; 685263029Sglebius 686240233Sglebiusstatic int 687145836Smlaiervpd_nextbyte(struct vpd_readstate *vrs, uint8_t *data) 688270574Sglebius{ 689270574Sglebius uint32_t reg; 690240233Sglebius uint8_t byte; 691240233Sglebius 692130613Smlaier if (vrs->bytesinval == 0) { 693240233Sglebius if (pci_read_vpd_reg(vrs->pcib, vrs->cfg, vrs->off, ®)) 694145836Smlaier return (ENXIO); 695145836Smlaier vrs->val = le32toh(reg); 696145836Smlaier vrs->off += 4; 697145836Smlaier byte = vrs->val & 0xff; 698145836Smlaier vrs->bytesinval = 3; 699130613Smlaier } else { 700240233Sglebius vrs->val = vrs->val >> 8; 701130613Smlaier byte = vrs->val & 0xff; 702240233Sglebius vrs->bytesinval--; 703240233Sglebius } 704130613Smlaier 705285940Sglebius vrs->cksum += byte; 706130613Smlaier *data = byte; 707263029Sglebius return (0); 708240233Sglebius} 709270574Sglebius 710130613Smlaierstatic void 711130613Smlaierpci_read_vpd(device_t pcib, pcicfgregs *cfg) 712145836Smlaier{ 713270574Sglebius struct vpd_readstate vrs; 714270574Sglebius int state; 715130613Smlaier int name; 716145836Smlaier int remain; 717130613Smlaier int i; 718130613Smlaier int alloc, off; /* alloc/off for RO/W arrays */ 719130613Smlaier int cksumvalid; 720126258Smlaier int dflen; 721261019Sglebius uint8_t byte; 722285940Sglebius uint8_t byte2; 723240233Sglebius 724223637Sbz /* init vpd reader */ 725285940Sglebius vrs.bytesinval = 0; 726240233Sglebius vrs.off = 0; 727261019Sglebius vrs.pcib = pcib; 728263029Sglebius vrs.cfg = cfg; 729261019Sglebius vrs.cksum = 0; 730240737Sglebius 731261019Sglebius state = 0; 732261019Sglebius name = remain = i = 0; /* shut up stupid gcc */ 733261019Sglebius alloc = off = 0; /* shut up stupid gcc */ 734261019Sglebius dflen = 0; /* shut up stupid gcc */ 735261019Sglebius cksumvalid = -1; 736261019Sglebius while (state >= 0) { 737261019Sglebius if (vpd_nextbyte(&vrs, &byte)) { 738285940Sglebius state = -2; 739261019Sglebius break; 740261019Sglebius } 741261019Sglebius#if 0 742285940Sglebius printf("vpd: val: %#x, off: %d, bytesinval: %d, byte: %#hhx, " \ 743285940Sglebius "state: %d, remain: %d, name: %#x, i: %d\n", vrs.val, 744261019Sglebius vrs.off, vrs.bytesinval, byte, state, remain, name, i); 745261019Sglebius#endif 746261019Sglebius switch (state) { 747240233Sglebius case 0: /* item name */ 748265008Smm if (byte & 0x80) { 749265008Smm if (vpd_nextbyte(&vrs, &byte2)) { 750265008Smm state = -2; 751265008Smm break; 752265008Smm } 753265008Smm remain = byte2; 754265008Smm if (vpd_nextbyte(&vrs, &byte2)) { 755265008Smm state = -2; 756265008Smm break; 757265008Smm } 758240233Sglebius remain |= byte2 << 8; 759223637Sbz if (remain > (0x7f*4 - vrs.off)) { 760240233Sglebius state = -1; 761240233Sglebius printf( 762240233Sglebius "pci%d:%d:%d:%d: invalid VPD data, remain %#x\n", 763240233Sglebius cfg->domain, cfg->bus, cfg->slot, 764223637Sbz cfg->func, remain); 765273736Shselasky } 766273736Shselasky name = byte & 0x7f; 767273736Shselasky } else { 768273736Shselasky remain = byte & 0x7; 769273736Shselasky name = (byte >> 3) & 0xf; 770273736Shselasky } 771240233Sglebius switch (name) { 772240233Sglebius case 0x2: /* String */ 773240233Sglebius cfg->vpd.vpd_ident = malloc(remain + 1, 774240233Sglebius M_DEVBUF, M_WAITOK); 775240233Sglebius i = 0; 776240233Sglebius state = 1; 777240233Sglebius break; 778240233Sglebius case 0xf: /* End */ 779244347Spjd state = -1; 780240233Sglebius break; 781240233Sglebius case 0x10: /* VPD-R */ 782240233Sglebius alloc = 8; 783240233Sglebius off = 0; 784273736Shselasky cfg->vpd.vpd_ros = malloc(alloc * 785240233Sglebius sizeof(*cfg->vpd.vpd_ros), M_DEVBUF, 786273736Shselasky M_WAITOK | M_ZERO); 787240233Sglebius state = 2; 788273736Shselasky break; 789273736Shselasky case 0x11: /* VPD-W */ 790240233Sglebius alloc = 8; 791251681Sglebius off = 0; 792240233Sglebius cfg->vpd.vpd_w = malloc(alloc * 793223637Sbz sizeof(*cfg->vpd.vpd_w), M_DEVBUF, 794223637Sbz M_WAITOK | M_ZERO); 795240233Sglebius state = 5; 796240233Sglebius break; 797240233Sglebius default: /* Invalid data, abort */ 798240233Sglebius state = -1; 799240233Sglebius break; 800240233Sglebius } 801244347Spjd break; 802273736Shselasky 803240233Sglebius case 1: /* Identifier String */ 804273736Shselasky cfg->vpd.vpd_ident[i++] = byte; 805273736Shselasky remain--; 806240233Sglebius if (remain == 0) { 807223637Sbz cfg->vpd.vpd_ident[i] = '\0'; 808240233Sglebius state = 0; 809240233Sglebius } 810240233Sglebius break; 811240233Sglebius 812240233Sglebius case 2: /* VPD-R Keyword Header */ 813240233Sglebius if (off == alloc) { 814240233Sglebius cfg->vpd.vpd_ros = reallocf(cfg->vpd.vpd_ros, 815240233Sglebius (alloc *= 2) * sizeof(*cfg->vpd.vpd_ros), 816240811Sglebius M_DEVBUF, M_WAITOK | M_ZERO); 817240233Sglebius } 818240811Sglebius cfg->vpd.vpd_ros[off].keyword[0] = byte; 819264454Smm if (vpd_nextbyte(&vrs, &byte2)) { 820240233Sglebius state = -2; 821240811Sglebius break; 822240811Sglebius } 823240233Sglebius cfg->vpd.vpd_ros[off].keyword[1] = byte2; 824240233Sglebius if (vpd_nextbyte(&vrs, &byte2)) { 825240233Sglebius state = -2; 826240233Sglebius break; 827223637Sbz } 828223637Sbz dflen = byte2; 829240233Sglebius if (dflen == 0 && 830265008Smm strncmp(cfg->vpd.vpd_ros[off].keyword, "RV", 831265008Smm 2) == 0) { 832265008Smm /* 833265008Smm * if this happens, we can't trust the rest 834265008Smm * of the VPD. 835265008Smm */ 836265008Smm printf( 837240233Sglebius "pci%d:%d:%d:%d: bad keyword length: %d\n", 838223637Sbz cfg->domain, cfg->bus, cfg->slot, 839240233Sglebius cfg->func, dflen); 840240233Sglebius cksumvalid = 0; 841240233Sglebius state = -1; 842240233Sglebius break; 843240233Sglebius } else if (dflen == 0) { 844223637Sbz cfg->vpd.vpd_ros[off].value = malloc(1 * 845273736Shselasky sizeof(*cfg->vpd.vpd_ros[off].value), 846240233Sglebius M_DEVBUF, M_WAITOK); 847240233Sglebius cfg->vpd.vpd_ros[off].value[0] = '\x00'; 848240233Sglebius } else 849240233Sglebius cfg->vpd.vpd_ros[off].value = malloc( 850240233Sglebius (dflen + 1) * 851240233Sglebius sizeof(*cfg->vpd.vpd_ros[off].value), 852240233Sglebius M_DEVBUF, M_WAITOK); 853240233Sglebius remain -= 3; 854240233Sglebius i = 0; 855240233Sglebius /* keep in sync w/ state 3's transistions */ 856240233Sglebius if (dflen == 0 && remain == 0) 857273736Shselasky state = 0; 858240233Sglebius else if (dflen == 0) 859240233Sglebius state = 2; 860240233Sglebius else 861240233Sglebius state = 3; 862240233Sglebius break; 863240233Sglebius 864240233Sglebius case 3: /* VPD-R Keyword Value */ 865240233Sglebius cfg->vpd.vpd_ros[off].value[i++] = byte; 866240233Sglebius if (strncmp(cfg->vpd.vpd_ros[off].keyword, 867240233Sglebius "RV", 2) == 0 && cksumvalid == -1) { 868240233Sglebius if (vrs.cksum == 0) 869240233Sglebius cksumvalid = 1; 870240811Sglebius else { 871240233Sglebius if (bootverbose) 872240233Sglebius printf( 873240233Sglebius "pci%d:%d:%d:%d: bad VPD cksum, remain %hhu\n", 874240233Sglebius cfg->domain, cfg->bus, 875240233Sglebius cfg->slot, cfg->func, 876240233Sglebius vrs.cksum); 877240233Sglebius cksumvalid = 0; 878240233Sglebius state = -1; 879265008Smm break; 880240233Sglebius } 881240233Sglebius } 882240233Sglebius dflen--; 883240233Sglebius remain--; 884240233Sglebius /* keep in sync w/ state 2's transistions */ 885240233Sglebius if (dflen == 0) 886240233Sglebius cfg->vpd.vpd_ros[off++].value[i++] = '\0'; 887240233Sglebius if (dflen == 0 && remain == 0) { 888240233Sglebius cfg->vpd.vpd_rocnt = off; 889223637Sbz cfg->vpd.vpd_ros = reallocf(cfg->vpd.vpd_ros, 890223637Sbz off * sizeof(*cfg->vpd.vpd_ros), 891223637Sbz M_DEVBUF, M_WAITOK | M_ZERO); 892240233Sglebius state = 0; 893240233Sglebius } else if (dflen == 0) 894130613Smlaier state = 2; 895223637Sbz break; 896265008Smm 897240233Sglebius case 4: 898223637Sbz remain--; 899240233Sglebius if (remain == 0) 900240233Sglebius state = 0; 901240233Sglebius break; 902240233Sglebius 903240233Sglebius case 5: /* VPD-W Keyword Header */ 904240233Sglebius if (off == alloc) { 905240233Sglebius cfg->vpd.vpd_w = reallocf(cfg->vpd.vpd_w, 906240233Sglebius (alloc *= 2) * sizeof(*cfg->vpd.vpd_w), 907265008Smm M_DEVBUF, M_WAITOK | M_ZERO); 908240233Sglebius } 909240233Sglebius cfg->vpd.vpd_w[off].keyword[0] = byte; 910240233Sglebius if (vpd_nextbyte(&vrs, &byte2)) { 911240233Sglebius state = -2; 912240233Sglebius break; 913240233Sglebius } 914240233Sglebius cfg->vpd.vpd_w[off].keyword[1] = byte2; 915240233Sglebius if (vpd_nextbyte(&vrs, &byte2)) { 916240233Sglebius state = -2; 917240233Sglebius break; 918240233Sglebius } 919240233Sglebius cfg->vpd.vpd_w[off].len = dflen = byte2; 920251681Sglebius cfg->vpd.vpd_w[off].start = vrs.off - vrs.bytesinval; 921240233Sglebius cfg->vpd.vpd_w[off].value = malloc((dflen + 1) * 922240233Sglebius sizeof(*cfg->vpd.vpd_w[off].value), 923240233Sglebius M_DEVBUF, M_WAITOK); 924240233Sglebius remain -= 3; 925240233Sglebius i = 0; 926240233Sglebius /* keep in sync w/ state 6's transistions */ 927240233Sglebius if (dflen == 0 && remain == 0) 928240233Sglebius state = 0; 929240233Sglebius else if (dflen == 0) 930251681Sglebius state = 5; 931251681Sglebius else 932251681Sglebius state = 6; 933251681Sglebius break; 934251681Sglebius 935251681Sglebius case 6: /* VPD-W Keyword Value */ 936251681Sglebius cfg->vpd.vpd_w[off].value[i++] = byte; 937251681Sglebius dflen--; 938251681Sglebius remain--; 939251681Sglebius /* keep in sync w/ state 5's transistions */ 940251681Sglebius if (dflen == 0) 941251681Sglebius cfg->vpd.vpd_w[off++].value[i++] = '\0'; 942251681Sglebius if (dflen == 0 && remain == 0) { 943251681Sglebius cfg->vpd.vpd_wcnt = off; 944251681Sglebius cfg->vpd.vpd_w = reallocf(cfg->vpd.vpd_w, 945251681Sglebius off * sizeof(*cfg->vpd.vpd_w), 946251681Sglebius M_DEVBUF, M_WAITOK | M_ZERO); 947251681Sglebius state = 0; 948251681Sglebius } else if (dflen == 0) 949251681Sglebius state = 5; 950251681Sglebius break; 951251681Sglebius 952251681Sglebius default: 953251681Sglebius printf("pci%d:%d:%d:%d: invalid state: %d\n", 954251681Sglebius cfg->domain, cfg->bus, cfg->slot, cfg->func, 955251681Sglebius state); 956251681Sglebius state = -1; 957251681Sglebius break; 958251681Sglebius } 959251681Sglebius } 960251681Sglebius 961251681Sglebius if (cksumvalid == 0 || state < -1) { 962251681Sglebius /* read-only data bad, clean up */ 963251681Sglebius if (cfg->vpd.vpd_ros != NULL) { 964240233Sglebius for (off = 0; cfg->vpd.vpd_ros[off].value; off++) 965240233Sglebius free(cfg->vpd.vpd_ros[off].value, M_DEVBUF); 966240233Sglebius free(cfg->vpd.vpd_ros, M_DEVBUF); 967251681Sglebius cfg->vpd.vpd_ros = NULL; 968240233Sglebius } 969240233Sglebius } 970240233Sglebius if (state < -1) { 971240233Sglebius /* I/O error, clean up */ 972240233Sglebius printf("pci%d:%d:%d:%d: failed to read VPD data.\n", 973240233Sglebius cfg->domain, cfg->bus, cfg->slot, cfg->func); 974240233Sglebius if (cfg->vpd.vpd_ident != NULL) { 975240233Sglebius free(cfg->vpd.vpd_ident, M_DEVBUF); 976240233Sglebius cfg->vpd.vpd_ident = NULL; 977240233Sglebius } 978240233Sglebius if (cfg->vpd.vpd_w != NULL) { 979240233Sglebius for (off = 0; cfg->vpd.vpd_w[off].value; off++) 980240233Sglebius free(cfg->vpd.vpd_w[off].value, M_DEVBUF); 981240233Sglebius free(cfg->vpd.vpd_w, M_DEVBUF); 982240233Sglebius cfg->vpd.vpd_w = NULL; 983223637Sbz } 984240233Sglebius } 985240233Sglebius cfg->vpd.vpd_cached = 1; 986251681Sglebius#undef REG 987251681Sglebius#undef WREG 988251681Sglebius} 989251681Sglebius 990251681Sglebiusint 991251681Sglebiuspci_get_vpd_ident_method(device_t dev, device_t child, const char **identptr) 992251681Sglebius{ 993251681Sglebius struct pci_devinfo *dinfo = device_get_ivars(child); 994251681Sglebius pcicfgregs *cfg = &dinfo->cfg; 995251681Sglebius 996251681Sglebius if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0) 997240233Sglebius pci_read_vpd(device_get_parent(dev), cfg); 998223637Sbz 999251681Sglebius *identptr = cfg->vpd.vpd_ident; 1000240233Sglebius 1001223637Sbz if (*identptr == NULL) 1002223637Sbz return (ENXIO); 1003223637Sbz 1004223637Sbz return (0); 1005223637Sbz} 1006223637Sbz 1007223637Sbzint 1008223637Sbzpci_get_vpd_readonly_method(device_t dev, device_t child, const char *kw, 1009223637Sbz const char **vptr) 1010223637Sbz{ 1011223637Sbz struct pci_devinfo *dinfo = device_get_ivars(child); 1012223637Sbz pcicfgregs *cfg = &dinfo->cfg; 1013223637Sbz int i; 1014240233Sglebius 1015223637Sbz if (!cfg->vpd.vpd_cached && cfg->vpd.vpd_reg != 0) 1016223637Sbz pci_read_vpd(device_get_parent(dev), cfg); 1017223637Sbz 1018223637Sbz for (i = 0; i < cfg->vpd.vpd_rocnt; i++) 1019223637Sbz if (memcmp(kw, cfg->vpd.vpd_ros[i].keyword, 1020223637Sbz sizeof(cfg->vpd.vpd_ros[i].keyword)) == 0) { 1021240233Sglebius *vptr = cfg->vpd.vpd_ros[i].value; 1022251681Sglebius } 1023240233Sglebius 1024240233Sglebius if (i != cfg->vpd.vpd_rocnt) 1025240233Sglebius return (0); 1026250522Sglebius 1027223637Sbz *vptr = NULL; 1028223637Sbz return (ENXIO); 1029240233Sglebius} 1030240233Sglebius 1031240233Sglebius/* 1032223637Sbz * Find the requested extended capability and return the offset in 1033240233Sglebius * configuration space via the pointer provided. The function returns 1034240233Sglebius * 0 on success and error code otherwise. 1035223637Sbz */ 1036126258Smlaierint 1037126258Smlaierpci_find_extcap_method(device_t dev, device_t child, int capability, 1038240233Sglebius int *capreg) 1039240233Sglebius{ 1040223637Sbz struct pci_devinfo *dinfo = device_get_ivars(child); 1041240233Sglebius pcicfgregs *cfg = &dinfo->cfg; 1042223637Sbz u_int32_t status; 1043240233Sglebius u_int8_t ptr; 1044223637Sbz 1045251681Sglebius /* 1046251681Sglebius * Check the CAP_LIST bit of the PCI status register first. 1047251681Sglebius */ 1048251681Sglebius status = pci_read_config(child, PCIR_STATUS, 2); 1049251681Sglebius if (!(status & PCIM_STATUS_CAPPRESENT)) 1050251681Sglebius return (ENXIO); 1051251681Sglebius 1052240233Sglebius /* 1053240233Sglebius * Determine the start pointer of the capabilities list. 1054240233Sglebius */ 1055240233Sglebius switch (cfg->hdrtype & PCIM_HDRTYPE) { 1056240233Sglebius case 0: 1057240233Sglebius case 1: 1058240233Sglebius ptr = PCIR_CAP_PTR; 1059240233Sglebius break; 1060240233Sglebius case 2: 1061240233Sglebius ptr = PCIR_CAP_PTR_2; 1062240233Sglebius break; 1063240233Sglebius default: 1064240233Sglebius /* XXX: panic? */ 1065240233Sglebius return (ENXIO); /* no extended capabilities support */ 1066251681Sglebius } 1067240233Sglebius ptr = pci_read_config(child, ptr, 1); 1068240233Sglebius 1069240233Sglebius /* 1070240233Sglebius * Traverse the capabilities list. 1071240233Sglebius */ 1072251681Sglebius while (ptr != 0) { 1073251681Sglebius if (pci_read_config(child, ptr + PCICAP_ID, 1) == capability) { 1074251681Sglebius if (capreg != NULL) 1075240233Sglebius *capreg = ptr; 1076240233Sglebius return (0); 1077240233Sglebius } 1078223637Sbz ptr = pci_read_config(child, ptr + PCICAP_NEXTPTR, 1); 1079251681Sglebius } 1080223637Sbz 1081223637Sbz return (ENOENT); 1082240233Sglebius} 1083223637Sbz 1084223637Sbz/* 1085240233Sglebius * Support for MSI-X message interrupts. 1086240233Sglebius */ 1087223637Sbzvoid 1088240233Sglebiuspci_enable_msix(device_t dev, u_int index, uint64_t address, uint32_t data) 1089240233Sglebius{ 1090240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(dev); 1091240233Sglebius struct pcicfg_msix *msix = &dinfo->cfg.msix; 1092240233Sglebius uint32_t offset; 1093240233Sglebius 1094240233Sglebius KASSERT(msix->msix_table_len > index, ("bogus index")); 1095240233Sglebius offset = msix->msix_table_offset + index * 16; 1096240233Sglebius bus_write_4(msix->msix_table_res, offset, address & 0xffffffff); 1097240233Sglebius bus_write_4(msix->msix_table_res, offset + 4, address >> 32); 1098240233Sglebius bus_write_4(msix->msix_table_res, offset + 8, data); 1099240233Sglebius 1100240233Sglebius /* Enable MSI -> HT mapping. */ 1101240233Sglebius pci_ht_map_msi(dev, address); 1102240233Sglebius} 1103223637Sbz 1104240233Sglebiusvoid 1105240233Sglebiuspci_mask_msix(device_t dev, u_int index) 1106240233Sglebius{ 1107240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(dev); 1108240233Sglebius struct pcicfg_msix *msix = &dinfo->cfg.msix; 1109240233Sglebius uint32_t offset, val; 1110240233Sglebius 1111223637Sbz KASSERT(msix->msix_msgnum > index, ("bogus index")); 1112223637Sbz offset = msix->msix_table_offset + index * 16 + 12; 1113240233Sglebius val = bus_read_4(msix->msix_table_res, offset); 1114223637Sbz if (!(val & PCIM_MSIX_VCTRL_MASK)) { 1115223637Sbz val |= PCIM_MSIX_VCTRL_MASK; 1116240233Sglebius bus_write_4(msix->msix_table_res, offset, val); 1117240233Sglebius } 1118240233Sglebius} 1119223637Sbz 1120240233Sglebiusvoid 1121223637Sbzpci_unmask_msix(device_t dev, u_int index) 1122240233Sglebius{ 1123240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(dev); 1124223637Sbz struct pcicfg_msix *msix = &dinfo->cfg.msix; 1125240233Sglebius uint32_t offset, val; 1126240233Sglebius 1127240233Sglebius KASSERT(msix->msix_table_len > index, ("bogus index")); 1128223637Sbz offset = msix->msix_table_offset + index * 16 + 12; 1129223637Sbz val = bus_read_4(msix->msix_table_res, offset); 1130223637Sbz if (val & PCIM_MSIX_VCTRL_MASK) { 1131240233Sglebius val &= ~PCIM_MSIX_VCTRL_MASK; 1132240233Sglebius bus_write_4(msix->msix_table_res, offset, val); 1133240233Sglebius } 1134240233Sglebius} 1135240233Sglebius 1136240233Sglebiusint 1137240233Sglebiuspci_pending_msix(device_t dev, u_int index) 1138240233Sglebius{ 1139240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(dev); 1140240233Sglebius struct pcicfg_msix *msix = &dinfo->cfg.msix; 1141240233Sglebius uint32_t offset, bit; 1142240233Sglebius 1143223637Sbz KASSERT(msix->msix_table_len > index, ("bogus index")); 1144240233Sglebius offset = msix->msix_pba_offset + (index / 32) * 4; 1145240233Sglebius bit = 1 << index % 32; 1146223637Sbz return (bus_read_4(msix->msix_pba_res, offset) & bit); 1147240233Sglebius} 1148223637Sbz 1149240233Sglebius/* 1150240233Sglebius * Restore MSI-X registers and table during resume. If MSI-X is 1151223637Sbz * enabled then walk the virtual table to restore the actual MSI-X 1152223637Sbz * table. 1153240233Sglebius */ 1154240233Sglebiusstatic void 1155240233Sglebiuspci_resume_msix(device_t dev) 1156240233Sglebius{ 1157240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(dev); 1158240233Sglebius struct pcicfg_msix *msix = &dinfo->cfg.msix; 1159240233Sglebius struct msix_table_entry *mte; 1160223637Sbz struct msix_vector *mv; 1161223637Sbz int i; 1162223637Sbz 1163240233Sglebius if (msix->msix_alloc > 0) { 1164240233Sglebius /* First, mask all vectors. */ 1165223637Sbz for (i = 0; i < msix->msix_msgnum; i++) 1166240233Sglebius pci_mask_msix(dev, i); 1167223637Sbz 1168240233Sglebius /* Second, program any messages with at least one handler. */ 1169240233Sglebius for (i = 0; i < msix->msix_table_len; i++) { 1170240233Sglebius mte = &msix->msix_table[i]; 1171223637Sbz if (mte->mte_vector == 0 || mte->mte_handlers == 0) 1172240233Sglebius continue; 1173223637Sbz mv = &msix->msix_vectors[mte->mte_vector - 1]; 1174240233Sglebius pci_enable_msix(dev, i, mv->mv_address, mv->mv_data); 1175223637Sbz pci_unmask_msix(dev, i); 1176223637Sbz } 1177223637Sbz } 1178223637Sbz pci_write_config(dev, msix->msix_location + PCIR_MSIX_CTRL, 1179223637Sbz msix->msix_ctrl, 2); 1180223637Sbz} 1181240233Sglebius 1182240233Sglebius/* 1183250522Sglebius * Attempt to allocate *count MSI-X messages. The actual number allocated is 1184223637Sbz * returned in *count. After this function returns, each message will be 1185240233Sglebius * available to the driver as SYS_RES_IRQ resources starting at rid 1. 1186240233Sglebius */ 1187240233Sglebiusint 1188240233Sglebiuspci_alloc_msix_method(device_t dev, device_t child, int *count) 1189240233Sglebius{ 1190240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(child); 1191223637Sbz pcicfgregs *cfg = &dinfo->cfg; 1192223637Sbz struct resource_list_entry *rle; 1193223637Sbz int actual, error, i, irq, max; 1194240233Sglebius 1195240233Sglebius /* Don't let count == 0 get us into trouble. */ 1196240233Sglebius if (*count == 0) 1197240233Sglebius return (EINVAL); 1198240233Sglebius 1199223637Sbz /* If rid 0 is allocated, then fail. */ 1200130613Smlaier rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0); 1201240233Sglebius if (rle != NULL && rle->res != NULL) 1202251681Sglebius return (ENXIO); 1203250522Sglebius 1204250522Sglebius /* Already have allocated messages? */ 1205244184Sglebius if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0) 1206240233Sglebius return (ENXIO); 1207251681Sglebius 1208240233Sglebius /* If MSI is blacklisted for this system, fail. */ 1209240233Sglebius if (pci_msi_blacklisted()) 1210240233Sglebius return (ENXIO); 1211240233Sglebius 1212240233Sglebius /* MSI-X capability present? */ 1213240233Sglebius if (cfg->msix.msix_location == 0 || !pci_do_msix) 1214223637Sbz return (ENODEV); 1215250521Sglebius 1216250312Sglebius /* Make sure the appropriate BARs are mapped. */ 1217240233Sglebius rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, 1218240233Sglebius cfg->msix.msix_table_bar); 1219130613Smlaier if (rle == NULL || rle->res == NULL || 1220223637Sbz !(rman_get_flags(rle->res) & RF_ACTIVE)) 1221250522Sglebius return (ENXIO); 1222130613Smlaier cfg->msix.msix_table_res = rle->res; 1223240233Sglebius if (cfg->msix.msix_pba_bar != cfg->msix.msix_table_bar) { 1224240233Sglebius rle = resource_list_find(&dinfo->resources, SYS_RES_MEMORY, 1225240233Sglebius cfg->msix.msix_pba_bar); 1226240233Sglebius if (rle == NULL || rle->res == NULL || 1227270574Sglebius !(rman_get_flags(rle->res) & RF_ACTIVE)) 1228223637Sbz return (ENXIO); 1229223637Sbz } 1230240233Sglebius cfg->msix.msix_pba_res = rle->res; 1231240233Sglebius 1232126258Smlaier if (bootverbose) 1233126258Smlaier device_printf(child, 1234126258Smlaier "attempting to allocate %d MSI-X vectors (%d supported)\n", 1235240233Sglebius *count, cfg->msix.msix_msgnum); 1236240233Sglebius max = min(*count, cfg->msix.msix_msgnum); 1237240233Sglebius for (i = 0; i < max; i++) { 1238223637Sbz /* Allocate a message. */ 1239240233Sglebius error = PCIB_ALLOC_MSIX(device_get_parent(dev), child, &irq); 1240223637Sbz if (error) 1241240233Sglebius break; 1242240233Sglebius resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq, 1243240233Sglebius irq, 1); 1244270574Sglebius } 1245223637Sbz actual = i; 1246273736Shselasky 1247223637Sbz if (bootverbose) { 1248240233Sglebius rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 1); 1249240233Sglebius if (actual == 1) 1250240233Sglebius device_printf(child, "using IRQ %lu for MSI-X\n", 1251240233Sglebius rle->start); 1252223637Sbz else { 1253240233Sglebius int run; 1254240233Sglebius 1255240233Sglebius /* 1256240233Sglebius * Be fancy and try to print contiguous runs of 1257223637Sbz * IRQ values as ranges. 'irq' is the previous IRQ. 1258223637Sbz * 'run' is true if we are in a range. 1259240233Sglebius */ 1260240233Sglebius device_printf(child, "using IRQs %lu", rle->start); 1261240233Sglebius irq = rle->start; 1262240233Sglebius run = 0; 1263240233Sglebius for (i = 1; i < actual; i++) { 1264240233Sglebius rle = resource_list_find(&dinfo->resources, 1265223637Sbz SYS_RES_IRQ, i + 1); 1266240233Sglebius 1267223637Sbz /* Still in a run? */ 1268240233Sglebius if (rle->start == irq + 1) { 1269240233Sglebius run = 1; 1270223637Sbz irq++; 1271270574Sglebius continue; 1272223637Sbz } 1273240233Sglebius 1274240233Sglebius /* Finish previous range. */ 1275240233Sglebius if (run) { 1276240233Sglebius printf("-%d", irq); 1277240233Sglebius run = 0; 1278240233Sglebius } 1279240233Sglebius 1280240233Sglebius /* Start new range. */ 1281240233Sglebius printf(",%lu", rle->start); 1282223637Sbz irq = rle->start; 1283223637Sbz } 1284240233Sglebius 1285223637Sbz /* Unfinished range? */ 1286240233Sglebius if (run) 1287240233Sglebius printf("-%d", irq); 1288240233Sglebius printf(" for MSI-X\n"); 1289240233Sglebius } 1290240233Sglebius } 1291261018Sglebius 1292240233Sglebius /* Mask all vectors. */ 1293261018Sglebius for (i = 0; i < cfg->msix.msix_msgnum; i++) 1294261018Sglebius pci_mask_msix(child, i); 1295261018Sglebius 1296240233Sglebius /* Allocate and initialize vector data and virtual table. */ 1297240233Sglebius cfg->msix.msix_vectors = malloc(sizeof(struct msix_vector) * actual, 1298240233Sglebius M_DEVBUF, M_WAITOK | M_ZERO); 1299240233Sglebius cfg->msix.msix_table = malloc(sizeof(struct msix_table_entry) * actual, 1300240233Sglebius M_DEVBUF, M_WAITOK | M_ZERO); 1301240233Sglebius for (i = 0; i < actual; i++) { 1302240233Sglebius rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1); 1303223637Sbz cfg->msix.msix_vectors[i].mv_irq = rle->start; 1304223637Sbz cfg->msix.msix_table[i].mte_vector = i + 1; 1305223637Sbz } 1306223637Sbz 1307223637Sbz /* Update control register to enable MSI-X. */ 1308223637Sbz cfg->msix.msix_ctrl |= PCIM_MSIXCTRL_MSIX_ENABLE; 1309223637Sbz pci_write_config(child, cfg->msix.msix_location + PCIR_MSIX_CTRL, 1310240233Sglebius cfg->msix.msix_ctrl, 2); 1311223637Sbz 1312240233Sglebius /* Update counts of alloc'd messages. */ 1313240233Sglebius cfg->msix.msix_alloc = actual; 1314223637Sbz cfg->msix.msix_table_len = actual; 1315270574Sglebius *count = actual; 1316223637Sbz return (0); 1317240233Sglebius} 1318223637Sbz 1319240233Sglebius/* 1320240233Sglebius * By default, pci_alloc_msix() will assign the allocated IRQ 1321240233Sglebius * resources consecutively to the first N messages in the MSI-X table. 1322240233Sglebius * However, device drivers may want to use different layouts if they 1323240233Sglebius * either receive fewer messages than they asked for, or they wish to 1324240233Sglebius * populate the MSI-X table sparsely. This method allows the driver 1325240233Sglebius * to specify what layout it wants. It must be called after a 1326223637Sbz * successful pci_alloc_msix() but before any of the associated 1327240233Sglebius * SYS_RES_IRQ resources are allocated via bus_alloc_resource(). 1328240233Sglebius * 1329240233Sglebius * The 'vectors' array contains 'count' message vectors. The array 1330240233Sglebius * maps directly to the MSI-X table in that index 0 in the array 1331240233Sglebius * specifies the vector for the first message in the MSI-X table, etc. 1332240233Sglebius * The vector value in each array index can either be 0 to indicate 1333240233Sglebius * that no vector should be assigned to a message slot, or it can be a 1334240233Sglebius * number from 1 to N (where N is the count returned from a 1335240233Sglebius * succcessful call to pci_alloc_msix()) to indicate which message 1336240233Sglebius * vector (IRQ) to be used for the corresponding message. 1337240233Sglebius * 1338240233Sglebius * On successful return, each message with a non-zero vector will have 1339240233Sglebius * an associated SYS_RES_IRQ whose rid is equal to the array index + 1340240233Sglebius * 1. Additionally, if any of the IRQs allocated via the previous 1341240233Sglebius * call to pci_alloc_msix() are not used in the mapping, those IRQs 1342240233Sglebius * will be freed back to the system automatically. 1343240233Sglebius * 1344240233Sglebius * For example, suppose a driver has a MSI-X table with 6 messages and 1345240233Sglebius * asks for 6 messages, but pci_alloc_msix() only returns a count of 1346240233Sglebius * 3. Call the three vectors allocated by pci_alloc_msix() A, B, and 1347240233Sglebius * C. After the call to pci_alloc_msix(), the device will be setup to 1348240233Sglebius * have an MSI-X table of ABC--- (where - means no vector assigned). 1349240233Sglebius * If the driver ten passes a vector array of { 1, 0, 1, 2, 0, 2 }, 1350240233Sglebius * then the MSI-X table will look like A-AB-B, and the 'C' vector will 1351240233Sglebius * be freed back to the system. This device will also have valid 1352240233Sglebius * SYS_RES_IRQ rids of 1, 3, 4, and 6. 1353240233Sglebius * 1354240233Sglebius * In any case, the SYS_RES_IRQ rid X will always map to the message 1355240233Sglebius * at MSI-X table index X - 1 and will only be valid if a vector is 1356240233Sglebius * assigned to that table entry. 1357240233Sglebius */ 1358240233Sglebiusint 1359240233Sglebiuspci_remap_msix_method(device_t dev, device_t child, int count, 1360240233Sglebius const u_int *vectors) 1361223637Sbz{ 1362223637Sbz struct pci_devinfo *dinfo = device_get_ivars(child); 1363223637Sbz struct pcicfg_msix *msix = &dinfo->cfg.msix; 1364223637Sbz struct resource_list_entry *rle; 1365240233Sglebius int i, irq, j, *used; 1366240233Sglebius 1367240233Sglebius /* 1368223637Sbz * Have to have at least one message in the table but the 1369240233Sglebius * table can't be bigger than the actual MSI-X table in the 1370240233Sglebius * device. 1371240233Sglebius */ 1372240233Sglebius if (count == 0 || count > msix->msix_msgnum) 1373240233Sglebius return (EINVAL); 1374240233Sglebius 1375126258Smlaier /* Sanity check the vectors. */ 1376240233Sglebius for (i = 0; i < count; i++) 1377240233Sglebius if (vectors[i] > msix->msix_alloc) 1378240233Sglebius return (EINVAL); 1379240233Sglebius 1380240233Sglebius /* 1381240233Sglebius * Make sure there aren't any holes in the vectors to be used. 1382240233Sglebius * It's a big pain to support it, and it doesn't really make 1383240233Sglebius * sense anyway. Also, at least one vector must be used. 1384240233Sglebius */ 1385240233Sglebius used = malloc(sizeof(int) * msix->msix_alloc, M_DEVBUF, M_WAITOK | 1386240233Sglebius M_ZERO); 1387240233Sglebius for (i = 0; i < count; i++) 1388240233Sglebius if (vectors[i] != 0) 1389240233Sglebius used[vectors[i] - 1] = 1; 1390240233Sglebius for (i = 0; i < msix->msix_alloc - 1; i++) 1391240233Sglebius if (used[i] == 0 && used[i + 1] == 1) { 1392240233Sglebius free(used, M_DEVBUF); 1393240233Sglebius return (EINVAL); 1394240233Sglebius } 1395240233Sglebius if (used[0] != 1) { 1396240233Sglebius free(used, M_DEVBUF); 1397240233Sglebius return (EINVAL); 1398240233Sglebius } 1399240233Sglebius 1400240233Sglebius /* Make sure none of the resources are allocated. */ 1401240233Sglebius for (i = 0; i < msix->msix_table_len; i++) { 1402240233Sglebius if (msix->msix_table[i].mte_vector == 0) 1403240233Sglebius continue; 1404240233Sglebius if (msix->msix_table[i].mte_handlers > 0) 1405240233Sglebius return (EBUSY); 1406240233Sglebius rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1); 1407240233Sglebius KASSERT(rle != NULL, ("missing resource")); 1408240233Sglebius if (rle->res != NULL) 1409240233Sglebius return (EBUSY); 1410240233Sglebius } 1411240233Sglebius 1412240233Sglebius /* Free the existing resource list entries. */ 1413240233Sglebius for (i = 0; i < msix->msix_table_len; i++) { 1414240233Sglebius if (msix->msix_table[i].mte_vector == 0) 1415240233Sglebius continue; 1416240233Sglebius resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1); 1417240233Sglebius } 1418171168Smlaier 1419126258Smlaier /* 1420241039Sglebius * Build the new virtual table keeping track of which vectors are 1421171168Smlaier * used. 1422223637Sbz */ 1423223637Sbz free(msix->msix_table, M_DEVBUF); 1424171168Smlaier msix->msix_table = malloc(sizeof(struct msix_table_entry) * count, 1425240233Sglebius M_DEVBUF, M_WAITOK | M_ZERO); 1426240233Sglebius for (i = 0; i < count; i++) 1427171168Smlaier msix->msix_table[i].mte_vector = vectors[i]; 1428226527Sbz msix->msix_table_len = count; 1429240233Sglebius 1430240233Sglebius /* Free any unused IRQs and resize the vectors array if necessary. */ 1431240233Sglebius j = msix->msix_alloc - 1; 1432240233Sglebius if (used[j] == 0) { 1433240233Sglebius struct msix_vector *vec; 1434240233Sglebius 1435240233Sglebius while (used[j] == 0) { 1436240233Sglebius PCIB_RELEASE_MSIX(device_get_parent(dev), child, 1437240233Sglebius msix->msix_vectors[j].mv_irq); 1438171168Smlaier j--; 1439240233Sglebius } 1440240233Sglebius vec = malloc(sizeof(struct msix_vector) * (j + 1), M_DEVBUF, 1441240233Sglebius M_WAITOK); 1442273736Shselasky bcopy(msix->msix_vectors, vec, sizeof(struct msix_vector) * 1443226527Sbz (j + 1)); 1444240233Sglebius free(msix->msix_vectors, M_DEVBUF); 1445240233Sglebius msix->msix_vectors = vec; 1446240233Sglebius msix->msix_alloc = j + 1; 1447240233Sglebius } 1448240233Sglebius free(used, M_DEVBUF); 1449240233Sglebius 1450240233Sglebius /* Map the IRQs onto the rids. */ 1451240233Sglebius for (i = 0; i < count; i++) { 1452240233Sglebius if (vectors[i] == 0) 1453240233Sglebius continue; 1454240233Sglebius irq = msix->msix_vectors[vectors[i]].mv_irq; 1455240233Sglebius resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, irq, 1456240233Sglebius irq, 1); 1457226527Sbz } 1458240233Sglebius 1459226527Sbz if (bootverbose) { 1460226527Sbz device_printf(child, "Remapped MSI-X IRQs as: "); 1461226527Sbz for (i = 0; i < count; i++) { 1462240233Sglebius if (i != 0) 1463126258Smlaier printf(", "); 1464240233Sglebius if (vectors[i] == 0) 1465273736Shselasky printf("---"); 1466240233Sglebius else 1467196372Smlaier printf("%d", 1468240233Sglebius msix->msix_vectors[vectors[i]].mv_irq); 1469241039Sglebius } 1470240233Sglebius printf("\n"); 1471240233Sglebius } 1472240233Sglebius 1473240233Sglebius return (0); 1474240233Sglebius} 1475171168Smlaier 1476240233Sglebiusstatic int 1477240233Sglebiuspci_release_msix(device_t dev, device_t child) 1478240233Sglebius{ 1479171168Smlaier struct pci_devinfo *dinfo = device_get_ivars(child); 1480171168Smlaier struct pcicfg_msix *msix = &dinfo->cfg.msix; 1481240233Sglebius struct resource_list_entry *rle; 1482223637Sbz int i; 1483126258Smlaier 1484126258Smlaier /* Do we have any messages to release? */ 1485126258Smlaier if (msix->msix_alloc == 0) 1486126258Smlaier return (ENODEV); 1487126258Smlaier 1488126258Smlaier /* Make sure none of the resources are allocated. */ 1489126258Smlaier for (i = 0; i < msix->msix_table_len; i++) { 1490126258Smlaier if (msix->msix_table[i].mte_vector == 0) 1491126258Smlaier continue; 1492126258Smlaier if (msix->msix_table[i].mte_handlers > 0) 1493126258Smlaier return (EBUSY); 1494126258Smlaier rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1); 1495240233Sglebius KASSERT(rle != NULL, ("missing resource")); 1496171168Smlaier if (rle->res != NULL) 1497171168Smlaier return (EBUSY); 1498240233Sglebius } 1499126261Smlaier 1500126258Smlaier /* Update control register to disable MSI-X. */ 1501126258Smlaier msix->msix_ctrl &= ~PCIM_MSIXCTRL_MSIX_ENABLE; 1502223637Sbz pci_write_config(child, msix->msix_location + PCIR_MSIX_CTRL, 1503126258Smlaier msix->msix_ctrl, 2); 1504126258Smlaier 1505126258Smlaier /* Free the resource list entries. */ 1506263029Sglebius for (i = 0; i < msix->msix_table_len; i++) { 1507126258Smlaier if (msix->msix_table[i].mte_vector == 0) 1508223637Sbz continue; 1509223637Sbz resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1); 1510223637Sbz } 1511126258Smlaier free(msix->msix_table, M_DEVBUF); 1512126258Smlaier msix->msix_table_len = 0; 1513126258Smlaier 1514126258Smlaier /* Release the IRQs. */ 1515126258Smlaier for (i = 0; i < msix->msix_alloc; i++) 1516126258Smlaier PCIB_RELEASE_MSIX(device_get_parent(dev), child, 1517240233Sglebius msix->msix_vectors[i].mv_irq); 1518126258Smlaier free(msix->msix_vectors, M_DEVBUF); 1519126258Smlaier msix->msix_alloc = 0; 1520126258Smlaier return (0); 1521126258Smlaier} 1522126258Smlaier 1523240233Sglebius/* 1524126258Smlaier * Return the max supported MSI-X messages this device supports. 1525261019Sglebius * Basically, assuming the MD code can alloc messages, this function 1526240233Sglebius * should return the maximum value that pci_alloc_msix() can return. 1527240233Sglebius * Thus, it is subject to the tunables, etc. 1528240233Sglebius */ 1529126258Smlaierint 1530261019Sglebiuspci_msix_count_method(device_t dev, device_t child) 1531273736Shselasky{ 1532240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(child); 1533240233Sglebius struct pcicfg_msix *msix = &dinfo->cfg.msix; 1534261018Sglebius 1535285940Sglebius if (pci_do_msix && msix->msix_location != 0) 1536261019Sglebius return (msix->msix_msgnum); 1537240233Sglebius return (0); 1538240233Sglebius} 1539240233Sglebius 1540223637Sbz/* 1541261019Sglebius * HyperTransport MSI mapping control 1542261019Sglebius */ 1543270574Sglebiusvoid 1544270574Sglebiuspci_ht_map_msi(device_t dev, uint64_t addr) 1545130613Smlaier{ 1546126258Smlaier struct pci_devinfo *dinfo = device_get_ivars(dev); 1547240233Sglebius struct pcicfg_ht *ht = &dinfo->cfg.ht; 1548130613Smlaier 1549130613Smlaier if (!ht->ht_msimap) 1550285940Sglebius return; 1551285940Sglebius 1552285940Sglebius if (addr && !(ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE) && 1553126258Smlaier ht->ht_msiaddr >> 20 == addr >> 20) { 1554285940Sglebius /* Enable MSI -> HT mapping. */ 1555285940Sglebius ht->ht_msictrl |= PCIM_HTCMD_MSI_ENABLE; 1556285940Sglebius pci_write_config(dev, ht->ht_msimap + PCIR_HT_COMMAND, 1557285940Sglebius ht->ht_msictrl, 2); 1558130613Smlaier } 1559285940Sglebius 1560285940Sglebius if (!addr && ht->ht_msictrl & PCIM_HTCMD_MSI_ENABLE) { 1561285940Sglebius /* Disable MSI -> HT mapping. */ 1562223637Sbz ht->ht_msictrl &= ~PCIM_HTCMD_MSI_ENABLE; 1563285940Sglebius pci_write_config(dev, ht->ht_msimap + PCIR_HT_COMMAND, 1564285940Sglebius ht->ht_msictrl, 2); 1565285940Sglebius } 1566285940Sglebius} 1567130613Smlaier 1568130613Smlaier/* 1569285940Sglebius * Support for MSI message signalled interrupts. 1570285940Sglebius */ 1571285940Sglebiusvoid 1572285940Sglebiuspci_enable_msi(device_t dev, uint64_t address, uint16_t data) 1573285940Sglebius{ 1574285940Sglebius struct pci_devinfo *dinfo = device_get_ivars(dev); 1575130613Smlaier struct pcicfg_msi *msi = &dinfo->cfg.msi; 1576130613Smlaier 1577130613Smlaier /* Write data and address values. */ 1578126258Smlaier pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR, 1579240233Sglebius address & 0xffffffff, 4); 1580240233Sglebius if (msi->msi_ctrl & PCIM_MSICTRL_64BIT) { 1581240233Sglebius pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR_HIGH, 1582240233Sglebius address >> 32, 4); 1583240233Sglebius pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA_64BIT, 1584240233Sglebius data, 2); 1585240233Sglebius } else 1586145836Smlaier pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA, data, 1587240233Sglebius 2); 1588223637Sbz 1589240233Sglebius /* Enable MSI in the control register. */ 1590240233Sglebius msi->msi_ctrl |= PCIM_MSICTRL_MSI_ENABLE; 1591240233Sglebius pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, 1592240233Sglebius 2); 1593240233Sglebius 1594240233Sglebius /* Enable MSI -> HT mapping. */ 1595240233Sglebius pci_ht_map_msi(dev, address); 1596240233Sglebius} 1597240233Sglebius 1598240233Sglebiusvoid 1599240233Sglebiuspci_disable_msi(device_t dev) 1600240233Sglebius{ 1601240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(dev); 1602240233Sglebius struct pcicfg_msi *msi = &dinfo->cfg.msi; 1603240233Sglebius 1604240233Sglebius /* Disable MSI -> HT mapping. */ 1605223637Sbz pci_ht_map_msi(dev, 0); 1606240233Sglebius 1607240233Sglebius /* Disable MSI in the control register. */ 1608240233Sglebius msi->msi_ctrl &= ~PCIM_MSICTRL_MSI_ENABLE; 1609240233Sglebius pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, 1610240233Sglebius 2); 1611240233Sglebius} 1612240233Sglebius 1613171168Smlaier/* 1614240233Sglebius * Restore MSI registers during resume. If MSI is enabled then 1615240233Sglebius * restore the data and address registers in addition to the control 1616240233Sglebius * register. 1617240233Sglebius */ 1618223637Sbzstatic void 1619240233Sglebiuspci_resume_msi(device_t dev) 1620240233Sglebius{ 1621263029Sglebius struct pci_devinfo *dinfo = device_get_ivars(dev); 1622243944Sglebius struct pcicfg_msi *msi = &dinfo->cfg.msi; 1623243941Sglebius uint64_t address; 1624243941Sglebius uint16_t data; 1625243941Sglebius 1626243941Sglebius if (msi->msi_ctrl & PCIM_MSICTRL_MSI_ENABLE) { 1627240233Sglebius address = msi->msi_addr; 1628240233Sglebius data = msi->msi_data; 1629240233Sglebius pci_write_config(dev, msi->msi_location + PCIR_MSI_ADDR, 1630240233Sglebius address & 0xffffffff, 4); 1631171168Smlaier if (msi->msi_ctrl & PCIM_MSICTRL_64BIT) { 1632171168Smlaier pci_write_config(dev, msi->msi_location + 1633171168Smlaier PCIR_MSI_ADDR_HIGH, address >> 32, 4); 1634171168Smlaier pci_write_config(dev, msi->msi_location + 1635171168Smlaier PCIR_MSI_DATA_64BIT, data, 2); 1636223637Sbz } else 1637240233Sglebius pci_write_config(dev, msi->msi_location + PCIR_MSI_DATA, 1638240233Sglebius data, 2); 1639240233Sglebius } 1640243944Sglebius pci_write_config(dev, msi->msi_location + PCIR_MSI_CTRL, msi->msi_ctrl, 1641145836Smlaier 2); 1642240233Sglebius} 1643270574Sglebius 1644145836Smlaierint 1645145836Smlaierpci_remap_msi_irq(device_t dev, u_int irq) 1646240233Sglebius{ 1647240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(dev); 1648240233Sglebius pcicfgregs *cfg = &dinfo->cfg; 1649241039Sglebius struct resource_list_entry *rle; 1650241039Sglebius struct msix_table_entry *mte; 1651130613Smlaier struct msix_vector *mv; 1652240233Sglebius device_t bus; 1653240233Sglebius uint64_t addr; 1654240233Sglebius uint32_t data; 1655240233Sglebius int error, i, j; 1656240233Sglebius 1657240233Sglebius bus = device_get_parent(dev); 1658240233Sglebius 1659240233Sglebius /* 1660240233Sglebius * Handle MSI first. We try to find this IRQ among our list 1661240233Sglebius * of MSI IRQs. If we find it, we request updated address and 1662240233Sglebius * data registers and apply the results. 1663240233Sglebius */ 1664240233Sglebius if (cfg->msi.msi_alloc > 0) { 1665240233Sglebius 1666240233Sglebius /* If we don't have any active handlers, nothing to do. */ 1667240233Sglebius if (cfg->msi.msi_handlers == 0) 1668240233Sglebius return (0); 1669240233Sglebius for (i = 0; i < cfg->msi.msi_alloc; i++) { 1670171168Smlaier rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 1671240233Sglebius i + 1); 1672240233Sglebius if (rle->start == irq) { 1673240233Sglebius error = PCIB_MAP_MSI(device_get_parent(bus), 1674240233Sglebius dev, irq, &addr, &data); 1675240233Sglebius if (error) 1676240233Sglebius return (error); 1677240233Sglebius pci_disable_msi(dev); 1678240233Sglebius dinfo->cfg.msi.msi_addr = addr; 1679171168Smlaier dinfo->cfg.msi.msi_data = data; 1680240233Sglebius pci_enable_msi(dev, addr, data); 1681241039Sglebius return (0); 1682241039Sglebius } 1683273736Shselasky } 1684241039Sglebius return (ENOENT); 1685241039Sglebius } 1686241039Sglebius 1687241039Sglebius /* 1688240233Sglebius * For MSI-X, we check to see if we have this IRQ. If we do, 1689126258Smlaier * we request the updated mapping info. If that works, we go 1690171168Smlaier * through all the slots that use this IRQ and update them. 1691240233Sglebius */ 1692196372Smlaier if (cfg->msix.msix_alloc > 0) { 1693241039Sglebius for (i = 0; i < cfg->msix.msix_alloc; i++) { 1694126258Smlaier mv = &cfg->msix.msix_vectors[i]; 1695126258Smlaier if (mv->mv_irq == irq) { 1696240233Sglebius error = PCIB_MAP_MSI(device_get_parent(bus), 1697240233Sglebius dev, irq, &addr, &data); 1698126258Smlaier if (error) 1699240233Sglebius return (error); 1700240233Sglebius mv->mv_address = addr; 1701126258Smlaier mv->mv_data = data; 1702240233Sglebius for (j = 0; j < cfg->msix.msix_table_len; j++) { 1703240811Sglebius mte = &cfg->msix.msix_table[j]; 1704240811Sglebius if (mte->mte_vector != i + 1) 1705240811Sglebius continue; 1706240811Sglebius if (mte->mte_handlers == 0) 1707240811Sglebius continue; 1708240811Sglebius pci_mask_msix(dev, j); 1709240811Sglebius pci_enable_msix(dev, j, addr, data); 1710240811Sglebius pci_unmask_msix(dev, j); 1711240811Sglebius } 1712240811Sglebius } 1713240811Sglebius } 1714240811Sglebius return (ENOENT); 1715240811Sglebius } 1716240233Sglebius 1717240233Sglebius return (ENOENT); 1718240233Sglebius} 1719240233Sglebius 1720240233Sglebius/* 1721240233Sglebius * Returns true if the specified device is blacklisted because MSI 1722240233Sglebius * doesn't work. 1723240233Sglebius */ 1724240233Sglebiusint 1725240233Sglebiuspci_msi_device_blacklisted(device_t dev) 1726240233Sglebius{ 1727240233Sglebius struct pci_quirk *q; 1728240233Sglebius 1729240233Sglebius if (!pci_honor_msi_blacklist) 1730240233Sglebius return (0); 1731240233Sglebius 1732240233Sglebius for (q = &pci_quirks[0]; q->devid; q++) { 1733126258Smlaier if (q->devid == pci_get_devid(dev) && 1734240233Sglebius q->type == PCI_QUIRK_DISABLE_MSI) 1735240233Sglebius return (1); 1736240233Sglebius } 1737240233Sglebius return (0); 1738240233Sglebius} 1739240233Sglebius 1740240233Sglebius/* 1741240233Sglebius * Determine if MSI is blacklisted globally on this sytem. Currently, 1742126258Smlaier * we just check for blacklisted chipsets as represented by the 1743126258Smlaier * host-PCI bridge at device 0:0:0. In the future, it may become 1744126258Smlaier * necessary to check other system attributes, such as the kenv values 1745126258Smlaier * that give the motherboard manufacturer and model number. 1746126258Smlaier */ 1747126258Smlaierstatic int 1748126258Smlaierpci_msi_blacklisted(void) 1749126258Smlaier{ 1750126258Smlaier device_t dev; 1751126258Smlaier 1752126258Smlaier if (!pci_honor_msi_blacklist) 1753126258Smlaier return (0); 1754126258Smlaier 1755126258Smlaier /* Blacklist all non-PCI-express and non-PCI-X chipsets. */ 1756126258Smlaier if (!(pcie_chipset || pcix_chipset)) 1757126258Smlaier return (1); 1758126258Smlaier 1759126258Smlaier dev = pci_find_bsf(0, 0, 0); 1760126258Smlaier if (dev != NULL) 1761126258Smlaier return (pci_msi_device_blacklisted(dev)); 1762126258Smlaier return (0); 1763223637Sbz} 1764223637Sbz 1765126258Smlaier/* 1766126258Smlaier * Attempt to allocate *count MSI messages. The actual number allocated is 1767126258Smlaier * returned in *count. After this function returns, each message will be 1768126258Smlaier * available to the driver as SYS_RES_IRQ resources starting at a rid 1. 1769223637Sbz */ 1770126258Smlaierint 1771223637Sbzpci_alloc_msi_method(device_t dev, device_t child, int *count) 1772223637Sbz{ 1773223637Sbz struct pci_devinfo *dinfo = device_get_ivars(child); 1774223637Sbz pcicfgregs *cfg = &dinfo->cfg; 1775126258Smlaier struct resource_list_entry *rle; 1776223637Sbz int actual, error, i, irqs[32]; 1777126258Smlaier uint16_t ctrl; 1778126258Smlaier 1779223637Sbz /* Don't let count == 0 get us into trouble. */ 1780223637Sbz if (*count == 0) 1781223637Sbz return (EINVAL); 1782223637Sbz 1783223637Sbz /* If rid 0 is allocated, then fail. */ 1784126258Smlaier rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, 0); 1785126258Smlaier if (rle != NULL && rle->res != NULL) 1786223637Sbz return (ENXIO); 1787223637Sbz 1788223637Sbz /* Already have allocated messages? */ 1789223637Sbz if (cfg->msi.msi_alloc != 0 || cfg->msix.msix_alloc != 0) 1790126258Smlaier return (ENXIO); 1791126258Smlaier 1792126258Smlaier /* If MSI is blacklisted for this system, fail. */ 1793126258Smlaier if (pci_msi_blacklisted()) 1794126258Smlaier return (ENXIO); 1795126258Smlaier 1796126258Smlaier /* MSI capability present? */ 1797126258Smlaier if (cfg->msi.msi_location == 0 || !pci_do_msi) 1798126258Smlaier return (ENODEV); 1799126258Smlaier 1800126258Smlaier if (bootverbose) 1801126258Smlaier device_printf(child, 1802126258Smlaier "attempting to allocate %d MSI vectors (%d supported)\n", 1803126258Smlaier *count, cfg->msi.msi_msgnum); 1804126258Smlaier 1805126258Smlaier /* Don't ask for more than the device supports. */ 1806126258Smlaier actual = min(*count, cfg->msi.msi_msgnum); 1807126258Smlaier 1808126258Smlaier /* Don't ask for more than 32 messages. */ 1809126258Smlaier actual = min(actual, 32); 1810223637Sbz 1811223637Sbz /* MSI requires power of 2 number of messages. */ 1812223637Sbz if (!powerof2(actual)) 1813240233Sglebius return (EINVAL); 1814223637Sbz 1815223637Sbz for (;;) { 1816223637Sbz /* Try to allocate N messages. */ 1817223637Sbz error = PCIB_ALLOC_MSI(device_get_parent(dev), child, actual, 1818223637Sbz cfg->msi.msi_msgnum, irqs); 1819223637Sbz if (error == 0) 1820223637Sbz break; 1821223637Sbz if (actual == 1) 1822223637Sbz return (error); 1823223637Sbz 1824223637Sbz /* Try N / 2. */ 1825223637Sbz actual >>= 1; 1826223637Sbz } 1827223637Sbz 1828223637Sbz /* 1829223637Sbz * We now have N actual messages mapped onto SYS_RES_IRQ 1830223637Sbz * resources in the irqs[] array, so add new resources 1831223637Sbz * starting at rid 1. 1832223637Sbz */ 1833126258Smlaier for (i = 0; i < actual; i++) 1834223637Sbz resource_list_add(&dinfo->resources, SYS_RES_IRQ, i + 1, 1835126258Smlaier irqs[i], irqs[i], 1); 1836126258Smlaier 1837223637Sbz if (bootverbose) { 1838126258Smlaier if (actual == 1) 1839126258Smlaier device_printf(child, "using IRQ %d for MSI\n", irqs[0]); 1840223637Sbz else { 1841126258Smlaier int run; 1842126258Smlaier 1843223637Sbz /* 1844126258Smlaier * Be fancy and try to print contiguous runs 1845126258Smlaier * of IRQ values as ranges. 'run' is true if 1846223637Sbz * we are in a range. 1847126258Smlaier */ 1848126258Smlaier device_printf(child, "using IRQs %d", irqs[0]); 1849223637Sbz run = 0; 1850223637Sbz for (i = 1; i < actual; i++) { 1851223637Sbz 1852223637Sbz /* Still in a run? */ 1853223637Sbz if (irqs[i] == irqs[i - 1] + 1) { 1854223637Sbz run = 1; 1855223637Sbz continue; 1856223637Sbz } 1857223637Sbz 1858223637Sbz /* Finish previous range. */ 1859223637Sbz if (run) { 1860223637Sbz printf("-%d", irqs[i - 1]); 1861223637Sbz run = 0; 1862223637Sbz } 1863223637Sbz 1864223637Sbz /* Start new range. */ 1865223637Sbz printf(",%d", irqs[i]); 1866223637Sbz } 1867223637Sbz 1868223637Sbz /* Unfinished range? */ 1869223637Sbz if (run) 1870223637Sbz printf("-%d", irqs[actual - 1]); 1871223637Sbz printf(" for MSI\n"); 1872223637Sbz } 1873223637Sbz } 1874223637Sbz 1875223637Sbz /* Update control register with actual count. */ 1876223637Sbz ctrl = cfg->msi.msi_ctrl; 1877223637Sbz ctrl &= ~PCIM_MSICTRL_MME_MASK; 1878223637Sbz ctrl |= (ffs(actual) - 1) << 4; 1879223637Sbz cfg->msi.msi_ctrl = ctrl; 1880223637Sbz pci_write_config(child, cfg->msi.msi_location + PCIR_MSI_CTRL, ctrl, 2); 1881223637Sbz 1882223637Sbz /* Update counts of alloc'd messages. */ 1883223637Sbz cfg->msi.msi_alloc = actual; 1884223637Sbz cfg->msi.msi_handlers = 0; 1885223637Sbz *count = actual; 1886223637Sbz return (0); 1887223637Sbz} 1888223637Sbz 1889223637Sbz/* Release the MSI messages associated with this device. */ 1890223637Sbzint 1891126258Smlaierpci_release_msi_method(device_t dev, device_t child) 1892126258Smlaier{ 1893126258Smlaier struct pci_devinfo *dinfo = device_get_ivars(child); 1894126258Smlaier struct pcicfg_msi *msi = &dinfo->cfg.msi; 1895126258Smlaier struct resource_list_entry *rle; 1896126258Smlaier int error, i, irqs[32]; 1897126258Smlaier 1898126258Smlaier /* Try MSI-X first. */ 1899126258Smlaier error = pci_release_msix(dev, child); 1900126258Smlaier if (error != ENODEV) 1901126258Smlaier return (error); 1902126258Smlaier 1903126258Smlaier /* Do we have any messages to release? */ 1904126258Smlaier if (msi->msi_alloc == 0) 1905126258Smlaier return (ENODEV); 1906126258Smlaier KASSERT(msi->msi_alloc <= 32, ("more than 32 alloc'd messages")); 1907126258Smlaier 1908126258Smlaier /* Make sure none of the resources are allocated. */ 1909126258Smlaier if (msi->msi_handlers > 0) 1910126258Smlaier return (EBUSY); 1911126258Smlaier for (i = 0; i < msi->msi_alloc; i++) { 1912126258Smlaier rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, i + 1); 1913126258Smlaier KASSERT(rle != NULL, ("missing MSI resource")); 1914126258Smlaier if (rle->res != NULL) 1915126258Smlaier return (EBUSY); 1916126258Smlaier irqs[i] = rle->start; 1917126258Smlaier } 1918126258Smlaier 1919126258Smlaier /* Update control register with 0 count. */ 1920126258Smlaier KASSERT(!(msi->msi_ctrl & PCIM_MSICTRL_MSI_ENABLE), 1921126258Smlaier ("%s: MSI still enabled", __func__)); 1922126258Smlaier msi->msi_ctrl &= ~PCIM_MSICTRL_MME_MASK; 1923126258Smlaier pci_write_config(child, msi->msi_location + PCIR_MSI_CTRL, 1924126258Smlaier msi->msi_ctrl, 2); 1925126258Smlaier 1926126258Smlaier /* Release the messages. */ 1927126258Smlaier PCIB_RELEASE_MSI(device_get_parent(dev), child, msi->msi_alloc, irqs); 1928126258Smlaier for (i = 0; i < msi->msi_alloc; i++) 1929126258Smlaier resource_list_delete(&dinfo->resources, SYS_RES_IRQ, i + 1); 1930126258Smlaier 1931126258Smlaier /* Update alloc count. */ 1932126258Smlaier msi->msi_alloc = 0; 1933126258Smlaier msi->msi_addr = 0; 1934126258Smlaier msi->msi_data = 0; 1935126258Smlaier return (0); 1936130613Smlaier} 1937126258Smlaier 1938126258Smlaier/* 1939126258Smlaier * Return the max supported MSI messages this device supports. 1940126258Smlaier * Basically, assuming the MD code can alloc messages, this function 1941126258Smlaier * should return the maximum value that pci_alloc_msi() can return. 1942126258Smlaier * Thus, it is subject to the tunables, etc. 1943126258Smlaier */ 1944145836Smlaierint 1945126258Smlaierpci_msi_count_method(device_t dev, device_t child) 1946126258Smlaier{ 1947126258Smlaier struct pci_devinfo *dinfo = device_get_ivars(child); 1948126258Smlaier struct pcicfg_msi *msi = &dinfo->cfg.msi; 1949126258Smlaier 1950126258Smlaier if (pci_do_msi && msi->msi_location != 0) 1951145836Smlaier return (msi->msi_msgnum); 1952126258Smlaier return (0); 1953126258Smlaier} 1954126258Smlaier 1955126258Smlaier/* free pcicfgregs structure and all depending data structures */ 1956126258Smlaier 1957126258Smlaierint 1958126258Smlaierpci_freecfg(struct pci_devinfo *dinfo) 1959126258Smlaier{ 1960126258Smlaier struct devlist *devlist_head; 1961126258Smlaier int i; 1962126258Smlaier 1963126258Smlaier devlist_head = &pci_devq; 1964126258Smlaier 1965126258Smlaier if (dinfo->cfg.vpd.vpd_reg) { 1966240233Sglebius free(dinfo->cfg.vpd.vpd_ident, M_DEVBUF); 1967126258Smlaier for (i = 0; i < dinfo->cfg.vpd.vpd_rocnt; i++) 1968126258Smlaier free(dinfo->cfg.vpd.vpd_ros[i].value, M_DEVBUF); 1969126258Smlaier free(dinfo->cfg.vpd.vpd_ros, M_DEVBUF); 1970126258Smlaier for (i = 0; i < dinfo->cfg.vpd.vpd_wcnt; i++) 1971126258Smlaier free(dinfo->cfg.vpd.vpd_w[i].value, M_DEVBUF); 1972126258Smlaier free(dinfo->cfg.vpd.vpd_w, M_DEVBUF); 1973223637Sbz } 1974126258Smlaier STAILQ_REMOVE(devlist_head, dinfo, pci_devinfo, pci_links); 1975126258Smlaier free(dinfo, M_DEVBUF); 1976126258Smlaier 1977126258Smlaier /* increment the generation count */ 1978126258Smlaier pci_generation++; 1979126258Smlaier 1980130613Smlaier /* we're losing one device */ 1981126258Smlaier pci_numdevs--; 1982171168Smlaier return (0); 1983126258Smlaier} 1984126258Smlaier 1985126258Smlaier/* 1986126258Smlaier * PCI power manangement 1987126258Smlaier */ 1988126258Smlaierint 1989126258Smlaierpci_set_powerstate_method(device_t dev, device_t child, int state) 1990126258Smlaier{ 1991126258Smlaier struct pci_devinfo *dinfo = device_get_ivars(child); 1992289703Skp pcicfgregs *cfg = &dinfo->cfg; 1993289703Skp uint16_t status; 1994289703Skp int result, oldstate, highest, delay; 1995289703Skp 1996289703Skp if (cfg->pp.pp_cap == 0) 1997289703Skp return (EOPNOTSUPP); 1998289703Skp 1999289703Skp /* 2000289703Skp * Optimize a no state change request away. While it would be OK to 2001289703Skp * write to the hardware in theory, some devices have shown odd 2002289703Skp * behavior when going from D3 -> D3. 2003289703Skp */ 2004289703Skp oldstate = pci_get_powerstate(child); 2005289703Skp if (oldstate == state) 2006289703Skp return (0); 2007289703Skp 2008126258Smlaier /* 2009126258Smlaier * The PCI power management specification states that after a state 2010126258Smlaier * transition between PCI power states, system software must 2011126258Smlaier * guarantee a minimal delay before the function accesses the device. 2012126258Smlaier * Compute the worst case delay that we need to guarantee before we 2013126258Smlaier * access the device. Many devices will be responsive much more 2014126258Smlaier * quickly than this delay, but there are some that don't respond 2015126258Smlaier * instantly to state changes. Transitions to/from D3 state require 2016126258Smlaier * 10ms, while D2 requires 200us, and D0/1 require none. The delay 2017126258Smlaier * is done below with DELAY rather than a sleeper function because 2018126258Smlaier * this function can be called from contexts where we cannot sleep. 2019126258Smlaier */ 2020126258Smlaier highest = (oldstate > state) ? oldstate : state; 2021126258Smlaier if (highest == PCI_POWERSTATE_D3) 2022126258Smlaier delay = 10000; 2023289703Skp else if (highest == PCI_POWERSTATE_D2) 2024289703Skp delay = 200; 2025289703Skp else 2026289703Skp delay = 0; 2027289703Skp status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2) 2028289703Skp & ~PCIM_PSTAT_DMASK; 2029289703Skp result = 0; 2030289703Skp switch (state) { 2031289703Skp case PCI_POWERSTATE_D0: 2032289703Skp status |= PCIM_PSTAT_D0; 2033240233Sglebius break; 2034289703Skp case PCI_POWERSTATE_D1: 2035289703Skp if ((cfg->pp.pp_cap & PCIM_PCAP_D1SUPP) == 0) 2036289703Skp return (EOPNOTSUPP); 2037126258Smlaier status |= PCIM_PSTAT_D1; 2038126258Smlaier break; 2039126258Smlaier case PCI_POWERSTATE_D2: 2040126258Smlaier if ((cfg->pp.pp_cap & PCIM_PCAP_D2SUPP) == 0) 2041126258Smlaier return (EOPNOTSUPP); 2042126258Smlaier status |= PCIM_PSTAT_D2; 2043126258Smlaier break; 2044289703Skp case PCI_POWERSTATE_D3: 2045289703Skp status |= PCIM_PSTAT_D3; 2046289703Skp break; 2047126258Smlaier default: 2048126258Smlaier return (EINVAL); 2049126258Smlaier } 2050126258Smlaier 2051126258Smlaier if (bootverbose) 2052126258Smlaier printf( 2053126258Smlaier "pci%d:%d:%d:%d: Transition from D%d to D%d\n", 2054126258Smlaier dinfo->cfg.domain, dinfo->cfg.bus, dinfo->cfg.slot, 2055126258Smlaier dinfo->cfg.func, oldstate, state); 2056289703Skp 2057289703Skp PCI_WRITE_CONFIG(dev, child, cfg->pp.pp_status, status, 2); 2058126258Smlaier if (delay) 2059289703Skp DELAY(delay); 2060289703Skp return (0); 2061289703Skp} 2062126258Smlaier 2063126258Smlaierint 2064126258Smlaierpci_get_powerstate_method(device_t dev, device_t child) 2065126258Smlaier{ 2066126258Smlaier struct pci_devinfo *dinfo = device_get_ivars(child); 2067126258Smlaier pcicfgregs *cfg = &dinfo->cfg; 2068289703Skp uint16_t status; 2069126258Smlaier int result; 2070126258Smlaier 2071126258Smlaier if (cfg->pp.pp_cap != 0) { 2072126258Smlaier status = PCI_READ_CONFIG(dev, child, cfg->pp.pp_status, 2); 2073126258Smlaier switch (status & PCIM_PSTAT_DMASK) { 2074126258Smlaier case PCIM_PSTAT_D0: 2075126258Smlaier result = PCI_POWERSTATE_D0; 2076289703Skp break; 2077289703Skp case PCIM_PSTAT_D1: 2078289703Skp result = PCI_POWERSTATE_D1; 2079126258Smlaier break; 2080126258Smlaier case PCIM_PSTAT_D2: 2081126258Smlaier result = PCI_POWERSTATE_D2; 2082289703Skp break; 2083289703Skp case PCIM_PSTAT_D3: 2084289703Skp result = PCI_POWERSTATE_D3; 2085289703Skp break; 2086289703Skp default: 2087289703Skp result = PCI_POWERSTATE_UNKNOWN; 2088289703Skp break; 2089126258Smlaier } 2090126258Smlaier } else { 2091126258Smlaier /* No support, device is always at D0 */ 2092126258Smlaier result = PCI_POWERSTATE_D0; 2093126258Smlaier } 2094126258Smlaier return (result); 2095126258Smlaier} 2096126258Smlaier 2097126258Smlaier/* 2098126258Smlaier * Some convenience functions for PCI device drivers. 2099126258Smlaier */ 2100126258Smlaier 2101126258Smlaierstatic __inline void 2102126258Smlaierpci_set_command_bit(device_t dev, device_t child, uint16_t bit) 2103289703Skp{ 2104289703Skp uint16_t command; 2105289703Skp 2106289703Skp command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); 2107289703Skp command |= bit; 2108289703Skp PCI_WRITE_CONFIG(dev, child, PCIR_COMMAND, command, 2); 2109289703Skp} 2110289703Skp 2111289703Skpstatic __inline void 2112289703Skppci_clear_command_bit(device_t dev, device_t child, uint16_t bit) 2113289703Skp{ 2114289703Skp uint16_t command; 2115289703Skp 2116126258Smlaier command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); 2117240233Sglebius command &= ~bit; 2118126258Smlaier PCI_WRITE_CONFIG(dev, child, PCIR_COMMAND, command, 2); 2119126258Smlaier} 2120126258Smlaier 2121126258Smlaierint 2122126258Smlaierpci_enable_busmaster_method(device_t dev, device_t child) 2123126258Smlaier{ 2124126258Smlaier pci_set_command_bit(dev, child, PCIM_CMD_BUSMASTEREN); 2125126258Smlaier return (0); 2126126258Smlaier} 2127126258Smlaier 2128126258Smlaierint 2129126258Smlaierpci_disable_busmaster_method(device_t dev, device_t child) 2130126258Smlaier{ 2131126258Smlaier pci_clear_command_bit(dev, child, PCIM_CMD_BUSMASTEREN); 2132126258Smlaier return (0); 2133126258Smlaier} 2134126258Smlaier 2135126258Smlaierint 2136126258Smlaierpci_enable_io_method(device_t dev, device_t child, int space) 2137126258Smlaier{ 2138126258Smlaier uint16_t command; 2139240233Sglebius uint16_t bit; 2140126258Smlaier char *error; 2141126258Smlaier 2142126258Smlaier bit = 0; 2143126258Smlaier error = NULL; 2144126258Smlaier 2145126258Smlaier switch(space) { 2146126258Smlaier case SYS_RES_IOPORT: 2147223637Sbz bit = PCIM_CMD_PORTEN; 2148223637Sbz error = "port"; 2149126258Smlaier break; 2150126258Smlaier case SYS_RES_MEMORY: 2151126258Smlaier bit = PCIM_CMD_MEMEN; 2152126258Smlaier error = "memory"; 2153223637Sbz break; 2154126258Smlaier default: 2155126258Smlaier return (EINVAL); 2156126258Smlaier } 2157126258Smlaier pci_set_command_bit(dev, child, bit); 2158126258Smlaier /* Some devices seem to need a brief stall here, what do to? */ 2159126258Smlaier command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); 2160126258Smlaier if (command & bit) 2161126258Smlaier return (0); 2162126258Smlaier device_printf(child, "failed to enable %s mapping!\n", error); 2163126258Smlaier return (ENXIO); 2164126258Smlaier} 2165126258Smlaier 2166126258Smlaierint 2167126258Smlaierpci_disable_io_method(device_t dev, device_t child, int space) 2168126258Smlaier{ 2169126258Smlaier uint16_t command; 2170126258Smlaier uint16_t bit; 2171126258Smlaier char *error; 2172126258Smlaier 2173126258Smlaier bit = 0; 2174126258Smlaier error = NULL; 2175126258Smlaier 2176126258Smlaier switch(space) { 2177126258Smlaier case SYS_RES_IOPORT: 2178126258Smlaier bit = PCIM_CMD_PORTEN; 2179126258Smlaier error = "port"; 2180126258Smlaier break; 2181126258Smlaier case SYS_RES_MEMORY: 2182126258Smlaier bit = PCIM_CMD_MEMEN; 2183126258Smlaier error = "memory"; 2184126258Smlaier break; 2185126258Smlaier default: 2186126258Smlaier return (EINVAL); 2187126258Smlaier } 2188126258Smlaier pci_clear_command_bit(dev, child, bit); 2189126258Smlaier command = PCI_READ_CONFIG(dev, child, PCIR_COMMAND, 2); 2190126258Smlaier if (command & bit) { 2191126258Smlaier device_printf(child, "failed to disable %s mapping!\n", error); 2192126258Smlaier return (ENXIO); 2193126258Smlaier } 2194126258Smlaier return (0); 2195126258Smlaier} 2196126258Smlaier 2197223637Sbz/* 2198223637Sbz * New style pci driver. Parent device is either a pci-host-bridge or a 2199223637Sbz * pci-pci-bridge. Both kinds are represented by instances of pcib. 2200223637Sbz */ 2201126258Smlaier 2202223637Sbzvoid 2203223637Sbzpci_print_verbose(struct pci_devinfo *dinfo) 2204223637Sbz{ 2205223637Sbz 2206223637Sbz if (bootverbose) { 2207126258Smlaier pcicfgregs *cfg = &dinfo->cfg; 2208126258Smlaier 2209223637Sbz printf("found->\tvendor=0x%04x, dev=0x%04x, revid=0x%02x\n", 2210223637Sbz cfg->vendor, cfg->device, cfg->revid); 2211223637Sbz printf("\tdomain=%d, bus=%d, slot=%d, func=%d\n", 2212223637Sbz cfg->domain, cfg->bus, cfg->slot, cfg->func); 2213223637Sbz printf("\tclass=%02x-%02x-%02x, hdrtype=0x%02x, mfdev=%d\n", 2214223637Sbz cfg->baseclass, cfg->subclass, cfg->progif, cfg->hdrtype, 2215223637Sbz cfg->mfdev); 2216223637Sbz printf("\tcmdreg=0x%04x, statreg=0x%04x, cachelnsz=%d (dwords)\n", 2217223637Sbz cfg->cmdreg, cfg->statreg, cfg->cachelnsz); 2218223637Sbz printf("\tlattimer=0x%02x (%d ns), mingnt=0x%02x (%d ns), maxlat=0x%02x (%d ns)\n", 2219223637Sbz cfg->lattimer, cfg->lattimer * 30, cfg->mingnt, 2220223637Sbz cfg->mingnt * 250, cfg->maxlat, cfg->maxlat * 250); 2221223637Sbz if (cfg->intpin > 0) 2222126258Smlaier printf("\tintpin=%c, irq=%d\n", 2223223637Sbz cfg->intpin +'a' -1, cfg->intline); 2224126258Smlaier if (cfg->pp.pp_cap) { 2225126258Smlaier uint16_t status; 2226126258Smlaier 2227171168Smlaier status = pci_read_config(cfg->dev, cfg->pp.pp_status, 2); 2228171168Smlaier printf("\tpowerspec %d supports D0%s%s D3 current D%d\n", 2229171168Smlaier cfg->pp.pp_cap & PCIM_PCAP_SPEC, 2230171168Smlaier cfg->pp.pp_cap & PCIM_PCAP_D1SUPP ? " D1" : "", 2231171168Smlaier cfg->pp.pp_cap & PCIM_PCAP_D2SUPP ? " D2" : "", 2232240233Sglebius status & PCIM_PSTAT_DMASK); 2233171168Smlaier } 2234171168Smlaier if (cfg->msi.msi_location) { 2235171168Smlaier int ctrl; 2236171168Smlaier 2237171168Smlaier ctrl = cfg->msi.msi_ctrl; 2238171168Smlaier printf("\tMSI supports %d message%s%s%s\n", 2239171168Smlaier cfg->msi.msi_msgnum, 2240171168Smlaier (cfg->msi.msi_msgnum == 1) ? "" : "s", 2241223637Sbz (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", 2242171168Smlaier (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks":""); 2243171168Smlaier } 2244171168Smlaier if (cfg->msix.msix_location) { 2245171168Smlaier printf("\tMSI-X supports %d message%s ", 2246171168Smlaier cfg->msix.msix_msgnum, 2247171168Smlaier (cfg->msix.msix_msgnum == 1) ? "" : "s"); 2248171168Smlaier if (cfg->msix.msix_table_bar == cfg->msix.msix_pba_bar) 2249171168Smlaier printf("in map 0x%x\n", 2250171168Smlaier cfg->msix.msix_table_bar); 2251171168Smlaier else 2252171168Smlaier printf("in maps 0x%x and 0x%x\n", 2253171168Smlaier cfg->msix.msix_table_bar, 2254171168Smlaier cfg->msix.msix_pba_bar); 2255171168Smlaier } 2256171168Smlaier } 2257171168Smlaier} 2258171168Smlaier 2259171168Smlaierstatic int 2260171168Smlaierpci_porten(device_t dev) 2261289703Skp{ 2262289703Skp return (pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_PORTEN) != 0; 2263289703Skp} 2264289703Skp 2265171168Smlaierstatic int 2266171168Smlaierpci_memen(device_t dev) 2267171168Smlaier{ 2268171168Smlaier return (pci_read_config(dev, PCIR_COMMAND, 2) & PCIM_CMD_MEMEN) != 0; 2269171168Smlaier} 2270171168Smlaier 2271171168Smlaierstatic void 2272171168Smlaierpci_read_bar(device_t dev, int reg, pci_addr_t *mapp, pci_addr_t *testvalp) 2273171168Smlaier{ 2274171168Smlaier pci_addr_t map, testval; 2275171168Smlaier int ln2range; 2276171168Smlaier uint16_t cmd; 2277171168Smlaier 2278171168Smlaier map = pci_read_config(dev, reg, 4); 2279171168Smlaier ln2range = pci_maprange(map); 2280171168Smlaier if (ln2range == 64) 2281171168Smlaier map |= (pci_addr_t)pci_read_config(dev, reg + 4, 4) << 32; 2282171168Smlaier 2283240233Sglebius /* 2284162238Scsjp * Disable decoding via the command register before 2285126258Smlaier * determining the BAR's length since we will be placing it in 2286126258Smlaier * a weird state. 2287145836Smlaier */ 2288240233Sglebius cmd = pci_read_config(dev, PCIR_COMMAND, 2); 2289126258Smlaier pci_write_config(dev, PCIR_COMMAND, 2290240233Sglebius cmd & ~(PCI_BAR_MEM(map) ? PCIM_CMD_MEMEN : PCIM_CMD_PORTEN), 2); 2291126258Smlaier 2292171168Smlaier /* 2293126258Smlaier * Determine the BAR's length by writing all 1's. The bottom 2294240233Sglebius * log_2(size) bits of the BAR will stick as 0 when we read 2295126258Smlaier * the value back. 2296126258Smlaier */ 2297240233Sglebius pci_write_config(dev, reg, 0xffffffff, 4); 2298126258Smlaier testval = pci_read_config(dev, reg, 4); 2299171168Smlaier if (ln2range == 64) { 2300171168Smlaier pci_write_config(dev, reg + 4, 0xffffffff, 4); 2301223637Sbz testval |= (pci_addr_t)pci_read_config(dev, reg + 4, 4) << 32; 2302126258Smlaier } 2303171168Smlaier 2304171168Smlaier /* 2305171168Smlaier * Restore the original value of the BAR. We may have reprogrammed 2306126258Smlaier * the BAR of the low-level console device and when booting verbose, 2307126258Smlaier * we need the console device addressable. 2308126258Smlaier */ 2309126258Smlaier pci_write_config(dev, reg, map, 4); 2310126258Smlaier if (ln2range == 64) 2311126258Smlaier pci_write_config(dev, reg + 4, map >> 32, 4); 2312126258Smlaier pci_write_config(dev, PCIR_COMMAND, cmd, 2); 2313126258Smlaier 2314126258Smlaier *mapp = map; 2315126258Smlaier *testvalp = testval; 2316126258Smlaier} 2317126258Smlaier 2318126258Smlaierstatic void 2319126258Smlaierpci_write_bar(device_t dev, int reg, pci_addr_t base) 2320126258Smlaier{ 2321126258Smlaier pci_addr_t map; 2322240233Sglebius int ln2range; 2323240233Sglebius 2324126258Smlaier map = pci_read_config(dev, reg, 4); 2325126258Smlaier ln2range = pci_maprange(map); 2326240233Sglebius pci_write_config(dev, reg, base, 4); 2327240233Sglebius if (ln2range == 64) 2328240233Sglebius pci_write_config(dev, reg + 4, base >> 32, 4); 2329132280Smlaier} 2330248324Sglebius 2331240233Sglebius/* 2332240233Sglebius * Add a resource based on a pci map register. Return 1 if the map 2333240233Sglebius * register is a 32bit map register or 2 if it is a 64bit register. 2334240233Sglebius */ 2335162238Scsjpstatic int 2336223637Sbzpci_add_map(device_t bus, device_t dev, int reg, struct resource_list *rl, 2337162238Scsjp int force, int prefetch) 2338171168Smlaier{ 2339240233Sglebius pci_addr_t base, map, testval; 2340171168Smlaier pci_addr_t start, end, count; 2341171168Smlaier int barlen, maprange, mapsize, type; 2342171168Smlaier uint16_t cmd; 2343171168Smlaier struct resource *res; 2344145836Smlaier 2345223637Sbz pci_read_bar(dev, reg, &map, &testval); 2346145836Smlaier if (PCI_BAR_MEM(map)) { 2347171168Smlaier type = SYS_RES_MEMORY; 2348178888Sjulian if (map & PCIM_BAR_MEM_PREFETCH) 2349223637Sbz prefetch = 1; 2350126258Smlaier } else 2351126258Smlaier type = SYS_RES_IOPORT; 2352171168Smlaier mapsize = pci_mapsize(testval); 2353223637Sbz base = pci_mapbase(map); 2354171168Smlaier maprange = pci_maprange(map); 2355171168Smlaier barlen = maprange == 64 ? 2 : 1; 2356126258Smlaier 2357145836Smlaier /* 2358126258Smlaier * For I/O registers, if bottom bit is set, and the next bit up 2359126258Smlaier * isn't clear, we know we have a BAR that doesn't conform to the 2360126258Smlaier * spec, so ignore it. Also, sanity check the size of the data 2361126258Smlaier * areas to the type of memory involved. Memory must be at least 2362126258Smlaier * 16 bytes in size, while I/O ranges must be at least 4. 2363126258Smlaier */ 2364126258Smlaier if (PCI_BAR_IO(testval) && (testval & PCIM_BAR_IO_RESERVED) != 0) 2365126258Smlaier return (barlen); 2366126258Smlaier if ((type == SYS_RES_MEMORY && mapsize < 4) || 2367126258Smlaier (type == SYS_RES_IOPORT && mapsize < 2)) 2368126258Smlaier return (barlen); 2369126258Smlaier 2370126258Smlaier if (bootverbose) { 2371126258Smlaier printf("\tmap[%02x]: type %s, range %2d, base %#jx, size %2d", 2372126258Smlaier reg, pci_maptype(map), maprange, (uintmax_t)base, mapsize); 2373126258Smlaier if (type == SYS_RES_IOPORT && !pci_porten(dev)) 2374126258Smlaier printf(", port disabled\n"); 2375126258Smlaier else if (type == SYS_RES_MEMORY && !pci_memen(dev)) 2376126258Smlaier printf(", memory disabled\n"); 2377126258Smlaier else 2378126258Smlaier printf(", enabled\n"); 2379126258Smlaier } 2380126258Smlaier 2381126258Smlaier /* 2382126258Smlaier * If base is 0, then we have problems. It is best to ignore 2383126258Smlaier * such entries for the moment. These will be allocated later if 2384126258Smlaier * the driver specifically requests them. However, some 2385126258Smlaier * removable busses look better when all resources are allocated, 2386126258Smlaier * so allow '0' to be overriden. 2387126258Smlaier * 2388126258Smlaier * Similarly treat maps whose values is the same as the test value 2389126258Smlaier * read back. These maps have had all f's written to them by the 2390126258Smlaier * BIOS in an attempt to disable the resources. 2391126258Smlaier */ 2392126258Smlaier if (!force && (base == 0 || map == testval)) 2393126258Smlaier return (barlen); 2394126258Smlaier if ((u_long)base != base) { 2395126258Smlaier device_printf(bus, 2396126258Smlaier "pci%d:%d:%d:%d bar %#x too many address bits", 2397126258Smlaier pci_get_domain(dev), pci_get_bus(dev), pci_get_slot(dev), 2398126258Smlaier pci_get_function(dev), reg); 2399126258Smlaier return (barlen); 2400126258Smlaier } 2401126258Smlaier 2402126258Smlaier /* 2403126258Smlaier * This code theoretically does the right thing, but has 2404126258Smlaier * undesirable side effects in some cases where peripherals 2405126258Smlaier * respond oddly to having these bits enabled. Let the user 2406126258Smlaier * be able to turn them off (since pci_enable_io_modes is 1 by 2407126258Smlaier * default). 2408126258Smlaier */ 2409126258Smlaier if (pci_enable_io_modes) { 2410126258Smlaier /* Turn on resources that have been left off by a lazy BIOS */ 2411126258Smlaier if (type == SYS_RES_IOPORT && !pci_porten(dev)) { 2412126258Smlaier cmd = pci_read_config(dev, PCIR_COMMAND, 2); 2413126258Smlaier cmd |= PCIM_CMD_PORTEN; 2414126258Smlaier pci_write_config(dev, PCIR_COMMAND, cmd, 2); 2415126258Smlaier } 2416126258Smlaier if (type == SYS_RES_MEMORY && !pci_memen(dev)) { 2417126258Smlaier cmd = pci_read_config(dev, PCIR_COMMAND, 2); 2418241913Sglebius cmd |= PCIM_CMD_MEMEN; 2419241913Sglebius pci_write_config(dev, PCIR_COMMAND, cmd, 2); 2420223637Sbz } 2421126258Smlaier } else { 2422145836Smlaier if (type == SYS_RES_IOPORT && !pci_porten(dev)) 2423240233Sglebius return (barlen); 2424126258Smlaier if (type == SYS_RES_MEMORY && !pci_memen(dev)) 2425126258Smlaier return (barlen); 2426126258Smlaier } 2427126258Smlaier 2428126258Smlaier count = 1 << mapsize; 2429126258Smlaier if (base == 0 || base == pci_mapbase(testval)) { 2430126258Smlaier start = 0; /* Let the parent decide. */ 2431126258Smlaier end = ~0ULL; 2432126258Smlaier } else { 2433126258Smlaier start = base; 2434126258Smlaier end = base + (1 << mapsize) - 1; 2435240233Sglebius } 2436126258Smlaier resource_list_add(rl, type, reg, start, end, count); 2437126258Smlaier 2438126258Smlaier /* 2439240233Sglebius * Try to allocate the resource for this BAR from our parent 2440240233Sglebius * so that this resource range is already reserved. The 2441126258Smlaier * driver for this device will later inherit this resource in 2442126258Smlaier * pci_alloc_resource(). 2443223637Sbz */ 2444126258Smlaier res = resource_list_alloc(rl, bus, dev, type, ®, start, end, count, 2445126258Smlaier prefetch ? RF_PREFETCHABLE : 0); 2446126258Smlaier if (res == NULL) { 2447240233Sglebius /* 2448240233Sglebius * If the allocation fails, clear the BAR and delete 2449223637Sbz * the resource list entry to force 2450126258Smlaier * pci_alloc_resource() to allocate resources from the 2451240233Sglebius * parent. 2452240233Sglebius */ 2453240233Sglebius resource_list_delete(rl, type, reg); 2454132280Smlaier start = 0; 2455240233Sglebius } else { 2456240233Sglebius start = rman_get_start(res); 2457240233Sglebius rman_set_device(res, bus); 2458223637Sbz } 2459240233Sglebius pci_write_bar(dev, reg, start); 2460223637Sbz return (barlen); 2461240233Sglebius} 2462240233Sglebius 2463126258Smlaier/* 2464240233Sglebius * For ATA devices we need to decide early what addressing mode to use. 2465171168Smlaier * Legacy demands that the primary and secondary ATA ports sits on the 2466171168Smlaier * same addresses that old ISA hardware did. This dictates that we use 2467126258Smlaier * those addresses and ignore the BAR's if we cannot set PCI native 2468171168Smlaier * addressing mode. 2469178888Sjulian */ 2470171168Smlaierstatic void 2471126258Smlaierpci_ata_maps(device_t bus, device_t dev, struct resource_list *rl, int force, 2472126258Smlaier uint32_t prefetchmask) 2473171168Smlaier{ 2474171168Smlaier struct resource *r; 2475171168Smlaier int rid, type, progif; 2476126258Smlaier#if 0 2477145836Smlaier /* if this device supports PCI native addressing use it */ 2478126258Smlaier progif = pci_read_config(dev, PCIR_PROGIF, 1); 2479126258Smlaier if ((progif & 0x8a) == 0x8a) { 2480126258Smlaier if (pci_mapbase(pci_read_config(dev, PCIR_BAR(0), 4)) && 2481126258Smlaier pci_mapbase(pci_read_config(dev, PCIR_BAR(2), 4))) { 2482240233Sglebius printf("Trying ATA native PCI addressing mode\n"); 2483126258Smlaier pci_write_config(dev, PCIR_PROGIF, progif | 0x05, 1); 2484126258Smlaier } 2485126258Smlaier } 2486126258Smlaier#endif 2487240233Sglebius progif = pci_read_config(dev, PCIR_PROGIF, 1); 2488126258Smlaier type = SYS_RES_IOPORT; 2489126258Smlaier if (progif & PCIP_STORAGE_IDE_MODEPRIM) { 2490126258Smlaier pci_add_map(bus, dev, PCIR_BAR(0), rl, force, 2491240233Sglebius prefetchmask & (1 << 0)); 2492240233Sglebius pci_add_map(bus, dev, PCIR_BAR(1), rl, force, 2493240233Sglebius prefetchmask & (1 << 1)); 2494240233Sglebius } else { 2495126258Smlaier rid = PCIR_BAR(0); 2496126258Smlaier resource_list_add(rl, type, rid, 0x1f0, 0x1f7, 8); 2497126258Smlaier r = resource_list_alloc(rl, bus, dev, type, &rid, 0x1f0, 0x1f7, 2498126258Smlaier 8, 0); 2499126258Smlaier rman_set_device(r, bus); 2500126258Smlaier rid = PCIR_BAR(1); 2501126258Smlaier resource_list_add(rl, type, rid, 0x3f6, 0x3f6, 1); 2502126258Smlaier r = resource_list_alloc(rl, bus, dev, type, &rid, 0x3f6, 0x3f6, 2503126258Smlaier 1, 0); 2504126258Smlaier rman_set_device(r, bus); 2505126258Smlaier } 2506126258Smlaier if (progif & PCIP_STORAGE_IDE_MODESEC) { 2507126258Smlaier pci_add_map(bus, dev, PCIR_BAR(2), rl, force, 2508126258Smlaier prefetchmask & (1 << 2)); 2509126258Smlaier pci_add_map(bus, dev, PCIR_BAR(3), rl, force, 2510126258Smlaier prefetchmask & (1 << 3)); 2511126258Smlaier } else { 2512126258Smlaier rid = PCIR_BAR(2); 2513126258Smlaier resource_list_add(rl, type, rid, 0x170, 0x177, 8); 2514126258Smlaier r = resource_list_alloc(rl, bus, dev, type, &rid, 0x170, 0x177, 2515126258Smlaier 8, 0); 2516126258Smlaier rman_set_device(r, bus); 2517126258Smlaier rid = PCIR_BAR(3); 2518126258Smlaier resource_list_add(rl, type, rid, 0x376, 0x376, 1); 2519126258Smlaier r = resource_list_alloc(rl, bus, dev, type, &rid, 0x376, 0x376, 2520126258Smlaier 1, 0); 2521126258Smlaier rman_set_device(r, bus); 2522126258Smlaier } 2523126258Smlaier pci_add_map(bus, dev, PCIR_BAR(4), rl, force, 2524126258Smlaier prefetchmask & (1 << 4)); 2525126258Smlaier pci_add_map(bus, dev, PCIR_BAR(5), rl, force, 2526126258Smlaier prefetchmask & (1 << 5)); 2527126258Smlaier} 2528126258Smlaier 2529126258Smlaierstatic void 2530126258Smlaierpci_assign_interrupt(device_t bus, device_t dev, int force_route) 2531126258Smlaier{ 2532126258Smlaier struct pci_devinfo *dinfo = device_get_ivars(dev); 2533126258Smlaier pcicfgregs *cfg = &dinfo->cfg; 2534126258Smlaier char tunable_name[64]; 2535126258Smlaier int irq; 2536126258Smlaier 2537126258Smlaier /* Has to have an intpin to have an interrupt. */ 2538126258Smlaier if (cfg->intpin == 0) 2539126258Smlaier return; 2540126258Smlaier 2541126258Smlaier /* Let the user override the IRQ with a tunable. */ 2542126258Smlaier irq = PCI_INVALID_IRQ; 2543223637Sbz snprintf(tunable_name, sizeof(tunable_name), 2544223637Sbz "hw.pci%d.%d.%d.INT%c.irq", 2545223637Sbz cfg->domain, cfg->bus, cfg->slot, cfg->intpin + 'A' - 1); 2546126258Smlaier if (TUNABLE_INT_FETCH(tunable_name, &irq) && (irq >= 255 || irq <= 0)) 2547223637Sbz irq = PCI_INVALID_IRQ; 2548223637Sbz 2549223637Sbz /* 2550223637Sbz * If we didn't get an IRQ via the tunable, then we either use the 2551223637Sbz * IRQ value in the intline register or we ask the bus to route an 2552223637Sbz * interrupt for us. If force_route is true, then we only use the 2553223637Sbz * value in the intline register if the bus was unable to assign an 2554223637Sbz * IRQ. 2555223637Sbz */ 2556223637Sbz if (!PCI_INTERRUPT_VALID(irq)) { 2557223637Sbz if (!PCI_INTERRUPT_VALID(cfg->intline) || force_route) 2558223637Sbz irq = PCI_ASSIGN_INTERRUPT(bus, dev); 2559223637Sbz if (!PCI_INTERRUPT_VALID(irq)) 2560223637Sbz irq = cfg->intline; 2561223637Sbz } 2562223637Sbz 2563223637Sbz /* If after all that we don't have an IRQ, just bail. */ 2564223637Sbz if (!PCI_INTERRUPT_VALID(irq)) 2565223637Sbz return; 2566223637Sbz 2567223637Sbz /* Update the config register if it changed. */ 2568223637Sbz if (irq != cfg->intline) { 2569223637Sbz cfg->intline = irq; 2570223637Sbz pci_write_config(dev, PCIR_INTLINE, irq, 1); 2571223637Sbz } 2572223637Sbz 2573223637Sbz /* Add this IRQ as rid 0 interrupt resource. */ 2574223637Sbz resource_list_add(&dinfo->resources, SYS_RES_IRQ, 0, irq, irq, 1); 2575223637Sbz} 2576223637Sbz 2577223637Sbzvoid 2578223637Sbzpci_add_resources(device_t bus, device_t dev, int force, uint32_t prefetchmask) 2579223637Sbz{ 2580223637Sbz struct pci_devinfo *dinfo = device_get_ivars(dev); 2581240233Sglebius pcicfgregs *cfg = &dinfo->cfg; 2582126258Smlaier struct resource_list *rl = &dinfo->resources; 2583126258Smlaier struct pci_quirk *q; 2584126258Smlaier int i; 2585126258Smlaier 2586126258Smlaier /* ATA devices needs special map treatment */ 2587126258Smlaier if ((pci_get_class(dev) == PCIC_STORAGE) && 2588126258Smlaier (pci_get_subclass(dev) == PCIS_STORAGE_IDE) && 2589126258Smlaier ((pci_get_progif(dev) & PCIP_STORAGE_IDE_MASTERDEV) || 2590126258Smlaier (!pci_read_config(dev, PCIR_BAR(0), 4) && 2591126258Smlaier !pci_read_config(dev, PCIR_BAR(2), 4))) ) 2592126258Smlaier pci_ata_maps(bus, dev, rl, force, prefetchmask); 2593126258Smlaier else 2594126258Smlaier for (i = 0; i < cfg->nummaps;) 2595126258Smlaier i += pci_add_map(bus, dev, PCIR_BAR(i), rl, force, 2596126258Smlaier prefetchmask & (1 << i)); 2597126258Smlaier 2598126258Smlaier /* 2599126258Smlaier * Add additional, quirked resources. 2600126258Smlaier */ 2601126258Smlaier for (q = &pci_quirks[0]; q->devid; q++) { 2602126258Smlaier if (q->devid == ((cfg->device << 16) | cfg->vendor) 2603126258Smlaier && q->type == PCI_QUIRK_MAP_REG) 2604126258Smlaier pci_add_map(bus, dev, q->arg1, rl, force, 0); 2605126258Smlaier } 2606126258Smlaier 2607126258Smlaier if (cfg->intpin > 0 && PCI_INTERRUPT_VALID(cfg->intline)) { 2608126258Smlaier#ifdef __PCI_REROUTE_INTERRUPT 2609126258Smlaier /* 2610126258Smlaier * Try to re-route interrupts. Sometimes the BIOS or 2611126258Smlaier * firmware may leave bogus values in these registers. 2612126258Smlaier * If the re-route fails, then just stick with what we 2613126258Smlaier * have. 2614126258Smlaier */ 2615126258Smlaier pci_assign_interrupt(bus, dev, 1); 2616240233Sglebius#else 2617126258Smlaier pci_assign_interrupt(bus, dev, 0); 2618126258Smlaier#endif 2619126258Smlaier } 2620126258Smlaier} 2621126258Smlaier 2622126258Smlaiervoid 2623126258Smlaierpci_add_children(device_t dev, int domain, int busno, size_t dinfo_size) 2624240233Sglebius{ 2625126258Smlaier#define REG(n, w) PCIB_READ_CONFIG(pcib, busno, s, f, n, w) 2626126258Smlaier device_t pcib = device_get_parent(dev); 2627126258Smlaier struct pci_devinfo *dinfo; 2628126258Smlaier int maxslots; 2629126258Smlaier int s, f, pcifunchigh; 2630126258Smlaier uint8_t hdrtype; 2631126258Smlaier 2632223637Sbz KASSERT(dinfo_size >= sizeof(struct pci_devinfo), 2633240233Sglebius ("dinfo_size too small")); 2634171168Smlaier maxslots = PCIB_MAXSLOTS(pcib); 2635171168Smlaier for (s = 0; s <= maxslots; s++) { 2636240233Sglebius pcifunchigh = 0; 2637171168Smlaier f = 0; 2638126258Smlaier DELAY(1); 2639126258Smlaier hdrtype = REG(PCIR_HDRTYPE, 1); 2640126258Smlaier if ((hdrtype & PCIM_HDRTYPE) > PCI_MAXHDRTYPE) 2641126258Smlaier continue; 2642126258Smlaier if (hdrtype & PCIM_MFDEV) 2643240233Sglebius pcifunchigh = PCI_FUNCMAX; 2644126258Smlaier for (f = 0; f <= pcifunchigh; f++) { 2645126258Smlaier dinfo = pci_read_device(pcib, domain, busno, s, f, 2646240233Sglebius dinfo_size); 2647126258Smlaier if (dinfo != NULL) { 2648240233Sglebius pci_add_child(dev, dinfo); 2649240233Sglebius } 2650240233Sglebius } 2651240233Sglebius } 2652240233Sglebius#undef REG 2653126258Smlaier} 2654126258Smlaier 2655126258Smlaiervoid 2656240641Sglebiuspci_add_child(device_t bus, struct pci_devinfo *dinfo) 2657240641Sglebius{ 2658240641Sglebius dinfo->cfg.dev = device_add_child(bus, NULL, -1); 2659240641Sglebius device_set_ivars(dinfo->cfg.dev, dinfo); 2660240641Sglebius resource_list_init(&dinfo->resources); 2661240641Sglebius pci_cfg_save(dinfo->cfg.dev, dinfo, 0); 2662240641Sglebius pci_cfg_restore(dinfo->cfg.dev, dinfo); 2663240641Sglebius pci_print_verbose(dinfo); 2664240641Sglebius pci_add_resources(bus, dinfo->cfg.dev, 0, 0); 2665240641Sglebius} 2666240641Sglebius 2667240641Sglebiusstatic int 2668240641Sglebiuspci_probe(device_t dev) 2669240641Sglebius{ 2670240641Sglebius 2671240641Sglebius device_set_desc(dev, "PCI bus"); 2672240641Sglebius 2673240641Sglebius /* Allow other subclasses to override this driver. */ 2674240641Sglebius return (BUS_PROBE_GENERIC); 2675240641Sglebius} 2676223637Sbz 2677240641Sglebiusstatic int 2678240641Sglebiuspci_attach(device_t dev) 2679240641Sglebius{ 2680145836Smlaier int busno, domain; 2681145836Smlaier 2682126258Smlaier /* 2683240233Sglebius * Since there can be multiple independantly numbered PCI 2684240233Sglebius * busses on systems with multiple PCI domains, we can't use 2685171168Smlaier * the unit number to decide which bus we are probing. We ask 2686171168Smlaier * the parent pcib what our domain and bus numbers are. 2687240641Sglebius */ 2688240641Sglebius domain = pcib_get_domain(dev); 2689240641Sglebius busno = pcib_get_bus(dev); 2690145836Smlaier if (bootverbose) 2691145836Smlaier device_printf(dev, "domain=%d, physical bus=%d\n", 2692145836Smlaier domain, busno); 2693145836Smlaier pci_add_children(dev, domain, busno, sizeof(struct pci_devinfo)); 2694240641Sglebius return (bus_generic_attach(dev)); 2695145836Smlaier} 2696145836Smlaier 2697145836Smlaierint 2698240641Sglebiuspci_suspend(device_t dev) 2699240641Sglebius{ 2700240641Sglebius int dstate, error, i, numdevs; 2701145836Smlaier device_t acpi_dev, child, *devlist; 2702145836Smlaier struct pci_devinfo *dinfo; 2703145836Smlaier 2704145836Smlaier /* 2705145836Smlaier * Save the PCI configuration space for each child and set the 2706145836Smlaier * device in the appropriate power state for this sleep state. 2707145836Smlaier */ 2708145836Smlaier acpi_dev = NULL; 2709145836Smlaier if (pci_do_power_resume) 2710145836Smlaier acpi_dev = devclass_get_device(devclass_find("acpi"), 0); 2711126258Smlaier if ((error = device_get_children(dev, &devlist, &numdevs)) != 0) 2712171168Smlaier return (error); 2713240641Sglebius for (i = 0; i < numdevs; i++) { 2714240641Sglebius child = devlist[i]; 2715240641Sglebius dinfo = (struct pci_devinfo *) device_get_ivars(child); 2716145836Smlaier pci_cfg_save(child, dinfo, 0); 2717145836Smlaier } 2718240641Sglebius 2719171168Smlaier /* Suspend devices before potentially powering them down. */ 2720145836Smlaier error = bus_generic_suspend(dev); 2721240233Sglebius if (error) { 2722240233Sglebius free(devlist, M_TEMP); 2723145836Smlaier return (error); 2724145836Smlaier } 2725145836Smlaier 2726240641Sglebius /* 2727240641Sglebius * Always set the device to D3. If ACPI suggests a different 2728240641Sglebius * power state, use it instead. If ACPI is not present, the 2729240641Sglebius * firmware is responsible for managing device power. Skip 2730240641Sglebius * children who aren't attached since they are powered down 2731240641Sglebius * separately. Only manage type 0 devices for now. 2732240641Sglebius */ 2733240641Sglebius for (i = 0; acpi_dev && i < numdevs; i++) { 2734240641Sglebius child = devlist[i]; 2735240641Sglebius dinfo = (struct pci_devinfo *) device_get_ivars(child); 2736240641Sglebius if (device_is_attached(child) && dinfo->cfg.hdrtype == 0) { 2737240641Sglebius dstate = PCI_POWERSTATE_D3; 2738240641Sglebius ACPI_PWR_FOR_SLEEP(acpi_dev, child, &dstate); 2739240641Sglebius pci_set_powerstate(child, dstate); 2740240641Sglebius } 2741240641Sglebius } 2742240641Sglebius free(devlist, M_TEMP); 2743171168Smlaier return (0); 2744171168Smlaier} 2745240641Sglebius 2746145836Smlaierint 2747145836Smlaierpci_resume(device_t dev) 2748145836Smlaier{ 2749145836Smlaier int i, numdevs, error; 2750145836Smlaier device_t acpi_dev, child, *devlist; 2751145836Smlaier struct pci_devinfo *dinfo; 2752145836Smlaier 2753145836Smlaier /* 2754145836Smlaier * Set each child to D0 and restore its PCI configuration space. 2755145836Smlaier */ 2756145836Smlaier acpi_dev = NULL; 2757145836Smlaier if (pci_do_power_resume) 2758145836Smlaier acpi_dev = devclass_get_device(devclass_find("acpi"), 0); 2759240641Sglebius if ((error = device_get_children(dev, &devlist, &numdevs)) != 0) 2760240641Sglebius return (error); 2761240641Sglebius for (i = 0; i < numdevs; i++) { 2762145836Smlaier /* 2763171168Smlaier * Notify ACPI we're going to D0 but ignore the result. If 2764171168Smlaier * ACPI is not present, the firmware is responsible for 2765145836Smlaier * managing device power. Only manage type 0 devices for now. 2766145836Smlaier */ 2767126258Smlaier child = devlist[i]; 2768126258Smlaier dinfo = (struct pci_devinfo *) device_get_ivars(child); 2769126258Smlaier if (acpi_dev && device_is_attached(child) && 2770126258Smlaier dinfo->cfg.hdrtype == 0) { 2771126258Smlaier ACPI_PWR_FOR_SLEEP(acpi_dev, child, NULL); 2772126258Smlaier pci_set_powerstate(child, PCI_POWERSTATE_D0); 2773126258Smlaier } 2774126258Smlaier 2775126258Smlaier /* Now the device is powered up, restore its config space. */ 2776126258Smlaier pci_cfg_restore(child, dinfo); 2777126258Smlaier } 2778126258Smlaier free(devlist, M_TEMP); 2779126258Smlaier return (bus_generic_resume(dev)); 2780126258Smlaier} 2781126258Smlaier 2782126258Smlaierstatic void 2783126258Smlaierpci_load_vendor_data(void) 2784126258Smlaier{ 2785126258Smlaier caddr_t vendordata, info; 2786126258Smlaier 2787126258Smlaier if ((vendordata = preload_search_by_type("pci_vendor_data")) != NULL) { 2788126258Smlaier info = preload_search_info(vendordata, MODINFO_ADDR); 2789126258Smlaier pci_vendordata = *(char **)info; 2790126258Smlaier info = preload_search_info(vendordata, MODINFO_SIZE); 2791126258Smlaier pci_vendordata_size = *(size_t *)info; 2792126258Smlaier /* terminate the database */ 2793130613Smlaier pci_vendordata[pci_vendordata_size] = '\n'; 2794126258Smlaier } 2795126258Smlaier} 2796126258Smlaier 2797126258Smlaiervoid 2798126258Smlaierpci_driver_added(device_t dev, driver_t *driver) 2799126258Smlaier{ 2800126258Smlaier int numdevs; 2801126258Smlaier device_t *devlist; 2802126258Smlaier device_t child; 2803126258Smlaier struct pci_devinfo *dinfo; 2804126258Smlaier int i; 2805126258Smlaier 2806126258Smlaier if (bootverbose) 2807126258Smlaier device_printf(dev, "driver added\n"); 2808126258Smlaier DEVICE_IDENTIFY(driver, dev); 2809126258Smlaier if (device_get_children(dev, &devlist, &numdevs) != 0) 2810126258Smlaier return; 2811126258Smlaier for (i = 0; i < numdevs; i++) { 2812126258Smlaier child = devlist[i]; 2813126258Smlaier if (device_get_state(child) != DS_NOTPRESENT) 2814126258Smlaier continue; 2815126258Smlaier dinfo = device_get_ivars(child); 2816126258Smlaier pci_print_verbose(dinfo); 2817126258Smlaier if (bootverbose) 2818126258Smlaier printf("pci%d:%d:%d:%d: reprobing on driver added\n", 2819126258Smlaier dinfo->cfg.domain, dinfo->cfg.bus, dinfo->cfg.slot, 2820126258Smlaier dinfo->cfg.func); 2821126258Smlaier pci_cfg_restore(child, dinfo); 2822126258Smlaier if (device_probe_and_attach(child) != 0) 2823126258Smlaier pci_cfg_save(child, dinfo, 1); 2824126258Smlaier } 2825240233Sglebius free(devlist, M_TEMP); 2826126258Smlaier} 2827126258Smlaier 2828126258Smlaierint 2829126261Smlaierpci_setup_intr(device_t dev, device_t child, struct resource *irq, int flags, 2830126258Smlaier driver_filter_t *filter, driver_intr_t *intr, void *arg, void **cookiep) 2831126258Smlaier{ 2832171168Smlaier struct pci_devinfo *dinfo; 2833171168Smlaier struct msix_table_entry *mte; 2834223637Sbz struct msix_vector *mv; 2835130613Smlaier uint64_t addr; 2836126258Smlaier uint32_t data; 2837171168Smlaier void *cookie; 2838171168Smlaier int error, rid; 2839126258Smlaier 2840126258Smlaier error = bus_generic_setup_intr(dev, child, irq, flags, filter, intr, 2841181803Sbz arg, &cookie); 2842126258Smlaier if (error) 2843126258Smlaier return (error); 2844171168Smlaier 2845171168Smlaier /* If this is not a direct child, just bail out. */ 2846126258Smlaier if (device_get_parent(child) != dev) { 2847126258Smlaier *cookiep = cookie; 2848181803Sbz return(0); 2849126258Smlaier } 2850126258Smlaier 2851171168Smlaier rid = rman_get_rid(irq); 2852126258Smlaier if (rid == 0) { 2853126258Smlaier /* Make sure that INTx is enabled */ 2854126258Smlaier pci_clear_command_bit(dev, child, PCIM_CMD_INTxDIS); 2855126258Smlaier } else { 2856126258Smlaier /* 2857126258Smlaier * Check to see if the interrupt is MSI or MSI-X. 2858126258Smlaier * Ask our parent to map the MSI and give 2859126258Smlaier * us the address and data register values. 2860126258Smlaier * If we fail for some reason, teardown the 2861126258Smlaier * interrupt handler. 2862126258Smlaier */ 2863126258Smlaier dinfo = device_get_ivars(child); 2864126258Smlaier if (dinfo->cfg.msi.msi_alloc > 0) { 2865130613Smlaier if (dinfo->cfg.msi.msi_addr == 0) { 2866145836Smlaier KASSERT(dinfo->cfg.msi.msi_handlers == 0, 2867126258Smlaier ("MSI has handlers, but vectors not mapped")); 2868240233Sglebius error = PCIB_MAP_MSI(device_get_parent(dev), 2869240233Sglebius child, rman_get_start(irq), &addr, &data); 2870126261Smlaier if (error) 2871240233Sglebius goto bad; 2872222488Srwatson dinfo->cfg.msi.msi_addr = addr; 2873240233Sglebius dinfo->cfg.msi.msi_data = data; 2874222488Srwatson pci_enable_msi(child, addr, data); 2875171168Smlaier } 2876126261Smlaier dinfo->cfg.msi.msi_handlers++; 2877126258Smlaier } else { 2878145836Smlaier KASSERT(dinfo->cfg.msix.msix_alloc > 0, 2879126258Smlaier ("No MSI or MSI-X interrupts allocated")); 2880126258Smlaier KASSERT(rid <= dinfo->cfg.msix.msix_table_len, 2881240233Sglebius ("MSI-X index too high")); 2882240233Sglebius mte = &dinfo->cfg.msix.msix_table[rid - 1]; 2883126261Smlaier KASSERT(mte->mte_vector != 0, ("no message vector")); 2884240233Sglebius mv = &dinfo->cfg.msix.msix_vectors[mte->mte_vector - 1]; 2885222488Srwatson KASSERT(mv->mv_irq == rman_get_start(irq), 2886240233Sglebius ("IRQ mismatch")); 2887222488Srwatson if (mv->mv_address == 0) { 2888171168Smlaier KASSERT(mte->mte_handlers == 0, 2889126261Smlaier ("MSI-X table entry has handlers, but vector not mapped")); 2890126258Smlaier error = PCIB_MAP_MSI(device_get_parent(dev), 2891126258Smlaier child, rman_get_start(irq), &addr, &data); 2892126258Smlaier if (error) 2893126258Smlaier goto bad; 2894171168Smlaier mv->mv_address = addr; 2895126258Smlaier mv->mv_data = data; 2896222488Srwatson } 2897183606Sbz if (mte->mte_handlers == 0) { 2898183606Sbz pci_enable_msix(child, rid - 1, mv->mv_address, 2899222488Srwatson mv->mv_data); 2900240233Sglebius pci_unmask_msix(child, rid - 1); 2901126258Smlaier } 2902126258Smlaier mte->mte_handlers++; 2903126258Smlaier } 2904240233Sglebius 2905126258Smlaier /* Make sure that INTx is disabled if we are using MSI/MSIX */ 2906126258Smlaier pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS); 2907126258Smlaier bad: 2908126258Smlaier if (error) { 2909126258Smlaier (void)bus_generic_teardown_intr(dev, child, irq, 2910126258Smlaier cookie); 2911126258Smlaier return (error); 2912126258Smlaier } 2913126258Smlaier } 2914126258Smlaier *cookiep = cookie; 2915126258Smlaier return (0); 2916126258Smlaier} 2917126258Smlaier 2918126258Smlaierint 2919126258Smlaierpci_teardown_intr(device_t dev, device_t child, struct resource *irq, 2920126258Smlaier void *cookie) 2921126258Smlaier{ 2922126258Smlaier struct msix_table_entry *mte; 2923126258Smlaier struct resource_list_entry *rle; 2924126258Smlaier struct pci_devinfo *dinfo; 2925126258Smlaier int error, rid; 2926126258Smlaier 2927126258Smlaier if (irq == NULL || !(rman_get_flags(irq) & RF_ACTIVE)) 2928126258Smlaier return (EINVAL); 2929126258Smlaier 2930126258Smlaier /* If this isn't a direct child, just bail out */ 2931130613Smlaier if (device_get_parent(child) != dev) 2932126258Smlaier return(bus_generic_teardown_intr(dev, child, irq, cookie)); 2933126258Smlaier 2934126258Smlaier rid = rman_get_rid(irq); 2935126258Smlaier if (rid == 0) { 2936126258Smlaier /* Mask INTx */ 2937126258Smlaier pci_set_command_bit(dev, child, PCIM_CMD_INTxDIS); 2938130613Smlaier } else { 2939126258Smlaier /* 2940126258Smlaier * Check to see if the interrupt is MSI or MSI-X. If so, 2941126258Smlaier * decrement the appropriate handlers count and mask the 2942126258Smlaier * MSI-X message, or disable MSI messages if the count 2943126258Smlaier * drops to 0. 2944240233Sglebius */ 2945126258Smlaier dinfo = device_get_ivars(child); 2946126258Smlaier rle = resource_list_find(&dinfo->resources, SYS_RES_IRQ, rid); 2947126258Smlaier if (rle->res != irq) 2948126258Smlaier return (EINVAL); 2949126258Smlaier if (dinfo->cfg.msi.msi_alloc > 0) { 2950181803Sbz KASSERT(rid <= dinfo->cfg.msi.msi_alloc, 2951126258Smlaier ("MSI-X index too high")); 2952126258Smlaier if (dinfo->cfg.msi.msi_handlers == 0) 2953126258Smlaier return (EINVAL); 2954126258Smlaier dinfo->cfg.msi.msi_handlers--; 2955126258Smlaier if (dinfo->cfg.msi.msi_handlers == 0) 2956126258Smlaier pci_disable_msi(child); 2957126258Smlaier } else { 2958126258Smlaier KASSERT(dinfo->cfg.msix.msix_alloc > 0, 2959126258Smlaier ("No MSI or MSI-X interrupts allocated")); 2960126258Smlaier KASSERT(rid <= dinfo->cfg.msix.msix_table_len, 2961126258Smlaier ("MSI-X index too high")); 2962126258Smlaier mte = &dinfo->cfg.msix.msix_table[rid - 1]; 2963126258Smlaier if (mte->mte_handlers == 0) 2964126258Smlaier return (EINVAL); 2965126258Smlaier mte->mte_handlers--; 2966126258Smlaier if (mte->mte_handlers == 0) 2967126258Smlaier pci_mask_msix(child, rid - 1); 2968145030Sglebius } 2969130613Smlaier } 2970126258Smlaier error = bus_generic_teardown_intr(dev, child, irq, cookie); 2971126258Smlaier if (rid > 0) 2972126258Smlaier KASSERT(error == 0, 2973126258Smlaier ("%s: generic teardown failed for MSI/MSI-X", __func__)); 2974126258Smlaier return (error); 2975126258Smlaier} 2976130613Smlaier 2977126258Smlaierint 2978126258Smlaierpci_print_child(device_t dev, device_t child) 2979126258Smlaier{ 2980126258Smlaier struct pci_devinfo *dinfo; 2981126258Smlaier struct resource_list *rl; 2982240233Sglebius int retval = 0; 2983231852Sbz 2984126258Smlaier dinfo = device_get_ivars(child); 2985126258Smlaier rl = &dinfo->resources; 2986126258Smlaier 2987126258Smlaier retval += bus_print_child_header(dev, child); 2988126258Smlaier 2989126258Smlaier retval += resource_list_print_type(rl, "port", SYS_RES_IOPORT, "%#lx"); 2990126258Smlaier retval += resource_list_print_type(rl, "mem", SYS_RES_MEMORY, "%#lx"); 2991126258Smlaier retval += resource_list_print_type(rl, "irq", SYS_RES_IRQ, "%ld"); 2992126258Smlaier if (device_get_flags(dev)) 2993126258Smlaier retval += printf(" flags %#x", device_get_flags(dev)); 2994223637Sbz 2995181803Sbz retval += printf(" at device %d.%d", pci_get_slot(child), 2996126258Smlaier pci_get_function(child)); 2997126258Smlaier 2998126258Smlaier retval += bus_print_child_footer(dev, child); 2999126258Smlaier 3000126258Smlaier return (retval); 3001126258Smlaier} 3002126258Smlaier 3003126258Smlaierstatic struct 3004126258Smlaier{ 3005126258Smlaier int class; 3006231852Sbz int subclass; 3007126258Smlaier char *desc; 3008126258Smlaier} pci_nomatch_tab[] = { 3009126258Smlaier {PCIC_OLD, -1, "old"}, 3010126258Smlaier {PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"}, 3011126258Smlaier {PCIC_OLD, PCIS_OLD_VGA, "VGA-compatible display device"}, 3012126258Smlaier {PCIC_STORAGE, -1, "mass storage"}, 3013126258Smlaier {PCIC_STORAGE, PCIS_STORAGE_SCSI, "SCSI"}, 3014126258Smlaier {PCIC_STORAGE, PCIS_STORAGE_IDE, "ATA"}, 3015126258Smlaier {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, "floppy disk"}, 3016126258Smlaier {PCIC_STORAGE, PCIS_STORAGE_IPI, "IPI"}, 3017126258Smlaier {PCIC_STORAGE, PCIS_STORAGE_RAID, "RAID"}, 3018231852Sbz {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"}, 3019126258Smlaier {PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"}, 3020126258Smlaier {PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"}, 3021126258Smlaier {PCIC_NETWORK, -1, "network"}, 3022126258Smlaier {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"}, 3023126258Smlaier {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"}, 3024126258Smlaier {PCIC_NETWORK, PCIS_NETWORK_FDDI, "fddi"}, 3025126258Smlaier {PCIC_NETWORK, PCIS_NETWORK_ATM, "ATM"}, 3026181803Sbz {PCIC_NETWORK, PCIS_NETWORK_ISDN, "ISDN"}, 3027126258Smlaier {PCIC_DISPLAY, -1, "display"}, 3028126258Smlaier {PCIC_DISPLAY, PCIS_DISPLAY_VGA, "VGA"}, 3029126258Smlaier {PCIC_DISPLAY, PCIS_DISPLAY_XGA, "XGA"}, 3030126258Smlaier {PCIC_DISPLAY, PCIS_DISPLAY_3D, "3D"}, 3031126258Smlaier {PCIC_MULTIMEDIA, -1, "multimedia"}, 3032126258Smlaier {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, "video"}, 3033126258Smlaier {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, "audio"}, 3034240233Sglebius {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, "telephony"}, 3035223637Sbz {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, "HDA"}, 3036223637Sbz {PCIC_MEMORY, -1, "memory"}, 3037223637Sbz {PCIC_MEMORY, PCIS_MEMORY_RAM, "RAM"}, 3038223637Sbz {PCIC_MEMORY, PCIS_MEMORY_FLASH, "flash"}, 3039223637Sbz {PCIC_BRIDGE, -1, "bridge"}, 3040223637Sbz {PCIC_BRIDGE, PCIS_BRIDGE_HOST, "HOST-PCI"}, 3041223637Sbz {PCIC_BRIDGE, PCIS_BRIDGE_ISA, "PCI-ISA"}, 3042223637Sbz {PCIC_BRIDGE, PCIS_BRIDGE_EISA, "PCI-EISA"}, 3043223637Sbz {PCIC_BRIDGE, PCIS_BRIDGE_MCA, "PCI-MCA"}, 3044223637Sbz {PCIC_BRIDGE, PCIS_BRIDGE_PCI, "PCI-PCI"}, 3045223637Sbz {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, "PCI-PCMCIA"}, 3046223637Sbz {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, "PCI-NuBus"}, 3047223637Sbz {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, "PCI-CardBus"}, 3048223637Sbz {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, "PCI-RACEway"}, 3049223637Sbz {PCIC_SIMPLECOMM, -1, "simple comms"}, 3050223637Sbz {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, "UART"}, /* could detect 16550 */ 3051223637Sbz {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, "parallel port"}, 3052223637Sbz {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, "multiport serial"}, 3053223637Sbz {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, "generic modem"}, 3054223637Sbz {PCIC_BASEPERIPH, -1, "base peripheral"}, 3055223637Sbz {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, "interrupt controller"}, 3056223637Sbz {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, "DMA controller"}, 3057223637Sbz {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, "timer"}, 3058223637Sbz {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, "realtime clock"}, 3059223637Sbz {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, "PCI hot-plug controller"}, 3060223637Sbz {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, "SD host controller"}, 3061223637Sbz {PCIC_INPUTDEV, -1, "input device"}, 3062223637Sbz {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, "keyboard"}, 3063223637Sbz {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,"digitizer"}, 3064223637Sbz {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, "mouse"}, 3065223637Sbz {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, "scanner"}, 3066223637Sbz {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, "gameport"}, 3067240233Sglebius {PCIC_DOCKING, -1, "docking station"}, 3068223637Sbz {PCIC_PROCESSOR, -1, "processor"}, 3069240233Sglebius {PCIC_SERIALBUS, -1, "serial bus"}, 3070240233Sglebius {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, "FireWire"}, 3071126258Smlaier {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, "AccessBus"}, 3072130613Smlaier {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, "SSA"}, 3073240233Sglebius {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, "USB"}, 3074240233Sglebius {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, "Fibre Channel"}, 3075126258Smlaier {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, "SMBus"}, 3076126258Smlaier {PCIC_WIRELESS, -1, "wireless controller"}, 3077126258Smlaier {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, "iRDA"}, 3078130613Smlaier {PCIC_WIRELESS, PCIS_WIRELESS_IR, "IR"}, 3079223637Sbz {PCIC_WIRELESS, PCIS_WIRELESS_RF, "RF"}, 3080223637Sbz {PCIC_INTELLIIO, -1, "intelligent I/O controller"}, 3081126258Smlaier {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, "I2O"}, 3082223637Sbz {PCIC_SATCOM, -1, "satellite communication"}, 3083171168Smlaier {PCIC_SATCOM, PCIS_SATCOM_TV, "sat TV"}, 3084145836Smlaier {PCIC_SATCOM, PCIS_SATCOM_AUDIO, "sat audio"}, 3085171168Smlaier {PCIC_SATCOM, PCIS_SATCOM_VOICE, "sat voice"}, 3086223637Sbz {PCIC_SATCOM, PCIS_SATCOM_DATA, "sat data"}, 3087223637Sbz {PCIC_CRYPTO, -1, "encrypt/decrypt"}, 3088223637Sbz {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "network/computer crypto"}, 3089223637Sbz {PCIC_CRYPTO, PCIS_CRYPTO_ENTERTAIN, "entertainment crypto"}, 3090240641Sglebius {PCIC_DASP, -1, "dasp"}, 3091126258Smlaier {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, 3092240233Sglebius {0, 0, NULL} 3093223637Sbz}; 3094240233Sglebius 3095240233Sglebiusvoid 3096240233Sglebiuspci_probe_nomatch(device_t dev, device_t child) 3097240233Sglebius{ 3098240233Sglebius int i; 3099145836Smlaier char *cp, *scp, *device; 3100145836Smlaier 3101223637Sbz /* 3102223637Sbz * Look for a listing for this device in a loaded device database. 3103223637Sbz */ 3104223637Sbz if ((device = pci_describe_device(child)) != NULL) { 3105223637Sbz device_printf(dev, "<%s>", device); 3106223637Sbz free(device, M_DEVBUF); 3107223637Sbz } else { 3108223637Sbz /* 3109223637Sbz * Scan the class/subclass descriptions for a general 3110223637Sbz * description. 3111223637Sbz */ 3112223637Sbz cp = "unknown"; 3113223637Sbz scp = NULL; 3114223637Sbz for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { 3115223637Sbz if (pci_nomatch_tab[i].class == pci_get_class(child)) { 3116223637Sbz if (pci_nomatch_tab[i].subclass == -1) { 3117223637Sbz cp = pci_nomatch_tab[i].desc; 3118223637Sbz } else if (pci_nomatch_tab[i].subclass == 3119223637Sbz pci_get_subclass(child)) { 3120223637Sbz scp = pci_nomatch_tab[i].desc; 3121223637Sbz } 3122223637Sbz } 3123223637Sbz } 3124223637Sbz device_printf(dev, "<%s%s%s>", 3125223637Sbz cp ? cp : "", 3126223637Sbz ((cp != NULL) && (scp != NULL)) ? ", " : "", 3127223637Sbz scp ? scp : ""); 3128223637Sbz } 3129223637Sbz printf(" at device %d.%d (no driver attached)\n", 3130223637Sbz pci_get_slot(child), pci_get_function(child)); 3131223637Sbz pci_cfg_save(child, (struct pci_devinfo *)device_get_ivars(child), 1); 3132223637Sbz return; 3133223637Sbz} 3134223637Sbz 3135223637Sbz/* 3136223637Sbz * Parse the PCI device database, if loaded, and return a pointer to a 3137223637Sbz * description of the device. 3138223637Sbz * 3139223637Sbz * The database is flat text formatted as follows: 3140223637Sbz * 3141223637Sbz * Any line not in a valid format is ignored. 3142223637Sbz * Lines are terminated with newline '\n' characters. 3143223637Sbz * 3144223637Sbz * A VENDOR line consists of the 4 digit (hex) vendor code, a TAB, then 3145223637Sbz * the vendor name. 3146223637Sbz * 3147223637Sbz * A DEVICE line is entered immediately below the corresponding VENDOR ID. 3148223637Sbz * - devices cannot be listed without a corresponding VENDOR line. 3149223637Sbz * A DEVICE line consists of a TAB, the 4 digit (hex) device code, 3150126258Smlaier * another TAB, then the device name. 3151126258Smlaier */ 3152223637Sbz 3153240233Sglebius/* 3154240641Sglebius * Assuming (ptr) points to the beginning of a line in the database, 3155240233Sglebius * return the vendor or device and description of the next entry. 3156240233Sglebius * The value of (vendor) or (device) inappropriate for the entry type 3157223637Sbz * is set to -1. Returns nonzero at the end of the database. 3158223637Sbz * 3159223637Sbz * Note that this is slightly unrobust in the face of corrupt data; 3160223637Sbz * we attempt to safeguard against this by spamming the end of the 3161223637Sbz * database with a newline when we initialise. 3162223637Sbz */ 3163223637Sbzstatic int 3164223637Sbzpci_describe_parse_line(char **ptr, int *vendor, int *device, char **desc) 3165223637Sbz{ 3166223637Sbz char *cp = *ptr; 3167223637Sbz int left; 3168289703Skp 3169223637Sbz *device = -1; 3170223637Sbz *vendor = -1; 3171223637Sbz **desc = '\0'; 3172223637Sbz for (;;) { 3173223637Sbz left = pci_vendordata_size - (cp - pci_vendordata); 3174223637Sbz if (left <= 0) { 3175223637Sbz *ptr = cp; 3176223637Sbz return(1); 3177289703Skp } 3178223637Sbz 3179223637Sbz /* vendor entry? */ 3180223637Sbz if (*cp != '\t' && 3181223637Sbz sscanf(cp, "%x\t%80[^\n]", vendor, *desc) == 2) 3182223637Sbz break; 3183126258Smlaier /* device entry? */ 3184223637Sbz if (*cp == '\t' && 3185223637Sbz sscanf(cp, "%x\t%80[^\n]", device, *desc) == 2) 3186223637Sbz break; 3187223637Sbz 3188223637Sbz /* skip to next line */ 3189223637Sbz while (*cp != '\n' && left > 0) { 3190223637Sbz cp++; 3191289703Skp left--; 3192223637Sbz } 3193223637Sbz if (*cp == '\n') { 3194223637Sbz cp++; 3195223637Sbz left--; 3196223637Sbz } 3197223637Sbz } 3198223637Sbz /* skip to next line */ 3199223637Sbz while (*cp != '\n' && left > 0) { 3200223637Sbz cp++; 3201289703Skp left--; 3202223637Sbz } 3203223637Sbz if (*cp == '\n' && left > 0) 3204223637Sbz cp++; 3205223637Sbz *ptr = cp; 3206223637Sbz return(0); 3207223637Sbz} 3208223637Sbz 3209223637Sbzstatic char * 3210223637Sbzpci_describe_device(device_t dev) 3211223637Sbz{ 3212223637Sbz int vendor, device; 3213223637Sbz char *desc, *vp, *dp, *line; 3214223637Sbz 3215223637Sbz desc = vp = dp = NULL; 3216223637Sbz 3217223637Sbz /* 3218223637Sbz * If we have no vendor data, we can't do anything. 3219223637Sbz */ 3220223637Sbz if (pci_vendordata == NULL) 3221223637Sbz goto out; 3222223637Sbz 3223223637Sbz /* 3224223637Sbz * Scan the vendor data looking for this device 3225223637Sbz */ 3226223637Sbz line = pci_vendordata; 3227223637Sbz if ((vp = malloc(80, M_DEVBUF, M_NOWAIT)) == NULL) 3228223637Sbz goto out; 3229223637Sbz for (;;) { 3230223637Sbz if (pci_describe_parse_line(&line, &vendor, &device, &vp)) 3231223637Sbz goto out; 3232223637Sbz if (vendor == pci_get_vendor(dev)) 3233223637Sbz break; 3234223637Sbz } 3235223637Sbz if ((dp = malloc(80, M_DEVBUF, M_NOWAIT)) == NULL) 3236223637Sbz goto out; 3237223637Sbz for (;;) { 3238223637Sbz if (pci_describe_parse_line(&line, &vendor, &device, &dp)) { 3239223637Sbz *dp = 0; 3240223637Sbz break; 3241223637Sbz } 3242223637Sbz if (vendor != -1) { 3243223637Sbz *dp = 0; 3244223637Sbz break; 3245223637Sbz } 3246223637Sbz if (device == pci_get_device(dev)) 3247223637Sbz break; 3248223637Sbz } 3249223637Sbz if (dp[0] == '\0') 3250223637Sbz snprintf(dp, 80, "0x%x", pci_get_device(dev)); 3251223637Sbz if ((desc = malloc(strlen(vp) + strlen(dp) + 3, M_DEVBUF, M_NOWAIT)) != 3252223637Sbz NULL) 3253223637Sbz sprintf(desc, "%s, %s", vp, dp); 3254223637Sbz out: 3255223637Sbz if (vp != NULL) 3256223637Sbz free(vp, M_DEVBUF); 3257223637Sbz if (dp != NULL) 3258223637Sbz free(dp, M_DEVBUF); 3259223637Sbz return(desc); 3260223637Sbz} 3261223637Sbz 3262223637Sbzint 3263223637Sbzpci_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 3264223637Sbz{ 3265223637Sbz struct pci_devinfo *dinfo; 3266223637Sbz pcicfgregs *cfg; 3267223637Sbz 3268223637Sbz dinfo = device_get_ivars(child); 3269223637Sbz cfg = &dinfo->cfg; 3270223637Sbz 3271223637Sbz switch (which) { 3272223637Sbz case PCI_IVAR_ETHADDR: 3273223637Sbz /* 3274126258Smlaier * The generic accessor doesn't deal with failure, so 3275223637Sbz * we set the return value, then return an error. 3276223637Sbz */ 3277223637Sbz *((uint8_t **) result) = NULL; 3278126258Smlaier return (EINVAL); 3279126258Smlaier case PCI_IVAR_SUBVENDOR: 3280126258Smlaier *result = cfg->subvendor; 3281126258Smlaier break; 3282171168Smlaier case PCI_IVAR_SUBDEVICE: 3283126258Smlaier *result = cfg->subdevice; 3284126258Smlaier break; 3285126258Smlaier case PCI_IVAR_VENDOR: 3286126258Smlaier *result = cfg->vendor; 3287126258Smlaier break; 3288223637Sbz case PCI_IVAR_DEVICE: 3289126258Smlaier *result = cfg->device; 3290171168Smlaier break; 3291231852Sbz case PCI_IVAR_DEVID: 3292126258Smlaier *result = (cfg->device << 16) | cfg->vendor; 3293223637Sbz break; 3294126258Smlaier case PCI_IVAR_CLASS: 3295223637Sbz *result = cfg->baseclass; 3296126258Smlaier break; 3297171168Smlaier case PCI_IVAR_SUBCLASS: 3298231852Sbz *result = cfg->subclass; 3299126258Smlaier break; 3300223637Sbz case PCI_IVAR_PROGIF: 3301126258Smlaier *result = cfg->progif; 3302223637Sbz break; 3303126258Smlaier case PCI_IVAR_REVID: 3304223637Sbz *result = cfg->revid; 3305223637Sbz break; 3306223637Sbz case PCI_IVAR_INTPIN: 3307223637Sbz *result = cfg->intpin; 3308223637Sbz break; 3309223637Sbz case PCI_IVAR_IRQ: 3310171168Smlaier *result = cfg->intline; 3311126258Smlaier break; 3312126258Smlaier case PCI_IVAR_DOMAIN: 3313126258Smlaier *result = cfg->domain; 3314223637Sbz break; 3315223637Sbz case PCI_IVAR_BUS: 3316126258Smlaier *result = cfg->bus; 3317223637Sbz break; 3318171168Smlaier case PCI_IVAR_SLOT: 3319240233Sglebius *result = cfg->slot; 3320126258Smlaier break; 3321171168Smlaier case PCI_IVAR_FUNCTION: 3322126258Smlaier *result = cfg->func; 3323223637Sbz break; 3324171168Smlaier case PCI_IVAR_CMDREG: 3325240233Sglebius *result = cfg->cmdreg; 3326126258Smlaier break; 3327171168Smlaier case PCI_IVAR_CACHELNSZ: 3328126258Smlaier *result = cfg->cachelnsz; 3329223637Sbz break; 3330223637Sbz case PCI_IVAR_MINGNT: 3331126258Smlaier *result = cfg->mingnt; 3332240233Sglebius break; 3333240233Sglebius case PCI_IVAR_MAXLAT: 3334126258Smlaier *result = cfg->maxlat; 3335223637Sbz break; 3336223637Sbz case PCI_IVAR_LATTIMER: 3337223637Sbz *result = cfg->lattimer; 3338223637Sbz break; 3339126258Smlaier default: 3340126258Smlaier return (ENOENT); 3341126258Smlaier } 3342126258Smlaier return (0); 3343171168Smlaier} 3344171168Smlaier 3345126258Smlaierint 3346171168Smlaierpci_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 3347126258Smlaier{ 3348126258Smlaier struct pci_devinfo *dinfo; 3349126258Smlaier 3350126258Smlaier dinfo = device_get_ivars(child); 3351126258Smlaier 3352126258Smlaier switch (which) { 3353126258Smlaier case PCI_IVAR_INTPIN: 3354240641Sglebius dinfo->cfg.intpin = value; 3355240641Sglebius return (0); 3356240641Sglebius case PCI_IVAR_ETHADDR: 3357126258Smlaier case PCI_IVAR_SUBVENDOR: 3358240641Sglebius case PCI_IVAR_SUBDEVICE: 3359240641Sglebius case PCI_IVAR_VENDOR: 3360171168Smlaier case PCI_IVAR_DEVICE: 3361126258Smlaier case PCI_IVAR_DEVID: 3362126258Smlaier case PCI_IVAR_CLASS: 3363126258Smlaier case PCI_IVAR_SUBCLASS: 3364126258Smlaier case PCI_IVAR_PROGIF: 3365126258Smlaier case PCI_IVAR_REVID: 3366126258Smlaier case PCI_IVAR_IRQ: 3367126258Smlaier case PCI_IVAR_DOMAIN: 3368223637Sbz case PCI_IVAR_BUS: 3369126258Smlaier case PCI_IVAR_SLOT: 3370223637Sbz case PCI_IVAR_FUNCTION: 3371240233Sglebius return (EINVAL); /* disallow for now */ 3372240233Sglebius 3373126258Smlaier default: 3374126258Smlaier return (ENOENT); 3375126258Smlaier } 3376126258Smlaier} 3377126258Smlaier 3378126258Smlaier 3379126258Smlaier#include "opt_ddb.h" 3380130613Smlaier#ifdef DDB 3381223637Sbz#include <ddb/ddb.h> 3382223637Sbz#include <sys/cons.h> 3383223637Sbz 3384223637Sbz/* 3385223637Sbz * List resources based on pci map registers, used for within ddb 3386223637Sbz */ 3387223637Sbz 3388223637SbzDB_SHOW_COMMAND(pciregs, db_pci_dump) 3389223637Sbz{ 3390223637Sbz struct pci_devinfo *dinfo; 3391223637Sbz struct devlist *devlist_head; 3392126258Smlaier struct pci_conf *p; 3393223637Sbz const char *name; 3394223637Sbz int i, error, none_count; 3395126258Smlaier 3396126258Smlaier none_count = 0; 3397223637Sbz /* get the head of the device queue */ 3398223637Sbz devlist_head = &pci_devq; 3399223637Sbz 3400223637Sbz /* 3401223637Sbz * Go through the list of devices and print out devices 3402223637Sbz */ 3403223637Sbz for (error = 0, i = 0, 3404223637Sbz dinfo = STAILQ_FIRST(devlist_head); 3405126258Smlaier (dinfo != NULL) && (error == 0) && (i < pci_numdevs) && !db_pager_quit; 3406223637Sbz dinfo = STAILQ_NEXT(dinfo, pci_links), i++) { 3407223637Sbz 3408223637Sbz /* Populate pd_name and pd_unit */ 3409223637Sbz name = NULL; 3410223637Sbz if (dinfo->cfg.dev) 3411223637Sbz name = device_get_name(dinfo->cfg.dev); 3412223637Sbz 3413223637Sbz p = &dinfo->conf; 3414223637Sbz db_printf("%s%d@pci%d:%d:%d:%d:\tclass=0x%06x card=0x%08x " 3415223637Sbz "chip=0x%08x rev=0x%02x hdr=0x%02x\n", 3416223637Sbz (name && *name) ? name : "none", 3417223637Sbz (name && *name) ? (int)device_get_unit(dinfo->cfg.dev) : 3418223637Sbz none_count++, 3419223637Sbz p->pc_sel.pc_domain, p->pc_sel.pc_bus, p->pc_sel.pc_dev, 3420223637Sbz p->pc_sel.pc_func, (p->pc_class << 16) | 3421223637Sbz (p->pc_subclass << 8) | p->pc_progif, 3422223637Sbz (p->pc_subdevice << 16) | p->pc_subvendor, 3423223637Sbz (p->pc_device << 16) | p->pc_vendor, 3424223637Sbz p->pc_revid, p->pc_hdr); 3425223637Sbz } 3426223637Sbz} 3427223637Sbz#endif /* DDB */ 3428223637Sbz 3429223637Sbzstatic struct resource * 3430223637Sbzpci_alloc_map(device_t dev, device_t child, int type, int *rid, 3431240233Sglebius u_long start, u_long end, u_long count, u_int flags) 3432223637Sbz{ 3433223637Sbz struct pci_devinfo *dinfo = device_get_ivars(child); 3434223637Sbz struct resource_list *rl = &dinfo->resources; 3435126258Smlaier struct resource_list_entry *rle; 3436126258Smlaier struct resource *res; 3437223637Sbz pci_addr_t map, testval; 3438223637Sbz int mapsize; 3439126258Smlaier 3440126258Smlaier /* 3441126258Smlaier * Weed out the bogons, and figure out how large the BAR/map 3442126258Smlaier * is. Bars that read back 0 here are bogus and unimplemented. 3443126258Smlaier * Note: atapci in legacy mode are special and handled elsewhere 3444223637Sbz * in the code. If you have a atapci device in legacy mode and 3445126258Smlaier * it fails here, that other code is broken. 3446240233Sglebius */ 3447126258Smlaier res = NULL; 3448223637Sbz pci_read_bar(child, *rid, &map, &testval); 3449126258Smlaier 3450240233Sglebius /* Ignore a BAR with a base of 0. */ 3451240233Sglebius if (pci_mapbase(testval) == 0) 3452126258Smlaier goto out; 3453223637Sbz 3454223637Sbz if (PCI_BAR_MEM(testval)) { 3455223637Sbz if (type != SYS_RES_MEMORY) { 3456240233Sglebius if (bootverbose) 3457240233Sglebius device_printf(dev, 3458240233Sglebius "child %s requested type %d for rid %#x," 3459223637Sbz " but the BAR says it is an memio\n", 3460223637Sbz device_get_nameunit(child), type, *rid); 3461223637Sbz goto out; 3462223637Sbz } 3463240233Sglebius } else { 3464223637Sbz if (type != SYS_RES_IOPORT) { 3465240233Sglebius if (bootverbose) 3466223637Sbz device_printf(dev, 3467126258Smlaier "child %s requested type %d for rid %#x," 3468223637Sbz " but the BAR says it is an ioport\n", 3469223637Sbz device_get_nameunit(child), type, *rid); 3470223637Sbz goto out; 3471130613Smlaier } 3472240233Sglebius } 3473240233Sglebius 3474240233Sglebius /* 3475223637Sbz * For real BARs, we need to override the size that 3476223637Sbz * the driver requests, because that's what the BAR 3477223637Sbz * actually uses and we would otherwise have a 3478223637Sbz * situation where we might allocate the excess to 3479223637Sbz * another driver, which won't work. 3480223637Sbz */ 3481240233Sglebius mapsize = pci_mapsize(testval); 3482223637Sbz count = 1UL << mapsize; 3483223637Sbz if (RF_ALIGNMENT(flags) < mapsize) 3484223637Sbz flags = (flags & ~RF_ALIGNMENT_MASK) | RF_ALIGNMENT_LOG2(mapsize); 3485130613Smlaier if (PCI_BAR_MEM(testval) && (testval & PCIM_BAR_MEM_PREFETCH)) 3486223637Sbz flags |= RF_PREFETCHABLE; 3487240233Sglebius 3488223637Sbz /* 3489240233Sglebius * Allocate enough resource, and then write back the 3490223637Sbz * appropriate bar for that resource. 3491223637Sbz */ 3492126258Smlaier res = BUS_ALLOC_RESOURCE(device_get_parent(dev), child, type, rid, 3493240233Sglebius start, end, count, flags & ~RF_ACTIVE); 3494223637Sbz if (res == NULL) { 3495240233Sglebius device_printf(child, 3496240233Sglebius "%#lx bytes of rid %#x res %d failed (%#lx, %#lx).\n", 3497240233Sglebius count, *rid, type, start, end); 3498240233Sglebius goto out; 3499223637Sbz } 3500223637Sbz rman_set_device(res, dev); 3501223637Sbz resource_list_add(rl, type, *rid, start, end, count); 3502223637Sbz rle = resource_list_find(rl, type, *rid); 3503223637Sbz if (rle == NULL) 3504223637Sbz panic("pci_alloc_map: unexpectedly can't find resource."); 3505223637Sbz rle->res = res; 3506223637Sbz rle->start = rman_get_start(res); 3507263029Sglebius rle->end = rman_get_end(res); 3508263029Sglebius rle->count = count; 3509270574Sglebius if (bootverbose) 3510223637Sbz device_printf(child, 3511223637Sbz "Lazy allocation of %#lx bytes rid %#x type %d at %#lx\n", 3512223637Sbz count, *rid, type, rman_get_start(res)); 3513223637Sbz map = rman_get_start(res); 3514223637Sbz pci_write_bar(child, *rid, map); 3515223637Sbzout:; 3516223637Sbz return (res); 3517223637Sbz} 3518223637Sbz 3519223637Sbz 3520223637Sbzstruct resource * 3521223637Sbzpci_alloc_resource(device_t dev, device_t child, int type, int *rid, 3522223637Sbz u_long start, u_long end, u_long count, u_int flags) 3523223637Sbz{ 3524223637Sbz struct pci_devinfo *dinfo = device_get_ivars(child); 3525223637Sbz struct resource_list *rl = &dinfo->resources; 3526240233Sglebius struct resource_list_entry *rle; 3527223637Sbz struct resource *res; 3528223637Sbz pcicfgregs *cfg = &dinfo->cfg; 3529223637Sbz 3530223637Sbz if (device_get_parent(child) != dev) 3531223637Sbz return (BUS_ALLOC_RESOURCE(device_get_parent(dev), child, 3532223637Sbz type, rid, start, end, count, flags)); 3533223637Sbz 3534223637Sbz /* 3535223637Sbz * Perform lazy resource allocation 3536223637Sbz */ 3537223637Sbz switch (type) { 3538223637Sbz case SYS_RES_IRQ: 3539223637Sbz /* 3540223637Sbz * Can't alloc legacy interrupt once MSI messages have 3541223637Sbz * been allocated. 3542223637Sbz */ 3543223637Sbz if (*rid == 0 && (cfg->msi.msi_alloc > 0 || 3544223637Sbz cfg->msix.msix_alloc > 0)) 3545126258Smlaier return (NULL); 3546223637Sbz 3547126258Smlaier /* 3548126258Smlaier * If the child device doesn't have an interrupt 3549126258Smlaier * routed and is deserving of an interrupt, try to 3550223637Sbz * assign it one. 3551223637Sbz */ 3552223637Sbz if (*rid == 0 && !PCI_INTERRUPT_VALID(cfg->intline) && 3553289703Skp (cfg->intpin != 0)) 3554126258Smlaier pci_assign_interrupt(dev, child, 0); 3555223637Sbz break; 3556126258Smlaier case SYS_RES_IOPORT: 3557126258Smlaier case SYS_RES_MEMORY: 3558126258Smlaier /* Allocate resources for this BAR if needed. */ 3559126258Smlaier rle = resource_list_find(rl, type, *rid); 3560223637Sbz if (rle == NULL) { 3561223637Sbz res = pci_alloc_map(dev, child, type, rid, start, end, 3562126258Smlaier count, flags); 3563126258Smlaier if (res == NULL) 3564126258Smlaier return (NULL); 3565126258Smlaier rle = resource_list_find(rl, type, *rid); 3566126258Smlaier } 3567126258Smlaier 3568126258Smlaier /* 3569126258Smlaier * If the resource belongs to the bus, then give it to 3570126258Smlaier * the child. We need to activate it if requested 3571126258Smlaier * since the bus always allocates inactive resources. 3572126258Smlaier */ 3573126258Smlaier if (rle != NULL && rle->res != NULL && 3574126258Smlaier rman_get_device(rle->res) == dev) { 3575126258Smlaier if (bootverbose) 3576126258Smlaier device_printf(child, 3577126258Smlaier "Reserved %#lx bytes for rid %#x type %d at %#lx\n", 3578223637Sbz rman_get_size(rle->res), *rid, type, 3579223637Sbz rman_get_start(rle->res)); 3580223637Sbz rman_set_device(rle->res, child); 3581223637Sbz if ((flags & RF_ACTIVE) && 3582223637Sbz bus_activate_resource(child, type, *rid, 3583223637Sbz rle->res) != 0) 3584223637Sbz return (NULL); 3585223637Sbz return (rle->res); 3586223637Sbz } 3587223637Sbz } 3588223637Sbz return (resource_list_alloc(rl, dev, child, type, rid, 3589223637Sbz start, end, count, flags)); 3590223637Sbz} 3591223637Sbz 3592223637Sbzint 3593223637Sbzpci_release_resource(device_t dev, device_t child, int type, int rid, 3594223637Sbz struct resource *r) 3595223637Sbz{ 3596270576Sglebius int error; 3597270576Sglebius 3598270925Sglebius if (device_get_parent(child) != dev) 3599270576Sglebius return (BUS_RELEASE_RESOURCE(device_get_parent(dev), child, 3600270576Sglebius type, rid, r)); 3601270576Sglebius 3602270576Sglebius /* 3603270576Sglebius * For BARs we don't actually want to release the resource. 3604270576Sglebius * Instead, we deactivate the resource if needed and then give 3605270576Sglebius * ownership of the BAR back to the bus. 3606270576Sglebius */ 3607240233Sglebius switch (type) { 3608240233Sglebius case SYS_RES_IOPORT: 3609223637Sbz case SYS_RES_MEMORY: 3610285940Sglebius if (rman_get_device(r) != child) 3611223637Sbz return (EINVAL); 3612223637Sbz if (rman_get_flags(r) & RF_ACTIVE) { 3613223637Sbz error = bus_deactivate_resource(child, type, rid, r); 3614223637Sbz if (error) 3615223637Sbz return (error); 3616223637Sbz } 3617223637Sbz rman_set_device(r, dev); 3618126258Smlaier return (0); 3619126258Smlaier } 3620126258Smlaier return (bus_generic_rl_release_resource(dev, child, type, rid, r)); 3621130613Smlaier} 3622145836Smlaier 3623240233Sglebiusint 3624126258Smlaierpci_activate_resource(device_t dev, device_t child, int type, int rid, 3625126258Smlaier struct resource *r) 3626126258Smlaier{ 3627145836Smlaier int error; 3628223637Sbz 3629145836Smlaier error = bus_generic_activate_resource(dev, child, type, rid, r); 3630145836Smlaier if (error) 3631145836Smlaier return (error); 3632126258Smlaier 3633130613Smlaier /* Enable decoding in the command register when activating BARs. */ 3634145836Smlaier if (device_get_parent(child) == dev) { 3635240233Sglebius switch (type) { 3636223637Sbz case SYS_RES_IOPORT: 3637126258Smlaier case SYS_RES_MEMORY: 3638126258Smlaier error = PCI_ENABLE_IO(dev, child, type); 3639223637Sbz break; 3640126258Smlaier } 3641240233Sglebius } 3642240233Sglebius return (error); 3643240233Sglebius} 3644240233Sglebius 3645240233Sglebiusvoid 3646240233Sglebiuspci_delete_resource(device_t dev, device_t child, int type, int rid) 3647240233Sglebius{ 3648240233Sglebius struct pci_devinfo *dinfo; 3649240233Sglebius struct resource_list *rl; 3650240233Sglebius struct resource_list_entry *rle; 3651240233Sglebius 3652240233Sglebius if (device_get_parent(child) != dev) 3653240233Sglebius return; 3654126258Smlaier 3655240233Sglebius dinfo = device_get_ivars(child); 3656240233Sglebius rl = &dinfo->resources; 3657240233Sglebius rle = resource_list_find(rl, type, rid); 3658240233Sglebius if (rle == NULL) 3659223637Sbz return; 3660223637Sbz 3661223637Sbz if (rle->res) { 3662223637Sbz if (rman_get_device(rle->res) != dev || 3663223637Sbz rman_get_flags(rle->res) & RF_ACTIVE) { 3664240233Sglebius device_printf(dev, "delete_resource: " 3665223637Sbz "Resource still owned by child, oops. " 3666223637Sbz "(type=%d, rid=%d, addr=%lx)\n", 3667223637Sbz rle->type, rle->rid, 3668126258Smlaier rman_get_start(rle->res)); 3669240233Sglebius return; 3670223637Sbz } 3671223637Sbz 3672223637Sbz /* 3673223637Sbz * If this is a BAR, clear the BAR so it stops 3674223637Sbz * decoding before releasing the resource. 3675223637Sbz */ 3676223637Sbz switch (type) { 3677223637Sbz case SYS_RES_IOPORT: 3678223637Sbz case SYS_RES_MEMORY: 3679223637Sbz pci_write_bar(child, rid, 0); 3680223637Sbz break; 3681223637Sbz } 3682223637Sbz bus_release_resource(dev, type, rid, rle->res); 3683223637Sbz } 3684223637Sbz resource_list_delete(rl, type, rid); 3685223637Sbz} 3686223637Sbz 3687223637Sbzstruct resource_list * 3688223637Sbzpci_get_resource_list (device_t dev, device_t child) 3689223637Sbz{ 3690223637Sbz struct pci_devinfo *dinfo = device_get_ivars(child); 3691223637Sbz 3692223637Sbz return (&dinfo->resources); 3693231852Sbz} 3694223637Sbz 3695231852Sbzuint32_t 3696231852Sbzpci_read_config_method(device_t dev, device_t child, int reg, int width) 3697223637Sbz{ 3698223637Sbz struct pci_devinfo *dinfo = device_get_ivars(child); 3699223637Sbz pcicfgregs *cfg = &dinfo->cfg; 3700240233Sglebius 3701223637Sbz return (PCIB_READ_CONFIG(device_get_parent(dev), 3702223637Sbz cfg->bus, cfg->slot, cfg->func, reg, width)); 3703171168Smlaier} 3704165631Smlaier 3705223637Sbzvoid 3706126258Smlaierpci_write_config_method(device_t dev, device_t child, int reg, 3707223637Sbz uint32_t val, int width) 3708223637Sbz{ 3709240233Sglebius struct pci_devinfo *dinfo = device_get_ivars(child); 3710223637Sbz pcicfgregs *cfg = &dinfo->cfg; 3711240233Sglebius 3712223637Sbz PCIB_WRITE_CONFIG(device_get_parent(dev), 3713285940Sglebius cfg->bus, cfg->slot, cfg->func, reg, val, width); 3714285940Sglebius} 3715285940Sglebius 3716285940Sglebiusint 3717285940Sglebiuspci_child_location_str_method(device_t dev, device_t child, char *buf, 3718285940Sglebius size_t buflen) 3719285940Sglebius{ 3720285940Sglebius 3721285940Sglebius snprintf(buf, buflen, "slot=%d function=%d", pci_get_slot(child), 3722285940Sglebius pci_get_function(child)); 3723285940Sglebius return (0); 3724285940Sglebius} 3725261019Sglebius 3726240737Sglebiusint 3727285940Sglebiuspci_child_pnpinfo_str_method(device_t dev, device_t child, char *buf, 3728285940Sglebius size_t buflen) 3729285940Sglebius{ 3730285940Sglebius struct pci_devinfo *dinfo; 3731285940Sglebius pcicfgregs *cfg; 3732286004Sglebius 3733285940Sglebius dinfo = device_get_ivars(child); 3734285940Sglebius cfg = &dinfo->cfg; 3735285940Sglebius snprintf(buf, buflen, "vendor=0x%04x device=0x%04x subvendor=0x%04x " 3736285940Sglebius "subdevice=0x%04x class=0x%02x%02x%02x", cfg->vendor, cfg->device, 3737285940Sglebius cfg->subvendor, cfg->subdevice, cfg->baseclass, cfg->subclass, 3738285940Sglebius cfg->progif); 3739261019Sglebius return (0); 3740240737Sglebius} 3741223637Sbz 3742126258Smlaierint 3743126258Smlaierpci_assign_interrupt_method(device_t dev, device_t child) 3744240233Sglebius{ 3745130613Smlaier struct pci_devinfo *dinfo = device_get_ivars(child); 3746126258Smlaier pcicfgregs *cfg = &dinfo->cfg; 3747126258Smlaier 3748126258Smlaier return (PCIB_ROUTE_INTERRUPT(device_get_parent(dev), child, 3749126258Smlaier cfg->intpin)); 3750126258Smlaier} 3751126258Smlaier 3752126258Smlaierstatic int 3753126258Smlaierpci_modevent(module_t mod, int what, void *arg) 3754145836Smlaier{ 3755171168Smlaier static struct cdev *pci_cdev; 3756240641Sglebius 3757126258Smlaier switch (what) { 3758240233Sglebius case MOD_LOAD: 3759240233Sglebius STAILQ_INIT(&pci_devq); 3760126258Smlaier pci_generation = 0; 3761126258Smlaier pci_cdev = make_dev(&pcicdev, 0, UID_ROOT, GID_WHEEL, 0644, 3762126258Smlaier "pci"); 3763171168Smlaier pci_load_vendor_data(); 3764126258Smlaier break; 3765126258Smlaier 3766126258Smlaier case MOD_UNLOAD: 3767126258Smlaier destroy_dev(pci_cdev); 3768126258Smlaier break; 3769126258Smlaier } 3770126258Smlaier 3771171168Smlaier return (0); 3772231852Sbz} 3773126258Smlaier 3774171168Smlaiervoid 3775231852Sbzpci_cfg_restore(device_t dev, struct pci_devinfo *dinfo) 3776126258Smlaier{ 3777171168Smlaier int i; 3778126258Smlaier 3779173815Smlaier /* 3780126258Smlaier * Only do header type 0 devices. Type 1 devices are bridges, 3781173815Smlaier * which we know need special treatment. Type 2 devices are 3782173815Smlaier * cardbus bridges which also require special treatment. 3783173815Smlaier * Other types are unknown, and we err on the side of safety 3784173815Smlaier * by ignoring them. 3785173815Smlaier */ 3786173815Smlaier if (dinfo->cfg.hdrtype != 0) 3787173815Smlaier return; 3788173815Smlaier 3789173815Smlaier /* 3790173815Smlaier * Restore the device to full power mode. We must do this 3791223637Sbz * before we restore the registers because moving from D3 to 3792223637Sbz * D0 will cause the chip's BARs and some other registers to 3793126258Smlaier * be reset to some unknown power on reset values. Cut down 3794240233Sglebius * the noise on boot by doing nothing if we are already in 3795240233Sglebius * state D0. 3796126258Smlaier */ 3797126258Smlaier if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) { 3798126258Smlaier pci_set_powerstate(dev, PCI_POWERSTATE_D0); 3799171168Smlaier } 3800126258Smlaier for (i = 0; i < dinfo->cfg.nummaps; i++) 3801126258Smlaier pci_write_config(dev, PCIR_BAR(i), dinfo->cfg.bar[i], 4); 3802126258Smlaier pci_write_config(dev, PCIR_BIOS, dinfo->cfg.bios, 4); 3803126258Smlaier pci_write_config(dev, PCIR_COMMAND, dinfo->cfg.cmdreg, 2); 3804126258Smlaier pci_write_config(dev, PCIR_INTLINE, dinfo->cfg.intline, 1); 3805126258Smlaier pci_write_config(dev, PCIR_INTPIN, dinfo->cfg.intpin, 1); 3806126258Smlaier pci_write_config(dev, PCIR_MINGNT, dinfo->cfg.mingnt, 1); 3807240641Sglebius pci_write_config(dev, PCIR_MAXLAT, dinfo->cfg.maxlat, 1); 3808240641Sglebius pci_write_config(dev, PCIR_CACHELNSZ, dinfo->cfg.cachelnsz, 1); 3809240641Sglebius pci_write_config(dev, PCIR_LATTIMER, dinfo->cfg.lattimer, 1); 3810126258Smlaier pci_write_config(dev, PCIR_PROGIF, dinfo->cfg.progif, 1); 3811240641Sglebius pci_write_config(dev, PCIR_REVID, dinfo->cfg.revid, 1); 3812240641Sglebius 3813171168Smlaier /* Restore MSI and MSI-X configurations if they are present. */ 3814126258Smlaier if (dinfo->cfg.msi.msi_location != 0) 3815126258Smlaier pci_resume_msi(dev); 3816126258Smlaier if (dinfo->cfg.msix.msix_location != 0) 3817126258Smlaier pci_resume_msix(dev); 3818126258Smlaier} 3819126258Smlaier 3820130613Smlaiervoid 3821126258Smlaierpci_cfg_save(device_t dev, struct pci_devinfo *dinfo, int setstate) 3822240233Sglebius{ 3823240233Sglebius int i; 3824126258Smlaier uint32_t cls; 3825126258Smlaier int ps; 3826126258Smlaier 3827126258Smlaier /* 3828240233Sglebius * Only do header type 0 devices. Type 1 devices are bridges, which 3829126258Smlaier * we know need special treatment. Type 2 devices are cardbus bridges 3830126258Smlaier * which also require special treatment. Other types are unknown, and 3831126258Smlaier * we err on the side of safety by ignoring them. Powering down 3832126258Smlaier * bridges should not be undertaken lightly. 3833126258Smlaier */ 3834126258Smlaier if (dinfo->cfg.hdrtype != 0) 3835126258Smlaier return; 3836240233Sglebius for (i = 0; i < dinfo->cfg.nummaps; i++) 3837200930Sdelphij dinfo->cfg.bar[i] = pci_read_config(dev, PCIR_BAR(i), 4); 3838200930Sdelphij dinfo->cfg.bios = pci_read_config(dev, PCIR_BIOS, 4); 3839200930Sdelphij 3840126258Smlaier /* 3841223637Sbz * Some drivers apparently write to these registers w/o updating our 3842223637Sbz * cached copy. No harm happens if we update the copy, so do so here 3843223637Sbz * so we can restore them. The COMMAND register is modified by the 3844223637Sbz * bus w/o updating the cache. This should represent the normally 3845223637Sbz * writable portion of the 'defined' part of type 0 headers. In 3846126258Smlaier * theory we also need to save/restore the PCI capability structures 3847126258Smlaier * we know about, but apart from power we don't know any that are 3848126258Smlaier * writable. 3849126258Smlaier */ 3850126258Smlaier dinfo->cfg.subvendor = pci_read_config(dev, PCIR_SUBVEND_0, 2); 3851126258Smlaier dinfo->cfg.subdevice = pci_read_config(dev, PCIR_SUBDEV_0, 2); 3852126258Smlaier dinfo->cfg.vendor = pci_read_config(dev, PCIR_VENDOR, 2); 3853126258Smlaier dinfo->cfg.device = pci_read_config(dev, PCIR_DEVICE, 2); 3854126258Smlaier dinfo->cfg.cmdreg = pci_read_config(dev, PCIR_COMMAND, 2); 3855126258Smlaier dinfo->cfg.intline = pci_read_config(dev, PCIR_INTLINE, 1); 3856126258Smlaier dinfo->cfg.intpin = pci_read_config(dev, PCIR_INTPIN, 1); 3857126258Smlaier dinfo->cfg.mingnt = pci_read_config(dev, PCIR_MINGNT, 1); 3858126258Smlaier dinfo->cfg.maxlat = pci_read_config(dev, PCIR_MAXLAT, 1); 3859145836Smlaier dinfo->cfg.cachelnsz = pci_read_config(dev, PCIR_CACHELNSZ, 1); 3860126258Smlaier dinfo->cfg.lattimer = pci_read_config(dev, PCIR_LATTIMER, 1); 3861126258Smlaier dinfo->cfg.baseclass = pci_read_config(dev, PCIR_CLASS, 1); 3862126258Smlaier dinfo->cfg.subclass = pci_read_config(dev, PCIR_SUBCLASS, 1); 3863126258Smlaier dinfo->cfg.progif = pci_read_config(dev, PCIR_PROGIF, 1); 3864126258Smlaier dinfo->cfg.revid = pci_read_config(dev, PCIR_REVID, 1); 3865126258Smlaier 3866126258Smlaier /* 3867126258Smlaier * don't set the state for display devices, base peripherals and 3868126258Smlaier * memory devices since bad things happen when they are powered down. 3869126258Smlaier * We should (a) have drivers that can easily detach and (b) use 3870126258Smlaier * generic drivers for these devices so that some device actually 3871126258Smlaier * attaches. We need to make sure that when we implement (a) we don't 3872126258Smlaier * power the device down on a reattach. 3873223637Sbz */ 3874223637Sbz cls = pci_get_class(dev); 3875126258Smlaier if (!setstate) 3876126258Smlaier return; 3877289703Skp switch (pci_do_power_nodriver) 3878126258Smlaier { 3879289703Skp case 0: /* NO powerdown at all */ 3880200930Sdelphij return; 3881126258Smlaier case 1: /* Conservative about what to power down */ 3882126258Smlaier if (cls == PCIC_STORAGE) 3883126258Smlaier return; 3884126258Smlaier /*FALLTHROUGH*/ 3885126258Smlaier case 2: /* Agressive about what to power down */ 3886126258Smlaier if (cls == PCIC_DISPLAY || cls == PCIC_MEMORY || 3887126258Smlaier cls == PCIC_BASEPERIPH) 3888126258Smlaier return; 3889126258Smlaier /*FALLTHROUGH*/ 3890126258Smlaier case 3: /* Power down everything */ 3891126258Smlaier break; 3892126258Smlaier } 3893126258Smlaier /* 3894126258Smlaier * PCI spec says we can only go into D3 state from D0 state. 3895126258Smlaier * Transition from D[12] into D0 before going to D3 state. 3896126258Smlaier */ 3897126258Smlaier ps = pci_get_powerstate(dev); 3898126258Smlaier if (ps != PCI_POWERSTATE_D0 && ps != PCI_POWERSTATE_D3) 3899126258Smlaier pci_set_powerstate(dev, PCI_POWERSTATE_D0); 3900126258Smlaier if (pci_get_powerstate(dev) != PCI_POWERSTATE_D3) 3901126258Smlaier pci_set_powerstate(dev, PCI_POWERSTATE_D3); 3902126258Smlaier} 3903126258Smlaier