vserver 1.9.3
[linux-2.6.git] / arch / i386 / pci / mmconfig.c
1 /*
2  * Copyright (C) 2004 Matthew Wilcox <matthew@wil.cx>
3  * Copyright (C) 2004 Intel Corp.
4  *
5  * This code is released under the GNU General Public License version 2.
6  */
7
8 /*
9  * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
10  */
11
12 #include <linux/pci.h>
13 #include <linux/init.h>
14 #include "pci.h"
15
16 /* The physical address of the MMCONFIG aperture.  Set from ACPI tables. */
17 u32 pci_mmcfg_base_addr;
18
19 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
20
21 /* The base address of the last MMCONFIG device accessed */
22 static u32 mmcfg_last_accessed_device;
23
24 /*
25  * Functions for accessing PCI configuration space with MMCONFIG accesses
26  */
27
28 static inline void pci_exp_set_dev_base(int bus, int devfn)
29 {
30         u32 dev_base = pci_mmcfg_base_addr | (bus << 20) | (devfn << 12);
31         if (dev_base != mmcfg_last_accessed_device) {
32                 mmcfg_last_accessed_device = dev_base;
33                 set_fixmap(FIX_PCIE_MCFG, dev_base);
34         }
35 }
36
37 static int pci_mmcfg_read(int seg, int bus, int devfn, int reg, int len, u32 *value)
38 {
39         unsigned long flags;
40
41         if (!value || (bus > 255) || (devfn > 255) || (reg > 4095))
42                 return -EINVAL;
43
44         spin_lock_irqsave(&pci_config_lock, flags);
45
46         pci_exp_set_dev_base(bus, devfn);
47
48         switch (len) {
49         case 1:
50                 *value = readb(mmcfg_virt_addr + reg);
51                 break;
52         case 2:
53                 *value = readw(mmcfg_virt_addr + reg);
54                 break;
55         case 4:
56                 *value = readl(mmcfg_virt_addr + reg);
57                 break;
58         }
59
60         spin_unlock_irqrestore(&pci_config_lock, flags);
61
62         return 0;
63 }
64
65 static int pci_mmcfg_write(int seg, int bus, int devfn, int reg, int len, u32 value)
66 {
67         unsigned long flags;
68
69         if ((bus > 255) || (devfn > 255) || (reg > 4095)) 
70                 return -EINVAL;
71
72         spin_lock_irqsave(&pci_config_lock, flags);
73
74         pci_exp_set_dev_base(bus, devfn);
75
76         switch (len) {
77         case 1:
78                 writeb(value, mmcfg_virt_addr + reg);
79                 break;
80         case 2:
81                 writew(value, mmcfg_virt_addr + reg);
82                 break;
83         case 4:
84                 writel(value, mmcfg_virt_addr + reg);
85                 break;
86         }
87
88         /* Dummy read to flush PCI write */
89         readl(mmcfg_virt_addr);
90
91         spin_unlock_irqrestore(&pci_config_lock, flags);
92
93         return 0;
94 }
95
96 static struct pci_raw_ops pci_mmcfg = {
97         .read =         pci_mmcfg_read,
98         .write =        pci_mmcfg_write,
99 };
100
101 static int __init pci_mmcfg_init(void)
102 {
103         if ((pci_probe & PCI_PROBE_MMCONF) == 0)
104                 goto out;
105         if (!pci_mmcfg_base_addr)
106                 goto out;
107
108         printk(KERN_INFO "PCI: Using MMCONFIG\n");
109         raw_pci_ops = &pci_mmcfg;
110         pci_probe = (pci_probe & ~PCI_PROBE_MASK) | PCI_PROBE_MMCONF;
111
112  out:
113         return 0;
114 }
115
116 arch_initcall(pci_mmcfg_init);