1efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang/*
2efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * sfi.c - x86 architecture SFI support.
3efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang *
4efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * Copyright (c) 2009, Intel Corporation.
5efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang *
6efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * This program is free software; you can redistribute it and/or modify it
7efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * under the terms and conditions of the GNU General Public License,
8efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * version 2, as published by the Free Software Foundation.
9efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang *
10efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * This program is distributed in the hope it will be useful, but WITHOUT
11efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * more details.
14efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang *
15efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * You should have received a copy of the GNU General Public License along with
16efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * this program; if not, write to the Free Software Foundation, Inc.,
17efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
18efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang *
19efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang */
20efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
21efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#define KMSG_COMPONENT "SFI"
22efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
23efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
24efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#include <linux/acpi.h>
25efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#include <linux/init.h>
26efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#include <linux/sfi.h>
27efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#include <linux/io.h>
281b5d3e00d45e093fa0551c588034c3355b362f66Jiang Liu#include <linux/irqdomain.h>
29efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
30efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#include <asm/io_apic.h>
31efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#include <asm/mpspec.h>
32efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#include <asm/setup.h>
33efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#include <asm/apic.h>
34efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
35efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#ifdef CONFIG_X86_LOCAL_APIC
36efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tangstatic unsigned long sfi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE;
37efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
38efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang/* All CPUs enumerated by SFI must be present and enabled */
399611dc7a8de8a5c6244886dad020995b1a896236Jan Beulichstatic void __init mp_sfi_register_lapic(u8 id)
40efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang{
41cb2ded37fd2e1039f96c8c892da024a8f033add5Yinghai Lu	if (MAX_LOCAL_APIC - id <= 0) {
42efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang		pr_warning("Processor #%d invalid (max %d)\n",
43cb2ded37fd2e1039f96c8c892da024a8f033add5Yinghai Lu			id, MAX_LOCAL_APIC);
44efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang		return;
45efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	}
46efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
47efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	pr_info("registering lapic[%d]\n", id);
48efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
49efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	generic_processor_info(id, GET_APIC_VERSION(apic_read(APIC_LVR)));
50efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang}
51efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
52efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tangstatic int __init sfi_parse_cpus(struct sfi_table_header *table)
53efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang{
54efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	struct sfi_table_simple *sb;
55efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	struct sfi_cpu_table_entry *pentry;
56efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	int i;
57efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	int cpu_num;
58efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
59efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	sb = (struct sfi_table_simple *)table;
60efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	cpu_num = SFI_GET_NUM_ENTRIES(sb, struct sfi_cpu_table_entry);
61efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	pentry = (struct sfi_cpu_table_entry *)sb->pentry;
62efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
63efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	for (i = 0; i < cpu_num; i++) {
64efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang		mp_sfi_register_lapic(pentry->apic_id);
65efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang		pentry++;
66efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	}
67efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
68efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	smp_found_config = 1;
69efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	return 0;
70efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang}
71efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#endif /* CONFIG_X86_LOCAL_APIC */
72efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
73efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#ifdef CONFIG_X86_IO_APIC
74ecc527d560cd87c74cc0bc7aff36eb72f7e18615Jiang Liustatic struct irq_domain_ops sfi_ioapic_irqdomain_ops = {
75ecc527d560cd87c74cc0bc7aff36eb72f7e18615Jiang Liu	.map = mp_irqdomain_map,
76ecc527d560cd87c74cc0bc7aff36eb72f7e18615Jiang Liu};
77efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
78efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tangstatic int __init sfi_parse_ioapic(struct sfi_table_header *table)
79efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang{
80efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	struct sfi_table_simple *sb;
81efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	struct sfi_apic_table_entry *pentry;
82efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	int i, num;
831b5d3e00d45e093fa0551c588034c3355b362f66Jiang Liu	struct ioapic_domain_cfg cfg = {
841b5d3e00d45e093fa0551c588034c3355b362f66Jiang Liu		.type = IOAPIC_DOMAIN_STRICT,
851b5d3e00d45e093fa0551c588034c3355b362f66Jiang Liu		.ops = &sfi_ioapic_irqdomain_ops,
861b5d3e00d45e093fa0551c588034c3355b362f66Jiang Liu	};
87efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
88efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	sb = (struct sfi_table_simple *)table;
89efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	num = SFI_GET_NUM_ENTRIES(sb, struct sfi_apic_table_entry);
90efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	pentry = (struct sfi_apic_table_entry *)sb->pentry;
91efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
92efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	for (i = 0; i < num; i++) {
931b5d3e00d45e093fa0551c588034c3355b362f66Jiang Liu		mp_register_ioapic(i, pentry->phys_addr, gsi_top, &cfg);
94efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang		pentry++;
95efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	}
96efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
97efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	WARN(pic_mode, KERN_WARNING
98efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang		"SFI: pic_mod shouldn't be 1 when IOAPIC table is present\n");
99efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	pic_mode = 0;
100efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	return 0;
101efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang}
102efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#endif /* CONFIG_X86_IO_APIC */
103efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang
104efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang/*
105efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang * sfi_platform_init(): register lapics & io-apics
106efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang */
107efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tangint __init sfi_platform_init(void)
108efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang{
109efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#ifdef CONFIG_X86_LOCAL_APIC
11053301f36f316a6519c464b0ef2a155386c20be19Yinghai Lu	register_lapic_address(sfi_lapic_addr);
111efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	sfi_table_parse(SFI_SIG_CPUS, NULL, NULL, sfi_parse_cpus);
112efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#endif
113efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#ifdef CONFIG_X86_IO_APIC
114efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	sfi_table_parse(SFI_SIG_APIC, NULL, NULL, sfi_parse_ioapic);
115efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang#endif
116efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang	return 0;
117efafc8b213e67ed148a5b53ade29ee7b48af907dFeng Tang}
118