1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 2fb9aa6f1SThomas Gleixner #include <linux/kernel.h> 3fb9aa6f1SThomas Gleixner #include <linux/pci.h> 4fb9aa6f1SThomas Gleixner #include <asm/pci-direct.h> 5fb9aa6f1SThomas Gleixner #include <asm/io.h> 682487711SJaswinder Singh Rajput #include <asm/pci_x86.h> 7fb9aa6f1SThomas Gleixner 8fb9aa6f1SThomas Gleixner /* Direct PCI access. This is used for PCI accesses in early boot before 9fb9aa6f1SThomas Gleixner the PCI subsystem works. */ 10fb9aa6f1SThomas Gleixner 11fb9aa6f1SThomas Gleixner u32 read_pci_config(u8 bus, u8 slot, u8 func, u8 offset) 12fb9aa6f1SThomas Gleixner { 13fb9aa6f1SThomas Gleixner u32 v; 14fb9aa6f1SThomas Gleixner outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); 15fb9aa6f1SThomas Gleixner v = inl(0xcfc); 16fb9aa6f1SThomas Gleixner return v; 17fb9aa6f1SThomas Gleixner } 18fb9aa6f1SThomas Gleixner 19fb9aa6f1SThomas Gleixner u8 read_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset) 20fb9aa6f1SThomas Gleixner { 21fb9aa6f1SThomas Gleixner u8 v; 22fb9aa6f1SThomas Gleixner outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); 23fb9aa6f1SThomas Gleixner v = inb(0xcfc + (offset&3)); 24fb9aa6f1SThomas Gleixner return v; 25fb9aa6f1SThomas Gleixner } 26fb9aa6f1SThomas Gleixner 27fb9aa6f1SThomas Gleixner u16 read_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset) 28fb9aa6f1SThomas Gleixner { 29fb9aa6f1SThomas Gleixner u16 v; 30fb9aa6f1SThomas Gleixner outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); 31fb9aa6f1SThomas Gleixner v = inw(0xcfc + (offset&2)); 32fb9aa6f1SThomas Gleixner return v; 33fb9aa6f1SThomas Gleixner } 34fb9aa6f1SThomas Gleixner 35fb9aa6f1SThomas Gleixner void write_pci_config(u8 bus, u8 slot, u8 func, u8 offset, 36fb9aa6f1SThomas Gleixner u32 val) 37fb9aa6f1SThomas Gleixner { 38fb9aa6f1SThomas Gleixner outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); 39fb9aa6f1SThomas Gleixner outl(val, 0xcfc); 40fb9aa6f1SThomas Gleixner } 41fb9aa6f1SThomas Gleixner 42fb9aa6f1SThomas Gleixner void write_pci_config_byte(u8 bus, u8 slot, u8 func, u8 offset, u8 val) 43fb9aa6f1SThomas Gleixner { 44fb9aa6f1SThomas Gleixner outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); 45e7891c73SYinghai Lu outb(val, 0xcfc + (offset&3)); 46e7891c73SYinghai Lu } 47e7891c73SYinghai Lu 48e7891c73SYinghai Lu void write_pci_config_16(u8 bus, u8 slot, u8 func, u8 offset, u16 val) 49e7891c73SYinghai Lu { 50e7891c73SYinghai Lu outl(0x80000000 | (bus<<16) | (slot<<11) | (func<<8) | offset, 0xcf8); 51e7891c73SYinghai Lu outw(val, 0xcfc + (offset&2)); 52fb9aa6f1SThomas Gleixner } 53fb9aa6f1SThomas Gleixner 54fb9aa6f1SThomas Gleixner int early_pci_allowed(void) 55fb9aa6f1SThomas Gleixner { 56fb9aa6f1SThomas Gleixner return (pci_probe & (PCI_PROBE_CONF1|PCI_PROBE_NOEARLY)) == 57fb9aa6f1SThomas Gleixner PCI_PROBE_CONF1; 58fb9aa6f1SThomas Gleixner } 59e3f2baebSYinghai Lu 60e3f2baebSYinghai Lu void early_dump_pci_device(u8 bus, u8 slot, u8 func) 61e3f2baebSYinghai Lu { 62e3f2baebSYinghai Lu int i; 63e3f2baebSYinghai Lu int j; 64e3f2baebSYinghai Lu u32 val; 65e3f2baebSYinghai Lu 667bc9e77dSBjorn Helgaas printk(KERN_INFO "pci 0000:%02x:%02x.%d config space:", 677bc9e77dSBjorn Helgaas bus, slot, func); 68e3f2baebSYinghai Lu 69e3f2baebSYinghai Lu for (i = 0; i < 256; i += 4) { 70e3f2baebSYinghai Lu if (!(i & 0x0f)) 717bc9e77dSBjorn Helgaas printk("\n %02x:",i); 72e3f2baebSYinghai Lu 73e3f2baebSYinghai Lu val = read_pci_config(bus, slot, func, i); 74e3f2baebSYinghai Lu for (j = 0; j < 4; j++) { 75e3f2baebSYinghai Lu printk(" %02x", val & 0xff); 76e3f2baebSYinghai Lu val >>= 8; 77e3f2baebSYinghai Lu } 78e3f2baebSYinghai Lu } 79e3f2baebSYinghai Lu printk("\n"); 80e3f2baebSYinghai Lu } 81e3f2baebSYinghai Lu 82e3f2baebSYinghai Lu void early_dump_pci_devices(void) 83e3f2baebSYinghai Lu { 84e3f2baebSYinghai Lu unsigned bus, slot, func; 85e3f2baebSYinghai Lu 86e3f2baebSYinghai Lu if (!early_pci_allowed()) 87e3f2baebSYinghai Lu return; 88e3f2baebSYinghai Lu 89e3f2baebSYinghai Lu for (bus = 0; bus < 256; bus++) { 90e3f2baebSYinghai Lu for (slot = 0; slot < 32; slot++) { 91e3f2baebSYinghai Lu for (func = 0; func < 8; func++) { 92e3f2baebSYinghai Lu u32 class; 93e3f2baebSYinghai Lu u8 type; 94600914baSBjorn Helgaas 95e3f2baebSYinghai Lu class = read_pci_config(bus, slot, func, 96e3f2baebSYinghai Lu PCI_CLASS_REVISION); 97e3f2baebSYinghai Lu if (class == 0xffffffff) 98600914baSBjorn Helgaas continue; 99e3f2baebSYinghai Lu 100e3f2baebSYinghai Lu early_dump_pci_device(bus, slot, func); 101e3f2baebSYinghai Lu 102600914baSBjorn Helgaas if (func == 0) { 103600914baSBjorn Helgaas type = read_pci_config_byte(bus, slot, 104600914baSBjorn Helgaas func, 105e3f2baebSYinghai Lu PCI_HEADER_TYPE); 106e3f2baebSYinghai Lu if (!(type & 0x80)) 107e3f2baebSYinghai Lu break; 108e3f2baebSYinghai Lu } 109e3f2baebSYinghai Lu } 110e3f2baebSYinghai Lu } 111e3f2baebSYinghai Lu } 112600914baSBjorn Helgaas } 113