mirror of
https://github.com/AetherDroid/android_kernel_samsung_on5xelte.git
synced 2025-09-09 01:28:05 -04:00
Fixed MTP to work with TWRP
This commit is contained in:
commit
f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions
46
arch/mips/sgi-ip27/Kconfig
Normal file
46
arch/mips/sgi-ip27/Kconfig
Normal file
|
@ -0,0 +1,46 @@
|
|||
choice
|
||||
prompt "Node addressing mode"
|
||||
depends on SGI_IP27
|
||||
default SGI_SN_M_MODE
|
||||
|
||||
config SGI_SN_M_MODE
|
||||
bool "IP27 M-Mode"
|
||||
help
|
||||
The nodes of Origin, Onyx, Fuel and Tezro systems can be configured
|
||||
in either N-Modes which allows for more nodes or M-Mode which allows
|
||||
for more memory. Your hardware is almost certainly running in
|
||||
M-Mode, so choose M-mode here.
|
||||
|
||||
config SGI_SN_N_MODE
|
||||
bool "IP27 N-Mode"
|
||||
help
|
||||
The nodes of Origin, Onyx, Fuel and Tezro systems can be configured
|
||||
in either N-Modes which allows for more nodes or M-Mode which allows
|
||||
for more memory. Your hardware is almost certainly running in
|
||||
M-Mode, so choose M-mode here.
|
||||
|
||||
endchoice
|
||||
|
||||
config MAPPED_KERNEL
|
||||
bool "Mapped kernel support"
|
||||
depends on SGI_IP27
|
||||
help
|
||||
Change the way a Linux kernel is loaded into memory on a MIPS64
|
||||
machine. This is required in order to support text replication on
|
||||
NUMA. If you need to understand it, read the source code.
|
||||
|
||||
config REPLICATE_KTEXT
|
||||
bool "Kernel text replication support"
|
||||
depends on SGI_IP27
|
||||
select MAPPED_KERNEL
|
||||
help
|
||||
Say Y here to enable replicating the kernel text across multiple
|
||||
nodes in a NUMA cluster. This trades memory for speed.
|
||||
|
||||
config REPLICATE_EXHANDLERS
|
||||
bool "Exception handler replication support"
|
||||
depends on SGI_IP27
|
||||
help
|
||||
Say Y here to enable replicating the kernel exception handlers
|
||||
across multiple nodes in a NUMA cluster. This trades memory for
|
||||
speed.
|
11
arch/mips/sgi-ip27/Makefile
Normal file
11
arch/mips/sgi-ip27/Makefile
Normal file
|
@ -0,0 +1,11 @@
|
|||
#
|
||||
# Makefile for the IP27 specific kernel interface routines under Linux.
|
||||
#
|
||||
|
||||
obj-y := ip27-berr.o ip27-irq.o ip27-init.o ip27-klconfig.o ip27-klnuma.o \
|
||||
ip27-memory.o ip27-nmi.o ip27-reset.o ip27-timer.o ip27-hubio.o \
|
||||
ip27-xtalk.o
|
||||
|
||||
obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o
|
||||
obj-$(CONFIG_PCI) += ip27-irq-pci.o
|
||||
obj-$(CONFIG_SMP) += ip27-smp.o
|
19
arch/mips/sgi-ip27/Platform
Normal file
19
arch/mips/sgi-ip27/Platform
Normal file
|
@ -0,0 +1,19 @@
|
|||
#
|
||||
# SGI-IP27 (Origin200/2000)
|
||||
#
|
||||
# Set the load address to >= 0xc000000000300000 if you want to leave space for
|
||||
# symmon, 0xc00000000001c000 for production kernels. Note that the value must
|
||||
# be 16kb aligned or the handling of the current variable will break.
|
||||
#
|
||||
ifdef CONFIG_SGI_IP27
|
||||
platform-$(CONFIG_SGI_IP27) += sgi-ip27/
|
||||
cflags-$(CONFIG_SGI_IP27) += -I$(srctree)/arch/mips/include/asm/mach-ip27
|
||||
ifdef CONFIG_MAPPED_KERNEL
|
||||
load-$(CONFIG_SGI_IP27) += 0xc00000004001c000
|
||||
OBJCOPYFLAGS := --change-addresses=0x3fffffff80000000
|
||||
dataoffset-$(CONFIG_SGI_IP27) += 0x01000000
|
||||
else
|
||||
load-$(CONFIG_SGI_IP27) += 0xa80000000001c000
|
||||
OBJCOPYFLAGS := --change-addresses=0x57ffffff80000000
|
||||
endif
|
||||
endif
|
19
arch/mips/sgi-ip27/TODO
Normal file
19
arch/mips/sgi-ip27/TODO
Normal file
|
@ -0,0 +1,19 @@
|
|||
1. Need to figure out why PCI writes to the IOC3 hang, and if it is okay
|
||||
not to write to the IOC3 ever.
|
||||
2. Need to figure out RRB allocation in bridge_startup().
|
||||
3. Need to figure out why address swaizzling is needed in inw/outw for
|
||||
Qlogic scsi controllers.
|
||||
4. Need to integrate ip27-klconfig.c:find_lboard and
|
||||
ip27-init.c:find_lbaord_real. DONE
|
||||
5. Is it okay to set calias space on all nodes as 0, instead of 8k as
|
||||
in irix?
|
||||
6. Investigate why things do not work without the setup_test() call
|
||||
being invoked on all nodes in ip27-memory.c.
|
||||
8. Too many do_page_faults invoked - investigate.
|
||||
9. start_thread must turn off UX64 ... and define tlb_refill_debug.
|
||||
10. Need a bad pmd table, bad pte table. __bad_pmd_table/__bad_pagetable
|
||||
does not agree with pgd_bad/pmd_bad.
|
||||
11. All intrs (ip27_do_irq handlers) are targeted at cpu A on the node.
|
||||
This might need to change later. Only the timer intr is set up to be
|
||||
received on both Cpu A and B. (ip27_do_irq()/bridge_startup())
|
||||
13. Cache flushing (specially the SMP version) has to be investigated.
|
93
arch/mips/sgi-ip27/ip27-berr.c
Normal file
93
arch/mips/sgi-ip27/ip27-berr.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 1994, 1995, 1996, 1999, 2000 by Ralf Baechle
|
||||
* Copyright (C) 1999, 2000 by Silicon Graphics
|
||||
* Copyright (C) 2002 Maciej W. Rozycki
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/signal.h> /* for SIGBUS */
|
||||
#include <linux/sched.h> /* schow_regs(), force_sig() */
|
||||
|
||||
#include <asm/module.h>
|
||||
#include <asm/sn/addrs.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/sn0/hub.h>
|
||||
#include <asm/tlbdebug.h>
|
||||
#include <asm/traps.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
static void dump_hub_information(unsigned long errst0, unsigned long errst1)
|
||||
{
|
||||
static char *err_type[2][8] = {
|
||||
{ NULL, "Uncached Partial Read PRERR", "DERR", "Read Timeout",
|
||||
NULL, NULL, NULL, NULL },
|
||||
{ "WERR", "Uncached Partial Write", "PWERR", "Write Timeout",
|
||||
NULL, NULL, NULL, NULL }
|
||||
};
|
||||
int wrb = errst1 & PI_ERR_ST1_WRBRRB_MASK;
|
||||
|
||||
if (!(errst0 & PI_ERR_ST0_VALID_MASK)) {
|
||||
printk("Hub does not contain valid error information\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
printk("Hub has valid error information:\n");
|
||||
if (errst0 & PI_ERR_ST0_OVERRUN_MASK)
|
||||
printk("Overrun is set. Error stack may contain additional "
|
||||
"information.\n");
|
||||
printk("Hub error address is %08lx\n",
|
||||
(errst0 & PI_ERR_ST0_ADDR_MASK) >> (PI_ERR_ST0_ADDR_SHFT - 3));
|
||||
printk("Incoming message command 0x%lx\n",
|
||||
(errst0 & PI_ERR_ST0_CMD_MASK) >> PI_ERR_ST0_CMD_SHFT);
|
||||
printk("Supplemental field of incoming message is 0x%lx\n",
|
||||
(errst0 & PI_ERR_ST0_SUPPL_MASK) >> PI_ERR_ST0_SUPPL_SHFT);
|
||||
printk("T5 Rn (for RRB only) is 0x%lx\n",
|
||||
(errst0 & PI_ERR_ST0_REQNUM_MASK) >> PI_ERR_ST0_REQNUM_SHFT);
|
||||
printk("Error type is %s\n", err_type[wrb]
|
||||
[(errst0 & PI_ERR_ST0_TYPE_MASK) >> PI_ERR_ST0_TYPE_SHFT]
|
||||
? : "invalid");
|
||||
}
|
||||
|
||||
int ip27_be_handler(struct pt_regs *regs, int is_fixup)
|
||||
{
|
||||
unsigned long errst0, errst1;
|
||||
int data = regs->cp0_cause & 4;
|
||||
int cpu = LOCAL_HUB_L(PI_CPU_NUM);
|
||||
|
||||
if (is_fixup)
|
||||
return MIPS_BE_FIXUP;
|
||||
|
||||
printk("Slice %c got %cbe at 0x%lx\n", 'A' + cpu, data ? 'd' : 'i',
|
||||
regs->cp0_epc);
|
||||
printk("Hub information:\n");
|
||||
printk("ERR_INT_PEND = 0x%06llx\n", LOCAL_HUB_L(PI_ERR_INT_PEND));
|
||||
errst0 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS0_B : PI_ERR_STATUS0_A);
|
||||
errst1 = LOCAL_HUB_L(cpu ? PI_ERR_STATUS1_B : PI_ERR_STATUS1_A);
|
||||
dump_hub_information(errst0, errst1);
|
||||
show_regs(regs);
|
||||
dump_tlb_all();
|
||||
while(1);
|
||||
force_sig(SIGBUS, current);
|
||||
}
|
||||
|
||||
void __init ip27_be_init(void)
|
||||
{
|
||||
/* XXX Initialize all the Hub & Bridge error handling here. */
|
||||
int cpu = LOCAL_HUB_L(PI_CPU_NUM);
|
||||
int cpuoff = cpu << 8;
|
||||
|
||||
board_be_handler = ip27_be_handler;
|
||||
|
||||
LOCAL_HUB_S(PI_ERR_INT_PEND,
|
||||
cpu ? PI_ERR_CLEAR_ALL_B : PI_ERR_CLEAR_ALL_A);
|
||||
LOCAL_HUB_S(PI_ERR_INT_MASK_A + cpuoff, 0);
|
||||
LOCAL_HUB_S(PI_ERR_STACK_ADDR_A + cpuoff, 0);
|
||||
LOCAL_HUB_S(PI_ERR_STACK_SIZE, 0); /* Disable error stack */
|
||||
LOCAL_HUB_S(PI_SYSAD_ERRCHK_EN, PI_SYSAD_CHECK_ALL);
|
||||
}
|
39
arch/mips/sgi-ip27/ip27-console.c
Normal file
39
arch/mips/sgi-ip27/ip27-console.c
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2001, 2002 Ralf Baechle
|
||||
*/
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/sn/addrs.h>
|
||||
#include <asm/sn/sn0/hub.h>
|
||||
#include <asm/sn/klconfig.h>
|
||||
#include <asm/sn/ioc3.h>
|
||||
#include <asm/sn/sn_private.h>
|
||||
|
||||
#include <linux/serial.h>
|
||||
#include <linux/serial_core.h>
|
||||
|
||||
#define IOC3_CLK (22000000 / 3)
|
||||
#define IOC3_FLAGS (0)
|
||||
|
||||
static inline struct ioc3_uartregs *console_uart(void)
|
||||
{
|
||||
struct ioc3 *ioc3;
|
||||
nasid_t nasid;
|
||||
|
||||
nasid = (master_nasid == INVALID_NASID) ? get_nasid() : master_nasid;
|
||||
ioc3 = (struct ioc3 *)KL_CONFIG_CH_CONS_INFO(nasid)->memory_base;
|
||||
|
||||
return &ioc3->sregs.uarta;
|
||||
}
|
||||
|
||||
void prom_putchar(char c)
|
||||
{
|
||||
struct ioc3_uartregs *uart = console_uart();
|
||||
|
||||
while ((uart->iu_lsr & 0x20) == 0);
|
||||
uart->iu_thr = c;
|
||||
}
|
185
arch/mips/sgi-ip27/ip27-hubio.c
Normal file
185
arch/mips/sgi-ip27/ip27-hubio.c
Normal file
|
@ -0,0 +1,185 @@
|
|||
/*
|
||||
* Copyright (C) 1992-1997, 2000-2003 Silicon Graphics, Inc.
|
||||
* Copyright (C) 2004 Christoph Hellwig.
|
||||
* Released under GPL v2.
|
||||
*
|
||||
* Support functions for the HUB ASIC - mostly PIO mapping related.
|
||||
*/
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/mmzone.h>
|
||||
#include <asm/sn/addrs.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/hub.h>
|
||||
|
||||
|
||||
static int force_fire_and_forget = 1;
|
||||
|
||||
/**
|
||||
* hub_pio_map - establish a HUB PIO mapping
|
||||
*
|
||||
* @hub: hub to perform PIO mapping on
|
||||
* @widget: widget ID to perform PIO mapping for
|
||||
* @xtalk_addr: xtalk_address that needs to be mapped
|
||||
* @size: size of the PIO mapping
|
||||
*
|
||||
**/
|
||||
unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget,
|
||||
unsigned long xtalk_addr, size_t size)
|
||||
{
|
||||
nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
|
||||
unsigned i;
|
||||
|
||||
/* use small-window mapping if possible */
|
||||
if ((xtalk_addr % SWIN_SIZE) + size <= SWIN_SIZE)
|
||||
return NODE_SWIN_BASE(nasid, widget) + (xtalk_addr % SWIN_SIZE);
|
||||
|
||||
if ((xtalk_addr % BWIN_SIZE) + size > BWIN_SIZE) {
|
||||
printk(KERN_WARNING "PIO mapping at hub %d widget %d addr 0x%lx"
|
||||
" too big (%ld)\n",
|
||||
nasid, widget, xtalk_addr, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
xtalk_addr &= ~(BWIN_SIZE-1);
|
||||
for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) {
|
||||
if (test_and_set_bit(i, hub_data(cnode)->h_bigwin_used))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* The code below does a PIO write to setup an ITTE entry.
|
||||
*
|
||||
* We need to prevent other CPUs from seeing our updated
|
||||
* memory shadow of the ITTE (in the piomap) until the ITTE
|
||||
* entry is actually set up; otherwise, another CPU might
|
||||
* attempt a PIO prematurely.
|
||||
*
|
||||
* Also, the only way we can know that an entry has been
|
||||
* received by the hub and can be used by future PIO reads/
|
||||
* writes is by reading back the ITTE entry after writing it.
|
||||
*
|
||||
* For these two reasons, we PIO read back the ITTE entry
|
||||
* after we write it.
|
||||
*/
|
||||
IIO_ITTE_PUT(nasid, i, HUB_PIO_MAP_TO_MEM, widget, xtalk_addr);
|
||||
(void) HUB_L(IIO_ITTE_GET(nasid, i));
|
||||
|
||||
return NODE_BWIN_BASE(nasid, widget) + (xtalk_addr % BWIN_SIZE);
|
||||
}
|
||||
|
||||
printk(KERN_WARNING "unable to establish PIO mapping for at"
|
||||
" hub %d widget %d addr 0x%lx\n",
|
||||
nasid, widget, xtalk_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* hub_setup_prb(nasid, prbnum, credits, conveyor)
|
||||
*
|
||||
* Put a PRB into fire-and-forget mode if conveyor isn't set. Otherwise,
|
||||
* put it into conveyor belt mode with the specified number of credits.
|
||||
*/
|
||||
static void hub_setup_prb(nasid_t nasid, int prbnum, int credits)
|
||||
{
|
||||
iprb_t prb;
|
||||
int prb_offset;
|
||||
|
||||
/*
|
||||
* Get the current register value.
|
||||
*/
|
||||
prb_offset = IIO_IOPRB(prbnum);
|
||||
prb.iprb_regval = REMOTE_HUB_L(nasid, prb_offset);
|
||||
|
||||
/*
|
||||
* Clear out some fields.
|
||||
*/
|
||||
prb.iprb_ovflow = 1;
|
||||
prb.iprb_bnakctr = 0;
|
||||
prb.iprb_anakctr = 0;
|
||||
|
||||
/*
|
||||
* Enable or disable fire-and-forget mode.
|
||||
*/
|
||||
prb.iprb_ff = force_fire_and_forget ? 1 : 0;
|
||||
|
||||
/*
|
||||
* Set the appropriate number of PIO cresits for the widget.
|
||||
*/
|
||||
prb.iprb_xtalkctr = credits;
|
||||
|
||||
/*
|
||||
* Store the new value to the register.
|
||||
*/
|
||||
REMOTE_HUB_S(nasid, prb_offset, prb.iprb_regval);
|
||||
}
|
||||
|
||||
/**
|
||||
* hub_set_piomode - set pio mode for a given hub
|
||||
*
|
||||
* @nasid: physical node ID for the hub in question
|
||||
*
|
||||
* Put the hub into either "PIO conveyor belt" mode or "fire-and-forget" mode.
|
||||
* To do this, we have to make absolutely sure that no PIOs are in progress
|
||||
* so we turn off access to all widgets for the duration of the function.
|
||||
*
|
||||
* XXX - This code should really check what kind of widget we're talking
|
||||
* to. Bridges can only handle three requests, but XG will do more.
|
||||
* How many can crossbow handle to widget 0? We're assuming 1.
|
||||
*
|
||||
* XXX - There is a bug in the crossbow that link reset PIOs do not
|
||||
* return write responses. The easiest solution to this problem is to
|
||||
* leave widget 0 (xbow) in fire-and-forget mode at all times. This
|
||||
* only affects pio's to xbow registers, which should be rare.
|
||||
**/
|
||||
static void hub_set_piomode(nasid_t nasid)
|
||||
{
|
||||
hubreg_t ii_iowa;
|
||||
hubii_wcr_t ii_wcr;
|
||||
unsigned i;
|
||||
|
||||
ii_iowa = REMOTE_HUB_L(nasid, IIO_OUTWIDGET_ACCESS);
|
||||
REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, 0);
|
||||
|
||||
ii_wcr.wcr_reg_value = REMOTE_HUB_L(nasid, IIO_WCR);
|
||||
|
||||
if (ii_wcr.iwcr_dir_con) {
|
||||
/*
|
||||
* Assume a bridge here.
|
||||
*/
|
||||
hub_setup_prb(nasid, 0, 3);
|
||||
} else {
|
||||
/*
|
||||
* Assume a crossbow here.
|
||||
*/
|
||||
hub_setup_prb(nasid, 0, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* XXX - Here's where we should take the widget type into
|
||||
* when account assigning credits.
|
||||
*/
|
||||
for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++)
|
||||
hub_setup_prb(nasid, i, 3);
|
||||
|
||||
REMOTE_HUB_S(nasid, IIO_OUTWIDGET_ACCESS, ii_iowa);
|
||||
}
|
||||
|
||||
/*
|
||||
* hub_pio_init - PIO-related hub initialization
|
||||
*
|
||||
* @hub: hubinfo structure for our hub
|
||||
*/
|
||||
void hub_pio_init(cnodeid_t cnode)
|
||||
{
|
||||
nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
|
||||
unsigned i;
|
||||
|
||||
/* initialize big window piomaps for this hub */
|
||||
bitmap_zero(hub_data(cnode)->h_bigwin_used, HUB_NUM_BIG_WINDOW);
|
||||
for (i = 0; i < HUB_NUM_BIG_WINDOW; i++)
|
||||
IIO_ITTE_DISABLE(nasid, i);
|
||||
|
||||
hub_set_piomode(nasid);
|
||||
}
|
221
arch/mips/sgi-ip27/ip27-init.c
Normal file
221
arch/mips/sgi-ip27/ip27-init.c
Normal file
|
@ -0,0 +1,221 @@
|
|||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License. See the file "COPYING" in the main directory of this
|
||||
* archive for more details.
|
||||
*
|
||||
* Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
|
||||
* Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <asm/cpu.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/time.h>
|
||||
#include <asm/sn/types.h>
|
||||
#include <asm/sn/sn0/addrs.h>
|
||||
#include <asm/sn/sn0/hubni.h>
|
||||
#include <asm/sn/sn0/hubio.h>
|
||||
#include <asm/sn/klconfig.h>
|
||||
#include <asm/sn/ioc3.h>
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/sn/gda.h>
|
||||
#include <asm/sn/hub.h>
|
||||
#include <asm/sn/intr.h>
|
||||
#include <asm/current.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/mmu_context.h>
|
||||
#include <asm/thread_info.h>
|
||||
#include <asm/sn/launch.h>
|
||||
#include <asm/sn/sn_private.h>
|
||||
#include <asm/sn/sn0/ip27.h>
|
||||
#include <asm/sn/mapped_kernel.h>
|
||||
|
||||
#define CPU_NONE (cpuid_t)-1
|
||||
|
||||
static DECLARE_BITMAP(hub_init_mask, MAX_COMPACT_NODES);
|
||||
nasid_t master_nasid = INVALID_NASID;
|
||||
|
||||
cnodeid_t nasid_to_compact_node[MAX_NASIDS];
|
||||
nasid_t compact_to_nasid_node[MAX_COMPACT_NODES];
|
||||
cnodeid_t cpuid_to_compact_node[MAXCPUS];
|
||||
|
||||
EXPORT_SYMBOL(nasid_to_compact_node);
|
||||
|
||||
struct cpuinfo_ip27 sn_cpu_info[NR_CPUS];
|
||||
EXPORT_SYMBOL_GPL(sn_cpu_info);
|
||||
|
||||
extern void pcibr_setup(cnodeid_t);
|
||||
|
||||
extern void xtalk_probe_node(cnodeid_t nid);
|
||||
|
||||
static void per_hub_init(cnodeid_t cnode)
|
||||
{
|
||||
struct hub_data *hub = hub_data(cnode);
|
||||
nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
|
||||
int i;
|
||||
|
||||
cpu_set(smp_processor_id(), hub->h_cpus);
|
||||
|
||||
if (test_and_set_bit(cnode, hub_init_mask))
|
||||
return;
|
||||
/*
|
||||
* Set CRB timeout at 5ms, (< PI timeout of 10ms)
|
||||
*/
|
||||
REMOTE_HUB_S(nasid, IIO_ICTP, 0x800);
|
||||
REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);
|
||||
|
||||
hub_rtc_init(cnode);
|
||||
xtalk_probe_node(cnode);
|
||||
|
||||
#ifdef CONFIG_REPLICATE_EXHANDLERS
|
||||
/*
|
||||
* If this is not a headless node initialization,
|
||||
* copy over the caliased exception handlers.
|
||||
*/
|
||||
if (get_compact_nodeid() == cnode) {
|
||||
extern char except_vec2_generic, except_vec3_generic;
|
||||
extern void build_tlb_refill_handler(void);
|
||||
|
||||
memcpy((void *)(CKSEG0 + 0x100), &except_vec2_generic, 0x80);
|
||||
memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x80);
|
||||
build_tlb_refill_handler();
|
||||
memcpy((void *)(CKSEG0 + 0x100), (void *) CKSEG0, 0x80);
|
||||
memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x100);
|
||||
__flush_cache_all();
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Some interrupts are reserved by hardware or by software convention.
|
||||
* Mark these as reserved right away so they won't be used accidentally
|
||||
* later.
|
||||
*/
|
||||
for (i = 0; i <= BASE_PCI_IRQ; i++) {
|
||||
__set_bit(i, hub->irq_alloc_mask);
|
||||
LOCAL_HUB_CLR_INTR(INT_PEND0_BASELVL + i);
|
||||
}
|
||||
|
||||
__set_bit(IP_PEND0_6_63, hub->irq_alloc_mask);
|
||||
LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63);
|
||||
|
||||
for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) {
|
||||
__set_bit(i, hub->irq_alloc_mask);
|
||||
LOCAL_HUB_CLR_INTR(INT_PEND1_BASELVL + i);
|
||||
}
|
||||
}
|
||||
|
||||
void per_cpu_init(void)
|
||||
{
|
||||
int cpu = smp_processor_id();
|
||||
int slice = LOCAL_HUB_L(PI_CPU_NUM);
|
||||
cnodeid_t cnode = get_compact_nodeid();
|
||||
struct hub_data *hub = hub_data(cnode);
|
||||
struct slice_data *si = hub->slice + slice;
|
||||
int i;
|
||||
|
||||
if (test_and_set_bit(slice, &hub->slice_map))
|
||||
return;
|
||||
|
||||
clear_c0_status(ST0_IM);
|
||||
|
||||
per_hub_init(cnode);
|
||||
|
||||
for (i = 0; i < LEVELS_PER_SLICE; i++)
|
||||
si->level_to_irq[i] = -1;
|
||||
|
||||
/*
|
||||
* We use this so we can find the local hub's data as fast as only
|
||||
* possible.
|
||||
*/
|
||||
cpu_data[cpu].data = si;
|
||||
|
||||
cpu_time_init();
|
||||
install_ipi();
|
||||
|
||||
/* Install our NMI handler if symmon hasn't installed one. */
|
||||
install_cpu_nmi_handler(cputoslice(cpu));
|
||||
|
||||
set_c0_status(SRB_DEV0 | SRB_DEV1);
|
||||
}
|
||||
|
||||
/*
|
||||
* get_nasid() returns the physical node id number of the caller.
|
||||
*/
|
||||
nasid_t
|
||||
get_nasid(void)
|
||||
{
|
||||
return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK)
|
||||
>> NSRI_NODEID_SHFT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Map the physical node id to a virtual node id (virtual node ids are contiguous).
|
||||
*/
|
||||
cnodeid_t get_compact_nodeid(void)
|
||||
{
|
||||
return NASID_TO_COMPACT_NODEID(get_nasid());
|
||||
}
|
||||
|
||||
static inline void ioc3_eth_init(void)
|
||||
{
|
||||
struct ioc3 *ioc3;
|
||||
nasid_t nid;
|
||||
|
||||
nid = get_nasid();
|
||||
ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;
|
||||
|
||||
ioc3->eier = 0;
|
||||
}
|
||||
|
||||
extern void ip27_reboot_setup(void);
|
||||
|
||||
void __init plat_mem_setup(void)
|
||||
{
|
||||
hubreg_t p, e, n_mode;
|
||||
nasid_t nid;
|
||||
|
||||
ip27_reboot_setup();
|
||||
|
||||
/*
|
||||
* hub_rtc init and cpu clock intr enabled for later calibrate_delay.
|
||||
*/
|
||||
nid = get_nasid();
|
||||
printk("IP27: Running on node %d.\n", nid);
|
||||
|
||||
p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1;
|
||||
e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1;
|
||||
printk("Node %d has %s primary CPU%s.\n", nid,
|
||||
p ? "a" : "no",
|
||||
e ? ", CPU is running" : "");
|
||||
|
||||
p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1;
|
||||
e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1;
|
||||
printk("Node %d has %s secondary CPU%s.\n", nid,
|
||||
p ? "a" : "no",
|
||||
e ? ", CPU is running" : "");
|
||||
|
||||
/*
|
||||
* Try to catch kernel missconfigurations and give user an
|
||||
* indication what option to select.
|
||||
*/
|
||||
n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK;
|
||||
printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M');
|
||||
#ifdef CONFIG_SGI_SN_N_MODE
|
||||
if (!n_mode)
|
||||
panic("Kernel compiled for M mode.");
|
||||
#else
|
||||
if (n_mode)
|
||||
panic("Kernel compiled for N mode.");
|
||||
#endif
|
||||
|
||||
ioc3_eth_init();
|
||||
per_cpu_init();
|
||||
|
||||
set_io_port_base(IO_BASE);
|
||||
}
|
265
arch/mips/sgi-ip27/ip27-irq-pci.c
Normal file
265
arch/mips/sgi-ip27/ip27-irq-pci.c
Normal file
|
@ -0,0 +1,265 @@
|
|||
/*
|
||||
* ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
|
||||
*
|
||||
* Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
|
||||
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
|
||||
* Copyright (C) 1999 - 2001 Kanoj Sarcar
|
||||
*/
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/irq.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mipsregs.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/pci/bridge.h>
|
||||
#include <asm/sn/addrs.h>
|
||||
#include <asm/sn/agent.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/hub.h>
|
||||
#include <asm/sn/intr.h>
|
||||
|
||||
/*
|
||||
* Linux has a controller-independent x86 interrupt architecture.
|
||||
* every controller has a 'controller-template', that is used
|
||||
* by the main code to do the right thing. Each driver-visible
|
||||
* interrupt source is transparently wired to the appropriate
|
||||
* controller. Thus drivers need not be aware of the
|
||||
* interrupt-controller.
|
||||
*
|
||||
* Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
|
||||
* PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
|
||||
* (IO-APICs assumed to be messaging to Pentium local-APICs)
|
||||
*
|
||||
* the code is designed to be easily extended with new/different
|
||||
* interrupt controllers, without having to do assembly magic.
|
||||
*/
|
||||
|
||||
extern struct bridge_controller *irq_to_bridge[];
|
||||
extern int irq_to_slot[];
|
||||
|
||||
/*
|
||||
* use these macros to get the encoded nasid and widget id
|
||||
* from the irq value
|
||||
*/
|
||||
#define IRQ_TO_BRIDGE(i) irq_to_bridge[(i)]
|
||||
#define SLOT_FROM_PCI_IRQ(i) irq_to_slot[i]
|
||||
|
||||
static inline int alloc_level(int cpu, int irq)
|
||||
{
|
||||
struct hub_data *hub = hub_data(cpu_to_node(cpu));
|
||||
struct slice_data *si = cpu_data[cpu].data;
|
||||
int level;
|
||||
|
||||
level = find_first_zero_bit(hub->irq_alloc_mask, LEVELS_PER_SLICE);
|
||||
if (level >= LEVELS_PER_SLICE)
|
||||
panic("Cpu %d flooded with devices", cpu);
|
||||
|
||||
__set_bit(level, hub->irq_alloc_mask);
|
||||
si->level_to_irq[level] = irq;
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
static inline int find_level(cpuid_t *cpunum, int irq)
|
||||
{
|
||||
int cpu, i;
|
||||
|
||||
for_each_online_cpu(cpu) {
|
||||
struct slice_data *si = cpu_data[cpu].data;
|
||||
|
||||
for (i = BASE_PCI_IRQ; i < LEVELS_PER_SLICE; i++)
|
||||
if (si->level_to_irq[i] == irq) {
|
||||
*cpunum = cpu;
|
||||
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
panic("Could not identify cpu/level for irq %d", irq);
|
||||
}
|
||||
|
||||
static int intr_connect_level(int cpu, int bit)
|
||||
{
|
||||
nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
|
||||
struct slice_data *si = cpu_data[cpu].data;
|
||||
|
||||
set_bit(bit, si->irq_enable_mask);
|
||||
|
||||
if (!cputoslice(cpu)) {
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
|
||||
} else {
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int intr_disconnect_level(int cpu, int bit)
|
||||
{
|
||||
nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
|
||||
struct slice_data *si = cpu_data[cpu].data;
|
||||
|
||||
clear_bit(bit, si->irq_enable_mask);
|
||||
|
||||
if (!cputoslice(cpu)) {
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK0_A, si->irq_enable_mask[0]);
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK1_A, si->irq_enable_mask[1]);
|
||||
} else {
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK0_B, si->irq_enable_mask[0]);
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK1_B, si->irq_enable_mask[1]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Startup one of the (PCI ...) IRQs routes over a bridge. */
|
||||
static unsigned int startup_bridge_irq(struct irq_data *d)
|
||||
{
|
||||
struct bridge_controller *bc;
|
||||
bridgereg_t device;
|
||||
bridge_t *bridge;
|
||||
int pin, swlevel;
|
||||
cpuid_t cpu;
|
||||
|
||||
pin = SLOT_FROM_PCI_IRQ(d->irq);
|
||||
bc = IRQ_TO_BRIDGE(d->irq);
|
||||
bridge = bc->base;
|
||||
|
||||
pr_debug("bridge_startup(): irq= 0x%x pin=%d\n", d->irq, pin);
|
||||
/*
|
||||
* "map" irq to a swlevel greater than 6 since the first 6 bits
|
||||
* of INT_PEND0 are taken
|
||||
*/
|
||||
swlevel = find_level(&cpu, d->irq);
|
||||
bridge->b_int_addr[pin].addr = (0x20000 | swlevel | (bc->nasid << 8));
|
||||
bridge->b_int_enable |= (1 << pin);
|
||||
bridge->b_int_enable |= 0x7ffffe00; /* more stuff in int_enable */
|
||||
|
||||
/*
|
||||
* Enable sending of an interrupt clear packt to the hub on a high to
|
||||
* low transition of the interrupt pin.
|
||||
*
|
||||
* IRIX sets additional bits in the address which are documented as
|
||||
* reserved in the bridge docs.
|
||||
*/
|
||||
bridge->b_int_mode |= (1UL << pin);
|
||||
|
||||
/*
|
||||
* We assume the bridge to have a 1:1 mapping between devices
|
||||
* (slots) and intr pins.
|
||||
*/
|
||||
device = bridge->b_int_device;
|
||||
device &= ~(7 << (pin*3));
|
||||
device |= (pin << (pin*3));
|
||||
bridge->b_int_device = device;
|
||||
|
||||
bridge->b_wid_tflush;
|
||||
|
||||
intr_connect_level(cpu, swlevel);
|
||||
|
||||
return 0; /* Never anything pending. */
|
||||
}
|
||||
|
||||
/* Shutdown one of the (PCI ...) IRQs routes over a bridge. */
|
||||
static void shutdown_bridge_irq(struct irq_data *d)
|
||||
{
|
||||
struct bridge_controller *bc = IRQ_TO_BRIDGE(d->irq);
|
||||
bridge_t *bridge = bc->base;
|
||||
int pin, swlevel;
|
||||
cpuid_t cpu;
|
||||
|
||||
pr_debug("bridge_shutdown: irq 0x%x\n", d->irq);
|
||||
pin = SLOT_FROM_PCI_IRQ(d->irq);
|
||||
|
||||
/*
|
||||
* map irq to a swlevel greater than 6 since the first 6 bits
|
||||
* of INT_PEND0 are taken
|
||||
*/
|
||||
swlevel = find_level(&cpu, d->irq);
|
||||
intr_disconnect_level(cpu, swlevel);
|
||||
|
||||
bridge->b_int_enable &= ~(1 << pin);
|
||||
bridge->b_wid_tflush;
|
||||
}
|
||||
|
||||
static inline void enable_bridge_irq(struct irq_data *d)
|
||||
{
|
||||
cpuid_t cpu;
|
||||
int swlevel;
|
||||
|
||||
swlevel = find_level(&cpu, d->irq); /* Criminal offence */
|
||||
intr_connect_level(cpu, swlevel);
|
||||
}
|
||||
|
||||
static inline void disable_bridge_irq(struct irq_data *d)
|
||||
{
|
||||
cpuid_t cpu;
|
||||
int swlevel;
|
||||
|
||||
swlevel = find_level(&cpu, d->irq); /* Criminal offence */
|
||||
intr_disconnect_level(cpu, swlevel);
|
||||
}
|
||||
|
||||
static struct irq_chip bridge_irq_type = {
|
||||
.name = "bridge",
|
||||
.irq_startup = startup_bridge_irq,
|
||||
.irq_shutdown = shutdown_bridge_irq,
|
||||
.irq_mask = disable_bridge_irq,
|
||||
.irq_unmask = enable_bridge_irq,
|
||||
};
|
||||
|
||||
void register_bridge_irq(unsigned int irq)
|
||||
{
|
||||
irq_set_chip_and_handler(irq, &bridge_irq_type, handle_level_irq);
|
||||
}
|
||||
|
||||
int request_bridge_irq(struct bridge_controller *bc)
|
||||
{
|
||||
int irq = allocate_irqno();
|
||||
int swlevel, cpu;
|
||||
nasid_t nasid;
|
||||
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
/*
|
||||
* "map" irq to a swlevel greater than 6 since the first 6 bits
|
||||
* of INT_PEND0 are taken
|
||||
*/
|
||||
cpu = bc->irq_cpu;
|
||||
swlevel = alloc_level(cpu, irq);
|
||||
if (unlikely(swlevel < 0)) {
|
||||
free_irqno(irq);
|
||||
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
/* Make sure it's not already pending when we connect it. */
|
||||
nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu));
|
||||
REMOTE_HUB_CLR_INTR(nasid, swlevel);
|
||||
|
||||
intr_connect_level(cpu, swlevel);
|
||||
|
||||
register_bridge_irq(irq);
|
||||
|
||||
return irq;
|
||||
}
|
208
arch/mips/sgi-ip27/ip27-irq.c
Normal file
208
arch/mips/sgi-ip27/ip27-irq.c
Normal file
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* ip27-irq.c: Highlevel interrupt handling for IP27 architecture.
|
||||
*
|
||||
* Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
|
||||
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
|
||||
* Copyright (C) 1999 - 2001 Kanoj Sarcar
|
||||
*/
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/irq.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/random.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/bootinfo.h>
|
||||
#include <asm/io.h>
|
||||
#include <asm/mipsregs.h>
|
||||
|
||||
#include <asm/processor.h>
|
||||
#include <asm/sn/addrs.h>
|
||||
#include <asm/sn/agent.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/hub.h>
|
||||
#include <asm/sn/intr.h>
|
||||
|
||||
/*
|
||||
* Linux has a controller-independent x86 interrupt architecture.
|
||||
* every controller has a 'controller-template', that is used
|
||||
* by the main code to do the right thing. Each driver-visible
|
||||
* interrupt source is transparently wired to the appropriate
|
||||
* controller. Thus drivers need not be aware of the
|
||||
* interrupt-controller.
|
||||
*
|
||||
* Various interrupt controllers we handle: 8259 PIC, SMP IO-APIC,
|
||||
* PIIX4's internal 8259 PIC and SGI's Visual Workstation Cobalt (IO-)APIC.
|
||||
* (IO-APICs assumed to be messaging to Pentium local-APICs)
|
||||
*
|
||||
* the code is designed to be easily extended with new/different
|
||||
* interrupt controllers, without having to do assembly magic.
|
||||
*/
|
||||
|
||||
extern asmlinkage void ip27_irq(void);
|
||||
|
||||
/*
|
||||
* Find first bit set
|
||||
*/
|
||||
static int ms1bit(unsigned long x)
|
||||
{
|
||||
int b = 0, s;
|
||||
|
||||
s = 16; if (x >> 16 == 0) s = 0; b += s; x >>= s;
|
||||
s = 8; if (x >> 8 == 0) s = 0; b += s; x >>= s;
|
||||
s = 4; if (x >> 4 == 0) s = 0; b += s; x >>= s;
|
||||
s = 2; if (x >> 2 == 0) s = 0; b += s; x >>= s;
|
||||
s = 1; if (x >> 1 == 0) s = 0; b += s;
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
/*
|
||||
* This code is unnecessarily complex, because we do
|
||||
* intr enabling. Basically, once we grab the set of intrs we need
|
||||
* to service, we must mask _all_ these interrupts; firstly, to make
|
||||
* sure the same intr does not intr again, causing recursion that
|
||||
* can lead to stack overflow. Secondly, we can not just mask the
|
||||
* one intr we are do_IRQing, because the non-masked intrs in the
|
||||
* first set might intr again, causing multiple servicings of the
|
||||
* same intr. This effect is mostly seen for intercpu intrs.
|
||||
* Kanoj 05.13.00
|
||||
*/
|
||||
|
||||
static void ip27_do_irq_mask0(void)
|
||||
{
|
||||
int irq, swlevel;
|
||||
hubreg_t pend0, mask0;
|
||||
cpuid_t cpu = smp_processor_id();
|
||||
int pi_int_mask0 =
|
||||
(cputoslice(cpu) == 0) ? PI_INT_MASK0_A : PI_INT_MASK0_B;
|
||||
|
||||
/* copied from Irix intpend0() */
|
||||
pend0 = LOCAL_HUB_L(PI_INT_PEND0);
|
||||
mask0 = LOCAL_HUB_L(pi_int_mask0);
|
||||
|
||||
pend0 &= mask0; /* Pick intrs we should look at */
|
||||
if (!pend0)
|
||||
return;
|
||||
|
||||
swlevel = ms1bit(pend0);
|
||||
#ifdef CONFIG_SMP
|
||||
if (pend0 & (1UL << CPU_RESCHED_A_IRQ)) {
|
||||
LOCAL_HUB_CLR_INTR(CPU_RESCHED_A_IRQ);
|
||||
scheduler_ipi();
|
||||
} else if (pend0 & (1UL << CPU_RESCHED_B_IRQ)) {
|
||||
LOCAL_HUB_CLR_INTR(CPU_RESCHED_B_IRQ);
|
||||
scheduler_ipi();
|
||||
} else if (pend0 & (1UL << CPU_CALL_A_IRQ)) {
|
||||
LOCAL_HUB_CLR_INTR(CPU_CALL_A_IRQ);
|
||||
smp_call_function_interrupt();
|
||||
} else if (pend0 & (1UL << CPU_CALL_B_IRQ)) {
|
||||
LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ);
|
||||
smp_call_function_interrupt();
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
/* "map" swlevel to irq */
|
||||
struct slice_data *si = cpu_data[cpu].data;
|
||||
|
||||
irq = si->level_to_irq[swlevel];
|
||||
do_IRQ(irq);
|
||||
}
|
||||
|
||||
LOCAL_HUB_L(PI_INT_PEND0);
|
||||
}
|
||||
|
||||
static void ip27_do_irq_mask1(void)
|
||||
{
|
||||
int irq, swlevel;
|
||||
hubreg_t pend1, mask1;
|
||||
cpuid_t cpu = smp_processor_id();
|
||||
int pi_int_mask1 = (cputoslice(cpu) == 0) ? PI_INT_MASK1_A : PI_INT_MASK1_B;
|
||||
struct slice_data *si = cpu_data[cpu].data;
|
||||
|
||||
/* copied from Irix intpend0() */
|
||||
pend1 = LOCAL_HUB_L(PI_INT_PEND1);
|
||||
mask1 = LOCAL_HUB_L(pi_int_mask1);
|
||||
|
||||
pend1 &= mask1; /* Pick intrs we should look at */
|
||||
if (!pend1)
|
||||
return;
|
||||
|
||||
swlevel = ms1bit(pend1);
|
||||
/* "map" swlevel to irq */
|
||||
irq = si->level_to_irq[swlevel];
|
||||
LOCAL_HUB_CLR_INTR(swlevel);
|
||||
do_IRQ(irq);
|
||||
|
||||
LOCAL_HUB_L(PI_INT_PEND1);
|
||||
}
|
||||
|
||||
static void ip27_prof_timer(void)
|
||||
{
|
||||
panic("CPU %d got a profiling interrupt", smp_processor_id());
|
||||
}
|
||||
|
||||
static void ip27_hub_error(void)
|
||||
{
|
||||
panic("CPU %d got a hub error interrupt", smp_processor_id());
|
||||
}
|
||||
|
||||
asmlinkage void plat_irq_dispatch(void)
|
||||
{
|
||||
unsigned long pending = read_c0_cause() & read_c0_status();
|
||||
extern unsigned int rt_timer_irq;
|
||||
|
||||
if (pending & CAUSEF_IP4)
|
||||
do_IRQ(rt_timer_irq);
|
||||
else if (pending & CAUSEF_IP2) /* PI_INT_PEND_0 or CC_PEND_{A|B} */
|
||||
ip27_do_irq_mask0();
|
||||
else if (pending & CAUSEF_IP3) /* PI_INT_PEND_1 */
|
||||
ip27_do_irq_mask1();
|
||||
else if (pending & CAUSEF_IP5)
|
||||
ip27_prof_timer();
|
||||
else if (pending & CAUSEF_IP6)
|
||||
ip27_hub_error();
|
||||
}
|
||||
|
||||
void __init arch_init_irq(void)
|
||||
{
|
||||
}
|
||||
|
||||
void install_ipi(void)
|
||||
{
|
||||
int slice = LOCAL_HUB_L(PI_CPU_NUM);
|
||||
int cpu = smp_processor_id();
|
||||
struct slice_data *si = cpu_data[cpu].data;
|
||||
struct hub_data *hub = hub_data(cpu_to_node(cpu));
|
||||
int resched, call;
|
||||
|
||||
resched = CPU_RESCHED_A_IRQ + slice;
|
||||
__set_bit(resched, hub->irq_alloc_mask);
|
||||
__set_bit(resched, si->irq_enable_mask);
|
||||
LOCAL_HUB_CLR_INTR(resched);
|
||||
|
||||
call = CPU_CALL_A_IRQ + slice;
|
||||
__set_bit(call, hub->irq_alloc_mask);
|
||||
__set_bit(call, si->irq_enable_mask);
|
||||
LOCAL_HUB_CLR_INTR(call);
|
||||
|
||||
if (slice == 0) {
|
||||
LOCAL_HUB_S(PI_INT_MASK0_A, si->irq_enable_mask[0]);
|
||||
LOCAL_HUB_S(PI_INT_MASK1_A, si->irq_enable_mask[1]);
|
||||
} else {
|
||||
LOCAL_HUB_S(PI_INT_MASK0_B, si->irq_enable_mask[0]);
|
||||
LOCAL_HUB_S(PI_INT_MASK1_B, si->irq_enable_mask[1]);
|
||||
}
|
||||
}
|
134
arch/mips/sgi-ip27/ip27-klconfig.c
Normal file
134
arch/mips/sgi-ip27/ip27-klconfig.c
Normal file
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
|
||||
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/mm.h>
|
||||
|
||||
#include <asm/sn/klconfig.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/gda.h>
|
||||
|
||||
klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type)
|
||||
{
|
||||
int index, j;
|
||||
|
||||
if (kli == (klinfo_t *)NULL) {
|
||||
index = 0;
|
||||
} else {
|
||||
for (j = 0; j < KLCF_NUM_COMPS(brd); j++)
|
||||
if (kli == KLCF_COMP(brd, j))
|
||||
break;
|
||||
index = j;
|
||||
if (index == KLCF_NUM_COMPS(brd)) {
|
||||
printk("find_component: Bad pointer: 0x%p\n", kli);
|
||||
return (klinfo_t *)NULL;
|
||||
}
|
||||
index++; /* next component */
|
||||
}
|
||||
|
||||
for (; index < KLCF_NUM_COMPS(brd); index++) {
|
||||
kli = KLCF_COMP(brd, index);
|
||||
if (KLCF_COMP_TYPE(kli) == struct_type)
|
||||
return kli;
|
||||
}
|
||||
|
||||
/* Didn't find it. */
|
||||
return (klinfo_t *)NULL;
|
||||
}
|
||||
|
||||
klinfo_t *find_first_component(lboard_t *brd, unsigned char struct_type)
|
||||
{
|
||||
return find_component(brd, (klinfo_t *)NULL, struct_type);
|
||||
}
|
||||
|
||||
lboard_t *find_lboard(lboard_t *start, unsigned char brd_type)
|
||||
{
|
||||
/* Search all boards stored on this node. */
|
||||
while (start) {
|
||||
if (start->brd_type == brd_type)
|
||||
return start;
|
||||
start = KLCF_NEXT(start);
|
||||
}
|
||||
/* Didn't find it. */
|
||||
return (lboard_t *)NULL;
|
||||
}
|
||||
|
||||
lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_type)
|
||||
{
|
||||
/* Search all boards stored on this node. */
|
||||
while (start) {
|
||||
if (KLCLASS(start->brd_type) == KLCLASS(brd_type))
|
||||
return start;
|
||||
start = KLCF_NEXT(start);
|
||||
}
|
||||
|
||||
/* Didn't find it. */
|
||||
return (lboard_t *)NULL;
|
||||
}
|
||||
|
||||
cnodeid_t get_cpu_cnode(cpuid_t cpu)
|
||||
{
|
||||
return CPUID_TO_COMPACT_NODEID(cpu);
|
||||
}
|
||||
|
||||
klcpu_t *nasid_slice_to_cpuinfo(nasid_t nasid, int slice)
|
||||
{
|
||||
lboard_t *brd;
|
||||
klcpu_t *acpu;
|
||||
|
||||
if (!(brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27)))
|
||||
return (klcpu_t *)NULL;
|
||||
|
||||
if (!(acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU)))
|
||||
return (klcpu_t *)NULL;
|
||||
|
||||
do {
|
||||
if ((acpu->cpu_info.physid) == slice)
|
||||
return acpu;
|
||||
} while ((acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu,
|
||||
KLSTRUCT_CPU)));
|
||||
return (klcpu_t *)NULL;
|
||||
}
|
||||
|
||||
klcpu_t *sn_get_cpuinfo(cpuid_t cpu)
|
||||
{
|
||||
nasid_t nasid;
|
||||
int slice;
|
||||
klcpu_t *acpu;
|
||||
gda_t *gdap = GDA;
|
||||
cnodeid_t cnode;
|
||||
|
||||
if (!(cpu < MAXCPUS)) {
|
||||
printk("sn_get_cpuinfo: illegal cpuid 0x%lx\n", cpu);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cnode = get_cpu_cnode(cpu);
|
||||
if (cnode == INVALID_CNODEID)
|
||||
return NULL;
|
||||
|
||||
if ((nasid = gdap->g_nasidtable[cnode]) == INVALID_NASID)
|
||||
return NULL;
|
||||
|
||||
for (slice = 0; slice < CPUS_PER_NODE; slice++) {
|
||||
acpu = nasid_slice_to_cpuinfo(nasid, slice);
|
||||
if (acpu && acpu->cpu_info.virtid == cpu)
|
||||
return acpu;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int get_cpu_slice(cpuid_t cpu)
|
||||
{
|
||||
klcpu_t *acpu;
|
||||
|
||||
if ((acpu = sn_get_cpuinfo(cpu)) == NULL)
|
||||
return -1;
|
||||
return acpu->cpu_info.physid;
|
||||
}
|
132
arch/mips/sgi-ip27/ip27-klnuma.c
Normal file
132
arch/mips/sgi-ip27/ip27-klnuma.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* Ported from IRIX to Linux by Kanoj Sarcar, 06/08/00.
|
||||
* Copyright 2000 - 2001 Silicon Graphics, Inc.
|
||||
* Copyright 2000 - 2001 Kanoj Sarcar (kanoj@sgi.com)
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mmzone.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/nodemask.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/sn/types.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/gda.h>
|
||||
#include <asm/sn/hub.h>
|
||||
#include <asm/sn/mapped_kernel.h>
|
||||
#include <asm/sn/sn_private.h>
|
||||
|
||||
static cpumask_t ktext_repmask;
|
||||
|
||||
/*
|
||||
* XXX - This needs to be much smarter about where it puts copies of the
|
||||
* kernel. For example, we should never put a copy on a headless node,
|
||||
* and we should respect the topology of the machine.
|
||||
*/
|
||||
void __init setup_replication_mask(void)
|
||||
{
|
||||
/* Set only the master cnode's bit. The master cnode is always 0. */
|
||||
cpus_clear(ktext_repmask);
|
||||
cpu_set(0, ktext_repmask);
|
||||
|
||||
#ifdef CONFIG_REPLICATE_KTEXT
|
||||
#ifndef CONFIG_MAPPED_KERNEL
|
||||
#error Kernel replication works with mapped kernel support. No calias support.
|
||||
#endif
|
||||
{
|
||||
cnodeid_t cnode;
|
||||
|
||||
for_each_online_node(cnode) {
|
||||
if (cnode == 0)
|
||||
continue;
|
||||
/* Advertise that we have a copy of the kernel */
|
||||
cpu_set(cnode, ktext_repmask);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
/* Set up a GDA pointer to the replication mask. */
|
||||
GDA->g_ktext_repmask = &ktext_repmask;
|
||||
}
|
||||
|
||||
|
||||
static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid)
|
||||
{
|
||||
kern_vars_t *kvp;
|
||||
|
||||
kvp = &hub_data(client_nasid)->kern_vars;
|
||||
|
||||
KERN_VARS_ADDR(client_nasid) = (unsigned long)kvp;
|
||||
|
||||
kvp->kv_magic = KV_MAGIC;
|
||||
kvp->kv_ro_nasid = server_nasid;
|
||||
kvp->kv_rw_nasid = master_nasid;
|
||||
kvp->kv_ro_baseaddr = NODE_CAC_BASE(server_nasid);
|
||||
kvp->kv_rw_baseaddr = NODE_CAC_BASE(master_nasid);
|
||||
printk("REPLICATION: ON nasid %d, ktext from nasid %d, kdata from nasid %d\n", client_nasid, server_nasid, master_nasid);
|
||||
}
|
||||
|
||||
/* XXX - When the BTE works, we should use it instead of this. */
|
||||
static __init void copy_kernel(nasid_t dest_nasid)
|
||||
{
|
||||
unsigned long dest_kern_start, source_start, source_end, kern_size;
|
||||
|
||||
source_start = (unsigned long) _stext;
|
||||
source_end = (unsigned long) _etext;
|
||||
kern_size = source_end - source_start;
|
||||
|
||||
dest_kern_start = CHANGE_ADDR_NASID(MAPPED_KERN_RO_TO_K0(source_start),
|
||||
dest_nasid);
|
||||
memcpy((void *)dest_kern_start, (void *)source_start, kern_size);
|
||||
}
|
||||
|
||||
void __init replicate_kernel_text()
|
||||
{
|
||||
cnodeid_t cnode;
|
||||
nasid_t client_nasid;
|
||||
nasid_t server_nasid;
|
||||
|
||||
server_nasid = master_nasid;
|
||||
|
||||
/* Record where the master node should get its kernel text */
|
||||
set_ktext_source(master_nasid, master_nasid);
|
||||
|
||||
for_each_online_node(cnode) {
|
||||
if (cnode == 0)
|
||||
continue;
|
||||
client_nasid = COMPACT_TO_NASID_NODEID(cnode);
|
||||
|
||||
/* Check if this node should get a copy of the kernel */
|
||||
if (cpu_isset(cnode, ktext_repmask)) {
|
||||
server_nasid = client_nasid;
|
||||
copy_kernel(server_nasid);
|
||||
}
|
||||
|
||||
/* Record where this node should get its kernel text */
|
||||
set_ktext_source(client_nasid, server_nasid);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return pfn of first free page of memory on a node. PROM may allocate
|
||||
* data structures on the first couple of pages of the first slot of each
|
||||
* node. If this is the case, getfirstfree(node) > getslotstart(node, 0).
|
||||
*/
|
||||
unsigned long node_getfirstfree(cnodeid_t cnode)
|
||||
{
|
||||
unsigned long loadbase = REP_BASE;
|
||||
nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
|
||||
unsigned long offset;
|
||||
|
||||
#ifdef CONFIG_MAPPED_KERNEL
|
||||
loadbase += 16777216;
|
||||
#endif
|
||||
offset = PAGE_ALIGN((unsigned long)(&_end)) - loadbase;
|
||||
if ((cnode == 0) || (cpu_isset(cnode, ktext_repmask)))
|
||||
return (TO_NODE(nasid, offset) >> PAGE_SHIFT);
|
||||
else
|
||||
return (KDM_TO_PHYS(PAGE_ALIGN(SYMMON_STK_ADDR(nasid, 0))) >>
|
||||
PAGE_SHIFT);
|
||||
}
|
485
arch/mips/sgi-ip27/ip27-memory.c
Normal file
485
arch/mips/sgi-ip27/ip27-memory.c
Normal file
|
@ -0,0 +1,485 @@
|
|||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2000, 05 by Ralf Baechle (ralf@linux-mips.org)
|
||||
* Copyright (C) 2000 by Silicon Graphics, Inc.
|
||||
* Copyright (C) 2004 by Christoph Hellwig
|
||||
*
|
||||
* On SGI IP27 the ARC memory configuration data is completly bogus but
|
||||
* alternate easier to use mechanisms are available.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/memblock.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/mmzone.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/nodemask.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/bootmem.h>
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/pgalloc.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/hub.h>
|
||||
#include <asm/sn/klconfig.h>
|
||||
#include <asm/sn/sn_private.h>
|
||||
|
||||
|
||||
#define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT)
|
||||
#define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT)
|
||||
|
||||
struct node_data *__node_data[MAX_COMPACT_NODES];
|
||||
|
||||
EXPORT_SYMBOL(__node_data);
|
||||
|
||||
static int fine_mode;
|
||||
|
||||
static int is_fine_dirmode(void)
|
||||
{
|
||||
return (((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK)
|
||||
>> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE);
|
||||
}
|
||||
|
||||
static hubreg_t get_region(cnodeid_t cnode)
|
||||
{
|
||||
if (fine_mode)
|
||||
return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT;
|
||||
else
|
||||
return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT;
|
||||
}
|
||||
|
||||
static hubreg_t region_mask;
|
||||
|
||||
static void gen_region_mask(hubreg_t *region_mask)
|
||||
{
|
||||
cnodeid_t cnode;
|
||||
|
||||
(*region_mask) = 0;
|
||||
for_each_online_node(cnode) {
|
||||
(*region_mask) |= 1ULL << get_region(cnode);
|
||||
}
|
||||
}
|
||||
|
||||
#define rou_rflag rou_flags
|
||||
|
||||
static int router_distance;
|
||||
|
||||
static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth)
|
||||
{
|
||||
klrou_t *router;
|
||||
lboard_t *brd;
|
||||
int port;
|
||||
|
||||
if (router_a->rou_rflag == 1)
|
||||
return;
|
||||
|
||||
if (depth >= router_distance)
|
||||
return;
|
||||
|
||||
router_a->rou_rflag = 1;
|
||||
|
||||
for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
|
||||
if (router_a->rou_port[port].port_nasid == INVALID_NASID)
|
||||
continue;
|
||||
|
||||
brd = (lboard_t *)NODE_OFFSET_TO_K0(
|
||||
router_a->rou_port[port].port_nasid,
|
||||
router_a->rou_port[port].port_offset);
|
||||
|
||||
if (brd->brd_type == KLTYPE_ROUTER) {
|
||||
router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
|
||||
if (router == router_b) {
|
||||
if (depth < router_distance)
|
||||
router_distance = depth;
|
||||
}
|
||||
else
|
||||
router_recurse(router, router_b, depth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
router_a->rou_rflag = 0;
|
||||
}
|
||||
|
||||
unsigned char __node_distances[MAX_COMPACT_NODES][MAX_COMPACT_NODES];
|
||||
EXPORT_SYMBOL(__node_distances);
|
||||
|
||||
static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b)
|
||||
{
|
||||
klrou_t *router, *router_a = NULL, *router_b = NULL;
|
||||
lboard_t *brd, *dest_brd;
|
||||
cnodeid_t cnode;
|
||||
nasid_t nasid;
|
||||
int port;
|
||||
|
||||
/* Figure out which routers nodes in question are connected to */
|
||||
for_each_online_node(cnode) {
|
||||
nasid = COMPACT_TO_NASID_NODEID(cnode);
|
||||
|
||||
if (nasid == -1) continue;
|
||||
|
||||
brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
|
||||
KLTYPE_ROUTER);
|
||||
|
||||
if (!brd)
|
||||
continue;
|
||||
|
||||
do {
|
||||
if (brd->brd_flags & DUPLICATE_BOARD)
|
||||
continue;
|
||||
|
||||
router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
|
||||
router->rou_rflag = 0;
|
||||
|
||||
for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
|
||||
if (router->rou_port[port].port_nasid == INVALID_NASID)
|
||||
continue;
|
||||
|
||||
dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
|
||||
router->rou_port[port].port_nasid,
|
||||
router->rou_port[port].port_offset);
|
||||
|
||||
if (dest_brd->brd_type == KLTYPE_IP27) {
|
||||
if (dest_brd->brd_nasid == nasid_a)
|
||||
router_a = router;
|
||||
if (dest_brd->brd_nasid == nasid_b)
|
||||
router_b = router;
|
||||
}
|
||||
}
|
||||
|
||||
} while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)));
|
||||
}
|
||||
|
||||
if (router_a == NULL) {
|
||||
printk("node_distance: router_a NULL\n");
|
||||
return -1;
|
||||
}
|
||||
if (router_b == NULL) {
|
||||
printk("node_distance: router_b NULL\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (nasid_a == nasid_b)
|
||||
return 0;
|
||||
|
||||
if (router_a == router_b)
|
||||
return 1;
|
||||
|
||||
router_distance = 100;
|
||||
router_recurse(router_a, router_b, 2);
|
||||
|
||||
return router_distance;
|
||||
}
|
||||
|
||||
static void __init init_topology_matrix(void)
|
||||
{
|
||||
nasid_t nasid, nasid2;
|
||||
cnodeid_t row, col;
|
||||
|
||||
for (row = 0; row < MAX_COMPACT_NODES; row++)
|
||||
for (col = 0; col < MAX_COMPACT_NODES; col++)
|
||||
__node_distances[row][col] = -1;
|
||||
|
||||
for_each_online_node(row) {
|
||||
nasid = COMPACT_TO_NASID_NODEID(row);
|
||||
for_each_online_node(col) {
|
||||
nasid2 = COMPACT_TO_NASID_NODEID(col);
|
||||
__node_distances[row][col] =
|
||||
compute_node_distance(nasid, nasid2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __init dump_topology(void)
|
||||
{
|
||||
nasid_t nasid;
|
||||
cnodeid_t cnode;
|
||||
lboard_t *brd, *dest_brd;
|
||||
int port;
|
||||
int router_num = 0;
|
||||
klrou_t *router;
|
||||
cnodeid_t row, col;
|
||||
|
||||
printk("************** Topology ********************\n");
|
||||
|
||||
printk(" ");
|
||||
for_each_online_node(col)
|
||||
printk("%02d ", col);
|
||||
printk("\n");
|
||||
for_each_online_node(row) {
|
||||
printk("%02d ", row);
|
||||
for_each_online_node(col)
|
||||
printk("%2d ", node_distance(row, col));
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
for_each_online_node(cnode) {
|
||||
nasid = COMPACT_TO_NASID_NODEID(cnode);
|
||||
|
||||
if (nasid == -1) continue;
|
||||
|
||||
brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid),
|
||||
KLTYPE_ROUTER);
|
||||
|
||||
if (!brd)
|
||||
continue;
|
||||
|
||||
do {
|
||||
if (brd->brd_flags & DUPLICATE_BOARD)
|
||||
continue;
|
||||
printk("Router %d:", router_num);
|
||||
router_num++;
|
||||
|
||||
router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]);
|
||||
|
||||
for (port = 1; port <= MAX_ROUTER_PORTS; port++) {
|
||||
if (router->rou_port[port].port_nasid == INVALID_NASID)
|
||||
continue;
|
||||
|
||||
dest_brd = (lboard_t *)NODE_OFFSET_TO_K0(
|
||||
router->rou_port[port].port_nasid,
|
||||
router->rou_port[port].port_offset);
|
||||
|
||||
if (dest_brd->brd_type == KLTYPE_IP27)
|
||||
printk(" %d", dest_brd->brd_nasid);
|
||||
if (dest_brd->brd_type == KLTYPE_ROUTER)
|
||||
printk(" r");
|
||||
}
|
||||
printk("\n");
|
||||
|
||||
} while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) );
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned long __init slot_getbasepfn(cnodeid_t cnode, int slot)
|
||||
{
|
||||
nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);
|
||||
|
||||
return ((unsigned long)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT);
|
||||
}
|
||||
|
||||
static unsigned long __init slot_psize_compute(cnodeid_t node, int slot)
|
||||
{
|
||||
nasid_t nasid;
|
||||
lboard_t *brd;
|
||||
klmembnk_t *banks;
|
||||
unsigned long size;
|
||||
|
||||
nasid = COMPACT_TO_NASID_NODEID(node);
|
||||
/* Find the node board */
|
||||
brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
|
||||
if (!brd)
|
||||
return 0;
|
||||
|
||||
/* Get the memory bank structure */
|
||||
banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK);
|
||||
if (!banks)
|
||||
return 0;
|
||||
|
||||
/* Size in _Megabytes_ */
|
||||
size = (unsigned long)banks->membnk_bnksz[slot/4];
|
||||
|
||||
/* hack for 128 dimm banks */
|
||||
if (size <= 128) {
|
||||
if (slot % 4 == 0) {
|
||||
size <<= 20; /* size in bytes */
|
||||
return(size >> PAGE_SHIFT);
|
||||
} else
|
||||
return 0;
|
||||
} else {
|
||||
size /= 4;
|
||||
size <<= 20;
|
||||
return size >> PAGE_SHIFT;
|
||||
}
|
||||
}
|
||||
|
||||
static void __init mlreset(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
master_nasid = get_nasid();
|
||||
fine_mode = is_fine_dirmode();
|
||||
|
||||
/*
|
||||
* Probe for all CPUs - this creates the cpumask and sets up the
|
||||
* mapping tables. We need to do this as early as possible.
|
||||
*/
|
||||
#ifdef CONFIG_SMP
|
||||
cpu_node_probe();
|
||||
#endif
|
||||
|
||||
init_topology_matrix();
|
||||
dump_topology();
|
||||
|
||||
gen_region_mask(®ion_mask);
|
||||
|
||||
setup_replication_mask();
|
||||
|
||||
/*
|
||||
* Set all nodes' calias sizes to 8k
|
||||
*/
|
||||
for_each_online_node(i) {
|
||||
nasid_t nasid;
|
||||
|
||||
nasid = COMPACT_TO_NASID_NODEID(i);
|
||||
|
||||
/*
|
||||
* Always have node 0 in the region mask, otherwise
|
||||
* CALIAS accesses get exceptions since the hub
|
||||
* thinks it is a node 0 address.
|
||||
*/
|
||||
REMOTE_HUB_S(nasid, PI_REGION_PRESENT, (region_mask | 1));
|
||||
#ifdef CONFIG_REPLICATE_EXHANDLERS
|
||||
REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_8K);
|
||||
#else
|
||||
REMOTE_HUB_S(nasid, PI_CALIAS_SIZE, PI_CALIAS_SIZE_0);
|
||||
#endif
|
||||
|
||||
#ifdef LATER
|
||||
/*
|
||||
* Set up all hubs to have a big window pointing at
|
||||
* widget 0. Memory mode, widget 0, offset 0
|
||||
*/
|
||||
REMOTE_HUB_S(nasid, IIO_ITTE(SWIN0_BIGWIN),
|
||||
((HUB_PIO_MAP_TO_MEM << IIO_ITTE_IOSP_SHIFT) |
|
||||
(0 << IIO_ITTE_WIDGET_SHIFT)));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static void __init szmem(void)
|
||||
{
|
||||
unsigned long slot_psize, slot0sz = 0, nodebytes; /* Hack to detect problem configs */
|
||||
int slot;
|
||||
cnodeid_t node;
|
||||
|
||||
for_each_online_node(node) {
|
||||
nodebytes = 0;
|
||||
for (slot = 0; slot < MAX_MEM_SLOTS; slot++) {
|
||||
slot_psize = slot_psize_compute(node, slot);
|
||||
if (slot == 0)
|
||||
slot0sz = slot_psize;
|
||||
/*
|
||||
* We need to refine the hack when we have replicated
|
||||
* kernel text.
|
||||
*/
|
||||
nodebytes += (1LL << SLOT_SHIFT);
|
||||
|
||||
if (!slot_psize)
|
||||
continue;
|
||||
|
||||
if ((nodebytes >> PAGE_SHIFT) * (sizeof(struct page)) >
|
||||
(slot0sz << PAGE_SHIFT)) {
|
||||
printk("Ignoring slot %d onwards on node %d\n",
|
||||
slot, node);
|
||||
slot = MAX_MEM_SLOTS;
|
||||
continue;
|
||||
}
|
||||
memblock_add_node(PFN_PHYS(slot_getbasepfn(node, slot)),
|
||||
PFN_PHYS(slot_psize), node);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __init node_mem_init(cnodeid_t node)
|
||||
{
|
||||
unsigned long slot_firstpfn = slot_getbasepfn(node, 0);
|
||||
unsigned long slot_freepfn = node_getfirstfree(node);
|
||||
unsigned long bootmap_size;
|
||||
unsigned long start_pfn, end_pfn;
|
||||
|
||||
get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
|
||||
|
||||
/*
|
||||
* Allocate the node data structures on the node first.
|
||||
*/
|
||||
__node_data[node] = __va(slot_freepfn << PAGE_SHIFT);
|
||||
memset(__node_data[node], 0, PAGE_SIZE);
|
||||
|
||||
NODE_DATA(node)->bdata = &bootmem_node_data[node];
|
||||
NODE_DATA(node)->node_start_pfn = start_pfn;
|
||||
NODE_DATA(node)->node_spanned_pages = end_pfn - start_pfn;
|
||||
|
||||
cpus_clear(hub_data(node)->h_cpus);
|
||||
|
||||
slot_freepfn += PFN_UP(sizeof(struct pglist_data) +
|
||||
sizeof(struct hub_data));
|
||||
|
||||
bootmap_size = init_bootmem_node(NODE_DATA(node), slot_freepfn,
|
||||
start_pfn, end_pfn);
|
||||
free_bootmem_with_active_regions(node, end_pfn);
|
||||
reserve_bootmem_node(NODE_DATA(node), slot_firstpfn << PAGE_SHIFT,
|
||||
((slot_freepfn - slot_firstpfn) << PAGE_SHIFT) + bootmap_size,
|
||||
BOOTMEM_DEFAULT);
|
||||
sparse_memory_present_with_active_regions(node);
|
||||
}
|
||||
|
||||
/*
|
||||
* A node with nothing. We use it to avoid any special casing in
|
||||
* cpumask_of_node
|
||||
*/
|
||||
static struct node_data null_node = {
|
||||
.hub = {
|
||||
.h_cpus = CPU_MASK_NONE
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Currently, the intranode memory hole support assumes that each slot
|
||||
* contains at least 32 MBytes of memory. We assume all bootmem data
|
||||
* fits on the first slot.
|
||||
*/
|
||||
void __init prom_meminit(void)
|
||||
{
|
||||
cnodeid_t node;
|
||||
|
||||
mlreset();
|
||||
szmem();
|
||||
|
||||
for (node = 0; node < MAX_COMPACT_NODES; node++) {
|
||||
if (node_online(node)) {
|
||||
node_mem_init(node);
|
||||
continue;
|
||||
}
|
||||
__node_data[node] = &null_node;
|
||||
}
|
||||
}
|
||||
|
||||
void __init prom_free_prom_memory(void)
|
||||
{
|
||||
/* We got nothing to free here ... */
|
||||
}
|
||||
|
||||
extern void setup_zero_pages(void);
|
||||
|
||||
void __init paging_init(void)
|
||||
{
|
||||
unsigned long zones_size[MAX_NR_ZONES] = {0, };
|
||||
unsigned node;
|
||||
|
||||
pagetable_init();
|
||||
|
||||
for_each_online_node(node) {
|
||||
unsigned long start_pfn, end_pfn;
|
||||
|
||||
get_pfn_range_for_nid(node, &start_pfn, &end_pfn);
|
||||
|
||||
if (end_pfn > max_low_pfn)
|
||||
max_low_pfn = end_pfn;
|
||||
}
|
||||
zones_size[ZONE_NORMAL] = max_low_pfn;
|
||||
free_area_init_nodes(zones_size);
|
||||
}
|
||||
|
||||
void __init mem_init(void)
|
||||
{
|
||||
high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT);
|
||||
free_all_bootmem();
|
||||
setup_zero_pages(); /* This comes from node 0 */
|
||||
mem_init_print_info(NULL);
|
||||
}
|
244
arch/mips/sgi-ip27/ip27-nmi.c
Normal file
244
arch/mips/sgi-ip27/ip27-nmi.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/mmzone.h>
|
||||
#include <linux/nodemask.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/atomic.h>
|
||||
#include <asm/sn/types.h>
|
||||
#include <asm/sn/addrs.h>
|
||||
#include <asm/sn/nmi.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/sn0/hub.h>
|
||||
|
||||
#if 0
|
||||
#define NODE_NUM_CPUS(n) CNODE_NUM_CPUS(n)
|
||||
#else
|
||||
#define NODE_NUM_CPUS(n) CPUS_PER_NODE
|
||||
#endif
|
||||
|
||||
#define CNODEID_NONE (cnodeid_t)-1
|
||||
|
||||
typedef unsigned long machreg_t;
|
||||
|
||||
static arch_spinlock_t nmi_lock = __ARCH_SPIN_LOCK_UNLOCKED;
|
||||
|
||||
/*
|
||||
* Lets see what else we need to do here. Set up sp, gp?
|
||||
*/
|
||||
void nmi_dump(void)
|
||||
{
|
||||
void cont_nmi_dump(void);
|
||||
|
||||
cont_nmi_dump();
|
||||
}
|
||||
|
||||
void install_cpu_nmi_handler(int slice)
|
||||
{
|
||||
nmi_t *nmi_addr;
|
||||
|
||||
nmi_addr = (nmi_t *)NMI_ADDR(get_nasid(), slice);
|
||||
if (nmi_addr->call_addr)
|
||||
return;
|
||||
nmi_addr->magic = NMI_MAGIC;
|
||||
nmi_addr->call_addr = (void *)nmi_dump;
|
||||
nmi_addr->call_addr_c =
|
||||
(void *)(~((unsigned long)(nmi_addr->call_addr)));
|
||||
nmi_addr->call_parm = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the cpu registers which have been saved in the IP27prom format
|
||||
* into the eframe format for the node under consideration.
|
||||
*/
|
||||
|
||||
void nmi_cpu_eframe_save(nasid_t nasid, int slice)
|
||||
{
|
||||
struct reg_struct *nr;
|
||||
int i;
|
||||
|
||||
/* Get the pointer to the current cpu's register set. */
|
||||
nr = (struct reg_struct *)
|
||||
(TO_UNCAC(TO_NODE(nasid, IP27_NMI_KREGS_OFFSET)) +
|
||||
slice * IP27_NMI_KREGS_CPU_SIZE);
|
||||
|
||||
printk("NMI nasid %d: slice %d\n", nasid, slice);
|
||||
|
||||
/*
|
||||
* Saved main processor registers
|
||||
*/
|
||||
for (i = 0; i < 32; ) {
|
||||
if ((i % 4) == 0)
|
||||
printk("$%2d :", i);
|
||||
printk(" %016lx", nr->gpr[i]);
|
||||
|
||||
i++;
|
||||
if ((i % 4) == 0)
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
printk("Hi : (value lost)\n");
|
||||
printk("Lo : (value lost)\n");
|
||||
|
||||
/*
|
||||
* Saved cp0 registers
|
||||
*/
|
||||
printk("epc : %016lx %pS\n", nr->epc, (void *) nr->epc);
|
||||
printk("%s\n", print_tainted());
|
||||
printk("ErrEPC: %016lx %pS\n", nr->error_epc, (void *) nr->error_epc);
|
||||
printk("ra : %016lx %pS\n", nr->gpr[31], (void *) nr->gpr[31]);
|
||||
printk("Status: %08lx ", nr->sr);
|
||||
|
||||
if (nr->sr & ST0_KX)
|
||||
printk("KX ");
|
||||
if (nr->sr & ST0_SX)
|
||||
printk("SX ");
|
||||
if (nr->sr & ST0_UX)
|
||||
printk("UX ");
|
||||
|
||||
switch (nr->sr & ST0_KSU) {
|
||||
case KSU_USER:
|
||||
printk("USER ");
|
||||
break;
|
||||
case KSU_SUPERVISOR:
|
||||
printk("SUPERVISOR ");
|
||||
break;
|
||||
case KSU_KERNEL:
|
||||
printk("KERNEL ");
|
||||
break;
|
||||
default:
|
||||
printk("BAD_MODE ");
|
||||
break;
|
||||
}
|
||||
|
||||
if (nr->sr & ST0_ERL)
|
||||
printk("ERL ");
|
||||
if (nr->sr & ST0_EXL)
|
||||
printk("EXL ");
|
||||
if (nr->sr & ST0_IE)
|
||||
printk("IE ");
|
||||
printk("\n");
|
||||
|
||||
printk("Cause : %08lx\n", nr->cause);
|
||||
printk("PrId : %08x\n", read_c0_prid());
|
||||
printk("BadVA : %016lx\n", nr->badva);
|
||||
printk("CErr : %016lx\n", nr->cache_err);
|
||||
printk("NMI_SR: %016lx\n", nr->nmi_sr);
|
||||
|
||||
printk("\n");
|
||||
}
|
||||
|
||||
void nmi_dump_hub_irq(nasid_t nasid, int slice)
|
||||
{
|
||||
hubreg_t mask0, mask1, pend0, pend1;
|
||||
|
||||
if (slice == 0) { /* Slice A */
|
||||
mask0 = REMOTE_HUB_L(nasid, PI_INT_MASK0_A);
|
||||
mask1 = REMOTE_HUB_L(nasid, PI_INT_MASK1_A);
|
||||
} else { /* Slice B */
|
||||
mask0 = REMOTE_HUB_L(nasid, PI_INT_MASK0_B);
|
||||
mask1 = REMOTE_HUB_L(nasid, PI_INT_MASK1_B);
|
||||
}
|
||||
|
||||
pend0 = REMOTE_HUB_L(nasid, PI_INT_PEND0);
|
||||
pend1 = REMOTE_HUB_L(nasid, PI_INT_PEND1);
|
||||
|
||||
printk("PI_INT_MASK0: %16Lx PI_INT_MASK1: %16Lx\n", mask0, mask1);
|
||||
printk("PI_INT_PEND0: %16Lx PI_INT_PEND1: %16Lx\n", pend0, pend1);
|
||||
printk("\n\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the cpu registers which have been saved in the IP27prom format
|
||||
* into the eframe format for the node under consideration.
|
||||
*/
|
||||
void nmi_node_eframe_save(cnodeid_t cnode)
|
||||
{
|
||||
nasid_t nasid;
|
||||
int slice;
|
||||
|
||||
/* Make sure that we have a valid node */
|
||||
if (cnode == CNODEID_NONE)
|
||||
return;
|
||||
|
||||
nasid = COMPACT_TO_NASID_NODEID(cnode);
|
||||
if (nasid == INVALID_NASID)
|
||||
return;
|
||||
|
||||
/* Save the registers into eframe for each cpu */
|
||||
for (slice = 0; slice < NODE_NUM_CPUS(slice); slice++) {
|
||||
nmi_cpu_eframe_save(nasid, slice);
|
||||
nmi_dump_hub_irq(nasid, slice);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Save the nmi cpu registers for all cpus in the system.
|
||||
*/
|
||||
void
|
||||
nmi_eframes_save(void)
|
||||
{
|
||||
cnodeid_t cnode;
|
||||
|
||||
for_each_online_node(cnode)
|
||||
nmi_node_eframe_save(cnode);
|
||||
}
|
||||
|
||||
void
|
||||
cont_nmi_dump(void)
|
||||
{
|
||||
#ifndef REAL_NMI_SIGNAL
|
||||
static atomic_t nmied_cpus = ATOMIC_INIT(0);
|
||||
|
||||
atomic_inc(&nmied_cpus);
|
||||
#endif
|
||||
/*
|
||||
* Only allow 1 cpu to proceed
|
||||
*/
|
||||
arch_spin_lock(&nmi_lock);
|
||||
|
||||
#ifdef REAL_NMI_SIGNAL
|
||||
/*
|
||||
* Wait up to 15 seconds for the other cpus to respond to the NMI.
|
||||
* If a cpu has not responded after 10 sec, send it 1 additional NMI.
|
||||
* This is for 2 reasons:
|
||||
* - sometimes a MMSC fail to NMI all cpus.
|
||||
* - on 512p SN0 system, the MMSC will only send NMIs to
|
||||
* half the cpus. Unfortunately, we don't know which cpus may be
|
||||
* NMIed - it depends on how the site chooses to configure.
|
||||
*
|
||||
* Note: it has been measure that it takes the MMSC up to 2.3 secs to
|
||||
* send NMIs to all cpus on a 256p system.
|
||||
*/
|
||||
for (i=0; i < 1500; i++) {
|
||||
for_each_online_node(node)
|
||||
if (NODEPDA(node)->dump_count == 0)
|
||||
break;
|
||||
if (node == MAX_NUMNODES)
|
||||
break;
|
||||
if (i == 1000) {
|
||||
for_each_online_node(node)
|
||||
if (NODEPDA(node)->dump_count == 0) {
|
||||
cpu = cpumask_first(cpumask_of_node(node));
|
||||
for (n=0; n < CNODE_NUM_CPUS(node); cpu++, n++) {
|
||||
CPUMASK_SETB(nmied_cpus, cpu);
|
||||
/*
|
||||
* cputonasid, cputoslice
|
||||
* needs kernel cpuid
|
||||
*/
|
||||
SEND_NMI((cputonasid(cpu)), (cputoslice(cpu)));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
udelay(10000);
|
||||
}
|
||||
#else
|
||||
while (atomic_read(&nmied_cpus) != num_online_cpus());
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Save the nmi cpu registers for all cpu in the eframe format.
|
||||
*/
|
||||
nmi_eframes_save();
|
||||
LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);
|
||||
}
|
80
arch/mips/sgi-ip27/ip27-reset.c
Normal file
80
arch/mips/sgi-ip27/ip27-reset.c
Normal file
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Reset an IP27.
|
||||
*
|
||||
* Copyright (C) 1997, 1998, 1999, 2000, 06 by Ralf Baechle
|
||||
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
|
||||
*/
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/mmzone.h>
|
||||
#include <linux/nodemask.h>
|
||||
#include <linux/pm.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/irq.h>
|
||||
#include <asm/reboot.h>
|
||||
#include <asm/sgialib.h>
|
||||
#include <asm/sn/addrs.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/gda.h>
|
||||
#include <asm/sn/sn0/hub.h>
|
||||
|
||||
void machine_restart(char *command) __attribute__((noreturn));
|
||||
void machine_halt(void) __attribute__((noreturn));
|
||||
void machine_power_off(void) __attribute__((noreturn));
|
||||
|
||||
#define noreturn while(1); /* Silence gcc. */
|
||||
|
||||
/* XXX How to pass the reboot command to the firmware??? */
|
||||
static void ip27_machine_restart(char *command)
|
||||
{
|
||||
#if 0
|
||||
int i;
|
||||
#endif
|
||||
|
||||
printk("Reboot started from CPU %d\n", smp_processor_id());
|
||||
#ifdef CONFIG_SMP
|
||||
smp_send_stop();
|
||||
#endif
|
||||
#if 0
|
||||
for_each_online_node(i)
|
||||
REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG,
|
||||
PROMOP_REBOOT);
|
||||
#else
|
||||
LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);
|
||||
#endif
|
||||
noreturn;
|
||||
}
|
||||
|
||||
static void ip27_machine_halt(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
smp_send_stop();
|
||||
#endif
|
||||
for_each_online_node(i)
|
||||
REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG,
|
||||
PROMOP_RESTART);
|
||||
LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET);
|
||||
noreturn;
|
||||
}
|
||||
|
||||
static void ip27_machine_power_off(void)
|
||||
{
|
||||
/* To do ... */
|
||||
noreturn;
|
||||
}
|
||||
|
||||
void ip27_reboot_setup(void)
|
||||
{
|
||||
_machine_restart = ip27_machine_restart;
|
||||
_machine_halt = ip27_machine_halt;
|
||||
pm_power_off = ip27_machine_power_off;
|
||||
}
|
238
arch/mips/sgi-ip27/ip27-smp.c
Normal file
238
arch/mips/sgi-ip27/ip27-smp.c
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General
|
||||
* Public License. See the file "COPYING" in the main directory of this
|
||||
* archive for more details.
|
||||
*
|
||||
* Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
|
||||
* Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
|
||||
*/
|
||||
#include <linux/init.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/nodemask.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/processor.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/gda.h>
|
||||
#include <asm/sn/intr.h>
|
||||
#include <asm/sn/klconfig.h>
|
||||
#include <asm/sn/launch.h>
|
||||
#include <asm/sn/mapped_kernel.h>
|
||||
#include <asm/sn/sn_private.h>
|
||||
#include <asm/sn/types.h>
|
||||
#include <asm/sn/sn0/hubpi.h>
|
||||
#include <asm/sn/sn0/hubio.h>
|
||||
#include <asm/sn/sn0/ip27.h>
|
||||
|
||||
/*
|
||||
* Takes as first input the PROM assigned cpu id, and the kernel
|
||||
* assigned cpu id as the second.
|
||||
*/
|
||||
static void alloc_cpupda(cpuid_t cpu, int cpunum)
|
||||
{
|
||||
cnodeid_t node = get_cpu_cnode(cpu);
|
||||
nasid_t nasid = COMPACT_TO_NASID_NODEID(node);
|
||||
|
||||
cputonasid(cpunum) = nasid;
|
||||
sn_cpu_info[cpunum].p_nodeid = node;
|
||||
cputoslice(cpunum) = get_cpu_slice(cpu);
|
||||
}
|
||||
|
||||
static nasid_t get_actual_nasid(lboard_t *brd)
|
||||
{
|
||||
klhub_t *hub;
|
||||
|
||||
if (!brd)
|
||||
return INVALID_NASID;
|
||||
|
||||
/* find out if we are a completely disabled brd. */
|
||||
hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB);
|
||||
if (!hub)
|
||||
return INVALID_NASID;
|
||||
if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */
|
||||
return hub->hub_info.physid;
|
||||
else
|
||||
return brd->brd_nasid;
|
||||
}
|
||||
|
||||
static int do_cpumask(cnodeid_t cnode, nasid_t nasid, int highest)
|
||||
{
|
||||
static int tot_cpus_found = 0;
|
||||
lboard_t *brd;
|
||||
klcpu_t *acpu;
|
||||
int cpus_found = 0;
|
||||
cpuid_t cpuid;
|
||||
|
||||
brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27);
|
||||
|
||||
do {
|
||||
acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU);
|
||||
while (acpu) {
|
||||
cpuid = acpu->cpu_info.virtid;
|
||||
/* cnode is not valid for completely disabled brds */
|
||||
if (get_actual_nasid(brd) == brd->brd_nasid)
|
||||
cpuid_to_compact_node[cpuid] = cnode;
|
||||
if (cpuid > highest)
|
||||
highest = cpuid;
|
||||
/* Only let it join in if it's marked enabled */
|
||||
if ((acpu->cpu_info.flags & KLINFO_ENABLE) &&
|
||||
(tot_cpus_found != NR_CPUS)) {
|
||||
set_cpu_possible(cpuid, true);
|
||||
alloc_cpupda(cpuid, tot_cpus_found);
|
||||
cpus_found++;
|
||||
tot_cpus_found++;
|
||||
}
|
||||
acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu,
|
||||
KLSTRUCT_CPU);
|
||||
}
|
||||
brd = KLCF_NEXT(brd);
|
||||
if (!brd)
|
||||
break;
|
||||
|
||||
brd = find_lboard(brd, KLTYPE_IP27);
|
||||
} while (brd);
|
||||
|
||||
return highest;
|
||||
}
|
||||
|
||||
void cpu_node_probe(void)
|
||||
{
|
||||
int i, highest = 0;
|
||||
gda_t *gdap = GDA;
|
||||
|
||||
/*
|
||||
* Initialize the arrays to invalid nodeid (-1)
|
||||
*/
|
||||
for (i = 0; i < MAX_COMPACT_NODES; i++)
|
||||
compact_to_nasid_node[i] = INVALID_NASID;
|
||||
for (i = 0; i < MAX_NASIDS; i++)
|
||||
nasid_to_compact_node[i] = INVALID_CNODEID;
|
||||
for (i = 0; i < MAXCPUS; i++)
|
||||
cpuid_to_compact_node[i] = INVALID_CNODEID;
|
||||
|
||||
/*
|
||||
* MCD - this whole "compact node" stuff can probably be dropped,
|
||||
* as we can handle sparse numbering now
|
||||
*/
|
||||
nodes_clear(node_online_map);
|
||||
for (i = 0; i < MAX_COMPACT_NODES; i++) {
|
||||
nasid_t nasid = gdap->g_nasidtable[i];
|
||||
if (nasid == INVALID_NASID)
|
||||
break;
|
||||
compact_to_nasid_node[i] = nasid;
|
||||
nasid_to_compact_node[nasid] = i;
|
||||
node_set_online(num_online_nodes());
|
||||
highest = do_cpumask(i, nasid, highest);
|
||||
}
|
||||
|
||||
printk("Discovered %d cpus on %d nodes\n", highest + 1, num_online_nodes());
|
||||
}
|
||||
|
||||
static __init void intr_clear_all(nasid_t nasid)
|
||||
{
|
||||
int i;
|
||||
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0);
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0);
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0);
|
||||
REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0);
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
REMOTE_HUB_CLR_INTR(nasid, i);
|
||||
}
|
||||
|
||||
static void ip27_send_ipi_single(int destid, unsigned int action)
|
||||
{
|
||||
int irq;
|
||||
|
||||
switch (action) {
|
||||
case SMP_RESCHEDULE_YOURSELF:
|
||||
irq = CPU_RESCHED_A_IRQ;
|
||||
break;
|
||||
case SMP_CALL_FUNCTION:
|
||||
irq = CPU_CALL_A_IRQ;
|
||||
break;
|
||||
default:
|
||||
panic("sendintr");
|
||||
}
|
||||
|
||||
irq += cputoslice(destid);
|
||||
|
||||
/*
|
||||
* Convert the compact hub number to the NASID to get the correct
|
||||
* part of the address space. Then set the interrupt bit associated
|
||||
* with the CPU we want to send the interrupt to.
|
||||
*/
|
||||
REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cpu_to_node(destid)), irq);
|
||||
}
|
||||
|
||||
static void ip27_send_ipi_mask(const struct cpumask *mask, unsigned int action)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for_each_cpu(i, mask)
|
||||
ip27_send_ipi_single(i, action);
|
||||
}
|
||||
|
||||
static void ip27_init_secondary(void)
|
||||
{
|
||||
per_cpu_init();
|
||||
}
|
||||
|
||||
static void ip27_smp_finish(void)
|
||||
{
|
||||
extern void hub_rt_clock_event_init(void);
|
||||
|
||||
hub_rt_clock_event_init();
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
/*
|
||||
* Launch a slave into smp_bootstrap(). It doesn't take an argument, and we
|
||||
* set sp to the kernel stack of the newly created idle process, gp to the proc
|
||||
* struct so that current_thread_info() will work.
|
||||
*/
|
||||
static void ip27_boot_secondary(int cpu, struct task_struct *idle)
|
||||
{
|
||||
unsigned long gp = (unsigned long)task_thread_info(idle);
|
||||
unsigned long sp = __KSTK_TOS(idle);
|
||||
|
||||
LAUNCH_SLAVE(cputonasid(cpu), cputoslice(cpu),
|
||||
(launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap),
|
||||
0, (void *) sp, (void *) gp);
|
||||
}
|
||||
|
||||
static void __init ip27_smp_setup(void)
|
||||
{
|
||||
cnodeid_t cnode;
|
||||
|
||||
for_each_online_node(cnode) {
|
||||
if (cnode == 0)
|
||||
continue;
|
||||
intr_clear_all(COMPACT_TO_NASID_NODEID(cnode));
|
||||
}
|
||||
|
||||
replicate_kernel_text();
|
||||
|
||||
/*
|
||||
* Assumption to be fixed: we're always booted on logical / physical
|
||||
* processor 0. While we're always running on logical processor 0
|
||||
* this still means this is physical processor zero; it might for
|
||||
* example be disabled in the firmware.
|
||||
*/
|
||||
alloc_cpupda(0, 0);
|
||||
}
|
||||
|
||||
static void __init ip27_prepare_cpus(unsigned int max_cpus)
|
||||
{
|
||||
/* We already did everything necessary earlier */
|
||||
}
|
||||
|
||||
struct plat_smp_ops ip27_smp_ops = {
|
||||
.send_ipi_single = ip27_send_ipi_single,
|
||||
.send_ipi_mask = ip27_send_ipi_mask,
|
||||
.init_secondary = ip27_init_secondary,
|
||||
.smp_finish = ip27_smp_finish,
|
||||
.boot_secondary = ip27_boot_secondary,
|
||||
.smp_setup = ip27_smp_setup,
|
||||
.prepare_cpus = ip27_prepare_cpus,
|
||||
};
|
234
arch/mips/sgi-ip27/ip27-timer.c
Normal file
234
arch/mips/sgi-ip27/ip27-timer.c
Normal file
|
@ -0,0 +1,234 @@
|
|||
/*
|
||||
* Copytight (C) 1999, 2000, 05, 06 Ralf Baechle (ralf@linux-mips.org)
|
||||
* Copytight (C) 1999, 2000 Silicon Graphics, Inc.
|
||||
*/
|
||||
#include <linux/bcd.h>
|
||||
#include <linux/clockchips.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/kernel_stat.h>
|
||||
#include <linux/param.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/timex.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/platform_device.h>
|
||||
|
||||
#include <asm/time.h>
|
||||
#include <asm/pgtable.h>
|
||||
#include <asm/sgialib.h>
|
||||
#include <asm/sn/ioc3.h>
|
||||
#include <asm/sn/klconfig.h>
|
||||
#include <asm/sn/arch.h>
|
||||
#include <asm/sn/addrs.h>
|
||||
#include <asm/sn/sn_private.h>
|
||||
#include <asm/sn/sn0/ip27.h>
|
||||
#include <asm/sn/sn0/hub.h>
|
||||
|
||||
#define TICK_SIZE (tick_nsec / 1000)
|
||||
|
||||
/* Includes for ioc3_init(). */
|
||||
#include <asm/sn/types.h>
|
||||
#include <asm/sn/sn0/addrs.h>
|
||||
#include <asm/sn/sn0/hubni.h>
|
||||
#include <asm/sn/sn0/hubio.h>
|
||||
#include <asm/pci/bridge.h>
|
||||
|
||||
static void enable_rt_irq(struct irq_data *d)
|
||||
{
|
||||
}
|
||||
|
||||
static void disable_rt_irq(struct irq_data *d)
|
||||
{
|
||||
}
|
||||
|
||||
static struct irq_chip rt_irq_type = {
|
||||
.name = "SN HUB RT timer",
|
||||
.irq_mask = disable_rt_irq,
|
||||
.irq_unmask = enable_rt_irq,
|
||||
};
|
||||
|
||||
static int rt_next_event(unsigned long delta, struct clock_event_device *evt)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
int slice = cputoslice(cpu);
|
||||
unsigned long cnt;
|
||||
|
||||
cnt = LOCAL_HUB_L(PI_RT_COUNT);
|
||||
cnt += delta;
|
||||
LOCAL_HUB_S(PI_RT_COMPARE_A + PI_COUNT_OFFSET * slice, cnt);
|
||||
|
||||
return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0;
|
||||
}
|
||||
|
||||
static void rt_set_mode(enum clock_event_mode mode,
|
||||
struct clock_event_device *evt)
|
||||
{
|
||||
/* Nothing to do ... */
|
||||
}
|
||||
|
||||
unsigned int rt_timer_irq;
|
||||
|
||||
static DEFINE_PER_CPU(struct clock_event_device, hub_rt_clockevent);
|
||||
static DEFINE_PER_CPU(char [11], hub_rt_name);
|
||||
|
||||
static irqreturn_t hub_rt_counter_handler(int irq, void *dev_id)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
|
||||
int slice = cputoslice(cpu);
|
||||
|
||||
/*
|
||||
* Ack
|
||||
*/
|
||||
LOCAL_HUB_S(PI_RT_PEND_A + PI_COUNT_OFFSET * slice, 0);
|
||||
cd->event_handler(cd);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
struct irqaction hub_rt_irqaction = {
|
||||
.handler = hub_rt_counter_handler,
|
||||
.flags = IRQF_PERCPU | IRQF_TIMER,
|
||||
.name = "hub-rt",
|
||||
};
|
||||
|
||||
/*
|
||||
* This is a hack; we really need to figure these values out dynamically
|
||||
*
|
||||
* Since 800 ns works very well with various HUB frequencies, such as
|
||||
* 360, 380, 390 and 400 MHZ, we use 800 ns rtc cycle time.
|
||||
*
|
||||
* Ralf: which clock rate is used to feed the counter?
|
||||
*/
|
||||
#define NSEC_PER_CYCLE 800
|
||||
#define CYCLES_PER_SEC (NSEC_PER_SEC / NSEC_PER_CYCLE)
|
||||
|
||||
void hub_rt_clock_event_init(void)
|
||||
{
|
||||
unsigned int cpu = smp_processor_id();
|
||||
struct clock_event_device *cd = &per_cpu(hub_rt_clockevent, cpu);
|
||||
unsigned char *name = per_cpu(hub_rt_name, cpu);
|
||||
int irq = rt_timer_irq;
|
||||
|
||||
sprintf(name, "hub-rt %d", cpu);
|
||||
cd->name = name;
|
||||
cd->features = CLOCK_EVT_FEAT_ONESHOT;
|
||||
clockevent_set_clock(cd, CYCLES_PER_SEC);
|
||||
cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd);
|
||||
cd->min_delta_ns = clockevent_delta2ns(0x300, cd);
|
||||
cd->rating = 200;
|
||||
cd->irq = irq;
|
||||
cd->cpumask = cpumask_of(cpu);
|
||||
cd->set_next_event = rt_next_event;
|
||||
cd->set_mode = rt_set_mode;
|
||||
clockevents_register_device(cd);
|
||||
}
|
||||
|
||||
static void __init hub_rt_clock_event_global_init(void)
|
||||
{
|
||||
int irq;
|
||||
|
||||
do {
|
||||
smp_wmb();
|
||||
irq = rt_timer_irq;
|
||||
if (irq)
|
||||
break;
|
||||
|
||||
irq = allocate_irqno();
|
||||
if (irq < 0)
|
||||
panic("Allocation of irq number for timer failed");
|
||||
} while (xchg(&rt_timer_irq, irq));
|
||||
|
||||
irq_set_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq);
|
||||
setup_irq(irq, &hub_rt_irqaction);
|
||||
}
|
||||
|
||||
static cycle_t hub_rt_read(struct clocksource *cs)
|
||||
{
|
||||
return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT);
|
||||
}
|
||||
|
||||
struct clocksource hub_rt_clocksource = {
|
||||
.name = "HUB-RT",
|
||||
.rating = 200,
|
||||
.read = hub_rt_read,
|
||||
.mask = CLOCKSOURCE_MASK(52),
|
||||
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
|
||||
};
|
||||
|
||||
static void __init hub_rt_clocksource_init(void)
|
||||
{
|
||||
struct clocksource *cs = &hub_rt_clocksource;
|
||||
|
||||
clocksource_register_hz(cs, CYCLES_PER_SEC);
|
||||
}
|
||||
|
||||
void __init plat_time_init(void)
|
||||
{
|
||||
hub_rt_clocksource_init();
|
||||
hub_rt_clock_event_global_init();
|
||||
hub_rt_clock_event_init();
|
||||
}
|
||||
|
||||
void cpu_time_init(void)
|
||||
{
|
||||
lboard_t *board;
|
||||
klcpu_t *cpu;
|
||||
int cpuid;
|
||||
|
||||
/* Don't use ARCS. ARCS is fragile. Klconfig is simple and sane. */
|
||||
board = find_lboard(KL_CONFIG_INFO(get_nasid()), KLTYPE_IP27);
|
||||
if (!board)
|
||||
panic("Can't find board info for myself.");
|
||||
|
||||
cpuid = LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX;
|
||||
cpu = (klcpu_t *) KLCF_COMP(board, cpuid);
|
||||
if (!cpu)
|
||||
panic("No information about myself?");
|
||||
|
||||
printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed);
|
||||
|
||||
set_c0_status(SRB_TIMOCLK);
|
||||
}
|
||||
|
||||
void hub_rtc_init(cnodeid_t cnode)
|
||||
{
|
||||
|
||||
/*
|
||||
* We only need to initialize the current node.
|
||||
* If this is not the current node then it is a cpuless
|
||||
* node and timeouts will not happen there.
|
||||
*/
|
||||
if (get_compact_nodeid() == cnode) {
|
||||
LOCAL_HUB_S(PI_RT_EN_A, 1);
|
||||
LOCAL_HUB_S(PI_RT_EN_B, 1);
|
||||
LOCAL_HUB_S(PI_PROF_EN_A, 0);
|
||||
LOCAL_HUB_S(PI_PROF_EN_B, 0);
|
||||
LOCAL_HUB_S(PI_RT_COUNT, 0);
|
||||
LOCAL_HUB_S(PI_RT_PEND_A, 0);
|
||||
LOCAL_HUB_S(PI_RT_PEND_B, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int __init sgi_ip27_rtc_devinit(void)
|
||||
{
|
||||
struct resource res;
|
||||
|
||||
memset(&res, 0, sizeof(res));
|
||||
res.start = XPHYSADDR(KL_CONFIG_CH_CONS_INFO(master_nasid)->memory_base +
|
||||
IOC3_BYTEBUS_DEV0);
|
||||
res.end = res.start + 32767;
|
||||
res.flags = IORESOURCE_MEM;
|
||||
|
||||
return IS_ERR(platform_device_register_simple("rtc-m48t35", -1,
|
||||
&res, 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* kludge make this a device_initcall after ioc3 resource conflicts
|
||||
* are resolved
|
||||
*/
|
||||
late_initcall(sgi_ip27_rtc_devinit);
|
135
arch/mips/sgi-ip27/ip27-xtalk.c
Normal file
135
arch/mips/sgi-ip27/ip27-xtalk.c
Normal file
|
@ -0,0 +1,135 @@
|
|||
/*
|
||||
* Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
|
||||
* Copyright (C) 1999, 2000 Silcon Graphics, Inc.
|
||||
* Copyright (C) 2004 Christoph Hellwig.
|
||||
* Released under GPL v2.
|
||||
*
|
||||
* Generic XTALK initialization code
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/smp.h>
|
||||
#include <asm/sn/types.h>
|
||||
#include <asm/sn/klconfig.h>
|
||||
#include <asm/sn/hub.h>
|
||||
#include <asm/pci/bridge.h>
|
||||
#include <asm/xtalk/xtalk.h>
|
||||
|
||||
|
||||
#define XBOW_WIDGET_PART_NUM 0x0
|
||||
#define XXBOW_WIDGET_PART_NUM 0xd000 /* Xbow in Xbridge */
|
||||
#define BASE_XBOW_PORT 8 /* Lowest external port */
|
||||
|
||||
extern int bridge_probe(nasid_t nasid, int widget, int masterwid);
|
||||
|
||||
static int probe_one_port(nasid_t nasid, int widget, int masterwid)
|
||||
{
|
||||
widgetreg_t widget_id;
|
||||
xwidget_part_num_t partnum;
|
||||
|
||||
widget_id = *(volatile widgetreg_t *)
|
||||
(RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID);
|
||||
partnum = XWIDGET_PART_NUM(widget_id);
|
||||
|
||||
printk(KERN_INFO "Cpu %d, Nasid 0x%x, widget 0x%x (partnum 0x%x) is ",
|
||||
smp_processor_id(), nasid, widget, partnum);
|
||||
|
||||
switch (partnum) {
|
||||
case BRIDGE_WIDGET_PART_NUM:
|
||||
case XBRIDGE_WIDGET_PART_NUM:
|
||||
bridge_probe(nasid, widget, masterwid);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int xbow_probe(nasid_t nasid)
|
||||
{
|
||||
lboard_t *brd;
|
||||
klxbow_t *xbow_p;
|
||||
unsigned masterwid, i;
|
||||
|
||||
printk("is xbow\n");
|
||||
|
||||
/*
|
||||
* found xbow, so may have multiple bridges
|
||||
* need to probe xbow
|
||||
*/
|
||||
brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8);
|
||||
if (!brd)
|
||||
return -ENODEV;
|
||||
|
||||
xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW);
|
||||
if (!xbow_p)
|
||||
return -ENODEV;
|
||||
|
||||
/*
|
||||
* Okay, here's a xbow. Lets arbitrate and find
|
||||
* out if we should initialize it. Set enabled
|
||||
* hub connected at highest or lowest widget as
|
||||
* master.
|
||||
*/
|
||||
#ifdef WIDGET_A
|
||||
i = HUB_WIDGET_ID_MAX + 1;
|
||||
do {
|
||||
i--;
|
||||
} while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
|
||||
(!XBOW_PORT_IS_ENABLED(xbow_p, i)));
|
||||
#else
|
||||
i = HUB_WIDGET_ID_MIN - 1;
|
||||
do {
|
||||
i++;
|
||||
} while ((!XBOW_PORT_TYPE_HUB(xbow_p, i)) ||
|
||||
(!XBOW_PORT_IS_ENABLED(xbow_p, i)));
|
||||
#endif
|
||||
|
||||
masterwid = i;
|
||||
if (nasid != XBOW_PORT_NASID(xbow_p, i))
|
||||
return 1;
|
||||
|
||||
for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) {
|
||||
if (XBOW_PORT_IS_ENABLED(xbow_p, i) &&
|
||||
XBOW_PORT_TYPE_IO(xbow_p, i))
|
||||
probe_one_port(nasid, i, masterwid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void xtalk_probe_node(cnodeid_t nid)
|
||||
{
|
||||
volatile u64 hubreg;
|
||||
nasid_t nasid;
|
||||
xwidget_part_num_t partnum;
|
||||
widgetreg_t widget_id;
|
||||
|
||||
nasid = COMPACT_TO_NASID_NODEID(nid);
|
||||
hubreg = REMOTE_HUB_L(nasid, IIO_LLP_CSR);
|
||||
|
||||
/* check whether the link is up */
|
||||
if (!(hubreg & IIO_LLP_CSR_IS_UP))
|
||||
return;
|
||||
|
||||
widget_id = *(volatile widgetreg_t *)
|
||||
(RAW_NODE_SWIN_BASE(nasid, 0x0) + WIDGET_ID);
|
||||
partnum = XWIDGET_PART_NUM(widget_id);
|
||||
|
||||
printk(KERN_INFO "Cpu %d, Nasid 0x%x: partnum 0x%x is ",
|
||||
smp_processor_id(), nasid, partnum);
|
||||
|
||||
switch (partnum) {
|
||||
case BRIDGE_WIDGET_PART_NUM:
|
||||
bridge_probe(nasid, 0x8, 0xa);
|
||||
break;
|
||||
case XBOW_WIDGET_PART_NUM:
|
||||
case XXBOW_WIDGET_PART_NUM:
|
||||
xbow_probe(nasid);
|
||||
break;
|
||||
default:
|
||||
printk(" unknown widget??\n");
|
||||
break;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue