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

root/arch/x86/kernel/numaq_32.c

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

DEFINITIONS

This source file includes following definitions.
  1. smp_dump_qct
  2. numaq_tsc_disable
  3. numaq_pre_time_init
  4. generate_logical_apicid
  5. mpc_apic_id
  6. mpc_oem_bus_info
  7. mpc_oem_pci_bus
  8. MP_translation_info
  9. mpf_checksum
  10. smp_read_mpc_oem
  11. numaq_setup_ioapic_ids
  12. numaq_mps_oem_check
  13. early_check_numaq
  14. get_memcfg_numaq

/*
 * Written by: Patricia Gaughen, IBM Corporation
 *
 * Copyright (C) 2002, IBM Corp.
 *
 * All rights reserved.          
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
 * NON INFRINGEMENT.  See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 * Send feedback to <gone@us.ibm.com>
 */

#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/mmzone.h>
#include <linux/module.h>
#include <linux/nodemask.h>
#include <asm/numaq.h>
#include <asm/topology.h>
#include <asm/processor.h>
#include <asm/mpspec.h>
#include <asm/e820.h>
#include <asm/setup.h>

#define MB_TO_PAGES(addr) ((addr) << (20 - PAGE_SHIFT))

/*
 * Function: smp_dump_qct()
 *
 * Description: gets memory layout from the quad config table.  This
 * function also updates node_online_map with the nodes (quads) present.
 */
static void __init smp_dump_qct(void)
{
        int node;
        struct eachquadmem *eq;
        struct sys_cfg_data *scd =
                (struct sys_cfg_data *)__va(SYS_CFG_DATA_PRIV_ADDR);

        nodes_clear(node_online_map);
        for_each_node(node) {
                if (scd->quads_present31_0 & (1 << node)) {
                        node_set_online(node);
                        eq = &scd->eq[node];
                        /* Convert to pages */
                        node_start_pfn[node] = MB_TO_PAGES(
                                eq->hi_shrd_mem_start - eq->priv_mem_size);
                        node_end_pfn[node] = MB_TO_PAGES(
                                eq->hi_shrd_mem_start + eq->hi_shrd_mem_size);

                        e820_register_active_regions(node, node_start_pfn[node],
                                                        node_end_pfn[node]);
                        memory_present(node,
                                node_start_pfn[node], node_end_pfn[node]);
                        node_remap_size[node] = node_memmap_size_bytes(node,
                                                        node_start_pfn[node],
                                                        node_end_pfn[node]);
                }
        }
}


void __cpuinit numaq_tsc_disable(void)
{
        if (!found_numaq)
                return;

        if (num_online_nodes() > 1) {
                printk(KERN_DEBUG "NUMAQ: disabling TSC\n");
                setup_clear_cpu_cap(X86_FEATURE_TSC);
        }
}

static int __init numaq_pre_time_init(void)
{
        numaq_tsc_disable();
        return 0;
}

int found_numaq;
/*
 * Have to match translation table entries to main table entries by counter
 * hence the mpc_record variable .... can't see a less disgusting way of
 * doing this ....
 */
struct mpc_config_translation {
        unsigned char mpc_type;
        unsigned char trans_len;
        unsigned char trans_type;
        unsigned char trans_quad;
        unsigned char trans_global;
        unsigned char trans_local;
        unsigned short trans_reserved;
};

/* x86_quirks member */
static int mpc_record;
static struct mpc_config_translation *translation_table[MAX_MPC_ENTRY]
    __cpuinitdata;

static inline int generate_logical_apicid(int quad, int phys_apicid)
{
        return (quad << 4) + (phys_apicid ? phys_apicid << 1 : 1);
}

/* x86_quirks member */
static int mpc_apic_id(struct mpc_config_processor *m)
{
        int quad = translation_table[mpc_record]->trans_quad;
        int logical_apicid = generate_logical_apicid(quad, m->mpc_apicid);

        printk(KERN_DEBUG "Processor #%d %u:%u APIC version %d (quad %d, apic %d)\n",
               m->mpc_apicid,
               (m->mpc_cpufeature & CPU_FAMILY_MASK) >> 8,
               (m->mpc_cpufeature & CPU_MODEL_MASK) >> 4,
               m->mpc_apicver, quad, logical_apicid);
        return logical_apicid;
}

int mp_bus_id_to_node[MAX_MP_BUSSES];

int mp_bus_id_to_local[MAX_MP_BUSSES];

/* x86_quirks member */
static void mpc_oem_bus_info(struct mpc_config_bus *m, char *name)
{
        int quad = translation_table[mpc_record]->trans_quad;
        int local = translation_table[mpc_record]->trans_local;

        mp_bus_id_to_node[m->mpc_busid] = quad;
        mp_bus_id_to_local[m->mpc_busid] = local;
        printk(KERN_INFO "Bus #%d is %s (node %d)\n",
               m->mpc_busid, name, quad);
}

int quad_local_to_mp_bus_id [NR_CPUS/4][4];

/* x86_quirks member */
static void mpc_oem_pci_bus(struct mpc_config_bus *m)
{
        int quad = translation_table[mpc_record]->trans_quad;
        int local = translation_table[mpc_record]->trans_local;

        quad_local_to_mp_bus_id[quad][local] = m->mpc_busid;
}

static void __init MP_translation_info(struct mpc_config_translation *m)
{
        printk(KERN_INFO
               "Translation: record %d, type %d, quad %d, global %d, local %d\n",
               mpc_record, m->trans_type, m->trans_quad, m->trans_global,
               m->trans_local);

        if (mpc_record >= MAX_MPC_ENTRY)
                printk(KERN_ERR "MAX_MPC_ENTRY exceeded!\n");
        else
                translation_table[mpc_record] = m;      /* stash this for later */
        if (m->trans_quad < MAX_NUMNODES && !node_online(m->trans_quad))
                node_set_online(m->trans_quad);
}

static int __init mpf_checksum(unsigned char *mp, int len)
{
        int sum = 0;

        while (len--)
                sum += *mp++;

        return sum & 0xFF;
}

/*
 * Read/parse the MPC oem tables
 */

static void __init smp_read_mpc_oem(struct mp_config_oemtable *oemtable,
                                    unsigned short oemsize)
{
        int count = sizeof(*oemtable);  /* the header size */
        unsigned char *oemptr = ((unsigned char *)oemtable) + count;

        mpc_record = 0;
        printk(KERN_INFO "Found an OEM MPC table at %8p - parsing it ... \n",
               oemtable);
        if (memcmp(oemtable->oem_signature, MPC_OEM_SIGNATURE, 4)) {
                printk(KERN_WARNING
                       "SMP mpc oemtable: bad signature [%c%c%c%c]!\n",
                       oemtable->oem_signature[0], oemtable->oem_signature[1],
                       oemtable->oem_signature[2], oemtable->oem_signature[3]);
                return;
        }
        if (mpf_checksum((unsigned char *)oemtable, oemtable->oem_length)) {
                printk(KERN_WARNING "SMP oem mptable: checksum error!\n");
                return;
        }
        while (count < oemtable->oem_length) {
                switch (*oemptr) {
                case MP_TRANSLATION:
                        {
                                struct mpc_config_translation *m =
                                    (struct mpc_config_translation *)oemptr;
                                MP_translation_info(m);
                                oemptr += sizeof(*m);
                                count += sizeof(*m);
                                ++mpc_record;
                                break;
                        }
                default:
                        {
                                printk(KERN_WARNING
                                       "Unrecognised OEM table entry type! - %d\n",
                                       (int)*oemptr);
                                return;
                        }
                }
        }
}

static int __init numaq_setup_ioapic_ids(void)
{
        /* so can skip it */
        return 1;
}

static struct x86_quirks numaq_x86_quirks __initdata = {
        .arch_pre_time_init     = numaq_pre_time_init,
        .arch_time_init         = NULL,
        .arch_pre_intr_init     = NULL,
        .arch_memory_setup      = NULL,
        .arch_intr_init         = NULL,
        .arch_trap_init         = NULL,
        .mach_get_smp_config    = NULL,
        .mach_find_smp_config   = NULL,
        .mpc_record             = &mpc_record,
        .mpc_apic_id            = mpc_apic_id,
        .mpc_oem_bus_info       = mpc_oem_bus_info,
        .mpc_oem_pci_bus        = mpc_oem_pci_bus,
        .smp_read_mpc_oem       = smp_read_mpc_oem,
        .setup_ioapic_ids       = numaq_setup_ioapic_ids,
};

void numaq_mps_oem_check(struct mp_config_table *mpc, char *oem,
                                 char *productid)
{
        if (strncmp(oem, "IBM NUMA", 8))
                printk("Warning!  Not a NUMA-Q system!\n");
        else
                found_numaq = 1;
}

static __init void early_check_numaq(void)
{
        /*
         * Find possible boot-time SMP configuration:
         */
        early_find_smp_config();
        /*
         * get boot-time SMP configuration:
         */
        if (smp_found_config)
                early_get_smp_config();

        if (found_numaq)
                x86_quirks = &numaq_x86_quirks;
}

int __init get_memcfg_numaq(void)
{
        early_check_numaq();
        if (!found_numaq)
                return 0;
        smp_dump_qct();
        return 1;
}

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

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