[funini.com] -> [kei@sodan] -> Kernel Reading

root/arch/x86/kernel/es7000_32.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. es7000_rename_gsi
  2. setup_unisys
  3. parse_unisys_oem
  4. find_unisys_acpi_oem_table
  5. unmap_unisys_acpi_oem_table
  6. es7000_spin
  7. es7000_mip_write
  8. es7000_start_cpu
  9. es7000_sw_apic

/*
 * Written by: Garry Forsgren, Unisys Corporation
 *             Natalie Protasevich, Unisys Corporation
 * This file contains the code to configure and interface
 * with Unisys ES7000 series hardware system manager.
 *
 * Copyright (c) 2003 Unisys Corporation.  All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2 of the GNU General Public License as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it would be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write the Free Software Foundation, Inc., 59
 * Temple Place - Suite 330, Boston MA 02111-1307, USA.
 *
 * Contact information: Unisys Corporation, Township Line & Union Meeting
 * Roads-A, Unisys Way, Blue Bell, Pennsylvania, 19424, or:
 *
 * http://www.unisys.com
 */

#include <linux/module.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/smp.h>
#include <linux/string.h>
#include <linux/spinlock.h>
#include <linux/errno.h>
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <asm/io.h>
#include <asm/nmi.h>
#include <asm/smp.h>
#include <asm/apicdef.h>
#include <mach_mpparse.h>

/*
 * ES7000 chipsets
 */

#define NON_UNISYS              0
#define ES7000_CLASSIC          1
#define ES7000_ZORRO            2


#define MIP_REG                 1
#define MIP_PSAI_REG            4

#define MIP_BUSY                1
#define MIP_SPIN                0xf0000
#define MIP_VALID               0x0100000000000000ULL
#define MIP_PORT(VALUE) ((VALUE >> 32) & 0xffff)

#define MIP_RD_LO(VALUE)        (VALUE & 0xffffffff)

struct mip_reg_info {
        unsigned long long mip_info;
        unsigned long long delivery_info;
        unsigned long long host_reg;
        unsigned long long mip_reg;
};

struct part_info {
        unsigned char type;
        unsigned char length;
        unsigned char part_id;
        unsigned char apic_mode;
        unsigned long snum;
        char ptype[16];
        char sname[64];
        char pname[64];
};

struct psai {
        unsigned long long entry_type;
        unsigned long long addr;
        unsigned long long bep_addr;
};

struct es7000_mem_info {
        unsigned char type;
        unsigned char length;
        unsigned char resv[6];
        unsigned long long  start;
        unsigned long long  size;
};

struct es7000_oem_table {
        unsigned long long hdr;
        struct mip_reg_info mip;
        struct part_info pif;
        struct es7000_mem_info shm;
        struct psai psai;
};

#ifdef CONFIG_ACPI

struct oem_table {
        struct acpi_table_header Header;
        u32 OEMTableAddr;
        u32 OEMTableSize;
};

extern int find_unisys_acpi_oem_table(unsigned long *oem_addr);
extern void unmap_unisys_acpi_oem_table(unsigned long oem_addr);
#endif

struct mip_reg {
        unsigned long long off_0;
        unsigned long long off_8;
        unsigned long long off_10;
        unsigned long long off_18;
        unsigned long long off_20;
        unsigned long long off_28;
        unsigned long long off_30;
        unsigned long long off_38;
};

#define MIP_SW_APIC             0x1020b
#define MIP_FUNC(VALUE)         (VALUE & 0xff)

/*
 * ES7000 Globals
 */

static volatile unsigned long   *psai = NULL;
static struct mip_reg           *mip_reg;
static struct mip_reg           *host_reg;
static int                      mip_port;
static unsigned long            mip_addr, host_addr;

int es7000_plat;

/*
 * GSI override for ES7000 platforms.
 */

static unsigned int base;

static int
es7000_rename_gsi(int ioapic, int gsi)
{
        if (es7000_plat == ES7000_ZORRO)
                return gsi;

        if (!base) {
                int i;
                for (i = 0; i < nr_ioapics; i++)
                        base += nr_ioapic_registers[i];
        }

        if (!ioapic && (gsi < 16))
                gsi += base;
        return gsi;
}

void __init
setup_unisys(void)
{
        /*
         * Determine the generation of the ES7000 currently running.
         *
         * es7000_plat = 1 if the machine is a 5xx ES7000 box
         * es7000_plat = 2 if the machine is a x86_64 ES7000 box
         *
         */
        if (!(boot_cpu_data.x86 <= 15 && boot_cpu_data.x86_model <= 2))
                es7000_plat = ES7000_ZORRO;
        else
                es7000_plat = ES7000_CLASSIC;
        ioapic_renumber_irq = es7000_rename_gsi;
}

/*
 * Parse the OEM Table
 */

int __init
parse_unisys_oem (char *oemptr)
{
        int                     i;
        int                     success = 0;
        unsigned char           type, size;
        unsigned long           val;
        char                    *tp = NULL;
        struct psai             *psaip = NULL;
        struct mip_reg_info     *mi;
        struct mip_reg          *host, *mip;

        tp = oemptr;

        tp += 8;

        for (i=0; i <= 6; i++) {
                type = *tp++;
                size = *tp++;
                tp -= 2;
                switch (type) {
                case MIP_REG:
                        mi = (struct mip_reg_info *)tp;
                        val = MIP_RD_LO(mi->host_reg);
                        host_addr = val;
                        host = (struct mip_reg *)val;
                        host_reg = __va(host);
                        val = MIP_RD_LO(mi->mip_reg);
                        mip_port = MIP_PORT(mi->mip_info);
                        mip_addr = val;
                        mip = (struct mip_reg *)val;
                        mip_reg = __va(mip);
                        pr_debug("es7000_mipcfg: host_reg = 0x%lx \n",
                                 (unsigned long)host_reg);
                        pr_debug("es7000_mipcfg: mip_reg = 0x%lx \n",
                                 (unsigned long)mip_reg);
                        success++;
                        break;
                case MIP_PSAI_REG:
                        psaip = (struct psai *)tp;
                        if (tp != NULL) {
                                if (psaip->addr)
                                        psai = __va(psaip->addr);
                                else
                                        psai = NULL;
                                success++;
                        }
                        break;
                default:
                        break;
                }
                tp += size;
        }

        if (success < 2) {
                es7000_plat = NON_UNISYS;
        } else
                setup_unisys();
        return es7000_plat;
}

#ifdef CONFIG_ACPI
static unsigned long oem_addrX;
static unsigned long oem_size;
int __init find_unisys_acpi_oem_table(unsigned long *oem_addr)
{
        struct acpi_table_header *header = NULL;
        int i = 0;
        acpi_size tbl_size;

        while (ACPI_SUCCESS(acpi_get_table_with_size("OEM1", i++, &header, &tbl_size))) {
                if (!memcmp((char *) &header->oem_id, "UNISYS", 6)) {
                        struct oem_table *t = (struct oem_table *)header;

                        oem_addrX = t->OEMTableAddr;
                        oem_size = t->OEMTableSize;
                        early_acpi_os_unmap_memory(header, tbl_size);

                        *oem_addr = (unsigned long)__acpi_map_table(oem_addrX,
                                                                    oem_size);
                        return 0;
                }
                early_acpi_os_unmap_memory(header, tbl_size);
        }
        return -1;
}

void __init unmap_unisys_acpi_oem_table(unsigned long oem_addr)
{
        if (!oem_addr)
                return;

        __acpi_unmap_table((char *)oem_addr, oem_size);
}
#endif

static void
es7000_spin(int n)
{
        int i = 0;

        while (i++ < n)
                rep_nop();
}

static int __init
es7000_mip_write(struct mip_reg *mip_reg)
{
        int                     status = 0;
        int                     spin;

        spin = MIP_SPIN;
        while (((unsigned long long)host_reg->off_38 &
                (unsigned long long)MIP_VALID) != 0) {
                        if (--spin <= 0) {
                                printk("es7000_mip_write: Timeout waiting for Host Valid Flag");
                                return -1;
                        }
                es7000_spin(MIP_SPIN);
        }

        memcpy(host_reg, mip_reg, sizeof(struct mip_reg));
        outb(1, mip_port);

        spin = MIP_SPIN;

        while (((unsigned long long)mip_reg->off_38 &
                (unsigned long long)MIP_VALID) == 0) {
                if (--spin <= 0) {
                        printk("es7000_mip_write: Timeout waiting for MIP Valid Flag");
                        return -1;
                }
                es7000_spin(MIP_SPIN);
        }

        status = ((unsigned long long)mip_reg->off_0 &
                (unsigned long long)0xffff0000000000ULL) >> 48;
        mip_reg->off_38 = ((unsigned long long)mip_reg->off_38 &
                (unsigned long long)~MIP_VALID);
        return status;
}

int
es7000_start_cpu(int cpu, unsigned long eip)
{
        unsigned long vect = 0, psaival = 0;

        if (psai == NULL)
                return -1;

        vect = ((unsigned long)__pa(eip)/0x1000) << 16;
        psaival = (0x1000000 | vect | cpu);

        while (*psai & 0x1000000)
                ;

        *psai = psaival;

        return 0;

}

void __init
es7000_sw_apic(void)
{
        if (es7000_plat) {
                int mip_status;
                struct mip_reg es7000_mip_reg;

                printk("ES7000: Enabling APIC mode.\n");
                memset(&es7000_mip_reg, 0, sizeof(struct mip_reg));
                es7000_mip_reg.off_0 = MIP_SW_APIC;
                es7000_mip_reg.off_38 = (MIP_VALID);
                while ((mip_status = es7000_mip_write(&es7000_mip_reg)) != 0)
                        printk("es7000_sw_apic: command failed, status = %x\n",
                                mip_status);
                return;
        }
}

/* [<][>][^][v][top][bottom][index][help] */

[funini.com] -> [kei@sodan] -> Kernel Reading