2 * Copyright (C) 2004 Matthew Wilcox <matthew@wil.cx>
3 * Copyright (C) 2004 Intel Corp.
5 * This code is released under the GNU General Public License version 2.
9 * mmconfig.c - Low-level direct PCI config space access via MMCONFIG
12 #include <linux/pci.h>
13 #include <linux/init.h>
16 /* The physical address of the MMCONFIG aperture. Set from ACPI tables. */
17 u32 pci_mmcfg_base_addr
;
19 #define mmcfg_virt_addr ((void __iomem *) fix_to_virt(FIX_PCIE_MCFG))
21 /* The base address of the last MMCONFIG device accessed */
22 static u32 mmcfg_last_accessed_device
;
25 * Functions for accessing PCI configuration space with MMCONFIG accesses
28 static inline void pci_exp_set_dev_base(int bus
, int devfn
)
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
);
37 static int pci_mmcfg_read(int seg
, int bus
, int devfn
, int reg
, int len
, u32
*value
)
41 if (!value
|| (bus
> 255) || (devfn
> 255) || (reg
> 4095))
44 spin_lock_irqsave(&pci_config_lock
, flags
);
46 pci_exp_set_dev_base(bus
, devfn
);
50 *value
= readb(mmcfg_virt_addr
+ reg
);
53 *value
= readw(mmcfg_virt_addr
+ reg
);
56 *value
= readl(mmcfg_virt_addr
+ reg
);
60 spin_unlock_irqrestore(&pci_config_lock
, flags
);
65 static int pci_mmcfg_write(int seg
, int bus
, int devfn
, int reg
, int len
, u32 value
)
69 if ((bus
> 255) || (devfn
> 255) || (reg
> 4095))
72 spin_lock_irqsave(&pci_config_lock
, flags
);
74 pci_exp_set_dev_base(bus
, devfn
);
78 writeb(value
, mmcfg_virt_addr
+ reg
);
81 writew(value
, mmcfg_virt_addr
+ reg
);
84 writel(value
, mmcfg_virt_addr
+ reg
);
88 /* Dummy read to flush PCI write */
89 readl(mmcfg_virt_addr
);
91 spin_unlock_irqrestore(&pci_config_lock
, flags
);
96 static struct pci_raw_ops pci_mmcfg
= {
97 .read
= pci_mmcfg_read
,
98 .write
= pci_mmcfg_write
,
101 static int __init
pci_mmcfg_init(void)
103 if ((pci_probe
& PCI_PROBE_MMCONF
) == 0)
105 if (!pci_mmcfg_base_addr
)
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
;
116 arch_initcall(pci_mmcfg_init
);