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