1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * vSMPowered(tm) systems specific initialization |
4 | * Copyright (C) 2005 ScaleMP Inc. |
5 | * |
6 | * Ravikiran Thirumalai <kiran@scalemp.com>, |
7 | * Shai Fultheim <shai@scalemp.com> |
8 | * Paravirt ops integration: Glauber de Oliveira Costa <gcosta@redhat.com>, |
9 | * Ravikiran Thirumalai <kiran@scalemp.com> |
10 | */ |
11 | |
12 | #include <linux/init.h> |
13 | #include <linux/pci_ids.h> |
14 | #include <linux/pci_regs.h> |
15 | #include <linux/smp.h> |
16 | #include <linux/irq.h> |
17 | |
18 | #include <asm/apic.h> |
19 | #include <asm/pci-direct.h> |
20 | #include <asm/io.h> |
21 | #include <asm/paravirt.h> |
22 | #include <asm/setup.h> |
23 | |
24 | #define TOPOLOGY_REGISTER_OFFSET 0x10 |
25 | |
26 | #ifdef CONFIG_PCI |
27 | static void __init set_vsmp_ctl(void) |
28 | { |
29 | void __iomem *address; |
30 | unsigned int cap, ctl, cfg; |
31 | |
32 | /* set vSMP magic bits to indicate vSMP capable kernel */ |
33 | cfg = read_pci_config(bus: 0, slot: 0x1f, func: 0, PCI_BASE_ADDRESS_0); |
34 | address = early_ioremap(phys_addr: cfg, size: 8); |
35 | cap = readl(addr: address); |
36 | ctl = readl(addr: address + 4); |
37 | printk(KERN_INFO "vSMP CTL: capabilities:0x%08x control:0x%08x\n" , |
38 | cap, ctl); |
39 | |
40 | /* If possible, let the vSMP foundation route the interrupt optimally */ |
41 | #ifdef CONFIG_SMP |
42 | if (cap & ctl & BIT(8)) { |
43 | ctl &= ~BIT(8); |
44 | |
45 | #ifdef CONFIG_PROC_FS |
46 | /* Don't let users change irq affinity via procfs */ |
47 | no_irq_affinity = 1; |
48 | #endif |
49 | } |
50 | #endif |
51 | |
52 | writel(val: ctl, addr: address + 4); |
53 | ctl = readl(addr: address + 4); |
54 | pr_info("vSMP CTL: control set to:0x%08x\n" , ctl); |
55 | |
56 | early_iounmap(addr: address, size: 8); |
57 | } |
58 | static int is_vsmp = -1; |
59 | |
60 | static void __init detect_vsmp_box(void) |
61 | { |
62 | is_vsmp = 0; |
63 | |
64 | if (!early_pci_allowed()) |
65 | return; |
66 | |
67 | /* Check if we are running on a ScaleMP vSMPowered box */ |
68 | if (read_pci_config(bus: 0, slot: 0x1f, func: 0, PCI_VENDOR_ID) == |
69 | (PCI_VENDOR_ID_SCALEMP | (PCI_DEVICE_ID_SCALEMP_VSMP_CTL << 16))) |
70 | is_vsmp = 1; |
71 | } |
72 | |
73 | static int is_vsmp_box(void) |
74 | { |
75 | if (is_vsmp != -1) |
76 | return is_vsmp; |
77 | else { |
78 | WARN_ON_ONCE(1); |
79 | return 0; |
80 | } |
81 | } |
82 | |
83 | #else |
84 | static void __init detect_vsmp_box(void) |
85 | { |
86 | } |
87 | static int is_vsmp_box(void) |
88 | { |
89 | return 0; |
90 | } |
91 | static void __init set_vsmp_ctl(void) |
92 | { |
93 | } |
94 | #endif |
95 | |
96 | static void __init vsmp_cap_cpus(void) |
97 | { |
98 | #if !defined(CONFIG_X86_VSMP) && defined(CONFIG_SMP) && defined(CONFIG_PCI) |
99 | void __iomem *address; |
100 | unsigned int cfg, topology, node_shift, maxcpus; |
101 | |
102 | /* |
103 | * CONFIG_X86_VSMP is not configured, so limit the number CPUs to the |
104 | * ones present in the first board, unless explicitly overridden by |
105 | * setup_max_cpus |
106 | */ |
107 | if (setup_max_cpus != NR_CPUS) |
108 | return; |
109 | |
110 | /* Read the vSMP Foundation topology register */ |
111 | cfg = read_pci_config(0, 0x1f, 0, PCI_BASE_ADDRESS_0); |
112 | address = early_ioremap(cfg + TOPOLOGY_REGISTER_OFFSET, 4); |
113 | if (WARN_ON(!address)) |
114 | return; |
115 | |
116 | topology = readl(address); |
117 | node_shift = (topology >> 16) & 0x7; |
118 | if (!node_shift) |
119 | /* The value 0 should be decoded as 8 */ |
120 | node_shift = 8; |
121 | maxcpus = (topology & ((1 << node_shift) - 1)) + 1; |
122 | |
123 | pr_info("vSMP CTL: Capping CPUs to %d (CONFIG_X86_VSMP is unset)\n" , |
124 | maxcpus); |
125 | setup_max_cpus = maxcpus; |
126 | early_iounmap(address, 4); |
127 | #endif |
128 | } |
129 | |
130 | void __init vsmp_init(void) |
131 | { |
132 | detect_vsmp_box(); |
133 | if (!is_vsmp_box()) |
134 | return; |
135 | |
136 | vsmp_cap_cpus(); |
137 | |
138 | set_vsmp_ctl(); |
139 | return; |
140 | } |
141 | |