lkml.org 
[lkml]   [2011]   [Nov]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[043/264] x86: uv2: Workaround for UV2 Hub bug (system global address format)
    3.1-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Jack Steiner <steiner@sgi.com>

    commit 6a469e4665bc158599de55d64388861d0a9f10f4 upstream.

    This is a workaround for a UV2 hub bug that affects the format of system
    global addresses.

    The GRU API for UV2 was inadvertently broken by a hardware change. The
    format of the physical address used for TLB dropins and for addresses used
    with instructions running in unmapped mode has changed. This change was
    not documented and became apparent only when diags failed running on
    system simulators.

    For UV1, TLB and GRU instruction physical addresses are identical to
    socket physical addresses (although high NASID bits must be OR'ed into the
    address).

    For UV2, socket physical addresses need to be converted. The NODE portion
    of the physical address needs to be shifted so that the low bit is in bit
    39 or bit 40, depending on an MMR value.

    It is not yet clear if this bug will be fixed in a silicon respin. If it
    is fixed, the hub revision will be incremented & the workaround disabled.

    Signed-off-by: Jack Steiner <steiner@sgi.com>
    Cc: Ingo Molnar <mingo@elte.hu>
    Cc: "H. Peter Anvin" <hpa@zytor.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    arch/x86/include/asm/uv/uv_bau.h | 1 +
    arch/x86/include/asm/uv/uv_hub.h | 37 ++++++++++++++++++++++++++++++++++---
    arch/x86/kernel/apic/x2apic_uv_x.c | 7 +++++--
    arch/x86/platform/uv/tlb_uv.c | 17 ++++++-----------
    4 files changed, 46 insertions(+), 16 deletions(-)

    --- a/arch/x86/include/asm/uv/uv_bau.h
    +++ b/arch/x86/include/asm/uv/uv_bau.h
    @@ -55,6 +55,7 @@
    #define UV_BAU_TUNABLES_DIR "sgi_uv"
    #define UV_BAU_TUNABLES_FILE "bau_tunables"
    #define WHITESPACE " \t\n"
    +#define uv_mmask ((1UL << uv_hub_info->m_val) - 1)
    #define uv_physnodeaddr(x) ((__pa((unsigned long)(x)) & uv_mmask))
    #define cpubit_isset(cpu, bau_local_cpumask) \
    test_bit((cpu), (bau_local_cpumask).bits)
    --- a/arch/x86/include/asm/uv/uv_hub.h
    +++ b/arch/x86/include/asm/uv/uv_hub.h
    @@ -46,6 +46,13 @@
    * PNODE - the low N bits of the GNODE. The PNODE is the most useful variant
    * of the nasid for socket usage.
    *
    + * GPA - (global physical address) a socket physical address converted
    + * so that it can be used by the GRU as a global address. Socket
    + * physical addresses 1) need additional NASID (node) bits added
    + * to the high end of the address, and 2) unaliased if the
    + * partition does not have a physical address 0. In addition, on
    + * UV2 rev 1, GPAs need the gnode left shifted to bits 39 or 40.
    + *
    *
    * NumaLink Global Physical Address Format:
    * +--------------------------------+---------------------+
    @@ -141,6 +148,8 @@ struct uv_hub_info_s {
    unsigned int gnode_extra;
    unsigned char hub_revision;
    unsigned char apic_pnode_shift;
    + unsigned char m_shift;
    + unsigned char n_lshift;
    unsigned long gnode_upper;
    unsigned long lowmem_remap_top;
    unsigned long lowmem_remap_base;
    @@ -177,6 +186,16 @@ static inline int is_uv2_hub(void)
    return uv_hub_info->hub_revision >= UV2_HUB_REVISION_BASE;
    }

    +static inline int is_uv2_1_hub(void)
    +{
    + return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE;
    +}
    +
    +static inline int is_uv2_2_hub(void)
    +{
    + return uv_hub_info->hub_revision == UV2_HUB_REVISION_BASE + 1;
    +}
    +
    union uvh_apicid {
    unsigned long v;
    struct uvh_apicid_s {
    @@ -276,7 +295,10 @@ static inline unsigned long uv_soc_phys_
    {
    if (paddr < uv_hub_info->lowmem_remap_top)
    paddr |= uv_hub_info->lowmem_remap_base;
    - return paddr | uv_hub_info->gnode_upper;
    + paddr |= uv_hub_info->gnode_upper;
    + paddr = ((paddr << uv_hub_info->m_shift) >> uv_hub_info->m_shift) |
    + ((paddr >> uv_hub_info->m_val) << uv_hub_info->n_lshift);
    + return paddr;
    }


    @@ -300,16 +322,19 @@ static inline unsigned long uv_gpa_to_so
    unsigned long remap_base = uv_hub_info->lowmem_remap_base;
    unsigned long remap_top = uv_hub_info->lowmem_remap_top;

    + gpa = ((gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift) |
    + ((gpa >> uv_hub_info->n_lshift) << uv_hub_info->m_val);
    + gpa = gpa & uv_hub_info->gpa_mask;
    if (paddr >= remap_base && paddr < remap_base + remap_top)
    paddr -= remap_base;
    return paddr;
    }


    -/* gnode -> pnode */
    +/* gpa -> pnode */
    static inline unsigned long uv_gpa_to_gnode(unsigned long gpa)
    {
    - return gpa >> uv_hub_info->m_val;
    + return gpa >> uv_hub_info->n_lshift;
    }

    /* gpa -> pnode */
    @@ -320,6 +345,12 @@ static inline int uv_gpa_to_pnode(unsign
    return uv_gpa_to_gnode(gpa) & n_mask;
    }

    +/* gpa -> node offset*/
    +static inline unsigned long uv_gpa_to_offset(unsigned long gpa)
    +{
    + return (gpa << uv_hub_info->m_shift) >> uv_hub_info->m_shift;
    +}
    +
    /* pnode, offset --> socket virtual */
    static inline void *uv_pnode_offset_to_vaddr(int pnode, unsigned long offset)
    {
    --- a/arch/x86/kernel/apic/x2apic_uv_x.c
    +++ b/arch/x86/kernel/apic/x2apic_uv_x.c
    @@ -832,6 +832,10 @@ void __init uv_system_init(void)
    uv_cpu_hub_info(cpu)->apic_pnode_shift = uvh_apicid.s.pnode_shift;
    uv_cpu_hub_info(cpu)->hub_revision = uv_hub_info->hub_revision;

    + uv_cpu_hub_info(cpu)->m_shift = 64 - m_val;
    + uv_cpu_hub_info(cpu)->n_lshift = is_uv2_1_hub() ?
    + (m_val == 40 ? 40 : 39) : m_val;
    +
    pnode = uv_apicid_to_pnode(apicid);
    blade = boot_pnode_to_blade(pnode);
    lcpu = uv_blade_info[blade].nr_possible_cpus;
    @@ -862,8 +866,7 @@ void __init uv_system_init(void)
    if (uv_node_to_blade[nid] >= 0)
    continue;
    paddr = node_start_pfn(nid) << PAGE_SHIFT;
    - paddr = uv_soc_phys_ram_to_gpa(paddr);
    - pnode = (paddr >> m_val) & pnode_mask;
    + pnode = uv_gpa_to_pnode(uv_soc_phys_ram_to_gpa(paddr));
    blade = boot_pnode_to_blade(pnode);
    uv_node_to_blade[nid] = blade;
    }
    --- a/arch/x86/platform/uv/tlb_uv.c
    +++ b/arch/x86/platform/uv/tlb_uv.c
    @@ -115,9 +115,6 @@ early_param("nobau", setup_nobau);

    /* base pnode in this partition */
    static int uv_base_pnode __read_mostly;
    -/* position of pnode (which is nasid>>1): */
    -static int uv_nshift __read_mostly;
    -static unsigned long uv_mmask __read_mostly;

    static DEFINE_PER_CPU(struct ptc_stats, ptcstats);
    static DEFINE_PER_CPU(struct bau_control, bau_control);
    @@ -1435,7 +1432,7 @@ static void activation_descriptor_init(i
    {
    int i;
    int cpu;
    - unsigned long pa;
    + unsigned long gpa;
    unsigned long m;
    unsigned long n;
    size_t dsize;
    @@ -1451,9 +1448,9 @@ static void activation_descriptor_init(i
    bau_desc = kmalloc_node(dsize, GFP_KERNEL, node);
    BUG_ON(!bau_desc);

    - pa = uv_gpa(bau_desc); /* need the real nasid*/
    - n = pa >> uv_nshift;
    - m = pa & uv_mmask;
    + gpa = uv_gpa(bau_desc);
    + n = uv_gpa_to_gnode(gpa);
    + m = uv_gpa_to_offset(gpa);

    /* the 14-bit pnode */
    write_mmr_descriptor_base(pnode, (n << UV_DESC_PSHIFT | m));
    @@ -1525,9 +1522,9 @@ static void pq_init(int node, int pnode)
    bcp->queue_last = pqp + (DEST_Q_SIZE - 1);
    }
    /*
    - * need the pnode of where the memory was really allocated
    + * need the gnode of where the memory was really allocated
    */
    - pn = uv_gpa(pqp) >> uv_nshift;
    + pn = uv_gpa_to_gnode(uv_gpa(pqp));
    first = uv_physnodeaddr(pqp);
    pn_first = ((unsigned long)pn << UV_PAYLOADQ_PNODE_SHIFT) | first;
    last = uv_physnodeaddr(pqp + (DEST_Q_SIZE - 1));
    @@ -1837,8 +1834,6 @@ static int __init uv_bau_init(void)
    zalloc_cpumask_var_node(mask, GFP_KERNEL, cpu_to_node(cur_cpu));
    }

    - uv_nshift = uv_hub_info->m_val;
    - uv_mmask = (1UL << uv_hub_info->m_val) - 1;
    nuvhubs = uv_num_possible_blades();
    spin_lock_init(&disable_lock);
    congested_cycles = usec_2_cycles(congested_respns_us);



    \
     
     \ /
      Last update: 2011-11-10 05:37    [W:4.192 / U:0.892 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site