| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * This file is subject to the terms and conditions of the GNU General | 
|  | 3 | * Public License.  See the file "COPYING" in the main directory of this | 
|  | 4 | * archive for more details. | 
|  | 5 | * | 
|  | 6 | * Copyright (C) 2000 - 2001 by Kanoj Sarcar (kanoj@sgi.com) | 
|  | 7 | * Copyright (C) 2000 - 2001 by Silicon Graphics, Inc. | 
|  | 8 | */ | 
|  | 9 | #include <linux/init.h> | 
|  | 10 | #include <linux/sched.h> | 
|  | 11 | #include <linux/nodemask.h> | 
|  | 12 | #include <asm/page.h> | 
|  | 13 | #include <asm/processor.h> | 
|  | 14 | #include <asm/sn/arch.h> | 
|  | 15 | #include <asm/sn/gda.h> | 
|  | 16 | #include <asm/sn/intr.h> | 
|  | 17 | #include <asm/sn/klconfig.h> | 
|  | 18 | #include <asm/sn/launch.h> | 
|  | 19 | #include <asm/sn/mapped_kernel.h> | 
|  | 20 | #include <asm/sn/sn_private.h> | 
|  | 21 | #include <asm/sn/types.h> | 
|  | 22 | #include <asm/sn/sn0/hubpi.h> | 
|  | 23 | #include <asm/sn/sn0/hubio.h> | 
|  | 24 | #include <asm/sn/sn0/ip27.h> | 
|  | 25 |  | 
|  | 26 | /* | 
|  | 27 | * Takes as first input the PROM assigned cpu id, and the kernel | 
|  | 28 | * assigned cpu id as the second. | 
|  | 29 | */ | 
|  | 30 | static void alloc_cpupda(cpuid_t cpu, int cpunum) | 
|  | 31 | { | 
|  | 32 | cnodeid_t node = get_cpu_cnode(cpu); | 
|  | 33 | nasid_t nasid = COMPACT_TO_NASID_NODEID(node); | 
|  | 34 |  | 
|  | 35 | cputonasid(cpunum) = nasid; | 
|  | 36 | cpu_data[cpunum].p_nodeid = node; | 
|  | 37 | cputoslice(cpunum) = get_cpu_slice(cpu); | 
|  | 38 | } | 
|  | 39 |  | 
|  | 40 | static nasid_t get_actual_nasid(lboard_t *brd) | 
|  | 41 | { | 
|  | 42 | klhub_t *hub; | 
|  | 43 |  | 
|  | 44 | if (!brd) | 
|  | 45 | return INVALID_NASID; | 
|  | 46 |  | 
|  | 47 | /* find out if we are a completely disabled brd. */ | 
|  | 48 | hub  = (klhub_t *)find_first_component(brd, KLSTRUCT_HUB); | 
|  | 49 | if (!hub) | 
|  | 50 | return INVALID_NASID; | 
|  | 51 | if (!(hub->hub_info.flags & KLINFO_ENABLE))	/* disabled node brd */ | 
|  | 52 | return hub->hub_info.physid; | 
|  | 53 | else | 
|  | 54 | return brd->brd_nasid; | 
|  | 55 | } | 
|  | 56 |  | 
|  | 57 | static int do_cpumask(cnodeid_t cnode, nasid_t nasid, int highest) | 
|  | 58 | { | 
|  | 59 | static int tot_cpus_found = 0; | 
|  | 60 | lboard_t *brd; | 
|  | 61 | klcpu_t *acpu; | 
|  | 62 | int cpus_found = 0; | 
|  | 63 | cpuid_t cpuid; | 
|  | 64 |  | 
|  | 65 | brd = find_lboard((lboard_t *)KL_CONFIG_INFO(nasid), KLTYPE_IP27); | 
|  | 66 |  | 
|  | 67 | do { | 
|  | 68 | acpu = (klcpu_t *)find_first_component(brd, KLSTRUCT_CPU); | 
|  | 69 | while (acpu) { | 
|  | 70 | cpuid = acpu->cpu_info.virtid; | 
|  | 71 | /* cnode is not valid for completely disabled brds */ | 
|  | 72 | if (get_actual_nasid(brd) == brd->brd_nasid) | 
|  | 73 | cpuid_to_compact_node[cpuid] = cnode; | 
|  | 74 | if (cpuid > highest) | 
|  | 75 | highest = cpuid; | 
|  | 76 | /* Only let it join in if it's marked enabled */ | 
|  | 77 | if ((acpu->cpu_info.flags & KLINFO_ENABLE) && | 
|  | 78 | (tot_cpus_found != NR_CPUS)) { | 
|  | 79 | cpu_set(cpuid, phys_cpu_present_map); | 
|  | 80 | alloc_cpupda(cpuid, tot_cpus_found); | 
|  | 81 | cpus_found++; | 
|  | 82 | tot_cpus_found++; | 
|  | 83 | } | 
|  | 84 | acpu = (klcpu_t *)find_component(brd, (klinfo_t *)acpu, | 
|  | 85 | KLSTRUCT_CPU); | 
|  | 86 | } | 
|  | 87 | brd = KLCF_NEXT(brd); | 
|  | 88 | if (!brd) | 
|  | 89 | break; | 
|  | 90 |  | 
|  | 91 | brd = find_lboard(brd, KLTYPE_IP27); | 
|  | 92 | } while (brd); | 
|  | 93 |  | 
|  | 94 | return highest; | 
|  | 95 | } | 
|  | 96 |  | 
|  | 97 | void cpu_node_probe(void) | 
|  | 98 | { | 
|  | 99 | int i, highest = 0; | 
|  | 100 | gda_t *gdap = GDA; | 
|  | 101 |  | 
|  | 102 | /* | 
|  | 103 | * Initialize the arrays to invalid nodeid (-1) | 
|  | 104 | */ | 
|  | 105 | for (i = 0; i < MAX_COMPACT_NODES; i++) | 
|  | 106 | compact_to_nasid_node[i] = INVALID_NASID; | 
|  | 107 | for (i = 0; i < MAX_NASIDS; i++) | 
|  | 108 | nasid_to_compact_node[i] = INVALID_CNODEID; | 
|  | 109 | for (i = 0; i < MAXCPUS; i++) | 
|  | 110 | cpuid_to_compact_node[i] = INVALID_CNODEID; | 
|  | 111 |  | 
|  | 112 | /* | 
|  | 113 | * MCD - this whole "compact node" stuff can probably be dropped, | 
|  | 114 | * as we can handle sparse numbering now | 
|  | 115 | */ | 
|  | 116 | nodes_clear(node_online_map); | 
|  | 117 | for (i = 0; i < MAX_COMPACT_NODES; i++) { | 
|  | 118 | nasid_t nasid = gdap->g_nasidtable[i]; | 
|  | 119 | if (nasid == INVALID_NASID) | 
|  | 120 | break; | 
|  | 121 | compact_to_nasid_node[i] = nasid; | 
|  | 122 | nasid_to_compact_node[nasid] = i; | 
|  | 123 | node_set_online(num_online_nodes()); | 
|  | 124 | highest = do_cpumask(i, nasid, highest); | 
|  | 125 | } | 
|  | 126 |  | 
|  | 127 | printk("Discovered %d cpus on %d nodes\n", highest + 1, num_online_nodes()); | 
|  | 128 | } | 
|  | 129 |  | 
|  | 130 | static void intr_clear_bits(nasid_t nasid, volatile hubreg_t *pend, | 
|  | 131 | int base_level) | 
|  | 132 | { | 
|  | 133 | volatile hubreg_t bits; | 
|  | 134 | int i; | 
|  | 135 |  | 
|  | 136 | /* Check pending interrupts */ | 
|  | 137 | if ((bits = HUB_L(pend)) != 0) | 
|  | 138 | for (i = 0; i < N_INTPEND_BITS; i++) | 
|  | 139 | if (bits & (1 << i)) | 
|  | 140 | LOCAL_HUB_CLR_INTR(base_level + i); | 
|  | 141 | } | 
|  | 142 |  | 
|  | 143 | static void intr_clear_all(nasid_t nasid) | 
|  | 144 | { | 
|  | 145 | REMOTE_HUB_S(nasid, PI_INT_MASK0_A, 0); | 
|  | 146 | REMOTE_HUB_S(nasid, PI_INT_MASK0_B, 0); | 
|  | 147 | REMOTE_HUB_S(nasid, PI_INT_MASK1_A, 0); | 
|  | 148 | REMOTE_HUB_S(nasid, PI_INT_MASK1_B, 0); | 
|  | 149 | intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND0), | 
|  | 150 | INT_PEND0_BASELVL); | 
|  | 151 | intr_clear_bits(nasid, REMOTE_HUB_ADDR(nasid, PI_INT_PEND1), | 
|  | 152 | INT_PEND1_BASELVL); | 
|  | 153 | } | 
|  | 154 |  | 
|  | 155 | void __init prom_prepare_cpus(unsigned int max_cpus) | 
|  | 156 | { | 
|  | 157 | cnodeid_t	cnode; | 
|  | 158 |  | 
|  | 159 | for_each_online_node(cnode) | 
|  | 160 | intr_clear_all(COMPACT_TO_NASID_NODEID(cnode)); | 
|  | 161 |  | 
|  | 162 | replicate_kernel_text(); | 
|  | 163 |  | 
|  | 164 | /* | 
|  | 165 | * Assumption to be fixed: we're always booted on logical / physical | 
|  | 166 | * processor 0.  While we're always running on logical processor 0 | 
|  | 167 | * this still means this is physical processor zero; it might for | 
|  | 168 | * example be disabled in the firwware. | 
|  | 169 | */ | 
|  | 170 | alloc_cpupda(0, 0); | 
|  | 171 | } | 
|  | 172 |  | 
|  | 173 | /* | 
|  | 174 | * Launch a slave into smp_bootstrap().  It doesn't take an argument, and we | 
|  | 175 | * set sp to the kernel stack of the newly created idle process, gp to the proc | 
|  | 176 | * struct so that current_thread_info() will work. | 
|  | 177 | */ | 
|  | 178 | void __init prom_boot_secondary(int cpu, struct task_struct *idle) | 
|  | 179 | { | 
|  | 180 | unsigned long gp = (unsigned long) idle->thread_info; | 
|  | 181 | unsigned long sp = gp + THREAD_SIZE - 32; | 
|  | 182 |  | 
|  | 183 | LAUNCH_SLAVE(cputonasid(cpu),cputoslice(cpu), | 
|  | 184 | (launch_proc_t)MAPPED_KERN_RW_TO_K0(smp_bootstrap), | 
|  | 185 | 0, (void *) sp, (void *) gp); | 
|  | 186 | } | 
|  | 187 |  | 
|  | 188 | void prom_init_secondary(void) | 
|  | 189 | { | 
|  | 190 | per_cpu_init(); | 
|  | 191 | local_irq_enable(); | 
|  | 192 | } | 
|  | 193 |  | 
|  | 194 | void __init prom_cpus_done(void) | 
|  | 195 | { | 
|  | 196 | } | 
|  | 197 |  | 
|  | 198 | void prom_smp_finish(void) | 
|  | 199 | { | 
|  | 200 | } | 
|  | 201 |  | 
|  | 202 | void core_send_ipi(int destid, unsigned int action) | 
|  | 203 | { | 
|  | 204 | int irq; | 
|  | 205 |  | 
|  | 206 | switch (action) { | 
|  | 207 | case SMP_RESCHEDULE_YOURSELF: | 
|  | 208 | irq = CPU_RESCHED_A_IRQ; | 
|  | 209 | break; | 
|  | 210 | case SMP_CALL_FUNCTION: | 
|  | 211 | irq = CPU_CALL_A_IRQ; | 
|  | 212 | break; | 
|  | 213 | default: | 
|  | 214 | panic("sendintr"); | 
|  | 215 | } | 
|  | 216 |  | 
|  | 217 | irq += cputoslice(destid); | 
|  | 218 |  | 
|  | 219 | /* | 
|  | 220 | * Convert the compact hub number to the NASID to get the correct | 
|  | 221 | * part of the address space.  Then set the interrupt bit associated | 
|  | 222 | * with the CPU we want to send the interrupt to. | 
|  | 223 | */ | 
|  | 224 | REMOTE_HUB_SEND_INTR(COMPACT_TO_NASID_NODEID(cpu_to_node(destid)), irq); | 
|  | 225 | } |