diff options
Diffstat (limited to 'target/linux/ar71xx/patches-3.2/111-MIPS-ath79-add-a-workaround-for-a-PCI-controller-bug.patch')
-rw-r--r-- | target/linux/ar71xx/patches-3.2/111-MIPS-ath79-add-a-workaround-for-a-PCI-controller-bug.patch | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/target/linux/ar71xx/patches-3.2/111-MIPS-ath79-add-a-workaround-for-a-PCI-controller-bug.patch b/target/linux/ar71xx/patches-3.2/111-MIPS-ath79-add-a-workaround-for-a-PCI-controller-bug.patch new file mode 100644 index 0000000..11391ab --- /dev/null +++ b/target/linux/ar71xx/patches-3.2/111-MIPS-ath79-add-a-workaround-for-a-PCI-controller-bug.patch @@ -0,0 +1,134 @@ +From b2ee3bd8706521c9bbf43405c767010927c101e5 Mon Sep 17 00:00:00 2001 +From: Gabor Juhos <juhosg@openwrt.org> +Date: Mon, 21 Nov 2011 17:57:51 +0100 +Subject: [PATCH 11/35] MIPS: ath79: add a workaround for a PCI controller bug in AR7240 SoCs + +The PCI controller of the AR724X SoCs has a hardware +bag. If the BAR0 register of the PCI device is set to +the proper base address, the memory address space of +the device is not accessible. + +When the device driver tries to access the memory +address space of the PCI device, it leads to data +bus error, similiar to this: + +Data bus error, epc == 801f69a0, ra == 801f698c +Oops[#1]: +Cpu 0 +$ 0 : 00000000 00000061 deadbeef 000000ff +$ 4 : 00000000 000000ff 00000014 00000000 +$ 8 : ff000000 fffffffc 00000000 00000000 +$12 : 000001f5 00000006 00000000 6e637920 +$16 : 81ca4000 81ca0260 81ca4000 804d70f0 +$20 : fffffff4 0000002b 803ad4c4 00000000 +$24 : 00000003 00000000 +$28 : 81c20000 81c21c60 00000000 801f698c +Hi : 00000000 +Lo : 00000000 +epc : 801f69a0 ath9k_hw_init+0xd0/0xa70 + Not tainted +ra : 801f698c ath9k_hw_init+0xbc/0xa70 +Status: 1000c103 KERNEL EXL IE +Cause : 1080001c +PrId : 00019374 (MIPS 24Kc) +Modules linked in: +Process swapper (pid: 1, threadinfo=81c20000, task=81c18000, tls=00000000) +Stack : 00000000 00000000 00000000 00000000 81c21c78 81ca0260 00000000 804d70f0 + 81ca0260 81c21cc0 81ca0e80 81ca0260 81ca4000 804d70f0 fffffff4 0000002b + 803ad4c4 00000000 00000000 801e3ae8 81c9d080 81ca0e80 b0000000 800b9b9c + 00000008 81c9d000 8031aeb0 802d38a0 00000000 81c14c00 81c14c60 00000000 + 81ca0e80 81ca0260 b0000000 801f08a4 81c9c820 81c21d48 81c9c820 80144320 + ... +Call Trace: +[<801f69a0>] ath9k_hw_init+0xd0/0xa70 +[<801e3ae8>] ath9k_init_device+0x174/0x680 +[<801f08a4>] ath_pci_probe+0x27c/0x380 +[<8019e490>] pci_device_probe+0x74/0x9c +[<801bfadc>] driver_probe_device+0x9c/0x1b4 +[<801bfcb0>] __driver_attach+0xbc/0xc4 +[<801bea0c>] bus_for_each_dev+0x5c/0x98 +[<801bf394>] bus_add_driver+0x1d0/0x2a4 +[<801c0364>] driver_register+0x8c/0x16c +[<8019e72c>] __pci_register_driver+0x4c/0xe4 +[<803d3d40>] ath9k_init+0x3c/0x88 +[<80060930>] do_one_initcall+0x3c/0x1cc +[<803c297c>] kernel_init+0xa4/0x138 +[<80063c04>] kernel_thread_helper+0x10/0x18 + +Signed-off-by: Gabor Juhos <juhosg@openwrt.org> + +v2: - apply the workaround on AR7240 only + - remove unrelated defines +--- + arch/mips/pci/pci-ar724x.c | 36 +++++++++++++++++++++++++++++++++++- + 1 files changed, 35 insertions(+), 1 deletions(-) + +--- a/arch/mips/pci/pci-ar724x.c ++++ b/arch/mips/pci/pci-ar724x.c +@@ -9,6 +9,7 @@ + */ + + #include <linux/pci.h> ++#include <asm/mach-ath79/ath79.h> + #include <asm/mach-ath79/pci.h> + + #define AR724X_PCI_CFG_BASE 0x14000000 +@@ -16,9 +17,14 @@ + #define AR724X_PCI_MEM_BASE 0x10000000 + #define AR724X_PCI_MEM_SIZE 0x08000000 + ++#define AR7240_BAR0_WAR_VALUE 0xffff ++ + static DEFINE_SPINLOCK(ar724x_pci_lock); + static void __iomem *ar724x_pci_devcfg_base; + ++static u32 ar724x_pci_bar0_value; ++static bool ar724x_pci_bar0_is_cached; ++ + static int ar724x_pci_read(struct pci_bus *bus, unsigned int devfn, int where, + int size, uint32_t *value) + { +@@ -56,7 +62,14 @@ static int ar724x_pci_read(struct pci_bu + } + + spin_unlock_irqrestore(&ar724x_pci_lock, flags); +- *value = data; ++ ++ if (where == PCI_BASE_ADDRESS_0 && size == 4 && ++ ar724x_pci_bar0_is_cached) { ++ /* use the cached value */ ++ *value = ar724x_pci_bar0_value; ++ } else { ++ *value = data; ++ } + + return PCIBIOS_SUCCESSFUL; + } +@@ -72,6 +85,27 @@ static int ar724x_pci_write(struct pci_b + if (devfn) + return PCIBIOS_DEVICE_NOT_FOUND; + ++ if (soc_is_ar7240() && where == PCI_BASE_ADDRESS_0 && size == 4) { ++ if (value != 0xffffffff) { ++ /* ++ * WAR for a hw issue. If the BAR0 register of the ++ * device is set to the proper base address, the ++ * memory space of the device is not accessible. ++ * ++ * Cache the intended value so it can be read back, ++ * and write a SoC specific constant value to the ++ * BAR0 register in order to make the device memory ++ * accessible. ++ */ ++ ar724x_pci_bar0_is_cached = true; ++ ar724x_pci_bar0_value = value; ++ ++ value = AR7240_BAR0_WAR_VALUE; ++ } else { ++ ar724x_pci_bar0_is_cached = false; ++ } ++ } ++ + base = ar724x_pci_devcfg_base; + + spin_lock_irqsave(&ar724x_pci_lock, flags); |