1  // SPDX-License-Identifier: GPL-2.0-only
2  /*
3   * Copyright (C) 2005 Intel Corporation
4   * Copyright (C) 2009 Hewlett-Packard Development Company, L.P.
5   *
6   *	Alex Chiang <achiang@hp.com>
7   *	- Unified x86/ia64 implementations
8   *
9   * I/O APIC hotplug support
10   *	Yinghai Lu <yinghai@kernel.org>
11   *	Jiang Liu <jiang.liu@intel.com>
12   */
13  #include <linux/export.h>
14  #include <linux/acpi.h>
15  #include <acpi/processor.h>
16  
get_madt_table(void)17  static struct acpi_table_madt *get_madt_table(void)
18  {
19  	static struct acpi_table_madt *madt;
20  	static int read_madt;
21  
22  	if (!read_madt) {
23  		if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
24  					(struct acpi_table_header **)&madt)))
25  			madt = NULL;
26  		read_madt++;
27  	}
28  
29  	return madt;
30  }
31  
map_lapic_id(struct acpi_subtable_header * entry,u32 acpi_id,phys_cpuid_t * apic_id)32  static int map_lapic_id(struct acpi_subtable_header *entry,
33  		 u32 acpi_id, phys_cpuid_t *apic_id)
34  {
35  	struct acpi_madt_local_apic *lapic =
36  		container_of(entry, struct acpi_madt_local_apic, header);
37  
38  	if (!(lapic->lapic_flags & ACPI_MADT_ENABLED))
39  		return -ENODEV;
40  
41  	if (lapic->processor_id != acpi_id)
42  		return -EINVAL;
43  
44  	*apic_id = lapic->id;
45  	return 0;
46  }
47  
map_x2apic_id(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * apic_id)48  static int map_x2apic_id(struct acpi_subtable_header *entry,
49  		int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
50  {
51  	struct acpi_madt_local_x2apic *apic =
52  		container_of(entry, struct acpi_madt_local_x2apic, header);
53  
54  	if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
55  		return -ENODEV;
56  
57  	if (device_declaration && (apic->uid == acpi_id)) {
58  		*apic_id = apic->local_apic_id;
59  		return 0;
60  	}
61  
62  	return -EINVAL;
63  }
64  
map_lsapic_id(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * apic_id)65  static int map_lsapic_id(struct acpi_subtable_header *entry,
66  		int device_declaration, u32 acpi_id, phys_cpuid_t *apic_id)
67  {
68  	struct acpi_madt_local_sapic *lsapic =
69  		container_of(entry, struct acpi_madt_local_sapic, header);
70  
71  	if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
72  		return -ENODEV;
73  
74  	if (device_declaration) {
75  		if ((entry->length < 16) || (lsapic->uid != acpi_id))
76  			return -EINVAL;
77  	} else if (lsapic->processor_id != acpi_id)
78  		return -EINVAL;
79  
80  	*apic_id = (lsapic->id << 8) | lsapic->eid;
81  	return 0;
82  }
83  
84  /*
85   * Retrieve the ARM CPU physical identifier (MPIDR)
86   */
map_gicc_mpidr(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * mpidr)87  static int map_gicc_mpidr(struct acpi_subtable_header *entry,
88  		int device_declaration, u32 acpi_id, phys_cpuid_t *mpidr)
89  {
90  	struct acpi_madt_generic_interrupt *gicc =
91  	    container_of(entry, struct acpi_madt_generic_interrupt, header);
92  
93  	if (!(gicc->flags &
94  	      (ACPI_MADT_ENABLED | ACPI_MADT_GICC_ONLINE_CAPABLE)))
95  		return -ENODEV;
96  
97  	/* device_declaration means Device object in DSDT, in the
98  	 * GIC interrupt model, logical processors are required to
99  	 * have a Processor Device object in the DSDT, so we should
100  	 * check device_declaration here
101  	 */
102  	if (device_declaration && (gicc->uid == acpi_id)) {
103  		*mpidr = gicc->arm_mpidr;
104  		return 0;
105  	}
106  
107  	return -EINVAL;
108  }
109  
110  /*
111   * Retrieve the RISC-V hartid for the processor
112   */
map_rintc_hartid(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * hartid)113  static int map_rintc_hartid(struct acpi_subtable_header *entry,
114  			    int device_declaration, u32 acpi_id,
115  			    phys_cpuid_t *hartid)
116  {
117  	struct acpi_madt_rintc *rintc =
118  	    container_of(entry, struct acpi_madt_rintc, header);
119  
120  	if (!(rintc->flags & ACPI_MADT_ENABLED))
121  		return -ENODEV;
122  
123  	/* device_declaration means Device object in DSDT, in the
124  	 * RISC-V, logical processors are required to
125  	 * have a Processor Device object in the DSDT, so we should
126  	 * check device_declaration here
127  	 */
128  	if (device_declaration && rintc->uid == acpi_id) {
129  		*hartid = rintc->hart_id;
130  		return 0;
131  	}
132  
133  	return -EINVAL;
134  }
135  
136  /*
137   * Retrieve LoongArch CPU physical id
138   */
map_core_pic_id(struct acpi_subtable_header * entry,int device_declaration,u32 acpi_id,phys_cpuid_t * phys_id)139  static int map_core_pic_id(struct acpi_subtable_header *entry,
140  		int device_declaration, u32 acpi_id, phys_cpuid_t *phys_id)
141  {
142  	struct acpi_madt_core_pic *core_pic =
143  		container_of(entry, struct acpi_madt_core_pic, header);
144  
145  	if (!(core_pic->flags & ACPI_MADT_ENABLED))
146  		return -ENODEV;
147  
148  	/* device_declaration means Device object in DSDT, in LoongArch
149  	 * system, logical processor acpi_id is required in _UID property
150  	 * of DSDT table, so we should check device_declaration here
151  	 */
152  	if (device_declaration && (core_pic->processor_id == acpi_id)) {
153  		*phys_id = core_pic->core_id;
154  		return 0;
155  	}
156  
157  	return -EINVAL;
158  }
159  
map_madt_entry(struct acpi_table_madt * madt,int type,u32 acpi_id)160  static phys_cpuid_t map_madt_entry(struct acpi_table_madt *madt,
161  				   int type, u32 acpi_id)
162  {
163  	unsigned long madt_end, entry;
164  	phys_cpuid_t phys_id = PHYS_CPUID_INVALID;	/* CPU hardware ID */
165  
166  	if (!madt)
167  		return phys_id;
168  
169  	entry = (unsigned long)madt;
170  	madt_end = entry + madt->header.length;
171  
172  	/* Parse all entries looking for a match. */
173  
174  	entry += sizeof(struct acpi_table_madt);
175  	while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
176  		struct acpi_subtable_header *header =
177  			(struct acpi_subtable_header *)entry;
178  		if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
179  			if (!map_lapic_id(header, acpi_id, &phys_id))
180  				break;
181  		} else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
182  			if (!map_x2apic_id(header, type, acpi_id, &phys_id))
183  				break;
184  		} else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
185  			if (!map_lsapic_id(header, type, acpi_id, &phys_id))
186  				break;
187  		} else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT) {
188  			if (!map_gicc_mpidr(header, type, acpi_id, &phys_id))
189  				break;
190  		} else if (header->type == ACPI_MADT_TYPE_RINTC) {
191  			if (!map_rintc_hartid(header, type, acpi_id, &phys_id))
192  				break;
193  		} else if (header->type == ACPI_MADT_TYPE_CORE_PIC) {
194  			if (!map_core_pic_id(header, type, acpi_id, &phys_id))
195  				break;
196  		}
197  		entry += header->length;
198  	}
199  	return phys_id;
200  }
201  
acpi_map_madt_entry(u32 acpi_id)202  phys_cpuid_t __init acpi_map_madt_entry(u32 acpi_id)
203  {
204  	struct acpi_table_madt *madt = NULL;
205  	phys_cpuid_t rv;
206  
207  	acpi_get_table(ACPI_SIG_MADT, 0,
208  		       (struct acpi_table_header **)&madt);
209  	if (!madt)
210  		return PHYS_CPUID_INVALID;
211  
212  	rv = map_madt_entry(madt, 1, acpi_id);
213  
214  	acpi_put_table((struct acpi_table_header *)madt);
215  
216  	return rv;
217  }
218  
acpi_get_madt_revision(void)219  int __init acpi_get_madt_revision(void)
220  {
221  	struct acpi_table_header *madt = NULL;
222  	int revision;
223  
224  	if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0, &madt)))
225  		return -EINVAL;
226  
227  	revision = madt->revision;
228  
229  	acpi_put_table(madt);
230  
231  	return revision;
232  }
233  
map_mat_entry(acpi_handle handle,int type,u32 acpi_id)234  static phys_cpuid_t map_mat_entry(acpi_handle handle, int type, u32 acpi_id)
235  {
236  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
237  	union acpi_object *obj;
238  	struct acpi_subtable_header *header;
239  	phys_cpuid_t phys_id = PHYS_CPUID_INVALID;
240  
241  	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
242  		goto exit;
243  
244  	if (!buffer.length || !buffer.pointer)
245  		goto exit;
246  
247  	obj = buffer.pointer;
248  	if (obj->type != ACPI_TYPE_BUFFER ||
249  	    obj->buffer.length < sizeof(struct acpi_subtable_header)) {
250  		goto exit;
251  	}
252  
253  	header = (struct acpi_subtable_header *)obj->buffer.pointer;
254  	if (header->type == ACPI_MADT_TYPE_LOCAL_APIC)
255  		map_lapic_id(header, acpi_id, &phys_id);
256  	else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC)
257  		map_lsapic_id(header, type, acpi_id, &phys_id);
258  	else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC)
259  		map_x2apic_id(header, type, acpi_id, &phys_id);
260  	else if (header->type == ACPI_MADT_TYPE_GENERIC_INTERRUPT)
261  		map_gicc_mpidr(header, type, acpi_id, &phys_id);
262  	else if (header->type == ACPI_MADT_TYPE_CORE_PIC)
263  		map_core_pic_id(header, type, acpi_id, &phys_id);
264  
265  exit:
266  	kfree(buffer.pointer);
267  	return phys_id;
268  }
269  
acpi_get_phys_id(acpi_handle handle,int type,u32 acpi_id)270  phys_cpuid_t acpi_get_phys_id(acpi_handle handle, int type, u32 acpi_id)
271  {
272  	phys_cpuid_t phys_id;
273  
274  	phys_id = map_mat_entry(handle, type, acpi_id);
275  	if (invalid_phys_cpuid(phys_id))
276  		phys_id = map_madt_entry(get_madt_table(), type, acpi_id);
277  
278  	return phys_id;
279  }
280  EXPORT_SYMBOL_GPL(acpi_get_phys_id);
281  
acpi_map_cpuid(phys_cpuid_t phys_id,u32 acpi_id)282  int acpi_map_cpuid(phys_cpuid_t phys_id, u32 acpi_id)
283  {
284  #ifdef CONFIG_SMP
285  	int i;
286  #endif
287  
288  	if (invalid_phys_cpuid(phys_id)) {
289  		/*
290  		 * On UP processor, there is no _MAT or MADT table.
291  		 * So above phys_id is always set to PHYS_CPUID_INVALID.
292  		 *
293  		 * BIOS may define multiple CPU handles even for UP processor.
294  		 * For example,
295  		 *
296  		 * Scope (_PR)
297  		 * {
298  		 *     Processor (CPU0, 0x00, 0x00000410, 0x06) {}
299  		 *     Processor (CPU1, 0x01, 0x00000410, 0x06) {}
300  		 *     Processor (CPU2, 0x02, 0x00000410, 0x06) {}
301  		 *     Processor (CPU3, 0x03, 0x00000410, 0x06) {}
302  		 * }
303  		 *
304  		 * Ignores phys_id and always returns 0 for the processor
305  		 * handle with acpi id 0 if nr_cpu_ids is 1.
306  		 * This should be the case if SMP tables are not found.
307  		 * Return -EINVAL for other CPU's handle.
308  		 */
309  		if (nr_cpu_ids <= 1 && acpi_id == 0)
310  			return acpi_id;
311  		else
312  			return -EINVAL;
313  	}
314  
315  #ifdef CONFIG_SMP
316  	for_each_possible_cpu(i) {
317  		if (cpu_physical_id(i) == phys_id)
318  			return i;
319  	}
320  #else
321  	/* In UP kernel, only processor 0 is valid */
322  	if (phys_id == 0)
323  		return phys_id;
324  #endif
325  	return -ENODEV;
326  }
327  
acpi_get_cpuid(acpi_handle handle,int type,u32 acpi_id)328  int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
329  {
330  	phys_cpuid_t phys_id;
331  
332  	phys_id = acpi_get_phys_id(handle, type, acpi_id);
333  
334  	return acpi_map_cpuid(phys_id, acpi_id);
335  }
336  EXPORT_SYMBOL_GPL(acpi_get_cpuid);
337  
338  #ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
get_ioapic_id(struct acpi_subtable_header * entry,u32 gsi_base,u64 * phys_addr,int * ioapic_id)339  static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
340  			 u64 *phys_addr, int *ioapic_id)
341  {
342  	struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
343  
344  	if (ioapic->global_irq_base != gsi_base)
345  		return 0;
346  
347  	*phys_addr = ioapic->address;
348  	*ioapic_id = ioapic->id;
349  	return 1;
350  }
351  
parse_madt_ioapic_entry(u32 gsi_base,u64 * phys_addr)352  static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
353  {
354  	struct acpi_subtable_header *hdr;
355  	unsigned long madt_end, entry;
356  	struct acpi_table_madt *madt;
357  	int apic_id = -1;
358  
359  	madt = get_madt_table();
360  	if (!madt)
361  		return apic_id;
362  
363  	entry = (unsigned long)madt;
364  	madt_end = entry + madt->header.length;
365  
366  	/* Parse all entries looking for a match. */
367  	entry += sizeof(struct acpi_table_madt);
368  	while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
369  		hdr = (struct acpi_subtable_header *)entry;
370  		if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
371  		    get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
372  			break;
373  		else
374  			entry += hdr->length;
375  	}
376  
377  	return apic_id;
378  }
379  
parse_mat_ioapic_entry(acpi_handle handle,u32 gsi_base,u64 * phys_addr)380  static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
381  				  u64 *phys_addr)
382  {
383  	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
384  	struct acpi_subtable_header *header;
385  	union acpi_object *obj;
386  	int apic_id = -1;
387  
388  	if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
389  		goto exit;
390  
391  	if (!buffer.length || !buffer.pointer)
392  		goto exit;
393  
394  	obj = buffer.pointer;
395  	if (obj->type != ACPI_TYPE_BUFFER ||
396  	    obj->buffer.length < sizeof(struct acpi_subtable_header))
397  		goto exit;
398  
399  	header = (struct acpi_subtable_header *)obj->buffer.pointer;
400  	if (header->type == ACPI_MADT_TYPE_IO_APIC)
401  		get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
402  
403  exit:
404  	kfree(buffer.pointer);
405  	return apic_id;
406  }
407  
408  /**
409   * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base
410   * @handle:	ACPI object for IOAPIC device
411   * @gsi_base:	GSI base to match with
412   * @phys_addr:	Pointer to store physical address of matching IOAPIC record
413   *
414   * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search
415   * for an ACPI IOAPIC record matching @gsi_base.
416   * Return IOAPIC id and store physical address in @phys_addr if found a match,
417   * otherwise return <0.
418   */
acpi_get_ioapic_id(acpi_handle handle,u32 gsi_base,u64 * phys_addr)419  int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr)
420  {
421  	int apic_id;
422  
423  	apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr);
424  	if (apic_id == -1)
425  		apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr);
426  
427  	return apic_id;
428  }
429  #endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */
430