01ccf9bbd2
APIC IDs are used with random data types u16, u32, int, unsigned int, unsigned long. Make it all consistently use u32 because that reflects the hardware register width even if that callback going to be removed soonish. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Tested-by: Juergen Gross <jgross@suse.com> Tested-by: Sohil Mehta <sohil.mehta@intel.com> Tested-by: Michael Kelley <mikelley@microsoft.com> Tested-by: Peter Zijlstra (Intel) <peterz@infradead.org> Tested-by: Zhang Rui <rui.zhang@intel.com> Reviewed-by: Arjan van de Ven <arjan@linux.intel.com> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org> Link: https://lore.kernel.org/r/20230814085113.113097126@linutronix.de
154 lines
3.3 KiB
C
154 lines
3.3 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* vSMPowered(tm) systems specific initialization
|
|
* Copyright (C) 2005 ScaleMP Inc.
|
|
*
|
|
* Ravikiran Thirumalai <kiran@scalemp.com>,
|
|
* Shai Fultheim <shai@scalemp.com>
|
|
* Paravirt ops integration: Glauber de Oliveira Costa <gcosta@redhat.com>,
|
|
* Ravikiran Thirumalai <kiran@scalemp.com>
|
|
*/
|
|
|
|
#include <linux/init.h>
|
|
#include <linux/pci_ids.h>
|
|
#include <linux/pci_regs.h>
|
|
#include <linux/smp.h>
|
|
#include <linux/irq.h>
|
|
|
|
#include <asm/apic.h>
|
|
#include <asm/pci-direct.h>
|
|
#include <asm/io.h>
|
|
#include <asm/paravirt.h>
|
|
#include <asm/setup.h>
|
|
|
|
#define TOPOLOGY_REGISTER_OFFSET 0x10
|
|
|
|
#ifdef CONFIG_PCI
|
|
static void __init set_vsmp_ctl(void)
|
|
{
|
|
void __iomem *address;
|
|
unsigned int cap, ctl, cfg;
|
|
|
|
/* set vSMP magic bits to indicate vSMP capable kernel */
|
|
cfg = read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0);
|
|
address = early_ioremap(cfg, 8);
|
|
cap = readl(address);
|
|
ctl = readl(address + 4);
|
|
printk(KERN_INFO "vSMP CTL: capabilities:0x%08x control:0x%08x\n",
|
|
cap, ctl);
|
|
|
|
/* If possible, let the vSMP foundation route the interrupt optimally */
|
|
#ifdef CONFIG_SMP
|
|
if (cap & ctl & BIT(8)) {
|
|
ctl &= ~BIT(8);
|
|
|
|
#ifdef CONFIG_PROC_FS
|
|
/* Don't let users change irq affinity via procfs */
|
|
no_irq_affinity = 1;
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
writel(ctl, address + 4);
|
|
ctl = readl(address + 4);
|
|
pr_info("vSMP CTL: control set to:0x%08x\n", ctl);
|
|
|
|
early_iounmap(address, 8);
|
|
}
|
|
static int is_vsmp = -1;
|
|
|
|
static void __init detect_vsmp_box(void)
|
|
{
|
|
is_vsmp = 0;
|
|
|
|
if (!early_pci_allowed())
|
|
return;
|
|
|
|
/* Check if we are running on a ScaleMP vSMPowered box */
|
|
if (read_pci_config(0, 0x1f, 0, PCI_VENDOR_ID) ==
|
|
(PCI_VENDOR_ID_SCALEMP | (PCI_DEVICE_ID_SCALEMP_VSMP_CTL << 16)))
|
|
is_vsmp = 1;
|
|
}
|
|
|
|
static int is_vsmp_box(void)
|
|
{
|
|
if (is_vsmp != -1)
|
|
return is_vsmp;
|
|
else {
|
|
WARN_ON_ONCE(1);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#else
|
|
static void __init detect_vsmp_box(void)
|
|
{
|
|
}
|
|
static int is_vsmp_box(void)
|
|
{
|
|
return 0;
|
|
}
|
|
static void __init set_vsmp_ctl(void)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
static void __init vsmp_cap_cpus(void)
|
|
{
|
|
#if !defined(CONFIG_X86_VSMP) && defined(CONFIG_SMP) && defined(CONFIG_PCI)
|
|
void __iomem *address;
|
|
unsigned int cfg, topology, node_shift, maxcpus;
|
|
|
|
/*
|
|
* CONFIG_X86_VSMP is not configured, so limit the number CPUs to the
|
|
* ones present in the first board, unless explicitly overridden by
|
|
* setup_max_cpus
|
|
*/
|
|
if (setup_max_cpus != NR_CPUS)
|
|
return;
|
|
|
|
/* Read the vSMP Foundation topology register */
|
|
cfg = read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0);
|
|
address = early_ioremap(cfg + TOPOLOGY_REGISTER_OFFSET, 4);
|
|
if (WARN_ON(!address))
|
|
return;
|
|
|
|
topology = readl(address);
|
|
node_shift = (topology >> 16) & 0x7;
|
|
if (!node_shift)
|
|
/* The value 0 should be decoded as 8 */
|
|
node_shift = 8;
|
|
maxcpus = (topology & ((1 << node_shift) - 1)) + 1;
|
|
|
|
pr_info("vSMP CTL: Capping CPUs to %d (CONFIG_X86_VSMP is unset)\n",
|
|
maxcpus);
|
|
setup_max_cpus = maxcpus;
|
|
early_iounmap(address, 4);
|
|
#endif
|
|
}
|
|
|
|
static u32 apicid_phys_pkg_id(u32 initial_apic_id, int index_msb)
|
|
{
|
|
return read_apic_id() >> index_msb;
|
|
}
|
|
|
|
static void vsmp_apic_post_init(void)
|
|
{
|
|
/* need to update phys_pkg_id */
|
|
apic->phys_pkg_id = apicid_phys_pkg_id;
|
|
}
|
|
|
|
void __init vsmp_init(void)
|
|
{
|
|
detect_vsmp_box();
|
|
if (!is_vsmp_box())
|
|
return;
|
|
|
|
x86_platform.apic_post_init = vsmp_apic_post_init;
|
|
|
|
vsmp_cap_cpus();
|
|
|
|
set_vsmp_ctl();
|
|
return;
|
|
}
|