/* K8 systems have some devices (typically in the builtin northbridge) that are only accessible using type1 Normally this can be expressed in the MCFG by not listing them and assigning suitable _SEGs, but this isn't implemented in some BIOS. Instead try to discover all devices on bus 0 that are unreachable using MM and fallback for them. */ static __init void unreachable_devices(void) { int i, k; unsigned long flags; for (k = 0; k < MAX_CHECK_BUS; k++) { for (i = 0; i < 32; i++) { u32 val1; u32 addr; pci_conf1_read(0, k, PCI_DEVFN(i, 0), 0, 4, &val1); if (val1 == 0xffffffff) continue; /* Locking probably not needed, but safer */ spin_lock_irqsave(&pci_config_lock, flags); addr = get_base_addr(0, k, PCI_DEVFN(i, 0)); if (addr != 0) pci_exp_set_dev_base(addr, k, PCI_DEVFN(i, 0)); if (addr == 0 || readl((u32 __iomem *)mmcfg_virt_addr) != val1) { set_bit(i + 32*k, fallback_slots); printk(KERN_NOTICE "PCI: No mmconfig possible on %x:%x\n", k, i); } spin_unlock_irqrestore(&pci_config_lock, flags); } } }
static int pci_mmcfg_read(unsigned int seg, unsigned int bus, unsigned int devfn, int reg, int len, u32 *value) { char __iomem *addr; /* Why do we have this when nobody checks it. How about a BUG()!? -AK */ if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095))) return -EINVAL; addr = pci_dev_base(seg, bus, devfn); if (!addr) return pci_conf1_read(seg,bus,devfn,reg,len,value); switch (len) { case 1: *value = readb(addr + reg); break; case 2: *value = readw(addr + reg); break; case 4: *value = readl(addr + reg); break; } return 0; }
static int pci_mmcfg_read(unsigned int seg, unsigned int bus, unsigned int devfn, int reg, int len, u32 *value) { unsigned long flags; u32 base; if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; base = get_base_addr(seg, bus, devfn); if (!base) return pci_conf1_read(seg,bus,devfn,reg,len,value); spin_lock_irqsave(&pci_config_lock, flags); pci_exp_set_dev_base(base, bus, devfn); switch (len) { case 1: *value = readb(mmcfg_virt_addr + reg); break; case 2: *value = readw(mmcfg_virt_addr + reg); break; case 4: *value = readl(mmcfg_virt_addr + reg); break; } spin_unlock_irqrestore(&pci_config_lock, flags); return 0; }
static int pci_conf1_read_config_dword(struct pci_dev *dev, int where, u32 *value) { if (!value) return -EINVAL; return pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, 4, value); }
static int pci_conf1_read_config_word(struct pci_dev *dev, int where, u16 *value) { int result; u32 data; result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, 2, &data); *value = (u16)data; return result; }
static int pci_conf1_read_config_byte(struct pci_dev *dev, int where, u8 *value) { int result; u32 data; if (!value) return -EINVAL; result = pci_conf1_read(0, dev->bus->number, PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), where, 1, &data); *value = (u8)data; return result; }
/* K8 systems have some devices (typically in the builtin northbridge) that are only accessible using type1 Normally this can be expressed in the MCFG by not listing them and assigning suitable _SEGs, but this isn't implemented in some BIOS. Instead try to discover all devices on bus 0 that are unreachable using MM and fallback for them. We only do this for bus 0/seg 0 */ static __init void unreachable_devices(void) { int i; for (i = 0; i < 32; i++) { u32 val1; char __iomem *addr; pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1); if (val1 == 0xffffffff) continue; addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0)); if (addr == NULL|| readl(addr) != val1) { set_bit(i, &fallback_slots); } } }
/* K8 systems have some devices (typically in the builtin northbridge) that are only accessible using type1 Normally this can be expressed in the MCFG by not listing them and assigning suitable _SEGs, but this isn't implemented in some BIOS. Instead try to discover all devices on bus 0 that are unreachable using MM and fallback for them. We only do this for bus 0/seg 0 */ static __init void unreachable_devices(void) { int i; unsigned long flags; for (i = 0; i < 32; i++) { u32 val1; u32 addr; pci_conf1_read(0, 0, PCI_DEVFN(i, 0), 0, 4, &val1); if (val1 == 0xffffffff) continue; /* Locking probably not needed, but safer */ spin_lock_irqsave(&pci_config_lock, flags); addr = get_base_addr(0, 0, PCI_DEVFN(i, 0)); if (addr != 0) pci_exp_set_dev_base(addr, 0, PCI_DEVFN(i, 0)); if (addr == 0 || readl((u32 __iomem *)mmcfg_virt_addr) != val1) set_bit(i, fallback_slots); spin_unlock_irqrestore(&pci_config_lock, flags); } }
static int pci_read(struct pci_bus *bus, unsigned int devfn, int where, int size, u32 *value) { return pci_conf1_read(pci_domain_nr(bus), bus->number, devfn, where, size, value); }