blob: f16c0d57c552f1fade440fb7a683fa649bc7099f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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>
Greg Kroah-Hartman54549392005-06-23 17:35:56 -070010#include <linux/acpi.h>
Andi Kleend6ece542005-12-12 22:17:11 -080011#include <linux/bitmap.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include "pci.h"
13
14#define MMCONFIG_APER_SIZE (256*1024*1024)
15
Andi Kleend6ece542005-12-12 22:17:11 -080016static DECLARE_BITMAP(fallback_slots, 32);
17
Linus Torvalds1da177e2005-04-16 15:20:36 -070018/* Static virtual mapping of the MMCONFIG aperture */
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070019struct mmcfg_virt {
20 struct acpi_table_mcfg_config *cfg;
Al Viro8b8a4e32005-12-15 09:17:44 +000021 char __iomem *virt;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070022};
23static struct mmcfg_virt *pci_mmcfg_virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070024
Al Viro8b8a4e32005-12-15 09:17:44 +000025static char __iomem *get_virt(unsigned int seg, unsigned bus)
Linus Torvalds1da177e2005-04-16 15:20:36 -070026{
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070027 int cfg_num = -1;
28 struct acpi_table_mcfg_config *cfg;
29
30 while (1) {
31 ++cfg_num;
32 if (cfg_num >= pci_mmcfg_config_num) {
Andi Kleen928cf8c2005-12-12 22:17:10 -080033 /* Not found - fall back to type 1. This happens
34 e.g. on the internal devices of a K8 northbridge. */
35 return NULL;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070036 }
37 cfg = pci_mmcfg_virt[cfg_num].cfg;
38 if (cfg->pci_segment_group_number != seg)
39 continue;
40 if ((cfg->start_bus_number <= bus) &&
41 (cfg->end_bus_number >= bus))
42 return pci_mmcfg_virt[cfg_num].virt;
43 }
44}
45
Al Viro8b8a4e32005-12-15 09:17:44 +000046static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070047{
Al Viro8b8a4e32005-12-15 09:17:44 +000048 char __iomem *addr;
Andi Kleend6ece542005-12-12 22:17:11 -080049 if (seg == 0 && bus == 0 && test_bit(PCI_SLOT(devfn), &fallback_slots))
50 return NULL;
51 addr = get_virt(seg, bus);
Andi Kleen928cf8c2005-12-12 22:17:10 -080052 if (!addr)
53 return NULL;
54 return addr + ((bus << 20) | (devfn << 12));
Linus Torvalds1da177e2005-04-16 15:20:36 -070055}
56
57static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
58 unsigned int devfn, int reg, int len, u32 *value)
59{
Al Viro8b8a4e32005-12-15 09:17:44 +000060 char __iomem *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Andi Kleen928cf8c2005-12-12 22:17:10 -080062 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
Linus Torvalds1da177e2005-04-16 15:20:36 -070063 if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
64 return -EINVAL;
65
Andi Kleen928cf8c2005-12-12 22:17:10 -080066 addr = pci_dev_base(seg, bus, devfn);
67 if (!addr)
68 return pci_conf1_read(seg,bus,devfn,reg,len,value);
69
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 switch (len) {
71 case 1:
72 *value = readb(addr + reg);
73 break;
74 case 2:
75 *value = readw(addr + reg);
76 break;
77 case 4:
78 *value = readl(addr + reg);
79 break;
80 }
81
82 return 0;
83}
84
85static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
86 unsigned int devfn, int reg, int len, u32 value)
87{
Al Viro8b8a4e32005-12-15 09:17:44 +000088 char __iomem *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089
Andi Kleen928cf8c2005-12-12 22:17:10 -080090 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
92 return -EINVAL;
93
Andi Kleen928cf8c2005-12-12 22:17:10 -080094 addr = pci_dev_base(seg, bus, devfn);
95 if (!addr)
96 return pci_conf1_write(seg,bus,devfn,reg,len,value);
97
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 switch (len) {
99 case 1:
100 writeb(value, addr + reg);
101 break;
102 case 2:
103 writew(value, addr + reg);
104 break;
105 case 4:
106 writel(value, addr + reg);
107 break;
108 }
109
110 return 0;
111}
112
113static struct pci_raw_ops pci_mmcfg = {
114 .read = pci_mmcfg_read,
115 .write = pci_mmcfg_write,
116};
117
Andi Kleend6ece542005-12-12 22:17:11 -0800118/* K8 systems have some devices (typically in the builtin northbridge)
119 that are only accessible using type1
120 Normally this can be expressed in the MCFG by not listing them
121 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
122 Instead try to discover all devices on bus 0 that are unreachable using MM
123 and fallback for them.
124 We only do this for bus 0/seg 0 */
125static __init void unreachable_devices(void)
126{
127 int i;
128 for (i = 0; i < 32; i++) {
129 u32 val1;
Al Viro8b8a4e32005-12-15 09:17:44 +0000130 char __iomem *addr;
Andi Kleend6ece542005-12-12 22:17:11 -0800131
132 pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1);
133 if (val1 == 0xffffffff)
134 continue;
135 addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0));
136 if (addr == NULL|| readl(addr) != val1) {
137 set_bit(i, &fallback_slots);
138 }
139 }
140}
141
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142static int __init pci_mmcfg_init(void)
143{
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700144 int i;
145
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
147 return 0;
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700148
149 acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
150 if ((pci_mmcfg_config_num == 0) ||
151 (pci_mmcfg_config == NULL) ||
152 (pci_mmcfg_config[0].base_address == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 return 0;
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 /* RED-PEN i386 doesn't do _nocache right now */
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700156 pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
157 if (pci_mmcfg_virt == NULL) {
158 printk("PCI: Can not allocate memory for mmconfig structures\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 return 0;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700160 }
161 for (i = 0; i < pci_mmcfg_config_num; ++i) {
162 pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
163 pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
164 if (!pci_mmcfg_virt[i].virt) {
165 printk("PCI: Cannot map mmconfig aperture for segment %d\n",
166 pci_mmcfg_config[i].pci_segment_group_number);
167 return 0;
168 }
169 printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
170 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
Andi Kleend6ece542005-12-12 22:17:11 -0800172 unreachable_devices();
173
Linus Torvalds1da177e2005-04-16 15:20:36 -0700174 raw_pci_ops = &pci_mmcfg;
175 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
176
177 return 0;
178}
179
180arch_initcall(pci_mmcfg_init);