diff -urN 2.4.5pre5/arch/alpha/kernel/core_cia.c cia/arch/alpha/kernel/core_cia.c --- 2.4.5pre5/arch/alpha/kernel/core_cia.c Sun Apr 1 01:17:07 2001 +++ cia/arch/alpha/kernel/core_cia.c Wed May 23 00:44:18 2001 @@ -297,80 +297,48 @@ * It cannot be invalidated. Rather than hard code the pass numbers, * actually try the tbia to see if it works. */ - -void -cia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) -{ - wmb(); - *(vip)CIA_IOC_PCI_TBIA = 3; /* Flush all locked and unlocked. */ - mb(); - *(vip)CIA_IOC_PCI_TBIA; -} - -/* - * Fixup attempt number 1. - * - * Write zeros directly into the tag registers. +/* Even if the tbia works, we cannot use it. It effectively locks the + * chip (as well as direct write to the tag registers) if there is a + * SG DMA operation in progress. This is true at least for PYXIS rev. 1. */ - -static void -cia_pci_tbi_try1(struct pci_controller *hose, - dma_addr_t start, dma_addr_t end) -{ - wmb(); - *(vip)CIA_IOC_TB_TAGn(0) = 0; - *(vip)CIA_IOC_TB_TAGn(1) = 0; - *(vip)CIA_IOC_TB_TAGn(2) = 0; - *(vip)CIA_IOC_TB_TAGn(3) = 0; - *(vip)CIA_IOC_TB_TAGn(4) = 0; - *(vip)CIA_IOC_TB_TAGn(5) = 0; - *(vip)CIA_IOC_TB_TAGn(6) = 0; - *(vip)CIA_IOC_TB_TAGn(7) = 0; - mb(); - *(vip)CIA_IOC_TB_TAGn(0); -} - -#if 0 /* - * Fixup attempt number 2. This is the method NT and NetBSD use. + * This is the method NT and NetBSD use. * * 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. */ -#define CIA_BROKEN_TBI_TRY2_BASE 0xE0000000 +#define CIA_BROKEN_TBIA_BASE 0xE0000000 +#define CIA_BROKEN_TBIA_SIZE 1024 -static void __init -cia_enable_broken_tbi_try2(void) +static inline void +cia_enable_broken_tbia(void) { unsigned long *ppte, pte; long i; - ppte = __alloc_bootmem(PAGE_SIZE, 32768, 0); + /* Use minimal 1K map. */ + ppte = __alloc_bootmem(CIA_BROKEN_TBIA_SIZE, 32768, 0); pte = (virt_to_phys(ppte) >> (PAGE_SHIFT - 1)) | 1; - for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); ++i) + for (i = 0; i < CIA_BROKEN_TBIA_SIZE / sizeof(unsigned long); ++i) ppte[i] = pte; - *(vip)CIA_IOC_PCI_W3_BASE = CIA_BROKEN_TBI_TRY2_BASE | 3; - *(vip)CIA_IOC_PCI_W3_MASK = (PAGE_SIZE - 1) & 0xfff00000; + *(vip)CIA_IOC_PCI_W3_BASE = CIA_BROKEN_TBIA_BASE | 3; + *(vip)CIA_IOC_PCI_W3_MASK = (CIA_BROKEN_TBIA_SIZE*1024 - 1) + & 0xfff00000; *(vip)CIA_IOC_PCI_T3_BASE = virt_to_phys(ppte) >> 2; } -static void -cia_pci_tbi_try2(struct pci_controller *hose, +void +cia_pci_tbi(struct pci_controller *hose, dma_addr_t start, dma_addr_t end) { - unsigned long flags; unsigned long bus_addr; int ctrl; - long i; - - __save_and_cli(flags); /* Put the chip into PCI loopback mode. */ - mb(); ctrl = *(vip)CIA_IOC_CIA_CTRL; *(vip)CIA_IOC_CIA_CTRL = ctrl | CIA_CTRL_PCI_LOOP_EN; mb(); @@ -382,21 +350,25 @@ TLB entries are not quite LRU, meaning that we need to read more times than there are actual tags. The 2117x docs claim strict round-robin. Oh well, we've come this far... */ - - bus_addr = cia_ioremap(CIA_BROKEN_TBI_TRY2_BASE); - for (i = 0; i < 12; ++i, bus_addr += 32768) - cia_readl(bus_addr); + /* Even better - as seen on the PYXIS rev 1 the TLB tags 0-3 can + be filled by the TLB misses *only once* after being invalidated + (by tbia or direct write). Next misses won't update them even + though the lock bits are cleared. Tags 4-7 are "quite LRU" though, + so use them and read at window 3 base exactly 4 times. -ink */ + + bus_addr = cia_ioremap(CIA_BROKEN_TBIA_BASE); + + cia_readl(bus_addr + 0x00000); + cia_readl(bus_addr + 0x08000); + cia_readl(bus_addr + 0x10000); + cia_readl(bus_addr + 0x18000); /* Restore normal PCI operation. */ mb(); *(vip)CIA_IOC_CIA_CTRL = ctrl; mb(); *(vip)CIA_IOC_CIA_CTRL; - mb(); - - __restore_flags(flags); } -#endif static void __init verify_tb_operation(void) @@ -440,10 +412,6 @@ /* First, verify we can read back what we've written. If this fails, we can't be sure of any of the other testing we're going to do, so bail. */ - /* ??? Actually, we could do the work with machine checks. - By passing this register update test, we pretty much - guarantee that cia_pci_tbi_try1 works. If this test - fails, cia_pci_tbi_try2 might still work. */ temp = *(vip)CIA_IOC_TB_TAGn(0); if (temp != tag0) { @@ -487,27 +455,7 @@ } printk("pci: passed sg loopback i/o read test\n"); - /* Third, try to invalidate the TLB. */ - - cia_pci_tbi(arena->hose, 0, -1); - temp = *(vip)CIA_IOC_TB_TAGn(0); - if (temp & 1) { - cia_pci_tbi_try1(arena->hose, 0, -1); - - temp = *(vip)CIA_IOC_TB_TAGn(0); - if (temp & 1) { - printk("pci: failed tbia test; " - "no usable workaround\n"); - goto failed; - } - - alpha_mv.mv_pci_tbi = cia_pci_tbi_try1; - printk("pci: failed tbia test; workaround 1 succeeded\n"); - } else { - printk("pci: passed tbia test\n"); - } - - /* Fourth, verify the TLB snoops the EV5's caches when + /* Third, verify the TLB snoops the EV5's caches when doing a tlb fill. */ data0 = 0x5adda15e; @@ -531,7 +479,7 @@ } printk("pci: passed pte write cache snoop test\n"); - /* Fifth, verify that a previously invalid PTE entry gets + /* Fourth, verify that a previously invalid PTE entry gets filled from the page table. */ data0 = 0xabcdef12; @@ -558,7 +506,7 @@ printk("pci: passed valid tag invalid pte reload test\n"); } - /* Sixth, verify machine checks are working. Test invalid + /* Fifth, verify machine checks are working. Test invalid pte under the same valid tag as we used above. */ mcheck_expected(0) = 1; @@ -571,9 +519,19 @@ printk("pci: %s pci machine check test\n", mcheck_taken(0) ? "passed" : "failed"); + printk("pci: broken tbia workaround enabled\n"); + /* Clean up after the tests. */ arena->ptes[4] = 0; arena->ptes[5] = 0; + + /* Disable tags 0-3 with the lock bit */ + wmb(); + *(vip)CIA_IOC_TB_TAGn(0) = 2; + *(vip)CIA_IOC_TB_TAGn(1) = 2; + *(vip)CIA_IOC_TB_TAGn(2) = 2; + *(vip)CIA_IOC_TB_TAGn(3) = 2; + alpha_mv.mv_pci_tbi(arena->hose, 0, -1); exit: @@ -706,7 +664,7 @@ *(vip)CIA_IOC_PCI_W2_MASK = (0x40000000 - 1) & 0xfff00000; *(vip)CIA_IOC_PCI_T2_BASE = 0x40000000 >> 2; - *(vip)CIA_IOC_PCI_W3_BASE = 0; + cia_enable_broken_tbia(); } void __init