1
0
Fork 0

Merge branch 'x86/generalize-visws' into x86/core

hifive-unleashed-5.1
Ingo Molnar 2008-07-11 21:22:18 +02:00
commit 6c82a000a2
36 changed files with 865 additions and 909 deletions

View File

@ -181,12 +181,12 @@ config X86_64_SMP
config X86_HT
bool
depends on SMP
depends on (X86_32 && !(X86_VISWS || X86_VOYAGER)) || X86_64
depends on (X86_32 && !X86_VOYAGER) || X86_64
default y
config X86_BIOS_REBOOT
bool
depends on !X86_VISWS && !X86_VOYAGER
depends on !X86_VOYAGER
default y
config X86_TRAMPOLINE
@ -232,13 +232,13 @@ config SMP
config X86_FIND_SMP_CONFIG
def_bool y
depends on X86_MPPARSE || X86_VOYAGER || X86_VISWS
depends on X86_MPPARSE || X86_VOYAGER
if ACPI
config X86_MPPARSE
def_bool y
bool "Enable MPS table"
depends on X86_LOCAL_APIC && !X86_VISWS
depends on X86_LOCAL_APIC
help
For old smp systems that do not have proper acpi support. Newer systems
(esp with 64bit cpus) with acpi support, MADT and DSDT will override it
@ -247,7 +247,7 @@ endif
if !ACPI
config X86_MPPARSE
def_bool y
depends on X86_LOCAL_APIC && !X86_VISWS
depends on X86_LOCAL_APIC
endif
choice
@ -281,18 +281,6 @@ config X86_VOYAGER
If you do not specifically know you have a Voyager based machine,
say N here, otherwise the kernel you build will not be bootable.
config X86_VISWS
bool "SGI 320/540 (Visual Workstation)"
depends on X86_32 && PCI
help
The SGI Visual Workstation series is an IA32-based workstation
based on SGI systems chips with some legacy PC hardware attached.
Say Y here to create a kernel to run on the SGI 320 or 540.
A kernel compiled for the Visual Workstation will not run on PCs
and vice versa. See <file:Documentation/sgi-visws.txt> for details.
config X86_GENERICARCH
bool "Generic architecture"
depends on X86_32
@ -363,6 +351,18 @@ config X86_VSMP
endchoice
config X86_VISWS
bool "SGI 320/540 (Visual Workstation)"
depends on X86_32 && PCI && !X86_VOYAGER && X86_MPPARSE && PCI_GODIRECT
help
The SGI Visual Workstation series is an IA32-based workstation
based on SGI systems chips with some legacy PC hardware attached.
Say Y here to create a kernel to run on the SGI 320 or 540.
A kernel compiled for the Visual Workstation will run on general
PCs as well. See <file:Documentation/sgi-visws.txt> for details.
config SCHED_NO_NO_OMIT_FRAME_POINTER
def_bool y
prompt "Single-depth WCHAN output"
@ -391,7 +391,7 @@ config VMI
bool "VMI Guest support"
select PARAVIRT
depends on X86_32
depends on !(X86_VISWS || X86_VOYAGER)
depends on !X86_VOYAGER
help
VMI provides a paravirtualized interface to the VMware ESX server
(it could be used by other hypervisors in theory too, but is not
@ -402,7 +402,7 @@ config KVM_CLOCK
bool "KVM paravirtualized clock"
select PARAVIRT
select PARAVIRT_CLOCK
depends on !(X86_VISWS || X86_VOYAGER)
depends on !X86_VOYAGER
help
Turning on this option will allow you to run a paravirtualized clock
when running over the KVM hypervisor. Instead of relying on a PIT
@ -413,7 +413,7 @@ config KVM_CLOCK
config KVM_GUEST
bool "KVM Guest support"
select PARAVIRT
depends on !(X86_VISWS || X86_VOYAGER)
depends on !X86_VOYAGER
help
This option enables various optimizations for running under the KVM
hypervisor.
@ -422,7 +422,7 @@ source "arch/x86/lguest/Kconfig"
config PARAVIRT
bool "Enable paravirtualization code"
depends on !(X86_VISWS || X86_VOYAGER)
depends on !X86_VOYAGER
help
This changes the kernel so it can modify itself when it is run
under a hypervisor, potentially improving performance significantly
@ -628,7 +628,7 @@ source "kernel/Kconfig.preempt"
config X86_UP_APIC
bool "Local APIC support on uniprocessors"
depends on X86_32 && !SMP && !(X86_VISWS || X86_VOYAGER || X86_GENERICARCH)
depends on X86_32 && !SMP && !(X86_VOYAGER || X86_GENERICARCH)
help
A local APIC (Advanced Programmable Interrupt Controller) is an
integrated interrupt controller in the CPU. If you have a single-CPU
@ -653,11 +653,11 @@ config X86_UP_IOAPIC
config X86_LOCAL_APIC
def_bool y
depends on X86_64 || (X86_32 && (X86_UP_APIC || ((X86_VISWS || SMP) && !X86_VOYAGER) || X86_GENERICARCH))
depends on X86_64 || (X86_32 && (X86_UP_APIC || (SMP && !X86_VOYAGER) || X86_GENERICARCH))
config X86_IO_APIC
def_bool y
depends on X86_64 || (X86_32 && (X86_UP_IOAPIC || (SMP && !(X86_VISWS || X86_VOYAGER)) || X86_GENERICARCH))
depends on X86_64 || (X86_32 && (X86_UP_IOAPIC || (SMP && !X86_VOYAGER) || X86_GENERICARCH))
config X86_VISWS_APIC
def_bool y
@ -711,7 +711,7 @@ config X86_MCE_NONFATAL
config X86_MCE_P4THERMAL
bool "check for P4 thermal throttling interrupt."
depends on X86_32 && X86_MCE && (X86_UP_APIC || SMP) && !X86_VISWS
depends on X86_32 && X86_MCE && (X86_UP_APIC || SMP)
help
Enabling this feature will cause a message to be printed when the P4
enters thermal throttling.
@ -1414,7 +1414,7 @@ config X86_APM_BOOT
menuconfig APM
tristate "APM (Advanced Power Management) BIOS support"
depends on X86_32 && PM_SLEEP && !X86_VISWS
depends on X86_32 && PM_SLEEP
---help---
APM is a BIOS specification for saving power using several different
techniques. This is mostly useful for battery powered laptops with
@ -1561,7 +1561,7 @@ config PCI
choice
prompt "PCI access mode"
depends on X86_32 && PCI && !X86_VISWS
depends on X86_32 && PCI
default PCI_GOANY
---help---
On PCI systems, the BIOS can be used to detect the PCI devices and
@ -1598,12 +1598,12 @@ endchoice
config PCI_BIOS
def_bool y
depends on X86_32 && !X86_VISWS && PCI && (PCI_GOBIOS || PCI_GOANY)
depends on X86_32 && PCI && (PCI_GOBIOS || PCI_GOANY)
# x86-64 doesn't support PCI BIOS access from long mode so always go direct.
config PCI_DIRECT
def_bool y
depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC) || X86_VISWS)
depends on PCI && (X86_64 || (PCI_GODIRECT || PCI_GOANY || PCI_GOOLPC))
config PCI_MMCONFIG
def_bool y
@ -1663,7 +1663,7 @@ if X86_32
config ISA
bool "ISA support"
depends on !(X86_VOYAGER || X86_VISWS)
depends on !X86_VOYAGER
help
Find out whether you have ISA slots on your motherboard. ISA is the
name of a bus system, i.e. the way the CPU talks to the other stuff
@ -1690,7 +1690,7 @@ config EISA
source "drivers/eisa/Kconfig"
config MCA
bool "MCA support" if !(X86_VISWS || X86_VOYAGER)
bool "MCA support" if !X86_VOYAGER
default y if X86_VOYAGER
help
MicroChannel Architecture is found in some IBM PS/2 machines and

View File

@ -113,10 +113,6 @@ mcore-y := arch/x86/mach-default/
mflags-$(CONFIG_X86_VOYAGER) := -Iinclude/asm-x86/mach-voyager
mcore-$(CONFIG_X86_VOYAGER) := arch/x86/mach-voyager/
# VISWS subarch support
mflags-$(CONFIG_X86_VISWS) := -Iinclude/asm-x86/mach-visws
mcore-$(CONFIG_X86_VISWS) := arch/x86/mach-visws/
# generic subarchitecture
mflags-$(CONFIG_X86_GENERICARCH):= -Iinclude/asm-x86/mach-generic
fcore-$(CONFIG_X86_GENERICARCH) += arch/x86/mach-generic/

View File

@ -19,6 +19,7 @@ obj-y := process_$(BITS).o signal_$(BITS).o entry_$(BITS).o
obj-y += traps_$(BITS).o irq_$(BITS).o
obj-y += time_$(BITS).o ioport.o ldt.o
obj-y += setup.o i8259.o irqinit_$(BITS).o setup_percpu.o
obj-$(CONFIG_X86_VISWS) += visws_quirks.o
obj-$(CONFIG_X86_32) += probe_roms_32.o
obj-$(CONFIG_X86_32) += sys_i386_32.o i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o

View File

@ -974,7 +974,7 @@ void __cpuinit setup_local_APIC(void)
* Double-check whether this APIC is really registered.
*/
if (!apic_id_registered())
BUG();
WARN_ON_ONCE(1);
/*
* Intel recommends to set DFR, LDR and TPR before enabling

View File

@ -1313,6 +1313,11 @@ void __init e820_reserve_resources(void)
}
}
/*
* Non-standard memory setup can be specified via this quirk:
*/
char * (*arch_memory_setup_quirk)(void);
char *__init default_machine_specific_memory_setup(void)
{
char *who = "BIOS-e820";
@ -1353,6 +1358,12 @@ char *__init default_machine_specific_memory_setup(void)
char *__init __attribute__((weak)) machine_specific_memory_setup(void)
{
if (arch_memory_setup_quirk) {
char *who = arch_memory_setup_quirk();
if (who)
return who;
}
return default_machine_specific_memory_setup();
}

View File

@ -725,13 +725,23 @@ static inline void __init construct_default_ISA_mptable(int mpc_default_type)
static struct intel_mp_floating *mpf_found;
/*
* Machine specific quirk for finding the SMP config before other setup
* activities destroy the table:
*/
int (*mach_get_smp_config_quirk)(unsigned int early);
/*
* Scan the memory blocks for an SMP configuration block.
*/
static void __init __get_smp_config(unsigned early)
static void __init __get_smp_config(unsigned int early)
{
struct intel_mp_floating *mpf = mpf_found;
if (mach_get_smp_config_quirk) {
if (mach_get_smp_config_quirk(early))
return;
}
if (acpi_lapic && early)
return;
/*
@ -889,10 +899,16 @@ static int __init smp_scan_config(unsigned long base, unsigned long length,
return 0;
}
static void __init __find_smp_config(unsigned reserve)
int (*mach_find_smp_config_quirk)(unsigned int reserve);
static void __init __find_smp_config(unsigned int reserve)
{
unsigned int address;
if (mach_find_smp_config_quirk) {
if (mach_find_smp_config_quirk(reserve))
return;
}
/*
* FIXME: Linux assumes you have 640K of base ram..
* this continues the error...

View File

@ -596,6 +596,7 @@ void __init setup_arch(char **cmdline_p)
{
#ifdef CONFIG_X86_32
memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
visws_early_detect();
pre_setup_arch_hook();
early_cpu_init();
#else

View File

@ -0,0 +1,709 @@
/*
* SGI Visual Workstation support and quirks, unmaintained.
*
* Split out from setup.c by davej@suse.de
*
* Copyright (C) 1999 Bent Hagemark, Ingo Molnar
*
* SGI Visual Workstation interrupt controller
*
* The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
* which serves as the main interrupt controller in the system. Non-legacy
* hardware in the system uses this controller directly. Legacy devices
* are connected to the PIIX4 which in turn has its 8259(s) connected to
* a of the Cobalt APIC entry.
*
* 09/02/2000 - Updated for 2.4 by jbarnes@sgi.com
*
* 25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru>
*/
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/smp.h>
#include <asm/visws/cobalt.h>
#include <asm/visws/piix4.h>
#include <asm/arch_hooks.h>
#include <asm/fixmap.h>
#include <asm/reboot.h>
#include <asm/setup.h>
#include <asm/e820.h>
#include <asm/smp.h>
#include <asm/io.h>
#include <mach_ipi.h>
#include "mach_apic.h"
#include <linux/init.h>
#include <linux/smp.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/apic.h>
#include <asm/i8259.h>
#include <asm/irq_vectors.h>
#include <asm/visws/cobalt.h>
#include <asm/visws/lithium.h>
#include <asm/visws/piix4.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
extern int no_broadcast;
#include <asm/io.h>
#include <asm/apic.h>
#include <asm/arch_hooks.h>
#include <asm/visws/cobalt.h>
#include <asm/visws/lithium.h>
char visws_board_type = -1;
char visws_board_rev = -1;
int is_visws_box(void)
{
return visws_board_type >= 0;
}
static int __init visws_time_init_quirk(void)
{
printk(KERN_INFO "Starting Cobalt Timer system clock\n");
/* Set the countdown value */
co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
/* Start the timer */
co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
/* Enable (unmask) the timer interrupt */
co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
/*
* Zero return means the generic timer setup code will set up
* the standard vector:
*/
return 0;
}
static int __init visws_pre_intr_init_quirk(void)
{
init_VISWS_APIC_irqs();
/*
* We dont want ISA irqs to be set up by the generic code:
*/
return 1;
}
/* Quirk for machine specific memory setup. */
#define MB (1024 * 1024)
unsigned long sgivwfb_mem_phys;
unsigned long sgivwfb_mem_size;
EXPORT_SYMBOL(sgivwfb_mem_phys);
EXPORT_SYMBOL(sgivwfb_mem_size);
long long mem_size __initdata = 0;
static char * __init visws_memory_setup_quirk(void)
{
long long gfx_mem_size = 8 * MB;
mem_size = boot_params.alt_mem_k;
if (!mem_size) {
printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
mem_size = 128 * MB;
}
/*
* this hardcodes the graphics memory to 8 MB
* it really should be sized dynamically (or at least
* set as a boot param)
*/
if (!sgivwfb_mem_size) {
printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
sgivwfb_mem_size = 8 * MB;
}
/*
* Trim to nearest MB
*/
sgivwfb_mem_size &= ~((1 << 20) - 1);
sgivwfb_mem_phys = mem_size - gfx_mem_size;
e820_add_region(0, LOWMEMSIZE(), E820_RAM);
e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
return "PROM";
}
static void visws_machine_emergency_restart(void)
{
/*
* Visual Workstations restart after this
* register is poked on the PIIX4
*/
outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT);
}
static void visws_machine_power_off(void)
{
unsigned short pm_status;
/* extern unsigned int pci_bus0; */
while ((pm_status = inw(PMSTS_PORT)) & 0x100)
outw(pm_status, PMSTS_PORT);
outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT);
mdelay(10);
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
/* outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8); */
outl(PIIX_SPECIAL_STOP, 0xCFC);
}
static int __init visws_get_smp_config_quirk(unsigned int early)
{
/*
* Prevent MP-table parsing by the generic code:
*/
return 1;
}
extern unsigned int __cpuinitdata maxcpus;
/*
* The Visual Workstation is Intel MP compliant in the hardware
* sense, but it doesn't have a BIOS(-configuration table).
* No problem for Linux.
*/
static void __init MP_processor_info (struct mpc_config_processor *m)
{
int ver, logical_apicid;
physid_mask_t apic_cpus;
if (!(m->mpc_cpuflag & CPU_ENABLED))
return;
logical_apicid = m->mpc_apicid;
printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n",
m->mpc_cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "",
m->mpc_apicid,
(m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8,
(m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
m->mpc_apicver);
if (m->mpc_cpuflag & CPU_BOOTPROCESSOR)
boot_cpu_physical_apicid = m->mpc_apicid;
ver = m->mpc_apicver;
if ((ver >= 0x14 && m->mpc_apicid >= 0xff) || m->mpc_apicid >= 0xf) {
printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
m->mpc_apicid, MAX_APICS);
return;
}
apic_cpus = apicid_to_cpu_present(m->mpc_apicid);
physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
/*
* Validate version
*/
if (ver == 0x0) {
printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! "
"fixing up to 0x10. (tell your hw vendor)\n",
m->mpc_apicid);
ver = 0x10;
}
apic_version[m->mpc_apicid] = ver;
}
int __init visws_find_smp_config_quirk(unsigned int reserve)
{
struct mpc_config_processor *mp = phys_to_virt(CO_CPU_TAB_PHYS);
unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
if (ncpus > CO_CPU_MAX) {
printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n",
ncpus, mp);
ncpus = CO_CPU_MAX;
}
if (ncpus > maxcpus)
ncpus = maxcpus;
#ifdef CONFIG_X86_LOCAL_APIC
smp_found_config = 1;
#endif
while (ncpus--)
MP_processor_info(mp++);
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
return 1;
}
extern int visws_trap_init_quirk(void);
void __init visws_early_detect(void)
{
int raw;
visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
>> PIIX_GPI_BD_SHIFT;
if (visws_board_type < 0)
return;
/*
* Install special quirks for timer, interrupt and memory setup:
*/
arch_time_init_quirk = visws_time_init_quirk;
arch_pre_intr_init_quirk = visws_pre_intr_init_quirk;
arch_memory_setup_quirk = visws_memory_setup_quirk;
/*
* Fall back to generic behavior for traps:
*/
arch_intr_init_quirk = NULL;
arch_trap_init_quirk = visws_trap_init_quirk;
/*
* Install reboot quirks:
*/
pm_power_off = visws_machine_power_off;
machine_ops.emergency_restart = visws_machine_emergency_restart;
/*
* Do not use broadcast IPIs:
*/
no_broadcast = 0;
/*
* Override generic MP-table parsing:
*/
mach_get_smp_config_quirk = visws_get_smp_config_quirk;
mach_find_smp_config_quirk = visws_find_smp_config_quirk;
#ifdef CONFIG_X86_IO_APIC
/*
* Turn off IO-APIC detection and initialization:
*/
skip_ioapic_setup = 1;
#endif
/*
* Get Board rev.
* First, we have to initialize the 307 part to allow us access
* to the GPIO registers. Let's map them at 0x0fc0 which is right
* after the PIIX4 PM section.
*/
outb_p(SIO_DEV_SEL, SIO_INDEX);
outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */
outb_p(SIO_DEV_MSB, SIO_INDEX);
outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */
outb_p(SIO_DEV_LSB, SIO_INDEX);
outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */
outb_p(SIO_DEV_ENB, SIO_INDEX);
outb_p(1, SIO_DATA); /* Enable GPIO registers. */
/*
* Now, we have to map the power management section to write
* a bit which enables access to the GPIO registers.
* What lunatic came up with this shit?
*/
outb_p(SIO_DEV_SEL, SIO_INDEX);
outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */
outb_p(SIO_DEV_MSB, SIO_INDEX);
outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */
outb_p(SIO_DEV_LSB, SIO_INDEX);
outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */
outb_p(SIO_DEV_ENB, SIO_INDEX);
outb_p(1, SIO_DATA); /* Enable PM registers. */
/*
* Now, write the PM register which enables the GPIO registers.
*/
outb_p(SIO_PM_FER2, SIO_PM_INDEX);
outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
/*
* Now, initialize the GPIO registers.
* We want them all to be inputs which is the
* power on default, so let's leave them alone.
* So, let's just read the board rev!
*/
raw = inb_p(SIO_GP_DATA1);
raw &= 0x7f; /* 7 bits of valid board revision ID. */
if (visws_board_type == VISWS_320) {
if (raw < 0x6) {
visws_board_rev = 4;
} else if (raw < 0xc) {
visws_board_rev = 5;
} else {
visws_board_rev = 6;
}
} else if (visws_board_type == VISWS_540) {
visws_board_rev = 2;
} else {
visws_board_rev = raw;
}
printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n",
(visws_board_type == VISWS_320 ? "320" :
(visws_board_type == VISWS_540 ? "540" :
"unknown")), visws_board_rev);
}
#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4)
#define BCD (LI_INTB | LI_INTC | LI_INTD)
#define ALLDEVS (A01234 | BCD)
static __init void lithium_init(void)
{
set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
(li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
/* panic("This machine is not SGI Visual Workstation 320/540"); */
}
if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
(li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
/* panic("This machine is not SGI Visual Workstation 320/540"); */
}
li_pcia_write16(LI_PCI_INTEN, ALLDEVS);
li_pcib_write16(LI_PCI_INTEN, ALLDEVS);
}
static __init void cobalt_init(void)
{
/*
* On normal SMP PC this is used only with SMP, but we have to
* use it and set it up here to start the Cobalt clock
*/
set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
setup_local_APIC();
printk(KERN_INFO "Local APIC Version %#x, ID %#x\n",
(unsigned int)apic_read(APIC_LVR),
(unsigned int)apic_read(APIC_ID));
set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n",
co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID));
/* Enable Cobalt APIC being careful to NOT change the ID! */
co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE);
printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n",
co_apic_read(CO_APIC_ID));
}
int __init visws_trap_init_quirk(void)
{
lithium_init();
cobalt_init();
return 1;
}
/*
* IRQ controller / APIC support:
*/
static DEFINE_SPINLOCK(cobalt_lock);
/*
* Set the given Cobalt APIC Redirection Table entry to point
* to the given IDT vector/index.
*/
static inline void co_apic_set(int entry, int irq)
{
co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR));
co_apic_write(CO_APIC_HI(entry), 0);
}
/*
* Cobalt (IO)-APIC functions to handle PCI devices.
*/
static inline int co_apic_ide0_hack(void)
{
extern char visws_board_type;
extern char visws_board_rev;
if (visws_board_type == VISWS_320 && visws_board_rev == 5)
return 5;
return CO_APIC_IDE0;
}
static int is_co_apic(unsigned int irq)
{
if (IS_CO_APIC(irq))
return CO_APIC(irq);
switch (irq) {
case 0: return CO_APIC_CPU;
case CO_IRQ_IDE0: return co_apic_ide0_hack();
case CO_IRQ_IDE1: return CO_APIC_IDE1;
default: return -1;
}
}
/*
* This is the SGI Cobalt (IO-)APIC:
*/
static void enable_cobalt_irq(unsigned int irq)
{
co_apic_set(is_co_apic(irq), irq);
}
static void disable_cobalt_irq(unsigned int irq)
{
int entry = is_co_apic(irq);
co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK);
co_apic_read(CO_APIC_LO(entry));
}
/*
* "irq" really just serves to identify the device. Here is where we
* map this to the Cobalt APIC entry where it's physically wired.
* This is called via request_irq -> setup_irq -> irq_desc->startup()
*/
static unsigned int startup_cobalt_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&cobalt_lock, flags);
if ((irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING)))
irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING);
enable_cobalt_irq(irq);
spin_unlock_irqrestore(&cobalt_lock, flags);
return 0;
}
static void ack_cobalt_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&cobalt_lock, flags);
disable_cobalt_irq(irq);
apic_write(APIC_EOI, APIC_EIO_ACK);
spin_unlock_irqrestore(&cobalt_lock, flags);
}
static void end_cobalt_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&cobalt_lock, flags);
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
enable_cobalt_irq(irq);
spin_unlock_irqrestore(&cobalt_lock, flags);
}
static struct irq_chip cobalt_irq_type = {
.typename = "Cobalt-APIC",
.startup = startup_cobalt_irq,
.shutdown = disable_cobalt_irq,
.enable = enable_cobalt_irq,
.disable = disable_cobalt_irq,
.ack = ack_cobalt_irq,
.end = end_cobalt_irq,
};
/*
* This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
* -- not the manner expected by the code in i8259.c.
*
* there is a 'master' physical interrupt source that gets sent to
* the CPU. But in the chipset there are various 'virtual' interrupts
* waiting to be handled. We represent this to Linux through a 'master'
* interrupt controller type, and through a special virtual interrupt-
* controller. Device drivers only see the virtual interrupt sources.
*/
static unsigned int startup_piix4_master_irq(unsigned int irq)
{
init_8259A(0);
return startup_cobalt_irq(irq);
}
static void end_piix4_master_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&cobalt_lock, flags);
enable_cobalt_irq(irq);
spin_unlock_irqrestore(&cobalt_lock, flags);
}
static struct irq_chip piix4_master_irq_type = {
.typename = "PIIX4-master",
.startup = startup_piix4_master_irq,
.ack = ack_cobalt_irq,
.end = end_piix4_master_irq,
};
static struct irq_chip piix4_virtual_irq_type = {
.typename = "PIIX4-virtual",
.shutdown = disable_8259A_irq,
.enable = enable_8259A_irq,
.disable = disable_8259A_irq,
};
/*
* PIIX4-8259 master/virtual functions to handle interrupt requests
* from legacy devices: floppy, parallel, serial, rtc.
*
* None of these get Cobalt APIC entries, neither do they have IDT
* entries. These interrupts are purely virtual and distributed from
* the 'master' interrupt source: CO_IRQ_8259.
*
* When the 8259 interrupts its handler figures out which of these
* devices is interrupting and dispatches to its handler.
*
* CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
* enable_irq gets the right irq. This 'master' irq is never directly
* manipulated by any driver.
*/
static irqreturn_t piix4_master_intr(int irq, void *dev_id)
{
int realirq;
irq_desc_t *desc;
unsigned long flags;
spin_lock_irqsave(&i8259A_lock, flags);
/* Find out what's interrupting in the PIIX4 master 8259 */
outb(0x0c, 0x20); /* OCW3 Poll command */
realirq = inb(0x20);
/*
* Bit 7 == 0 means invalid/spurious
*/
if (unlikely(!(realirq & 0x80)))
goto out_unlock;
realirq &= 7;
if (unlikely(realirq == 2)) {
outb(0x0c, 0xa0);
realirq = inb(0xa0);
if (unlikely(!(realirq & 0x80)))
goto out_unlock;
realirq = (realirq & 7) + 8;
}
/* mask and ack interrupt */
cached_irq_mask |= 1 << realirq;
if (unlikely(realirq > 7)) {
inb(0xa1);
outb(cached_slave_mask, 0xa1);
outb(0x60 + (realirq & 7), 0xa0);
outb(0x60 + 2, 0x20);
} else {
inb(0x21);
outb(cached_master_mask, 0x21);
outb(0x60 + realirq, 0x20);
}
spin_unlock_irqrestore(&i8259A_lock, flags);
desc = irq_desc + realirq;
/*
* handle this 'virtual interrupt' as a Cobalt one now.
*/
kstat_cpu(smp_processor_id()).irqs[realirq]++;
if (likely(desc->action != NULL))
handle_IRQ_event(realirq, desc->action);
if (!(desc->status & IRQ_DISABLED))
enable_8259A_irq(realirq);
return IRQ_HANDLED;
out_unlock:
spin_unlock_irqrestore(&i8259A_lock, flags);
return IRQ_NONE;
}
static struct irqaction master_action = {
.handler = piix4_master_intr,
.name = "PIIX4-8259",
};
static struct irqaction cascade_action = {
.handler = no_action,
.name = "cascade",
};
void init_VISWS_APIC_irqs(void)
{
int i;
for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
if (i == 0) {
irq_desc[i].chip = &cobalt_irq_type;
}
else if (i == CO_IRQ_IDE0) {
irq_desc[i].chip = &cobalt_irq_type;
}
else if (i == CO_IRQ_IDE1) {
irq_desc[i].chip = &cobalt_irq_type;
}
else if (i == CO_IRQ_8259) {
irq_desc[i].chip = &piix4_master_irq_type;
}
else if (i < CO_IRQ_APIC0) {
irq_desc[i].chip = &piix4_virtual_irq_type;
}
else if (IS_CO_APIC(i)) {
irq_desc[i].chip = &cobalt_irq_type;
}
}
setup_irq(CO_IRQ_8259, &master_action);
setup_irq(2, &cascade_action);
}

View File

@ -3,7 +3,7 @@ config LGUEST_GUEST
select PARAVIRT
depends on X86_32
depends on !X86_PAE
depends on !(X86_VISWS || X86_VOYAGER)
depends on !X86_VOYAGER
select VIRTIO
select VIRTIO_RING
select VIRTIO_CONSOLE

View File

@ -10,6 +10,14 @@
#include <asm/e820.h>
#include <asm/setup.h>
/*
* Any quirks to be performed to initialize timers/irqs/etc?
*/
int (*arch_time_init_quirk)(void);
int (*arch_pre_intr_init_quirk)(void);
int (*arch_intr_init_quirk)(void);
int (*arch_trap_init_quirk)(void);
#ifdef CONFIG_HOTPLUG_CPU
#define DEFAULT_SEND_IPI (1)
#else
@ -29,6 +37,10 @@ int no_broadcast=DEFAULT_SEND_IPI;
**/
void __init pre_intr_init_hook(void)
{
if (arch_pre_intr_init_quirk) {
if (arch_pre_intr_init_quirk())
return;
}
init_ISA_irqs();
}
@ -52,6 +64,10 @@ static struct irqaction irq2 = {
**/
void __init intr_init_hook(void)
{
if (arch_intr_init_quirk) {
if (arch_intr_init_quirk())
return;
}
#ifdef CONFIG_X86_LOCAL_APIC
apic_intr_init();
#endif
@ -65,7 +81,7 @@ void __init intr_init_hook(void)
*
* Description:
* generally used to activate any machine specific identification
* routines that may be needed before setup_arch() runs. On VISWS
* routines that may be needed before setup_arch() runs. On Voyager
* this is used to get the board revision and type.
**/
void __init pre_setup_arch_hook(void)
@ -81,6 +97,10 @@ void __init pre_setup_arch_hook(void)
**/
void __init trap_init_hook(void)
{
if (arch_trap_init_quirk) {
if (arch_trap_init_quirk())
return;
}
}
static struct irqaction irq0 = {
@ -99,6 +119,16 @@ static struct irqaction irq0 = {
**/
void __init time_init_hook(void)
{
if (arch_time_init_quirk) {
/*
* A nonzero return code does not mean failure, it means
* that the architecture quirk does not want any
* generic (timer) setup to be performed after this:
*/
if (arch_time_init_quirk())
return;
}
irq0.mask = cpumask_of_cpu(0);
setup_irq(0, &irq0);
}

View File

@ -1,8 +0,0 @@
#
# Makefile for the linux kernel.
#
obj-y := setup.o traps.o reboot.o
obj-$(CONFIG_X86_VISWS_APIC) += visws_apic.o
obj-$(CONFIG_X86_LOCAL_APIC) += mpparse.o

View File

@ -1,85 +0,0 @@
#include <linux/init.h>
#include <linux/smp.h>
#include <asm/smp.h>
#include <asm/io.h>
#include "cobalt.h"
#include "mach_apic.h"
extern unsigned int __cpuinitdata maxcpus;
/*
* The Visual Workstation is Intel MP compliant in the hardware
* sense, but it doesn't have a BIOS(-configuration table).
* No problem for Linux.
*/
static void __init MP_processor_info (struct mpc_config_processor *m)
{
int ver, logical_apicid;
physid_mask_t apic_cpus;
if (!(m->mpc_cpuflag & CPU_ENABLED))
return;
logical_apicid = m->mpc_apicid;
printk(KERN_INFO "%sCPU #%d %u:%u APIC version %d\n",
m->mpc_cpuflag & CPU_BOOTPROCESSOR ? "Bootup " : "",
m->mpc_apicid,
(m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8,
(m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
m->mpc_apicver);
if (m->mpc_cpuflag & CPU_BOOTPROCESSOR)
boot_cpu_physical_apicid = m->mpc_apicid;
ver = m->mpc_apicver;
if ((ver >= 0x14 && m->mpc_apicid >= 0xff) || m->mpc_apicid >= 0xf) {
printk(KERN_ERR "Processor #%d INVALID. (Max ID: %d).\n",
m->mpc_apicid, MAX_APICS);
return;
}
apic_cpus = apicid_to_cpu_present(m->mpc_apicid);
physids_or(phys_cpu_present_map, phys_cpu_present_map, apic_cpus);
/*
* Validate version
*/
if (ver == 0x0) {
printk(KERN_ERR "BIOS bug, APIC version is 0 for CPU#%d! "
"fixing up to 0x10. (tell your hw vendor)\n",
m->mpc_apicid);
ver = 0x10;
}
apic_version[m->mpc_apicid] = ver;
}
void __init find_smp_config(void)
{
struct mpc_config_processor *mp = phys_to_virt(CO_CPU_TAB_PHYS);
unsigned short ncpus = readw(phys_to_virt(CO_CPU_NUM_PHYS));
if (ncpus > CO_CPU_MAX) {
printk(KERN_WARNING "find_visws_smp: got cpu count of %d at %p\n",
ncpus, mp);
ncpus = CO_CPU_MAX;
}
if (ncpus > maxcpus)
ncpus = maxcpus;
#ifdef CONFIG_X86_LOCAL_APIC
smp_found_config = 1;
#endif
while (ncpus--)
MP_processor_info(mp++);
mp_lapic_addr = APIC_DEFAULT_PHYS_BASE;
}
void __init get_smp_config (void)
{
}

View File

@ -1,55 +0,0 @@
#include <linux/module.h>
#include <linux/smp.h>
#include <linux/delay.h>
#include <asm/io.h>
#include "piix4.h"
void (*pm_power_off)(void);
EXPORT_SYMBOL(pm_power_off);
void machine_shutdown(void)
{
#ifdef CONFIG_SMP
smp_send_stop();
#endif
}
void machine_emergency_restart(void)
{
/*
* Visual Workstations restart after this
* register is poked on the PIIX4
*/
outb(PIIX4_RESET_VAL, PIIX4_RESET_PORT);
}
void machine_restart(char * __unused)
{
machine_shutdown();
machine_emergency_restart();
}
void machine_power_off(void)
{
unsigned short pm_status;
extern unsigned int pci_bus0;
while ((pm_status = inw(PMSTS_PORT)) & 0x100)
outw(pm_status, PMSTS_PORT);
outw(PM_SUSPEND_ENABLE, PMCNTRL_PORT);
mdelay(10);
#define PCI_CONF1_ADDRESS(bus, devfn, reg) \
(0x80000000 | (bus << 16) | (devfn << 8) | (reg & ~3))
outl(PCI_CONF1_ADDRESS(pci_bus0, SPECIAL_DEV, SPECIAL_REG), 0xCF8);
outl(PIIX_SPECIAL_STOP, 0xCFC);
}
void machine_halt(void)
{
}

View File

@ -1,183 +0,0 @@
/*
* Unmaintained SGI Visual Workstation support.
* Split out from setup.c by davej@suse.de
*/
#include <linux/smp.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <asm/fixmap.h>
#include <asm/arch_hooks.h>
#include <asm/io.h>
#include <asm/e820.h>
#include <asm/setup.h>
#include "cobalt.h"
#include "piix4.h"
int no_broadcast;
char visws_board_type = -1;
char visws_board_rev = -1;
void __init visws_get_board_type_and_rev(void)
{
int raw;
visws_board_type = (char)(inb_p(PIIX_GPI_BD_REG) & PIIX_GPI_BD_REG)
>> PIIX_GPI_BD_SHIFT;
/*
* Get Board rev.
* First, we have to initialize the 307 part to allow us access
* to the GPIO registers. Let's map them at 0x0fc0 which is right
* after the PIIX4 PM section.
*/
outb_p(SIO_DEV_SEL, SIO_INDEX);
outb_p(SIO_GP_DEV, SIO_DATA); /* Talk to GPIO regs. */
outb_p(SIO_DEV_MSB, SIO_INDEX);
outb_p(SIO_GP_MSB, SIO_DATA); /* MSB of GPIO base address */
outb_p(SIO_DEV_LSB, SIO_INDEX);
outb_p(SIO_GP_LSB, SIO_DATA); /* LSB of GPIO base address */
outb_p(SIO_DEV_ENB, SIO_INDEX);
outb_p(1, SIO_DATA); /* Enable GPIO registers. */
/*
* Now, we have to map the power management section to write
* a bit which enables access to the GPIO registers.
* What lunatic came up with this shit?
*/
outb_p(SIO_DEV_SEL, SIO_INDEX);
outb_p(SIO_PM_DEV, SIO_DATA); /* Talk to GPIO regs. */
outb_p(SIO_DEV_MSB, SIO_INDEX);
outb_p(SIO_PM_MSB, SIO_DATA); /* MSB of PM base address */
outb_p(SIO_DEV_LSB, SIO_INDEX);
outb_p(SIO_PM_LSB, SIO_DATA); /* LSB of PM base address */
outb_p(SIO_DEV_ENB, SIO_INDEX);
outb_p(1, SIO_DATA); /* Enable PM registers. */
/*
* Now, write the PM register which enables the GPIO registers.
*/
outb_p(SIO_PM_FER2, SIO_PM_INDEX);
outb_p(SIO_PM_GP_EN, SIO_PM_DATA);
/*
* Now, initialize the GPIO registers.
* We want them all to be inputs which is the
* power on default, so let's leave them alone.
* So, let's just read the board rev!
*/
raw = inb_p(SIO_GP_DATA1);
raw &= 0x7f; /* 7 bits of valid board revision ID. */
if (visws_board_type == VISWS_320) {
if (raw < 0x6) {
visws_board_rev = 4;
} else if (raw < 0xc) {
visws_board_rev = 5;
} else {
visws_board_rev = 6;
}
} else if (visws_board_type == VISWS_540) {
visws_board_rev = 2;
} else {
visws_board_rev = raw;
}
printk(KERN_INFO "Silicon Graphics Visual Workstation %s (rev %d) detected\n",
(visws_board_type == VISWS_320 ? "320" :
(visws_board_type == VISWS_540 ? "540" :
"unknown")), visws_board_rev);
}
void __init pre_intr_init_hook(void)
{
init_VISWS_APIC_irqs();
}
void __init intr_init_hook(void)
{
#ifdef CONFIG_X86_LOCAL_APIC
apic_intr_init();
#endif
}
void __init pre_setup_arch_hook()
{
visws_get_board_type_and_rev();
}
static struct irqaction irq0 = {
.handler = timer_interrupt,
.flags = IRQF_DISABLED | IRQF_IRQPOLL,
.name = "timer",
};
void __init time_init_hook(void)
{
printk(KERN_INFO "Starting Cobalt Timer system clock\n");
/* Set the countdown value */
co_cpu_write(CO_CPU_TIMEVAL, CO_TIME_HZ/HZ);
/* Start the timer */
co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) | CO_CTRL_TIMERUN);
/* Enable (unmask) the timer interrupt */
co_cpu_write(CO_CPU_CTRL, co_cpu_read(CO_CPU_CTRL) & ~CO_CTRL_TIMEMASK);
/* Wire cpu IDT entry to s/w handler (and Cobalt APIC to IDT) */
setup_irq(0, &irq0);
}
/* Hook for machine specific memory setup. */
#define MB (1024 * 1024)
unsigned long sgivwfb_mem_phys;
unsigned long sgivwfb_mem_size;
EXPORT_SYMBOL(sgivwfb_mem_phys);
EXPORT_SYMBOL(sgivwfb_mem_size);
long long mem_size __initdata = 0;
char * __init machine_specific_memory_setup(void)
{
long long gfx_mem_size = 8 * MB;
mem_size = boot_params.alt_mem_k;
if (!mem_size) {
printk(KERN_WARNING "Bootloader didn't set memory size, upgrade it !\n");
mem_size = 128 * MB;
}
/*
* this hardcodes the graphics memory to 8 MB
* it really should be sized dynamically (or at least
* set as a boot param)
*/
if (!sgivwfb_mem_size) {
printk(KERN_WARNING "Defaulting to 8 MB framebuffer size\n");
sgivwfb_mem_size = 8 * MB;
}
/*
* Trim to nearest MB
*/
sgivwfb_mem_size &= ~((1 << 20) - 1);
sgivwfb_mem_phys = mem_size - gfx_mem_size;
e820_add_region(0, LOWMEMSIZE(), E820_RAM);
e820_add_region(HIGH_MEMORY, mem_size - sgivwfb_mem_size - HIGH_MEMORY, E820_RAM);
e820_add_region(sgivwfb_mem_phys, sgivwfb_mem_size, E820_RESERVED);
return "PROM";
}

View File

@ -1,69 +0,0 @@
/* VISWS traps */
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
#include <asm/io.h>
#include <asm/arch_hooks.h>
#include <asm/apic.h>
#include "cobalt.h"
#include "lithium.h"
#define A01234 (LI_INTA_0 | LI_INTA_1 | LI_INTA_2 | LI_INTA_3 | LI_INTA_4)
#define BCD (LI_INTB | LI_INTC | LI_INTD)
#define ALLDEVS (A01234 | BCD)
static __init void lithium_init(void)
{
set_fixmap(FIX_LI_PCIA, LI_PCI_A_PHYS);
set_fixmap(FIX_LI_PCIB, LI_PCI_B_PHYS);
if ((li_pcia_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
(li_pcia_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'A');
panic("This machine is not SGI Visual Workstation 320/540");
}
if ((li_pcib_read16(PCI_VENDOR_ID) != PCI_VENDOR_ID_SGI) ||
(li_pcib_read16(PCI_DEVICE_ID) != PCI_DEVICE_ID_SGI_LITHIUM)) {
printk(KERN_EMERG "Lithium hostbridge %c not found\n", 'B');
panic("This machine is not SGI Visual Workstation 320/540");
}
li_pcia_write16(LI_PCI_INTEN, ALLDEVS);
li_pcib_write16(LI_PCI_INTEN, ALLDEVS);
}
static __init void cobalt_init(void)
{
/*
* On normal SMP PC this is used only with SMP, but we have to
* use it and set it up here to start the Cobalt clock
*/
set_fixmap(FIX_APIC_BASE, APIC_DEFAULT_PHYS_BASE);
setup_local_APIC();
printk(KERN_INFO "Local APIC Version %#x, ID %#x\n",
(unsigned int)apic_read(APIC_LVR),
(unsigned int)apic_read(APIC_ID));
set_fixmap(FIX_CO_CPU, CO_CPU_PHYS);
set_fixmap(FIX_CO_APIC, CO_APIC_PHYS);
printk(KERN_INFO "Cobalt Revision %#lx, APIC ID %#lx\n",
co_cpu_read(CO_CPU_REV), co_apic_read(CO_APIC_ID));
/* Enable Cobalt APIC being careful to NOT change the ID! */
co_apic_write(CO_APIC_ID, co_apic_read(CO_APIC_ID) | CO_APIC_ENABLE);
printk(KERN_INFO "Cobalt APIC enabled: ID reg %#lx\n",
co_apic_read(CO_APIC_ID));
}
void __init trap_init_hook(void)
{
lithium_init();
cobalt_init();
}

View File

@ -1,296 +0,0 @@
/*
* Copyright (C) 1999 Bent Hagemark, Ingo Molnar
*
* SGI Visual Workstation interrupt controller
*
* The Cobalt system ASIC in the Visual Workstation contains a "Cobalt" APIC
* which serves as the main interrupt controller in the system. Non-legacy
* hardware in the system uses this controller directly. Legacy devices
* are connected to the PIIX4 which in turn has its 8259(s) connected to
* a of the Cobalt APIC entry.
*
* 09/02/2000 - Updated for 2.4 by jbarnes@sgi.com
*
* 25/11/2002 - Updated for 2.5 by Andrey Panin <pazke@orbita1.ru>
*/
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <asm/io.h>
#include <asm/apic.h>
#include <asm/i8259.h>
#include <asm/irq_vectors.h>
#include "cobalt.h"
static DEFINE_SPINLOCK(cobalt_lock);
/*
* Set the given Cobalt APIC Redirection Table entry to point
* to the given IDT vector/index.
*/
static inline void co_apic_set(int entry, int irq)
{
co_apic_write(CO_APIC_LO(entry), CO_APIC_LEVEL | (irq + FIRST_EXTERNAL_VECTOR));
co_apic_write(CO_APIC_HI(entry), 0);
}
/*
* Cobalt (IO)-APIC functions to handle PCI devices.
*/
static inline int co_apic_ide0_hack(void)
{
extern char visws_board_type;
extern char visws_board_rev;
if (visws_board_type == VISWS_320 && visws_board_rev == 5)
return 5;
return CO_APIC_IDE0;
}
static int is_co_apic(unsigned int irq)
{
if (IS_CO_APIC(irq))
return CO_APIC(irq);
switch (irq) {
case 0: return CO_APIC_CPU;
case CO_IRQ_IDE0: return co_apic_ide0_hack();
case CO_IRQ_IDE1: return CO_APIC_IDE1;
default: return -1;
}
}
/*
* This is the SGI Cobalt (IO-)APIC:
*/
static void enable_cobalt_irq(unsigned int irq)
{
co_apic_set(is_co_apic(irq), irq);
}
static void disable_cobalt_irq(unsigned int irq)
{
int entry = is_co_apic(irq);
co_apic_write(CO_APIC_LO(entry), CO_APIC_MASK);
co_apic_read(CO_APIC_LO(entry));
}
/*
* "irq" really just serves to identify the device. Here is where we
* map this to the Cobalt APIC entry where it's physically wired.
* This is called via request_irq -> setup_irq -> irq_desc->startup()
*/
static unsigned int startup_cobalt_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&cobalt_lock, flags);
if ((irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING)))
irq_desc[irq].status &= ~(IRQ_DISABLED | IRQ_INPROGRESS | IRQ_WAITING);
enable_cobalt_irq(irq);
spin_unlock_irqrestore(&cobalt_lock, flags);
return 0;
}
static void ack_cobalt_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&cobalt_lock, flags);
disable_cobalt_irq(irq);
apic_write(APIC_EOI, APIC_EIO_ACK);
spin_unlock_irqrestore(&cobalt_lock, flags);
}
static void end_cobalt_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&cobalt_lock, flags);
if (!(irq_desc[irq].status & (IRQ_DISABLED | IRQ_INPROGRESS)))
enable_cobalt_irq(irq);
spin_unlock_irqrestore(&cobalt_lock, flags);
}
static struct irq_chip cobalt_irq_type = {
.typename = "Cobalt-APIC",
.startup = startup_cobalt_irq,
.shutdown = disable_cobalt_irq,
.enable = enable_cobalt_irq,
.disable = disable_cobalt_irq,
.ack = ack_cobalt_irq,
.end = end_cobalt_irq,
};
/*
* This is the PIIX4-based 8259 that is wired up indirectly to Cobalt
* -- not the manner expected by the code in i8259.c.
*
* there is a 'master' physical interrupt source that gets sent to
* the CPU. But in the chipset there are various 'virtual' interrupts
* waiting to be handled. We represent this to Linux through a 'master'
* interrupt controller type, and through a special virtual interrupt-
* controller. Device drivers only see the virtual interrupt sources.
*/
static unsigned int startup_piix4_master_irq(unsigned int irq)
{
init_8259A(0);
return startup_cobalt_irq(irq);
}
static void end_piix4_master_irq(unsigned int irq)
{
unsigned long flags;
spin_lock_irqsave(&cobalt_lock, flags);
enable_cobalt_irq(irq);
spin_unlock_irqrestore(&cobalt_lock, flags);
}
static struct irq_chip piix4_master_irq_type = {
.typename = "PIIX4-master",
.startup = startup_piix4_master_irq,
.ack = ack_cobalt_irq,
.end = end_piix4_master_irq,
};
static struct irq_chip piix4_virtual_irq_type = {
.typename = "PIIX4-virtual",
.shutdown = disable_8259A_irq,
.enable = enable_8259A_irq,
.disable = disable_8259A_irq,
};
/*
* PIIX4-8259 master/virtual functions to handle interrupt requests
* from legacy devices: floppy, parallel, serial, rtc.
*
* None of these get Cobalt APIC entries, neither do they have IDT
* entries. These interrupts are purely virtual and distributed from
* the 'master' interrupt source: CO_IRQ_8259.
*
* When the 8259 interrupts its handler figures out which of these
* devices is interrupting and dispatches to its handler.
*
* CAREFUL: devices see the 'virtual' interrupt only. Thus disable/
* enable_irq gets the right irq. This 'master' irq is never directly
* manipulated by any driver.
*/
static irqreturn_t piix4_master_intr(int irq, void *dev_id)
{
int realirq;
irq_desc_t *desc;
unsigned long flags;
spin_lock_irqsave(&i8259A_lock, flags);
/* Find out what's interrupting in the PIIX4 master 8259 */
outb(0x0c, 0x20); /* OCW3 Poll command */
realirq = inb(0x20);
/*
* Bit 7 == 0 means invalid/spurious
*/
if (unlikely(!(realirq & 0x80)))
goto out_unlock;
realirq &= 7;
if (unlikely(realirq == 2)) {
outb(0x0c, 0xa0);
realirq = inb(0xa0);
if (unlikely(!(realirq & 0x80)))
goto out_unlock;
realirq = (realirq & 7) + 8;
}
/* mask and ack interrupt */
cached_irq_mask |= 1 << realirq;
if (unlikely(realirq > 7)) {
inb(0xa1);
outb(cached_slave_mask, 0xa1);
outb(0x60 + (realirq & 7), 0xa0);
outb(0x60 + 2, 0x20);
} else {
inb(0x21);
outb(cached_master_mask, 0x21);
outb(0x60 + realirq, 0x20);
}
spin_unlock_irqrestore(&i8259A_lock, flags);
desc = irq_desc + realirq;
/*
* handle this 'virtual interrupt' as a Cobalt one now.
*/
kstat_cpu(smp_processor_id()).irqs[realirq]++;
if (likely(desc->action != NULL))
handle_IRQ_event(realirq, desc->action);
if (!(desc->status & IRQ_DISABLED))
enable_8259A_irq(realirq);
return IRQ_HANDLED;
out_unlock:
spin_unlock_irqrestore(&i8259A_lock, flags);
return IRQ_NONE;
}
static struct irqaction master_action = {
.handler = piix4_master_intr,
.name = "PIIX4-8259",
};
static struct irqaction cascade_action = {
.handler = no_action,
.name = "cascade",
};
void init_VISWS_APIC_irqs(void)
{
int i;
for (i = 0; i < CO_IRQ_APIC0 + CO_APIC_LAST + 1; i++) {
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = 0;
irq_desc[i].depth = 1;
if (i == 0) {
irq_desc[i].chip = &cobalt_irq_type;
}
else if (i == CO_IRQ_IDE0) {
irq_desc[i].chip = &cobalt_irq_type;
}
else if (i == CO_IRQ_IDE1) {
irq_desc[i].chip = &cobalt_irq_type;
}
else if (i == CO_IRQ_8259) {
irq_desc[i].chip = &piix4_master_irq_type;
}
else if (i < CO_IRQ_APIC0) {
irq_desc[i].chip = &piix4_virtual_irq_type;
}
else if (IS_CO_APIC(i)) {
irq_desc[i].chip = &cobalt_irq_type;
}
}
setup_irq(CO_IRQ_8259, &master_action);
setup_irq(2, &cascade_action);
}

View File

@ -9,9 +9,7 @@ pci-y := fixup.o
pci-$(CONFIG_ACPI) += acpi.o
pci-y += legacy.o irq.o
# Careful: VISWS overrule the pci-y above. The colons are
# therefor correct. This needs a proper fix by distangling the code.
pci-$(CONFIG_X86_VISWS) := visws.o fixup.o
pci-$(CONFIG_X86_VISWS) += visws.o
pci-$(CONFIG_X86_NUMAQ) += numa.o

View File

@ -62,6 +62,11 @@ int __init pci_subsys_init(void)
#endif
pci_legacy_init();
pcibios_irq_init();
#ifdef CONFIG_X86_NUMAQ
pci_numa_init();
#endif
pcibios_init();
return 0;
}
subsys_initcall(pci_subsys_init);

View File

@ -151,7 +151,7 @@ static void __devinit pci_fixup_i450nx(struct pci_dev *d)
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82451NX, pci_fixup_i450nx);
static int __init pci_numa_init(void)
int __init pci_numa_init(void)
{
int quad;
@ -176,11 +176,3 @@ static int __init pci_numa_init(void)
}
return 0;
}
static __init int pci_subsys_init(void)
{
pci_numa_init();
pcibios_irq_init();
pcibios_init();
}
subsys_initcall(pci_subsys_init);

View File

@ -107,6 +107,7 @@ extern void __init dmi_check_skip_isa_align(void);
/* some common used subsys_initcalls */
extern int __init pci_acpi_init(void);
extern int __init pcibios_irq_init(void);
extern int __init pci_numa_init(void);
extern int __init pcibios_init(void);
/* pci-mmconfig.c */

View File

@ -8,18 +8,19 @@
#include <linux/pci.h>
#include <linux/init.h>
#include "cobalt.h"
#include "lithium.h"
#include <asm/setup.h>
#include <asm/visws/cobalt.h>
#include <asm/visws/lithium.h>
#include "pci.h"
static int pci_visws_enable_irq(struct pci_dev *dev) { return 0; }
static void pci_visws_disable_irq(struct pci_dev *dev) { }
int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq;
void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq;
/* int (*pcibios_enable_irq)(struct pci_dev *dev) = &pci_visws_enable_irq; */
/* void (*pcibios_disable_irq)(struct pci_dev *dev) = &pci_visws_disable_irq; */
void __init pcibios_penalize_isa_irq(int irq, int active) {}
/* void __init pcibios_penalize_isa_irq(int irq, int active) {} */
unsigned int pci_bus0, pci_bus1;
@ -107,7 +108,15 @@ static int __init pci_visws_init(void)
static __init int pci_subsys_init(void)
{
if (!is_visws_box())
return -1;
pcibios_enable_irq = &pci_visws_enable_irq;
pcibios_disable_irq = &pci_visws_disable_irq;
pci_visws_init();
pcibios_init();
return 0;
}
subsys_initcall(pci_subsys_init);

View File

@ -4,7 +4,6 @@
menuconfig ACPI
bool "ACPI (Advanced Configuration and Power Interface) Support"
depends on !X86_VISWS
depends on !IA64_HP_SIM
depends on IA64 || X86
depends on PCI

View File

@ -1,6 +1,6 @@
config LGUEST
tristate "Linux hypervisor example code"
depends on X86_32 && EXPERIMENTAL && !X86_PAE && FUTEX && !(X86_VISWS || X86_VOYAGER)
depends on X86_32 && EXPERIMENTAL && !X86_PAE && FUTEX && !X86_VOYAGER
select HVC_DRIVER
---help---
This is a very simple module which allows you to run

View File

@ -21,8 +21,7 @@
#include <asm/io.h>
#include <asm/mtrr.h>
#include <setup_arch.h>
#include <asm/visws/sgivw.h>
#define INCLUDE_TIMING_TABLE_DATA
#define DBE_REG_BASE par->regs

View File

@ -107,9 +107,9 @@
#define LAST_VM86_IRQ 15
#define invalid_vm86_irq(irq) ((irq) < 3 || (irq) > 15)
#if !defined(CONFIG_X86_VISWS) && !defined(CONFIG_X86_VOYAGER)
#if !defined(CONFIG_X86_VOYAGER)
# if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_PARAVIRT)
# if defined(CONFIG_X86_IO_APIC) || defined(CONFIG_PARAVIRT) || defined(CONFIG_X86_VISWS)
# define NR_IRQS 224

View File

@ -3,7 +3,9 @@
static inline void smpboot_clear_io_apic_irqs(void)
{
#ifdef CONFIG_X86_IO_APIC
io_apic_irqs = 0;
#endif
}
static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
@ -35,6 +37,7 @@ static inline void smpboot_restore_warm_reset_vector(void)
static inline void __init smpboot_setup_io_apic(void)
{
#ifdef CONFIG_X86_IO_APIC
/*
* Here we can be sure that there is an IO-APIC in the system. Let's
* go and set it up:
@ -45,9 +48,12 @@ static inline void __init smpboot_setup_io_apic(void)
nr_ioapics = 0;
localise_nmi_watchdog();
}
#endif
}
static inline void smpboot_clear_io_apic(void)
{
#ifdef CONFIG_X86_IO_APIC
nr_ioapics = 0;
#endif
}

View File

@ -1,103 +1 @@
#ifndef __ASM_MACH_APIC_H
#define __ASM_MACH_APIC_H
#include <mach_apicdef.h>
#include <asm/smp.h>
#define APIC_DFR_VALUE (APIC_DFR_FLAT)
#define no_balance_irq (0)
#define esr_disable (0)
#define INT_DELIVERY_MODE dest_LowestPrio
#define INT_DEST_MODE 1 /* logical delivery broadcast to all procs */
#ifdef CONFIG_SMP
#define TARGET_CPUS cpu_online_map
#else
#define TARGET_CPUS cpumask_of_cpu(0)
#endif
#define check_apicid_used(bitmap, apicid) physid_isset(apicid, bitmap)
#define check_apicid_present(bit) physid_isset(bit, phys_cpu_present_map)
static inline int apic_id_registered(void)
{
return physid_isset(GET_APIC_ID(read_apic_id()), phys_cpu_present_map);
}
/*
* Set up the logical destination ID.
*
* Intel recommends to set DFR, LDR and TPR before enabling
* an APIC. See e.g. "AP-388 82489DX User's Manual" (Intel
* document number 292116). So here it goes...
*/
static inline void init_apic_ldr(void)
{
unsigned long val;
apic_write_around(APIC_DFR, APIC_DFR_VALUE);
val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
val |= SET_APIC_LOGICAL_ID(1UL << smp_processor_id());
apic_write_around(APIC_LDR, val);
}
static inline void summit_check(char *oem, char *productid)
{
}
static inline void setup_apic_routing(void)
{
}
static inline int apicid_to_node(int logical_apicid)
{
return 0;
}
/* Mapping from cpu number to logical apicid */
static inline int cpu_to_logical_apicid(int cpu)
{
return 1 << cpu;
}
static inline int cpu_present_to_apicid(int mps_cpu)
{
if (mps_cpu < get_physical_broadcast())
return mps_cpu;
else
return BAD_APICID;
}
static inline physid_mask_t apicid_to_cpu_present(int apicid)
{
return physid_mask_of_physid(apicid);
}
#define WAKE_SECONDARY_VIA_INIT
static inline void setup_portio_remap(void)
{
}
static inline void enable_apic_mode(void)
{
}
static inline int check_phys_apicid_present(int boot_cpu_physical_apicid)
{
return physid_isset(boot_cpu_physical_apicid, phys_cpu_present_map);
}
static inline unsigned int cpu_mask_to_apicid(cpumask_t cpumask)
{
return cpus_addr(cpumask)[0];
}
static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
{
return cpuid_apic >> index_msb;
}
#endif /* __ASM_MACH_APIC_H */
#include "../mach-default/mach_apic.h"

View File

@ -1,12 +1 @@
#ifndef __ASM_MACH_APICDEF_H
#define __ASM_MACH_APICDEF_H
#define APIC_ID_MASK (0xF<<24)
static inline unsigned get_apic_id(unsigned long x)
{
return (((x)>>24)&0xF);
}
#define GET_APIC_ID(x) get_apic_id(x)
#endif
#include "../mach-default/mach_apicdef.h"

View File

@ -1,6 +1 @@
/* Hook to call BIOS initialisation function */
extern unsigned long sgivwfb_mem_phys;
extern unsigned long sgivwfb_mem_size;
/* no action for visws */
#include "../mach-default/setup_arch.h"

View File

@ -1,28 +1 @@
static inline void smpboot_setup_warm_reset_vector(unsigned long start_eip)
{
CMOS_WRITE(0xa, 0xf);
local_flush_tlb();
Dprintk("1.\n");
*((volatile unsigned short *) TRAMPOLINE_HIGH) = start_eip >> 4;
Dprintk("2.\n");
*((volatile unsigned short *) TRAMPOLINE_LOW) = start_eip & 0xf;
Dprintk("3.\n");
}
/* for visws do nothing for any of these */
static inline void smpboot_clear_io_apic_irqs(void)
{
}
static inline void smpboot_restore_warm_reset_vector(void)
{
}
static inline void smpboot_setup_io_apic(void)
{
}
static inline void smpboot_clear_io_apic(void)
{
}
#include "../mach-default/smpboot_hooks.h"

View File

@ -8,6 +8,25 @@
/* Interrupt control for vSMPowered x86_64 systems */
void vsmp_init(void);
#ifdef CONFIG_X86_VISWS
extern void visws_early_detect(void);
extern int is_visws_box(void);
#else
static inline void visws_early_detect(void) { }
static inline int is_visws_box(void) { return 0; }
#endif
/*
* Any setup quirks to be performed?
*/
extern int (*arch_time_init_quirk)(void);
extern int (*arch_pre_intr_init_quirk)(void);
extern int (*arch_intr_init_quirk)(void);
extern int (*arch_trap_init_quirk)(void);
extern char * (*arch_memory_setup_quirk)(void);
extern int (*mach_get_smp_config_quirk)(unsigned int early);
extern int (*mach_find_smp_config_quirk)(unsigned int reserve);
#ifndef CONFIG_PARAVIRT
#define paravirt_post_allocator_init() do {} while (0)
#endif

View File

@ -0,0 +1,5 @@
/*
* Frame buffer position and size:
*/
extern unsigned long sgivwfb_mem_phys;
extern unsigned long sgivwfb_mem_size;

View File

@ -150,7 +150,7 @@
#include <linux/interrupt.h>
#include <linux/mutex.h>
#include <asm/mach-visws/cobalt.h>
#include <asm/visws/cobalt.h>
#include "sound_config.h"