xref: /openbmc/linux/arch/x86/pci/legacy.c (revision 58e16d792a6a8c6b750f637a4649967fcac853dc)
1*457c8996SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fb9aa6f1SThomas Gleixner /*
3fb9aa6f1SThomas Gleixner  * legacy.c - traditional, old school PCI bus probing
4fb9aa6f1SThomas Gleixner  */
5fb9aa6f1SThomas Gleixner #include <linux/init.h>
669c60c88SPaul Gortmaker #include <linux/export.h>
7fb9aa6f1SThomas Gleixner #include <linux/pci.h>
8690f4304SJan Kiszka #include <asm/jailhouse_para.h>
982487711SJaswinder Singh Rajput #include <asm/pci_x86.h>
10fb9aa6f1SThomas Gleixner 
11fb9aa6f1SThomas Gleixner /*
12fb9aa6f1SThomas Gleixner  * Discover remaining PCI buses in case there are peer host bridges.
13fb9aa6f1SThomas Gleixner  * We use the number of last PCI bus provided by the PCI BIOS.
14fb9aa6f1SThomas Gleixner  */
pcibios_fixup_peer_bridges(void)15a18e3690SGreg Kroah-Hartman static void pcibios_fixup_peer_bridges(void)
16fb9aa6f1SThomas Gleixner {
175707b24aSAristeu Rozanski 	int n;
18fb9aa6f1SThomas Gleixner 
199dd1e9ebSAndi Kleen 	if (pcibios_last_bus <= 0 || pcibios_last_bus > 0xff)
20fb9aa6f1SThomas Gleixner 		return;
21fb9aa6f1SThomas Gleixner 	DBG("PCI: Peer bridge fixup\n");
22fb9aa6f1SThomas Gleixner 
235707b24aSAristeu Rozanski 	for (n=0; n <= pcibios_last_bus; n++)
245707b24aSAristeu Rozanski 		pcibios_scan_specific_bus(n);
25fb9aa6f1SThomas Gleixner }
26fb9aa6f1SThomas Gleixner 
pci_legacy_init(void)27b72d0db9SThomas Gleixner int __init pci_legacy_init(void)
28fb9aa6f1SThomas Gleixner {
29aae3e318SThomas Gleixner 	if (!raw_pci_ops)
30aae3e318SThomas Gleixner 		return 1;
31fb9aa6f1SThomas Gleixner 
32aae3e318SThomas Gleixner 	pr_info("PCI: Probing PCI hardware\n");
33b7869ba1SBjorn Helgaas 	pcibios_scan_root(0);
34fb9aa6f1SThomas Gleixner 	return 0;
35fb9aa6f1SThomas Gleixner }
365707b24aSAristeu Rozanski 
pcibios_scan_specific_bus(int busn)37a18e3690SGreg Kroah-Hartman void pcibios_scan_specific_bus(int busn)
385707b24aSAristeu Rozanski {
39690f4304SJan Kiszka 	int stride = jailhouse_paravirt() ? 1 : 8;
405707b24aSAristeu Rozanski 	int devfn;
415707b24aSAristeu Rozanski 	u32 l;
425707b24aSAristeu Rozanski 
435707b24aSAristeu Rozanski 	if (pci_find_bus(0, busn))
445707b24aSAristeu Rozanski 		return;
455707b24aSAristeu Rozanski 
46690f4304SJan Kiszka 	for (devfn = 0; devfn < 256; devfn += stride) {
475707b24aSAristeu Rozanski 		if (!raw_pci_read(0, busn, devfn, PCI_VENDOR_ID, 2, &l) &&
485707b24aSAristeu Rozanski 		    l != 0x0000 && l != 0xffff) {
495707b24aSAristeu Rozanski 			DBG("Found device at %02x:%02x [%04x]\n", busn, devfn, l);
50aae3e318SThomas Gleixner 			pr_info("PCI: Discovered peer bus %02x\n", busn);
513d2a3661SBjorn Helgaas 			pcibios_scan_root(busn);
525707b24aSAristeu Rozanski 			return;
535707b24aSAristeu Rozanski 		}
545707b24aSAristeu Rozanski 	}
555707b24aSAristeu Rozanski }
56d1fd4fb6SMauro Carvalho Chehab EXPORT_SYMBOL_GPL(pcibios_scan_specific_bus);
57fb9aa6f1SThomas Gleixner 
pci_subsys_init(void)5868d0d979SAlexander Kuleshov static int __init pci_subsys_init(void)
598dd779b1SRobert Richter {
60b72d0db9SThomas Gleixner 	/*
61b72d0db9SThomas Gleixner 	 * The init function returns an non zero value when
62b72d0db9SThomas Gleixner 	 * pci_legacy_init should be invoked.
63b72d0db9SThomas Gleixner 	 */
64aae3e318SThomas Gleixner 	if (x86_init.pci.init()) {
65aae3e318SThomas Gleixner 		if (pci_legacy_init()) {
66aae3e318SThomas Gleixner 			pr_info("PCI: System does not support PCI\n");
67aae3e318SThomas Gleixner 			return -ENODEV;
68aae3e318SThomas Gleixner 		}
69aae3e318SThomas Gleixner 	}
70b72d0db9SThomas Gleixner 
71e42d1fe8SYinghai Lu 	pcibios_fixup_peer_bridges();
72ab3b3793SThomas Gleixner 	x86_init.pci.init_irq();
738dd779b1SRobert Richter 	pcibios_init();
743a62ed73SRobert Richter 
753a62ed73SRobert Richter 	return 0;
768dd779b1SRobert Richter }
778dd779b1SRobert Richter subsys_initcall(pci_subsys_init);
78