Logo Search packages:      
Sourcecode: linux-2.6 version File versions  Download package

sys_nautilus.c

/*
 *    linux/arch/alpha/kernel/sys_nautilus.c
 *
 *    Copyright (C) 1995 David A Rusling
 *    Copyright (C) 1998 Richard Henderson
 *    Copyright (C) 1999 Alpha Processor, Inc.,
 *          (David Daniel, Stig Telfer, Soohoon Lee)
 *
 * Code supporting NAUTILUS systems.
 *
 *
 * NAUTILUS has the following I/O features:
 *
 * a) Driven by AMD 751 aka IRONGATE (northbridge):
 *     4 PCI slots
 *     1 AGP slot
 *
 * b) Driven by ALI M1543C (southbridge)
 *     2 ISA slots
 *     2 IDE connectors
 *     1 dual drive capable FDD controller
 *     2 serial ports
 *     1 ECP/EPP/SP parallel port
 *     2 USB ports
 */

#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/reboot.h>
#include <linux/bootmem.h>
#include <linux/bitops.h>

#include <asm/ptrace.h>
#include <asm/system.h>
#include <asm/dma.h>
#include <asm/irq.h>
#include <asm/mmu_context.h>
#include <asm/io.h>
#include <asm/pci.h>
#include <asm/pgtable.h>
#include <asm/core_irongate.h>
#include <asm/hwrpb.h>
#include <asm/tlbflush.h>

#include "proto.h"
#include "err_impl.h"
#include "irq_impl.h"
#include "pci_impl.h"
#include "machvec_impl.h"


static void __init
nautilus_init_irq(void)
{
      if (alpha_using_srm) {
            alpha_mv.device_interrupt = srm_device_interrupt;
      }

      init_i8259a_irqs();
      common_init_isa_dma();
}

static int __init
nautilus_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
{
      /* Preserve the IRQ set up by the console.  */

      u8 irq;
      pci_read_config_byte(dev, PCI_INTERRUPT_LINE, &irq);
      return irq;
}

void
nautilus_kill_arch(int mode)
{
      struct pci_bus *bus = pci_isa_hose->bus;
      u32 pmuport;
      int off;

      switch (mode) {
      case LINUX_REBOOT_CMD_RESTART:
            if (! alpha_using_srm) {
                  u8 t8;
                  pci_bus_read_config_byte(bus, 0x38, 0x43, &t8);
                  pci_bus_write_config_byte(bus, 0x38, 0x43, t8 | 0x80);
                  outb(1, 0x92);
                  outb(0, 0x92);
                  /* NOTREACHED */
            }
            break;

      case LINUX_REBOOT_CMD_POWER_OFF:
            /* Assume M1543C */
            off = 0x2000;           /* SLP_TYPE = 0, SLP_EN = 1 */
            pci_bus_read_config_dword(bus, 0x88, 0x10, &pmuport);
            if (!pmuport) {
                  /* M1535D/D+ */
                  off = 0x3400;     /* SLP_TYPE = 5, SLP_EN = 1 */
                  pci_bus_read_config_dword(bus, 0x88, 0xe0, &pmuport);
            }
            pmuport &= 0xfffe;
            outw(0xffff, pmuport);  /* Clear pending events. */
            outw(off, pmuport + 4);
            /* NOTREACHED */
            break;
      }
}

/* Perform analysis of a machine check that arrived from the system (NMI) */

static void
naut_sys_machine_check(unsigned long vector, unsigned long la_ptr,
                   struct pt_regs *regs)
{
      printk("PC %lx RA %lx\n", regs->pc, regs->r26);
      irongate_pci_clr_err();
}

/* Machine checks can come from two sources - those on the CPU and those
   in the system.  They are analysed separately but all starts here.  */

void
nautilus_machine_check(unsigned long vector, unsigned long la_ptr,
                   struct pt_regs *regs)
{
      char *mchk_class;

      /* Now for some analysis.  Machine checks fall into two classes --
         those picked up by the system, and those picked up by the CPU.
         Add to that the two levels of severity - correctable or not.  */

      if (vector == SCB_Q_SYSMCHK
          && ((IRONGATE0->dramms & 0x300) == 0x300)) {
            unsigned long nmi_ctl;

            /* Clear ALI NMI */
            nmi_ctl = inb(0x61);
            nmi_ctl |= 0x0c;
            outb(nmi_ctl, 0x61);
            nmi_ctl &= ~0x0c;
            outb(nmi_ctl, 0x61);

            /* Write again clears error bits.  */
            IRONGATE0->stat_cmd = IRONGATE0->stat_cmd & ~0x100;
            mb();
            IRONGATE0->stat_cmd;

            /* Write again clears error bits.  */
            IRONGATE0->dramms = IRONGATE0->dramms;
            mb();
            IRONGATE0->dramms;

            draina();
            wrmces(0x7);
            mb();
            return;
      }

      if (vector == SCB_Q_SYSERR)
            mchk_class = "Correctable";
      else if (vector == SCB_Q_SYSMCHK)
            mchk_class = "Fatal";
      else {
            ev6_machine_check(vector, la_ptr, regs);
            return;
      }

      printk(KERN_CRIT "NAUTILUS Machine check 0x%lx "
                   "[%s System Machine Check (NMI)]\n",
             vector, mchk_class);

      naut_sys_machine_check(vector, la_ptr, regs);

      /* Tell the PALcode to clear the machine check */
      draina();
      wrmces(0x7);
      mb();
}

extern void free_reserved_mem(void *, void *);

static struct resource irongate_mem = {
      .name = "Irongate PCI MEM",
      .flags      = IORESOURCE_MEM,
};

void __init
nautilus_init_pci(void)
{
      struct pci_controller *hose = hose_head;
      struct pci_bus *bus;
      struct pci_dev *irongate;
      unsigned long bus_align, bus_size, pci_mem;
      unsigned long memtop = max_low_pfn << PAGE_SHIFT;

      /* Scan our single hose.  */
      bus = pci_scan_bus(0, alpha_mv.pci_ops, hose);
      hose->bus = bus;

      irongate = pci_find_slot(0, 0);
      bus->self = irongate;
      bus->resource[1] = &irongate_mem;

      pci_bus_size_bridges(bus);

      /* IO port range. */
      bus->resource[0]->start = 0;
      bus->resource[0]->end = 0xffff;

      /* Set up PCI memory range - limit is hardwired to 0xffffffff,
         base must be at aligned to 16Mb. */
      bus_align = bus->resource[1]->start;
      bus_size = bus->resource[1]->end + 1 - bus_align;
      if (bus_align < 0x1000000UL)
            bus_align = 0x1000000UL;

      pci_mem = (0x100000000UL - bus_size) & -bus_align;

      bus->resource[1]->start = pci_mem;
      bus->resource[1]->end = 0xffffffffUL;
      if (request_resource(&iomem_resource, bus->resource[1]) < 0)
            printk(KERN_ERR "Failed to request MEM on hose 0\n");

      if (pci_mem < memtop)
            memtop = pci_mem;
      if (memtop > alpha_mv.min_mem_address) {
            free_reserved_mem(__va(alpha_mv.min_mem_address),
                          __va(memtop));
            printk("nautilus_init_pci: %ldk freed\n",
                  (memtop - alpha_mv.min_mem_address) >> 10);
      }

      if ((IRONGATE0->dev_vendor >> 16) > 0x7006)     /* Albacore? */
            IRONGATE0->pci_mem = pci_mem;

      pci_bus_assign_resources(bus);
      pci_fixup_irqs(alpha_mv.pci_swizzle, alpha_mv.pci_map_irq);
}

/*
 * The System Vectors
 */

struct alpha_machine_vector nautilus_mv __initmv = {
      .vector_name            = "Nautilus",
      DO_EV6_MMU,
      DO_DEFAULT_RTC,
      DO_IRONGATE_IO,
      .machine_check          = nautilus_machine_check,
      .max_isa_dma_address    = ALPHA_MAX_ISA_DMA_ADDRESS,
      .min_io_address         = DEFAULT_IO_BASE,
      .min_mem_address  = IRONGATE_DEFAULT_MEM_BASE,

      .nr_irqs          = 16,
      .device_interrupt = isa_device_interrupt,

      .init_arch        = irongate_init_arch,
      .init_irq         = nautilus_init_irq,
      .init_rtc         = common_init_rtc,
      .init_pci         = nautilus_init_pci,
      .kill_arch        = nautilus_kill_arch,
      .pci_map_irq            = nautilus_map_irq,
      .pci_swizzle            = common_swizzle,
};
ALIAS_MV(nautilus)

Generated by  Doxygen 1.6.0   Back to index