aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386/pci/mmconfig.c
diff options
context:
space:
mode:
authorOGAWA Hirofumi <hogawa@miraclelinux.com>2006-12-22 20:00:43 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-23 17:06:33 -0500
commit8d1c481960ba833362aa78245fdff12e3804f8b5 (patch)
treed6315d4442f686b232770c4a89416c7453287fdd /arch/i386/pci/mmconfig.c
parente1d9fd2e3d33b2fec3207171ec8ca6e71d5c81c7 (diff)
[PATCH] arch/i386/pci/mmconfig.c tlb flush fix
We use the fixmap for accessing pci config space in pci_mmcfg_read/write(). The problem is in pci_exp_set_dev_base(). It is caching a last accessed address to avoid calling set_fixmap_nocache() whenever pci_mmcfg_read/write() is used. static inline void pci_exp_set_dev_base(int bus, int devfn) { u32 dev_base = base | (bus << 20) | (devfn << 12); if (dev_base != mmcfg_last_accessed_device) { mmcfg_last_accessed_device = dev_base; set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); } } cpu0 cpu1 --------------------------------------------------------------------------- pci_mmcfg_read("device-A") pci_exp_set_dev_base() set_fixmap_nocache() pci_mmcfg_read("device-B") pci_exp_set_dev_base() set_fixmap_nocache() pci_mmcfg_read("device-B") pci_exp_set_dev_base() /* doesn't flush tlb */ But if cpus accessed the above order, the second pci_mmcfg_read() on cpu0 doesn't flush the TLB, because "mmcfg_last_accessed_device" is device-B. So, second pci_mmcfg_read() on cpu0 accesses a device-A via a previous TLB cache. This problem became the cause of several strange behavior. This patches fixes this situation by adds "mmcfg_last_accessed_cpu" check. [ Alternatively, we could make a per-cpu mapping area or something. Not that it's probably worth it, but if we wanted to avoid all locking and instead just disable preemption, that would be the way to go. --Linus ] Signed-off-by: OGAWA Hirofumi <hogawa@miraclelinux.com> Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/i386/pci/mmconfig.c')
-rw-r--r--arch/i386/pci/mmconfig.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/arch/i386/pci/mmconfig.c b/arch/i386/pci/mmconfig.c
index c6b6d9bbc453..e2616a266e13 100644
--- a/arch/i386/pci/mmconfig.c
+++ b/arch/i386/pci/mmconfig.c
@@ -26,6 +26,7 @@
26 26
27/* The base address of the last MMCONFIG device accessed */ 27/* The base address of the last MMCONFIG device accessed */
28static u32 mmcfg_last_accessed_device; 28static u32 mmcfg_last_accessed_device;
29static int mmcfg_last_accessed_cpu;
29 30
30static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32); 31static DECLARE_BITMAP(fallback_slots, MAX_CHECK_BUS*32);
31 32
@@ -73,8 +74,11 @@ static u32 get_base_addr(unsigned int seg, int bus, unsigned devfn)
73static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn) 74static void pci_exp_set_dev_base(unsigned int base, int bus, int devfn)
74{ 75{
75 u32 dev_base = base | (bus << 20) | (devfn << 12); 76 u32 dev_base = base | (bus << 20) | (devfn << 12);
76 if (dev_base != mmcfg_last_accessed_device) { 77 int cpu = smp_processor_id();
78 if (dev_base != mmcfg_last_accessed_device ||
79 cpu != mmcfg_last_accessed_cpu) {
77 mmcfg_last_accessed_device = dev_base; 80 mmcfg_last_accessed_device = dev_base;
81 mmcfg_last_accessed_cpu = cpu;
78 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base); 82 set_fixmap_nocache(FIX_PCIE_MCFG, dev_base);
79 } 83 }
80} 84}