/* * 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) 2005 Silicon Graphics, Inc. All Rights Reserved. */ #ifndef _LINUX_IOC4_H #define _LINUX_IOC4_H #include /*************** * Definitions * ***************/ /* Miscellaneous values inherent to hardware */ #define IOC4_EXTINT_COUNT_DIVISOR 520 /* PCI clocks per COUNT tick */ /*********************************** * Structures needed by subdrivers * ***********************************/ /* This structure fully describes the IOC4 miscellaneous registers which * appear at bar[0]+0x00000 through bar[0]+0x0005c. The corresponding * PCI resource is managed by the main IOC4 driver because it contains * registers of interest to many different IOC4 subdrivers. */ struct ioc4_misc_regs { /* Miscellaneous IOC4 registers */ union ioc4_pci_err_addr_l { uint32_t raw; struct { uint32_t valid:1; /* Address captured */ uint32_t master_id:4; /* Unit causing error * 0/1: Serial port 0 TX/RX * 2/3: Serial port 1 TX/RX * 4/5: Serial port 2 TX/RX * 6/7: Serial port 3 TX/RX * 8: ATA/ATAPI * 9-15: Undefined */ uint32_t mul_err:1; /* Multiple errors occurred */ uint32_t addr:26; /* Bits 31-6 of error addr */ } fields; } pci_err_addr_l; uint32_t pci_err_addr_h; /* Bits 63-32 of error addr */ union ioc4_sio_int { uint32_t raw; struct { uint8_t tx_mt:1; /* TX ring buffer empty */ uint8_t rx_full:1; /* RX ring buffer full */ uint8_t rx_high:1; /* RX high-water exceeded */ uint8_t rx_timer:1; /* RX timer has triggered */ uint8_t delta_dcd:1; /* DELTA_DCD seen */ uint8_t delta_cts:1; /* DELTA_CTS seen */ uint8_t intr_pass:1; /* Interrupt pass-through */ uint8_t tx_explicit:1; /* TX, MCW, or delay complete */ } fields[4]; } sio_ir; /* Serial interrupt state */ union ioc4_other_int { uint32_t raw; struct { uint32_t ata_int:1; /* ATA port passthru */ uint32_t ata_memerr:1; /* ATA halted by mem error */ uint32_t memerr:4; /* Serial halted by mem err */ uint32_t kbd_int:1; /* kbd/mouse intr asserted */ uint32_t reserved:16; /* zero */ uint32_t rt_int:1; /* INT_OUT section latch */ uint32_t gen_int:8; /* Intr. from generic pins */ } fields; } other_ir; /* Other interrupt state */ union ioc4_sio_int sio_ies; /* Serial interrupt enable set */ union ioc4_other_int other_ies; /* Other interrupt enable set */ union ioc4_sio_int sio_iec; /* Serial interrupt enable clear */ union ioc4_other_int other_iec; /* Other interrupt enable clear */ union ioc4_sio_cr { uint32_t raw; struct { uint32_t cmd_pulse:4; /* Bytebus strobe width */ uint32_t arb_diag:3; /* PCI bus requester */ uint32_t sio_diag_idle:1; /* Active ser req? */ uint32_t ata_diag_idle:1; /* Active ATA req? */ uint32_t ata_diag_active:1; /* ATA req is winner */ uint32_t reserved:22; /* zero */ } fields; } sio_cr; uint32_t unused1; union ioc4_int_out { uint32_t raw; struct { uint32_t count:16; /* Period control */ uint32_t mode:3; /* Output signal shape */ uint32_t reserved:11; /* zero */ uint32_t diag:1; /* Timebase control */ uint32_t int_out:1; /* Current value */ } fields; } int_out; /* External interrupt output control */ uint32_t unused2; union ioc4_gpcr { uint32_t raw; struct { uint32_t dir:8; /* Pin direction */ uint32_t edge:8; /* Edge/level mode */ uint32_t reserved1:4; /* zero */ uint32_t int_out_en:1; /* INT_OUT enable */ uint32_t reserved2:11; /* zero */ } fields; } gpcr_s; /* Generic PIO control set */ union ioc4_gpcr gpcr_c; /* Generic PIO control clear */ union ioc4_gpdr { uint32_t raw; struct { uint32_t gen_pin:8; /* State of pins */ uint32_t reserved:24; } fields; } gpdr; /* Generic PIO data */ uint32_t unused3; union ioc4_gppr { uint32_t raw; struct { uint32_t gen_pin:1; /* Single pin state */ uint32_t reserved:31; } fields; } gppr[8]; /* Generic PIO pins */ }; /* Masks for GPCR DIR pins */ #define IOC4_GPCR_DIR_0 0x01 /* External interrupt output */ #define IOC4_GPCR_DIR_1 0x02 /* External interrupt input */ #define IOC4_GPCR_DIR_2 0x04 #define IOC4_GPCR_DIR_3 0x08 /* Keyboard/mouse presence */ #define IOC4_GPCR_DIR_4 0x10 /* Ser. port 0 xcvr select (0=232, 1=422) */ #define IOC4_GPCR_DIR_5 0x20 /* Ser. port 1 xcvr select (0=232, 1=422) */ #define IOC4_GPCR_DIR_6 0x40 /* Ser. port 2 xcvr select (0=232, 1=422) */ #define IOC4_GPCR_DIR_7 0x80 /* Ser. port 3 xcvr select (0=232, 1=422) */ /* Masks for GPCR EDGE pins */ #define IOC4_GPCR_EDGE_0 0x01 #define IOC4_GPCR_EDGE_1 0x02 /* External interrupt input */ #define IOC4_GPCR_EDGE_2 0x04 #define IOC4_GPCR_EDGE_3 0x08 #define IOC4_GPCR_EDGE_4 0x10 #define IOC4_GPCR_EDGE_5 0x20 #define IOC4_GPCR_EDGE_6 0x40 #define IOC4_GPCR_EDGE_7 0x80 #define IOC4_VARIANT_IO9 0x0900 #define IOC4_VARIANT_PCI_RT 0x0901 #define IOC4_VARIANT_IO10 0x1000 /* One of these per IOC4 */ struct ioc4_driver_data { struct list_head idd_list; unsigned long idd_bar0; struct pci_dev *idd_pdev; const struct pci_device_id *idd_pci_id; struct ioc4_misc_regs __iomem *idd_misc_regs; unsigned long count_period; void *idd_serial_data; unsigned int idd_variant; }; /* One per submodule */ struct ioc4_submodule { struct list_head is_list; char *is_name; struct module *is_owner; int (*is_probe) (struct ioc4_driver_data *); int (*is_remove) (struct ioc4_driver_data *); }; #define IOC4_NUM_CARDS 8 /* max cards per partition */ /********************************** * Functions needed by submodules * **********************************/ extern int ioc4_register_submodule(struct ioc4_submodule *); extern void ioc4_unregister_submodule(struct ioc4_submodule *); #endif /* _LINUX_IOC4_H */ 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
/*
 * This file is subject to the terms and conditions of the GNU General
 * Public License.  See the file "COPYING" in the main directory of this
 * archive for more details.
 *
 * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com)
 * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc.
 */
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/cpumask.h>
#include <asm/cpu.h>
#include <asm/io.h>
#include <asm/pgtable.h>
#include <asm/time.h>
#include <asm/sn/types.h>
#include <asm/sn/sn0/addrs.h>
#include <asm/sn/sn0/hubni.h>
#include <asm/sn/sn0/hubio.h>
#include <asm/sn/klconfig.h>
#include <asm/sn/ioc3.h>
#include <asm/mipsregs.h>
#include <asm/sn/gda.h>
#include <asm/sn/hub.h>
#include <asm/sn/intr.h>
#include <asm/current.h>
#include <asm/smp.h>
#include <asm/processor.h>
#include <asm/mmu_context.h>
#include <asm/thread_info.h>
#include <asm/sn/launch.h>
#include <asm/sn/sn_private.h>
#include <asm/sn/sn0/ip27.h>
#include <asm/sn/mapped_kernel.h>

#define CPU_NONE		(cpuid_t)-1

static DECLARE_BITMAP(hub_init_mask, MAX_COMPACT_NODES);
nasid_t master_nasid = INVALID_NASID;

cnodeid_t	nasid_to_compact_node[MAX_NASIDS];
nasid_t		compact_to_nasid_node[MAX_COMPACT_NODES];
cnodeid_t	cpuid_to_compact_node[MAXCPUS];

EXPORT_SYMBOL(nasid_to_compact_node);

extern void pcibr_setup(cnodeid_t);

extern void xtalk_probe_node(cnodeid_t nid);

static void __init per_hub_init(cnodeid_t cnode)
{
	struct hub_data *hub = hub_data(cnode);
	nasid_t nasid = COMPACT_TO_NASID_NODEID(cnode);

	cpu_set(smp_processor_id(), hub->h_cpus);

	if (test_and_set_bit(cnode, hub_init_mask))
		return;

	/*
	 * Set CRB timeout at 5ms, (< PI timeout of 10ms)
	 */
	REMOTE_HUB_S(nasid, IIO_ICTP, 0x800);
	REMOTE_HUB_S(nasid, IIO_ICTO, 0xff);

	hub_rtc_init(cnode);
	xtalk_probe_node(cnode);

#ifdef CONFIG_REPLICATE_EXHANDLERS
	/*
	 * If this is not a headless node initialization,
	 * copy over the caliased exception handlers.
	 */
	if (get_compact_nodeid() == cnode) {
		extern char except_vec2_generic, except_vec3_generic;
		extern void build_tlb_refill_handler(void);

		memcpy((void *)(CKSEG0 + 0x100), &except_vec2_generic, 0x80);
		memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x80);
		build_tlb_refill_handler();
		memcpy((void *)(CKSEG0 + 0x100), (void *) CKSEG0, 0x80);
		memcpy((void *)(CKSEG0 + 0x180), &except_vec3_generic, 0x100);
		__flush_cache_all();
	}
#endif
}

void __init per_cpu_init(void)
{
	int cpu = smp_processor_id();
	int slice = LOCAL_HUB_L(PI_CPU_NUM);
	cnodeid_t cnode = get_compact_nodeid();
	struct hub_data *hub = hub_data(cnode);
	struct slice_data *si = hub->slice + slice;
	int i;

	if (test_and_set_bit(slice, &hub->slice_map))
		return;

	clear_c0_status(ST0_IM);

	for (i = 0; i < LEVELS_PER_SLICE; i++)
		si->level_to_irq[i] = -1;

	/*
	 * Some interrupts are reserved by hardware or by software convention.
	 * Mark these as reserved right away so they won't be used accidently
	 * later.
	 */
	for (i = 0; i <= BASE_PCI_IRQ; i++) {
		__set_bit(i, si->irq_alloc_mask);
		LOCAL_HUB_S(PI_INT_PEND_MOD, i);
	}

	__set_bit(IP_PEND0_6_63, si->irq_alloc_mask);
	LOCAL_HUB_S(PI_INT_PEND_MOD, IP_PEND0_6_63);

	for (i = NI_BRDCAST_ERR_A; i <= MSC_PANIC_INTR; i++) {
		__set_bit(i, si->irq_alloc_mask + 1);
		LOCAL_HUB_S(PI_INT_PEND_MOD, i);
	}

	LOCAL_HUB_L(PI_INT_PEND0);

	/*
	 * We use this so we can find the local hub's data as fast as only
	 * possible.
	 */
	cpu_data[cpu].data = si;

	cpu_time_init();
	install_ipi();

	/* Install our NMI handler if symmon hasn't installed one. */
	install_cpu_nmi_handler(cputoslice(cpu));

	set_c0_status(SRB_DEV0 | SRB_DEV1);

	per_hub_init(cnode);
}

/*
 * get_nasid() returns the physical node id number of the caller.
 */
nasid_t
get_nasid(void)
{
	return (nasid_t)((LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_NODEID_MASK)
	                 >> NSRI_NODEID_SHFT);
}

/*
 * Map the physical node id to a virtual node id (virtual node ids are contiguous).
 */
cnodeid_t get_compact_nodeid(void)
{
	return NASID_TO_COMPACT_NODEID(get_nasid());
}

/* Extracted from the IOC3 meta driver.  FIXME.  */
static inline void ioc3_sio_init(void)
{
	struct ioc3 *ioc3;
	nasid_t nid;
	long loops;

	nid = get_nasid();
	ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;

	ioc3->sscr_a = 0;			/* PIO mode for uarta.  */
	ioc3->sscr_b = 0;			/* PIO mode for uartb.  */
	ioc3->sio_iec = ~0;
	ioc3->sio_ies = (SIO_IR_SA_INT | SIO_IR_SB_INT);

	loops=1000000; while(loops--);
	ioc3->sregs.uarta.iu_fcr = 0;
	ioc3->sregs.uartb.iu_fcr = 0;
	loops=1000000; while(loops--);
}

static inline void ioc3_eth_init(void)
{
	struct ioc3 *ioc3;
	nasid_t nid;

	nid = get_nasid();
	ioc3 = (struct ioc3 *) KL_CONFIG_CH_CONS_INFO(nid)->memory_base;

	ioc3->eier = 0;
}

extern void ip27_setup_console(void);
extern void ip27_time_init(void);
extern void ip27_reboot_setup(void);

static int __init ip27_setup(void)
{
	hubreg_t p, e, n_mode;
	nasid_t nid;

	ip27_setup_console();
	ip27_reboot_setup();

	/*
	 * hub_rtc init and cpu clock intr enabled for later calibrate_delay.
	 */
	nid = get_nasid();
	printk("IP27: Running on node %d.\n", nid);

	p = LOCAL_HUB_L(PI_CPU_PRESENT_A) & 1;
	e = LOCAL_HUB_L(PI_CPU_ENABLE_A) & 1;
	printk("Node %d has %s primary CPU%s.\n", nid,
	       p ? "a" : "no",
	       e ? ", CPU is running" : "");

	p = LOCAL_HUB_L(PI_CPU_PRESENT_B) & 1;
	e = LOCAL_HUB_L(PI_CPU_ENABLE_B) & 1;
	printk("Node %d has %s secondary CPU%s.\n", nid,
	       p ? "a" : "no",
	       e ? ", CPU is running" : "");

	/*
	 * Try to catch kernel missconfigurations and give user an
	 * indication what option to select.
	 */
	n_mode = LOCAL_HUB_L(NI_STATUS_REV_ID) & NSRI_MORENODES_MASK;
	printk("Machine is in %c mode.\n", n_mode ? 'N' : 'M');
#ifdef CONFIG_SGI_SN0_N_MODE
	if (!n_mode)
		panic("Kernel compiled for M mode.");
#else
	if (n_mode)
		panic("Kernel compiled for N mode.");
#endif

	ioc3_sio_init();
	ioc3_eth_init();
	per_cpu_init();

	set_io_port_base(IO_BASE);

	board_time_init = ip27_time_init;

	return 0;
}

early_initcall(ip27_setup);