patch-2.3.43 linux/arch/alpha/kernel/core_pyxis.c
Next file: linux/arch/alpha/kernel/core_t2.c
Previous file: linux/arch/alpha/kernel/core_polaris.c
Back to the patch index
Back to the overall index
- Lines: 303
- Date:
Mon Feb 7 20:09:33 2000
- Orig file:
v2.3.42/linux/arch/alpha/kernel/core_pyxis.c
- Orig date:
Tue Dec 7 09:32:39 1999
diff -u --recursive --new-file v2.3.42/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c
@@ -6,20 +6,22 @@
* Code common to all PYXIS core logic chips.
*/
-#include <linux/kernel.h>
#include <linux/types.h>
+#include <linux/kernel.h>
+
+#define __EXTERN_INLINE inline
+#include <asm/io.h>
+#include <asm/core_pyxis.h>
+#undef __EXTERN_INLINE
+
#include <linux/pci.h>
#include <linux/sched.h>
#include <linux/init.h>
+#include <linux/bootmem.h>
#include <asm/ptrace.h>
#include <asm/system.h>
-#define __EXTERN_INLINE inline
-#include <asm/io.h>
-#include <asm/core_pyxis.h>
-#undef __EXTERN_INLINE
-
#include "proto.h"
#include "pci_impl.h"
@@ -284,6 +286,84 @@
write_dword: pyxis_write_config_dword
};
+void
+pyxis_pci_tbi(struct pci_controler *hose, dma_addr_t start, dma_addr_t end)
+{
+ wmb();
+ *(vip)PYXIS_TBIA = 3; /* Flush all locked and unlocked. */
+ mb();
+}
+
+/*
+ * Pass 1 and 2 have a broken scatter-gather tlb -- it cannot be invalidated.
+ * To work around this problem, we allocate mappings, and put the chip into
+ * DMA loopback mode to read a garbage page. This works by causing TLB
+ * misses, causing old entries to be purged to make room for the new entries
+ * coming in for the garbage page.
+ *
+ * Thanks to NetBSD sources for pointing out this bug. What a pain.
+ */
+
+static unsigned long broken_tbi_addr;
+
+#define BROKEN_TBI_READS 12
+
+static void
+pyxis_broken_pci_tbi(struct pci_controler *hose,
+ dma_addr_t start, dma_addr_t end)
+{
+ unsigned long flags;
+ unsigned long bus_addr;
+ unsigned int ctrl;
+ long i;
+
+ __save_and_cli(flags);
+
+ /* Put the chip into PCI loopback mode. */
+ mb();
+ ctrl = *(vuip)PYXIS_CTRL;
+ *(vuip)PYXIS_CTRL = ctrl | 4;
+ mb();
+
+ /* Read from PCI dense memory space at TBI_ADDR, skipping 64k
+ on each read. This forces SG TLB misses. It appears that
+ the TLB entries are "not quite LRU", meaning that we need
+ to read more times than there are actual tags. */
+
+ bus_addr = broken_tbi_addr;
+ for (i = 0; i < BROKEN_TBI_READS; ++i, bus_addr += 64*1024)
+ pyxis_readl(bus_addr);
+
+ /* Restore normal PCI operation. */
+ mb();
+ *(vuip)PYXIS_CTRL = ctrl;
+ mb();
+
+ __restore_flags(flags);
+}
+
+static void
+pyxis_enable_broken_tbi(struct pci_iommu_arena *arena)
+{
+ void *page;
+ unsigned long *ppte, ofs, pte;
+ long i, npages;
+
+ page = alloc_bootmem_pages(PAGE_SIZE);
+ pte = (virt_to_phys(page) >> (PAGE_SHIFT - 1)) | 1;
+ npages = (BROKEN_TBI_READS + 1) * 64*1024 / PAGE_SIZE;
+
+ ofs = iommu_arena_alloc(arena, npages);
+ ppte = arena->ptes + ofs;
+ for (i = 0; i < npages; ++i)
+ ppte[i] = pte;
+
+ broken_tbi_addr = pyxis_ioremap(arena->dma_base + ofs*PAGE_SIZE);
+ alpha_mv.mv_pci_tbi = pyxis_broken_pci_tbi;
+
+ printk("PYXIS: Enabling broken tbia workaround.\n");
+}
+
void __init
pyxis_init_arch(void)
{
@@ -306,84 +386,100 @@
*/
temp = *(vuip)PYXIS_ERR_MASK;
temp &= ~4;
- *(vuip)PYXIS_ERR_MASK = temp; mb();
- temp = *(vuip)PYXIS_ERR_MASK; /* re-read to force write */
+ *(vuip)PYXIS_ERR_MASK = temp;
+ mb();
+ *(vuip)PYXIS_ERR_MASK; /* re-read to force write */
+
+ temp = *(vuip)PYXIS_ERR;
+ temp |= 0x180; /* master/target abort */
+ *(vuip)PYXIS_ERR = temp;
+ mb();
+ *(vuip)PYXIS_ERR; /* re-read to force write */
- temp = *(vuip)PYXIS_ERR ;
- temp |= 0x180; /* master/target abort */
- *(vuip)PYXIS_ERR = temp; mb();
- temp = *(vuip)PYXIS_ERR; /* re-read to force write */
+ /*
+ * Create our single hose.
+ */
+
+ hose = alloc_pci_controler();
+ hose->io_space = &ioport_resource;
+ hose->mem_space = &iomem_resource;
+ hose->config_space = PYXIS_CONF;
+ hose->index = 0;
/*
- * Set up the PCI->physical memory translation windows.
- * For now, windows 2 and 3 are disabled. In the future, we may
- * want to use them to do scatter/gather DMA.
+ * Set up the PCI to main memory translation windows.
+ *
+ * Window 0 is scatter-gather 8MB at 8MB (for isa)
+ * Window 1 is scatter-gather 128MB at 3GB
+ * Window 2 is direct access 1GB at 1GB
+ * Window 3 is direct access 1GB at 2GB
+ * ??? We ought to scale window 1 with memory.
*
- * Window 0 goes at 2 GB and is 1 GB large.
- * Window 1 goes at 3 GB and is 1 GB large.
+ * We must actually use 2 windows to direct-map the 2GB space,
+ * because of an idiot-syncrasy of the CYPRESS chip. It may
+ * respond to a PCI bus address in the last 1MB of the 4GB
+ * address range.
*/
- *(vuip)PYXIS_W0_BASE = PYXIS_DMA_WIN0_BASE_DEFAULT | 1U;
- *(vuip)PYXIS_W0_MASK = (PYXIS_DMA_WIN0_SIZE_DEFAULT - 1) & 0xfff00000U;
- *(vuip)PYXIS_T0_BASE = PYXIS_DMA_WIN0_TRAN_DEFAULT >> 2;
-
- *(vuip)PYXIS_W1_BASE = PYXIS_DMA_WIN1_BASE_DEFAULT | 1U;
- *(vuip)PYXIS_W1_MASK = (PYXIS_DMA_WIN1_SIZE_DEFAULT - 1) & 0xfff00000U;
- *(vuip)PYXIS_T1_BASE = PYXIS_DMA_WIN1_TRAN_DEFAULT >> 2;
+ /* NetBSD hints that page tables must be aligned to 32K due
+ to a hardware bug. No description of what models affected. */
+ hose->sg_isa = iommu_arena_new(0x00800000, 0x00800000, 32768);
+ hose->sg_pci = iommu_arena_new(0xc0000000, 0x08000000, 32768);
+ __direct_map_base = 0x40000000;
+ __direct_map_size = 0x80000000;
+
+ *(vuip)PYXIS_W0_BASE = hose->sg_isa->dma_base | 3;
+ *(vuip)PYXIS_W0_MASK = (hose->sg_isa->size - 1) & 0xfff00000;
+ *(vuip)PYXIS_T0_BASE = virt_to_phys(hose->sg_isa->ptes) >> 2;
+
+ *(vuip)PYXIS_W1_BASE = hose->sg_pci->dma_base | 3;
+ *(vuip)PYXIS_W1_MASK = (hose->sg_pci->size - 1) & 0xfff00000;
+ *(vuip)PYXIS_T1_BASE = virt_to_phys(hose->sg_pci->ptes) >> 2;
+
+ *(vuip)PYXIS_W2_BASE = 0x40000000 | 1;
+ *(vuip)PYXIS_W2_MASK = (0x40000000 - 1) & 0xfff00000;
+ *(vuip)PYXIS_T2_BASE = 0;
+
+ *(vuip)PYXIS_W3_BASE = 0x80000000 | 1;
+ *(vuip)PYXIS_W3_MASK = (0x40000000 - 1) & 0xfff00000;
+ *(vuip)PYXIS_T3_BASE = 0;
+
+ /* Pass 1 and 2 (ie revision <= 1) have a broken TBIA. See the
+ complete description next to pyxis_broken_pci_tbi for details. */
+ if ((*(vuip)PYXIS_REV & 0xff) <= 1)
+ pyxis_enable_broken_tbi(hose->sg_pci);
- *(vuip)PYXIS_W2_BASE = 0x0;
- *(vuip)PYXIS_W3_BASE = 0x0;
- mb();
+ alpha_mv.mv_pci_tbi(hose, 0, -1);
/*
- * Next, clear the PYXIS_CFG register, which gets used
+ * Next, clear the PYXIS_CFG register, which gets used
* for PCI Config Space accesses. That is the way
* we want to use it, and we do not want to depend on
* what ARC or SRM might have left behind...
*/
- {
- unsigned int pyxis_cfg, temp;
- pyxis_cfg = *(vuip)PYXIS_CFG; mb();
- if (pyxis_cfg != 0) {
-#if 1
- printk("PYXIS_init: CFG was 0x%x\n", pyxis_cfg);
-#endif
- *(vuip)PYXIS_CFG = 0; mb();
- temp = *(vuip)PYXIS_CFG; /* re-read to force write */
- }
+ temp = *(vuip)PYXIS_CFG;
+ if (temp != 0) {
+ *(vuip)PYXIS_CFG = 0;
+ mb();
+ *(vuip)PYXIS_CFG; /* re-read to force write */
}
/* Zero the HAE. */
*(vuip)PYXIS_HAE_MEM = 0U; mb();
- *(vuip)PYXIS_HAE_MEM; /* re-read to force write */
+ *(vuip)PYXIS_HAE_MEM; /* re-read to force write */
*(vuip)PYXIS_HAE_IO = 0; mb();
- *(vuip)PYXIS_HAE_IO; /* re-read to force write */
+ *(vuip)PYXIS_HAE_IO; /* re-read to force write */
/*
* Finally, check that the PYXIS_CTRL1 has IOA_BEN set for
* enabling byte/word PCI bus space(s) access.
*/
- {
- unsigned int ctrl1;
- ctrl1 = *(vuip) PYXIS_CTRL1;
- if (!(ctrl1 & 1)) {
-#if 1
- printk("PYXIS_init: enabling byte/word PCI space\n");
-#endif
- *(vuip) PYXIS_CTRL1 = ctrl1 | 1; mb();
- ctrl1 = *(vuip)PYXIS_CTRL1; /* re-read */
- }
+ temp = *(vuip) PYXIS_CTRL1;
+ if (!(temp & 1)) {
+ *(vuip)PYXIS_CTRL1 = temp | 1;
+ mb();
+ *(vuip)PYXIS_CTRL1; /* re-read */
}
-
- /*
- * Create our single hose.
- */
-
- hose = alloc_pci_controler();
- hose->io_space = &ioport_resource;
- hose->mem_space = &iomem_resource;
- hose->config_space = PYXIS_CONF;
- hose->index = 0;
}
static inline void
@@ -401,6 +497,8 @@
pyxis_machine_check(unsigned long vector, unsigned long la_ptr,
struct pt_regs * regs)
{
+ int expected;
+
/* Clear the error before reporting anything. */
mb();
mb(); /* magic */
@@ -409,5 +507,23 @@
wrmces(0x7);
mb();
- process_mcheck_info(vector, la_ptr, regs, "PYXIS", mcheck_expected(0));
+ expected = mcheck_expected(0);
+ if (!expected && vector == 0x660) {
+ struct el_common *com;
+ struct el_common_EV5_uncorrectable_mcheck *ev5;
+ struct el_PYXIS_sysdata_mcheck *pyxis;
+
+ com = (void *)la_ptr;
+ ev5 = (void *)(la_ptr + com->proc_offset);
+ pyxis = (void *)(la_ptr + com->sys_offset);
+
+ if (com->code == 0x202) {
+ printk(KERN_CRIT "PYXIS PCI machine check: err0=%08x "
+ "err1=%08x err2=%08x\n",
+ (int) pyxis->pci_err0, (int) pyxis->pci_err1,
+ (int) pyxis->pci_err2);
+ expected = 1;
+ }
+ }
+ process_mcheck_info(vector, la_ptr, regs, "PYXIS", expected);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)