Merge branch 'x86-uv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Feb 2010 19:00:55 +0000 (11:00 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sun, 28 Feb 2010 19:00:55 +0000 (11:00 -0800)
* 'x86-uv-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86, uv: Remove recursion in uv_heartbeat_enable()
  x86, uv: uv_global_gru_mmr_address() macro fix
  x86, uv: Add serial number parameter to uv_bios_get_sn_info()

1  2 
arch/x86/include/asm/uv/bios.h
arch/x86/include/asm/uv/uv_hub.h
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/bios_uv.c

@@@ -18,8 -18,8 +18,8 @@@
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
-  *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
-  *  Copyright (c) Russ Anderson
+  *  Copyright (c) 2008-2009 Silicon Graphics, Inc.  All Rights Reserved.
+  *  Copyright (c) Russ Anderson <rja@sgi.com>
   */
  
  #include <linux/rtc.h>
@@@ -36,8 -36,7 +36,8 @@@ enum uv_bios_cmd 
        UV_BIOS_WATCHLIST_ALLOC,
        UV_BIOS_WATCHLIST_FREE,
        UV_BIOS_MEMPROTECT,
 -      UV_BIOS_GET_PARTITION_ADDR
 +      UV_BIOS_GET_PARTITION_ADDR,
 +      UV_BIOS_SET_LEGACY_VGA_TARGET
  };
  
  /*
@@@ -90,14 -89,13 +90,14 @@@ extern s64 uv_bios_call(enum uv_bios_cm
  extern s64 uv_bios_call_irqsave(enum uv_bios_cmd, u64, u64, u64, u64, u64);
  extern s64 uv_bios_call_reentrant(enum uv_bios_cmd, u64, u64, u64, u64, u64);
  
- extern s64 uv_bios_get_sn_info(int, int *, long *, long *, long *);
+ extern s64 uv_bios_get_sn_info(int, int *, long *, long *, long *, long *);
  extern s64 uv_bios_freq_base(u64, u64 *);
  extern int uv_bios_mq_watchlist_alloc(unsigned long, unsigned int,
                                        unsigned long *);
  extern int uv_bios_mq_watchlist_free(int, int);
  extern s64 uv_bios_change_memprotect(u64, u64, enum uv_memprotect);
  extern s64 uv_bios_reserved_page_pa(u64, u64 *, u64 *, u64 *);
 +extern int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus);
  
  extern void uv_bios_init(void);
  
@@@ -106,6 -104,7 +106,7 @@@ extern int uv_type
  extern long sn_partition_id;
  extern long sn_coherency_id;
  extern long sn_region_size;
+ extern long system_serial_number;
  #define partition_coherence_id()      (sn_coherency_id)
  
  extern struct kobject *sgi_uv_kobj;   /* /sys/firmware/sgi_uv */
   *              contiguous (although various IO spaces may punch holes in
   *              it)..
   *
 - *    N       - Number of bits in the node portion of a socket physical
 - *              address.
 + *    N       - Number of bits in the node portion of a socket physical
 + *              address.
   *
 - *    NASID   - network ID of a router, Mbrick or Cbrick. Nasid values of
 - *              routers always have low bit of 1, C/MBricks have low bit
 - *              equal to 0. Most addressing macros that target UV hub chips
 - *              right shift the NASID by 1 to exclude the always-zero bit.
 - *              NASIDs contain up to 15 bits.
 + *    NASID   - network ID of a router, Mbrick or Cbrick. Nasid values of
 + *              routers always have low bit of 1, C/MBricks have low bit
 + *              equal to 0. Most addressing macros that target UV hub chips
 + *              right shift the NASID by 1 to exclude the always-zero bit.
 + *              NASIDs contain up to 15 bits.
   *
   *    GNODE   - NASID right shifted by 1 bit. Most mmrs contain gnodes instead
   *              of nasids.
   *
 - *    PNODE   - the low N bits of the GNODE. The PNODE is the most useful variant
 - *              of the nasid for socket usage.
 + *    PNODE   - the low N bits of the GNODE. The PNODE is the most useful variant
 + *              of the nasid for socket usage.
   *
   *
   *  NumaLink Global Physical Address Format:
   *
   *
   * APICID format
 - *    NOTE!!!!!! This is the current format of the APICID. However, code
 - *    should assume that this will change in the future. Use functions
 - *    in this file for all APICID bit manipulations and conversion.
 + *    NOTE!!!!!! This is the current format of the APICID. However, code
 + *    should assume that this will change in the future. Use functions
 + *    in this file for all APICID bit manipulations and conversion.
   *
 - *            1111110000000000
 - *            5432109876543210
 + *            1111110000000000
 + *            5432109876543210
   *            pppppppppplc0cch
   *            sssssssssss
   *
@@@ -89,9 -89,9 +89,9 @@@
   *    Note: Processor only supports 12 bits in the APICID register. The ACPI
   *          tables hold all 16 bits. Software needs to be aware of this.
   *
 - *          Unless otherwise specified, all references to APICID refer to
 - *          the FULL value contained in ACPI tables, not the subset in the
 - *          processor APICID register.
 + *          Unless otherwise specified, all references to APICID refer to
 + *          the FULL value contained in ACPI tables, not the subset in the
 + *          processor APICID register.
   */
  
  
@@@ -151,16 -151,16 +151,16 @@@ struct uv_hub_info_s 
  };
  
  DECLARE_PER_CPU(struct uv_hub_info_s, __uv_hub_info);
 -#define uv_hub_info           (&__get_cpu_var(__uv_hub_info))
 +#define uv_hub_info           (&__get_cpu_var(__uv_hub_info))
  #define uv_cpu_hub_info(cpu)  (&per_cpu(__uv_hub_info, cpu))
  
  /*
   * Local & Global MMR space macros.
 - *    Note: macros are intended to be used ONLY by inline functions
 - *    in this file - not by other kernel code.
 - *            n -  NASID (full 15-bit global nasid)
 - *            g -  GNODE (full 15-bit global nasid, right shifted 1)
 - *            p -  PNODE (local part of nsids, right shifted 1)
 + *    Note: macros are intended to be used ONLY by inline functions
 + *    in this file - not by other kernel code.
 + *            n -  NASID (full 15-bit global nasid)
 + *            g -  GNODE (full 15-bit global nasid, right shifted 1)
 + *            p -  PNODE (local part of nsids, right shifted 1)
   */
  #define UV_NASID_TO_PNODE(n)          (((n) >> 1) & uv_hub_info->pnode_mask)
  #define UV_PNODE_TO_GNODE(p)          ((p) |uv_hub_info->gnode_extra)
  /*
   * Macros for converting between kernel virtual addresses, socket local physical
   * addresses, and UV global physical addresses.
 - *    Note: use the standard __pa() & __va() macros for converting
 - *          between socket virtual and socket physical addresses.
 + *    Note: use the standard __pa() & __va() macros for converting
 + *          between socket virtual and socket physical addresses.
   */
  
  /* socket phys RAM --> UV global physical address */
@@@ -287,18 -287,21 +287,18 @@@ static inline int uv_apicid_to_pnode(in
   * Access global MMRs using the low memory MMR32 space. This region supports
   * faster MMR access but not all MMRs are accessible in this space.
   */
 -static inline unsigned long *uv_global_mmr32_address(int pnode,
 -                              unsigned long offset)
 +static inline unsigned long *uv_global_mmr32_address(int pnode, unsigned long offset)
  {
        return __va(UV_GLOBAL_MMR32_BASE |
                       UV_GLOBAL_MMR32_PNODE_BITS(pnode) | offset);
  }
  
 -static inline void uv_write_global_mmr32(int pnode, unsigned long offset,
 -                               unsigned long val)
 +static inline void uv_write_global_mmr32(int pnode, unsigned long offset, unsigned long val)
  {
        writeq(val, uv_global_mmr32_address(pnode, offset));
  }
  
 -static inline unsigned long uv_read_global_mmr32(int pnode,
 -                                               unsigned long offset)
 +static inline unsigned long uv_read_global_mmr32(int pnode, unsigned long offset)
  {
        return readq(uv_global_mmr32_address(pnode, offset));
  }
   * Access Global MMR space using the MMR space located at the top of physical
   * memory.
   */
 -static inline unsigned long *uv_global_mmr64_address(int pnode,
 -                              unsigned long offset)
 +static inline unsigned long *uv_global_mmr64_address(int pnode, unsigned long offset)
  {
        return __va(UV_GLOBAL_MMR64_BASE |
                    UV_GLOBAL_MMR64_PNODE_BITS(pnode) | offset);
  }
  
 -static inline void uv_write_global_mmr64(int pnode, unsigned long offset,
 -                              unsigned long val)
 +static inline void uv_write_global_mmr64(int pnode, unsigned long offset, unsigned long val)
  {
        writeq(val, uv_global_mmr64_address(pnode, offset));
  }
  
 -static inline unsigned long uv_read_global_mmr64(int pnode,
 -                                               unsigned long offset)
 +static inline unsigned long uv_read_global_mmr64(int pnode, unsigned long offset)
  {
        return readq(uv_global_mmr64_address(pnode, offset));
  }
   */
  static inline unsigned long uv_global_gru_mmr_address(int pnode, unsigned long offset)
  {
-       return UV_GLOBAL_GRU_MMR_BASE | offset | (pnode << uv_hub_info->m_val);
+       return UV_GLOBAL_GRU_MMR_BASE | offset |
+               ((unsigned long)pnode << uv_hub_info->m_val);
  }
  
 +static inline void uv_write_global_mmr8(int pnode, unsigned long offset, unsigned char val)
 +{
 +      writeb(val, uv_global_mmr64_address(pnode, offset));
 +}
 +
 +static inline unsigned char uv_read_global_mmr8(int pnode, unsigned long offset)
 +{
 +      return readb(uv_global_mmr64_address(pnode, offset));
 +}
 +
  /*
   * Access hub local MMRs. Faster than using global space but only local MMRs
   * are accessible.
@@@ -461,17 -458,11 +462,17 @@@ static inline void uv_set_scir_bits(uns
        }
  }
  
 +static inline unsigned long uv_scir_offset(int apicid)
 +{
 +      return SCIR_LOCAL_MMR_BASE | (apicid & 0x3f);
 +}
 +
  static inline void uv_set_cpu_scir_bits(int cpu, unsigned char value)
  {
        if (uv_cpu_hub_info(cpu)->scir.state != value) {
 +              uv_write_global_mmr8(uv_cpu_to_pnode(cpu),
 +                              uv_cpu_hub_info(cpu)->scir.offset, value);
                uv_cpu_hub_info(cpu)->scir.state = value;
 -              uv_write_local_mmr8(uv_cpu_hub_info(cpu)->scir.offset, value);
        }
  }
  
@@@ -495,17 -486,5 +496,17 @@@ static inline void uv_hub_send_ipi(int 
        uv_write_global_mmr64(pnode, UVH_IPI_INT, val);
  }
  
 +/*
 + * Get the minimum revision number of the hub chips within the partition.
 + *     1 - initial rev 1.0 silicon
 + *     2 - rev 2.0 production silicon
 + */
 +static inline int uv_get_min_hub_revision_id(void)
 +{
 +      extern int uv_min_hub_revision_id;
 +
 +      return uv_min_hub_revision_id;
 +}
 +
  #endif /* CONFIG_X86_64 */
  #endif /* _ASM_X86_UV_UV_HUB_H */
@@@ -5,7 -5,7 +5,7 @@@
   *
   * SGI UV APIC functions (note: not an Intel compatible APIC)
   *
-  * Copyright (C) 2007-2008 Silicon Graphics, Inc. All rights reserved.
+  * Copyright (C) 2007-2009 Silicon Graphics, Inc. All rights reserved.
   */
  #include <linux/cpumask.h>
  #include <linux/hardirq.h>
@@@ -20,8 -20,6 +20,8 @@@
  #include <linux/cpu.h>
  #include <linux/init.h>
  #include <linux/io.h>
 +#include <linux/pci.h>
 +#include <linux/kdebug.h>
  
  #include <asm/uv/uv_mmrs.h>
  #include <asm/uv/uv_hub.h>
  
  DEFINE_PER_CPU(int, x2apic_extra_bits);
  
 +#define PR_DEVEL(fmt, args...)        pr_devel("%s: " fmt, __func__, args)
 +
  static enum uv_system_type uv_system_type;
  static u64 gru_start_paddr, gru_end_paddr;
 +int uv_min_hub_revision_id;
 +EXPORT_SYMBOL_GPL(uv_min_hub_revision_id);
 +static DEFINE_SPINLOCK(uv_nmi_lock);
  
  static inline bool is_GRU_range(u64 start, u64 end)
  {
@@@ -62,28 -55,20 +62,28 @@@ static int early_get_nodeid(void
        mmr = early_ioremap(UV_LOCAL_MMR_BASE | UVH_NODE_ID, sizeof(*mmr));
        node_id.v = *mmr;
        early_iounmap(mmr, sizeof(*mmr));
 +
 +      /* Currently, all blades have same revision number */
 +      uv_min_hub_revision_id = node_id.s.revision;
 +
        return node_id.s.node_id;
  }
  
  static int __init uv_acpi_madt_oem_check(char *oem_id, char *oem_table_id)
  {
 +      int nodeid;
 +
        if (!strcmp(oem_id, "SGI")) {
 +              nodeid = early_get_nodeid();
                x86_platform.is_untracked_pat_range =  uv_is_untracked_pat_range;
 +              x86_platform.nmi_init = uv_nmi_init;
                if (!strcmp(oem_table_id, "UVL"))
                        uv_system_type = UV_LEGACY_APIC;
                else if (!strcmp(oem_table_id, "UVX"))
                        uv_system_type = UV_X2APIC;
                else if (!strcmp(oem_table_id, "UVH")) {
                        __get_cpu_var(x2apic_extra_bits) =
 -                              early_get_nodeid() << (UV_APIC_PNODE_SHIFT - 1);
 +                              nodeid << (UV_APIC_PNODE_SHIFT - 1);
                        uv_system_type = UV_NON_UNIQUE_APIC;
                        return 1;
                }
@@@ -240,7 -225,10 +240,7 @@@ uv_cpu_mask_to_apicid_and(const struct 
                if (cpumask_test_cpu(cpu, cpu_online_mask))
                        break;
        }
 -      if (cpu < nr_cpu_ids)
 -              return per_cpu(x86_cpu_to_apicid, cpu);
 -
 -      return BAD_APICID;
 +      return per_cpu(x86_cpu_to_apicid, cpu);
  }
  
  static unsigned int x2apic_get_apic_id(unsigned long x)
@@@ -389,13 -377,13 +389,13 @@@ static __init void get_lowmem_redirect(
  
  enum map_type {map_wb, map_uc};
  
 -static __init void map_high(char *id, unsigned long base, int shift,
 -                          int max_pnode, enum map_type map_type)
 +static __init void map_high(char *id, unsigned long base, int pshift,
 +                      int bshift, int max_pnode, enum map_type map_type)
  {
        unsigned long bytes, paddr;
  
 -      paddr = base << shift;
 -      bytes = (1UL << shift) * (max_pnode + 1);
 +      paddr = base << pshift;
 +      bytes = (1UL << bshift) * (max_pnode + 1);
        printk(KERN_INFO "UV: Map %s_HI 0x%lx - 0x%lx\n", id, paddr,
                                                paddr + bytes);
        if (map_type == map_uc)
@@@ -411,7 -399,7 +411,7 @@@ static __init void map_gru_high(int max
  
        gru.v = uv_read_local_mmr(UVH_RH_GAM_GRU_OVERLAY_CONFIG_MMR);
        if (gru.s.enable) {
 -              map_high("GRU", gru.s.base, shift, max_pnode, map_wb);
 +              map_high("GRU", gru.s.base, shift, shift, max_pnode, map_wb);
                gru_start_paddr = ((u64)gru.s.base << shift);
                gru_end_paddr = gru_start_paddr + (1UL << shift) * (max_pnode + 1);
  
@@@ -425,7 -413,7 +425,7 @@@ static __init void map_mmr_high(int max
  
        mmr.v = uv_read_local_mmr(UVH_RH_GAM_MMR_OVERLAY_CONFIG_MMR);
        if (mmr.s.enable)
 -              map_high("MMR", mmr.s.base, shift, max_pnode, map_uc);
 +              map_high("MMR", mmr.s.base, shift, shift, max_pnode, map_uc);
  }
  
  static __init void map_mmioh_high(int max_pnode)
  
        mmioh.v = uv_read_local_mmr(UVH_RH_GAM_MMIOH_OVERLAY_CONFIG_MMR);
        if (mmioh.s.enable)
 -              map_high("MMIOH", mmioh.s.base, shift, max_pnode, map_uc);
 +              map_high("MMIOH", mmioh.s.base, shift, mmioh.s.m_io,
 +                      max_pnode, map_uc);
  }
  
  static __init void map_low_mmrs(void)
@@@ -488,7 -475,7 +488,7 @@@ static void uv_heartbeat(unsigned long 
  
  static void __cpuinit uv_heartbeat_enable(int cpu)
  {
-       if (!uv_cpu_hub_info(cpu)->scir.enabled) {
+       while (!uv_cpu_hub_info(cpu)->scir.enabled) {
                struct timer_list *timer = &uv_cpu_hub_info(cpu)->scir.timer;
  
                uv_set_cpu_scir_bits(cpu, SCIR_CPU_HEARTBEAT|SCIR_CPU_ACTIVITY);
                timer->expires = jiffies + SCIR_CPU_HB_INTERVAL;
                add_timer_on(timer, cpu);
                uv_cpu_hub_info(cpu)->scir.enabled = 1;
-       }
  
-       /* check boot cpu */
-       if (!uv_cpu_hub_info(0)->scir.enabled)
-               uv_heartbeat_enable(0);
+               /* also ensure that boot cpu is enabled */
+               cpu = 0;
+       }
  }
  
  #ifdef CONFIG_HOTPLUG_CPU
@@@ -559,30 -545,6 +558,30 @@@ late_initcall(uv_init_heartbeat)
  
  #endif /* !CONFIG_HOTPLUG_CPU */
  
 +/* Direct Legacy VGA I/O traffic to designated IOH */
 +int uv_set_vga_state(struct pci_dev *pdev, bool decode,
 +                    unsigned int command_bits, bool change_bridge)
 +{
 +      int domain, bus, rc;
 +
 +      PR_DEVEL("devfn %x decode %d cmd %x chg_brdg %d\n",
 +                      pdev->devfn, decode, command_bits, change_bridge);
 +
 +      if (!change_bridge)
 +              return 0;
 +
 +      if ((command_bits & PCI_COMMAND_IO) == 0)
 +              return 0;
 +
 +      domain = pci_domain_nr(pdev->bus);
 +      bus = pdev->bus->number;
 +
 +      rc = uv_bios_set_legacy_vga_target(decode, domain, bus);
 +      PR_DEVEL("vga decode %d %x:%x, rc: %d\n", decode, domain, bus, rc);
 +
 +      return rc;
 +}
 +
  /*
   * Called on each cpu to initialize the per_cpu UV data area.
   * FIXME: hotplug not supported yet
@@@ -599,46 -561,6 +598,46 @@@ void __cpuinit uv_cpu_init(void
                set_x2apic_extra_bits(uv_hub_info->pnode);
  }
  
 +/*
 + * When NMI is received, print a stack trace.
 + */
 +int uv_handle_nmi(struct notifier_block *self, unsigned long reason, void *data)
 +{
 +      if (reason != DIE_NMI_IPI)
 +              return NOTIFY_OK;
 +      /*
 +       * Use a lock so only one cpu prints at a time
 +       * to prevent intermixed output.
 +       */
 +      spin_lock(&uv_nmi_lock);
 +      pr_info("NMI stack dump cpu %u:\n", smp_processor_id());
 +      dump_stack();
 +      spin_unlock(&uv_nmi_lock);
 +
 +      return NOTIFY_STOP;
 +}
 +
 +static struct notifier_block uv_dump_stack_nmi_nb = {
 +      .notifier_call  = uv_handle_nmi
 +};
 +
 +void uv_register_nmi_notifier(void)
 +{
 +      if (register_die_notifier(&uv_dump_stack_nmi_nb))
 +              printk(KERN_WARNING "UV NMI handler failed to register\n");
 +}
 +
 +void uv_nmi_init(void)
 +{
 +      unsigned int value;
 +
 +      /*
 +       * Unmask NMI on all cpus
 +       */
 +      value = apic_read(APIC_LVT1) | APIC_DM_NMI;
 +      value &= ~APIC_LVT_MASKED;
 +      apic_write(APIC_LVT1, value);
 +}
  
  void __init uv_system_init(void)
  {
        }
  
        uv_bios_init();
-       uv_bios_get_sn_info(0, &uv_type, &sn_partition_id,
-                           &sn_coherency_id, &sn_region_size);
+       uv_bios_get_sn_info(0, &uv_type, &sn_partition_id, &sn_coherency_id,
+                           &sn_region_size, &system_serial_number);
        uv_rtc_init();
  
        for_each_present_cpu(cpu) {
 +              int apicid = per_cpu(x86_cpu_to_apicid, cpu);
 +
                nid = cpu_to_node(cpu);
 -              pnode = uv_apicid_to_pnode(per_cpu(x86_cpu_to_apicid, cpu));
 +              pnode = uv_apicid_to_pnode(apicid);
                blade = boot_pnode_to_blade(pnode);
                lcpu = uv_blade_info[blade].nr_possible_cpus;
                uv_blade_info[blade].nr_possible_cpus++;
                uv_cpu_hub_info(cpu)->gnode_extra = gnode_extra;
                uv_cpu_hub_info(cpu)->global_mmr_base = mmr_base;
                uv_cpu_hub_info(cpu)->coherency_domain_number = sn_coherency_id;
 -              uv_cpu_hub_info(cpu)->scir.offset = SCIR_LOCAL_MMR_BASE + lcpu;
 +              uv_cpu_hub_info(cpu)->scir.offset = uv_scir_offset(apicid);
                uv_node_to_blade[nid] = blade;
                uv_cpu_to_blade[cpu] = blade;
                max_pnode = max(pnode, max_pnode);
  
 -              printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, "
 -                      "lcpu %d, blade %d\n",
 -                      cpu, per_cpu(x86_cpu_to_apicid, cpu), pnode, nid,
 -                      lcpu, blade);
 +              printk(KERN_DEBUG "UV: cpu %d, apicid 0x%x, pnode %d, nid %d, lcpu %d, blade %d\n",
 +                      cpu, apicid, pnode, nid, lcpu, blade);
        }
  
        /* Add blade/pnode info for nodes without cpus */
  
        uv_cpu_init();
        uv_scir_register_cpu_notifier();
 +      uv_register_nmi_notifier();
        proc_mkdir("sgi_uv", NULL);
 +
 +      /* register Legacy VGA I/O redirection handler */
 +      pci_register_set_vga_state(uv_set_vga_state);
  }
@@@ -15,8 -15,8 +15,8 @@@
   *  along with this program; if not, write to the Free Software
   *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
   *
-  *  Copyright (c) 2008 Silicon Graphics, Inc.  All Rights Reserved.
-  *  Copyright (c) Russ Anderson
+  *  Copyright (c) 2008-2009 Silicon Graphics, Inc.  All Rights Reserved.
+  *  Copyright (c) Russ Anderson <rja@sgi.com>
   */
  
  #include <linux/efi.h>
@@@ -30,6 -30,7 +30,7 @@@ static struct uv_systab uv_systab
  s64 uv_bios_call(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3, u64 a4, u64 a5)
  {
        struct uv_systab *tab = &uv_systab;
+       s64 ret;
  
        if (!tab->function)
                /*
                 */
                return BIOS_STATUS_UNIMPLEMENTED;
  
-       return efi_call6((void *)__va(tab->function),
-                                       (u64)which, a1, a2, a3, a4, a5);
+       ret = efi_call6((void *)__va(tab->function), (u64)which,
+                       a1, a2, a3, a4, a5);
+       return ret;
  }
+ EXPORT_SYMBOL_GPL(uv_bios_call);
  
  s64 uv_bios_call_irqsave(enum uv_bios_cmd which, u64 a1, u64 a2, u64 a3,
                                        u64 a4, u64 a5)
@@@ -73,11 -76,14 +76,14 @@@ long sn_coherency_id
  EXPORT_SYMBOL_GPL(sn_coherency_id);
  long sn_region_size;
  EXPORT_SYMBOL_GPL(sn_region_size);
+ long system_serial_number;
+ EXPORT_SYMBOL_GPL(system_serial_number);
  int uv_type;
+ EXPORT_SYMBOL_GPL(uv_type);
  
  
  s64 uv_bios_get_sn_info(int fc, int *uvtype, long *partid, long *coher,
-               long *region)
+               long *region, long *ssn)
  {
        s64 ret;
        u64 v0, v1;
                *coher = part.coherence_id;
        if (region)
                *region = part.region_size;
+       if (ssn)
+               *ssn = v1;
        return ret;
  }
+ EXPORT_SYMBOL_GPL(uv_bios_get_sn_info);
  
  int
  uv_bios_mq_watchlist_alloc(unsigned long addr, unsigned int mq_size,
@@@ -154,25 -163,6 +163,25 @@@ s64 uv_bios_freq_base(u64 clock_type, u
  }
  EXPORT_SYMBOL_GPL(uv_bios_freq_base);
  
 +/*
 + * uv_bios_set_legacy_vga_target - Set Legacy VGA I/O Target
 + * @decode: true to enable target, false to disable target
 + * @domain: PCI domain number
 + * @bus: PCI bus number
 + *
 + * Returns:
 + *    0: Success
 + *    -EINVAL: Invalid domain or bus number
 + *    -ENOSYS: Capability not available
 + *    -EBUSY: Legacy VGA I/O cannot be retargeted at this time
 + */
 +int uv_bios_set_legacy_vga_target(bool decode, int domain, int bus)
 +{
 +      return uv_bios_call(UV_BIOS_SET_LEGACY_VGA_TARGET,
 +                              (u64)decode, (u64)domain, (u64)bus, 0, 0);
 +}
 +EXPORT_SYMBOL_GPL(uv_bios_set_legacy_vga_target);
 +
  
  #ifdef CONFIG_EFI
  void uv_bios_init(void)
  
  void uv_bios_init(void) { }
  #endif