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