es7000plat.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  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. #include <linux/module.h>
  27. #include <linux/types.h>
  28. #include <linux/kernel.h>
  29. #include <linux/smp.h>
  30. #include <linux/string.h>
  31. #include <linux/spinlock.h>
  32. #include <linux/errno.h>
  33. #include <linux/notifier.h>
  34. #include <linux/reboot.h>
  35. #include <linux/init.h>
  36. #include <linux/acpi.h>
  37. #include <asm/io.h>
  38. #include <asm/nmi.h>
  39. #include <asm/smp.h>
  40. #include <asm/apicdef.h>
  41. #include "es7000.h"
  42. #include <mach_mpparse.h>
  43. /*
  44. * ES7000 Globals
  45. */
  46. volatile unsigned long *psai = NULL;
  47. struct mip_reg *mip_reg;
  48. struct mip_reg *host_reg;
  49. int mip_port;
  50. unsigned long mip_addr, host_addr;
  51. /*
  52. * GSI override for ES7000 platforms.
  53. */
  54. static unsigned int base;
  55. static int
  56. es7000_rename_gsi(int ioapic, int gsi)
  57. {
  58. if (es7000_plat == ES7000_ZORRO)
  59. return gsi;
  60. if (!base) {
  61. int i;
  62. for (i = 0; i < nr_ioapics; i++)
  63. base += nr_ioapic_registers[i];
  64. }
  65. if (!ioapic && (gsi < 16))
  66. gsi += base;
  67. return gsi;
  68. }
  69. void __init
  70. setup_unisys(void)
  71. {
  72. /*
  73. * Determine the generation of the ES7000 currently running.
  74. *
  75. * es7000_plat = 1 if the machine is a 5xx ES7000 box
  76. * es7000_plat = 2 if the machine is a x86_64 ES7000 box
  77. *
  78. */
  79. if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
  80. es7000_plat = ES7000_ZORRO;
  81. else
  82. es7000_plat = ES7000_CLASSIC;
  83. ioapic_renumber_irq = es7000_rename_gsi;
  84. }
  85. /*
  86. * Parse the OEM Table
  87. */
  88. int __init
  89. parse_unisys_oem (char *oemptr)
  90. {
  91. int i;
  92. int success = 0;
  93. unsigned char type, size;
  94. unsigned long val;
  95. char *tp = NULL;
  96. struct psai *psaip = NULL;
  97. struct mip_reg_info *mi;
  98. struct mip_reg *host, *mip;
  99. tp = oemptr;
  100. tp += 8;
  101. for (i=0; i <= 6; i++) {
  102. type = *tp++;
  103. size = *tp++;
  104. tp -= 2;
  105. switch (type) {
  106. case MIP_REG:
  107. mi = (struct mip_reg_info *)tp;
  108. val = MIP_RD_LO(mi->host_reg);
  109. host_addr = val;
  110. host = (struct mip_reg *)val;
  111. host_reg = __va(host);
  112. val = MIP_RD_LO(mi->mip_reg);
  113. mip_port = MIP_PORT(mi->mip_info);
  114. mip_addr = val;
  115. mip = (struct mip_reg *)val;
  116. mip_reg = __va(mip);
  117. Dprintk("es7000_mipcfg: host_reg = 0x%lx \n",
  118. (unsigned long)host_reg);
  119. Dprintk("es7000_mipcfg: mip_reg = 0x%lx \n",
  120. (unsigned long)mip_reg);
  121. success++;
  122. break;
  123. case MIP_PSAI_REG:
  124. psaip = (struct psai *)tp;
  125. if (tp != NULL) {
  126. if (psaip->addr)
  127. psai = __va(psaip->addr);
  128. else
  129. psai = NULL;
  130. success++;
  131. }
  132. break;
  133. default:
  134. break;
  135. }
  136. tp += size;
  137. }
  138. if (success < 2) {
  139. es7000_plat = NON_UNISYS;
  140. } else
  141. setup_unisys();
  142. return es7000_plat;
  143. }
  144. #ifdef CONFIG_ACPI
  145. int __init
  146. find_unisys_acpi_oem_table(unsigned long *oem_addr)
  147. {
  148. struct acpi_table_header *header = NULL;
  149. int i = 0;
  150. while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
  151. if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
  152. struct oem_table *t = (struct oem_table *)header;
  153. *oem_addr = (unsigned long)__acpi_map_table(t->OEMTableAddr,
  154. t->OEMTableSize);
  155. return 0;
  156. }
  157. }
  158. return -1;
  159. }
  160. #endif
  161. /*
  162. * This file also gets compiled if CONFIG_X86_GENERICARCH is set. Generic
  163. * arch already has got following function definitions (asm-generic/es7000.c)
  164. * hence no need to define these for that case.
  165. */
  166. #ifndef CONFIG_X86_GENERICARCH
  167. void es7000_sw_apic(void);
  168. void __init enable_apic_mode(void)
  169. {
  170. es7000_sw_apic();
  171. return;
  172. }
  173. __init int mps_oem_check(struct mp_config_table *mpc, char *oem,
  174. char *productid)
  175. {
  176. if (mpc->mpc_oemptr) {
  177. struct mp_config_oemtable *oem_table =
  178. (struct mp_config_oemtable *)mpc->mpc_oemptr;
  179. if (!strncmp(oem, "UNISYS", 6))
  180. return parse_unisys_oem((char *)oem_table);
  181. }
  182. return 0;
  183. }
  184. #ifdef CONFIG_ACPI
  185. /* Hook from generic ACPI tables.c */
  186. int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
  187. {
  188. unsigned long oem_addr;
  189. if (!find_unisys_acpi_oem_table(&oem_addr)) {
  190. if (es7000_check_dsdt())
  191. return parse_unisys_oem((char *)oem_addr);
  192. else {
  193. setup_unisys();
  194. return 1;
  195. }
  196. }
  197. return 0;
  198. }
  199. #else
  200. int __init acpi_madt_oem_check(char *oem_id, char *oem_table_id)
  201. {
  202. return 0;
  203. }
  204. #endif
  205. #endif /* COFIG_X86_GENERICARCH */
  206. static void
  207. es7000_spin(int n)
  208. {
  209. int i = 0;
  210. while (i++ < n)
  211. rep_nop();
  212. }
  213. static int __init
  214. es7000_mip_write(struct mip_reg *mip_reg)
  215. {
  216. int status = 0;
  217. int spin;
  218. spin = MIP_SPIN;
  219. while (((unsigned long long)host_reg->off_38 &
  220. (unsigned long long)MIP_VALID) != 0) {
  221. if (--spin <= 0) {
  222. printk("es7000_mip_write: Timeout waiting for Host Valid Flag");
  223. return -1;
  224. }
  225. es7000_spin(MIP_SPIN);
  226. }
  227. memcpy(host_reg, mip_reg, sizeof(struct mip_reg));
  228. outb(1, mip_port);
  229. spin = MIP_SPIN;
  230. while (((unsigned long long)mip_reg->off_38 &
  231. (unsigned long long)MIP_VALID) == 0) {
  232. if (--spin <= 0) {
  233. printk("es7000_mip_write: Timeout waiting for MIP Valid Flag");
  234. return -1;
  235. }
  236. es7000_spin(MIP_SPIN);
  237. }
  238. status = ((unsigned long long)mip_reg->off_0 &
  239. (unsigned long long)0xffff0000000000ULL) >> 48;
  240. mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 &
  241. (unsigned long long)~MIP_VALID);
  242. return status;
  243. }
  244. int
  245. es7000_start_cpu(int cpu, unsigned long eip)
  246. {
  247. unsigned long vect = 0, psaival = 0;
  248. if (psai == NULL)
  249. return -1;
  250. vect = ((unsigned long)__pa(eip)/0x1000) << 16;
  251. psaival = (0x1000000 | vect | cpu);
  252. while (*psai & 0x1000000)
  253. ;
  254. *psai = psaival;
  255. return 0;
  256. }
  257. int
  258. es7000_stop_cpu(int cpu)
  259. {
  260. int startup;
  261. if (psai == NULL)
  262. return -1;
  263. startup= (0x1000000 | cpu);
  264. while ((*psai & 0xff00ffff) != startup)
  265. ;
  266. startup = (*psai & 0xff0000) >> 16;
  267. *psai &= 0xffffff;
  268. return 0;
  269. }
  270. void __init
  271. es7000_sw_apic()
  272. {
  273. if (es7000_plat) {
  274. int mip_status;
  275. struct mip_reg es7000_mip_reg;
  276. printk("ES7000: Enabling APIC mode.\n");
  277. memset(&es7000_mip_reg, 0, sizeof(struct mip_reg));
  278. es7000_mip_reg.off_0 = MIP_SW_APIC;
  279. es7000_mip_reg.off_38 = (MIP_VALID);
  280. while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0)
  281. printk("es7000_sw_apic: command failed, status = %x\n",
  282. mip_status);
  283. return;
  284. }
  285. }