blob: 18f371fe37f89639f06ba4e24f876ea9854fd003 [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;
Andi Kleen31030392006-01-27 02:03:50 +010032 if (cfg_num >= pci_mmcfg_config_num)
33 break;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070034 cfg = pci_mmcfg_virt[cfg_num].cfg;
35 if (cfg->pci_segment_group_number != seg)
36 continue;
37 if ((cfg->start_bus_number <= bus) &&
38 (cfg->end_bus_number >= bus))
39 return pci_mmcfg_virt[cfg_num].virt;
40 }
Andi Kleen31030392006-01-27 02:03:50 +010041
42 /* Handle more broken MCFG tables on Asus etc.
43 They only contain a single entry for bus 0-0. Assume
44 this applies to all busses. */
45 cfg = &pci_mmcfg_config[0];
46 if (pci_mmcfg_config_num == 1 &&
47 cfg->pci_segment_group_number == 0 &&
48 (cfg->start_bus_number | cfg->end_bus_number) == 0)
Andi Kleen1de6bf32006-02-03 21:51:29 +010049 return pci_mmcfg_virt[0].virt;
Andi Kleen31030392006-01-27 02:03:50 +010050
51 /* Fall back to type 0 */
Al Virocc598532006-02-03 20:28:01 -050052 return NULL;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070053}
54
Al Viro8b8a4e32005-12-15 09:17:44 +000055static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070056{
Al Viro8b8a4e32005-12-15 09:17:44 +000057 char __iomem *addr;
Andi Kleend6ece542005-12-12 22:17:11 -080058 if (seg == 0 && bus == 0 && test_bit(PCI_SLOT(devfn), &fallback_slots))
59 return NULL;
60 addr = get_virt(seg, bus);
Andi Kleen928cf8c2005-12-12 22:17:10 -080061 if (!addr)
62 return NULL;
63 return addr + ((bus << 20) | (devfn << 12));
Linus Torvalds1da177e2005-04-16 15:20:36 -070064}
65
66static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
67 unsigned int devfn, int reg, int len, u32 *value)
68{
Al Viro8b8a4e32005-12-15 09:17:44 +000069 char __iomem *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070070
Andi Kleen928cf8c2005-12-12 22:17:10 -080071 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
Linus Torvalds1da177e2005-04-16 15:20:36 -070072 if (unlikely(!value || (bus > 255) || (devfn > 255) || (reg > 4095)))
73 return -EINVAL;
74
Andi Kleen928cf8c2005-12-12 22:17:10 -080075 addr = pci_dev_base(seg, bus, devfn);
76 if (!addr)
77 return pci_conf1_read(seg,bus,devfn,reg,len,value);
78
Linus Torvalds1da177e2005-04-16 15:20:36 -070079 switch (len) {
80 case 1:
81 *value = readb(addr + reg);
82 break;
83 case 2:
84 *value = readw(addr + reg);
85 break;
86 case 4:
87 *value = readl(addr + reg);
88 break;
89 }
90
91 return 0;
92}
93
94static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
95 unsigned int devfn, int reg, int len, u32 value)
96{
Al Viro8b8a4e32005-12-15 09:17:44 +000097 char __iomem *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098
Andi Kleen928cf8c2005-12-12 22:17:10 -080099 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
101 return -EINVAL;
102
Andi Kleen928cf8c2005-12-12 22:17:10 -0800103 addr = pci_dev_base(seg, bus, devfn);
104 if (!addr)
105 return pci_conf1_write(seg,bus,devfn,reg,len,value);
106
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107 switch (len) {
108 case 1:
109 writeb(value, addr + reg);
110 break;
111 case 2:
112 writew(value, addr + reg);
113 break;
114 case 4:
115 writel(value, addr + reg);
116 break;
117 }
118
119 return 0;
120}
121
122static struct pci_raw_ops pci_mmcfg = {
123 .read = pci_mmcfg_read,
124 .write = pci_mmcfg_write,
125};
126
Andi Kleend6ece542005-12-12 22:17:11 -0800127/* K8 systems have some devices (typically in the builtin northbridge)
128 that are only accessible using type1
129 Normally this can be expressed in the MCFG by not listing them
130 and assigning suitable _SEGs, but this isn't implemented in some BIOS.
131 Instead try to discover all devices on bus 0 that are unreachable using MM
132 and fallback for them.
133 We only do this for bus 0/seg 0 */
134static __init void unreachable_devices(void)
135{
136 int i;
137 for (i = 0; i < 32; i++) {
138 u32 val1;
Al Viro8b8a4e32005-12-15 09:17:44 +0000139 char __iomem *addr;
Andi Kleend6ece542005-12-12 22:17:11 -0800140
141 pci_conf1_read(0, 0, PCI_DEVFN(i,0), 0, 4, &val1);
142 if (val1 == 0xffffffff)
143 continue;
144 addr = pci_dev_base(0, 0, PCI_DEVFN(i, 0));
145 if (addr == NULL|| readl(addr) != val1) {
146 set_bit(i, &fallback_slots);
147 }
148 }
149}
150
Linus Torvalds1da177e2005-04-16 15:20:36 -0700151static int __init pci_mmcfg_init(void)
152{
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700153 int i;
154
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155 if ((pci_probe & PCI_PROBE_MMCONF) == 0)
156 return 0;
Greg Kroah-Hartman54549392005-06-23 17:35:56 -0700157
158 acpi_table_parse(ACPI_MCFG, acpi_parse_mcfg);
159 if ((pci_mmcfg_config_num == 0) ||
160 (pci_mmcfg_config == NULL) ||
161 (pci_mmcfg_config[0].base_address == 0))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 return 0;
163
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 /* RED-PEN i386 doesn't do _nocache right now */
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700165 pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) * pci_mmcfg_config_num, GFP_KERNEL);
166 if (pci_mmcfg_virt == NULL) {
167 printk("PCI: Can not allocate memory for mmconfig structures\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 return 0;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700169 }
170 for (i = 0; i < pci_mmcfg_config_num; ++i) {
171 pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
172 pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].base_address, MMCONFIG_APER_SIZE);
173 if (!pci_mmcfg_virt[i].virt) {
174 printk("PCI: Cannot map mmconfig aperture for segment %d\n",
175 pci_mmcfg_config[i].pci_segment_group_number);
176 return 0;
177 }
178 printk(KERN_INFO "PCI: Using MMCONFIG at %x\n", pci_mmcfg_config[i].base_address);
179 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180
Andi Kleend6ece542005-12-12 22:17:11 -0800181 unreachable_devices();
182
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 raw_pci_ops = &pci_mmcfg;
184 pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
185
186 return 0;
187}
188
189arch_initcall(pci_mmcfg_init);