162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * legacy.c - traditional, old school PCI bus probing 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci#include <linux/init.h> 662306a36Sopenharmony_ci#include <linux/export.h> 762306a36Sopenharmony_ci#include <linux/pci.h> 862306a36Sopenharmony_ci#include <asm/jailhouse_para.h> 962306a36Sopenharmony_ci#include <asm/pci_x86.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci/* 1262306a36Sopenharmony_ci * Discover remaining PCI buses in case there are peer host bridges. 1362306a36Sopenharmony_ci * We use the number of last PCI bus provided by the PCI BIOS. 1462306a36Sopenharmony_ci */ 1562306a36Sopenharmony_cistatic void pcibios_fixup_peer_bridges(void) 1662306a36Sopenharmony_ci{ 1762306a36Sopenharmony_ci int n; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci if (pcibios_last_bus <= 0 || pcibios_last_bus > 0xff) 2062306a36Sopenharmony_ci return; 2162306a36Sopenharmony_ci DBG("PCI: Peer bridge fixup\n"); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci for (n=0; n <= pcibios_last_bus; n++) 2462306a36Sopenharmony_ci pcibios_scan_specific_bus(n); 2562306a36Sopenharmony_ci} 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciint __init pci_legacy_init(void) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci if (!raw_pci_ops) 3062306a36Sopenharmony_ci return 1; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci pr_info("PCI: Probing PCI hardware\n"); 3362306a36Sopenharmony_ci pcibios_scan_root(0); 3462306a36Sopenharmony_ci return 0; 3562306a36Sopenharmony_ci} 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_civoid pcibios_scan_specific_bus(int busn) 3862306a36Sopenharmony_ci{ 3962306a36Sopenharmony_ci int stride = jailhouse_paravirt() ? 1 : 8; 4062306a36Sopenharmony_ci int devfn; 4162306a36Sopenharmony_ci u32 l; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci if (pci_find_bus(0, busn)) 4462306a36Sopenharmony_ci return; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci for (devfn = 0; devfn < 256; devfn += stride) { 4762306a36Sopenharmony_ci if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) && 4862306a36Sopenharmony_ci l != 0x0000 && l != 0xffff) { 4962306a36Sopenharmony_ci DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l); 5062306a36Sopenharmony_ci pr_info("PCI: Discovered peer bus %02x\n", busn); 5162306a36Sopenharmony_ci pcibios_scan_root(busn); 5262306a36Sopenharmony_ci return; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci} 5662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(pcibios_scan_specific_bus); 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int __init pci_subsys_init(void) 5962306a36Sopenharmony_ci{ 6062306a36Sopenharmony_ci /* 6162306a36Sopenharmony_ci * The init function returns an non zero value when 6262306a36Sopenharmony_ci * pci_legacy_init should be invoked. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci if (x86_init.pci.init()) { 6562306a36Sopenharmony_ci if (pci_legacy_init()) { 6662306a36Sopenharmony_ci pr_info("PCI: System does not support PCI\n"); 6762306a36Sopenharmony_ci return -ENODEV; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci pcibios_fixup_peer_bridges(); 7262306a36Sopenharmony_ci x86_init.pci.init_irq(); 7362306a36Sopenharmony_ci pcibios_init(); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci return 0; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_cisubsys_initcall(pci_subsys_init); 78