diff --git a/arch/mips/include/asm/irq.h b/arch/mips/include/asm/irq.h index 15e0fec..97d00af 100644 --- a/arch/mips/include/asm/irq.h +++ b/arch/mips/include/asm/irq.h @@ -33,9 +33,11 @@ extern void do_IRQ(unsigned int irq); extern void arch_init_irq(void); extern void spurious_interrupt(void); -extern int allocate_irqno(void); -extern void alloc_legacy_irqno(void); -extern void free_irqno(unsigned int irq); +#if defined(CONFIG_SGI_IP27) +extern int ip27_alloc_irq_num(void); +extern void ip27_assign_irq_num(int irq); +extern void ip27_free_irq_num(int irq); +#endif /* * Before R2 the timer and performance counter interrupts were both fixed to diff --git a/arch/mips/include/asm/mach-ip27/dma-coherence.h b/arch/mips/include/asm/mach-ip27/dma-coherence.h index 1daa644..04d8620 100644 --- a/arch/mips/include/asm/mach-ip27/dma-coherence.h +++ b/arch/mips/include/asm/mach-ip27/dma-coherence.h @@ -64,7 +64,7 @@ static inline void plat_post_dma_flush(struct device *dev) static inline int plat_device_is_coherent(struct device *dev) { - return 1; /* IP27 non-cohernet mode is unsupported */ + return 1; /* IP27 non-coherent mode is unsupported */ } #endif /* __ASM_MACH_IP27_DMA_COHERENCE_H */ diff --git a/arch/mips/include/asm/mach-ip27/mangle-port.h b/arch/mips/include/asm/mach-ip27/mangle-port.h index f6e4912..5184c94 100644 --- a/arch/mips/include/asm/mach-ip27/mangle-port.h +++ b/arch/mips/include/asm/mach-ip27/mangle-port.h @@ -8,7 +8,7 @@ #ifndef __ASM_MACH_IP27_MANGLE_PORT_H #define __ASM_MACH_IP27_MANGLE_PORT_H -#define __swizzle_addr_b(port) (port) +#define __swizzle_addr_b(port) ((port) ^ 3) #define __swizzle_addr_w(port) ((port) ^ 2) #define __swizzle_addr_l(port) (port) #define __swizzle_addr_q(port) (port) @@ -20,6 +20,6 @@ # define ioswabl(a, x) (x) # define __mem_ioswabl(a, x) cpu_to_le32(x) # define ioswabq(a, x) (x) -# define __mem_ioswabq(a, x) cpu_to_le32(x) +# define __mem_ioswabq(a, x) cpu_to_le64(x) #endif /* __ASM_MACH_IP27_MANGLE_PORT_H */ diff --git a/arch/mips/include/asm/mach-ip27/mmzone.h b/arch/mips/include/asm/mach-ip27/mmzone.h index ebc9377..4bff2f5 100644 --- a/arch/mips/include/asm/mach-ip27/mmzone.h +++ b/arch/mips/include/asm/mach-ip27/mmzone.h @@ -1,3 +1,9 @@ +/* + * 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. + */ + #ifndef _ASM_MACH_MMZONE_H #define _ASM_MACH_MMZONE_H @@ -5,24 +11,44 @@ #include #include -#define pa_to_nid(addr) NASID_TO_COMPACT_NODEID(NASID_GET(addr)) - -#define LEVELS_PER_SLICE 128 +#define pa_to_nid(addr) sn_nasid_to_cnodeid[NASID_GET(addr)] -struct slice_data { - unsigned long irq_enable_mask[2]; - int level_to_irq[LEVELS_PER_SLICE]; -}; +#define BITS_PER_HUB 128 struct hub_data { kern_vars_t kern_vars; DECLARE_BITMAP(h_bigwin_used, HUB_NUM_BIG_WINDOW); cpumask_t h_cpus; unsigned long slice_map; - unsigned long irq_alloc_mask[2]; - struct slice_data slice[2]; + unsigned long irq_alloc_map[2]; + s8 irq_to_bit[BITS_PER_HUB]; + s8 bit_to_irq[BITS_PER_HUB]; }; +/** + * struct ip27_percpu_data - percpu data for each CPU in an IP27 system. + * @id: ID of the CPU + * @nasid: node id. + * @codeid: compact node id. + * @slice: 0 for CPU A or 1 for CPU B + * @irq_mask: array of two unsigned longs to hold the INT_PEND mask. + * @irq_owner: boolean array to mark if a CPU owns an IRQ. + * @hub_data: struct hub_data pointer for the HUB chip the CPU is attached to. + */ +struct ip27_percpu_data { + u32 id; + nasid_t nasid; + cnodeid_t cnodeid; + u8 slice; + unsigned long irq_mask[2]; + bool irq_owner[BITS_PER_HUB]; + struct hub_data *hub; +}; + +/* XXX: This probably belongs in a dedicated cpu.h header. */ +#define IP27_CPU_SLICE(_s) \ + (!(_s) ? 'A' : 'B') + struct node_data { struct pglist_data pglist; struct hub_data hub; diff --git a/arch/mips/include/asm/mach-ip27/pcibr.h b/arch/mips/include/asm/mach-ip27/pcibr.h new file mode 100644 index 0000000..5750849 --- /dev/null +++ b/arch/mips/include/asm/mach-ip27/pcibr.h @@ -0,0 +1,48 @@ +/* + * Definitions for PCI bridges in IP27. + * + * Copyright (C) 2004-2007 Stanislaw Skowronek + * Copyright (C) 2015-2016 Joshua Kinard + * + * 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. + */ + +#ifndef __ASM_MACH_IP27_PCIBR_H +#define __ASM_MACH_IP27_PCIBR_H + +#include +#include + +/* Xtalk */ +#define PCIBR_OFFSET_MEM 0x200000 +#define PCIBR_OFFSET_IO 0xa00000 +#define PCIBR_OFFSET_END 0xc00000 + +#define PCIBR_DIR_ALLOC_BASE 0x1000000 + +/* + * This is how XIO sees HUB's PI_INT_PEND_MOD register. + */ +#define PCIBR_XIO_SEES_HUB 0x01800090 + +/* + * Max # of PCI buses we can handle; ie, max #PCI bridges. + */ +#define PCIBR_MAX_NUM_PCIBUS 40 + +/* + * Max # of PCI devices (like scsi controllers) we handle on a bus. + */ +#define PCIBR_MAX_DEV_PCIBUS 8 + +/* + * Used by ip27-bridge.c and ip27-irq.c. + */ +#define PCIBR_MAX_BUS_X_DEV PCIBR_MAX_NUM_PCIBUS * PCIBR_MAX_DEV_PCIBUS +extern struct bridge_controller *ip27_irq_to_bridge[PCIBR_MAX_BUS_X_DEV]; +extern u32 ip27_irq_to_slot[PCIBR_MAX_BUS_X_DEV]; + +#endif /* __ASM_MACH_IP27_PCIBR_H */ + diff --git a/arch/mips/include/asm/mach-ip27/spaces.h b/arch/mips/include/asm/mach-ip27/spaces.h index b18802a..424c919 100644 --- a/arch/mips/include/asm/mach-ip27/spaces.h +++ b/arch/mips/include/asm/mach-ip27/spaces.h @@ -10,20 +10,25 @@ #ifndef _ASM_MACH_IP27_SPACES_H #define _ASM_MACH_IP27_SPACES_H +#include + /* * IP27 uses the R10000's uncached attribute feature. Attribute 3 selects * uncached memory addressing. */ - -#define HSPEC_BASE 0x9000000000000000 -#define IO_BASE 0x9200000000000000 -#define MSPEC_BASE 0x9400000000000000 -#define UNCAC_BASE 0x9600000000000000 +#ifdef CONFIG_64BIT +#define HSPEC_BASE _AC(0x9000000000000000, UL) +#define IO_BASE _AC(0x9200000000000000, UL) +#define MSPEC_BASE _AC(0x9400000000000000, UL) +#define UNCAC_BASE _AC(0x9600000000000000, UL) #define TO_MSPEC(x) (MSPEC_BASE | ((x) & TO_PHYS_MASK)) #define TO_HSPEC(x) (HSPEC_BASE | ((x) & TO_PHYS_MASK)) +#define PAGE_OFFSET CAC_BASE + #define HIGHMEM_START (~0UL) +#endif /* CONFIG_64BIT */ #include diff --git a/arch/mips/include/asm/mach-ip27/sysinfo.h b/arch/mips/include/asm/mach-ip27/sysinfo.h new file mode 100644 index 0000000..83270d0 --- /dev/null +++ b/arch/mips/include/asm/mach-ip27/sysinfo.h @@ -0,0 +1,23 @@ +/* + * IP27/Origin/Onyx2 misc system defines that don't fit into other headers. + * + * Copyright (C) 2016 Joshua Kinard + * + * 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. + */ +#ifndef __ASM_MACH_IP27_SYSINFO_H +#define __ASM_MACH_IP27_SYSINFO_H + +/* Hardcoded IP27 xtalk widget IDs. */ +#define IP27_WIDGET_XBOW _AC(0x0, UL) /* XBow is always 0 */ +#define IP27_WIDGET_HUB _AC(0xa, UL) /* HUB is always 0xa */ +#define IP27_WIDGET_PCI_CAGE _AC(0xc, UL) /* PCI Cage is always 12 */ +#define IP27_WIDGET_PCI_BASE _AC(0xf, UL) /* IO6[-G] is always 15 */ + +/* On the IO6 BRIDGE, at least one slot is hardwired for special functions */ +#define IP27_IO6_2ND_IOC3 3 +/* XXX: Could there be more? What's slot #4 do? */ + +#endif /* __ASM_MACH_IP27_SYSINFO_H */ diff --git a/arch/mips/include/asm/mach-ip27/topology.h b/arch/mips/include/asm/mach-ip27/topology.h index defd135..f34f43e 100644 --- a/arch/mips/include/asm/mach-ip27/topology.h +++ b/arch/mips/include/asm/mach-ip27/topology.h @@ -1,32 +1,22 @@ +/* + * 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. + */ + #ifndef _ASM_MACH_TOPOLOGY_H -#define _ASM_MACH_TOPOLOGY_H 1 +#define _ASM_MACH_TOPOLOGY_H #include #include #include -struct cpuinfo_ip27 { -// cpuid_t p_cpuid; /* PROM assigned cpuid */ - cnodeid_t p_nodeid; /* my node ID in compact-id-space */ - nasid_t p_nasid; /* my node ID in numa-as-id-space */ - unsigned char p_slice; /* Physical position on node board */ -#if 0 - unsigned long loops_per_sec; - unsigned long ipi_count; - unsigned long irq_attempt[NR_IRQS]; - unsigned long smp_local_irq_count; - unsigned long prof_multiplier; - unsigned long prof_counter; -#endif -}; - -extern struct cpuinfo_ip27 sn_cpu_info[NR_CPUS]; - -#define cpu_to_node(cpu) (sn_cpu_info[(cpu)].p_nodeid) +DECLARE_PER_CPU(struct ip27_percpu_data, ip27_cpu); + +#define cpu_to_node(cpu) (per_cpu(ip27_cpu, cpu).cnodeid) #define parent_node(node) (node) #define cpumask_of_node(node) ((node) == -1 ? \ - cpu_all_mask : \ - &hub_data(node)->h_cpus) + cpu_all_mask : &hub_data(node)->h_cpus) struct pci_bus; extern int pcibus_to_node(struct pci_bus *); diff --git a/arch/mips/include/asm/sn/addrs.h b/arch/mips/include/asm/sn/addrs.h index 66814f8..ac11851 100644 --- a/arch/mips/include/asm/sn/addrs.h +++ b/arch/mips/include/asm/sn/addrs.h @@ -140,7 +140,7 @@ #define UALIAS_FLIP_BASE UALIAS_BASE #define UALIAS_FLIP_SIZE 0x20000 #define UALIAS_FLIP_BIT 0x10000 -#define UALIAS_FLIP_ADDR(_x) (cputoslice(smp_processor_id()) ? \ +#define UALIAS_FLIP_ADDR(_x) (per_cpu(ip27_cpu, smp_processor_id()).slice) ? \ (_x) ^ UALIAS_FLIP_BIT : (_x)) #define LBOOT_BASE (HSPEC_BASE + 0x10000000) diff --git a/arch/mips/include/asm/sn/agent.h b/arch/mips/include/asm/sn/agent.h index e33d092..c7ad95e 100644 --- a/arch/mips/include/asm/sn/agent.h +++ b/arch/mips/include/asm/sn/agent.h @@ -25,8 +25,8 @@ */ #if defined(CONFIG_SGI_IP27) -#define HUB_NIC_ADDR(_cpuid) \ - REMOTE_HUB_ADDR(COMPACT_TO_NASID_NODEID(cpu_to_node(_cpuid)), \ +#define HUB_NIC_ADDR(_cpuid) \ + REMOTE_HUB_ADDR(sn_cnodeid_to_nasid[sn_cpuid_to_cnodeid[(_cpuid)]], \ MD_MLAN_CTL) #endif diff --git a/arch/mips/include/asm/sn/arch.h b/arch/mips/include/asm/sn/arch.h index 471e687..9b9bc31 100644 --- a/arch/mips/include/asm/sn/arch.h +++ b/arch/mips/include/asm/sn/arch.h @@ -12,6 +12,8 @@ #define _ASM_SN_ARCH_H #include +#include + #include #ifdef CONFIG_SGI_IP27 #include @@ -19,8 +21,6 @@ typedef u64 hubreg_t; -#define cputonasid(cpu) (sn_cpu_info[(cpu)].p_nasid) -#define cputoslice(cpu) (sn_cpu_info[(cpu)].p_slice) #define makespnum(_nasid, _slice) \ (((_nasid) << CPUS_PER_NODE_SHFT) | (_slice)) @@ -30,35 +30,24 @@ typedef u64 hubreg_t; #define INVALID_MODULE (moduleid_t)-1 #define INVALID_PARTID (partid_t)-1 -extern nasid_t get_nasid(void); -extern cnodeid_t get_cpu_cnode(cpuid_t); -extern int get_cpu_slice(cpuid_t); +extern nasid_t ip27_get_nasid(void); +extern int get_cpu_slice(cpuid_t) __init; -/* - * NO ONE should access these arrays directly. The only reason we refer to - * them here is to avoid the procedure call that would be required in the - * macros below. (Really want private data members here :-) - */ -extern cnodeid_t nasid_to_compact_node[MAX_NASIDS]; -extern nasid_t compact_to_nasid_node[MAX_COMPACT_NODES]; +#define NASID_TO_REGION(nnode) \ + ((nnode) >> (is_fine_dirmode() ? \ + NASID_TO_FINEREG_SHFT : NASID_TO_COARSEREG_SHFT)) -/* - * These macros are used by various parts of the kernel to convert - * between the three different kinds of node numbering. At least some - * of them may change to procedure calls in the future, but the macros - * will continue to work. Don't use the arrays above directly. - */ -#define NASID_TO_REGION(nnode) \ - ((nnode) >> \ - (is_fine_dirmode() ? NASID_TO_FINEREG_SHFT : NASID_TO_COARSEREG_SHFT)) +/* Compact node ID to nasid mappings as per-cpu data */ +DECLARE_PER_CPU(cnodeid_t, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]); +#define sn_cnodeid_to_nasid this_cpu_ptr(&__sn_cnodeid_to_nasid[0]) -extern cnodeid_t nasid_to_compact_node[MAX_NASIDS]; -extern nasid_t compact_to_nasid_node[MAX_COMPACT_NODES]; -extern cnodeid_t cpuid_to_compact_node[MAXCPUS]; +/* NUMA-node-as-ID to compact node ID mappings as per-cpu data */ +DECLARE_PER_CPU(nasid_t, __sn_nasid_to_cnodeid[MAX_NASIDS]); +#define sn_nasid_to_cnodeid this_cpu_ptr(&__sn_nasid_to_cnodeid[0]) -#define NASID_TO_COMPACT_NODEID(nnode) (nasid_to_compact_node[nnode]) -#define COMPACT_TO_NASID_NODEID(cnode) (compact_to_nasid_node[cnode]) -#define CPUID_TO_COMPACT_NODEID(cpu) (cpuid_to_compact_node[(cpu)]) +/* CPUID to compact node ID mappings as per-cpu data */ +DECLARE_PER_CPU(cnodeid_t, __sn_cpuid_to_cnodeid[MAXCPUS]); +#define sn_cpuid_to_cnodeid this_cpu_ptr(&__sn_cpuid_to_cnodeid[0]) #endif /* _ASM_SN_ARCH_H */ diff --git a/arch/mips/include/asm/sn/fru.h b/arch/mips/include/asm/sn/fru.h index bbb8325..b92901e 100644 --- a/arch/mips/include/asm/sn/fru.h +++ b/arch/mips/include/asm/sn/fru.h @@ -14,13 +14,11 @@ #define MAX_DIMMS 8 /* max # of dimm banks */ #define MAX_PCIDEV 8 /* max # of pci devices on a pci bus */ -typedef unsigned char confidence_t; - typedef struct kf_mem_s { - confidence_t km_confidence; /* confidence level that the memory is bad + u8 km_confidence; /* confidence level that the memory is bad * is this necessary ? */ - confidence_t km_dimm[MAX_DIMMS]; + u8 km_dimm[MAX_DIMMS]; /* confidence level that dimm[i] is bad *I think this is the right number */ @@ -28,16 +26,16 @@ typedef struct kf_mem_s { } kf_mem_t; typedef struct kf_cpu_s { - confidence_t kc_confidence; /* confidence level that cpu is bad */ - confidence_t kc_icache; /* confidence level that instr. cache is bad */ - confidence_t kc_dcache; /* confidence level that data cache is bad */ - confidence_t kc_scache; /* confidence level that sec. cache is bad */ - confidence_t kc_sysbus; /* confidence level that sysad/cmd/state bus is bad */ + u8 kc_confidence; /* confidence level that cpu is bad */ + u8 kc_icache; /* confidence level that instr. cache is bad */ + u8 kc_dcache; /* confidence level that data cache is bad */ + u8 kc_scache; /* confidence level that sec. cache is bad */ + u8 kc_sysbus; /* confidence level that sysad/cmd/state bus is bad */ } kf_cpu_t; typedef struct kf_pci_bus_s { - confidence_t kpb_belief; /* confidence level that the pci bus is bad */ - confidence_t kpb_pcidev_belief[MAX_PCIDEV]; + u8 kpb_belief; /* confidence level that the pci bus is bad */ + u8 kpb_pcidev_belief[MAX_PCIDEV]; /* confidence level that the pci dev is bad */ } kf_pci_bus_t; diff --git a/arch/mips/include/asm/sn/gda.h b/arch/mips/include/asm/sn/gda.h index 85fa1b5..852d48c 100644 --- a/arch/mips/include/asm/sn/gda.h +++ b/arch/mips/include/asm/sn/gda.h @@ -65,7 +65,7 @@ typedef struct gda { */ } gda_t; -#define GDA ((gda_t*) GDA_ADDR(get_nasid())) +#define GDA ((gda_t*) GDA_ADDR(ip27_get_nasid())) #endif /* !__ASSEMBLY__ */ /* diff --git a/arch/mips/include/asm/sn/hub.h b/arch/mips/include/asm/sn/hub.h index 1992d92..c4e33fa 100644 --- a/arch/mips/include/asm/sn/hub.h +++ b/arch/mips/include/asm/sn/hub.h @@ -11,6 +11,6 @@ /* ip27-hubio.c */ extern unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, unsigned long xtalk_addr, size_t size); -extern void hub_pio_init(cnodeid_t cnode); +extern void __init ip27_hub_pio_init(cnodeid_t cnode); #endif /* __ASM_SN_HUB_H */ diff --git a/arch/mips/include/asm/sn/klconfig.h b/arch/mips/include/asm/sn/klconfig.h index 467c313..9290691 100644 --- a/arch/mips/include/asm/sn/klconfig.h +++ b/arch/mips/include/asm/sn/klconfig.h @@ -11,210 +11,28 @@ #ifndef _ASM_SN_KLCONFIG_H #define _ASM_SN_KLCONFIG_H -/* - * The KLCONFIG structures store info about the various BOARDs found - * during Hardware Discovery. In addition, it stores info about the - * components found on the BOARDs. - */ - -/* - * WARNING: - * Certain assembly language routines (notably xxxxx.s) in the IP27PROM - * will depend on the format of the data structures in this file. In - * most cases, rearranging the fields can seriously break things. - * Adding fields in the beginning or middle can also break things. - * Add fields if necessary, to the end of a struct in such a way - * that offsets of existing fields do not change. - */ - #include #include #if defined(CONFIG_SGI_IP27) - #include -//#include -// XXX Stolen from : -#define MAX_ROUTER_PORTS (6) /* Max. number of ports on a router */ #include -//#include -//#include - -#elif defined(CONFIG_SGI_IP35) - -#include -#include -#include -#include +/* CONFIG_SGI_IP35 bits will go here in the future. */ +#endif /* CONFIG_SGI_IP27 */ -#endif /* !CONFIG_SGI_IP27 && !CONFIG_SGI_IP35 */ - -#if defined(CONFIG_SGI_IP27) || defined(CONFIG_SGI_IP35) +#if defined(CONFIG_SGI_IP27) /* || defined(CONFIG_SGI_IP35) */ #include #include #include -#if defined(CONFIG_SGI_IP35) -// The hack file has to be before vector and after sn0_fru.... -#include -#include -#include -#endif /* CONFIG_SGI_IP35 */ -#endif /* CONFIG_SGI_IP27 || CONFIG_SGI_IP35 */ - -typedef u64 nic_t; - -#define KLCFGINFO_MAGIC 0xbeedbabe +/* CONFIG_SGI_IP35 bits will go here in the future. */ +#endif /* CONFIG_SGI_IP27 */ -typedef s32 klconf_off_t; - -/* - * Some IMPORTANT OFFSETS. These are the offsets on all NODES. - */ -#define MAX_MODULE_ID 255 -#define SIZE_PAD 4096 /* 4k padding for structures */ -/* - * 1 NODE brd, 2 Router brd (1 8p, 1 meta), 6 Widgets, - * 2 Midplanes assuming no pci card cages - */ -#define MAX_SLOTS_PER_NODE (1 + 2 + 6 + 2) - -/* XXX if each node is guaranteed to have some memory */ - -#define MAX_PCI_DEVS 8 - -/* lboard_t->brd_flags fields */ -/* All bits in this field are currently used. Try the pad fields if - you need more flag bits */ - -#define ENABLE_BOARD 0x01 -#define FAILED_BOARD 0x02 -#define DUPLICATE_BOARD 0x04 /* Boards like midplanes/routers which - are discovered twice. Use one of them */ -#define VISITED_BOARD 0x08 /* Used for compact hub numbering. */ -#define LOCAL_MASTER_IO6 0x10 /* master io6 for that node */ -#define GLOBAL_MASTER_IO6 0x20 -#define THIRD_NIC_PRESENT 0x40 /* for future use */ -#define SECOND_NIC_PRESENT 0x80 /* addons like MIO are present */ - -/* klinfo->flags fields */ - -#define KLINFO_ENABLE 0x01 /* This component is enabled */ -#define KLINFO_FAILED 0x02 /* This component failed */ -#define KLINFO_DEVICE 0x04 /* This component is a device */ -#define KLINFO_VISITED 0x08 /* This component has been visited */ -#define KLINFO_CONTROLLER 0x10 /* This component is a device controller */ -#define KLINFO_INSTALL 0x20 /* Install a driver */ -#define KLINFO_HEADLESS 0x40 /* Headless (or hubless) component */ -#define IS_CONSOLE_IOC3(i) ((((klinfo_t *)i)->flags) & KLINFO_INSTALL) - -#define GB2 0x80000000 - -#define MAX_RSV_PTRS 32 - -/* Structures to manage various data storage areas */ -/* The numbers must be contiguous since the array index i - is used in the code to allocate various areas. -*/ - -#define BOARD_STRUCT 0 -#define COMPONENT_STRUCT 1 -#define ERRINFO_STRUCT 2 -#define KLMALLOC_TYPE_MAX (ERRINFO_STRUCT + 1) -#define DEVICE_STRUCT 3 - - -typedef struct console_s { - unsigned long uart_base; - unsigned long config_base; - unsigned long memory_base; - short baud; - short flag; - int type; - nasid_t nasid; - char wid; - char npci; - nic_t baseio_nic; -} console_t; - -typedef struct klc_malloc_hdr { - klconf_off_t km_base; - klconf_off_t km_limit; - klconf_off_t km_current; -} klc_malloc_hdr_t; - -/* Functions/macros needed to use this structure */ - -typedef struct kl_config_hdr { - u64 ch_magic; /* set this to KLCFGINFO_MAGIC */ - u32 ch_version; /* structure version number */ - klconf_off_t ch_malloc_hdr_off; /* offset of ch_malloc_hdr */ - klconf_off_t ch_cons_off; /* offset of ch_cons */ - klconf_off_t ch_board_info; /* the link list of boards */ - console_t ch_cons_info; /* address info of the console */ - klc_malloc_hdr_t ch_malloc_hdr[KLMALLOC_TYPE_MAX]; - confidence_t ch_sw_belief; /* confidence that software is bad*/ - confidence_t ch_sn0net_belief; /* confidence that sn0net is bad */ -} kl_config_hdr_t; - - -#define KL_CONFIG_HDR(_nasid) ((kl_config_hdr_t *)(KLCONFIG_ADDR(_nasid))) -#define KL_CONFIG_INFO_OFFSET(_nasid) \ - (KL_CONFIG_HDR(_nasid)->ch_board_info) -#define KL_CONFIG_INFO_SET_OFFSET(_nasid, _off) \ - (KL_CONFIG_HDR(_nasid)->ch_board_info = (_off)) - -#define KL_CONFIG_INFO(_nasid) \ - (lboard_t *)((KL_CONFIG_HDR(_nasid)->ch_board_info) ? \ - NODE_OFFSET_TO_K1((_nasid), KL_CONFIG_HDR(_nasid)->ch_board_info) : \ - 0) -#define KL_CONFIG_MAGIC(_nasid) (KL_CONFIG_HDR(_nasid)->ch_magic) - -#define KL_CONFIG_CHECK_MAGIC(_nasid) \ - (KL_CONFIG_HDR(_nasid)->ch_magic == KLCFGINFO_MAGIC) - -#define KL_CONFIG_HDR_INIT_MAGIC(_nasid) \ - (KL_CONFIG_HDR(_nasid)->ch_magic = KLCFGINFO_MAGIC) - -/* --- New Macros for the changed kl_config_hdr_t structure --- */ - -#define PTR_CH_MALLOC_HDR(_k) ((klc_malloc_hdr_t *)\ - ((unsigned long)_k + (_k->ch_malloc_hdr_off))) - -#define KL_CONFIG_CH_MALLOC_HDR(_n) PTR_CH_MALLOC_HDR(KL_CONFIG_HDR(_n)) - -#define PTR_CH_CONS_INFO(_k) ((console_t *)\ - ((unsigned long)_k + (_k->ch_cons_off))) - -#define KL_CONFIG_CH_CONS_INFO(_n) PTR_CH_CONS_INFO(KL_CONFIG_HDR(_n)) - -/* ------------------------------------------------------------- */ - -#define KL_CONFIG_INFO_START(_nasid) \ - (klconf_off_t)(KLCONFIG_OFFSET(_nasid) + sizeof(kl_config_hdr_t)) - -#define KL_CONFIG_BOARD_NASID(_brd) ((_brd)->brd_nasid) -#define KL_CONFIG_BOARD_SET_NEXT(_brd, _off) ((_brd)->brd_next = (_off)) - -#define KL_CONFIG_DUPLICATE_BOARD(_brd) ((_brd)->brd_flags & DUPLICATE_BOARD) - -#define XBOW_PORT_TYPE_HUB(_xbowp, _link) \ - ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_flag & XBOW_PORT_HUB) -#define XBOW_PORT_TYPE_IO(_xbowp, _link) \ - ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_flag & XBOW_PORT_IO) - -#define XBOW_PORT_IS_ENABLED(_xbowp, _link) \ - ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_flag & XBOW_PORT_ENABLE) -#define XBOW_PORT_NASID(_xbowp, _link) \ - ((_xbowp)->xbow_port_info[(_link) - BASE_XBOW_PORT].port_nasid) - -#define XBOW_PORT_IO 0x1 -#define XBOW_PORT_HUB 0x2 -#define XBOW_PORT_ENABLE 0x4 - -#define SN0_PORT_FENCE_SHFT 0 -#define SN0_PORT_FENCE_MASK (1 << SN0_PORT_FENCE_SHFT) /* + * The KLCONFIG structures store info about the various BOARDs found + * during Hardware Discovery. In addition, it stores info about the + * components found on the BOARDs. + * * The KLCONFIG area is organized as a LINKED LIST of BOARDs. A BOARD * can be either 'LOCAL' or 'REMOTE'. LOCAL means it is attached to * the LOCAL/current NODE. REMOTE means it is attached to a different @@ -240,31 +58,31 @@ typedef struct kl_config_hdr { * the local base address and ignoring all rboard values. * * - KLCONFIG - - +------------+ +------------+ +------------+ +------------+ - | lboard | +-->| lboard | +-->| rboard | +-->| lboard | - +------------+ | +------------+ | +------------+ | +------------+ - | board info | | | board info | | |errinfo,bptr| | | board info | - +------------+ | +------------+ | +------------+ | +------------+ - | offset |--+ | offset |--+ | offset |--+ |offset=NULL | - +------------+ +------------+ +------------+ +------------+ - - - +------------+ - | board info | - +------------+ +--------------------------------+ - | compt 1 |------>| type, rev, diaginfo, size ... | (CPU) - +------------+ +--------------------------------+ - | compt 2 |--+ - +------------+ | +--------------------------------+ - | ... | +--->| type, rev, diaginfo, size ... | (MEM_BANK) - +------------+ +--------------------------------+ - | errinfo |--+ - +------------+ | +--------------------------------+ - +--->|r/l brd errinfo,compt err flags | - +--------------------------------+ - + * KLCONFIG + * + * +------------+ +------------+ +------------+ +------------+ + * | lboard | +-->| lboard | +-->| rboard | +-->| lboard | + * +------------+ | +------------+ | +------------+ | +------------+ + * | board info | | | board info | | |errinfo,bptr| | | board info | + * +------------+ | +------------+ | +------------+ | +------------+ + * | offset |--+ | offset |--+ | offset |--+ |offset=NULL | + * +------------+ +------------+ +------------+ +------------+ + * + * + * +------------+ + * | board info | + * +------------+ +--------------------------------+ + * | comp 1 |------>| type, rev, diaginfo, size ... | (CPU) + * +------------+ +--------------------------------+ + * | comp 2 |--+ + * +------------+ | +--------------------------------+ + * | ... | +--->| type, rev, diaginfo, size ... | (MEM_BANK) + * +------------+ +--------------------------------+ + * | errinfo |--+ + * +------------+ | +--------------------------------+ + * +--->|r/l brd errinfo,compt err flags | + * +--------------------------------+ + * * * Each BOARD consists of COMPONENTs and the BOARD structure has * pointers (offsets) to its COMPONENT structure. @@ -292,11 +110,12 @@ typedef struct kl_config_hdr { * using the rboard errinfo pointer. * * In order to get useful information from this Data organization, a set of - * interface routines are provided (TBD). The important thing to remember while - * manipulating the structures, is that, the NODE number information should - * be used. If the NODE is non-zero (remote) then each offset should - * be added to the REMOTE BASE ADDR else it should be added to the LOCAL BASE ADDR. - * This includes offsets for BOARDS, COMPONENTS and ERRORINFO. + * interface routines are provided (TBD). The important thing to remember + * while manipulating the structures, is that, the NODE number information + * should be used. If the NODE is non-zero (remote) then each offset should + * be added to the REMOTE_BASE_ADDR else it should be added to the + * LOCAL_BASE_ADDR. This includes offsets for BOARDS, COMPONENTS and + * ERRORINFO. * * Note that these structures do not provide much info about connectivity. * That info will be part of HWGRAPH, which is an extension of the cfg_t @@ -304,595 +123,1099 @@ typedef struct kl_config_hdr { * the IO part of the Network(TBD). * * The data structures below define the above concepts. + * + * XXX: Missing definition for struct klc_rboard! */ /* - * Values for CPU types + * XXX: Linux note: The below warning is apparently a relic from IRIX. + * + * WARNING: + * Certain assembly language routines (notably xxxxx.s) in the IP27PROM + * will depend on the format of the data structures in this file. In + * most cases, rearranging the fields can seriously break things. + * Adding fields in the beginning or middle can also break things. + * Add fields if necessary, to the end of a struct in such a way + * that offsets of existing fields do not change. */ -#define KL_CPU_R4000 0x1 /* Standard R4000 */ -#define KL_CPU_TFP 0x2 /* TFP processor */ -#define KL_CPU_R10000 0x3 /* R10000 (T5) */ -#define KL_CPU_NONE (-1) /* no cpu present in slot */ + + +/* XXX: Linux note: The below defines aren't used anywhere. Keep? */ +#define MAX_MODULE_ID 255 +#define SIZE_PAD 4096 /* 4k padding for structures */ +#define GB2 0x80000000 +#define MAX_RSV_PTRS 32 +#define SN0_PORT_FENCE_SHFT 0 +#define SN0_PORT_FENCE_MASK (1 << SN0_PORT_FENCE_SHFT) /* - * IP27 BOARD classes + * 1 NODE brd, 2 Router brd (1 8p, 1 meta), 6 Widgets, + * 2 Midplanes assuming no pci card cages */ +#define MAX_SLOTS_PER_NODE (1 + 2 + 6 + 2) -#define KLCLASS_MASK 0xf0 -#define KLCLASS_NONE 0x00 -#define KLCLASS_NODE 0x10 /* CPU, Memory and HUB board */ -#define KLCLASS_CPU KLCLASS_NODE -#define KLCLASS_IO 0x20 /* BaseIO, 4 ch SCSI, ethernet, FDDI - and the non-graphics widget boards */ -#define KLCLASS_ROUTER 0x30 /* Router board */ -#define KLCLASS_MIDPLANE 0x40 /* We need to treat this as a board - so that we can record error info */ -#define KLCLASS_GFX 0x50 /* graphics boards */ +/* ----------------------------------------------------------------------- */ +/* struct klc_* casting wrappers - Add more as needed */ -#define KLCLASS_PSEUDO_GFX 0x60 /* HDTV type cards that use a gfx - * hw ifc to xtalk and are not gfx - * class for sw purposes */ +/* + * Common parameter conventions for macros: + * _b: BOARD or MEMBANK + * _c: Component + * _i: struct klc_info passed by value + * _k: Refers to either K0 or K1 MIPS memory area + * _n: NASID + * _o: Offset + * _t: Type + * _x: XBOW + */ -#define KLCLASS_MAX 7 /* Bump this if a new CLASS is added */ -#define KLTYPE_MAX 10 /* Bump this if a new CLASS is added */ +#define KLCF_CAST(_t) (struct klc_##_t *) +#define KLCF_CAST_CONS(_t) (KLCF_CAST(cons)(_t)) /* klc_cons */ +#define KLCF_CAST_MALLOC(_t) (KLCF_CAST(malloc)(_t)) /* klc_malloc */ +#define KLCF_CAST_HEADER(_t) (KLCF_CAST(header)(_t)) /* klc_header */ +#define KLCF_CAST_INFO(_t) (KLCF_CAST(info)(_t)) /* klc_info */ +#define KLCF_CAST_LBOARD(_t) (KLCF_CAST(lboard)(_t)) /* klc_lboard */ +#define KLCF_CAST_ROUTER(_t) (KLCF_CAST(router)(_t)) /* klc_router */ +#define KLCF_CAST_CPU(_t) (KLCF_CAST(cpu)(_t)) /* klc_cpu */ +#define KLCF_CAST_HUB(_t) (KLCF_CAST(hub)(_t)) /* klc_hub */ +#define KLCF_CAST_MEMBANK(_t) (KLCF_CAST(membank)(_t)) /* klc_membank */ +#define KLCF_CAST_MOD_SN(_t) (KLCF_CAST(mod_sn)(_t)) /* klc_mod_sn */ +#define KLCF_CAST_XBOW(_t) (KLCF_CAST(xbow)(_t)) /* klc_xbow */ -#define KLCLASS_UNKNOWN 0xf0 -#define KLCLASS(_x) ((_x) & KLCLASS_MASK) +/* ----------------------------------------------------------------------- */ +/* struct klc_cons, struct klc_malloc, and struct klc_header */ /* - * IP27 board types - */ - -#define KLTYPE_MASK 0x0f -#define KLTYPE_NONE 0x00 -#define KLTYPE_EMPTY 0x00 - -#define KLTYPE_WEIRDCPU (KLCLASS_CPU | 0x0) -#define KLTYPE_IP27 (KLCLASS_CPU | 0x1) /* 2 CPUs(R10K) per board */ - -#define KLTYPE_WEIRDIO (KLCLASS_IO | 0x0) -#define KLTYPE_BASEIO (KLCLASS_IO | 0x1) /* IOC3, SuperIO, Bridge, SCSI */ -#define KLTYPE_IO6 KLTYPE_BASEIO /* Additional name */ -#define KLTYPE_4CHSCSI (KLCLASS_IO | 0x2) -#define KLTYPE_MSCSI KLTYPE_4CHSCSI /* Additional name */ -#define KLTYPE_ETHERNET (KLCLASS_IO | 0x3) -#define KLTYPE_MENET KLTYPE_ETHERNET /* Additional name */ -#define KLTYPE_FDDI (KLCLASS_IO | 0x4) -#define KLTYPE_UNUSED (KLCLASS_IO | 0x5) /* XXX UNUSED */ -#define KLTYPE_HAROLD (KLCLASS_IO | 0x6) /* PCI SHOE BOX */ -#define KLTYPE_PCI KLTYPE_HAROLD -#define KLTYPE_VME (KLCLASS_IO | 0x7) /* Any 3rd party VME card */ -#define KLTYPE_MIO (KLCLASS_IO | 0x8) -#define KLTYPE_FC (KLCLASS_IO | 0x9) -#define KLTYPE_LINC (KLCLASS_IO | 0xA) -#define KLTYPE_TPU (KLCLASS_IO | 0xB) /* Tensor Processing Unit */ -#define KLTYPE_GSN_A (KLCLASS_IO | 0xC) /* Main GSN board */ -#define KLTYPE_GSN_B (KLCLASS_IO | 0xD) /* Auxiliary GSN board */ - -#define KLTYPE_GFX (KLCLASS_GFX | 0x0) /* unknown graphics type */ -#define KLTYPE_GFX_KONA (KLCLASS_GFX | 0x1) /* KONA graphics on IP27 */ -#define KLTYPE_GFX_MGRA (KLCLASS_GFX | 0x3) /* MGRAS graphics on IP27 */ - -#define KLTYPE_WEIRDROUTER (KLCLASS_ROUTER | 0x0) -#define KLTYPE_ROUTER (KLCLASS_ROUTER | 0x1) -#define KLTYPE_ROUTER2 KLTYPE_ROUTER /* Obsolete! */ -#define KLTYPE_NULL_ROUTER (KLCLASS_ROUTER | 0x2) -#define KLTYPE_META_ROUTER (KLCLASS_ROUTER | 0x3) - -#define KLTYPE_WEIRDMIDPLANE (KLCLASS_MIDPLANE | 0x0) -#define KLTYPE_MIDPLANE8 (KLCLASS_MIDPLANE | 0x1) /* 8 slot backplane */ -#define KLTYPE_MIDPLANE KLTYPE_MIDPLANE8 -#define KLTYPE_PBRICK_XBOW (KLCLASS_MIDPLANE | 0x2) - -#define KLTYPE_IOBRICK (KLCLASS_IOBRICK | 0x0) -#define KLTYPE_IBRICK (KLCLASS_IOBRICK | 0x1) -#define KLTYPE_PBRICK (KLCLASS_IOBRICK | 0x2) -#define KLTYPE_XBRICK (KLCLASS_IOBRICK | 0x3) + * The numbers must be contiguous since the array index i is used in the code + * to allocate the various areas. + */ +#define BOARD_STRUCT 0 +#define COMPONENT_STRUCT 1 +#define ERRINFO_STRUCT 2 +#define KLMALLOC_TYPE_MAX (ERRINFO_STRUCT + 1) +#define DEVICE_STRUCT 3 -#define KLTYPE_PBRICK_BRIDGE KLTYPE_PBRICK +/** + * struct klc_cons - KLCONFIG main console + * @uart_base: base addr of UART + * @config_base: base addr of UART config + * @memory_base: base addr of UART mem + * @baud: Baud rate + * @flag: UART flags + * @type: UART type + * @nasid: NASID of node + * @wid: Widget ID + * @npci: ? + * @baseio_nic: BaseIO Number + */ +struct klc_cons { + unsigned long uart_base; + unsigned long config_base; + unsigned long memory_base; + s16 baud; + s16 flag; + int type; + nasid_t nasid; + s8 wid; + s8 npci; + u64 baseio_nic; +}; + +/** + * struct klc_malloc - KLCONFIG main console + * @base: ? + * @limit: ? + * @curr: ? + */ +struct klc_malloc { + s32 base; + s32 limit; + s32 curr; +}; + +/* KLCONFIG Header */ +#define KLCONFIG_MAGIC 0xbeedbabe + +/** + * struct klc_header - KLCONFIG main console + * @magic: set to KLCONFIG_MAGIC + * @version: STRUCTURE VERSION + * @malloc_hdr_off: offset to klc_malloc + * @cons_off: offset to klc_cons + * @board_info: beginning of linked list of boards + * @cons_info: console info as struct klc_cons + * @malloc_hdr: + * @sw_belief: confidence that software is bad + * @sn0net_belief: confidence that sn0net is bad + */ +struct klc_header { + u64 magic; + u32 version; + s32 malloc_hdr_off; + s32 cons_off; + s32 board_info; + struct klc_cons cons_info; + struct klc_malloc malloc_hdr[KLMALLOC_TYPE_MAX]; + u8 sw_belief; + u8 sn0net_belief; +}; + +/* Gets a pointer to the start of the KLCONFIG data area. */ +#define KL_CONFIG_HDR(_n) (KLCF_CAST_HEADER(KLCONFIG_ADDR(_n))) + +/* Gets a pointer to the start of the linked list of boards. */ +#define KL_CONFIG_BRD_INFO_OFF(_n) \ + (KL_CONFIG_HDR(_n)->board_info) + +/* Get the KLCONFIG magic value. */ +#define KL_CONFIG_MAGIC(_n) (KL_CONFIG_HDR(_n)->magic) + +/* Check the KLCONFIG magic value against KLCFGINFO_MAGIC. */ +#define KL_CONFIG_CHECK_MAGIC(_n) \ + (KL_CONFIG_MAGIC(_n) == KLCFGINFO_MAGIC) + +/* Initialize the KLCONFIG magic value. */ +#define KL_CONFIG_HDR_INIT_MAGIC(_n) \ + (KL_CONFIG_MAGIC(_n) = KLCFGINFO_MAGIC) + +/* Pointer macro to struct klc_header->cons_info */ +#define PTR_CONS_INFO(_k) \ + (KLCF_CAST_CONS((unsigned long)_k + (_k->cons_off))) + +/* Returns struct klc_cons from struct klc_header->cons_info */ +#define KL_CONFIG_CONS_INFO(_n) \ + PTR_CONS_INFO(KL_CONFIG_HDR(_n)) + +/* Pointer macro to struct klc_header->malloc_hdr_off */ +#define PTR_MALLOC_HDR(_k) \ + (KLCF_CAST_MALLOC((unsigned long)_k + (_k->malloc_hdr_off))) + +/* Returns struct klc_malloc from struct klc_header->malloc_hdr_off */ +#define KL_CONFIG_MALLOC_HDR(_n) \ + PTR_MALLOC_HDR(KL_CONFIG_HDR(_n)) + +/* Points at the first struct klc_info area (?) */ +#define KL_CONFIG_INFO_START(_n) \ + (s32)(KLCONFIG_OFFSET(_n) + sizeof(struct klc_header)) + + +/* ----------------------------------------------------------------------- */ +/* struct klc_info */ + +/** + * struct klc_info - stores common info about a component + * @struct_type: type of this structure + * @struct_version: ver of this structure + * @flags: enabled/disabled state, etc + * @revision: component revision + * @diag_val: diagnostic value + * @diag_parm: diagnostic param + * @inventory: prev inventory status + * @nic: must be aligned properly + * @physid: physical id of component + * @virtid: virtual id as seen by system + * @widid: widget id (if applicable) + * @nasid: node number (from parent) + * @_pad0: padding + * @arcs_compt: ptr to the ARCS struct for ease + * @errinfo: component specific errors + * @_pad1: padding + */ +struct klc_info { + u8 struct_type; + u8 struct_version; + u8 flags; + u8 revision; + u16 diag_val; + u16 diag_parm; + u8 inventory; + u64 nic; + u8 physid; + u32 virtid; + u8 widid; + nasid_t nasid; + u16 _pad0; + COMPONENT *arcs_compt; + s32 errinfo; + u32 _pad1; +}; + +/* struct klc_info->flags definitions */ +#define KLINFO_ENABLE 0x01 /* Component is enabled */ +#define KLINFO_FAILED 0x02 /* Component failed */ +#define KLINFO_DEVICE 0x04 /* Component is a device */ +#define KLINFO_VISITED 0x08 /* Component has been visited */ +#define KLINFO_CONTROLLER 0x10 /* Component is a device controller */ +#define KLINFO_INSTALL 0x20 /* Install a driver */ +#define KLINFO_HEADLESS 0x40 /* Headless (or hubless) component */ -/* The value of type should be more than 8 so that hinv prints - * out the board name from the NIC string. For values less than - * 8 the name of the board needs to be hard coded in a few places. - * When bringup started nic names had not standardized and so we - * had to hard code. (For people interested in history.) +#define IS_CONSOLE_IOC3(_i) ((KLCF_CAST_INFO(_i)->flags) & KLINFO_INSTALL) + +/* Wrapper to get the NUMA-as-node-ID from a board */ +#define KLCF_BOARD_NASID(_b) ((_b)->nasid) + +/* Wrapper to get the next board in the linked list */ +#define KLCF_BOARD_NEXT(_b) ((_b)->next) + +/* Wrapper to check the board flags for a duplicate board */ +#define KL_CONFIG_DUPLICATE_BOARD(_b) \ + ((_b)->flags & DUPLICATE_BOARD) + +/* Test whether a board is local or remote */ +#define KLCF_REMOTE(_b) (((_b)->struct_type & KLBOARD_LOCAL) ? 0 : 1) + +/* Test if a board is enabled - pass by value, not reference */ +#define KLCF_INFO_ENABLED(_i) ((_i).flags & KLINFO_ENABLE) + +/* ----------------------------------------------------------------------- */ +/* struct klc_lboard */ + +#define MAX_COMPONENTS 24 /* Max components per board */ +#define KLBOARD_LOCAL 0x1 /* Board is local to node */ +#define KLBOARD_REMOTE 0x2 /* Board is on another node */ + +/** + * struct klc_info - stores info about a local BOARD + * @next: next BOARD + * @struct_type: type of struct, local or remote + * @type: board type + class + * @struct_ver: structure version + * @rev: board revision + * @prom_ver: board prom version, if any + * @flags: board flags + * @slot: board slot num + * @debug_switch: debug switches + * @module: module to which board belongs + * @partition: partition number + * @diag_val: diag value + * @diag_parm: diag param + * @inventory: inventory history + * @num_components: num of components + * @nic: Number-in-a-Can (NIC) + * @nasid: NUMA-node-AS-ID + * @components: board components + * @err_info: board's error information + * @parent: logical parent for this board + * @graph_link: vertex handle for external components + * @confidence: belief that board is bad + * @owner: who owns this board + * @nic_flags: to handle 8 more NICs + * @name: static string for board name */ -#define KLTYPE_XTHD (KLCLASS_PSEUDO_GFX | 0x9) +struct klc_lboard { + s32 next; + u8 struct_type; + u8 type; + u8 struct_ver; + u8 rev; + u8 prom_ver; + u8 flags; + u8 slot; + u16 debug_switch; + moduleid_t module; + partid_t partition; + u16 diag_val; + u16 diag_parm; + u8 inventory; + u8 num_components; + u64 nic; + nasid_t nasid; + s32 components[MAX_COMPONENTS]; + s32 err_info; + struct klc_lboard *parent; + dev_t graph_link; + u8 confidence; + nasid_t owner; + u8 nic_flags; + s8 name[32]; +}; -#define KLTYPE_UNKNOWN (KLCLASS_UNKNOWN | 0xf) +/* + * struct klc_lboard->flags fields + * + * All bits in this field are currently used. Try the __padX fields if + * additional flag bits are needed + */ +#define ENABLE_BOARD 0x01 +#define FAILED_BOARD 0x02 +#define DUPLICATE_BOARD 0x04 /* Boards like midplanes/routers which + are discovered twice. Use only 1 */ +#define VISITED_BOARD 0x08 /* Used for compact hub numbering. */ +#define LOCAL_MASTER_IO6 0x10 /* Master IO6 for that node */ +#define GLOBAL_MASTER_IO6 0x20 /* Global IO6 for all nodes */ +#define THIRD_NIC_PRESENT 0x40 /* For the future (?) */ +#define SECOND_NIC_PRESENT 0x80 /* Add-ons like MIO are present */ + +/* These are the indices of various components within a lboard structure */ +#define IP27_CPU0_INDEX 0 +#define IP27_CPU1_INDEX 1 +#define IP27_HUB_INDEX 2 +#define IP27_MEM_INDEX 3 +#define BASEIO_BRIDGE_INDEX 0 +#define BASEIO_IOC3_INDEX 1 +#define BASEIO_SCSI0_INDEX 2 +#define BASEIO_SCSI1_INDEX 3 +#define MIDPLANE_XBOW_INDEX 0 +#define ROUTER_COMPONENT_INDEX 0 +#define CH4SCSI_BRIDGE_INDEX 0 + +/* Gets the board info from the specified node. */ +#define KL_CONFIG_INFO(_n) \ + (KLCF_CAST_LBOARD(KL_CONFIG_BRD_INFO_OFF(_n) ? \ + NODE_OFFSET_TO_K1((_n), KL_CONFIG_BRD_INFO_OFF(_n)) : 0)) + +/* Get board information */ +#define KLCF_SLOT(_b) ((_b)->slot) +#define KLCF_CLASS(_b) KLCLASS((_b)->type) +#define KLCF_TYPE(_b) KLTYPE((_b)->type) +#define KLCF_NUM_COMPS(_b) ((_b)->num_components) /* # of components */ +#define KLCF_MODULE_ID(_b) ((_b)->module) /* Module ID */ + + +/* ----------------------------------------------------------------------- */ +/* Various BOARD definition values */ + +/* Values for CPU types */ +#define KL_CPU_R4000 0x1 /* Standard R4000 */ +#define KL_CPU_TFP 0x2 /* R8000 (TFP) */ +#define KL_CPU_R10000 0x3 /* R10000 (T5) */ +#define KL_CPU_NONE (-1) /* No cpu present in slot */ + +/* IP27 BOARD Classes */ +#define KLCLASS_MASK 0xf0 +#define KLCLASS_UNKNOWN 0xf0 /* XXX: Same as KLCLASS_MASK */ +#define KLCLASS_NONE 0x00 +#define KLCLASS_NODE 0x10 /* CPU/Mem/HUB nodeboard */ +#define KLCLASS_CPU KLCLASS_NODE +#define KLCLASS_IO 0x20 /* BaseIO, 4ch SCSI, Eth, FDDI, + * & the non-graphics widget + * boards + */ +#define KLCLASS_ROUTER 0x30 /* Router board */ +#define KLCLASS_MIDPLANE 0x40 /* We need to treat this as a + * board so that we can record + * error info + */ +#define KLCLASS_GFX 0x50 /* Gfx boards (kona, mgras) */ +#define KLCLASS_PSEUDO_GFX 0x60 /* HDTV type cards that use a + * gfx hw interface to xtalk + * and are not gfx class for + * software purposes. + */ +/* Bump both of these if a new CLASS is added */ +#define KLCLASS_MAX 7 +#define KLTYPE_MAX 10 + +/* Given struct klc_lboard->type, returns the BOARD's class */ +#define KLCLASS(_x) ((_x) & KLCLASS_MASK) + + +/* IP27 BOARD Types */ +#define KLTYPE_MASK 0x0f +#define KLTYPE_NONE 0x00 +#define KLTYPE_EMPTY 0x00 +#define KLTYPE_UNKNOWN (KLCLASS_UNKNOWN | 0xf) +/* CPU */ +#define KLTYPE_WEIRDCPU (KLCLASS_CPU | 0x0) /* Unknown CPU */ +#define KLTYPE_IP27 (KLCLASS_CPU | 0x1) /* 2 CPUs/nodeboard */ +/* I/O */ +#define KLTYPE_WEIRDIO (KLCLASS_IO | 0x0) +#define KLTYPE_BASEIO (KLCLASS_IO | 0x1) /* IOC3/BRIDGE/SCSI */ +#define KLTYPE_IO6 KLTYPE_BASEIO +#define KLTYPE_4CHSCSI (KLCLASS_IO | 0x2) /* Quad SCSI Xtalk */ +#define KLTYPE_MSCSI KLTYPE_4CHSCSI +#define KLTYPE_MENET (KLCLASS_IO | 0x3) /* IOC3 Ethernet */ +#define KLTYPE_ETHERNET KLTYPE_MENET +#define KLTYPE_FDDI (KLCLASS_IO | 0x4) /* FDDI Xtalk */ +#define KLTYPE_UNUSED (KLCLASS_IO | 0x5) /* XXX: Unused */ +#define KLTYPE_PCIBOX (KLCLASS_IO | 0x6) /* PCI Shoebox */ +#define KLTYPE_HAROLD KLTYPE_PCIBOX +#define KLTYPE_VME (KLCLASS_IO | 0x7) /* VME cards */ +#define KLTYPE_MIO (KLCLASS_IO | 0x8) /* XXX: Unknown */ +#define KLTYPE_FC (KLCLASS_IO | 0x9) /* FibreChannel */ +#define KLTYPE_LINC (KLCLASS_IO | 0xa) /* LINC (HIPPI/ATM) */ +#define KLTYPE_TPU (KLCLASS_IO | 0xb) /* Tensor Processor */ +#define KLTYPE_GSN_A (KLCLASS_IO | 0xc) /* Main GSN board */ +#define KLTYPE_GSN_B (KLCLASS_IO | 0xd) /* Aux GSN board */ +/* GFX */ +#define KLTYPE_GFX (KLCLASS_GFX | 0x0) /* Unknown Gfx type */ +#define KLTYPE_GFX_KONA (KLCLASS_GFX | 0x1) /* InfiniteReality */ +#define KLTYPE_GFX_MGRA (KLCLASS_GFX | 0x3) /* MGRAS/Impact Gfx */ +#define KLTYPE_HDTV (KLCLASS_PSEUDO_GFX | 0x9) /* HDTV board */ +/* Routers */ +#define KLTYPE_WEIRDROUTER (KLCLASS_ROUTER | 0x0) /* Unknown router */ +#define KLTYPE_ROUTER (KLCLASS_ROUTER | 0x1) /* Std router */ +#define KLTYPE_NULL_ROUTER (KLCLASS_ROUTER | 0x2) /* Null Router */ +#define KLTYPE_META_ROUTER (KLCLASS_ROUTER | 0x3) /* Metarouter */ +/* Midplanes */ +#define KLTYPE_WEIRDMIDPLANE (KLCLASS_MIDPLANE | 0x0)/* Unknown Midplane */ +#define KLTYPE_MIDPLANE (KLCLASS_MIDPLANE | 0x1)/* 8 slot backplane */ +#define KLTYPE_PBRICK_XBOW (KLCLASS_MIDPLANE | 0x2)/* IP35 P-BRICK Xbow */ +/* IP35 BRICKs */ +#define KLTYPE_IOBRICK (KLCLASS_IOBRICK | 0x0) /* IP35 Basic I/O */ +#define KLTYPE_IBRICK (KLCLASS_IOBRICK | 0x1) +#define KLTYPE_PBRICK (KLCLASS_IOBRICK | 0x2) /* IP35 PCI */ +#define KLTYPE_XBRICK (KLCLASS_IOBRICK | 0x3) /* IP35 XIO */ +#define KLTYPE_PBRICK_BRIDGE KLTYPE_PBRICK -#define KLTYPE(_x) ((_x) & KLTYPE_MASK) -#define IS_MIO_PRESENT(l) ((l->brd_type == KLTYPE_BASEIO) && \ - (l->brd_flags & SECOND_NIC_PRESENT)) -#define IS_MIO_IOC3(l, n) (IS_MIO_PRESENT(l) && (n > 2)) +/* Given struct klc_lboard->type, returns the BOARD's type */ +#define KLTYPE(_t) ((_t) & KLTYPE_MASK) /* - * board structures - */ - -#define MAX_COMPTS_PER_BRD 24 - -#define LOCAL_BOARD 1 -#define REMOTE_BOARD 2 - -#define LBOARD_STRUCT_VERSION 2 - -typedef struct lboard_s { - klconf_off_t brd_next; /* Next BOARD */ - unsigned char struct_type; /* type of structure, local or remote */ - unsigned char brd_type; /* type+class */ - unsigned char brd_sversion; /* version of this structure */ - unsigned char brd_brevision; /* board revision */ - unsigned char brd_promver; /* board prom version, if any */ - unsigned char brd_flags; /* Enabled, Disabled etc */ - unsigned char brd_slot; /* slot number */ - unsigned short brd_debugsw; /* Debug switches */ - moduleid_t brd_module; /* module to which it belongs */ - partid_t brd_partition; /* Partition number */ - unsigned short brd_diagval; /* diagnostic value */ - unsigned short brd_diagparm; /* diagnostic parameter */ - unsigned char brd_inventory; /* inventory history */ - unsigned char brd_numcompts; /* Number of components */ - nic_t brd_nic; /* Number in CAN */ - nasid_t brd_nasid; /* passed parameter */ - klconf_off_t brd_compts[MAX_COMPTS_PER_BRD]; /* pointers to COMPONENTS */ - klconf_off_t brd_errinfo; /* Board's error information */ - struct lboard_s *brd_parent; /* Logical parent for this brd */ - vertex_hdl_t brd_graph_link; /* vertex hdl to connect extern compts */ - confidence_t brd_confidence; /* confidence that the board is bad */ - nasid_t brd_owner; /* who owns this board */ - unsigned char brd_nic_flags; /* To handle 8 more NICs */ - char brd_name[32]; -} lboard_t; + * Linux note: The below is apocryphal information. No idea where it belongs. + * + * The value of type should be more than 8 so that hinv prints out the board + * name from the NIC string. For values less than 8 the name of the board + * needs to be hard coded in a few places. When bringup started NIC names + * had not been standardized and so we had to hard code. (For people + * interested in history.) + */ + +/* ----------------------------------------------------------------------- */ +/* Various Component definitions */ /* - * Make sure we pass back the calias space address for local boards. - * klconfig board traversal and error structure extraction defines. + * Following are the currently identified components: + * - CPU, HUB, MEM_BANK, + * - XBOW (consists of 16 WIDGETs, each of which can be HUB/GFX/BRIDGE), + * - BRIDGE, IOC3, SuperIO, SCSI, FDDI, + * - ROUTER, + * - GRAPHICS, */ +#define KLSTRUCT_UNKNOWN 0 +#define KLSTRUCT_CPU 1 +#define KLSTRUCT_HUB 2 +#define KLSTRUCT_MEMBNK 3 +#define KLSTRUCT_XBOW 4 +#define KLSTRUCT_BRI 5 +#define KLSTRUCT_IOC3 6 +#define KLSTRUCT_PCI 7 +#define KLSTRUCT_VME 8 +#define KLSTRUCT_ROU 9 +#define KLSTRUCT_GFX 10 +#define KLSTRUCT_SCSI 11 +#define KLSTRUCT_FDDI 12 +#define KLSTRUCT_MIO 13 +#define KLSTRUCT_DISK 14 +#define KLSTRUCT_TAPE 15 +#define KLSTRUCT_CDROM 16 +#define KLSTRUCT_HUB_UART 17 +#define KLSTRUCT_IOC3ENET 18 +#define KLSTRUCT_IOC3UART 19 +#define KLSTRUCT_UNUSED 20 /* XXX: UNUSED */ +#define KLSTRUCT_IOC3PCKM 21 +#define KLSTRUCT_RAD 22 +#define KLSTRUCT_HUB_TTY 23 +#define KLSTRUCT_IOC3_TTY 24 -#define BOARD_SLOT(_brd) ((_brd)->brd_slot) +/* + * Linux note: The below likely refers to something IRIX-specific. + * + * Early access IO proms are compatible only with KLSTRUCT values up to 24. + */ +#define KLSTRUCT_FIBERCHANNEL 25 +#define KLSTRUCT_MOD_SERIAL_NUM 26 +#define KLSTRUCT_IOC3MS 27 +#define KLSTRUCT_TPU 28 +#define KLSTRUCT_GSN_A 29 +#define KLSTRUCT_GSN_B 30 +#define KLSTRUCT_HDTV 31 -#define KLCF_CLASS(_brd) KLCLASS((_brd)->brd_type) -#define KLCF_TYPE(_brd) KLTYPE((_brd)->brd_type) -#define KLCF_REMOTE(_brd) (((_brd)->struct_type & LOCAL_BOARD) ? 0 : 1) -#define KLCF_NUM_COMPS(_brd) ((_brd)->brd_numcompts) -#define KLCF_MODULE_ID(_brd) ((_brd)->brd_module) -#define KLCF_NEXT(_brd) \ - ((_brd)->brd_next ? \ - (lboard_t *)(NODE_OFFSET_TO_K1(NASID_GET(_brd), (_brd)->brd_next)):\ - NULL) -#define KLCF_COMP(_brd, _ndx) \ - (klinfo_t *)(NODE_OFFSET_TO_K1(NASID_GET(_brd), \ - (_brd)->brd_compts[(_ndx)])) +/* ----------------------------------------------------------------------- */ +/* Component struct definitions */ -#define KLCF_COMP_ERROR(_brd, _comp) \ - (NODE_OFFSET_TO_K1(NASID_GET(_brd), (_comp)->errinfo)) +/* + * Linux note: The below applies to struct klc_port. + * + * The port info in ip27_cfg area translates to a struct klc_lboard in the + * KLCONFIG area. But since KLCONFIG does not use pointers, struct klc_lboard + * is stored in terms of a nasid and a offset from start of KLCONFIG area on + * that nasid. + */ -#define KLCF_COMP_TYPE(_comp) ((_comp)->struct_type) -#define KLCF_BRIDGE_W_ID(_comp) ((_comp)->physid) /* Widget ID */ +/** + * struct klc_port - stores info about a port on HUB or XBOW + * @nasid: NUMA-node-AS-ID + * @flag: port flags + * @offset: port offset + */ +struct klc_port { + nasid_t nasid; + u8 flag; + s32 offset; +}; + + +/** + * struct klc_cpu - stores info about a CPU + * @kl_info: common info + * @prid: processor PRID value + * @fpirr: FPU IRR value + * @speed: speed in MHZ + * @scache_sz: L2 size in MB + * @scache_spd: L2 speed in MHz + */ +struct klc_cpu { + struct klc_info kl_info; + u16 prid; + u16 fpirr; + u16 speed; + u16 scache_sz; + u16 scache_spd; +}; + + +/** + * struct klc_hub - stores info about a HUB chip on a nodeboard + * @kl_info: common info + * @flags: PCFG_HUB_xxx flags + * @port: XBOW port that HUB is connected to + * @box_nic: ? + * @mfg_nic: mfgr NIC string + * @speed: speed of HUB in HZ + */ +struct klc_hub { + struct klc_info kl_info; + u32 flags; + struct klc_port port; + u64 box_nic; + s32 mfg_nic; + u64 speed; +}; + + +/** + * struct klc_hub_uart - stores info about a UART chip attached to a HUB + * @kl_info: common info + * @flags: PCFG_HUB_xxx flags + * @box_nic: ? + */ +struct klc_hub_uart { + struct klc_info kl_info; + u32 flags; + u64 box_nic; +}; + + +/** + * struct klc_membank - stores info about a memory bank + * @kl_info: common info + * @mem_sz: total memory in MB + * @dimm_select: bank to physaddr mapping + * @bank_sz: memory bank sizes + * @attr: bank attributes + */ +struct klc_membank { + struct klc_info kl_info; + s16 mem_sz; + s16 dimm_select; + s16 bank_sz[MD_MEM_BANKS]; + s16 attr; +}; + +/* Get the size of a memory bank. */ +#define KLCF_MEMBANK_SIZE(_i, _b) \ + ((_i)->bank_sz[(_b)]) + +/* Check if a memory bank has premium DIMMs (directory memory). */ +#define MEMBANK_PREM 1 +#define KLCONFIG_MEMBANK_PREM(_i, _b) \ + ((_i)->attr & (MEMBANK_PREM << (_b))) + + +#define MAX_SERIAL_NUM_SIZE 10 +/** + * struct klc_mod_sn - stores info about a module serial + * @kl_info: common info + * @sn: union sn: read S/N as either string or integer + * @str: read S/N as str + * @num: read S/N as integer + */ +struct klc_mod_sn { + struct klc_info kl_info; + union { + s8 str[MAX_SERIAL_NUM_SIZE]; + u64 num; + } sn; +}; +/* + * Hard coded values are necessary since we cannot treat the serial number + * as a component without losing compatibility between PROM versions. + */ +#define GET_COMP_SERIAL(_c) \ + (KLCF_CAST_MOD_SN(KLCF_COMP(_c, _c->num_components))) -/* - * Generic info structure. This stores common info about a - * component. - */ - -typedef struct klinfo_s { /* Generic info */ - unsigned char struct_type; /* type of this structure */ - unsigned char struct_version; /* version of this structure */ - unsigned char flags; /* Enabled, disabled etc */ - unsigned char revision; /* component revision */ - unsigned short diagval; /* result of diagnostics */ - unsigned short diagparm; /* diagnostic parameter */ - unsigned char inventory; /* previous inventory status */ - nic_t nic; /* MUst be aligned properly */ - unsigned char physid; /* physical id of component */ - unsigned int virtid; /* virtual id as seen by system */ - unsigned char widid; /* Widget id - if applicable */ - nasid_t nasid; /* node number - from parent */ - char pad1; /* pad out structure. */ - char pad2; /* pad out structure. */ - COMPONENT *arcs_compt; /* ptr to the arcs struct for ease*/ - klconf_off_t errinfo; /* component specific errors */ - unsigned short pad3; /* pci fields have moved over to */ - unsigned short pad4; /* klbri_t */ -} klinfo_t ; - -#define KLCONFIG_INFO_ENABLED(_i) ((_i)->flags & KLINFO_ENABLE) -/* - * Component structures. - * Following are the currently identified components: - * CPU, HUB, MEM_BANK, - * XBOW(consists of 16 WIDGETs, each of which can be HUB or GRAPHICS or BRIDGE) - * BRIDGE, IOC3, SuperIO, SCSI, FDDI - * ROUTER - * GRAPHICS - */ -#define KLSTRUCT_UNKNOWN 0 -#define KLSTRUCT_CPU 1 -#define KLSTRUCT_HUB 2 -#define KLSTRUCT_MEMBNK 3 -#define KLSTRUCT_XBOW 4 -#define KLSTRUCT_BRI 5 -#define KLSTRUCT_IOC3 6 -#define KLSTRUCT_PCI 7 -#define KLSTRUCT_VME 8 -#define KLSTRUCT_ROU 9 -#define KLSTRUCT_GFX 10 -#define KLSTRUCT_SCSI 11 -#define KLSTRUCT_FDDI 12 -#define KLSTRUCT_MIO 13 -#define KLSTRUCT_DISK 14 -#define KLSTRUCT_TAPE 15 -#define KLSTRUCT_CDROM 16 -#define KLSTRUCT_HUB_UART 17 -#define KLSTRUCT_IOC3ENET 18 -#define KLSTRUCT_IOC3UART 19 -#define KLSTRUCT_UNUSED 20 /* XXX UNUSED */ -#define KLSTRUCT_IOC3PCKM 21 -#define KLSTRUCT_RAD 22 -#define KLSTRUCT_HUB_TTY 23 -#define KLSTRUCT_IOC3_TTY 24 - -/* Early Access IO proms are compatible - only with KLSTRUCT values up to 24. */ - -#define KLSTRUCT_FIBERCHANNEL 25 -#define KLSTRUCT_MOD_SERIAL_NUM 26 -#define KLSTRUCT_IOC3MS 27 -#define KLSTRUCT_TPU 28 -#define KLSTRUCT_GSN_A 29 -#define KLSTRUCT_GSN_B 30 -#define KLSTRUCT_XTHD 31 +#define MAX_XBOW_LINKS 16 +#define XBOW_PORT_IO 0x1 +#define XBOW_PORT_HUB 0x2 +#define XBOW_PORT_ENABLE 0x4 -/* - * These are the indices of various components within a lboard structure. +/** + * struct klc_xbow - stores info about a XBOW chip + * @kl_info: common info + * @port_info: represents each XBOW port as struct klc_port + * @master_hub_link: holds numeric value of which XBOW port HUB is connected */ +struct klc_xbow { + struct klc_info kl_info; + struct klc_port port_info[MAX_XBOW_LINKS]; + int master_hub_link; + /* type of brd connected + component struct ptr+flags */ +}; -#define IP27_CPU0_INDEX 0 -#define IP27_CPU1_INDEX 1 -#define IP27_HUB_INDEX 2 -#define IP27_MEM_INDEX 3 +/* Get struct klc_xbow->port_info[offset] */ +#define XBOW_PORT_INFO(_x, _o) \ + ((_x)->port_info[(_o) - BASE_XBOW_PORT]) -#define BASEIO_BRIDGE_INDEX 0 -#define BASEIO_IOC3_INDEX 1 -#define BASEIO_SCSI1_INDEX 2 -#define BASEIO_SCSI2_INDEX 3 +/* Get struct klc_xbow->port_info[offset].flag */ +#define XBOW_PORT_FLAG(_x, _o) \ + XBOW_PORT_INFO(_x, _o).flag -#define MIDPLANE_XBOW_INDEX 0 -#define ROUTER_COMPONENT_INDEX 0 +/* Check if port flag indicates a HUB is attached */ +#define XBOW_PORT_TYPE_HUB(_x, _o) \ + (XBOW_PORT_FLAG(_x, _o) & XBOW_PORT_HUB) -#define CH4SCSI_BRIDGE_INDEX 0 +/* Check if port flag indicates an I/O device is attached */ +#define XBOW_PORT_TYPE_IO(_x, _o) \ + (XBOW_PORT_FLAG(_x, _o) & XBOW_PORT_IO) -/* Info holders for various hardware components */ +/* Check if port is enabled */ +#define XBOW_PORT_IS_ENABLED(_x, _o) \ + (XBOW_PORT_FLAG(_x, _o) & XBOW_PORT_ENABLE) -typedef u64 *pci_t; -typedef u64 *vmeb_t; -typedef u64 *vmed_t; -typedef u64 *fddi_t; -typedef u64 *scsi_t; -typedef u64 *mio_t; -typedef u64 *graphics_t; -typedef u64 *router_t; +/* Get port NASID */ +#define XBOW_PORT_NASID(_x, _o) \ + (XBOW_PORT_INFO(_x, _o).nasid) + + +#define MAX_PCI_DEVS 8 +/** + * struct klc_pdev - stores info about a PCI device + * @dev_id: 32-bits vendor/device ID + * @__pad: 32-bits padding + */ +struct klc_pdev { + u32 dev_id; + u32 __pad; +}; + +/** + * struct klc_pcibr - stores info about a PCI [X]BRIDGE + * @kl_info: common info + * @io6prom_info: IO6prom connected to bridge + * @bustype: PCI/VME BUS bridge/GIO + * @specific: PCI Board config info + * @devices: PCI IDs + * @mfg_nic: BRIDGE MFG NIC + */ +struct klc_pcibr { + struct klc_info kl_info; + u8 io6prom_info; + u8 bustype; + u64 *specific; + struct klc_pdev devices[MAX_PCI_DEVS]; + s32 mfg_nic; +}; + +#define MAX_IOC3_TTY 2 +/** + * struct klc_ioc3 - stores info about an IOC3 device + * @kl_info: common info + * @ssram: Info about SSRAM + * @nvram: Info about NVRAM + * @kl_sio_info: struct klc_info for SuperIO device + * @tty_off: offset to tty info (?) + * @kl_eth_info: struct klc_info for ethernet device + * @eth_off: offset to ethernet info (?) + * @kbd_off: offset to keyboard/mouse info (?) + */ +struct klc_ioc3 { + struct klc_info kl_info; + u8 ssram; + u8 nvram; + struct klc_info kl_sio_info; + s32 tty_off; + struct klc_info kl_eth_info; + s32 eth_off; + s32 kbd_off; +}; + +/* Get the widget ID of a bridge component. */ +#define KLCF_BRIDGE_W_ID(_c) ((_c)->physid) + + +#define MAX_VME_SLOTS 8 +/** + * struct klc_vme - stores info about a VME BRIDGE Ctlr + * @kl_info: common info + * @specific: VME-specific info + * @slots: VME slot/board info + */ +struct klc_vme { + struct klc_info kl_info; + u64 *specific; + s32 slots[MAX_VME_SLOTS]; +}; + + +#define MAX_ROUTER_PORTS 6 /* Max num of ports on a router */ +/** + * struct klc_router - stores info about a ROUTER that links nodes together + * @kl_info: common info + * @flags: PCFG_ROUTER_xxx flags + * @box_nic: NIC of the containing module + * @port: struct klc_port for each ROUTER port + * @mfg_nic: MFG NIC string + * @vector: vector from master node + */ +struct klc_router { + struct klc_info kl_info; + u32 flags; + u64 box_nic; + struct klc_port port[MAX_ROUTER_PORTS + 1]; + s32 mfg_nic; + u64 vector; +}; -/* - * The port info in ip27_cfg area translates to a lboart_t in the - * KLCONFIG area. But since KLCONFIG does not use pointers, lboart_t - * is stored in terms of a nasid and a offset from start of KLCONFIG - * area on that nasid. - */ -typedef struct klport_s { - nasid_t port_nasid; - unsigned char port_flag; - klconf_off_t port_offset; -} klport_t; - -typedef struct klcpu_s { /* CPU */ - klinfo_t cpu_info; - unsigned short cpu_prid; /* Processor PRID value */ - unsigned short cpu_fpirr; /* FPU IRR value */ - unsigned short cpu_speed; /* Speed in MHZ */ - unsigned short cpu_scachesz; /* secondary cache size in MB */ - unsigned short cpu_scachespeed;/* secondary cache speed in MHz */ -} klcpu_t ; - -#define CPU_STRUCT_VERSION 2 - -typedef struct klhub_s { /* HUB */ - klinfo_t hub_info; - unsigned int hub_flags; /* PCFG_HUB_xxx flags */ - klport_t hub_port; /* hub is connected to this */ - nic_t hub_box_nic; /* nic of containing box */ - klconf_off_t hub_mfg_nic; /* MFG NIC string */ - u64 hub_speed; /* Speed of hub in HZ */ -} klhub_t ; - -typedef struct klhub_uart_s { /* HUB */ - klinfo_t hubuart_info; - unsigned int hubuart_flags; /* PCFG_HUB_xxx flags */ - nic_t hubuart_box_nic; /* nic of containing box */ -} klhub_uart_t ; - -#define MEMORY_STRUCT_VERSION 2 - -typedef struct klmembnk_s { /* MEMORY BANK */ - klinfo_t membnk_info; - short membnk_memsz; /* Total memory in megabytes */ - short membnk_dimm_select; /* bank to physical addr mapping*/ - short membnk_bnksz[MD_MEM_BANKS]; /* Memory bank sizes */ - short membnk_attr; -} klmembnk_t ; - -#define KLCONFIG_MEMBNK_SIZE(_info, _bank) \ - ((_info)->membnk_bnksz[(_bank)]) - - -#define MEMBNK_PREMIUM 1 -#define KLCONFIG_MEMBNK_PREMIUM(_info, _bank) \ - ((_info)->membnk_attr & (MEMBNK_PREMIUM << (_bank))) - -#define MAX_SERIAL_NUM_SIZE 10 - -typedef struct klmod_serial_num_s { - klinfo_t snum_info; - union { - char snum_str[MAX_SERIAL_NUM_SIZE]; - unsigned long long snum_int; - } snum; -} klmod_serial_num_t; - -/* Macros needed to access serial number structure in lboard_t. - Hard coded values are necessary since we cannot treat - serial number struct as a component without losing compatibility - between prom versions. */ - -#define GET_SNUM_COMP(_l) ((klmod_serial_num_t *)\ - KLCF_COMP(_l, _l->brd_numcompts)) - -#define MAX_XBOW_LINKS 16 - -typedef struct klxbow_s { /* XBOW */ - klinfo_t xbow_info ; - klport_t xbow_port_info[MAX_XBOW_LINKS] ; /* Module number */ - int xbow_master_hub_link; - /* type of brd connected+component struct ptr+flags */ -} klxbow_t ; - -#define MAX_PCI_SLOTS 8 - -typedef struct klpci_device_s { - s32 pci_device_id; /* 32 bits of vendor/device ID. */ - s32 pci_device_pad; /* 32 bits of padding. */ -} klpci_device_t; - -#define BRIDGE_STRUCT_VERSION 2 - -typedef struct klbri_s { /* BRIDGE */ - klinfo_t bri_info ; - unsigned char bri_eprominfo ; /* IO6prom connected to bridge */ - unsigned char bri_bustype ; /* PCI/VME BUS bridge/GIO */ - pci_t pci_specific ; /* PCI Board config info */ - klpci_device_t bri_devices[MAX_PCI_DEVS] ; /* PCI IDs */ - klconf_off_t bri_mfg_nic ; -} klbri_t ; - -#define MAX_IOC3_TTY 2 - -typedef struct klioc3_s { /* IOC3 */ - klinfo_t ioc3_info ; - unsigned char ioc3_ssram ; /* Info about ssram */ - unsigned char ioc3_nvram ; /* Info about nvram */ - klinfo_t ioc3_superio ; /* Info about superio */ - klconf_off_t ioc3_tty_off ; - klinfo_t ioc3_enet ; - klconf_off_t ioc3_enet_off ; - klconf_off_t ioc3_kbd_off ; -} klioc3_t ; - -#define MAX_VME_SLOTS 8 - -typedef struct klvmeb_s { /* VME BRIDGE - PCI CTLR */ - klinfo_t vmeb_info ; - vmeb_t vmeb_specific ; - klconf_off_t vmeb_brdinfo[MAX_VME_SLOTS] ; /* VME Board config info */ -} klvmeb_t ; - -typedef struct klvmed_s { /* VME DEVICE - VME BOARD */ - klinfo_t vmed_info ; - vmed_t vmed_specific ; - klconf_off_t vmed_brdinfo[MAX_VME_SLOTS] ; /* VME Board config info */ -} klvmed_t ; - -#define ROUTER_VECTOR_VERS 2 - -/* XXX - Don't we need the number of ports here?!? */ -typedef struct klrou_s { /* ROUTER */ - klinfo_t rou_info ; - unsigned int rou_flags ; /* PCFG_ROUTER_xxx flags */ - nic_t rou_box_nic ; /* nic of the containing module */ - klport_t rou_port[MAX_ROUTER_PORTS + 1] ; /* array index 1 to 6 */ - klconf_off_t rou_mfg_nic ; /* MFG NIC string */ - u64 rou_vector; /* vector from master node */ -} klrou_t ; /* - * Graphics Controller/Device + * XXX: Linux note: The below is IRIX apocrypha. * - * (IP27/IO6) Prom versions 6.13 (and 6.5.1 kernels) and earlier - * used a couple different structures to store graphics information. - * For compatibility reasons, the newer data structure preserves some - * of the layout so that fields that are used in the old versions remain - * in the same place (with the same info). Determination of what version - * of this structure we have is done by checking the cookie field. - */ -#define KLGFX_COOKIE 0x0c0de000 - -typedef struct klgfx_s { /* GRAPHICS Device */ - klinfo_t gfx_info; - klconf_off_t old_gndevs; /* for compatibility with older proms */ - klconf_off_t old_gdoff0; /* for compatibility with older proms */ - unsigned int cookie; /* for compatibility with older proms */ - unsigned int moduleslot; - struct klgfx_s *gfx_next_pipe; - graphics_t gfx_specific; - klconf_off_t pad0; /* for compatibility with older proms */ - klconf_off_t gfx_mfg_nic; -} klgfx_t; - -typedef struct klxthd_s { - klinfo_t xthd_info ; - klconf_off_t xthd_mfg_nic ; /* MFG NIC string */ -} klxthd_t ; - -typedef struct kltpu_s { /* TPU board */ - klinfo_t tpu_info ; - klconf_off_t tpu_mfg_nic ; /* MFG NIC string */ -} kltpu_t ; - -typedef struct klgsn_s { /* GSN board */ - klinfo_t gsn_info ; - klconf_off_t gsn_mfg_nic ; /* MFG NIC string */ -} klgsn_t ; + * (IP27/IO6) Prom versions 6.13 (and 6.5.1 kernels) and earlier used a + * couple different structures to store graphics information. + * For compatibility reasons, the newer data structure preserves some of + * the layout so that fields that are used in the old versions remain in + * the same place (with the same info). Determination of what version of + * this structure we have is done by checking the cookie field. + */ + +#define KLGFX_COOKIE 0x0c0de000 +/** + * struct klc_gfx - stores info about a GRAPHICS device (Kona/Mgras) + * @kl_info: common info + * @old_gndevs: compatibility w/ older PROMs + * @old_gdoff0: compatibility w/ older PROMs + * @cookie: compatibility w/ older PROMs + * @module_slot: slot of the containing module + * @next_pipe: pointer to next gfx pipe + * @specific: pointer to gfx-specific info + * @__pad: padding (compat w/ older PROMs) + * @mfg_nic: MFG NIC string + */ +struct klc_gfx { + struct klc_info kl_info; + s32 old_gndevs; + s32 old_gdoff0; + u32 cookie; + u32 module_slot; + struct klc_gfx *next_pipe; + u64 *specific; + s32 __pad; + s32 mfg_nic; +}; + +/** + * struct klc_hdtv - stores info about a pseudo-gfx device (HDTV board) + * @kl_info: common info + * @mfg_nic: MFG NIC string + */ +struct klc_hdtv { + struct klc_info kl_info; + s32 mfg_nic; +}; + + +/** + * struct klc_tpu - stores info about a tensor processing unit (rare hw) + * @kl_info: common info + * @mfg_nic: MFG NIC string + */ +struct klc_tpu { + struct klc_info kl_info; + s32 mfg_nic; +}; + +/** + * struct klc_gsn - stores info about a GSN board (?) (rare hw) + * @kl_info: common info + * @mfg_nic: MFG NIC string + */ +struct klc_gsn { + struct klc_info kl_info; + s32 mfg_nic; +}; + #define MAX_SCSI_DEVS 16 +/** + * struct klc_scsi - stores info about a SCSI controller + * @kl_info: common info + * @specific: pointer to SCSI-specific info + * @num_devs: number of attached devices + * @dev_info: per-device info + */ +struct klc_scsi { + struct klc_info kl_info; + u64 *specific; + u8 num_devs; + s32 dev_info[MAX_SCSI_DEVS]; +}; + + +#define MAX_FDDI_DEVS 10 /* XXX: Is this correct? */ +/** + * struct klc_fddi - stores info about an FDDI controller + * @kl_info: common info + * @specific: pointer to FDDI-specific info + * @dev_info: per-device info + */ +struct klc_fddi { + struct klc_info kl_info; + u64 *specific; + s32 dev_info[MAX_FDDI_DEVS]; +}; -/* - * NOTE: THis is the max sized kl* structure and is used in klmalloc.c - * to allocate space of type COMPONENT. Make sure that if the size of - * any other component struct becomes more than this, then redefine - * that as the size to be klmalloced. - */ - -typedef struct klscsi_s { /* SCSI Controller */ - klinfo_t scsi_info ; - scsi_t scsi_specific ; - unsigned char scsi_numdevs ; - klconf_off_t scsi_devinfo[MAX_SCSI_DEVS] ; -} klscsi_t ; - -typedef struct klscdev_s { /* SCSI device */ - klinfo_t scdev_info ; - struct scsidisk_data *scdev_cfg ; /* driver fills up this */ -} klscdev_t ; - -typedef struct klttydev_s { /* TTY device */ - klinfo_t ttydev_info ; - struct terminal_data *ttydev_cfg ; /* driver fills up this */ -} klttydev_t ; - -typedef struct klenetdev_s { /* ENET device */ - klinfo_t enetdev_info ; - struct net_data *enetdev_cfg ; /* driver fills up this */ -} klenetdev_t ; - -typedef struct klkbddev_s { /* KBD device */ - klinfo_t kbddev_info ; - struct keyboard_data *kbddev_cfg ; /* driver fills up this */ -} klkbddev_t ; - -typedef struct klmsdev_s { /* mouse device */ - klinfo_t msdev_info ; - void *msdev_cfg ; -} klmsdev_t ; - -#define MAX_FDDI_DEVS 10 /* XXX Is this true */ - -typedef struct klfddi_s { /* FDDI */ - klinfo_t fddi_info ; - fddi_t fddi_specific ; - klconf_off_t fddi_devinfo[MAX_FDDI_DEVS] ; -} klfddi_t ; - -typedef struct klmio_s { /* MIO */ - klinfo_t mio_info ; - mio_t mio_specific ; -} klmio_t ; - - -typedef union klcomp_s { - klcpu_t kc_cpu; - klhub_t kc_hub; - klmembnk_t kc_mem; - klxbow_t kc_xbow; - klbri_t kc_bri; - klioc3_t kc_ioc3; - klvmeb_t kc_vmeb; - klvmed_t kc_vmed; - klrou_t kc_rou; - klgfx_t kc_gfx; - klscsi_t kc_scsi; - klscdev_t kc_scsi_dev; - klfddi_t kc_fddi; - klmio_t kc_mio; - klmod_serial_num_t kc_snum ; -} klcomp_t; - -typedef union kldev_s { /* for device structure allocation */ - klscdev_t kc_scsi_dev ; - klttydev_t kc_tty_dev ; - klenetdev_t kc_enet_dev ; - klkbddev_t kc_kbd_dev ; -} kldev_t ; - -/* Data structure interface routines. TBD */ - -/* Include launch info in this file itself? TBD */ -/* - * TBD - Can the ARCS and device driver related info also be included in the - * KLCONFIG area. On the IO4PROM, prom device driver info is part of cfgnode_t - * structure, viz private to the IO4prom. +/** + * struct klc_mio - stores info about a MIO device (?) + * @kl_info: common info + * @specific: pointer to MIO-specific info + */ +struct klc_mio { + struct klc_info kl_info; + u64 *specific; +}; + +#define IS_MIO_PRESENT(_b) \ + ((_b->type == KLTYPE_BASEIO) && \ + (_b->flags & SECOND_NIC_PRESENT)) + +#define IS_MIO_IOC3(_b, _n) \ + (IS_MIO_PRESENT(_b) && ((_n) > 2)) + + +/** + * struct klc_scdev - stores info about a SCSI device + * @kl_info: common info + * @dev_cfg: void pointer to driver-specific info */ +struct klc_scdev { + struct klc_info kl_info; + void *dev_cfg; +}; + +/** + * struct klc_tty - stores info about a TTY device + * @kl_info: common info + * @dev_cfg: void pointer to driver-specific info + */ +struct klc_tty { + struct klc_info kl_info; + void *dev_cfg; +}; + +/** + * struct klc_eth - stores info about an ethernet device + * @kl_info: common info + * @dev_cfg: void pointer to driver-specific info + */ +struct klc_eth { + struct klc_info kl_info; + void *dev_cfg; +}; + +/** + * struct klc_kbd - stores info about a keyboard device + * @kl_info: common info + * @dev_cfg: void pointer to driver-specific info + */ +struct klc_kbd { + struct klc_info kl_info; + void *dev_cfg; +}; + +/** + * struct klc_mouse - stores info about a mouse device + * @kl_info: common info + * @dev_cfg: void pointer to driver-specific info + */ +struct klc_mouse { + struct klc_info kl_info; + void *dev_cfg; +}; + + +/** + * union klc_components - union to access component data + * @cpu: CPU + * @hub: HUB ASIC + * @membank: memory bank + * @xbow: XBOW ASIC + * @pcibr: PCI [X]BRIDGE + * @ioc3: IOC3 device + * @vmebr: VME BRIDGE + * @vdev: VME device + * @router: ROUTER board + * @gfx: GRAPHICS pipe + * @hdtv: pseudo-GFX device/HDTV + * @tpu: tensor processing unit + * @gsn: GSN device/board + * @scsi: SCSI controller + * @scdev: SCSI device + * @fddi: FDDI controller + * @mio: MIO device + * @serial_num: serial number + */ +union klc_components { + struct klc_cpu cpu; + struct klc_hub hub; + struct klc_membank membank; + struct klc_xbow xbow; + struct klc_pcibr pcibr; + struct klc_ioc3 ioc3; + struct klc_vme vmebr; + struct klc_vme vdev; + struct klc_router router; + struct klc_gfx gfx; + struct klc_hdtv hdtv; + struct klc_tpu tpu; + struct klc_gsn gsn; + struct klc_scsi scsi; + struct klc_scdev scdev; + struct klc_fddi fddi; + struct klc_mio mio; + struct klc_mod_sn serial_num; +}; + +/** + * union klc_components - union to access component data + * @scdev: SCSI device + * @tty: TTY device + * @eth: ethernet device + * @kbd: keyboard + * @mouse: mouse + */ +union klc_devices { + struct klc_scdev scdev; + struct klc_tty tty; + struct klc_eth eth; + struct klc_kbd kbd; + struct klc_mouse mouse; +}; + + +/* ----------------------------------------------------------------------- */ +/* Macros that assist in casting to various struct klc_* instances */ + +/* struct klc_* via KLCF_NODE_OFFSET_K(0|1) */ +#define KLCF_NODE_OFFSET(_k, _b, _o) \ + (NODE_OFFSET_TO_##_k(NASID_GET(_b), (_o))) + +/* klc_info via K1 */ +#define KLCF_INFO_K1(_b, _o) \ + (KLCF_CAST_INFO(KLCF_NODE_OFFSET(K1, (_b), (_o)))) + +/* klc_lboard via K0 */ +#define KLCF_LBOARD_K0(_b, _o) \ + (KLCF_CAST_LBOARD(KLCF_NODE_OFFSET(K0, (_b), (_o)))) + +/* klc_lboard via K1 */ +#define KLCF_LBOARD_K1(_b, _o) \ + (KLCF_CAST_LBOARD(KLCF_NODE_OFFSET(K1, (_b), (_o)))) + +/* klc_router via K0 */ +#define KLCF_ROUTER_K0(_b, _o) \ + (KLCF_CAST_ROUTER(KLCF_NODE_OFFSET(K0, (_b), (_o)))) + +/* struct klc_lboard via KL_CONFIG_INFO() */ +#define KLCF_LBOARD_INFO(_n) \ + KLCF_CAST_LBOARD(KL_CONFIG_INFO(_n)) + +/* Get a pointer to the next board. */ +#define KLCF_NEXT(_b) \ + ((_b)->next ? \ + KLCF_LBOARD_K1((_b), (_b)->next) : NULL) + +/* Get a pointer to a component on a board. */ +#define KLCF_COMP(_b, _o) \ + (KLCF_INFO_K1((_b), (_b)->components[(_o)])) + +/* Get a pointer to a component's errinfo data. */ +#define KLCF_COMP_ERROR(_b, _c) \ + (KLCF_NODE_OFFSET(K1, (_b), (_c)->errinfo)) + +/* Get the component's structure type. */ +#define KLCF_COMP_TYPE(_c) \ + ((_c)->struct_type) + + +/* ----------------------------------------------------------------------- */ +/* External function declarations */ + +extern struct klc_lboard *kl_find_lboard(struct klc_lboard *start, u8 type); +extern struct klc_info *kl_find_component(struct klc_lboard *brd, + struct klc_info *kli, u8 type); +extern struct klc_info *kl_find_1st_component(struct klc_lboard *brd, u8 type); +extern struct klc_cpu *nasid_slice_to_cpuinfo(nasid_t, int); +extern struct klc_lboard *kl_find_lboard_class(struct klc_lboard *start, + u8 brd_class); + + +/* ----------------------------------------------------------------------- */ +/* Virtual dipswitch values (starting from switch "7") */ + +#define VDS_NOGFX 0x8000 /* Don't enable gfx and autoboot */ +#define VDS_NOMP 0x0100 /* Don't start slave processors */ +#define VDS_MANUMODE 0x0080 /* Manufacturing mode */ +#define VDS_NOARB 0x0040 /* No bootmaster arbitration */ +#define VDS_PODMODE 0x0020 /* Go straight to POD mode */ +#define VDS_NO_DIAGS 0x0010 /* Don't run any diags after BM arb */ +#define VDS_DEFAULTS 0x0008 /* Use default environment values */ +#define VDS_NOMEMCLEAR 0x0004 /* Don't run mem cfg code */ +#define VDS_2ND_IO4 0x0002 /* Boot from the second IO4 */ +#define VDS_DEBUG_PROM 0x0001 /* Print PROM debugging messages */ + + +/* ----------------------------------------------------------------------- */ +/* Miscellania */ + +/* XXX: Data structure interface routines. TBD */ + +/* XXX: Include launch info in this file itself? TBD */ /* - * TBD - Allocation issues. - * - * Do we need to Mark off sepatate heaps for lboard_t, rboard_t, component, - * errinfo and allocate from them, or have a single heap and allocate all - * structures from it. Debug is easier in the former method since we can - * dump all similar structs in one command, but there will be lots of holes, - * in memory and max limits are needed for number of structures. - * Another way to make it organized, is to have a union of all components - * and allocate a aligned chunk of memory greater than the biggest - * component. + * XXX: TBD: Can the ARCS and device driver related info also be included in + * the KLCONFIG area. On the IO4PROM, prom device driver info is part of + * cfgnode_t structure, viz private to the IO4prom. */ -typedef union { - lboard_t *lbinfo ; -} biptr_t ; +/* + * XXX: TBD: Allocation issues. + * Do we need to mark off separate heaps for struct klc_lboard, + * struct klc_rboard, struct klc_components, errinfo and allocate from + * them, or have a single heap and allocate all structures from it. + * Debug is easier in the former method since we can dump all similar + * structs in one command, but there will be lots of holes, in memory + * and max limits are needed for number of structures. + * Another way to make it organized, is to have a union of all components + * and allocate an aligned chunk of memory greater than the biggest + * component. + */ +/* XXX: What is this? */ +union klc_biptr { + struct klc_lboard *lbinfo; +}; +/* XXX: these probably belong elsewhere. */ #define BRI_PER_XBOW 6 #define PCI_PER_BRI 8 #define DEV_PER_PCI 16 -/* Virtual dipswitch values (starting from switch "7"): */ - -#define VDS_NOGFX 0x8000 /* Don't enable gfx and autoboot */ -#define VDS_NOMP 0x100 /* Don't start slave processors */ -#define VDS_MANUMODE 0x80 /* Manufacturing mode */ -#define VDS_NOARB 0x40 /* No bootmaster arbitration */ -#define VDS_PODMODE 0x20 /* Go straight to POD mode */ -#define VDS_NO_DIAGS 0x10 /* Don't run any diags after BM arb */ -#define VDS_DEFAULTS 0x08 /* Use default environment values */ -#define VDS_NOMEMCLEAR 0x04 /* Don't run mem cfg code */ -#define VDS_2ND_IO4 0x02 /* Boot from the second IO4 */ -#define VDS_DEBUG_PROM 0x01 /* Print PROM debugging messages */ - -/* external declarations of Linux kernel functions. */ - -extern lboard_t *find_lboard(lboard_t *start, unsigned char type); -extern klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char type); -extern klinfo_t *find_first_component(lboard_t *brd, unsigned char type); -extern klcpu_t *nasid_slice_to_cpuinfo(nasid_t, int); -extern lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_class); - - -extern klcpu_t *sn_get_cpuinfo(cpuid_t cpu); - #endif /* _ASM_SN_KLCONFIG_H */ diff --git a/arch/mips/include/asm/sn/sn0/arch.h b/arch/mips/include/asm/sn/sn0/arch.h index 425a67e..840a44a 100644 --- a/arch/mips/include/asm/sn/sn0/arch.h +++ b/arch/mips/include/asm/sn/sn0/arch.h @@ -11,8 +11,6 @@ #ifndef _ASM_SN_SN0_ARCH_H #define _ASM_SN_SN0_ARCH_H - -#ifndef SN0XXL /* 128 cpu SMP max */ /* * This is the maximum number of nodes that can be part of a kernel. * Effectively, it's the maximum number of compact node ids (cnodeid_t). @@ -25,12 +23,16 @@ */ #define MAXCPUS 128 -#else /* SN0XXL system */ - -#define MAX_COMPACT_NODES 128 -#define MAXCPUS 256 - -#endif /* SN0XXL */ +/* + * XXX: Historical Note regarding SN0XXL: + * + * There used to be an obscure #ifndef check for SN0XXL, which appears to + * have been a much larger IP27 setup that supported a maximum of 128 compact + * nodes and 256 CPUs. SN0XXL was never defined anywhere, though, so those + * defines never got used. In reality, complete SN0XXL systems are not likely + * to exist any longer, so I think it's safe to remove these definitions and + * leave this historical note behind. + */ /* * This is the maximum number of NASIDS that can be present in a system. @@ -63,7 +65,7 @@ #endif /* CONFIG_SGI_SN_M_MODE */ #define SLOT_SHIFT (27) -#define SLOT_MIN_MEM_SIZE (32*1024*1024) +#define SLOT_MIN_MEM_SIZE (32 * 1024 * 1024) #define CPUS_PER_NODE 2 /* CPUs on a single hub */ #define CPUS_PER_NODE_SHFT 1 /* Bits to shift in the node number */ diff --git a/arch/mips/include/asm/sn/sn0/hubmd.h b/arch/mips/include/asm/sn/sn0/hubmd.h index 305d002..d0e48ff 100644 --- a/arch/mips/include/asm/sn/sn0/hubmd.h +++ b/arch/mips/include/asm/sn/sn0/hubmd.h @@ -438,7 +438,7 @@ (HUB_S(CPU_LED_ADDR(_nasid, _slice), (_val))) #define SET_MY_LEDS(_v) \ - SET_CPU_LEDS(get_nasid(), get_slice(), (_v)) + SET_CPU_LEDS(ip27_get_nasid(), get_slice(), (_v)) /* * Operations on Memory/Directory DIMM control register diff --git a/arch/mips/include/asm/sn/sn_private.h b/arch/mips/include/asm/sn/sn_private.h index fdfae43..184e356 100644 --- a/arch/mips/include/asm/sn/sn_private.h +++ b/arch/mips/include/asm/sn/sn_private.h @@ -5,15 +5,12 @@ extern nasid_t master_nasid; -extern void cpu_node_probe(void); -extern cnodeid_t get_compact_nodeid(void); -extern void hub_rtc_init(cnodeid_t); -extern void cpu_time_init(void); -extern void per_cpu_init(void); -extern void install_cpu_nmi_handler(int slice); -extern void install_ipi(void); +extern void ip27_smp_cpu_node_probe(void); +extern void ip27_per_cpu_init(void); +extern void ip27_install_cpu_nmi_handler(int slice); +extern void ip27_install_ipi(void); extern void setup_replication_mask(void); extern void replicate_kernel_text(void); -extern unsigned long node_getfirstfree(cnodeid_t); +extern unsigned long node_get_first_free(cnodeid_t); #endif /* __ASM_SN_SN_PRIVATE_H */ diff --git a/arch/mips/include/asm/sn/types.h b/arch/mips/include/asm/sn/types.h index 6d24d4e..6a01f14 100644 --- a/arch/mips/include/asm/sn/types.h +++ b/arch/mips/include/asm/sn/types.h @@ -13,13 +13,9 @@ typedef unsigned long cpuid_t; typedef unsigned long cnodemask_t; -typedef signed short nasid_t; /* node id in numa-as-id space */ -typedef signed short cnodeid_t; /* node id in compact-id space */ -typedef signed char partid_t; /* partition ID type */ -typedef signed short moduleid_t; /* user-visible module number type */ -typedef signed short cmoduleid_t; /* kernel compact module id type */ -typedef unsigned char clusterid_t; /* Clusterid of the cell */ - -typedef dev_t vertex_hdl_t; /* hardware graph vertex handle */ +typedef s16 nasid_t; /* node id in numa-as-id space */ +typedef s16 cnodeid_t; /* node id in compact-id space */ +typedef s8 partid_t; /* partition ID type */ +typedef s16 moduleid_t; /* user-visible module number type */ #endif /* _ASM_SN_TYPES_H */ diff --git a/arch/mips/include/asm/xtalk/xtalk.h b/arch/mips/include/asm/xtalk/xtalk.h index 26d2ed1..ed596ca 100644 --- a/arch/mips/include/asm/xtalk/xtalk.h +++ b/arch/mips/include/asm/xtalk/xtalk.h @@ -16,25 +16,26 @@ /* * User-level device driver visible types */ -typedef char xwidgetnum_t; /* xtalk widget number (0..15) */ +typedef s8 xwidgetnum_t; /* xtalk widget number (0..15) */ #define XWIDGET_NONE -1 -typedef int xwidget_part_num_t; /* xtalk widget part number */ +typedef s32 xwidget_part_num_t; /* xtalk widget part number */ #define XWIDGET_PART_NUM_NONE -1 -typedef int xwidget_rev_num_t; /* xtalk widget revision number */ +typedef s32 xwidget_rev_num_t; /* xtalk widget revision number */ #define XWIDGET_REV_NUM_NONE -1 -typedef int xwidget_mfg_num_t; /* xtalk widget manufacturing ID */ +typedef s32 xwidget_mfg_num_t; /* xtalk widget manufacturing ID */ #define XWIDGET_MFG_NUM_NONE -1 typedef struct xtalk_piomap_s *xtalk_piomap_t; -/* It is often convenient to fold the XIO target port +/* + * It is often convenient to fold the XIO target port * number into the XIO address. */ #define XIO_NOWHERE (0xFFFFFFFFFFFFFFFFull) @@ -47,15 +48,6 @@ typedef struct xtalk_piomap_s *xtalk_piomap_t; #define XIO_PORT(x) ((xwidgetnum_t)(((x)&XIO_PORT_BITS) >> XIO_PORT_SHIFT)) #define XIO_PACK(p, o) ((((uint64_t)(p))< + #include + + /* Widget bits */ + #define XTALK_XBOW IP27_WIDGET_XBOW + #define XTALK_HUB IP27_WIDGET_HUB + #define XTALK_PCIBR IP27_WIDGET_PCI_CAGE + #define XTALK_BRIDGE IP27_WIDGET_PCI_BASE + #define XTALK_LOW_DEV HUB_WIDGET_ID_MIN + #define XTALK_HIGH_DEV HUB_WIDGET_ID_MAX +#endif + +/* Common widget bits */ +#define XTALK_NODEV 0xffffffff + +/* Common Xbow bits */ +#define XBOW_REG_LINK_STAT_0 0x114 +#define XBOW_REG_LINK_BLK_SIZE 0x40 +#define XBOW_REG_LINK_ALIVE 0x80000000 + +/** + * xwidget_platform_data - platform data for xtalk widgets. + * @nasid: signed short for the NUMA node ID. + * @masterwid: master xtalk widget for this xwidget (HUB, HEART, BEDROCK) + * @bridge_pdata: pointer to struct bridge_platform_data. + */ +struct xwidget_platform_data { + s16 nasid; + xwidgetnum_t masterwid; + struct bridge_platform_data *bridge_pdata; +}; + /* * according to the crosstalk spec, only 32-bits access to the widget * configuration registers is allowed. some widgets may allow 64-bits diff --git a/arch/mips/pci/Makefile b/arch/mips/pci/Makefile index 139ad1d..11fa609 100644 --- a/arch/mips/pci/Makefile +++ b/arch/mips/pci/Makefile @@ -35,7 +35,7 @@ obj-$(CONFIG_MIPS_MALTA) += fixup-malta.o pci-malta.o obj-$(CONFIG_PMC_MSP7120_GW) += fixup-pmcmsp.o ops-pmcmsp.o obj-$(CONFIG_PMC_MSP7120_EVAL) += fixup-pmcmsp.o ops-pmcmsp.o obj-$(CONFIG_PMC_MSP7120_FPGA) += fixup-pmcmsp.o ops-pmcmsp.o -obj-$(CONFIG_SGI_IP27) += ops-bridge.o pci-ip27.o +obj-$(CONFIG_SGI_IP27) += ops-bridge.o pci-bridge.o obj-$(CONFIG_SGI_IP32) += fixup-ip32.o ops-mace.o pci-ip32.o obj-$(CONFIG_SIBYTE_SB1250) += fixup-sb1250.o pci-sb1250.o obj-$(CONFIG_SIBYTE_BCM112X) += fixup-sb1250.o pci-sb1250.o diff --git a/arch/mips/pci/ops-bridge.c b/arch/mips/pci/ops-bridge.c index 9e22fd0..96397ff 100644 --- a/arch/mips/pci/ops-bridge.c +++ b/arch/mips/pci/ops-bridge.c @@ -10,9 +10,11 @@ #include #include +#if defined(CONFIG_SGI_IP27) #include #include #include +#endif /* * Most of the IOC3 PCI config register aren't present diff --git a/arch/mips/sgi-ip27/Makefile b/arch/mips/sgi-ip27/Makefile index ab4affa..e260866 100644 --- a/arch/mips/sgi-ip27/Makefile +++ b/arch/mips/sgi-ip27/Makefile @@ -7,5 +7,6 @@ obj-y := ip27-berr.o ip27-irq.o ip27-irqno.o ip27-init.o ip27-klconfig.o \ ip27-hubio.o ip27-xtalk.o obj-$(CONFIG_EARLY_PRINTK) += ip27-console.o -obj-$(CONFIG_PCI) += ip27-irq-pci.o +obj-$(CONFIG_PCI) += ip27-irq-pci.o ip27-bridge.o obj-$(CONFIG_SMP) += ip27-smp.o +obj-$(CONFIG_RTC_DRV_M48T35) += ip27-rtc.o diff --git a/arch/mips/sgi-ip27/ip27-bridge.c b/arch/mips/sgi-ip27/ip27-bridge.c new file mode 100644 index 0000000..cb580ba --- /dev/null +++ b/arch/mips/sgi-ip27/ip27-bridge.c @@ -0,0 +1,164 @@ +/* + * 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. + * + * ip27-bridge.c: BRIDGE platform device setup for IP27. + * + * Copyright (C) 2016 Joshua Kinard + */ + +#include +#include +#include + +#include +#include + +#include +#include + +/* Defined in ip27-irq-pci.c. */ +extern int ip27_request_irq(void); + +/* Defined in arch/mips/pci/pci-bridge.c */ +extern u32 bridge_alloc_rrbs(u8, u8, u8, u8, bool, bool, bool, bool); + + +/* + * XXX: drivers/misc/ioc3.c metadriver needs to check device flags + * to see what devices are actually present on a given IOC3 chip. + * + * XXX: for now, use a static bool to determine if we're probing the + * first IOC3 card on either an IO6 or IO6-G card. If it's an IO6-G, + * then this bool will prevent the second IOC3 from trying to acquire + * a second IRQ. + */ +static bool ip27_io6_probed_2nd_ioc3_irq __initdata = false; + +#ifdef CONFIG_NUMA +/** + * pcibus_to_node - fetch the nasid that the passed struct pci_bus lives on. + * @bus: struct pci_bus pointer for a given PCI bus. + * + * casts bus->sysdata to struct bridge_controller and returns the nasid + * member that references the specific node this PCI bus lives on. + */ +int +pcibus_to_node(struct pci_bus *bus) +{ + struct bridge_controller *bc = BRIDGE_CONTROLLER(bus); + + return bc->nasid; +} +EXPORT_SYMBOL(pcibus_to_node); +#endif /* CONFIG_NUMA */ + + +/** + * ip27_setup_io6_rrbs - alloc the read response buffers on an IP27 IO6 card. + * @bridge: const pointer to a BRIDGE structure. + * @census: array of bools indicating if a slot is populated or not. + * + * RRB values and logic was adapted from the original (and unused) function + * "sn00_rrb_alloc", found in arch/ia64/sn/io/ml_iograph.c in Linux-2.5.70. + */ +static void __init +ip27_bridge_setup_io6_rrbs(bridge_t *bridge, const bool *census) +{ + u32 rrbs; + + /* Even RRBs */ + if (census[6]) + rrbs = bridge_alloc_rrbs(3, 2, 0, 3, + true, false, false, false); + else + rrbs = bridge_alloc_rrbs(4, 4, 0, 0, + true, false, false, false); + bridge->b_even_resp = rrbs; + + /* Odd RRBs are a bit tricker ... */ + if (census[5] && census[7]) + rrbs = bridge_alloc_rrbs(2, 1, 3, 2, + true, false, false, false); + else if (census[5] && !census[7]) + rrbs = bridge_alloc_rrbs(3, 2, 3, 0, + true, false, false, false); + else if (!census[5] && census[7]) + rrbs = bridge_alloc_rrbs(3, 2, 0, 3, + true, false, false, false); + else + rrbs = bridge_alloc_rrbs(4, 4, 0, 0, + true, false, false, false); + bridge->b_odd_resp = rrbs; +} + +int __init +ip27_bridge_alloc_irq(struct pci_dev *dev) +{ + struct pci_dev *rdev = bridge_root_dev(dev); + struct bridge_controller *bc = BRIDGE_CONTROLLER(dev->bus); + int slot = PCI_SLOT(rdev->devfn); + int irq; + unsigned long flags; + + spin_lock_irqsave(&bc->lock, flags); + irq = bc->pci_int[slot]; + if (irq == -1) { + irq = ip27_request_irq(); + if (irq < 0) + goto out; + + bc->pci_int[slot] = irq; + } else if ((bc->widget_id == IP27_WIDGET_PCI_BASE) && + (dev->device == PCI_DEVICE_ID_SGI_IOC3)) { + + /* + * XXX: Onyx2 systems have an IO6-G, which has TWO IOC3 + * chips on it. The first IOC3 is much like the Origin 2k's + * IO6, but the second IOC3 on an IO6-G only has 2x serial + * ports and kb/mouse ports, no ethernet. So, in that + * instance, PCI INTA will have already been allocated and + * and hopefully, those ports will all work. But the IOC3 + * metadriver is a tad braindead and will still attempt to + * request a 2nd IRQ, which isn't needed on this 2nd IOC3 + * chip, so bail. + */ + if (ip27_io6_probed_2nd_ioc3_irq) { + irq = -1; + goto out; + } + + /* + * XXX: IO6 IOC3 needs a second IRQ, which will also be + * hardwired to BRIDGE slot #3. But don't overwrite the + * dev->irq assignment, as the ethernet is primary. + */ + irq = ip27_request_irq(); + ip27_irq_to_bridge[irq] = bc; + ip27_irq_to_slot[irq] = IP27_IO6_2ND_IOC3; + ip27_io6_probed_2nd_ioc3_irq = true; + goto out; + } + + ip27_irq_to_bridge[irq] = bc; + ip27_irq_to_slot[irq] = slot; + dev->irq = irq; + +out: + spin_unlock_irqrestore(&bc->lock, flags); + return irq; +} + +struct bridge_platform_data +ip27_bridge_platform_data[] __initdata = { + { + .xio_target_addr = PCIBR_XIO_SEES_HUB, + .baseio_widget_id = IP27_WIDGET_PCI_BASE, + .iomem_swap = true, + .add_512 = false, + .setup_baseio_rrbs = ip27_bridge_setup_io6_rrbs, + .alloc_irq = ip27_bridge_alloc_irq, + .startup_resource = NULL, + }, +}; diff --git a/arch/mips/sgi-ip27/ip27-console.c b/arch/mips/sgi-ip27/ip27-console.c index 225a13e..cf28a85 100644 --- a/arch/mips/sgi-ip27/ip27-console.c +++ b/arch/mips/sgi-ip27/ip27-console.c @@ -6,12 +6,14 @@ * Copyright (C) 2001, 2002 Ralf Baechle */ +#include #include + +#include #include -#include #include -#include #include +#include #include #include @@ -19,21 +21,26 @@ #define IOC3_CLK (22000000 / 3) #define IOC3_FLAGS (0) -static inline struct ioc3_uartregs *console_uart(void) +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; + nasid = ((master_nasid == INVALID_NASID) ? ip27_get_nasid() : + master_nasid); + ioc3 = (struct ioc3 *)KL_CONFIG_CONS_INFO(nasid)->memory_base; return &ioc3->sregs.uarta; } -void prom_putchar(char c) +void +prom_putchar(char c) { struct ioc3_uartregs *uart = console_uart(); - while ((uart->iu_lsr & 0x20) == 0); + while ((((u8 __iomem)uart->iu_lsr) & 0x20) == 0) + cpu_relax(); + uart->iu_thr = c; } diff --git a/arch/mips/sgi-ip27/ip27-hubio.c b/arch/mips/sgi-ip27/ip27-hubio.c index 328ceb3..f2d86ef 100644 --- a/arch/mips/sgi-ip27/ip27-hubio.c +++ b/arch/mips/sgi-ip27/ip27-hubio.c @@ -14,35 +14,40 @@ #include -static int force_fire_and_forget = 1; +static int __initdata force_fire_and_forget = 1; + +#if 0 +/* + * XXX: Requires porting from 2.4 arch/ia64/sn/io/io.c the various HUB + * PIO/DMA mapping stuff and setting up generic Xtalk bus support. + */ /** - * hub_pio_map - establish a HUB PIO mapping - * - * @hub: hub to perform PIO mapping on - * @widget: widget ID to perform PIO mapping for + * ip27_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) + * @size: size of the PIO mapping + */ +u64 +ip27_hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, + unsigned long xtalk_addr, size_t size) { - nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); + nasid_t nasid = sn_cnodeid_to_nasid[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); + 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); + pr_warn("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); + 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; @@ -65,23 +70,24 @@ unsigned long hub_pio_map(cnodeid_t cnode, xwidgetnum_t widget, 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); + 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); + pr_warn("IP27: Unable to establish PIO mapping for at hub %d, " + "widget %d, addr 0x%lx\n", nasid, widget, xtalk_addr); return 0; } - +#endif /* - * hub_setup_prb(nasid, prbnum, credits, conveyor) + * ip27_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. + * 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) +static void __init +ip27_hub_setup_prb(nasid_t nasid, int prbnum, int credits) { iprb_t prb; int prb_offset; @@ -116,24 +122,24 @@ static void hub_setup_prb(nasid_t nasid, int prbnum, int credits) } /** - * hub_set_piomode - set pio mode for a given hub - * - * @nasid: physical node ID for the hub in question + * ip27_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 + * 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 + * 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) +static void __init +ip27_hub_set_piomode(nasid_t nasid) { hubreg_t ii_iowa; hubii_wcr_t ii_wcr; @@ -148,12 +154,12 @@ static void hub_set_piomode(nasid_t nasid) /* * Assume a bridge here. */ - hub_setup_prb(nasid, 0, 3); + ip27_hub_setup_prb(nasid, 0, 3); } else { /* * Assume a crossbow here. */ - hub_setup_prb(nasid, 0, 1); + ip27_hub_setup_prb(nasid, 0, 1); } /* @@ -161,19 +167,19 @@ static void hub_set_piomode(nasid_t nasid) * when account assigning credits. */ for (i = HUB_WIDGET_ID_MIN; i <= HUB_WIDGET_ID_MAX; i++) - hub_setup_prb(nasid, i, 3); + ip27_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 +/** + * ip27_hub_pio_init - PIO-related hub initialization. + * @cnode: cnodeid_t value for the cnode to init. */ -void hub_pio_init(cnodeid_t cnode) +void __init +ip27_hub_pio_init(cnodeid_t cnode) { - nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); + nasid_t nasid = sn_cnodeid_to_nasid[cnode]; unsigned i; /* initialize big window piomaps for this hub */ @@ -181,5 +187,5 @@ void hub_pio_init(cnodeid_t cnode) for (i = 0; i < HUB_NUM_BIG_WINDOW; i++) IIO_ITTE_DISABLE(nasid, i); - hub_set_piomode(nasid); + ip27_hub_set_piomode(nasid); } diff --git a/arch/mips/sgi-ip27/ip27-init.c b/arch/mips/sgi-ip27/ip27-init.c index 6997b1e..b766e35 100644 --- a/arch/mips/sgi-ip27/ip27-init.c +++ b/arch/mips/sgi-ip27/ip27-init.c @@ -36,49 +36,136 @@ #include #include -#define CPU_NONE (cpuid_t)-1 - -static DECLARE_BITMAP(hub_init_mask, MAX_COMPACT_NODES); +static DECLARE_BITMAP(hub_init_mask, MAX_COMPACT_NODES) __initdata; 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]; +DEFINE_PER_CPU(cnodeid_t, __sn_cnodeid_to_nasid[MAX_COMPACT_NODES]); +EXPORT_PER_CPU_SYMBOL(__sn_cnodeid_to_nasid); + +DEFINE_PER_CPU(nasid_t, __sn_nasid_to_cnodeid[MAX_NASIDS]); +EXPORT_PER_CPU_SYMBOL(__sn_nasid_to_cnodeid); + +DEFINE_PER_CPU(cnodeid_t, __sn_cpuid_to_cnodeid[MAXCPUS]); +EXPORT_PER_CPU_SYMBOL(__sn_cpuid_to_cnodeid); -EXPORT_SYMBOL(nasid_to_compact_node); +DEFINE_PER_CPU(struct ip27_percpu_data, ip27_cpu); +EXPORT_PER_CPU_SYMBOL(ip27_cpu); -struct cpuinfo_ip27 sn_cpu_info[NR_CPUS]; -EXPORT_SYMBOL_GPL(sn_cpu_info); +/* XXX: Found in 2.4 arch/ia64/sn/io/ml_SN_init.c */ +static DEFINE_SPINLOCK(ip27_hub_lock); -extern void pcibr_setup(cnodeid_t); -extern void xtalk_probe_node(cnodeid_t nid); +/* ----------------------------------------------------------------------- */ +/* IP27 Initialization routines. */ -static void per_hub_init(cnodeid_t cnode) +/* + * ip27_get_nasid() returns the physical node id number of the caller. + */ +nasid_t +ip27_get_nasid(void) +{ + return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK) >> + NSRI_NODEID_SHFT); +} + +/** + * ip27_hub_clock_init - enable/set the various clocks on a HUB. + * @cnode: compact nodeid of the current node. + * + * We only need to initialize the current node. If this is not the current + * node, then it is a cpuless (headless) node and timeouts will not happen + * there. + */ +static void __init +ip27_hub_clock_init(cnodeid_t cnode) +{ + cnodeid_t this_cnode = sn_nasid_to_cnodeid[ip27_get_nasid()]; + + if (this_cnode == 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); + } +} + +/** + * ip27_per_hub_init - initialize each HUB on a node. + * @cnode: compact nodeid of the current node. + */ +static void __init +ip27_per_hub_init(cnodeid_t cnode) { - struct hub_data *hub = hub_data(cnode); - nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); int i; + nasid_t nasid = sn_cnodeid_to_nasid[cnode]; + struct hub_data *hub = hub_data(cnode); +#ifdef CONFIG_REPLICATE_EXHANDLERS + cnodeid_t this_cnode = sn_nasid_to_cnodeid[ip27_get_nasid()]; +#endif + spin_lock(&ip27_hub_lock); cpumask_set_cpu(smp_processor_id(), &hub->h_cpus); - if (test_and_set_bit(cnode, hub_init_mask)) + if (test_and_set_bit(cnode, hub_init_mask)) { + spin_unlock(&ip27_hub_lock); return; + } + + /* + * Clear the HUB IRQ allocation map and set all irq_to_bit/bit_to_irq + * mappings to -1. There's two INT_PEND registers, each 64-bits wide, + * for a total of 128 bits per HUB. HUB carries two INT_MASK regs + * for each CPU. + */ + for (i = 0; i < BITS_PER_HUB; i++) { + hub->irq_to_bit[i] = -1; + hub->bit_to_irq[i] = -1; + __clear_bit(i, hub->irq_alloc_map); + } + + /* + * Some interrupts are reserved by hardware or by software convention. + * Mark these as reserved right away so they won't be accidentally + * used later. + */ + for (i = 0; i <= BASE_PCI_IRQ; i++) { + __set_bit(i, hub->irq_alloc_map); + LOCAL_HUB_CLR_INTR(INT_PEND0_BASELVL + i); + } + + __set_bit(IP_PEND0_6_63, hub->irq_alloc_map); + 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_map); + LOCAL_HUB_CLR_INTR(INT_PEND1_BASELVL + i); + } + spin_unlock(&ip27_hub_lock); + /* - * Set CRB timeout at 5ms, (< PI timeout of 10ms) + * XXX: Set CRB timeout to be 10ms. + * Found in old arch/ia64 2.4 code. It works for + * SN1, so why not SN0? */ - REMOTE_HUB_S(nasid, IIO_ICTP, 0x800); + REMOTE_HUB_S(nasid, IIO_ICTP, 0x1000 ); +// /* +// * 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); + ip27_hub_clock_init(cnode); + ip27_hub_pio_init(cnode); #ifdef CONFIG_REPLICATE_EXHANDLERS /* * If this is not a headless node initialization, * copy over the caliased exception handlers. */ - if (get_compact_nodeid() == cnode) { + if (this_cnode == cnode) { extern char except_vec2_generic, except_vec3_generic; extern void build_tlb_refill_handler(void); @@ -90,92 +177,128 @@ static void per_hub_init(cnodeid_t cnode) __flush_cache_all(); } #endif +} + +/** + * ip27_cpu_time_init - platform time initialization. + */ +static void __init +ip27_cpu_time_init(void) +{ + struct klc_lboard *brd; + struct klc_cpu *cpu; + int cpuid; + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); /* - * Some interrupts are reserved by hardware or by software convention. - * Mark these as reserved right away so they won't be used accidentally - * later. + * ARCS is fragile and its place in memory is typically obliterated + * right after the TLB is set up by the kernel, so we cannot use it + * to discover information about the hardware in the system. + * + * Fortunately, IP27 platforms have KLCONFIG available, which is a + * simple linked-list data structure set up by the PROM that contains + * a complete hardware inventory and it is always available. */ - for (i = 0; i <= BASE_PCI_IRQ; i++) { - __set_bit(i, hub->irq_alloc_mask); - LOCAL_HUB_CLR_INTR(INT_PEND0_BASELVL + i); - } + brd = kl_find_lboard(KLCF_LBOARD_INFO(ip27_get_nasid()), KLTYPE_IP27); + if (!brd) + panic("IP27: Can't find board info for myself?"); - __set_bit(IP_PEND0_6_63, hub->irq_alloc_mask); - LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63); + cpuid = (LOCAL_HUB_L(PI_CPU_NUM) ? IP27_CPU0_INDEX : IP27_CPU1_INDEX); + cpu = KLCF_CAST_CPU(KLCF_COMP(brd, cpuid)); + if (!cpu) + panic("IP27: No information about myself?"); - 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); - } + mips_hpt_frequency = (read_c0_count() * 10); + pr_info("IP27: CPU %d%c (CPU%d): %d MHz CPU detected.\n", + (cpud->nasid + 1), IP27_CPU_SLICE(cpud->slice), cpud->id, + cpu->speed); + + set_c0_status(STATUSF_IP4); /* SRB_TIMOCLK */ } -void per_cpu_init(void) +void __init +ip27_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; + cnodeid_t this_cnode = sn_nasid_to_cnodeid[ip27_get_nasid()]; + struct hub_data *hub = hub_data(this_cnode); + struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); int i; if (test_and_set_bit(slice, &hub->slice_map)) return; + /* Disable all interrupts. */ clear_c0_status(ST0_IM); - per_hub_init(cnode); + /* Populate the percpu struct for IP27 CPU data. */ + cpud->id = cpu; + cpud->nasid = ip27_get_nasid(); + cpud->cnodeid = this_cnode; + cpud->slice = slice; - for (i = 0; i < LEVELS_PER_SLICE; i++) - si->level_to_irq[i] = -1; + /* Initialize the array tracking which CPU owns what IRQ number. */ + for (i = 0; i < BITS_PER_HUB; i++) { + cpud->irq_owner[i] = false; + __clear_bit(i, cpud->irq_mask); + } - /* - * We use this so we can find the local hub's data as fast as only - * possible. - */ - cpu_data[cpu].data = si; + /* Run necessary HUB init code if not already done. */ + ip27_per_hub_init(this_cnode); - cpu_time_init(); - install_ipi(); + if (cpu != 0) { + /* Copy CPU0's sn_cnodeid_to_nasid table to this cpu. */ + memcpy(sn_cnodeid_to_nasid, + (&per_cpu(__sn_cnodeid_to_nasid, 0)), + sizeof(this_cpu_ptr(__sn_cnodeid_to_nasid))); - /* Install our NMI handler if symmon hasn't installed one. */ - install_cpu_nmi_handler(cputoslice(cpu)); + /* Copy CPU0's sn_nasid_to_cnodeid table to this cpu. */ + memcpy(sn_nasid_to_cnodeid, + (&per_cpu(__sn_nasid_to_cnodeid, 0)), + sizeof(this_cpu_ptr(__sn_nasid_to_cnodeid))); - set_c0_status(SRB_DEV0 | SRB_DEV1); -} + /* Copy CPU0's sn_cpuid_to_cnodeid table to this cpu. */ + memcpy(sn_cpuid_to_cnodeid, + (&per_cpu(__sn_cpuid_to_cnodeid, 0)), + sizeof(this_cpu_ptr(__sn_cpuid_to_cnodeid))); + } -/* - * 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); -} + /* Done with ip27_percpu_data. */ + cpud->hub = hub; + smp_wmb(); -/* - * 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()); + ip27_cpu_time_init(); + ip27_install_ipi(); + + /* Install an NMI handler. */ + ip27_install_cpu_nmi_handler(slice); + +//#if 0 /* LATER */ +// /* XXX: Need to re-enable INT_PEND1 and HUB errors later on. */ + set_c0_status(STATUSF_IP2 | STATUSF_IP3 | STATUSF_IP6); +//#else +// set_c0_status(STATUSF_IP2); // | STATUSF_IP3 | STATUSF_IP6); +//#endif } -static inline void ioc3_eth_init(void) +static void __init +ip27_ioc3_eth_init(void) { struct ioc3 *ioc3; nasid_t nid; - nid = get_nasid(); - ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base; + nid = ip27_get_nasid(); + ioc3 = (struct ioc3 *)KL_CONFIG_CONS_INFO(nid)->memory_base; ioc3->eier = 0; } extern void ip27_reboot_setup(void); +extern void ip27_be_init(void); -void __init plat_mem_setup(void) +void __init +plat_mem_setup(void) { hubreg_t p, e, n_mode; nasid_t nid; @@ -185,27 +308,27 @@ void __init plat_mem_setup(void) /* * hub_rtc init and cpu clock intr enabled for later calibrate_delay. */ - nid = get_nasid(); - printk("IP27: Running on node %d.\n", nid); + nid = ip27_get_nasid(); + pr_info("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_A) & 1); + e = (LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1); + pr_info("IP27: 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" : ""); + p = (LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1); + e = (LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1); + pr_info("IP27: 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'); + pr_info("IP27: 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."); @@ -214,8 +337,9 @@ void __init plat_mem_setup(void) panic("Kernel compiled for N mode."); #endif - ioc3_eth_init(); - per_cpu_init(); + ip27_ioc3_eth_init(); + ip27_per_cpu_init(); + ip27_be_init(); set_io_port_base(IO_BASE); } diff --git a/arch/mips/sgi-ip27/ip27-irq-pci.c b/arch/mips/sgi-ip27/ip27-irq-pci.c index 2a1c407..918b2eb 100644 --- a/arch/mips/sgi-ip27/ip27-irq-pci.c +++ b/arch/mips/sgi-ip27/ip27-irq-pci.c @@ -1,265 +1,398 @@ /* - * ip27-irq.c: Highlevel interrupt handling for IP27 architecture. + * 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) 1999, 2000 Ralf Baechle (ralf@gnu.org) - * Copyright (C) 1999, 2000 Silicon Graphics, Inc. - * Copyright (C) 1999 - 2001 Kanoj Sarcar + * ip27-irq-pci.c: Highlevel interrupt handling for IP27 architecture. + * + * The original version of this file inspired the original IRQ logic for + * the IP30 platform in ip30-irq.c, but ideas from that were later refactored + * back into this file, which was then re-used to rewrite ip30-irq.c so the + * two look remarkably similar now. As such, the original code is: + * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org) + * Copyright (C) 1999, 2000 Silicon Graphics, Inc. + * Copyright (C) 1999-2001 Kanoj Sarcar + * + * While snippets of code from ip30-irq.c are: + * Copyright (C) 2004-2007 Stanislaw Skowronek + * Copyright (C) 2009 Johannes Dickgreber + * Copyright (C) 2007-2014, 2016 Joshua Kinard */ #undef DEBUG #include #include -#include -#include #include #include -#include -#include -#include -#include -#include -#include -#include #include +#include #include #include #include -#include #include #include #include #include #include #include +#include -/* - * 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[]; +#include -/* - * 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] +#undef IP27_DEBUG_IRQ -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; +/* Defined in ip27-init.c */ +DECLARE_PER_CPU(struct ip27_percpu_data, ip27_cpu); - level = find_first_zero_bit(hub->irq_alloc_mask, LEVELS_PER_SLICE); - if (level >= LEVELS_PER_SLICE) - panic("Cpu %d flooded with devices", cpu); +/* Defined in ip27-irq.c */ +extern struct bridge_controller *ip27_irq_to_bridge[PCIBR_MAX_BUS_X_DEV]; +extern u32 ip27_irq_to_slot[PCIBR_MAX_BUS_X_DEV]; - __set_bit(level, hub->irq_alloc_mask); - si->level_to_irq[level] = irq; - return level; -} +/* ----------------------------------------------------------------------- */ +/* HUB Interrupt Bit Ops */ -static inline int find_level(cpuid_t *cpunum, int irq) +/** + * ip27_earmark_hub_bit - earmarks a free interrupt bit in the HUB to an irq. + * @hub: pointer to struct hub_data. + * @nasid: node ID. + * @irq: int value of irq to assign. + * + * This function finds the first free bit in HUB's irq_alloc_map and + * earmarks it for assignment to the requested IRQ number. It then returns + * the earmarked bit. + * + * Interrupt mapping on IP27 is not straight-forward. An IRQ number can be + * assigned to any CPU attached to a given HUB chip in any of the nodes of + * the machine. Although, so far, this mapping appears to limit interrupts + * from a device to the specific HUB that that device's corresponding XBOW + * chip is connected to. Meaning, we hope that if CPU 1A earmarks a free bit + * in its connected HUB chip, that CPU 2B won't be the CPU that attempts to + * claim ownership, because that CPU would be on a different HUB chip entirely. + * + * CPU ownership takes place in ip27_startup_hub_irq(), which is where the IRQ + * bring up happens. + * + * Note: Previously, a "bit" was known as a "level" in IRIX terminology. But + * this is Linux, not IRIX. + */ +static int +ip27_earmark_hub_bit(struct hub_data *hub, nasid_t nasid, int irq) { - int cpu, i; + u32 bit; - for_each_online_cpu(cpu) { - struct slice_data *si = cpu_data[cpu].data; + bit = find_first_zero_bit(hub->irq_alloc_map, BITS_PER_HUB); + if (bit >= BITS_PER_HUB) { + panic("IP27: HUB on nasid %d flooded with IRQ assignments!\n", + nasid); + } - for (i = BASE_PCI_IRQ; i < LEVELS_PER_SLICE; i++) - if (si->level_to_irq[i] == irq) { - *cpunum = cpu; + smp_mb__before_atomic(); + set_bit(bit, hub->irq_alloc_map); + hub->irq_to_bit[irq] = bit; + hub->bit_to_irq[bit] = irq; + smp_mb__after_atomic(); - return i; - } - } +#ifdef IP27_DEBUG_IRQ + pr_info("IP27: CPU %d%c (CPU%d): earmarking IRQ %d to HUB bit %d\n", + (cpud->nasid + 1), IP27_CPU_SLICE(cpud->slice), cpud->id, + irq, bit); +#endif - panic("Could not identify cpu/level for irq %d", irq); + return bit; } -static int intr_connect_level(int cpu, int bit) +/** + * ip27_update_hub_irq_mask - updates irq_mask on a specific HUB/CPU. + * @cpud: const pointer to the percpu ip27_percpu_data structure. + */ +static inline void +ip27_update_hub_irq_mask(const struct ip27_percpu_data __percpu *cpud) { - 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]); + if (!cpud->slice) { + REMOTE_HUB_S(cpud->nasid, PI_INT_MASK0_A, cpud->irq_mask[0]); + REMOTE_HUB_S(cpud->nasid, PI_INT_MASK1_A, cpud->irq_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]); + REMOTE_HUB_S(cpud->nasid, PI_INT_MASK0_B, cpud->irq_mask[0]); + REMOTE_HUB_S(cpud->nasid, PI_INT_MASK1_B, cpud->irq_mask[1]); } - - return 0; } -static int intr_disconnect_level(int cpu, int bit) +/** + * ip27_set_hub_bit - sets a bit in irq_mask for a specific HUB/CPU. + * @bit: int value of the interrupt bit to set. + */ +static inline void +ip27_set_hub_bit(int bit) { - nasid_t nasid = COMPACT_TO_NASID_NODEID(cpu_to_node(cpu)); - struct slice_data *si = cpu_data[cpu].data; + struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); - clear_bit(bit, si->irq_enable_mask); + set_bit(bit, cpud->irq_mask); + ip27_update_hub_irq_mask(cpud); +} - 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]); - } +/** + * ip27_clear_hub_bit - clears a bit in irq_mask for a specific HUB/CPU. + * @bit: int value of the interrupt bit to clear. + */ +static inline void +ip27_clear_hub_bit(int bit) +{ + struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); - return 0; + clear_bit(bit, cpud->irq_mask); + ip27_update_hub_irq_mask(cpud); } -/* Startup one of the (PCI ...) IRQs routes over a bridge. */ -static unsigned int startup_bridge_irq(struct irq_data *d) +/* ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- */ +/* HUB IRQ Ops */ + +/** + * ip27_startup_hub_irq - assigns a HUB IRQ to a CPU and/or Bridge slot. + * @d: struct irq_data containing IRQ information. + * + * Returns 0. + */ +static unsigned int +ip27_startup_hub_irq(struct irq_data *d) { - struct bridge_controller *bc; + u32 slot; + int hub_bit; bridgereg_t device; bridge_t *bridge; - int pin, swlevel; - cpuid_t cpu; + struct bridge_controller *bc; + struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); - pin = SLOT_FROM_PCI_IRQ(d->irq); - bc = IRQ_TO_BRIDGE(d->irq); - bridge = bc->base; +#ifdef IP27_DEBUG_IRQ + pr_info("IP27: %s: IRQ %d startup on CPU %d%c (CPU%d)\n", __func__, + d->irq, (cpud->nasid + 1), IP27_CPU_SLICE(cpud->slice), + cpud->id); +#endif - 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 */ + /* This CPU will now claim ownership of the IRQ. */ + cpud->irq_owner[d->irq] = true; + hub_bit = cpud->hub->irq_to_bit[d->irq]; /* - * Enable sending of an interrupt clear packt to the hub on a high to - * low transition of the interrupt pin. + * Handle BRIDGE IRQs. * - * IRIX sets additional bits in the address which are documented as - * reserved in the bridge docs. + * bridge->b_int_addr[slot].addr - Points to the HUB that this BRIDGE + * is assigned to, so that BRIDGE can frob the PI_INT_PEND_MOD + * register directly, without having to know which nasid the + * specific HUB is on. + * + * bridge->b_int_mode - Enable the sending of an interrupt clear + * packet to the HUB on a high-to-low transition of the + * interrupt pin. + * + * bridge->b_int_device - We assume the bridge to have a 1:1 mapping + * between devices (slots) and interrupt numbers. + * + * XXX: Replace the magic values with readable macros at some point. */ - bridge->b_int_mode |= (1UL << pin); + bc = ip27_irq_to_bridge[d->irq]; + if (bc) { + bridge = bc->base; + if (bridge) { + slot = ip27_irq_to_slot[d->irq]; + bridge->b_int_addr[slot].addr = + (0x20000 | hub_bit | (bc->nasid << 8)); + bridge->b_int_enable |= (BIT(slot) | 0x7ffffe00); + bridge->b_int_mode |= BIT(slot); + device = bridge->b_int_device; + device &= ~BRIDGE_INT_DEV_MASK(slot); + device |= BRIDGE_INT_DEV_SET(slot, slot); + bridge->b_int_device = device; + BRIDGE_FLUSH(bridge); + } + } - /* - * 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; + /* Unmask IRQ */ + ip27_set_hub_bit(hub_bit); - bridge->b_wid_tflush; + /* Never anything pending. */ + return 0; +} + +/** + * ip27_shutdown_hub_irq - removes a HUB IRQ from a CPU and/or Bridge slot. + * @d: struct irq_data containing IRQ information. + */ +static void +ip27_shutdown_hub_irq(struct irq_data *d) +{ + u32 slot; + int hub_bit; + bridge_t *bridge; + struct bridge_controller *bc; + struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); + + /* Mask the IRQ on HUB */ + hub_bit = cpud->hub->irq_to_bit[d->irq]; + ip27_clear_hub_bit(hub_bit); + + /* Ditto for BRIDGE */ + bc = ip27_irq_to_bridge[d->irq]; + if (bc) { + bridge = bc->base; + if (bridge) { + slot = ip27_irq_to_slot[d->irq]; + bridge->b_int_enable &= ~(BIT(slot)); + BRIDGE_FLUSH(bridge); + } + } - intr_connect_level(cpu, swlevel); + /* Release ownership of the IRQ. */ + cpud->irq_owner[d->irq] = false; - return 0; /* Never anything pending. */ +#ifdef IP27_DEBUG_IRQ + pr_info("IP27: %s: IRQ %d shutdown on CPU %d%c (CPU%d)\n", __func__, + d->irq, (cpud->nasid + 1), IP27_CPU_SLICE(cpud->slice), + cpud->id); +#endif } -/* Shutdown one of the (PCI ...) IRQs routes over a bridge. */ -static void shutdown_bridge_irq(struct irq_data *d) +/** + * ip27_ack_hub_irq - acks a HUB IRQ. + * @d: struct irq_data containing IRQ information. + */ +static void +ip27_ack_hub_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; + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); - pr_debug("bridge_shutdown: irq 0x%x\n", d->irq); - pin = SLOT_FROM_PCI_IRQ(d->irq); + /* Ack */ + LOCAL_HUB_CLR_INTR(cpud->hub->irq_to_bit[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); +/** + * ip27_mask_hub_irq - masks a HUB IRQ. + * @d: struct irq_data containing IRQ information. + */ +static void +ip27_mask_hub_irq(struct irq_data *d) +{ + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); - bridge->b_int_enable &= ~(1 << pin); - bridge->b_wid_tflush; + /* Mask */ + ip27_clear_hub_bit(cpud->hub->irq_to_bit[d->irq]); } -static inline void enable_bridge_irq(struct irq_data *d) +/** + * ip27_mask_and_ack_hub_irq - masks and acks a HUB IRQ. + * @d: struct irq_data containing IRQ information. + */ +static void +ip27_mask_and_ack_hub_irq(struct irq_data *d) { - cpuid_t cpu; - int swlevel; + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); + const s8 bit = cpud->hub->irq_to_bit[d->irq]; + + /* Mask */ + ip27_clear_hub_bit(bit); - swlevel = find_level(&cpu, d->irq); /* Criminal offence */ - intr_connect_level(cpu, swlevel); + /* Ack */ + LOCAL_HUB_CLR_INTR(bit); } -static inline void disable_bridge_irq(struct irq_data *d) +/** + * ip27_unmask_hub_irq - unmasks a HUB IRQ. + * @d: struct irq_data containing IRQ information. + */ +static void +ip27_unmask_hub_irq(struct irq_data *d) { - cpuid_t cpu; - int swlevel; + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); - swlevel = find_level(&cpu, d->irq); /* Criminal offence */ - intr_disconnect_level(cpu, swlevel); + /* Unmask */ + ip27_set_hub_bit(cpud->hub->irq_to_bit[d->irq]); } -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, +/** + * struct ip27_hub_irq - HUB struct irq_chip ops. + * @irq_startup: startup function. + * @irq_shutdown: shutdown function. + * @irq_ack: ack function. + * @irq_mask: mask function. + * @irq_mask_ack: mask & ack function. + * @irq_unmask: unmask function. + * @irq_disable: disable (mask) function. + * @irq_enable: enable (unmask) function. + */ +static struct irq_chip __read_mostly +ip27_hub_irq = { + .name = "HUB", + .irq_startup = ip27_startup_hub_irq, + .irq_shutdown = ip27_shutdown_hub_irq, + .irq_ack = ip27_ack_hub_irq, + .irq_mask = ip27_mask_hub_irq, + .irq_mask_ack = ip27_mask_and_ack_hub_irq, + .irq_unmask = ip27_unmask_hub_irq, + .irq_disable = ip27_mask_hub_irq, + .irq_enable = ip27_unmask_hub_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) +/** + * ip27_request_irq - requests an irq number. + * + * Returns the allocated IRQ number assigned to a specific HUB interrupt bit. + */ +int +ip27_request_irq(void) { - int irq = allocate_irqno(); - int swlevel, cpu; - nasid_t nasid; + int hub_bit; + int irq_num = ip27_alloc_irq_num(); + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); - if (irq < 0) - return irq; + /* Bail if ip27_alloc_irq_num() failed. */ + if (irq_num < 0) + return irq_num; - /* - * "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); + /* Assign the IRQ to a free HUB interrupt bit. */ + hub_bit = ip27_earmark_hub_bit(cpud->hub, cpud->nasid, irq_num); - return -EAGAIN; - } + /* Assign the irq_chip handler. */ + irq_set_chip_and_handler(irq_num, &ip27_hub_irq, handle_level_irq); /* 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); + REMOTE_HUB_CLR_INTR(cpud->cnodeid, hub_bit); + + return irq_num; +} - intr_connect_level(cpu, swlevel); +/* ----------------------------------------------------------------------- */ - register_bridge_irq(irq); - return irq; +/* ----------------------------------------------------------------------- */ +/* Arch IRQ initialization - runs on CPU0 only. */ + +/** + * arch_init_irq - arch initialization function. + */ +void __init +arch_init_irq(void) +{ +#ifdef CONFIG_SMP + irq_set_chip_and_handler(CPU_RESCHED_A_IRQ, &ip27_hub_irq, + handle_percpu_irq); + irq_set_chip_and_handler(CPU_RESCHED_B_IRQ, &ip27_hub_irq, + handle_percpu_irq); + irq_set_chip_and_handler(CPU_CALL_A_IRQ, &ip27_hub_irq, + handle_percpu_irq); + irq_set_chip_and_handler(CPU_CALL_B_IRQ, &ip27_hub_irq, + handle_percpu_irq); +#endif } + +/* ----------------------------------------------------------------------- */ diff --git a/arch/mips/sgi-ip27/ip27-irq.c b/arch/mips/sgi-ip27/ip27-irq.c index 16ec4e1..ae9b477 100644 --- a/arch/mips/sgi-ip27/ip27-irq.c +++ b/arch/mips/sgi-ip27/ip27-irq.c @@ -8,205 +8,212 @@ #undef DEBUG -#include -#include +#include #include -#include -#include -#include #include -#include -#include +#include #include -#include -#include -#include -#include -#include +#include +#include #include #include #include -#include #include #include #include #include #include -/* - * 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. - */ +#include -extern asmlinkage void ip27_irq(void); +struct bridge_controller *ip27_irq_to_bridge[PCIBR_MAX_BUS_X_DEV]; +u32 ip27_irq_to_slot[PCIBR_MAX_BUS_X_DEV]; -/* - * Find first bit set +/* Defined in ip27-init.c */ +DECLARE_PER_CPU(struct ip27_percpu_data, ip27_cpu); + +/* ----------------------------------------------------------------------- */ +/* HUB Interrupt Handlers */ + +/** + * ip27_find_first_set_msb - finds the first most significant bit set. + * @dword: u64 value in which to find the first bit set. */ -static int ms1bit(unsigned long x) +static inline u32 +ip27_find_first_set_msb(u64 dword) { - int b = 0, s; + /* b: bit, s: shift */ + u32 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; + s = 32; if (dword >> s == 0) s = 0; b += s; dword >>= s; + s = 16; if (dword >> s == 0) s = 0; b += s; dword >>= s; + s = 8; if (dword >> s == 0) s = 0; b += s; dword >>= s; + s = 4; if (dword >> s == 0) s = 0; b += s; dword >>= s; + s = 2; if (dword >> s == 0) s = 0; b += s; dword >>= s; + s = 1; if (dword >> s == 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 +/** + * ip27_do_hub_irq - main interrupt servicing routine for IP27. + * @cpu: u32 value of the cpu processing the interrupt. + * @pend_reg: u32 value of the PEND0/PEND1 register offset. + * @mask_reg: u32 value of the MASK0/MASK1 register offset for a cpu. */ - -static void ip27_do_irq_mask0(void) +static noinline void +ip27_do_hub_irq(u32 pend_reg, u32 mask_reg) { - 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; + int irq; + u32 hub_bit; + hubreg_t pend, mask; + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); - 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); - irq_enter(); - generic_smp_call_function_interrupt(); - irq_exit(); - } else if (pend0 & (1UL << CPU_CALL_B_IRQ)) { - LOCAL_HUB_CLR_INTR(CPU_CALL_B_IRQ); - irq_enter(); - generic_smp_call_function_interrupt(); - irq_exit(); - } else -#endif - { - /* "map" swlevel to irq */ - struct slice_data *si = cpu_data[cpu].data; - - irq = si->level_to_irq[swlevel]; - do_IRQ(irq); - } + pend = LOCAL_HUB_L(pend_reg); + mask = LOCAL_HUB_L(mask_reg); - LOCAL_HUB_L(PI_INT_PEND0); + pend &= mask; + if (unlikely(!pend)) + return; + + hub_bit = ip27_find_first_set_msb(pend); + irq = cpud->hub->bit_to_irq[hub_bit]; + do_IRQ(irq); } -static void ip27_do_irq_mask1(void) +/** + * ip27_do_hub_pend0 - services an interrupt from PEND0. + * @cpu: u32 value of the cpu processing the interrupt. + */ +static noinline void +ip27_do_hub_pend0(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; + int pi_int_mask0 = (!this_cpu_read(ip27_cpu.slice) ? + PI_INT_MASK0_A : PI_INT_MASK0_B); - swlevel = ms1bit(pend1); - /* "map" swlevel to irq */ - irq = si->level_to_irq[swlevel]; - LOCAL_HUB_CLR_INTR(swlevel); - do_IRQ(irq); + ip27_do_hub_irq(PI_INT_PEND0, pi_int_mask0); +} + +/** + * ip27_do_hub_pend1 - services an interrupt from PEND1. + * @cpu: u32 value of the cpu processing the interrupt. + */ +static noinline void +ip27_do_hub_pend1(void) +{ + int pi_int_mask1 = (!this_cpu_read(ip27_cpu.slice) ? + PI_INT_MASK1_A : PI_INT_MASK1_B); - LOCAL_HUB_L(PI_INT_PEND1); + ip27_do_hub_irq(PI_INT_PEND1, pi_int_mask1); } -static void ip27_prof_timer(void) +/** + * ip27_prof_timer - stub function to handle CAUSEF_IP5 interrupts. + * + * XXX: Currently calls panic() - can we do anything useful instead + * with this interrupt? + */ +static void +ip27_prof_timer(void) { panic("CPU %d got a profiling interrupt", smp_processor_id()); } -static void ip27_hub_error(void) +/** + * ip27_hub_error - stub function to handle HUB error interrupts. + * + * XXX: Currently calls panic() - need to rip HUB error reporting code from + * the old arch/ia64 code in 2.4.x and late 2.5.x kernels, in which SGI + * GPL'ed and imported a large amount of IP27 code straight from IRIX + * during their bringup of the Altix/IA64 platform by using existing + * hardware. + */ +static void +ip27_hub_error(void) { +// pr_crit("CPU %d got a hub error interrupt", smp_processor_id()); panic("CPU %d got a hub error interrupt", smp_processor_id()); } -asmlinkage void plat_irq_dispatch(void) +/* ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- */ + +/** + * plat_irq_dispatch - platform IRQ dispatch. + * + * Interrupts are disabled. + */ +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) + unsigned long pending = (read_c0_cause() & read_c0_status()); + extern int ip27_hub_rt_irq_num; /* Defined in ip27-timer.c. */ + + /* IP4, HUB Counter/Compare */ + if (likely(pending & CAUSEF_IP4)) + do_IRQ(ip27_hub_rt_irq_num); + /* IP2, HUB INT_PEND0 (also IPI/SMP IRQs) */ + else if (likely(pending & CAUSEF_IP2)) + ip27_do_hub_pend0(); + /* IP3, HUB INT_PEND1 (Error IRQs) */ + else if (unlikely(pending & CAUSEF_IP3)) + ip27_do_hub_pend1(); + /* IP5, Profiling Clock? (SRB_PROFCLK) */ + else if (unlikely(pending & CAUSEF_IP5)) ip27_prof_timer(); - else if (pending & CAUSEF_IP6) + /* IP6, HUB Errors */ + else if (unlikely(pending & CAUSEF_IP6)) ip27_hub_error(); } -void __init arch_init_irq(void) +/* ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- */ + +/** + * __ip27_install_ipi - sets up interprocessor interrupts on each CPU. + */ +static void __init +__ip27_install_ipi(u32 irq) { + struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); + struct hub_data *hub = cpud->hub; + + smp_mb__before_atomic(); + set_bit(irq, hub->irq_alloc_map); + set_bit(irq, cpud->irq_mask); + cpud->irq_owner[irq] = true; + hub->irq_to_bit[irq] = irq; /* These two are 1-to-1 mapped. */ + hub->bit_to_irq[irq] = irq; + smp_mb__after_atomic(); + ip27_assign_irq_num(irq); + LOCAL_HUB_CLR_INTR(irq); } -void install_ipi(void) +/** + * ip27_install_ipi - extern func called from either ip27-init or ip27-smp. + */ +void __init +ip27_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]); + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); + u8 slice = cpud->slice; + + __ip27_install_ipi(CPU_RESCHED_A_IRQ + slice); + __ip27_install_ipi(CPU_CALL_A_IRQ + slice); + + if (!slice) { + LOCAL_HUB_S(PI_INT_MASK0_A, cpud->irq_mask[0]); + LOCAL_HUB_S(PI_INT_MASK1_A, cpud->irq_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]); + LOCAL_HUB_S(PI_INT_MASK0_B, cpud->irq_mask[0]); + LOCAL_HUB_S(PI_INT_MASK1_B, cpud->irq_mask[1]); } } + +/* ----------------------------------------------------------------------- */ diff --git a/arch/mips/sgi-ip27/ip27-irqno.c b/arch/mips/sgi-ip27/ip27-irqno.c index 957ab58..21d20b2 100644 --- a/arch/mips/sgi-ip27/ip27-irqno.c +++ b/arch/mips/sgi-ip27/ip27-irqno.c @@ -11,14 +11,24 @@ static DECLARE_BITMAP(irq_map, NR_IRQS); -int allocate_irqno(void) + +/* ----------------------------------------------------------------------- */ + +/** + * ip27_alloc_irq_num - finds a free irq in irq_map. + * + * Returns the first free IRQ number in irq_map. This IRQ will later + * be linked to a specific HUB interrupt bit. + */ +int +ip27_alloc_irq_num(void) { int irq; again: irq = find_first_zero_bit(irq_map, NR_IRQS); - if (irq >= NR_IRQS) + if (unlikely(irq >= NR_IRQS)) return -ENOSPC; if (test_and_set_bit(irq, irq_map)) @@ -27,22 +37,28 @@ again: return irq; } -/* - * Allocate the 16 legacy interrupts for i8259 devices. This happens early - * in the kernel initialization so treating allocation failure as BUG() is - * ok. +/** + * ip27_assign_irq_num - assign an irq in irq_map. + * @irq: unsigned int of irq to free. */ -void __init alloc_legacy_irqno(void) +void +ip27_assign_irq_num(int irq) { - int i; - - for (i = 0; i <= 16; i++) - BUG_ON(test_and_set_bit(i, irq_map)); + smp_mb__before_atomic(); + set_bit(irq, irq_map); + smp_mb__after_atomic(); } -void free_irqno(unsigned int irq) +/** + * ip27_free_irq_num - free an irq in irq_map and make it available again. + * @irq: unsigned int of irq to free. + */ +void +ip27_free_irq_num(int irq) { smp_mb__before_atomic(); clear_bit(irq, irq_map); smp_mb__after_atomic(); } + +/* ----------------------------------------------------------------------- */ diff --git a/arch/mips/sgi-ip27/ip27-klconfig.c b/arch/mips/sgi-ip27/ip27-klconfig.c index c873d62..c529262 100644 --- a/arch/mips/sgi-ip27/ip27-klconfig.c +++ b/arch/mips/sgi-ip27/ip27-klconfig.c @@ -14,11 +14,20 @@ #include #include -klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type) +/** + * kl_find_component - navigate the available components on an lboard/rboard. + * @brd: + * @kli: + * @struct_type: + * + * Returns the next component from the KLCONFIG structure on SGI SN systems. + */ +struct klc_info * +kl_find_component(struct klc_lboard *brd, struct klc_info *kli, u8 struct_type) { int index, j; - if (kli == (klinfo_t *)NULL) { + if (kli == KLCF_CAST_INFO(NULL)) { index = 0; } else { for (j = 0; j < KLCF_NUM_COMPS(brd); j++) @@ -26,8 +35,8 @@ klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type break; index = j; if (index == KLCF_NUM_COMPS(brd)) { - printk("find_component: Bad pointer: 0x%p\n", kli); - return (klinfo_t *)NULL; + pr_err("KLCONFIG: Bad pointer: 0x%p\n", kli); + return KLCF_CAST_INFO(NULL); } index++; /* next component */ } @@ -39,96 +48,101 @@ klinfo_t *find_component(lboard_t *brd, klinfo_t *kli, unsigned char struct_type } /* Didn't find it. */ - return (klinfo_t *)NULL; + return KLCF_CAST_INFO(NULL); } -klinfo_t *find_first_component(lboard_t *brd, unsigned char struct_type) +struct klc_info * +kl_find_1st_component(struct klc_lboard *brd, u8 struct_type) { - return find_component(brd, (klinfo_t *)NULL, struct_type); + return kl_find_component(brd, KLCF_CAST_INFO(NULL), struct_type); } -lboard_t *find_lboard(lboard_t *start, unsigned char brd_type) +struct klc_lboard * +kl_find_lboard(struct klc_lboard *start, u8 brd_type) { /* Search all boards stored on this node. */ while (start) { - if (start->brd_type == brd_type) + if (start->type == brd_type) return start; start = KLCF_NEXT(start); } /* Didn't find it. */ - return (lboard_t *)NULL; + return KLCF_CAST_LBOARD(NULL); } -lboard_t *find_lboard_class(lboard_t *start, unsigned char brd_type) +struct klc_lboard * +kl_find_lboard_class(struct klc_lboard *start, u8 brd_type) { /* Search all boards stored on this node. */ while (start) { - if (KLCLASS(start->brd_type) == KLCLASS(brd_type)) + if (KLCLASS(start->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); + return KLCF_CAST_LBOARD(NULL); } -klcpu_t *nasid_slice_to_cpuinfo(nasid_t nasid, int slice) +struct klc_cpu * +nasid_slice_to_cpuinfo(nasid_t nasid, int slice) { - lboard_t *brd; - klcpu_t *acpu; + struct klc_lboard *brd; + struct klc_cpu *acpu; - if (!(brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27))) - return (klcpu_t *)NULL; + if (!(brd = kl_find_lboard(KLCF_LBOARD_INFO(nasid), KLTYPE_IP27))) + return KLCF_CAST_CPU(NULL); - if (!(acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU))) - return (klcpu_t *)NULL; + if (!(acpu = KLCF_CAST_CPU(kl_find_1st_component(brd, KLSTRUCT_CPU)))) + return KLCF_CAST_CPU(NULL); do { - if ((acpu->cpu_info.physid) == slice) + if ((acpu->kl_info.physid) == slice) return acpu; - } while ((acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu, - KLSTRUCT_CPU))); - return (klcpu_t *)NULL; + } while ((acpu = KLCF_CAST_CPU(kl_find_component(brd, + KLCF_CAST_INFO(acpu), + KLSTRUCT_CPU)))); + return KLCF_CAST_CPU(NULL); } -klcpu_t *sn_get_cpuinfo(cpuid_t cpu) +static struct klc_cpu * __init +sn_get_cpuinfo(cpuid_t cpu) { nasid_t nasid; int slice; - klcpu_t *acpu; + struct klc_cpu *acpu; gda_t *gdap = GDA; cnodeid_t cnode; - if (!(cpu < MAXCPUS)) { - printk("sn_get_cpuinfo: illegal cpuid 0x%lx\n", cpu); - return NULL; + if (cpu > MAXCPUS) { + pr_err("KLCONFIG: illegal cpuid 0x%lx\n", cpu); + goto err_out; } - cnode = get_cpu_cnode(cpu); + cnode = sn_cpuid_to_cnodeid[cpu]; if (cnode == INVALID_CNODEID) - return NULL; + goto err_out; if ((nasid = gdap->g_nasidtable[cnode]) == INVALID_NASID) - return NULL; + goto err_out; for (slice = 0; slice < CPUS_PER_NODE; slice++) { acpu = nasid_slice_to_cpuinfo(nasid, slice); - if (acpu && acpu->cpu_info.virtid == cpu) + if (acpu && acpu->kl_info.virtid == cpu) return acpu; } - return NULL; + +err_out: + return KLCF_CAST_CPU(NULL); } -int get_cpu_slice(cpuid_t cpu) +int __init +get_cpu_slice(cpuid_t cpu) { - klcpu_t *acpu; + struct klc_cpu *acpu; if ((acpu = sn_get_cpuinfo(cpu)) == NULL) return -1; - return acpu->cpu_info.physid; + + return acpu->kl_info.physid; } diff --git a/arch/mips/sgi-ip27/ip27-klnuma.c b/arch/mips/sgi-ip27/ip27-klnuma.c index bda90cf..5fb7e36 100644 --- a/arch/mips/sgi-ip27/ip27-klnuma.c +++ b/arch/mips/sgi-ip27/ip27-klnuma.c @@ -26,7 +26,8 @@ static cpumask_t ktext_repmask; * 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) +void __init +setup_replication_mask(void) { /* Set only the master cnode's bit. The master cnode is always 0. */ cpumask_clear(&ktext_repmask); @@ -52,7 +53,8 @@ void __init setup_replication_mask(void) } -static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid) +static void __init +set_ktext_source(nasid_t client_nasid, nasid_t server_nasid) { kern_vars_t *kvp; @@ -69,7 +71,8 @@ static __init void set_ktext_source(nasid_t client_nasid, nasid_t server_nasid) } /* XXX - When the BTE works, we should use it instead of this. */ -static __init void copy_kernel(nasid_t dest_nasid) +static void __init +copy_kernel(nasid_t dest_nasid) { unsigned long dest_kern_start, source_start, source_end, kern_size; @@ -82,7 +85,8 @@ static __init void copy_kernel(nasid_t dest_nasid) memcpy((void *)dest_kern_start, (void *)source_start, kern_size); } -void __init replicate_kernel_text() +void __init +replicate_kernel_text() { cnodeid_t cnode; nasid_t client_nasid; @@ -96,7 +100,7 @@ void __init replicate_kernel_text() for_each_online_node(cnode) { if (cnode == 0) continue; - client_nasid = COMPACT_TO_NASID_NODEID(cnode); + client_nasid = sn_cnodeid_to_nasid[cnode]; /* Check if this node should get a copy of the kernel */ if (cpumask_test_cpu(cnode, &ktext_repmask)) { @@ -114,11 +118,12 @@ void __init replicate_kernel_text() * 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 +node_get_first_free(cnodeid_t cnode) { - unsigned long loadbase = REP_BASE; - nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); unsigned long offset; + unsigned long loadbase = REP_BASE; + nasid_t nasid = sn_cnodeid_to_nasid[cnode]; #ifdef CONFIG_MAPPED_KERNEL loadbase += 16777216; diff --git a/arch/mips/sgi-ip27/ip27-memory.c b/arch/mips/sgi-ip27/ip27-memory.c index f1f8829..6b39ad46 100644 --- a/arch/mips/sgi-ip27/ip27-memory.c +++ b/arch/mips/sgi-ip27/ip27-memory.c @@ -7,8 +7,8 @@ * Copyright (C) 2000 by Silicon Graphics, Inc. * Copyright (C) 2004 by Christoph Hellwig * - * On SGI IP27 the ARC memory configuration data is completely bogus but - * alternate easier to use mechanisms are available. + * On SGI IP27, the ARC memory configuration data is completely bogus. But + * KLCONFIG is an alternate and easier to use mechanism. */ #include #include @@ -31,135 +31,153 @@ #include -#define SLOT_PFNSHIFT (SLOT_SHIFT - PAGE_SHIFT) -#define PFN_NASIDSHFT (NASID_SHFT - PAGE_SHIFT) +#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) +static int fine_mode __initdata; + +static int __init +ip27_mem_is_fine_dir_mode(void) { - return ((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE; + return ((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_REGIONSIZE_MASK) + >> NSRI_REGIONSIZE_SHFT) & REGIONSIZE_FINE; } -static hubreg_t get_region(cnodeid_t cnode) +static hubreg_t __init +ip27_mem_get_region(cnodeid_t cnode) { if (fine_mode) - return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_FINEREG_SHFT; + return (sn_cnodeid_to_nasid[cnode] + >> NASID_TO_FINEREG_SHFT); else - return COMPACT_TO_NASID_NODEID(cnode) >> NASID_TO_COARSEREG_SHFT; + return (sn_cnodeid_to_nasid[cnode] + >> NASID_TO_COARSEREG_SHFT); } -static hubreg_t region_mask; +static hubreg_t region_mask __initdata; -static void gen_region_mask(hubreg_t *region_mask) +static void __init +ip27_mem_gen_region_mask(hubreg_t *region_mask) { cnodeid_t cnode; (*region_mask) = 0; for_each_online_node(cnode) { - (*region_mask) |= 1ULL << get_region(cnode); + (*region_mask) |= BIT_ULL(ip27_mem_get_region(cnode)); } } -#define rou_rflag rou_flags -static int router_distance; +/* XXX: Move to new source file 'ip27-topology.c' */ +static int router_distance __initdata; -static void router_recurse(klrou_t *router_a, klrou_t *router_b, int depth) +/* XXX: Move to new source file 'ip27-topology.c' */ +static void __init +ip27_topo_router_recurse(struct klc_router *router_a, struct klc_router *router_b, + int depth) { - klrou_t *router; - lboard_t *brd; - int port; + int port; + struct klc_router *router; + struct klc_lboard *brd; + struct klc_port *rport; - if (router_a->rou_rflag == 1) + if (router_a->flags == 1) return; if (depth >= router_distance) return; - router_a->rou_rflag = 1; + router_a->flags = 1; for (port = 1; port <= MAX_ROUTER_PORTS; port++) { - if (router_a->rou_port[port].port_nasid == INVALID_NASID) + rport = &router_a->port[port]; + if (rport->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); + brd = KLCF_LBOARD_K0(rport->nasid, rport->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); + if (KLCF_TYPE(brd) != KLTYPE_ROUTER) + continue; + + router = KLCF_ROUTER_K0(brd, brd->components[0]); + if (router == router_b) { + if (depth < router_distance) + router_distance = depth; + } else { + ip27_topo_router_recurse(router, router_b, depth + 1); } } - router_a->rou_rflag = 0; + router_a->flags = 0; } +/* XXX: Move to new source file 'ip27-topology.c' */ 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) +/* XXX: Move to new source file 'ip27-topology.c' */ +static int __init +ip27_topo_calc_node_distance(nasid_t nasid_a, nasid_t nasid_b) { - klrou_t *router, *router_a = NULL, *router_b = NULL; - lboard_t *brd, *dest_brd; + int port; cnodeid_t cnode; nasid_t nasid; - int port; + struct klc_port *rport; + struct klc_lboard *brd, *dest_brd; + struct klc_router *router, *router_a = NULL, *router_b = NULL; /* Figure out which routers nodes in question are connected to */ for_each_online_node(cnode) { - nasid = COMPACT_TO_NASID_NODEID(cnode); + nasid = sn_cnodeid_to_nasid[cnode]; if (nasid == -1) continue; - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); + brd = kl_find_lboard_class(KLCF_LBOARD_INFO(nasid), + KLTYPE_ROUTER); if (!brd) continue; do { - if (brd->brd_flags & DUPLICATE_BOARD) + if (KL_CONFIG_DUPLICATE_BOARD(brd)) continue; - router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]); - router->rou_rflag = 0; + router = KLCF_ROUTER_K0(brd, brd->components[0]); + router->flags = 0; for (port = 1; port <= MAX_ROUTER_PORTS; port++) { - if (router->rou_port[port].port_nasid == INVALID_NASID) + rport = &router->port[port]; + if (rport->nasid == INVALID_NASID) + continue; + + dest_brd = KLCF_LBOARD_K0(rport->nasid, + rport->offset); + + if (KLCF_TYPE(dest_brd) != KLTYPE_IP27) continue; - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - router->rou_port[port].port_nasid, - router->rou_port[port].port_offset); + if (KLCF_BOARD_NASID(dest_brd) == nasid_a) + router_a = router; - 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; - } + if (KLCF_BOARD_NASID(dest_brd) == nasid_b) + router_b = router; } - } while ((brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER))); + } while ((brd = kl_find_lboard_class(KLCF_NEXT(brd), + KLTYPE_ROUTER))); } if (router_a == NULL) { - printk("node_distance: router_a NULL\n"); + pr_debug("IP27: Router A is NULL\n"); return -1; } + if (router_b == NULL) { - printk("node_distance: router_b NULL\n"); + pr_debug("IP27: Router B is NULL\n"); return -1; } @@ -170,14 +188,16 @@ static int __init compute_node_distance(nasid_t nasid_a, nasid_t nasid_b) return 1; router_distance = 100; - router_recurse(router_a, router_b, 2); + ip27_topo_router_recurse(router_a, router_b, 2); return router_distance; } -static void __init init_topology_matrix(void) +/* XXX: Move to new source file 'ip27-topology.c' */ +static void __init +ip27_topo_init_matrix(void) { - nasid_t nasid, nasid2; + nasid_t nasid1, nasid2; cnodeid_t row, col; for (row = 0; row < MAX_COMPACT_NODES; row++) @@ -185,137 +205,141 @@ static void __init init_topology_matrix(void) __node_distances[row][col] = -1; for_each_online_node(row) { - nasid = COMPACT_TO_NASID_NODEID(row); + nasid1 = sn_cnodeid_to_nasid[row]; for_each_online_node(col) { - nasid2 = COMPACT_TO_NASID_NODEID(col); + nasid2 = sn_cnodeid_to_nasid[col]; __node_distances[row][col] = - compute_node_distance(nasid, nasid2); + ip27_topo_calc_node_distance(nasid1, nasid2); } } } -static void __init dump_topology(void) +/* XXX: Move to new source file 'ip27-topology.c' */ +static void __init +ip27_topo_dump_matrix(void) { + int port, router_num = 0; nasid_t nasid; - cnodeid_t cnode; - lboard_t *brd, *dest_brd; - int port; - int router_num = 0; - klrou_t *router; - cnodeid_t row, col; + cnodeid_t cnode, row, col; + struct klc_router *router; + struct klc_port *rport; + struct klc_lboard *brd, *dest_brd; - printk("************** Topology ********************\n"); + pr_info("************** Topology ********************\n"); - printk(" "); + pr_cont(" "); for_each_online_node(col) - printk("%02d ", col); - printk("\n"); + pr_cont("%02d ", col); + pr_cont("\n"); for_each_online_node(row) { - printk("%02d ", row); + pr_cont("%02d ", row); for_each_online_node(col) - printk("%2d ", node_distance(row, col)); - printk("\n"); + pr_cont("%2d ", node_distance(row, col)); + pr_cont("\n"); } for_each_online_node(cnode) { - nasid = COMPACT_TO_NASID_NODEID(cnode); + nasid = sn_cnodeid_to_nasid[cnode]; if (nasid == -1) continue; - brd = find_lboard_class((lboard_t *)KL_CONFIG_INFO(nasid), - KLTYPE_ROUTER); + brd = kl_find_lboard_class(KLCF_LBOARD_INFO(nasid), + KLTYPE_ROUTER); if (!brd) continue; do { - if (brd->brd_flags & DUPLICATE_BOARD) + if (KL_CONFIG_DUPLICATE_BOARD(brd)) continue; - printk("Router %d:", router_num); + pr_cont("Router %d:", router_num); router_num++; - router = (klrou_t *)NODE_OFFSET_TO_K0(NASID_GET(brd), brd->brd_compts[0]); + router = KLCF_ROUTER_K0(brd, brd->components[0]); for (port = 1; port <= MAX_ROUTER_PORTS; port++) { - if (router->rou_port[port].port_nasid == INVALID_NASID) + rport = &router->port[port]; + if (rport->nasid == INVALID_NASID) continue; - dest_brd = (lboard_t *)NODE_OFFSET_TO_K0( - router->rou_port[port].port_nasid, - router->rou_port[port].port_offset); + dest_brd = KLCF_LBOARD_K0(rport->nasid, + rport->offset); - if (dest_brd->brd_type == KLTYPE_IP27) - printk(" %d", dest_brd->brd_nasid); - if (dest_brd->brd_type == KLTYPE_ROUTER) - printk(" r"); + if (KLCF_TYPE(dest_brd) == KLTYPE_IP27) + pr_cont(" %d", KLCF_BOARD_NASID(dest_brd)); + + if (KLCF_TYPE(dest_brd) == KLTYPE_ROUTER) + pr_cont(" r"); } - printk("\n"); + pr_cont("\n"); - } while ( (brd = find_lboard_class(KLCF_NEXT(brd), KLTYPE_ROUTER)) ); + } while ((brd = kl_find_lboard_class(KLCF_NEXT(brd), + KLTYPE_ROUTER))); } } -static unsigned long __init slot_getbasepfn(cnodeid_t cnode, int slot) +static u64 __init +ip27_mem_slot_getbasepfn(cnodeid_t cnode, int slot) { - nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode); + nasid_t nasid = sn_cnodeid_to_nasid[cnode]; - return ((unsigned long)nasid << PFN_NASIDSHFT) | (slot << SLOT_PFNSHIFT); + return (((u64)nasid << PFN_NASIDSHFT) | + (slot << SLOT_PFNSHIFT)); } -static unsigned long __init slot_psize_compute(cnodeid_t node, int slot) +static u64 __init +ip27_mem_slot_calc_psize(cnodeid_t cnode, int slot) { + u64 size; nasid_t nasid; - lboard_t *brd; - klmembnk_t *banks; - unsigned long size; + struct klc_lboard *brd; + struct klc_membank *banks; - nasid = COMPACT_TO_NASID_NODEID(node); + nasid = sn_cnodeid_to_nasid[cnode]; /* Find the node board */ - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); + brd = kl_find_lboard(KLCF_LBOARD_INFO(nasid), KLTYPE_IP27); if (!brd) return 0; /* Get the memory bank structure */ - banks = (klmembnk_t *) find_first_component(brd, KLSTRUCT_MEMBNK); + banks = KLCF_CAST_MEMBANK(kl_find_1st_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 + size = (u64)KLCF_MEMBANK_SIZE(banks, (slot / 4)); + + /* XXX: Hack for 128MB dimm banks */ + if (size <= 128) + if ((slot % 4) == 0) + return PFN_DOWN((size << 20)); + else return 0; - } else { - size /= 4; - size <<= 20; - return size >> PAGE_SHIFT; - } + else + return PFN_DOWN(((size / 4) << 20)); } -static void __init mlreset(void) +/* XXX: Move to file 'ip27-init.c' */ +static void __init +ip27_machine_init(void) { int i; - master_nasid = get_nasid(); - fine_mode = is_fine_dirmode(); + master_nasid = ip27_get_nasid(); + fine_mode = ip27_mem_is_fine_dir_mode(); /* * 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(); + ip27_smp_cpu_node_probe(); #endif - init_topology_matrix(); - dump_topology(); + ip27_topo_init_matrix(); + ip27_topo_dump_matrix(); - gen_region_mask(®ion_mask); + ip27_mem_gen_region_mask(®ion_mask); setup_replication_mask(); @@ -325,7 +349,7 @@ static void __init mlreset(void) for_each_online_node(i) { nasid_t nasid; - nasid = COMPACT_TO_NASID_NODEID(i); + nasid = sn_cnodeid_to_nasid[i]; /* * Always have node 0 in the region mask, otherwise @@ -351,78 +375,84 @@ static void __init mlreset(void) } } -static void __init szmem(void) +static void __init +ip27_mem_init(void) { - unsigned long slot_psize, slot0sz = 0, nodebytes; /* Hack to detect problem configs */ - int slot; - cnodeid_t node; + /* Hack to detect problem configs */ + u32 slot; + u64 slot_psize, slot0_size = 0, slot_basepfn; + u64 node_bytes, node_page; + cnodeid_t cnode; - for_each_online_node(node) { - nodebytes = 0; + for_each_online_node(cnode) { + node_bytes = 0; for (slot = 0; slot < MAX_MEM_SLOTS; slot++) { - slot_psize = slot_psize_compute(node, slot); + slot_psize = ip27_mem_slot_calc_psize(cnode, slot); if (slot == 0) - slot0sz = slot_psize; + slot0_size = (PFN_PHYS(slot_psize)); /* - * We need to refine the hack when we have replicated - * kernel text. + * XXX: We need to refine this hack when we have + * replicated kernel text. */ - nodebytes += (1LL << SLOT_SHIFT); + node_bytes += BIT_ULL(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); + node_page = PFN_DOWN(node_bytes); + if ((node_page * sizeof(struct page)) > slot0_size) { + pr_notice("IP27: Ignoring memory slot %d and " + "up on cnode %d\n", slot, cnode); slot = MAX_MEM_SLOTS; continue; } - memblock_add_node(PFN_PHYS(slot_getbasepfn(node, slot)), - PFN_PHYS(slot_psize), node); + slot_basepfn = ip27_mem_slot_getbasepfn(cnode, slot); + memblock_add_node(PFN_PHYS(slot_basepfn), + PFN_PHYS(slot_psize), cnode); } } } -static void __init node_mem_init(cnodeid_t node) +static void __init +ip27_mem_node_init(cnodeid_t cnode) { - unsigned long slot_firstpfn = slot_getbasepfn(node, 0); - unsigned long slot_freepfn = node_getfirstfree(node); + unsigned long slot_firstpfn = ip27_mem_slot_getbasepfn(cnode, 0); + unsigned long slot_freepfn = node_get_first_free(cnode); unsigned long bootmap_size; unsigned long start_pfn, end_pfn; - get_pfn_range_for_nid(node, &start_pfn, &end_pfn); + get_pfn_range_for_nid(cnode, &start_pfn, &end_pfn); /* - * Allocate the node data structures on the node first. + * Allocate the node data structures on the cnode first. */ - __node_data[node] = __va(slot_freepfn << PAGE_SHIFT); - memset(__node_data[node], 0, PAGE_SIZE); + __node_data[cnode] = __va(PFN_PHYS(slot_freepfn)); + memset(__node_data[cnode], 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; + NODE_DATA(cnode)->bdata = &bootmem_node_data[cnode]; + NODE_DATA(cnode)->node_start_pfn = start_pfn; + NODE_DATA(cnode)->node_spanned_pages = end_pfn - start_pfn; - cpumask_clear(&hub_data(node)->h_cpus); + cpumask_clear(&hub_data(cnode)->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, + bootmap_size = init_bootmem_node(NODE_DATA(cnode), slot_freepfn, + start_pfn, end_pfn); + free_bootmem_with_active_regions(cnode, end_pfn); + reserve_bootmem_node(NODE_DATA(cnode), PFN_PHYS(slot_firstpfn), + (PFN_PHYS(slot_freepfn - slot_firstpfn) + bootmap_size), BOOTMEM_DEFAULT); - sparse_memory_present_with_active_regions(node); + sparse_memory_present_with_active_regions(cnode); } /* - * A node with nothing. We use it to avoid any special casing in - * cpumask_of_node + * A node with nothing. We use it to avoid any special casing in + * cpumask_of_node. */ -static struct node_data null_node = { +static struct node_data +ip27_mem_null_node = { .hub = { .h_cpus = CPU_MASK_NONE } @@ -430,33 +460,36 @@ static struct node_data null_node = { /* * 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. + * contains at least 32MB of memory. We assume all bootmem data fits + * on the first slot. */ -void __init prom_meminit(void) +void __init +prom_meminit(void) { - cnodeid_t node; + cnodeid_t cnode; - mlreset(); - szmem(); + ip27_machine_init(); + ip27_mem_init(); - for (node = 0; node < MAX_COMPACT_NODES; node++) { - if (node_online(node)) { - node_mem_init(node); + for (cnode = 0; cnode < MAX_COMPACT_NODES; cnode++) { + if (node_online(cnode)) { + ip27_mem_node_init(cnode); continue; } - __node_data[node] = &null_node; + __node_data[cnode] = &ip27_mem_null_node; } } -void __init prom_free_prom_memory(void) +void __init +prom_free_prom_memory(void) { /* We got nothing to free here ... */ } extern void setup_zero_pages(void); -void __init paging_init(void) +void __init +paging_init(void) { unsigned long zones_size[MAX_NR_ZONES] = {0, }; unsigned node; @@ -475,9 +508,10 @@ void __init paging_init(void) free_area_init_nodes(zones_size); } -void __init mem_init(void) +void __init +mem_init(void) { - high_memory = (void *) __va(get_num_physpages() << PAGE_SHIFT); + high_memory = (void *) __va(PFN_PHYS(get_num_physpages())); free_all_bootmem(); setup_zero_pages(); /* This comes from node 0 */ mem_init_print_info(NULL); diff --git a/arch/mips/sgi-ip27/ip27-nmi.c b/arch/mips/sgi-ip27/ip27-nmi.c index a2358b4..6576eafa 100644 --- a/arch/mips/sgi-ip27/ip27-nmi.c +++ b/arch/mips/sgi-ip27/ip27-nmi.c @@ -1,14 +1,30 @@ +/* + * 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. + */ + #include #include #include #include #include #include -#include + #include -#include #include +#include +#include +#include +#include +#include +#include + +#include #include +#include +#include +#include #if 0 #define NODE_NUM_CPUS(n) CNODE_NUM_CPUS(n) @@ -25,18 +41,20 @@ 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 +nmi_dump(void) { void cont_nmi_dump(void); cont_nmi_dump(); } -void install_cpu_nmi_handler(int slice) +void __init +ip27_install_cpu_nmi_handler(int slice) { nmi_t *nmi_addr; - nmi_addr = (nmi_t *)NMI_ADDR(get_nasid(), slice); + nmi_addr = (nmi_t *)NMI_ADDR(ip27_get_nasid(), slice); if (nmi_addr->call_addr) return; nmi_addr->magic = NMI_MAGIC; @@ -51,90 +69,94 @@ void install_cpu_nmi_handler(int slice) * into the eframe format for the node under consideration. */ -void nmi_cpu_eframe_save(nasid_t nasid, int slice) +void +nmi_cpu_eframe_save(nasid_t nasid, int slice) { + int i; 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); + pr_crit("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]); + pr_cont("$%2d :", i); + pr_cont(" %016lx", nr->gpr[i]); i++; if ((i % 4) == 0) - printk("\n"); + pr_cont("\n"); } - printk("Hi : (value lost)\n"); - printk("Lo : (value lost)\n"); + pr_cont("Hi : (value lost)\n"); + pr_cont("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); + pr_cont("epc : %016lx %pS\n", nr->epc, (void *) nr->epc); + pr_cont("%s\n", print_tainted()); + pr_cont("ErrEPC: %016lx %pS\n", nr->error_epc, (void *) nr->error_epc); + pr_cont("ra : %016lx %pS\n", nr->gpr[31], (void *) nr->gpr[31]); + pr_cont("Status: %08lx ", nr->sr); if (nr->sr & ST0_KX) - printk("KX "); + pr_cont("KX "); if (nr->sr & ST0_SX) - printk("SX "); + pr_cont("SX "); if (nr->sr & ST0_UX) - printk("UX "); + pr_cont("UX "); switch (nr->sr & ST0_KSU) { case KSU_USER: - printk("USER "); + pr_cont("USER "); break; case KSU_SUPERVISOR: - printk("SUPERVISOR "); + pr_cont("SUPERVISOR "); break; case KSU_KERNEL: - printk("KERNEL "); + pr_cont("KERNEL "); break; default: - printk("BAD_MODE "); + pr_cont("BAD_MODE "); break; } if (nr->sr & ST0_ERL) - printk("ERL "); + pr_cont("ERL "); if (nr->sr & ST0_EXL) - printk("EXL "); + pr_cont("EXL "); if (nr->sr & ST0_IE) - printk("IE "); - printk("\n"); + pr_cont("IE "); + pr_cont("\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); + pr_cont("Cause : %08lx\n", nr->cause); + pr_cont("PrId : %08x\n", read_c0_prid()); + pr_cont("BadVA : %016lx\n", nr->badva); + pr_cont("CErr : %016lx\n", nr->cache_err); + pr_cont("NMI_SR: %016lx\n", nr->nmi_sr); - printk("\n"); + pr_cont("\n"); } -void nmi_dump_hub_irq(nasid_t nasid, int slice) +void +nmi_dump_hub_irq(nasid_t nasid, int slice) { hubreg_t mask0, mask1, pend0, pend1; - if (slice == 0) { /* Slice A */ + 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 */ + } else { + /* Slice B */ mask0 = REMOTE_HUB_L(nasid, PI_INT_MASK0_B); mask1 = REMOTE_HUB_L(nasid, PI_INT_MASK1_B); } @@ -142,16 +164,18 @@ void nmi_dump_hub_irq(nasid_t nasid, int slice) 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"); + pr_crit("PI_INT_PEND0: 0x%.16llx, " + "PI_INT_MASK0: 0x%.16llx\n", pend0, mask0); + pr_crit("PI_INT_PEND1: 0x%.16llx, " + "PI_INT_MASK1: 0x%.16llx\n\n", pend1, mask1); } /* * 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) +void +nmi_node_eframe_save(cnodeid_t cnode) { nasid_t nasid; int slice; @@ -160,7 +184,7 @@ void nmi_node_eframe_save(cnodeid_t cnode) if (cnode == CNODEID_NONE) return; - nasid = COMPACT_TO_NASID_NODEID(cnode); + nasid = sn_cnodeid_to_nasid[cnode]; if (nasid == INVALID_NASID) return; @@ -186,7 +210,10 @@ nmi_eframes_save(void) void cont_nmi_dump(void) { -#ifndef REAL_NMI_SIGNAL +#if 0 /* LATER */ + s8 slice; + nasid_t nasid; +#else static atomic_t nmied_cpus = ATOMIC_INIT(0); atomic_inc(&nmied_cpus); @@ -196,49 +223,54 @@ cont_nmi_dump(void) */ arch_spin_lock(&nmi_lock); -#ifdef REAL_NMI_SIGNAL +#if 0 /* LATER */ + /* XXX: Needs a lot of work. Copy missing bits from IA64. */ + /* * 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. + * - Sometimes an MMSC fails to NMI all cpus. + * - On a 512p SN0 system, the MMSC will only send NMIs to + * half the cpus. Unfortunately, we don't know which cpus + * may be NMI'ed, as 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 + * Note: it has been measured 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 (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))); - } + for_each_online_node(node) { + if (NODEPDA(node)->dump_count != 0) + continue; + + cpu = cpumask_first(cpumask_of_node(node)); + for (n = 0; n < CNODE_NUM_CPUS(node); cpu++, n++) { + CPUMASK_SETB(nmied_cpus, cpu); + slice = per_cpu(ip27_cpu, cpu).slice; + nasid = per_cpu(ip27_cpu, cpu).nasid; + SEND_NMI(nasid, slice); } - + } } udelay(10000); } #else - while (atomic_read(&nmied_cpus) != num_online_cpus()); + while (atomic_read(&nmied_cpus) != num_online_cpus()) + cpu_relax(); #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); + LOCAL_HUB_S(NI_PORT_RESET, (NPR_PORTRESET | NPR_LOCALRESET)); } diff --git a/arch/mips/sgi-ip27/ip27-reset.c b/arch/mips/sgi-ip27/ip27-reset.c index e44a15d..578363a 100644 --- a/arch/mips/sgi-ip27/ip27-reset.c +++ b/arch/mips/sgi-ip27/ip27-reset.c @@ -33,7 +33,8 @@ void machine_power_off(void) __noreturn; #define noreturn while(1); /* Silence gcc. */ /* XXX How to pass the reboot command to the firmware??? */ -static void ip27_machine_restart(char *command) +static void +ip27_machine_restart(char *command) { #if 0 int i; @@ -45,15 +46,16 @@ static void ip27_machine_restart(char *command) #endif #if 0 for_each_online_node(i) - REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG, - PROMOP_REBOOT); + REMOTE_HUB_S(sn_cnodeid_to_nasid[i], PROMOP_REG, + PROMOP_REBOOT); #else LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); #endif noreturn; } -static void ip27_machine_halt(void) +static void +ip27_machine_halt(void) { int i; @@ -61,19 +63,21 @@ static void ip27_machine_halt(void) smp_send_stop(); #endif for_each_online_node(i) - REMOTE_HUB_S(COMPACT_TO_NASID_NODEID(i), PROMOP_REG, - PROMOP_RESTART); + REMOTE_HUB_S(sn_cnodeid_to_nasid[i], PROMOP_REG, + PROMOP_RESTART); LOCAL_HUB_S(NI_PORT_RESET, NPR_PORTRESET | NPR_LOCALRESET); noreturn; } -static void ip27_machine_power_off(void) +static void +ip27_machine_power_off(void) { /* To do ... */ noreturn; } -void ip27_reboot_setup(void) +void +ip27_reboot_setup(void) { _machine_restart = ip27_machine_restart; _machine_halt = ip27_machine_halt; diff --git a/arch/mips/sgi-ip27/ip27-rtc.c b/arch/mips/sgi-ip27/ip27-rtc.c new file mode 100644 index 0000000..e9b9af4 --- /dev/null +++ b/arch/mips/sgi-ip27/ip27-rtc.c @@ -0,0 +1,140 @@ +/* + * 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. + * + * ip27-rtc.c: RTC submodule for the IOC3 metadriver for IP27. + * + * Copyright (C) 2014, 2016 Joshua Kinard + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * On IP27, the RTC is hidden behind the IOC3 device, attached to a generic + * ByteBus. Use klconfig routines to safely map to the start address of the + * RTC area in ByteBus DEV0. + */ +#define IP27_RTC_RES_START \ + (XPHYSADDR(KL_CONFIG_CONS_INFO(master_nasid)->memory_base + \ + IOC3_BYTEBUS_DEV0)) +#define IP27_RTC_RES_END (IP27_RTC_RES_START + 32767) + +static struct ioc3_driver_data *ioc3; +static struct resource ip27_rtc_resources[1]; +static int ip27_rtc_probed = 0; + +/** + * ip27_rtc_read - read a value from an rtc register. + * @rtc: pointer to the m48t35 rtc structure. + * @reg: the register address to read. + */ +u8 +ip27_rtc_read(struct m48t35_priv *rtc, int reg) +{ + return readb(((u8 __iomem *)(((u64)(rtc->regs + reg)) ^ 3))); +} + +/** + * ip27_rtc_write - write a value to an rtc register. + * @rtc: pointer to the m48t35 rtc structure. + * @reg: the register address to write. + * @value: value to write to the register. + */ +void +ip27_rtc_write(struct m48t35_priv *rtc, int reg, u8 value) +{ + writeb(value, ((u8 __iomem *)(((u64)(rtc->regs + reg)) ^ 3))); +} + +static struct m48t35_rtc_platform_data +ip27_rtc_platform_data[] = { + { + /* + * XXX: set req_mem_region to true after ioc3 resource + * conflicts are resolved. + */ + .req_mem_region = false, + .plat_read = ip27_rtc_read, + .plat_write = ip27_rtc_write, + }, +}; + +static struct platform_device +ip27_rtc_device = { + .name = "rtc-m48t35", + .id = -1, + .dev = { + .platform_data = ip27_rtc_platform_data, + }, + .num_resources = ARRAY_SIZE(ip27_rtc_resources), + .resource = ip27_rtc_resources, +}; + + +/* IOC3 Metadriver probe/remove */ +static int +ip27_ioc3_rtc_probe(struct ioc3_submodule *is, struct ioc3_driver_data *idd) +{ + int ret; + + /* This code only applies to an Origin/Onyx2 */ + if (ioc3 || (idd->class != IOC3_CLASS_BASE_IP27)) + return 1; + + ioc3 = idd; + + if (ip27_rtc_probed) + return 0; + + ip27_rtc_resources[0].start = IP27_RTC_RES_START, + ip27_rtc_resources[0].end = IP27_RTC_RES_END, + ip27_rtc_resources[0].flags = IORESOURCE_MEM, + + ret = platform_device_register(&ip27_rtc_device); + ip27_rtc_probed = 1; + + return ret; +} + + +static int +ip27_ioc3_rtc_remove(struct ioc3_submodule *is, struct ioc3_driver_data *idd) +{ + if (ioc3 != idd) + return 1; + + platform_device_unregister(&ip27_rtc_device); + ioc3 = NULL; + + return 0; +} + + +/* entry/exit functions */ +static struct ioc3_submodule +ip27_ioc3_rtc_submodule = { + .name = "rtc", + .probe = ip27_ioc3_rtc_probe, + .remove = ip27_ioc3_rtc_remove, + .owner = THIS_MODULE, +}; + +ioc3_submodule_driver(ip27_ioc3_rtc_submodule); + +MODULE_AUTHOR("Joshua Kinard "); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("IP27 RTC Submodule for IOC3"); diff --git a/arch/mips/sgi-ip27/ip27-smp.c b/arch/mips/sgi-ip27/ip27-smp.c index f9ae6a8..64d84b1 100644 --- a/arch/mips/sgi-ip27/ip27-smp.c +++ b/arch/mips/sgi-ip27/ip27-smp.c @@ -7,10 +7,18 @@ * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc. */ #include -#include +#include +#include #include +#include +#include + +#include +#include #include #include +#include + #include #include #include @@ -19,82 +27,371 @@ #include #include #include + #include #include #include -/* - * Takes as first input the PROM assigned cpu id, and the kernel - * assigned cpu id as the second. +extern void generic_smp_call_function_interrupt(void); +extern void scheduler_ipi(void); + +/* Defined in ip27-init.c */ +DECLARE_PER_CPU(struct ip27_percpu_data, ip27_cpu); + + +/* ----------------------------------------------------------------------- */ +/* SMP IPI Ops */ + +/** + * ip27_smp_send_ipi_single - Send an action to another CPU via IPI. + * @cpu: integer CPU to send IPI to with action. + * @action: u32 integer containing list of actions to take OR'ed together. + * + * Runs on CPUx and sends an IPI to CPUy. + */ +static void +ip27_smp_send_ipi_single(int cpu, u32 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("IP27: Unknown action value in %s!\n", __func__); + } + + irq += per_cpu(ip27_cpu, cpu).slice; + + /* + * 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(per_cpu(ip27_cpu, cpu).cnodeid, irq); +} + +/** + * ip27_smp_send_ipi_mask - Send an action to many CPUs via IPI. + * @mask: cpumask of CPUs to send IPI to with action. + * @action: u32 integer containing list of actions to take OR'ed together. + */ +static void +ip27_smp_send_ipi_mask(const struct cpumask *mask, u32 action) +{ + unsigned int i; + + for_each_cpu(i, mask) + ip27_smp_send_ipi_single(i, action); +} + +/** + * ip27_smp_ipi_irq - IRQ handler that runs on CPUy and services the IPI. + * @irq: integer of IRQ# for IPI being serviced. + * @dev_id: void pointer to dev_id data. + */ +static irqreturn_t +ip27_smp_ipi_irq(int irq, void *dev_id) +{ + int hub_bit; + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); + + if (!cpud->irq_owner[irq]) + return IRQ_NONE; + else + hub_bit = cpud->hub->irq_to_bit[irq]; + + /* Kernel statistics. */ + kstat_incr_irq_this_cpu(irq); + + switch (hub_bit) { + case CPU_RESCHED_A_IRQ: + case CPU_RESCHED_B_IRQ: + scheduler_ipi(); + break; + case CPU_CALL_A_IRQ: + case CPU_CALL_B_IRQ: + generic_smp_call_function_interrupt(); + break; + default: + panic("IP27: Received unknown SMP IPI IRQ %d on " + "CPU %d%c (CPU%d)!", irq, (cpud->nasid + 1), + IP27_CPU_SLICE(cpud->slice), cpud->id); + } + + return IRQ_HANDLED; +} + +/* ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- */ +/* SMP CPU Bringup - CPU0 Code */ + +/** + * ip27_smp_setup - performs housekeeping on each CPU as it comes online. + */ +static void __init +ip27_smp_setup(void) +{ + cnodeid_t cnode; + nasid_t nasid; + int i; + + for_each_online_node(cnode) { + if (cnode == 0) + continue; + + nasid = sn_cnodeid_to_nasid[cnode]; + + 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 < BITS_PER_HUB; i++) + REMOTE_HUB_CLR_INTR(nasid, i); + } + + replicate_kernel_text(); +} + +/** + * Used to request IRQs. + */ +DEFINE_PER_CPU(char [9], ip27_ipi_r_name); +DEFINE_PER_CPU(char [9], ip27_ipi_c_name); + +/** + * ip27_smp_prepare_cpus - requests CPU0 IPI interrupt. + * @max_cpus: unused by IP27 SMP code. + * + * Runs on CPU0 + */ +static void __init +ip27_smp_prepare_cpus(unsigned int max_cpus) +{ + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); + unsigned long irq_flags = (IRQF_PERCPU | IRQF_SHARED); + u8 *ipi_r_name = per_cpu(ip27_ipi_r_name, cpud->id); + u8 *ipi_c_name = per_cpu(ip27_ipi_c_name, cpud->id); + + /* Request IRQ numbers for the CPU IPI bits. */ + sprintf(ipi_r_name, "%dA-rsch", (cpud->nasid + 1)); + sprintf(ipi_c_name, "%dA-call", (cpud->nasid + 1)); + if (request_irq(CPU_RESCHED_A_IRQ, ip27_smp_ipi_irq, irq_flags, + ipi_r_name, ip27_smp_ipi_irq)) + panic("IP27: Can't request CPU%d " + "CPU_RESCHED_A_IRQ IPI", cpud->id); + if (request_irq(CPU_CALL_A_IRQ, ip27_smp_ipi_irq, irq_flags, + ipi_c_name, ip27_smp_ipi_irq)) + panic("IP27: Can't request CPU%d " + "CPU_CALL_A_IRQ IPI", cpud->id); +} + +/** + * ip27_smp_boot_secondary - boots remaining CPUs into smp_bootstrap. + * @cpu: integer of CPUx to prepare before booting. + * @idle: struct task_struct containing idle task for CPUx. + * + * Runs on CPU0 and boots CPUx, where x > 0 + */ +static void __init +ip27_smp_boot_secondary(int cpu, struct task_struct *idle) +{ + cnodeid_t cnode = sn_cpuid_to_cnodeid[cpu]; + nasid_t nasid = sn_cnodeid_to_nasid[cnode]; + unsigned long gp = (unsigned long)task_thread_info(idle); + unsigned long sp = __KSTK_TOS(idle); + + LAUNCH_SLAVE(nasid, get_cpu_slice(cpu), + (launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap), + 0, (void *) sp, (void *) gp); + + /* Kick the CPU awake. */ + mb(); + +} + +/* ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- */ +/* SMP CPU Bringup - CPUx Code */ + +/** + * ip27_smp_init_secondary - requests CPUs's IPI IRQ and unmasks interrupts. + * + * Runs on CPUx, where x > 0, after cache probe. */ -static void alloc_cpupda(cpuid_t cpu, int cpunum) +static void __init +ip27_smp_init_secondary(void) { - cnodeid_t node = get_cpu_cnode(cpu); - nasid_t nasid = COMPACT_TO_NASID_NODEID(node); + const struct ip27_percpu_data *cpud; + unsigned long irq_flags = (IRQF_PERCPU | IRQF_SHARED); + u8 *ipi_r_name, *ipi_c_name; + + ip27_per_cpu_init(); + cpud = this_cpu_ptr(&ip27_cpu); + ipi_r_name = per_cpu(ip27_ipi_r_name, cpud->id); + ipi_c_name = per_cpu(ip27_ipi_c_name, cpud->id); + + /* Request IRQ numbers for the CPU IPI bits. */ + if (!cpud->slice) { + sprintf(ipi_r_name, "%dA-rsch", (cpud->nasid + 1)); + sprintf(ipi_c_name, "%dA-call", (cpud->nasid + 1)); + if (request_irq(CPU_RESCHED_A_IRQ, ip27_smp_ipi_irq, irq_flags, + ipi_r_name, ip27_smp_ipi_irq)) + panic("IP27: Can't request CPU%d " + "CPU_RESCHED_A_IRQ IPI", cpud->id); + if (request_irq(CPU_CALL_A_IRQ, ip27_smp_ipi_irq, irq_flags, + ipi_c_name, ip27_smp_ipi_irq)) + panic("IP27: Can't request CPU%d " + "CPU_CALL_A_IRQ IPI", cpud->id); + } else { + sprintf(ipi_r_name, "%dB-rsch", (cpud->nasid + 1)); + sprintf(ipi_c_name, "%dB-call", (cpud->nasid + 1)); + if (request_irq(CPU_RESCHED_B_IRQ, ip27_smp_ipi_irq, irq_flags, + ipi_r_name, ip27_smp_ipi_irq)) + panic("IP27: Can't request CPU%d " + "CPU_RESCHED_B_IRQ IPI", cpud->id); + if (request_irq(CPU_CALL_B_IRQ, ip27_smp_ipi_irq, irq_flags, + ipi_c_name, ip27_smp_ipi_irq)) + panic("IP27: Can't request CPU%d " + "CPU_CALL_B_IRQ IPI", cpud->id); + } +} + +/** + * ip27_smp_finish - Sets CPU1 counter and enables interrupts. + * + * Runs on CPUx, where x > 0, before entering the idle loop. + */ +static void __init +ip27_smp_finish(void) +{ + extern void ip27_hub_clockevent_init(void); - cputonasid(cpunum) = nasid; - sn_cpu_info[cpunum].p_nodeid = node; - cputoslice(cpunum) = get_cpu_slice(cpu); + /* + * HUB has two compare registers, one for each CPU, so need to setup + * the clock_event stuff on each CPU before enabling interrupts. + */ + ip27_hub_clockevent_init(); + + /* + * Make sure an interrupt won't happen for a little bit. + */ + write_c0_compare(read_c0_count() + mips_hpt_frequency / HZ); + local_irq_enable(); } -static nasid_t get_actual_nasid(lboard_t *brd) +/** + * struct ip27_smp_ops - IP27 SMP ops. + * @send_ipi_single: send one interprocessor interrupt. + * @send_ipi_mask: send interprocessor interrup to each CPU. + * @smp_setup: probe for additional CPUs. + * @prepare_cpus: setup CPU0 IPI interrupt. + * @boot_secondary: boot additional CPUs. + * @init_secondary: setup CPUx IPI interrupts. + * @smp_finish: setup CPUx counter, enable IRQs. + */ +struct plat_smp_ops __read_mostly +ip27_smp_ops = { + .send_ipi_single = ip27_smp_send_ipi_single, + .send_ipi_mask = ip27_smp_send_ipi_mask, + .smp_setup = ip27_smp_setup, + .prepare_cpus = ip27_smp_prepare_cpus, + .boot_secondary = ip27_smp_boot_secondary, + .init_secondary = ip27_smp_init_secondary, + .smp_finish = ip27_smp_finish, +}; + +/* ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- */ +/* Misc SMP code used during init. */ + +/** + * ip27_smp_kl_nasid - gets the nasid of a nodeboard via klconfig. + * @brd: struct klc_lboard pointer of a nodeboard to get the nasid from. + */ +static nasid_t __init +ip27_smp_kl_nasid(struct klc_lboard *brd) { - klhub_t *hub; + struct klc_hub *hub; if (!brd) return INVALID_NASID; - /* find out if we are a completely disabled brd. */ - hub = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); + /* Find out if we are a completely disabled board */ + hub = KLCF_CAST_HUB(kl_find_1st_component(brd, KLSTRUCT_HUB)); if (!hub) return INVALID_NASID; - if (!(hub->hub_info.flags & KLINFO_ENABLE)) /* disabled node brd */ - return hub->hub_info.physid; + if (!(KLCF_INFO_ENABLED(hub->kl_info))) + return hub->kl_info.physid; else - return brd->brd_nasid; + return KLCF_BOARD_NASID(brd); } -static int do_cpumask(cnodeid_t cnode, nasid_t nasid, int highest) +/** + * ip27_smp_do_cpumask - update the smp cpumask for enabled cpus in a nasid. + * @cnode: cnodeid_t value of the compact node id. + * @nasid: nasid_t of the node id (physical node). + * @highest: int value of the highest CPU number discovered. + * + * Returns value of 'highest' back to the caller. + */ +static int __init +ip27_smp_do_cpumask(cnodeid_t cnode, nasid_t nasid, int highest) { - static int tot_cpus_found = 0; - lboard_t *brd; - klcpu_t *acpu; + static int total_cpus_found = 0; + struct klc_lboard *brd; + struct klc_cpu *acpu; int cpus_found = 0; cpuid_t cpuid; - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); + brd = kl_find_lboard(KLCF_LBOARD_INFO(nasid), KLTYPE_IP27); do { - acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU); + acpu = KLCF_CAST_CPU(kl_find_1st_component(brd, KLSTRUCT_CPU)); while (acpu) { - cpuid = acpu->cpu_info.virtid; + cpuid = acpu->kl_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 (ip27_smp_kl_nasid(brd) == KLCF_BOARD_NASID(brd)) + sn_cpuid_to_cnodeid[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)) { + if ((KLCF_INFO_ENABLED(acpu->kl_info)) && + (total_cpus_found != NR_CPUS)) { set_cpu_possible(cpuid, true); - alloc_cpupda(cpuid, tot_cpus_found); cpus_found++; - tot_cpus_found++; + total_cpus_found++; } - acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu, - KLSTRUCT_CPU); + acpu = KLCF_CAST_CPU(kl_find_component(brd, + KLCF_CAST_INFO(acpu), + KLSTRUCT_CPU)); } brd = KLCF_NEXT(brd); if (!brd) break; - brd = find_lboard(brd, KLTYPE_IP27); + brd = kl_find_lboard(brd, KLTYPE_IP27); } while (brd); return highest; } -void cpu_node_probe(void) +/** + * ip27_smp_cpu_node_probe - probe nodeboards for available CPUs via klconfig. + */ +void __init +ip27_smp_cpu_node_probe(void) { int i, highest = 0; gda_t *gdap = GDA; @@ -102,137 +399,32 @@ void cpu_node_probe(void) /* * 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; + memset(sn_cnodeid_to_nasid, -1, + sizeof(this_cpu_ptr(__sn_cnodeid_to_nasid))); + memset(sn_nasid_to_cnodeid, -1, + sizeof(this_cpu_ptr(__sn_nasid_to_cnodeid))); + memset(sn_cpuid_to_cnodeid, -1, + sizeof(this_cpu_ptr(__sn_cpuid_to_cnodeid))); /* - * MCD - this whole "compact node" stuff can probably be dropped, - * as we can handle sparse numbering now + * XXX: MCD - this whole "compact node" stuff can probably be dropped, + * as we can handle sparse numbering now */ + nodes_clear(node_possible_map); 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; + sn_nasid_to_cnodeid[nasid] = i; + sn_cnodeid_to_nasid[i] = nasid; + node_set_state(num_online_nodes(), N_POSSIBLE); 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)); + highest = ip27_smp_do_cpumask(i, nasid, highest); } - 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); + pr_info("SMP: Discovered %d cpus on %d nodes\n", (highest + 1), + num_online_nodes()); } -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, -}; +/* ----------------------------------------------------------------------- */ diff --git a/arch/mips/sgi-ip27/ip27-timer.c b/arch/mips/sgi-ip27/ip27-timer.c index d3b995e..f6180ba 100644 --- a/arch/mips/sgi-ip27/ip27-timer.c +++ b/arch/mips/sgi-ip27/ip27-timer.c @@ -37,199 +37,266 @@ #include #include -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); +/* Defined in ip27-init.c */ +DECLARE_PER_CPU(struct ip27_percpu_data, ip27_cpu); - return LOCAL_HUB_L(PI_RT_COUNT) >= cnt ? -ETIME : 0; -} - -unsigned int rt_timer_irq; +int ip27_hub_rt_irq_num; -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", -}; +/* ----------------------------------------------------------------------- */ +/* HUB Clocksource setup. */ /* - * This is a hack; we really need to figure these values out dynamically + * XXX: 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) +#define HUB_NSEC_PER_CYCLE 800 +#define HUB_CYCLES_PER_SEC (NSEC_PER_SEC / HUB_NSEC_PER_CYCLE) -void hub_rt_clock_event_init(void) +/** + * ip27_hub_csrc_counter_read - read HUB counter register (52-bit). + * @clocksource: pointer to clocksource struct. (unused) + * + * Returns cycle_t value of the HUB count register. + */ +static cycle_t +ip27_hub_csrc_counter_read(struct clocksource *cs) { - 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; - clockevents_register_device(cd); + return REMOTE_HUB_L(per_cpu(ip27_cpu, 0).nasid, PI_RT_COUNT); } -static void __init hub_rt_clock_event_global_init(void) +/** + * struct ip27_hub_clocksource - HUB clocksource definition. + * @name: self-explanatory. + * @rating: quality of this clocksource (HUB has 80ns cycle time). + * @read: pointer to function to read the counter register. + * @mask: bitmask for the counter (52bit counter/24bit compare). + * @flags: clocksource flags. + */ +static struct clocksource __read_mostly +ip27_hub_clocksource = { + .name = "HUB", + .rating = 400, + .read = ip27_hub_csrc_counter_read, + .mask = CLOCKSOURCE_MASK(52), + .flags = (CLOCK_SOURCE_IS_CONTINUOUS | CLOCK_SOURCE_VALID_FOR_HRES), +}; + +/** + * ip27_hub_read_sched_clock - make the HUB counter the sched_clock() source. + * + * Returns u64 value of the HUB count register. + */ +static u64 notrace +ip27_hub_csrc_read_sched_clock(void) { - int irq; + return REMOTE_HUB_L(per_cpu(ip27_cpu, 0).nasid, PI_RT_COUNT); +} - do { - smp_wmb(); - irq = rt_timer_irq; - if (irq) - break; +/** + * ip27_hub_clocksource_init - init the clocksource for HUB. + */ +static void __init +ip27_hub_clocksource_init(void) +{ + struct clocksource *cs = &ip27_hub_clocksource; - irq = allocate_irqno(); - if (irq < 0) - panic("Allocation of irq number for timer failed"); - } while (xchg(&rt_timer_irq, irq)); + clocksource_register_hz(cs, HUB_CYCLES_PER_SEC); - irq_set_chip_and_handler(irq, &rt_irq_type, handle_percpu_irq); - setup_irq(irq, &hub_rt_irqaction); + sched_clock_register(ip27_hub_csrc_read_sched_clock, 52, + HUB_CYCLES_PER_SEC); } -static cycle_t hub_rt_read(struct clocksource *cs) +/* ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- */ +/* HUB Clockevent setup. */ + +/* Should be globally-visible now. */ +DEFINE_PER_CPU(struct clock_event_device, ip27_hub_clockevent); +DEFINE_PER_CPU(char [11], ip27_hub_cevt_name); + +/** + * ip27_hub_rt_next_event - resets the compare bit on HUB for CPUA. + * @delta: difference between count and compare. + * @evt: pointer to clock_event_device struct. + * + * Returns -ETIME if local HUB counter is > cnt, else 0. + * + * HUB has one count register (PI_RT_COUNT) and two compare registers + * (PI_RT_COMPARE_A & PI_RT_COMPARE_B), one for each of the two CPUs attached + * to a HUB. + */ +static int +ip27_hub_rt_next_event(unsigned long delta, struct clock_event_device *evt) { - return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); -} + unsigned long cnt; -struct clocksource hub_rt_clocksource = { - .name = "HUB-RT", - .rating = 200, - .read = hub_rt_read, - .mask = CLOCKSOURCE_MASK(52), - .flags = CLOCK_SOURCE_IS_CONTINUOUS, -}; + cnt = (LOCAL_HUB_L(PI_RT_COUNT) + delta); + LOCAL_HUB_S(PI_RT_COMPARE_A + PI_COUNT_OFFSET * + this_cpu_read(ip27_cpu.slice), cnt); -static u64 notrace hub_rt_read_sched_clock(void) + return ((LOCAL_HUB_L(PI_RT_COUNT) >= cnt) ? -ETIME : 0); +} + +/** + * ip27_hub_rt_event_handler - Clock event handler on HUB. + * @cd: pointer to clock_event_device struct. + * + * Not supported on HUB. + */ +static void +ip27_hub_rt_event_handler(struct clock_event_device *cd) { - return REMOTE_HUB_L(cputonasid(0), PI_RT_COUNT); + /* Nothing to do */ } -static void __init hub_rt_clocksource_init(void) +/** + * ip27_hub_rt_compare_irq - IRQ handler for the HUB compare interrupt. + * @irq: IRQ number. + * @dev_id: void pointer to the clock_event_device struct. (unused on IP27) + * + * Always returns IRQ_HANDLED. + */ +static irqreturn_t +ip27_hub_rt_compare_irq(int irq, void *dev_id) { - struct clocksource *cs = &hub_rt_clocksource; + struct clock_event_device *cd = this_cpu_ptr(&ip27_hub_clockevent); - clocksource_register_hz(cs, CYCLES_PER_SEC); + /* Ack */ + LOCAL_HUB_S(PI_RT_PEND_A + PI_COUNT_OFFSET * + this_cpu_read(ip27_cpu.slice), 0); + cd->event_handler(cd); - sched_clock_register(hub_rt_read_sched_clock, 52, CYCLES_PER_SEC); + return IRQ_HANDLED; } -void __init plat_time_init(void) +/** + * struct ip27_hub_rt_irqaction - irqaction block for HUB. + * @name: self-explanatory. + * @flags: HUB counter IRQ flags. + * @handler: pointer to IRQ handler for the counter interrupt. + */ +struct irqaction +ip27_hub_rt_irqaction = { + .name = "hub_timer", + .flags = (IRQF_PERCPU | IRQF_TIMER | IRQF_NOBALANCING), + .handler = ip27_hub_rt_compare_irq, +}; + +/** + * ip27_hub_clockevent_init - per-HUB clockevent initialization. + */ +void +ip27_hub_clockevent_init(void) { - hub_rt_clocksource_init(); - hub_rt_clock_event_global_init(); - hub_rt_clock_event_init(); + const struct ip27_percpu_data *cpud = this_cpu_ptr(&ip27_cpu); + struct clock_event_device *cd = this_cpu_ptr(&ip27_hub_clockevent); + unsigned char *name = per_cpu(ip27_hub_cevt_name, cpud->id); + + sprintf(name, "HUB %d", cpud->id); + cd->name = name; + cd->features = CLOCK_EVT_FEAT_ONESHOT; + clockevent_set_clock(cd, HUB_CYCLES_PER_SEC); + cd->max_delta_ns = clockevent_delta2ns(0xfffffffffffff, cd); + cd->min_delta_ns = clockevent_delta2ns(0x300, cd); + cd->rating = 400; + cd->irq = ip27_hub_rt_irq_num; + cd->cpumask = cpumask_of(cpud->id); + cd->set_next_event = ip27_hub_rt_next_event; + cd->event_handler = ip27_hub_rt_event_handler; + clockevents_register_device(cd); } -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?"); +/* ----------------------------------------------------------------------- */ +/* HUB "RT" IRQ. */ - printk("CPU %d clock is %dMHz.\n", smp_processor_id(), cpu->cpu_speed); +/* + * HUB has a separate interrupt pending register for its "realtime" (RT) + * counter component, PI_RT_PEND_A or PI_RT_PEND_B. We use dummy irq_chip + * stubs to handle this, because the real ack'ing happens in + * ip27_hub_compare_irq, when invoked by the clockevent subsystem. + */ - set_c0_status(SRB_TIMOCLK); +/** + * ip27_mask_hub_rt_irq - masks a HUB RT IRQ. + * @d: struct irq_data containing IRQ information. + */ +static void +ip27_mask_hub_rt_irq(struct irq_data *d) +{ + /* Nothing */ } -void hub_rtc_init(cnodeid_t cnode) +/** + * ip27_unmask_hub_rt_irq - unmasks a HUB RT IRQ. + * @d: struct irq_data containing IRQ information. + */ +static void +ip27_unmask_hub_rt_irq(struct irq_data *d) { - - /* - * 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); - } + /* Nothing */ } -static int __init sgi_ip27_rtc_devinit(void) +/** + * struct ip27_hub_rt_irq - HUB struct irq_chip ops. + * @irq_mask: mask function. + * @irq_unmask: unmask function. + */ +static struct irq_chip __read_mostly +ip27_hub_rt_irq = { + .name = "HUB_RT", + .irq_mask = ip27_mask_hub_rt_irq, + .irq_unmask = ip27_unmask_hub_rt_irq, +}; + +/** + * ip27_hub_clock_event_irq_init - allocates a dynamic IRQ for HUB RT. + * @d: struct irq_data containing IRQ information. + */ +static void __init +ip27_hub_rt_irq_init(void) { - struct resource res; + int irq; - 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; + do { + smp_wmb(); + irq = ip27_hub_rt_irq_num; + if (irq) + break; + + irq = ip27_alloc_irq_num(); + if (irq < 0) + panic("Allocation of HUB timer IRQ number failed!"); + } while (xchg(&ip27_hub_rt_irq_num, irq)); - return IS_ERR(platform_device_register_simple("rtc-m48t35", -1, - &res, 1)); + irq_set_chip_and_handler(irq, &ip27_hub_rt_irq, handle_percpu_irq); + setup_irq(ip27_hub_rt_irq_num, &ip27_hub_rt_irqaction); } -/* - * kludge make this a device_initcall after ioc3 resource conflicts - * are resolved +/* ----------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------- */ + +/** + * plat_time_init - platform time initialization. */ -late_initcall(sgi_ip27_rtc_devinit); +void __init +plat_time_init(void) +{ + /* Init clocksource and clockevent for HUB on CPU0. */ + ip27_hub_clocksource_init(); + ip27_hub_rt_irq_init(); + ip27_hub_clockevent_init(); +} + +/* ----------------------------------------------------------------------- */ diff --git a/arch/mips/sgi-ip27/ip27-xtalk.c b/arch/mips/sgi-ip27/ip27-xtalk.c index 20f582a..69adc31 100644 --- a/arch/mips/sgi-ip27/ip27-xtalk.c +++ b/arch/mips/sgi-ip27/ip27-xtalk.c @@ -9,60 +9,155 @@ #include #include -#include -#include -#include -#include +#include + #include +#include + +#include + +#include +#include +#include +#include +#define xtalk_read __raw_readl -#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); +struct widget_data { + u32 mfgr; + u32 part; + char *name; + char *rev; +}; + +/* XXX: Kill */ +unsigned long inline +xtalk_get_swin(int node, int wid) +{ + return NODE_SWIN_BASE(node, wid); +} -static int probe_one_port(nasid_t nasid, int widget, int masterwid) +static void __init +xtalk_bridge_platform_setup(nasid_t nasid, const struct widget_data *wd, + xwidgetnum_t widget, xwidgetnum_t master_wid) { - widgetreg_t widget_id; - xwidget_part_num_t partnum; + struct platform_device *xw_pdev; + struct xwidget_platform_data *xw_pdata; + extern struct bridge_platform_data ip27_bridge_platform_data; + + xw_pdata = kzalloc(sizeof(struct xwidget_platform_data), GFP_KERNEL); + xw_pdata->nasid = nasid; + xw_pdata->masterwid = master_wid; + xw_pdata->bridge_pdata = &ip27_bridge_platform_data; + + xw_pdev = kzalloc(sizeof(struct platform_device), GFP_KERNEL); + xw_pdev->name = wd->name; + xw_pdev->id = widget; + xw_pdev->dev.platform_data = xw_pdata; + + platform_device_register(xw_pdev); + pr_info("xtalk:n%d/%x %s widget (rev %s) registered as a " + "platform device.\n", nasid, widget, wd->name, wd->rev); +} - widget_id = *(volatile widgetreg_t *) - (RAW_NODE_SWIN_BASE(nasid, widget) + WIDGET_ID); - partnum = XWIDGET_PART_NUM(widget_id); +static unsigned int __init +xtalk_get_widget_data(nasid_t nasid, xwidgetnum_t wid) +{ + unsigned int link_stat; + + if (wid != XTALK_XBOW && + (wid < XTALK_LOW_DEV || wid > XTALK_HIGH_DEV)) + return XTALK_NODEV; + + if (wid) { + link_stat = xtalk_read((void *)(RAW_NODE_SWIN_BASE(nasid, 0) + + XBOW_REG_LINK_STAT_0 + + XBOW_REG_LINK_BLK_SIZE * + (wid - XTALK_LOW_DEV))); + /* Is the link alive? */ + if (!(link_stat & XBOW_REG_LINK_ALIVE)) + return XTALK_NODEV; + } - printk(KERN_INFO "Cpu %d, Nasid 0x%x, widget 0x%x (partnum 0x%x) is ", - smp_processor_id(), nasid, widget, partnum); + return xtalk_read((void *)(RAW_NODE_SWIN_BASE(nasid, wid) + WIDGET_ID)); +} - switch (partnum) { - case BRIDGE_WIDGET_PART_NUM: - case XBRIDGE_WIDGET_PART_NUM: - bridge_probe(nasid, widget, masterwid); - break; - default: - break; +static struct widget_data __init * +xtalk_get_widget_info(nasid_t nasid, xwidgetnum_t widget) +{ + u32 wid_data, rev; + struct widget_data *wd; + const struct widget_ident *wi; + + wd = kzalloc(sizeof(struct widget_data), GFP_KERNEL); + if (!wd) + return NULL; + + wid_data = xtalk_get_widget_data(nasid, widget); + if (wid_data == XTALK_NODEV) + return NULL; + + rev = XWIDGET_REV_NUM(wid_data); + for (wi = widget_idents; wi->name; wi++) + if ((wi->mfgr == XWIDGET_MFG_NUM(wid_data)) && + (wi->part == XWIDGET_PART_NUM(wid_data))) + break; + + if (unlikely(wi->name == NULL)) { + pr_info("xtalk:n%d/%x unknown widget 0x%x\n", nasid, + widget, wid_data); + return NULL; } - return 0; + wd->mfgr = wi->mfgr; + wd->part = wi->part; + wd->name = wi->name; + wd->rev = (wi->revs[rev] ? wi->revs[rev] : "unknown"); + + return wd; } -static int xbow_probe(nasid_t nasid) +static void __init +xtalk_init_widget(nasid_t nasid, xwidgetnum_t widget, xwidgetnum_t masterwid) { - lboard_t *brd; - klxbow_t *xbow_p; - unsigned masterwid, i; + struct widget_data *wd; - printk("is xbow\n"); + wd = xtalk_get_widget_info(nasid, widget); + if (!wd) + return; + + switch (wd->part) { + case WIDGET_BRIDG_PART_NUM: + case WIDGET_XBRDG_PART_NUM: + xtalk_bridge_platform_setup(nasid, wd, widget, masterwid); + break; + default: + if (platform_device_register_simple(wd->name, widget, NULL, 0)) + pr_info("xtalk:n%d/%x %s widget (rev %s) " + "registered as a platform device.\n", nasid, + widget, wd->name, wd->rev); + } + kzfree(wd); +} + +static int __init +xbow_probe(nasid_t nasid) +{ + struct klc_lboard *brd; + struct klc_xbow *xbow_p; + xwidgetnum_t masterwid, i; /* * found xbow, so may have multiple bridges * need to probe xbow */ - brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_MIDPLANE8); + brd = kl_find_lboard(KLCF_LBOARD_INFO(nasid), KLTYPE_MIDPLANE); if (!brd) return -ENODEV; - xbow_p = (klxbow_t *)find_component(brd, NULL, KLSTRUCT_XBOW); + xbow_p = KLCF_CAST_XBOW(kl_find_component(brd, NULL, KLSTRUCT_XBOW)); if (!xbow_p) return -ENODEV; @@ -72,19 +167,11 @@ static int xbow_probe(nasid_t nasid) * 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)) @@ -93,43 +180,62 @@ static int xbow_probe(nasid_t nasid) 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); + xtalk_init_widget(nasid, i, masterwid); } return 0; } -void xtalk_probe_node(cnodeid_t nid) +void __init +xtalk_probe_node(cnodeid_t cnodeid) { - volatile u64 hubreg; - nasid_t nasid; - xwidget_part_num_t partnum; - widgetreg_t widget_id; + volatile u64 hubreg; + nasid_t nasid; + struct widget_data *wd; - nasid = COMPACT_TO_NASID_NODEID(nid); + nasid = sn_cnodeid_to_nasid[cnodeid]; 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); + wd = xtalk_get_widget_info(nasid, XTALK_XBOW); + if (!wd) + return; - switch (partnum) { - case BRIDGE_WIDGET_PART_NUM: - bridge_probe(nasid, 0x8, 0xa); + switch (wd->part) { + case WIDGET_BRIDG_PART_NUM: + xtalk_bridge_platform_setup(nasid, wd, 0x8, 0xa); break; - case XBOW_WIDGET_PART_NUM: - case XXBOW_WIDGET_PART_NUM: + case WIDGET_XBOW_PART_NUM: + case WIDGET_XXBOW_PART_NUM: + pr_info("xtalk:n%d/%lx %s widget (rev %s)\n", + nasid, XTALK_XBOW, wd->name, wd->rev); xbow_probe(nasid); break; default: - printk(" unknown widget??\n"); - break; + if (platform_device_register_simple(wd->name, XTALK_XBOW, NULL, 0)) + pr_info("xtalk:n%d/%lx %s widget (rev %s) " + "registered as platform device.\n", nasid, + XTALK_XBOW, wd->name, wd->rev); } + kzfree(wd); } + +static int __init +ip27_xtalk_init(void) +{ + cnodeid_t cnode; + + /* XXX: kludge alert.. */ + ioport_resource.end = ~0UL; + + for_each_online_node(cnode) { + xtalk_probe_node(cnode); + } + + return 0; +} + +arch_initcall(ip27_xtalk_init);