linux/arch/x86/kernel/es7000_32.c
<<
>>
Prefs
   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 <mach_mpparse.h>
  43
  44/*
  45 * ES7000 chipsets
  46 */
  47
  48#define NON_UNISYS              0
  49#define ES7000_CLASSIC          1
  50#define ES7000_ZORRO            2
  51
  52
  53#define MIP_REG                 1
  54#define MIP_PSAI_REG            4
  55
  56#define MIP_BUSY                1
  57#define MIP_SPIN                0xf0000
  58#define MIP_VALID               0x0100000000000000ULL
  59#define MIP_PORT(VALUE) ((VALUE >> 32) & 0xffff)
  60
  61#define MIP_RD_LO(VALUE)        (VALUE & 0xffffffff)
  62
  63struct mip_reg_info {
  64        unsigned long long mip_info;
  65        unsigned long long delivery_info;
  66        unsigned long long host_reg;
  67        unsigned long long mip_reg;
  68};
  69
  70struct part_info {
  71        unsigned char type;
  72        unsigned char length;
  73        unsigned char part_id;
  74        unsigned char apic_mode;
  75        unsigned long snum;
  76        char ptype[16];
  77        char sname[64];
  78        char pname[64];
  79};
  80
  81struct psai {
  82        unsigned long long entry_type;
  83        unsigned long long addr;
  84        unsigned long long bep_addr;
  85};
  86
  87struct es7000_mem_info {
  88        unsigned char type;
  89        unsigned char length;
  90        unsigned char resv[6];
  91        unsigned long long  start;
  92        unsigned long long  size;
  93};
  94
  95struct es7000_oem_table {
  96        unsigned long long hdr;
  97        struct mip_reg_info mip;
  98        struct part_info pif;
  99        struct es7000_mem_info shm;
 100        struct psai psai;
 101};
 102
 103#ifdef CONFIG_ACPI
 104
 105struct oem_table {
 106        struct acpi_table_header Header;
 107        u32 OEMTableAddr;
 108        u32 OEMTableSize;
 109};
 110
 111extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
 112extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
 113#endif
 114
 115struct mip_reg {
 116        unsigned long long off_0;
 117        unsigned long long off_8;
 118        unsigned long long off_10;
 119        unsigned long long off_18;
 120        unsigned long long off_20;
 121        unsigned long long off_28;
 122        unsigned long long off_30;
 123        unsigned long long off_38;
 124};
 125
 126#define MIP_SW_APIC             0x1020b
 127#define MIP_FUNC(VALUE)         (VALUE & 0xff)
 128
 129/*
 130 * ES7000 Globals
 131 */
 132
 133static volatile unsigned long   *psai = NULL;
 134static struct mip_reg           *mip_reg;
 135static struct mip_reg           *host_reg;
 136static int                      mip_port;
 137static unsigned long            mip_addr, host_addr;
 138
 139int es7000_plat;
 140
 141/*
 142 * GSI override for ES7000 platforms.
 143 */
 144
 145static unsigned int base;
 146
 147static int
 148es7000_rename_gsi(int ioapic, int gsi)
 149{
 150        if (es7000_plat == ES7000_ZORRO)
 151                return gsi;
 152
 153        if (!base) {
 154                int i;
 155                for (i = 0; i < nr_ioapics; i++)
 156                        base += nr_ioapic_registers[i];
 157        }
 158
 159        if (!ioapic && (gsi < 16))
 160                gsi += base;
 161        return gsi;
 162}
 163
 164void __init
 165setup_unisys(void)
 166{
 167        /*
 168         * Determine the generation of the ES7000 currently running.
 169         *
 170         * es7000_plat = 1 if the machine is a 5xx ES7000 box
 171         * es7000_plat = 2 if the machine is a x86_64 ES7000 box
 172         *
 173         */
 174        if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
 175                es7000_plat = ES7000_ZORRO;
 176        else
 177                es7000_plat = ES7000_CLASSIC;
 178        ioapic_renumber_irq = es7000_rename_gsi;
 179}
 180
 181/*
 182 * Parse the OEM Table
 183 */
 184
 185int __init
 186parse_unisys_oem (char *oemptr)
 187{
 188        int                     i;
 189        int                     success = 0;
 190        unsigned char           type, size;
 191        unsigned long           val;
 192        char                    *tp = NULL;
 193        struct psai             *psaip = NULL;
 194        struct mip_reg_info     *mi;
 195        struct mip_reg          *host, *mip;
 196
 197        tp = oemptr;
 198
 199        tp += 8;
 200
 201        for (i=0; i <= 6; i++) {
 202                type = *tp++;
 203                size = *tp++;
 204                tp -= 2;
 205                switch (type) {
 206                case MIP_REG:
 207                        mi = (struct mip_reg_info *)tp;
 208                        val = MIP_RD_LO(mi->host_reg);
 209                        host_addr = val;
 210                        host = (struct mip_reg *)val;
 211                        host_reg = __va(host);
 212                        val = MIP_RD_LO(mi->mip_reg);
 213                        mip_port = MIP_PORT(mi->mip_info);
 214                        mip_addr = val;
 215                        mip = (struct mip_reg *)val;
 216                        mip_reg = __va(mip);
 217                        pr_debug("es7000_mipcfg: host_reg = 0x%lx \n",
 218                                 (unsigned long)host_reg);
 219                        pr_debug("es7000_mipcfg: mip_reg = 0x%lx \n",
 220                                 (unsigned long)mip_reg);
 221                        success++;
 222                        break;
 223                case MIP_PSAI_REG:
 224                        psaip = (struct psai *)tp;
 225                        if (tp != NULL) {
 226                                if (psaip->addr)
 227                                        psai = __va(psaip->addr);
 228                                else
 229                                        psai = NULL;
 230                                success++;
 231                        }
 232                        break;
 233                default:
 234                        break;
 235                }
 236                tp += size;
 237        }
 238
 239        if (success < 2) {
 240                es7000_plat = NON_UNISYS;
 241        } else
 242                setup_unisys();
 243        return es7000_plat;
 244}
 245
 246#ifdef CONFIG_ACPI
 247static unsigned long oem_addrX;
 248static unsigned long oem_size;
 249int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
 250{
 251        struct acpi_table_header *header = NULL;
 252        int i = 0;
 253
 254        while (ACPI_SUCCESS(acpi_get_table("OEM1", i++, &header))) {
 255                if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
 256                        struct oem_table *t = (struct oem_table *)header;
 257
 258                        oem_addrX = t->OEMTableAddr;
 259                        oem_size = t->OEMTableSize;
 260
 261                        *oem_addr = (unsigned long)__acpi_map_table(oem_addrX,
 262                                                                    oem_size);
 263                        return 0;
 264                }
 265        }
 266        return -1;
 267}
 268
 269void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
 270{
 271}
 272#endif
 273
 274static void
 275es7000_spin(int n)
 276{
 277        int i = 0;
 278
 279        while (i++ < n)
 280                rep_nop();
 281}
 282
 283static int __init
 284es7000_mip_write(struct mip_reg *mip_reg)
 285{
 286        int                     status = 0;
 287        int                     spin;
 288
 289        spin = MIP_SPIN;
 290        while (((unsigned long long)host_reg->off_38 &
 291                (unsigned long long)MIP_VALID) != 0) {
 292                        if (--spin <= 0) {
 293                                printk("es7000_mip_write: Timeout waiting for Host Valid Flag");
 294                                return -1;
 295                        }
 296                es7000_spin(MIP_SPIN);
 297        }
 298
 299        memcpy(host_reg, mip_reg, sizeof(struct mip_reg));
 300        outb(1, mip_port);
 301
 302        spin = MIP_SPIN;
 303
 304        while (((unsigned long long)mip_reg->off_38 &
 305                (unsigned long long)MIP_VALID) == 0) {
 306                if (--spin <= 0) {
 307                        printk("es7000_mip_write: Timeout waiting for MIP Valid Flag");
 308                        return -1;
 309                }
 310                es7000_spin(MIP_SPIN);
 311        }
 312
 313        status = ((unsigned long long)mip_reg->off_0 &
 314                (unsigned long long)0xffff0000000000ULL) >> 48;
 315        mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 &
 316                (unsigned long long)~MIP_VALID);
 317        return status;
 318}
 319
 320int
 321es7000_start_cpu(int cpu, unsigned long eip)
 322{
 323        unsigned long vect = 0, psaival = 0;
 324
 325        if (psai == NULL)
 326                return -1;
 327
 328        vect = ((unsigned long)__pa(eip)/0x1000) << 16;
 329        psaival = (0x1000000 | vect | cpu);
 330
 331        while (*psai & 0x1000000)
 332                ;
 333
 334        *psai = psaival;
 335
 336        return 0;
 337
 338}
 339
 340void __init
 341es7000_sw_apic(void)
 342{
 343        if (es7000_plat) {
 344                int mip_status;
 345                struct mip_reg es7000_mip_reg;
 346
 347                printk("ES7000: Enabling APIC mode.\n");
 348                memset(&es7000_mip_reg, 0, sizeof(struct mip_reg));
 349                es7000_mip_reg.off_0 = MIP_SW_APIC;
 350                es7000_mip_reg.off_38 = (MIP_VALID);
 351                while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0)
 352                        printk("es7000_sw_apic: command failed, status = %x\n",
 353                                mip_status);
 354                return;
 355        }
 356}
 357
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.