1/* 2 * Written by: Garry Forsgren, Unisys Corporation 3 * Natalie Protasevich, Unisys Corporation 4 * This file contains the code to configure and interface 5 * with Unisys ES7000 series hardware system manager. 6 * 7 * Copyright (c) 2003 Unisys Corporation. All Rights Reserved. 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of version 2 of the GNU General Public License as 11 * published by the Free Software Foundation. 12 * 13 * This program is distributed in the hope that it would be useful, but 14 * WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * You should have received a copy of the GNU General Public License along 18 * with this program; if not, write the Free Software Foundation, Inc., 59 19 * Temple Place - Suite 330, Boston MA 02111-1307, USA. 20 * 21 * Contact information: Unisys Corporation, Township Line & Union Meeting 22 * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or: 23 * 24 * http://www.unisys.com 25 */ 26 27#include <linux/module.h> 28#include <linux/types.h> 29#include <linux/kernel.h> 30#include <linux/smp.h> 31#include <linux/string.h> 32#include <linux/spinlock.h> 33#include <linux/errno.h> 34#include <linux/notifier.h> 35#include <linux/reboot.h> 36#include <linux/init.h> 37#include <linux/acpi.h> 38#include <asm/io.h> 39#include <asm/nmi.h> 40#include <asm/smp.h> 41#include <asm/apicdef.h> 42#include "es7000.h" 43#include <mach_mpparse.h> 44 45/* 46 * ES7000 Globals 47 */ 48 49volatile unsigned long *psai = NULL; 50struct mip_reg *mip_reg; 51struct mip_reg *host_reg; 52int mip_port; 53unsigned long mip_addr, host_addr; 54 55/* 56 * GSI override for ES7000 platforms. 57 */ 58 59static unsigned int base; 60 61static int 62es7000_rename_gsi(int ioapic, int gsi) 63{ 64 if (es7000_plat == ES7000_ZORRO) 65 return gsi; 66 67 if (!base) { 68 int i; 69 for (i = 0; i < nr_ioapics; i++) 70 base += nr_ioapic_registers[i]; 71 } 72 73 if (!ioapic && (gsi < 16)) 74 gsi += base; 75 return gsi; 76} 77 78void __init 79setup_unisys(void) 80{ 81 /* 82 * Determine the generation of the ES7000 currently running. 83 * 84 * es7000_plat = 1 if the machine is a 5xx ES7000 box 85 * es7000_plat = 2 if the machine is a x86_64 ES7000 box 86 * 87 */ 88 if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2)) 89 es7000_plat = ES7000_ZORRO; 90 else 91 es7000_plat = ES7000_CLASSIC; 92 ioapic_renumber_irq = es7000_rename_gsi; 93} 94 95/* 96 * Parse the OEM Table 97 */ 98 99int __init 100parse_unisys_oem (char *oemptr) 101{ 102 int i; 103 int success = 0; 104 unsigned char type, size; 105 unsigned long val; 106 char *tp = NULL; 107 struct psai *psaip = NULL; 108 struct mip_reg_info *mi; 109 struct mip_reg *host, *mip; 110 111 tp = oemptr; 112 113 tp += 8; 114 115 for (i=0; i <= 6; i++) { 116 type = *tp++; 117 size = *tp++; 118 tp -= 2; 119 switch (type) { 120 case MIP_REG: 121 mi = (struct mip_reg_info *)tp; 122 val = MIP_RD_LO(mi->host_reg); 123 host_addr = val; 124 host = (struct mip_reg *)val; 125 host_reg = __va(host); 126 val = MIP_RD_LO(mi->mip_reg); 127 mip_port = MIP_PORT(mi->mip_info); 128 mip_addr = val; 129 mip = (struct mip_reg *)val; 130 mip_reg = __va(mip); 131 Dprintk("es7000_mipcfg: host_reg = 0x%lx \n", 132 (unsigned long)host_reg); 133 Dprintk("es7000_mipcfg: mip_reg = 0x%lx \n", 134 (unsigned long)mip_reg); 135 success++; 136 break; 137 case MIP_PSAI_REG: 138 psaip = (struct psai *)tp; 139 if (tp != NULL) { 140 if (psaip->addr) 141 psai = __va(psaip->addr); 142 else 143 psai = NULL; 144 success++; 145 } 146 break; 147 default: 148 break; 149 } 150 tp += size; 151 } 152 153 if (success < 2) { 154 es7000_plat = NON_UNISYS; 155 } else 156 setup_unisys(); 157 return es7000_plat; 158} 159 160#ifdef CONFIG_ACPI 161int __init 162find_unisys_acpi_oem_table(unsigned long *oem_addr) 163{ 164 struct acpi_table_header *header = NULL; 165 int i = 0; 166 while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) { 167 if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) { 168 struct oem_table *t = (struct oem_table *)header; 169 *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr, 170 t->OEMTableSize); 171 return 0; 172 } 173 } 174 return -1; 175} 176#endif 177 178/* 179 * This file also gets compiled if CONFIG_X86_GENERICARCH is set. Generic 180 * arch already has got following function definitions (asm-generic/es7000.c) 181 * hence no need to define these for that case. 182 */ 183#ifndef CONFIG_X86_GENERICARCH 184void es7000_sw_apic(void); 185void __init enable_apic_mode(void) 186{ 187 es7000_sw_apic(); 188 return; 189} 190 191__init int mps_oem_check(struct mp_config_table *mpc, char *oem, 192 char *productid) 193{ 194 if (mpc->mpc_oemptr) { 195 struct mp_config_oemtable *oem_table = 196 (struct mp_config_oemtable *)mpc->mpc_oemptr; 197 if (!strncmp(oem, "UNISYS", 6)) 198 return parse_unisys_oem((char *)oem_table); 199 } 200 return 0; 201} 202#ifdef CONFIG_ACPI 203/* Hook from generic ACPI tables.c */ 204int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) 205{ 206 unsigned long oem_addr; 207 if (!find_unisys_acpi_oem_table(&oem_addr)) { 208 if (es7000_check_dsdt()) 209 return parse_unisys_oem((char *)oem_addr); 210 else { 211 setup_unisys(); 212 return 1; 213 } 214 } 215 return 0; 216} 217#else 218int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id) 219{ 220 return 0; 221} 222#endif 223#endif /* COFIG_X86_GENERICARCH */ 224 225static void 226es7000_spin(int n) 227{ 228 int i = 0; 229 230 while (i++ < n) 231 rep_nop(); 232} 233 234static int __init 235es7000_mip_write(struct mip_reg *mip_reg) 236{ 237 int status = 0; 238 int spin; 239 240 spin = MIP_SPIN; 241 while (((unsigned long long)host_reg->off_38 & 242 (unsigned long long)MIP_VALID) != 0) { 243 if (--spin <= 0) { 244 printk("es7000_mip_write: Timeout waiting for Host Valid Flag"); 245 return -1; 246 } 247 es7000_spin(MIP_SPIN); 248 } 249 250 memcpy(host_reg, mip_reg, sizeof(struct mip_reg)); 251 outb(1, mip_port); 252 253 spin = MIP_SPIN; 254 255 while (((unsigned long long)mip_reg->off_38 & 256 (unsigned long long)MIP_VALID) == 0) { 257 if (--spin <= 0) { 258 printk("es7000_mip_write: Timeout waiting for MIP Valid Flag"); 259 return -1; 260 } 261 es7000_spin(MIP_SPIN); 262 } 263 264 status = ((unsigned long long)mip_reg->off_0 & 265 (unsigned long long)0xffff0000000000ULL) >> 48; 266 mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 & 267 (unsigned long long)~MIP_VALID); 268 return status; 269} 270 271int 272es7000_start_cpu(int cpu, unsigned long eip) 273{ 274 unsigned long vect = 0, psaival = 0; 275 276 if (psai == NULL) 277 return -1; 278 279 vect = ((unsigned long)__pa(eip)/0x1000) << 16; 280 psaival = (0x1000000 | vect | cpu); 281 282 while (*psai & 0x1000000) 283 ; 284 285 *psai = psaival; 286 287 return 0; 288 289} 290 291int 292es7000_stop_cpu(int cpu) 293{ 294 int startup; 295 296 if (psai == NULL) 297 return -1; 298 299 startup= (0x1000000 | cpu); 300 301 while ((*psai & 0xff00ffff) != startup) 302 ; 303 304 startup = (*psai & 0xff0000) >> 16; 305 *psai &= 0xffffff; 306 307 return 0; 308 309} 310 311void __init 312es7000_sw_apic() 313{ 314 if (es7000_plat) { 315 int mip_status; 316 struct mip_reg es7000_mip_reg; 317 318 printk("ES7000: Enabling APIC mode.\n"); 319 memset(&es7000_mip_reg, 0, sizeof(struct mip_reg)); 320 es7000_mip_reg.off_0 = MIP_SW_APIC; 321 es7000_mip_reg.off_38 = (MIP_VALID); 322 while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0) 323 printk("es7000_sw_apic: command failed, status = %x\n", 324 mip_status); 325 return; 326 } 327} 328