Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
mmconfig_64.c
Go to the documentation of this file.
1 /*
2  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
3  *
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>
10 #include <linux/acpi.h>
11 #include <linux/bitmap.h>
12 #include <linux/rcupdate.h>
13 #include <asm/e820.h>
14 #include <asm/pci_x86.h>
15 
16 #define PREFIX "PCI: "
17 
18 static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
19 {
20  struct pci_mmcfg_region *cfg = pci_mmconfig_lookup(seg, bus);
21 
22  if (cfg && cfg->virt)
23  return cfg->virt + (PCI_MMCFG_BUS_OFFSET(bus) | (devfn << 12));
24  return NULL;
25 }
26 
27 static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
28  unsigned int devfn, int reg, int len, u32 *value)
29 {
30  char __iomem *addr;
31 
32  /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
33  if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
34 err: *value = -1;
35  return -EINVAL;
36  }
37 
38  rcu_read_lock();
39  addr = pci_dev_base(seg, bus, devfn);
40  if (!addr) {
41  rcu_read_unlock();
42  goto err;
43  }
44 
45  switch (len) {
46  case 1:
47  *value = mmio_config_readb(addr + reg);
48  break;
49  case 2:
50  *value = mmio_config_readw(addr + reg);
51  break;
52  case 4:
53  *value = mmio_config_readl(addr + reg);
54  break;
55  }
56  rcu_read_unlock();
57 
58  return 0;
59 }
60 
61 static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
62  unsigned int devfn, int reg, int len, u32 value)
63 {
64  char __iomem *addr;
65 
66  /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
67  if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
68  return -EINVAL;
69 
70  rcu_read_lock();
71  addr = pci_dev_base(seg, bus, devfn);
72  if (!addr) {
73  rcu_read_unlock();
74  return -EINVAL;
75  }
76 
77  switch (len) {
78  case 1:
79  mmio_config_writeb(addr + reg, value);
80  break;
81  case 2:
82  mmio_config_writew(addr + reg, value);
83  break;
84  case 4:
85  mmio_config_writel(addr + reg, value);
86  break;
87  }
88  rcu_read_unlock();
89 
90  return 0;
91 }
92 
93 const struct pci_raw_ops pci_mmcfg = {
94  .read = pci_mmcfg_read,
95  .write = pci_mmcfg_write,
96 };
97 
98 static void __iomem * __devinit mcfg_ioremap(struct pci_mmcfg_region *cfg)
99 {
100  void __iomem *addr;
101  u64 start, size;
102  int num_buses;
103 
104  start = cfg->address + PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
105  num_buses = cfg->end_bus - cfg->start_bus + 1;
106  size = PCI_MMCFG_BUS_OFFSET(num_buses);
107  addr = ioremap_nocache(start, size);
108  if (addr)
109  addr -= PCI_MMCFG_BUS_OFFSET(cfg->start_bus);
110  return addr;
111 }
112 
114 {
115  struct pci_mmcfg_region *cfg;
116 
118  if (pci_mmcfg_arch_map(cfg)) {
120  return 0;
121  }
122 
124 
125  return 1;
126 }
127 
129 {
130  struct pci_mmcfg_region *cfg;
131 
134 }
135 
137 {
138  cfg->virt = mcfg_ioremap(cfg);
139  if (!cfg->virt) {
140  pr_err(PREFIX "can't map MMCONFIG at %pR\n", &cfg->res);
141  return -ENOMEM;
142  }
143 
144  return 0;
145 }
146 
148 {
149  if (cfg && cfg->virt) {
151  cfg->virt = NULL;
152  }
153 }