Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi...
[deliverable/linux.git] / arch / x86 / pci / mmconfig_64.c
CommitLineData
1da177e4
LT
1/*
2 * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
15a58ed1 3 *
1da177e4
LT
4 * This is an 64bit optimized version that always keeps the full mmconfig
5 * space mapped. This allows lockless config space operation.
6 */
7
8#include <linux/pci.h>
9#include <linux/init.h>
54549391 10#include <linux/acpi.h>
d6ece549 11#include <linux/bitmap.h>
946f2ee5 12#include <asm/e820.h>
82487711 13#include <asm/pci_x86.h>
1da177e4 14
8c57786a
BH
15#define PREFIX "PCI: "
16
8b8a4e33 17static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
1cde8a16 18{
f6e1d8cc 19 struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
a0ca9909 20
f6e1d8cc
BH
21 if (cfg && cfg->virt)
22 return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
23 return NULL;
1da177e4
LT
24}
25
26static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
27 unsigned int devfn, int reg, int len, u32 *value)
28{
8b8a4e33 29 char __iomem *addr;
1da177e4 30
928cf8c6 31 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
ecc16ba9 32 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
a0ca9909 33err: *value = -1;
1da177e4 34 return -EINVAL;
49c93e84 35 }
1da177e4 36
928cf8c6
AK
37 addr = pci_dev_base(seg, bus, devfn);
38 if (!addr)
a0ca9909 39 goto err;
928cf8c6 40
1da177e4
LT
41 switch (len) {
42 case 1:
3320ad99 43 *value = mmio_config_readb(addr + reg);
1da177e4
LT
44 break;
45 case 2:
3320ad99 46 *value = mmio_config_readw(addr + reg);
1da177e4
LT
47 break;
48 case 4:
3320ad99 49 *value = mmio_config_readl(addr + reg);
1da177e4
LT
50 break;
51 }
52
53 return 0;
54}
55
56static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
57 unsigned int devfn, int reg, int len, u32 value)
58{
8b8a4e33 59 char __iomem *addr;
1da177e4 60
928cf8c6 61 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
1da177e4
LT
62 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
63 return -EINVAL;
64
928cf8c6
AK
65 addr = pci_dev_base(seg, bus, devfn);
66 if (!addr)
a0ca9909 67 return -EINVAL;
928cf8c6 68
1da177e4
LT
69 switch (len) {
70 case 1:
3320ad99 71 mmio_config_writeb(addr + reg, value);
1da177e4
LT
72 break;
73 case 2:
3320ad99 74 mmio_config_writew(addr + reg, value);
1da177e4
LT
75 break;
76 case 4:
3320ad99 77 mmio_config_writel(addr + reg, value);
1da177e4
LT
78 break;
79 }
80
81 return 0;
82}
83
84static struct pci_raw_ops pci_mmcfg = {
85 .read = pci_mmcfg_read,
86 .write = pci_mmcfg_write,
87};
88
d215a9c8 89static void __iomem * __init mcfg_ioremap(struct pci_mmcfg_region *cfg)
44de0203
OH
90{
91 void __iomem *addr;
068258bc 92 u64 start, size;
df5eb1d6 93 int num_buses;
068258bc 94
d7e6b66f
BH
95 start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
96 num_buses = cfg->end_bus - cfg->start_bus + 1;
df5eb1d6 97 size = PCI_MMCFG_BUS_OFFSET(num_buses);
068258bc 98 addr = ioremap_nocache(start, size);
8c57786a 99 if (addr)
d7e6b66f 100 addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
44de0203
OH
101 return addr;
102}
103
b7867394 104int __init pci_mmcfg_arch_init(void)
1da177e4 105{
3f0f5503 106 struct pci_mmcfg_region *cfg;
b7867394 107
ff097ddd 108 list_for_each_entry(cfg, &pci_mmcfg_list, list) {
3f0f5503
BH
109 cfg->virt = mcfg_ioremap(cfg);
110 if (!cfg->virt) {
8c57786a
BH
111 printk(KERN_ERR PREFIX "can't map MMCONFIG at %pR\n",
112 &cfg->res);
0b64ad71 113 pci_mmcfg_arch_free();
b7867394 114 return 0;
1cde8a16 115 }
1cde8a16 116 }
b6ce068a 117 raw_pci_ext_ops = &pci_mmcfg;
b7867394 118 return 1;
1da177e4 119}
0b64ad71
YL
120
121void __init pci_mmcfg_arch_free(void)
122{
3f0f5503 123 struct pci_mmcfg_region *cfg;
0b64ad71 124
ff097ddd 125 list_for_each_entry(cfg, &pci_mmcfg_list, list) {
3f0f5503
BH
126 if (cfg->virt) {
127 iounmap(cfg->virt + PCI_MMCFG_BUS_OFFSET(cfg->start_bus));
128 cfg->virt = NULL;
0b64ad71
YL
129 }
130 }
0b64ad71 131}
This page took 0.721648 seconds and 5 git commands to generate.