patch-2_6_7-vs1_9_1_12
[linux-2.6.git] / arch / i386 / mach-es7000 / es7000plat.c
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
44 /*
45  * ES7000 Globals
46  */
47
48 volatile unsigned long  *psai = NULL;
49 struct mip_reg          *mip_reg;
50 struct mip_reg          *host_reg;
51 int                     mip_port;
52 unsigned long           mip_addr, host_addr;
53
54 static int __init
55 es7000_rename_gsi(int ioapic, int gsi)
56 {
57         if (ioapic)
58                 return gsi;
59         else {
60                 if (gsi == 0)
61                         return 13;
62                 if (gsi == 1)
63                         return 16;
64                 if (gsi == 4)
65                         return 17;
66                 if (gsi == 6)
67                         return 18;
68                 if (gsi == 7)
69                         return 19;
70                 if (gsi == 8)
71                         return 20;
72                 return gsi;
73         }
74 }
75
76 /*
77  * Parse the OEM Table
78  */
79
80 int __init
81 parse_unisys_oem (char *oemptr, int oem_entries)
82 {
83         int                     i;
84         int                     success = 0;
85         unsigned char           type, size;
86         unsigned long           val;
87         char                    *tp = NULL;
88         struct psai             *psaip = NULL;
89         struct mip_reg_info     *mi;
90         struct mip_reg          *host, *mip;
91
92         tp = oemptr;
93
94         tp += 8;
95
96         for (i=0; i <= oem_entries; i++) {
97                 type = *tp++;
98                 size = *tp++;
99                 tp -= 2;
100                 switch (type) {
101                 case MIP_REG:
102                         mi = (struct mip_reg_info *)tp;
103                         val = MIP_RD_LO(mi->host_reg);
104                         host_addr = val;
105                         host = (struct mip_reg *)val;
106                         host_reg = __va(host);
107                         val = MIP_RD_LO(mi->mip_reg);
108                         mip_port = MIP_PORT(mi->mip_info);
109                         mip_addr = val;
110                         mip = (struct mip_reg *)val;
111                         mip_reg = __va(mip);
112                         Dprintk("es7000_mipcfg: host_reg = 0x%lx \n",
113                                 (unsigned long)host_reg);
114                         Dprintk("es7000_mipcfg: mip_reg = 0x%lx \n",
115                                 (unsigned long)mip_reg);
116                         success++;
117                         break;
118                 case MIP_PSAI_REG:
119                         psaip = (struct psai *)tp;
120                         if (tp != NULL) {
121                                 if (psaip->addr)
122                                         psai = __va(psaip->addr);
123                                 else
124                                         psai = NULL;
125                                 success++;
126                         }
127                         break;
128                 default:
129                         break;
130                 }
131                 if (i == 6) break;
132                 tp += size;
133         }
134
135         if (success < 2) {
136                 es7000_plat = 0;
137         } else {
138                 printk("\nEnabling ES7000 specific features...\n");
139                 es7000_plat = 1;
140                 platform_rename_gsi = es7000_rename_gsi;
141         }
142         return es7000_plat;
143 }
144
145 int __init
146 find_unisys_acpi_oem_table(unsigned long *oem_addr, int *length)
147 {
148         struct acpi_table_rsdp          *rsdp = NULL;
149         unsigned long                   rsdp_phys = 0;
150         struct acpi_table_header        *header = NULL;
151         int                             i;
152         struct acpi_table_sdt           sdt;
153
154         rsdp_phys = acpi_find_rsdp();
155         rsdp = __va(rsdp_phys);
156         if (rsdp->rsdt_address) {
157                 struct acpi_table_rsdt  *mapped_rsdt = NULL;
158                 sdt.pa = rsdp->rsdt_address;
159
160                 header = (struct acpi_table_header *)
161                         __acpi_map_table(sdt.pa, sizeof(struct acpi_table_header));
162                 if (!header)
163                         return -ENODEV;
164
165                 sdt.count = (header->length - sizeof(struct acpi_table_header)) >> 3;
166                 mapped_rsdt = (struct acpi_table_rsdt *)
167                         __acpi_map_table(sdt.pa, header->length);
168                 if (!mapped_rsdt)
169                         return -ENODEV;
170
171                 header = &mapped_rsdt->header;
172
173                 for (i = 0; i < sdt.count; i++)
174                         sdt.entry[i].pa = (unsigned long) mapped_rsdt->entry[i];
175         };
176         for (i = 0; i < sdt.count; i++) {
177
178                 header = (struct acpi_table_header *)
179                         __acpi_map_table(sdt.entry[i].pa,
180                                 sizeof(struct acpi_table_header));
181                 if (!header)
182                         continue;
183                 if (!strncmp((char *) &header->signature, "OEM1", 4)) {
184                         if (!strncmp((char *) &header->oem_id, "UNISYS", 6)) {
185                                 void *addr;
186                                 struct oem_table *t;
187                                 acpi_table_print(header, sdt.entry[i].pa);
188                                 t = (struct oem_table *) __acpi_map_table(sdt.entry[i].pa, header->length);
189                                 addr = (void *) __acpi_map_table(t->OEMTableAddr, t->OEMTableSize);
190                                 *length = header->length;
191                                 *oem_addr = (unsigned long) addr;
192                                 return 0;
193                         }
194                 }
195         }
196         printk("ES7000: did not find Unisys ACPI OEM table!\n");
197         return -1;
198 }
199
200 static void
201 es7000_spin(int n)
202 {
203         int i = 0;
204
205         while (i++ < n)
206                 rep_nop();
207 }
208
209 static int __init
210 es7000_mip_write(struct mip_reg *mip_reg)
211 {
212         int                     status = 0;
213         int                     spin;
214
215         spin = MIP_SPIN;
216         while (((unsigned long long)host_reg->off_38 &
217                 (unsigned long long)MIP_VALID) != 0) {
218                         if (--spin <= 0) {
219                                 printk("es7000_mip_write: Timeout waiting for Host Valid Flag");
220                                 return -1;
221                         }
222                 es7000_spin(MIP_SPIN);
223         }
224
225         memcpy(host_reg, mip_reg, sizeof(struct mip_reg));
226         outb(1, mip_port);
227
228         spin = MIP_SPIN;
229
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
239         status = ((unsigned long long)mip_reg->off_0 &
240                 (unsigned long long)0xffff0000000000) >> 48;
241         mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 &
242                 (unsigned long long)~MIP_VALID);
243         return status;
244 }
245
246 int
247 es7000_start_cpu(int cpu, unsigned long eip)
248 {
249         unsigned long vect = 0, psaival = 0;
250
251         if (psai == NULL)
252                 return -1;
253
254         vect = ((unsigned long)__pa(eip)/0x1000) << 16;
255         psaival = (0x1000000 | vect | cpu);
256
257         while (*psai & 0x1000000)
258                 ;
259
260         *psai = psaival;
261
262         return 0;
263
264 }
265
266 int
267 es7000_stop_cpu(int cpu)
268 {
269         int startup;
270
271         if (psai == NULL)
272                 return -1;
273
274         startup= (0x1000000 | cpu);
275
276         while ((*psai & 0xff00ffff) != startup)
277                 ;
278
279         startup = (*psai & 0xff0000) >> 16;
280         *psai &= 0xffffff;
281
282         return 0;
283
284 }
285
286 void __init
287 es7000_sw_apic()
288 {
289         if (es7000_plat) {
290                 int mip_status;
291                 struct mip_reg es7000_mip_reg;
292
293                 printk("ES7000: Enabling APIC mode.\n");
294                 memset(&es7000_mip_reg, 0, sizeof(struct mip_reg));
295                 es7000_mip_reg.off_0 = MIP_SW_APIC;
296                 es7000_mip_reg.off_38 = (MIP_VALID);
297                 while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0)
298                         printk("es7000_sw_apic: command failed, status = %x\n",
299                                 mip_status);
300                 return;
301         }
302 }