static int pci_mmcfg_write(unsigned int seg, unsigned int bus, unsigned int devfn, int reg, int len, u32 value) { unsigned long flags; u32 base; if ((bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; base = get_base_addr(seg, bus, devfn); if (!base) return -EINVAL; raw_spin_lock_irqsave(&pci_config_lock, flags); pci_exp_set_dev_base(base, bus, devfn); switch (len) { case 1: mmio_config_writeb(mmcfg_virt_addr + reg, value); break; case 2: mmio_config_writew(mmcfg_virt_addr + reg, value); break; case 4: mmio_config_writel(mmcfg_virt_addr + reg, value); break; } raw_spin_unlock_irqrestore(&pci_config_lock, flags); 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 ((bus > 255) || (devfn > 255) || (reg > 4095)) { err: *value = -1; return -EINVAL; } base = get_base_addr(seg, bus, devfn); if (!base) goto err; raw_spin_lock_irqsave(&pci_config_lock, flags); pci_exp_set_dev_base(base, bus, devfn); switch (len) { case 1: *value = mmio_config_readb(mmcfg_virt_addr + reg); break; case 2: *value = mmio_config_readw(mmcfg_virt_addr + reg); break; case 4: *value = mmio_config_readl(mmcfg_virt_addr + reg); break; } raw_spin_unlock_irqrestore(&pci_config_lock, flags); return 0; }
static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value) { unsigned long flags; if ((bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; spin_lock_irqsave(&pci_config_lock, flags); pci_exp_set_dev_base(bus, devfn); switch (len) { case 1: writeb(value, mmcfg_virt_addr + reg); break; case 2: writew(value, mmcfg_virt_addr + reg); break; case 4: writel(value, mmcfg_virt_addr + reg); break; } spin_unlock_irqrestore(&pci_config_lock, flags); return 0; }
static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value) { unsigned long flags; if (!value || (bus > 255) || (devfn > 255) || (reg > 4095)) return -EINVAL; spin_lock_irqsave(&pci_config_lock, flags); pci_exp_set_dev_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; }
/* 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); } } }
/* 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); } }