blob: 0847735bb31e3c3679b9cafa93812ed6dbeff6c3 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +03003 *
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 * 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>
Arjan van de Ven946f2ee2006-04-07 19:49:30 +020012#include <asm/e820.h>
13
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include "pci.h"
15
Chuck Ebbertead2bfe2006-06-15 04:41:52 -040016/* aperture is up to 256MB but BIOS may reserve less */
17#define MMCONFIG_APER_MIN (2 * 1024*1024)
18#define MMCONFIG_APER_MAX (256 * 1024*1024)
19
Andi Kleen8c30b1a742006-04-07 19:50:12 +020020/* Verify the first 16 busses. We assume that systems with more busses
21 get MCFG right. */
Olivier Galibertb7867392007-02-13 13:26:20 +010022#define PCI_MMCFG_MAX_CHECK_BUS 16
Andi Kleend6ece542005-12-12 22:17:11 -080023
Linus Torvalds1da177e2005-04-16 15:20:36 -070024/* Static virtual mapping of the MMCONFIG aperture */
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070025struct mmcfg_virt {
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +030026 struct acpi_mcfg_allocation *cfg;
Al Viro8b8a4e32005-12-15 09:17:44 +000027 char __iomem *virt;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070028};
29static struct mmcfg_virt *pci_mmcfg_virt;
Linus Torvalds1da177e2005-04-16 15:20:36 -070030
Al Viro8b8a4e32005-12-15 09:17:44 +000031static char __iomem *get_virt(unsigned int seg, unsigned bus)
Linus Torvalds1da177e2005-04-16 15:20:36 -070032{
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070033 int cfg_num = -1;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +030034 struct acpi_mcfg_allocation *cfg;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070035
36 while (1) {
37 ++cfg_num;
Andi Kleen31030392006-01-27 02:03:50 +010038 if (cfg_num >= pci_mmcfg_config_num)
39 break;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070040 cfg = pci_mmcfg_virt[cfg_num].cfg;
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +030041 if (cfg->pci_segment != seg)
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070042 continue;
43 if ((cfg->start_bus_number <= bus) &&
44 (cfg->end_bus_number >= bus))
45 return pci_mmcfg_virt[cfg_num].virt;
46 }
Andi Kleen31030392006-01-27 02:03:50 +010047
48 /* Handle more broken MCFG tables on Asus etc.
49 They only contain a single entry for bus 0-0. Assume
50 this applies to all busses. */
51 cfg = &pci_mmcfg_config[0];
52 if (pci_mmcfg_config_num == 1 &&
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +030053 cfg->pci_segment == 0 &&
Andi Kleen31030392006-01-27 02:03:50 +010054 (cfg->start_bus_number | cfg->end_bus_number) == 0)
Andi Kleen1de6bf32006-02-03 21:51:29 +010055 return pci_mmcfg_virt[0].virt;
Andi Kleen31030392006-01-27 02:03:50 +010056
57 /* Fall back to type 0 */
Al Virocc598532006-02-03 20:28:01 -050058 return NULL;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070059}
60
Al Viro8b8a4e32005-12-15 09:17:44 +000061static char __iomem *pci_dev_base(unsigned int seg, unsigned int bus, unsigned int devfn)
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -070062{
Al Viro8b8a4e32005-12-15 09:17:44 +000063 char __iomem *addr;
Olivier Galibertb7867392007-02-13 13:26:20 +010064 if (seg == 0 && bus < PCI_MMCFG_MAX_CHECK_BUS &&
65 test_bit(32*bus + PCI_SLOT(devfn), pci_mmcfg_fallback_slots))
Andi Kleend6ece542005-12-12 22:17:11 -080066 return NULL;
67 addr = get_virt(seg, bus);
Andi Kleen928cf8c2005-12-12 22:17:10 -080068 if (!addr)
69 return NULL;
70 return addr + ((bus << 20) | (devfn << 12));
Linus Torvalds1da177e2005-04-16 15:20:36 -070071}
72
73static int pci_mmcfg_read(unsigned int seg, unsigned int bus,
74 unsigned int devfn, int reg, int len, u32 *value)
75{
Al Viro8b8a4e32005-12-15 09:17:44 +000076 char __iomem *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -070077
Andi Kleen928cf8c2005-12-12 22:17:10 -080078 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
Andi Kleenecc16ba2006-04-11 12:54:48 +020079 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095))) {
Andi Kleen49c93e82006-04-07 19:50:15 +020080 *value = -1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070081 return -EINVAL;
Andi Kleen49c93e82006-04-07 19:50:15 +020082 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070083
Andi Kleen928cf8c2005-12-12 22:17:10 -080084 addr = pci_dev_base(seg, bus, devfn);
85 if (!addr)
86 return pci_conf1_read(seg,bus,devfn,reg,len,value);
87
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 switch (len) {
89 case 1:
90 *value = readb(addr + reg);
91 break;
92 case 2:
93 *value = readw(addr + reg);
94 break;
95 case 4:
96 *value = readl(addr + reg);
97 break;
98 }
99
100 return 0;
101}
102
103static int pci_mmcfg_write(unsigned int seg, unsigned int bus,
104 unsigned int devfn, int reg, int len, u32 value)
105{
Al Viro8b8a4e32005-12-15 09:17:44 +0000106 char __iomem *addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700107
Andi Kleen928cf8c2005-12-12 22:17:10 -0800108 /* Why do we have this when nobody checks it. How about a BUG()!? -AK */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700109 if (unlikely((bus > 255) || (devfn > 255) || (reg > 4095)))
110 return -EINVAL;
111
Andi Kleen928cf8c2005-12-12 22:17:10 -0800112 addr = pci_dev_base(seg, bus, devfn);
113 if (!addr)
114 return pci_conf1_write(seg,bus,devfn,reg,len,value);
115
Linus Torvalds1da177e2005-04-16 15:20:36 -0700116 switch (len) {
117 case 1:
118 writeb(value, addr + reg);
119 break;
120 case 2:
121 writew(value, addr + reg);
122 break;
123 case 4:
124 writel(value, addr + reg);
125 break;
126 }
127
128 return 0;
129}
130
131static struct pci_raw_ops pci_mmcfg = {
132 .read = pci_mmcfg_read,
133 .write = pci_mmcfg_write,
134};
135
Olivier Galibertb7867392007-02-13 13:26:20 +0100136int __init pci_mmcfg_arch_init(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137{
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700138 int i;
Olivier Galibertb7867392007-02-13 13:26:20 +0100139 pci_mmcfg_virt = kmalloc(sizeof(*pci_mmcfg_virt) *
140 pci_mmcfg_config_num, GFP_KERNEL);
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700141 if (pci_mmcfg_virt == NULL) {
Dave Jones3095fc02006-10-20 14:45:33 -0700142 printk(KERN_ERR "PCI: Can not allocate memory for mmconfig structures\n");
Olivier Galibertb7867392007-02-13 13:26:20 +0100143 return 0;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700144 }
Olivier Galibertb7867392007-02-13 13:26:20 +0100145
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700146 for (i = 0; i < pci_mmcfg_config_num; ++i) {
147 pci_mmcfg_virt[i].cfg = &pci_mmcfg_config[i];
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300148 pci_mmcfg_virt[i].virt = ioremap_nocache(pci_mmcfg_config[i].address,
Chuck Ebbertead2bfe2006-06-15 04:41:52 -0400149 MMCONFIG_APER_MAX);
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700150 if (!pci_mmcfg_virt[i].virt) {
Dave Jones3095fc02006-10-20 14:45:33 -0700151 printk(KERN_ERR "PCI: Cannot map mmconfig aperture for "
152 "segment %d\n",
Alexey Starikovskiy15a58ed2007-02-02 19:48:22 +0300153 pci_mmcfg_config[i].pci_segment);
Olivier Galibertb7867392007-02-13 13:26:20 +0100154 return 0;
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700155 }
Olivier Galibertb7867392007-02-13 13:26:20 +0100156 printk(KERN_INFO "PCI: Using MMCONFIG at %Lx\n",
157 pci_mmcfg_config[i].address);
Greg Kroah-Hartman1cde8a12005-06-23 17:35:56 -0700158 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 raw_pci_ops = &pci_mmcfg;
Olivier Galibertb7867392007-02-13 13:26:20 +0100160 return 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161}