patch-2.3.99-pre2 linux/arch/alpha/kernel/core_pyxis.c
Next file: linux/arch/alpha/kernel/core_tsunami.c
Previous file: linux/arch/alpha/kernel/core_cia.c
Back to the patch index
Back to the overall index
- Lines: 645
- Date:
Wed Dec 31 16:00:00 1969
- Orig file:
v2.3.99-pre1/linux/arch/alpha/kernel/core_pyxis.c
- Orig date:
Thu Mar 2 14:36:22 2000
diff -u --recursive --new-file v2.3.99-pre1/linux/arch/alpha/kernel/core_pyxis.c linux/arch/alpha/kernel/core_pyxis.c
@@ -1,644 +0,0 @@
-/*
- * linux/arch/alpha/kernel/core_pyxis.c
- *
- * Based on code written by David A Rusling (david.rusling@reo.mts.dec.com).
- *
- * Code common to all PYXIS core logic chips.
- */
-
-#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>
-
-#include "proto.h"
-#include "irq_impl.h"
-#include "pci_impl.h"
-
-
-/* NOTE: Herein are back-to-back mb instructions. They are magic.
- One plausible explanation is that the I/O controller does not properly
- handle the system transaction. Another involves timing. Ho hum. */
-
-/*
- * BIOS32-style PCI interface:
- */
-
-#define DEBUG_CONFIG 0
-#if DEBUG_CONFIG
-# define DBG_CNF(args) printk args
-#else
-# define DBG_CNF(args)
-#endif
-
-
-/*
- * Given a bus, device, and function number, compute resulting
- * configuration space address and setup the PYXIS_HAXR2 register
- * accordingly. It is therefore not safe to have concurrent
- * invocations to configuration space access routines, but there
- * really shouldn't be any need for this.
- *
- * Type 0:
- *
- * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
- * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | | |D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|0|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * 31:11 Device select bit.
- * 10:8 Function number
- * 7:2 Register number
- *
- * Type 1:
- *
- * 3 3|3 3 2 2|2 2 2 2|2 2 2 2|1 1 1 1|1 1 1 1|1 1
- * 3 2|1 0 9 8|7 6 5 4|3 2 1 0|9 8 7 6|5 4 3 2|1 0 9 8|7 6 5 4|3 2 1 0
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | | | | | | | | | | |B|B|B|B|B|B|B|B|D|D|D|D|D|F|F|F|R|R|R|R|R|R|0|1|
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- *
- * 31:24 reserved
- * 23:16 bus number (8 bits = 128 possible buses)
- * 15:11 Device number (5 bits)
- * 10:8 function number
- * 7:2 register number
- *
- * Notes:
- * The function number selects which function of a multi-function device
- * (e.g., SCSI and Ethernet).
- *
- * The register selects a DWORD (32 bit) register offset. Hence it
- * doesn't get shifted by 2 bits as we want to "drop" the bottom two
- * bits.
- */
-
-static int
-mk_conf_addr(struct pci_dev *dev, int where, unsigned long *pci_addr,
- unsigned char *type1)
-{
- u8 bus = dev->bus->number;
- u8 device_fn = dev->devfn;
-
- *type1 = (bus == 0) ? 0 : 1;
- *pci_addr = (bus << 16) | (device_fn << 8) | (where);
-
- DBG_CNF(("mk_conf_addr(bus=%d ,device_fn=0x%x, where=0x%x,"
- " returning address 0x%p\n"
- bus, device_fn, where, *pci_addr));
-
- return 0;
-}
-
-static unsigned int
-conf_read(unsigned long addr, unsigned char type1)
-{
- unsigned long flags;
- unsigned int stat0, value, temp;
- unsigned int pyxis_cfg = 0;
-
- __save_and_cli(flags); /* avoid getting hit by machine check */
-
- /* Reset status register to avoid losing errors. */
- stat0 = *(vuip)PYXIS_ERR;
- *(vuip)PYXIS_ERR = stat0; mb();
- temp = *(vuip)PYXIS_ERR; /* re-read to force write */
-
- /* If Type1 access, must set PYXIS CFG. */
- if (type1) {
- pyxis_cfg = *(vuip)PYXIS_CFG;
- *(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb();
- temp = *(vuip)PYXIS_CFG; /* re-read to force write */
- }
-
- mb();
- draina();
- mcheck_expected(0) = 1;
- mcheck_taken(0) = 0;
- mb();
-
- /* Access configuration space. */
- value = *(vuip)addr;
- mb();
- mb(); /* magic */
-
- if (mcheck_taken(0)) {
- mcheck_taken(0) = 0;
- value = 0xffffffffU;
- mb();
- }
- mcheck_expected(0) = 0;
- mb();
-
- /* If Type1 access, must reset IOC CFG so normal IO space ops work. */
- if (type1) {
- *(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb();
- temp = *(vuip)PYXIS_CFG; /* re-read to force write */
- }
-
- __restore_flags(flags);
-
- DBG_CNF(("conf_read(addr=0x%lx, type1=%d) = %#x\n",
- addr, type1, value));
-
- return value;
-}
-
-static void
-conf_write(unsigned long addr, unsigned int value, unsigned char type1)
-{
- unsigned long flags;
- unsigned int stat0, temp;
- unsigned int pyxis_cfg = 0;
-
- __save_and_cli(flags); /* avoid getting hit by machine check */
-
- /* Reset status register to avoid losing errors. */
- stat0 = *(vuip)PYXIS_ERR;
- *(vuip)PYXIS_ERR = stat0; mb();
- temp = *(vuip)PYXIS_ERR; /* re-read to force write */
-
- /* If Type1 access, must set PYXIS CFG. */
- if (type1) {
- pyxis_cfg = *(vuip)PYXIS_CFG;
- *(vuip)PYXIS_CFG = (pyxis_cfg & ~3L) | 1; mb();
- temp = *(vuip)PYXIS_CFG; /* re-read to force write */
- }
-
- mb();
- draina();
- mcheck_expected(0) = 1;
- mcheck_taken(0) = 0;
- mb();
-
- /* Access configuration space. */
- *(vuip)addr = value;
- mb();
- temp = *(vuip)addr; /* read back to force the write */
- mcheck_expected(0) = 0;
- mb();
-
- /* If Type1 access, must reset IOC CFG so normal IO space ops work. */
- if (type1) {
- *(vuip)PYXIS_CFG = pyxis_cfg & ~3L; mb();
- temp = *(vuip)PYXIS_CFG; /* re-read to force write */
- }
-
- __restore_flags(flags);
-
- DBG_CNF(("conf_write(addr=%#lx, value=%#x, type1=%d)\n",
- addr, value, type1));
-}
-
-static int
-pyxis_read_config_byte(struct pci_dev *dev, int where, u8 *value)
-{
- unsigned long addr, pci_addr;
- unsigned char type1;
-
- if (mk_conf_addr(dev, where, &pci_addr, &type1))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- addr = (pci_addr << 5) + 0x00 + PYXIS_CONF;
- *value = conf_read(addr, type1) >> ((where & 3) * 8);
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pyxis_read_config_word(struct pci_dev *dev, int where, u16 *value)
-{
- unsigned long addr, pci_addr;
- unsigned char type1;
-
- if (mk_conf_addr(dev, where, &pci_addr, &type1))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- addr = (pci_addr << 5) + 0x08 + PYXIS_CONF;
- *value = conf_read(addr, type1) >> ((where & 3) * 8);
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pyxis_read_config_dword(struct pci_dev *dev, int where, u32 *value)
-{
- unsigned long addr, pci_addr;
- unsigned char type1;
-
- if (mk_conf_addr(dev, where, &pci_addr, &type1))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- addr = (pci_addr << 5) + 0x18 + PYXIS_CONF;
- *value = conf_read(addr, type1);
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pyxis_write_config(struct pci_dev *dev, int where, u32 value, long mask)
-{
- unsigned long addr, pci_addr;
- unsigned char type1;
-
- if (mk_conf_addr(dev, where, &pci_addr, &type1))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- addr = (pci_addr << 5) + mask + PYXIS_CONF;
- conf_write(addr, value << ((where & 3) * 8), type1);
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int
-pyxis_write_config_byte(struct pci_dev *dev, int where, u8 value)
-{
- return pyxis_write_config(dev, where, value, 0x00);
-}
-
-static int
-pyxis_write_config_word(struct pci_dev *dev, int where, u16 value)
-{
- return pyxis_write_config(dev, where, value, 0x08);
-}
-
-static int
-pyxis_write_config_dword(struct pci_dev *dev, int where, u32 value)
-{
- return pyxis_write_config(dev, where, value, 0x18);
-}
-
-struct pci_ops pyxis_pci_ops =
-{
- read_byte: pyxis_read_config_byte,
- read_word: pyxis_read_config_word,
- read_dword: pyxis_read_config_dword,
- write_byte: pyxis_write_config_byte,
- write_word: pyxis_write_config_word,
- write_dword: pyxis_write_config_dword
-};
-
-/* Note mask bit is true for ENABLED irqs. */
-static unsigned long cached_irq_mask;
-
-static inline void
-pyxis_update_irq_hw(unsigned long mask)
-{
- *(vulp)PYXIS_INT_MASK = mask;
- mb();
- *(vulp)PYXIS_INT_MASK;
-}
-
-static inline void
-pyxis_enable_irq(unsigned int irq)
-{
- pyxis_update_irq_hw(cached_irq_mask |= 1UL << (irq - 16));
-}
-
-static void
-pyxis_disable_irq(unsigned int irq)
-{
- pyxis_update_irq_hw(cached_irq_mask &= ~(1UL << (irq - 16)));
-}
-
-static unsigned int
-pyxis_startup_irq(unsigned int irq)
-{
- pyxis_enable_irq(irq);
- return 0;
-}
-
-static void
-pyxis_end_irq(unsigned int irq)
-{
- if (!(irq_desc[irq].status & (IRQ_DISABLED|IRQ_INPROGRESS)))
- pyxis_enable_irq(irq);
-}
-
-static void
-pyxis_mask_and_ack_irq(unsigned int irq)
-{
- unsigned long bit = 1UL << (irq - 16);
- unsigned long mask = cached_irq_mask &= ~bit;
-
- /* Disable the interrupt. */
- *(vulp)PYXIS_INT_MASK = mask;
- wmb();
- /* Ack PYXIS PCI interrupt. */
- *(vulp)PYXIS_INT_REQ = bit;
- mb();
- /* Re-read to force both writes. */
- *(vulp)PYXIS_INT_MASK;
-}
-
-static struct hw_interrupt_type pyxis_irq_type = {
- typename: "PYXIS",
- startup: pyxis_startup_irq,
- shutdown: pyxis_disable_irq,
- enable: pyxis_enable_irq,
- disable: pyxis_disable_irq,
- ack: pyxis_mask_and_ack_irq,
- end: pyxis_end_irq,
-};
-
-void
-pyxis_device_interrupt(unsigned long vector, struct pt_regs *regs)
-{
- unsigned long pld;
- unsigned int i;
-
- /* Read the interrupt summary register of PYXIS */
- pld = *(vulp)PYXIS_INT_REQ;
- pld &= cached_irq_mask;
-
- /*
- * Now for every possible bit set, work through them and call
- * the appropriate interrupt handler.
- */
- while (pld) {
- i = ffz(~pld);
- pld &= pld - 1; /* clear least bit set */
- if (i == 7)
- isa_device_interrupt(vector, regs);
- else
- handle_irq(16+i, regs);
- }
-}
-
-void __init
-init_pyxis_irqs(unsigned long ignore_mask)
-{
- long i;
-
- *(vulp)PYXIS_INT_MASK = 0; /* disable all */
- *(vulp)PYXIS_INT_REQ = -1; /* flush all */
- mb();
-
- /* Send -INTA pulses to clear any pending interrupts ...*/
- *(vuip) PYXIS_IACK_SC;
-
- for (i = 16; i < 48; ++i) {
- if ((ignore_mask >> i) & 1)
- continue;
- irq_desc[i].status = IRQ_DISABLED | IRQ_LEVEL;
- irq_desc[i].handler = &pyxis_irq_type;
- }
-
- setup_irq(16+7, &isa_cascade_irqaction);
-}
-
-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();
- *(vuip)PYXIS_CTRL;
- 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();
- *(vuip)PYXIS_CTRL;
- mb();
-
- __restore_flags(flags);
-}
-
-static void __init
-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)
-{
- struct pci_controler *hose;
- unsigned int temp;
-
- /* Set up error reporting. Make sure CPU_PE is OFF in the mask. */
- temp = *(vuip)PYXIS_ERR_MASK;
- *(vuip)PYXIS_ERR_MASK = temp & ~4;
-
- /* Enable master/target abort. */
- temp = *(vuip)PYXIS_ERR;
- *(vuip)PYXIS_ERR = temp | 0x180;
-
- /* 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. */
- *(vuip)PYXIS_CFG = 0;
-
- /* Zero the HAEs. */
- *(vuip)PYXIS_HAE_MEM = 0;
- *(vuip)PYXIS_HAE_IO = 0;
-
- /* Finally, check that the PYXIS_CTRL1 has IOA_BEN set for
- enabling byte/word PCI bus space(s) access. */
- temp = *(vuip)PYXIS_CTRL1;
- *(vuip)PYXIS_CTRL1 = temp | 1;
-
- /* Syncronize with all previous changes. */
- mb();
- *(vuip)PYXIS_REV;
-
- /*
- * 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 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.
- *
- * 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.
- */
-
-#if 1
- /* ??? There's some bit of syncronization wrt writing new tlb
- entries that's missing. Sometimes it works, sometimes invalid
- tlb machine checks, sometimes hard lockup. And this just within
- the boot sequence.
-
- I've tried extra memory barriers, extra alignment, pyxis
- register reads, tlb flushes, and loopback tlb accesses.
-
- I guess the pyxis revision in the sx164 is just too buggy... */
-
- hose->sg_isa = hose->sg_pci = NULL;
- __direct_map_base = 0x40000000;
- __direct_map_size = 0x80000000;
-
- *(vuip)PYXIS_W0_BASE = 0x40000000 | 1;
- *(vuip)PYXIS_W0_MASK = (0x40000000 - 1) & 0xfff00000;
- *(vuip)PYXIS_T0_BASE = 0;
-
- *(vuip)PYXIS_W1_BASE = 0x80000000 | 1;
- *(vuip)PYXIS_W1_MASK = (0x40000000 - 1) & 0xfff00000;
- *(vuip)PYXIS_T1_BASE = 0;
-
- *(vuip)PYXIS_W2_BASE = 0;
- *(vuip)PYXIS_W3_BASE = 0;
-
- alpha_mv.mv_pci_tbi = NULL;
- mb();
-#else
- /* ??? NetBSD hints that page tables must be aligned to 32K,
- possibly due to a hardware bug. This is over-aligned
- from the 8K alignment one would expect for an 8MB window.
- No description of what CIA revisions affected. */
- hose->sg_isa = iommu_arena_new(hose, 0x00800000, 0x00800000, 0x08000);
- hose->sg_pci = iommu_arena_new(hose, 0xc0000000, 0x08000000, 0x20000);
- __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);
-
- alpha_mv.mv_pci_tbi(hose, 0, -1);
-#endif
-}
-
-static inline void
-pyxis_pci_clr_err(void)
-{
- unsigned int tmp;
-
- tmp = *(vuip)PYXIS_ERR;
- *(vuip)PYXIS_ERR = tmp;
- mb();
- *(vuip)PYXIS_ERR; /* re-read to force write */
-}
-
-void
-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 */
- draina();
- pyxis_pci_clr_err();
- wrmces(0x7);
- mb();
-
- 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)