aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/apic/io_apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/apic/io_apic.c')
-rw-r--r--arch/x86/kernel/apic/io_apic.c87
1 files changed, 56 insertions, 31 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 60f25e88734b..4333a751937d 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -3840,20 +3840,6 @@ int mp_find_ioapic_pin(int ioapic, u32 gsi)
3840 return gsi - gsi_cfg->gsi_base; 3840 return gsi - gsi_cfg->gsi_base;
3841} 3841}
3842 3842
3843static int bad_ioapic(unsigned long address)
3844{
3845 if (nr_ioapics >= MAX_IO_APICS) {
3846 pr_warn("WARNING: Max # of I/O APICs (%d) exceeded (found %d), skipping\n",
3847 MAX_IO_APICS, nr_ioapics);
3848 return 1;
3849 }
3850 if (!address) {
3851 pr_warn("WARNING: Bogus (zero) I/O APIC address found in table, skipping!\n");
3852 return 1;
3853 }
3854 return 0;
3855}
3856
3857static int bad_ioapic_register(int idx) 3843static int bad_ioapic_register(int idx)
3858{ 3844{
3859 union IO_APIC_reg_00 reg_00; 3845 union IO_APIC_reg_00 reg_00;
@@ -3873,29 +3859,51 @@ static int bad_ioapic_register(int idx)
3873 return 0; 3859 return 0;
3874} 3860}
3875 3861
3876void mp_register_ioapic(int id, u32 address, u32 gsi_base, 3862static int find_free_ioapic_entry(void)
3877 struct ioapic_domain_cfg *cfg) 3863{
3864 return nr_ioapics;
3865}
3866
3867/**
3868 * mp_register_ioapic - Register an IOAPIC device
3869 * @id: hardware IOAPIC ID
3870 * @address: physical address of IOAPIC register area
3871 * @gsi_base: base of GSI associated with the IOAPIC
3872 * @cfg: configuration information for the IOAPIC
3873 */
3874int mp_register_ioapic(int id, u32 address, u32 gsi_base,
3875 struct ioapic_domain_cfg *cfg)
3878{ 3876{
3879 int idx = 0;
3880 int entries;
3881 struct mp_ioapic_gsi *gsi_cfg; 3877 struct mp_ioapic_gsi *gsi_cfg;
3878 int idx, ioapic, entries;
3879 u32 gsi_end;
3882 3880
3883 if (bad_ioapic(address)) 3881 if (!address) {
3884 return; 3882 pr_warn("Bogus (zero) I/O APIC address found, skipping!\n");
3883 return -EINVAL;
3884 }
3885 for_each_ioapic(ioapic)
3886 if (ioapics[ioapic].mp_config.apicaddr == address) {
3887 pr_warn("address 0x%x conflicts with IOAPIC%d\n",
3888 address, ioapic);
3889 return -EEXIST;
3890 }
3885 3891
3886 idx = nr_ioapics; 3892 idx = find_free_ioapic_entry();
3893 if (idx >= MAX_IO_APICS) {
3894 pr_warn("Max # of I/O APICs (%d) exceeded (found %d), skipping\n",
3895 MAX_IO_APICS, idx);
3896 return -ENOSPC;
3897 }
3887 3898
3888 ioapics[idx].mp_config.type = MP_IOAPIC; 3899 ioapics[idx].mp_config.type = MP_IOAPIC;
3889 ioapics[idx].mp_config.flags = MPC_APIC_USABLE; 3900 ioapics[idx].mp_config.flags = MPC_APIC_USABLE;
3890 ioapics[idx].mp_config.apicaddr = address; 3901 ioapics[idx].mp_config.apicaddr = address;
3891 ioapics[idx].irqdomain = NULL;
3892 ioapics[idx].irqdomain_cfg = *cfg;
3893 3902
3894 set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); 3903 set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address);
3895
3896 if (bad_ioapic_register(idx)) { 3904 if (bad_ioapic_register(idx)) {
3897 clear_fixmap(FIX_IO_APIC_BASE_0 + idx); 3905 clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
3898 return; 3906 return -ENODEV;
3899 } 3907 }
3900 3908
3901 ioapics[idx].mp_config.apicid = io_apic_unique_id(idx, id); 3909 ioapics[idx].mp_config.apicid = io_apic_unique_id(idx, id);
@@ -3906,24 +3914,41 @@ void mp_register_ioapic(int id, u32 address, u32 gsi_base,
3906 * and to prevent reprogramming of IOAPIC pins (PCI GSIs). 3914 * and to prevent reprogramming of IOAPIC pins (PCI GSIs).
3907 */ 3915 */
3908 entries = io_apic_get_redir_entries(idx); 3916 entries = io_apic_get_redir_entries(idx);
3917 gsi_end = gsi_base + entries - 1;
3918 for_each_ioapic(ioapic) {
3919 gsi_cfg = mp_ioapic_gsi_routing(ioapic);
3920 if ((gsi_base >= gsi_cfg->gsi_base &&
3921 gsi_base <= gsi_cfg->gsi_end) ||
3922 (gsi_end >= gsi_cfg->gsi_base &&
3923 gsi_end <= gsi_cfg->gsi_end)) {
3924 pr_warn("GSI range [%u-%u] for new IOAPIC conflicts with GSI[%u-%u]\n",
3925 gsi_base, gsi_end,
3926 gsi_cfg->gsi_base, gsi_cfg->gsi_end);
3927 clear_fixmap(FIX_IO_APIC_BASE_0 + idx);
3928 return -ENOSPC;
3929 }
3930 }
3909 gsi_cfg = mp_ioapic_gsi_routing(idx); 3931 gsi_cfg = mp_ioapic_gsi_routing(idx);
3910 gsi_cfg->gsi_base = gsi_base; 3932 gsi_cfg->gsi_base = gsi_base;
3911 gsi_cfg->gsi_end = gsi_base + entries - 1; 3933 gsi_cfg->gsi_end = gsi_end;
3912 3934
3913 /* 3935 ioapics[idx].irqdomain = NULL;
3914 * The number of IO-APIC IRQ registers (== #pins): 3936 ioapics[idx].irqdomain_cfg = *cfg;
3915 */
3916 ioapics[idx].nr_registers = entries;
3917 3937
3918 if (gsi_cfg->gsi_end >= gsi_top) 3938 if (gsi_cfg->gsi_end >= gsi_top)
3919 gsi_top = gsi_cfg->gsi_end + 1; 3939 gsi_top = gsi_cfg->gsi_end + 1;
3940 if (nr_ioapics <= idx)
3941 nr_ioapics = idx + 1;
3942
3943 /* Set nr_registers to mark entry present */
3944 ioapics[idx].nr_registers = entries;
3920 3945
3921 pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, GSI %d-%d\n", 3946 pr_info("IOAPIC[%d]: apic_id %d, version %d, address 0x%x, GSI %d-%d\n",
3922 idx, mpc_ioapic_id(idx), 3947 idx, mpc_ioapic_id(idx),
3923 mpc_ioapic_ver(idx), mpc_ioapic_addr(idx), 3948 mpc_ioapic_ver(idx), mpc_ioapic_addr(idx),
3924 gsi_cfg->gsi_base, gsi_cfg->gsi_end); 3949 gsi_cfg->gsi_base, gsi_cfg->gsi_end);
3925 3950
3926 nr_ioapics++; 3951 return 0;
3927} 3952}
3928 3953
3929int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq, 3954int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,