summaryrefslogtreecommitdiffstats
path: root/arch/x86/include/asm/summit/apic.h
blob: 526d19e79447dc45090e8d0a156b3bae5eadcec6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#ifndef __ASM_SUMMIT_APIC_H
#define __ASM_SUMMIT_APIC_H

#include <asm/smp.h>
#include <linux/gfp.h>

/* In clustered mode, the high nibble of APIC ID is a cluster number.
 * The low nibble is a 4-bit bitmap. */
#define XAPIC_DEST_CPUS_SHIFT	4
#define XAPIC_DEST_CPUS_MASK	((1u << XAPIC_DEST_CPUS_SHIFT) - 1)
#define XAPIC_DEST_CLUSTER_MASK	(XAPIC_DEST_CPUS_MASK << XAPIC_DEST_CPUS_SHIFT)

#define APIC_DFR_VALUE	(APIC_DFR_CLUSTER)

static inline const cpumask_t *summit_target_cpus(void)
{
	/* CPU_MASK_ALL (0xff) has undefined behaviour with
	 * dest_LowestPrio mode logical clustered apic interrupt routing
	 * Just start on cpu 0.  IRQ balancing will spread load
	 */
	return &cpumask_of_cpu(0);
}

static inline unsigned long
summit_check_apicid_used(physid_mask_t bitmap, int apicid)
{
	return 0;
}

/* we don't use the phys_cpu_present_map to indicate apicid presence */
static inline unsigned long summit_check_apicid_present(int bit)
{
	return 1;
}

#define apicid_cluster(apicid) ((apicid) & XAPIC_DEST_CLUSTER_MASK)

extern u8 cpu_2_logical_apicid[];

static inline void summit_init_apic_ldr(void)
{
	unsigned long val, id;
	int count = 0;
	u8 my_id = (u8)hard_smp_processor_id();
	u8 my_cluster = (u8)apicid_cluster(my_id);
#ifdef CONFIG_SMP
	u8 lid;
	int i;

	/* Create logical APIC IDs by counting CPUs already in cluster. */
	for (count = 0, i = nr_cpu_ids; --i >= 0; ) {
		lid = cpu_2_logical_apicid[i];
		if (lid != BAD_APICID && apicid_cluster(lid) == my_cluster)
			++count;
	}
#endif
	/* We only have a 4 wide bitmap in cluster mode.  If a deranged
	 * BIOS puts 5 CPUs in one APIC cluster, we're hosed. */
	BUG_ON(count >= XAPIC_DEST_CPUS_SHIFT);
	id = my_cluster | (1UL << count);
	apic_write(APIC_DFR, APIC_DFR_VALUE);
	val = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
	val |= SET_APIC_LOGICAL_ID(id);
	apic_write(APIC_LDR, val);
}

static inline int summit_apic_id_registered(void)
{
	return 1;
}

static inline void summit_setup_apic_routing(void)
{
	printk("Enabling APIC mode:  Summit.  Using %d I/O APICs\n",
						nr_ioapics);
}

static inline int summit_apicid_to_node(int logical_apicid)
{
#ifdef CONFIG_SMP
	return apicid_2_node[hard_smp_processor_id()];
#else
	return 0;
#endif
}

/* Mapping from cpu number to logical apicid */
static inline int summit_cpu_to_logical_apicid(int cpu)
{
#ifdef CONFIG_SMP
	if (cpu >= nr_cpu_ids)
		return BAD_APICID;
	return (int)cpu_2_logical_apicid[cpu];
#else
	return logical_smp_processor_id();
#endif
}

static inline int summit_cpu_present_to_apicid(int mps_cpu)
{
	if (mps_cpu < nr_cpu_ids)
		return (int)per_cpu(x86_bios_cpu_apicid, mps_cpu);
	else
		return BAD_APICID;
}

static inline physid_mask_t
summit_ioapic_phys_id_map(physid_mask_t phys_id_map)
{
	/* For clustered we don't have a good way to do this yet - hack */
	return physids_promote(0x0F);
}

static inline physid_mask_t summit_apicid_to_cpu_present(int apicid)
{
	return physid_mask_of_physid(0);
}

static inline void summit_setup_portio_remap(void)
{
}

static inline int summit_check_phys_apicid_present(int boot_cpu_physical_apicid)
{
	return 1;
}

static inline unsigned int cpu_mask_to_apicid(const cpumask_t *cpumask)
{
	int num_bits_set;
	int cpus_found = 0;
	int cpu;
	int apicid;

	num_bits_set = cpus_weight(*cpumask);
	/* Return id to all */
	if (num_bits_set >= nr_cpu_ids)
		return (int) 0xFF;
	/*
	 * The cpus in the mask must all be on the apic cluster.  If are not
	 * on the same apicid cluster return default value of target_cpus():
	 */
	cpu = first_cpu(*cpumask);
	apicid = summit_cpu_to_logical_apicid(cpu);
	while (cpus_found < num_bits_set) {
		if (cpu_isset(cpu, *cpumask)) {
			int new_apicid = summit_cpu_to_logical_apicid(cpu);
			if (apicid_cluster(apicid) !=
					apicid_cluster(new_apicid)){
				printk ("%s: Not a valid mask!\n", __func__);
				return 0xFF;
			}
			apicid = apicid | new_apicid;
			cpus_found++;
		}
		cpu++;
	}
	return apicid;
}

static inline unsigned int cpu_mask_to_apicid_and(const struct cpumask *inmask,
						  const struct cpumask *andmask)
{
	int apicid = summit_cpu_to_logical_apicid(0);
	cpumask_var_t cpumask;

	if (!alloc_cpumask_var(&cpumask, GFP_ATOMIC))
		return apicid;

	cpumask_and(cpumask, inmask, andmask);
	cpumask_and(cpumask, cpumask, cpu_online_mask);
	apicid = cpu_mask_to_apicid(cpumask);

	free_cpumask_var(cpumask);
	return apicid;
}

/* cpuid returns the value latched in the HW at reset, not the APIC ID
 * register's value.  For any box whose BIOS changes APIC IDs, like
 * clustered APIC systems, we must use hard_smp_processor_id.
 *
 * See Intel's IA-32 SW Dev's Manual Vol2 under CPUID.
 */
static inline u32 phys_pkg_id(u32 cpuid_apic, int index_msb)
{
	return hard_smp_processor_id() >> index_msb;
}

#endif /* __ASM_SUMMIT_APIC_H */