aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/apic/io_apic.c
diff options
context:
space:
mode:
authorJiang Liu <jiang.liu@linux.intel.com>2015-04-13 02:11:55 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-04-24 09:36:51 -0400
commit49c7e60022912d10da88ba67e8eb2927f1143f6a (patch)
tree7c539f35485d4d4345c0f23cb7de1e872f21df68 /arch/x86/kernel/apic/io_apic.c
parentc4d05a2c354b15965c9b2a5f46016a5d9f43e224 (diff)
x86/irq: Implement callbacks to enable hierarchical irqdomains on IOAPICs
Implement required callbacks to prepare for enabling hierarchical irqdomains on IOAPICs. After the conversion we can remove quite some code from the old implementation. Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com> Tested-by: Joerg Roedel <jroedel@suse.de> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: David Cohen <david.a.cohen@linux.intel.com> Cc: Sander Eikelenboom <linux@eikelenboom.it> Cc: David Vrabel <david.vrabel@citrix.com> Cc: Tony Luck <tony.luck@intel.com> Cc: Joerg Roedel <joro@8bytes.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Cc: Bjorn Helgaas <bhelgaas@google.com> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Rafael J. Wysocki <rjw@rjwysocki.net> Cc: Randy Dunlap <rdunlap@infradead.org> Cc: Yinghai Lu <yinghai@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Dimitri Sivanich <sivanich@sgi.com> Cc: Jan Beulich <JBeulich@suse.com> Cc: Grant Likely <grant.likely@linaro.org> Link: http://lkml.kernel.org/r/1428905519-23704-34-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'arch/x86/kernel/apic/io_apic.c')
-rw-r--r--arch/x86/kernel/apic/io_apic.c159
1 files changed, 156 insertions, 3 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 5c953bb96ecf..3406dbec1570 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -78,6 +78,13 @@ static DEFINE_MUTEX(ioapic_mutex);
78static unsigned int ioapic_dynirq_base; 78static unsigned int ioapic_dynirq_base;
79static int ioapic_initialized; 79static int ioapic_initialized;
80 80
81struct mp_chip_data {
82 struct IO_APIC_route_entry entry;
83 int trigger;
84 int polarity;
85 bool isa_irq;
86};
87
81struct mp_pin_info { 88struct mp_pin_info {
82 int trigger; 89 int trigger;
83 int polarity; 90 int polarity;
@@ -949,11 +956,28 @@ void ioapic_set_alloc_attr(struct irq_alloc_info *info, int node,
949 info->ioapic_valid = 1; 956 info->ioapic_valid = 1;
950} 957}
951 958
959static void mp_register_handler(unsigned int irq, unsigned long trigger)
960{
961 irq_flow_handler_t hdl;
962 bool fasteoi;
963
964 if (trigger) {
965 irq_set_status_flags(irq, IRQ_LEVEL);
966 fasteoi = true;
967 } else {
968 irq_clear_status_flags(irq, IRQ_LEVEL);
969 fasteoi = false;
970 }
971
972 hdl = fasteoi ? handle_fasteoi_irq : handle_edge_irq;
973 __irq_set_handler(irq, hdl, 0, fasteoi ? "fasteoi" : "edge");
974}
975
952static int alloc_irq_from_domain(struct irq_domain *domain, u32 gsi, int pin, 976static int alloc_irq_from_domain(struct irq_domain *domain, u32 gsi, int pin,
953 struct irq_alloc_info *info) 977 struct irq_alloc_info *info)
954{ 978{
955 int irq = -1; 979 int irq = -1;
956 int ioapic = (int)(long)domain->host_data; 980 int ioapic = mp_irqdomain_ioapic_idx(domain);
957 int type = ioapics[ioapic].irqdomain_cfg.type; 981 int type = ioapics[ioapic].irqdomain_cfg.type;
958 982
959 switch (type) { 983 switch (type) {
@@ -3029,7 +3053,7 @@ static inline void set_io_apic_irq_attr(struct io_apic_irq_attr *irq_attr,
3029int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq, 3053int mp_irqdomain_map(struct irq_domain *domain, unsigned int virq,
3030 irq_hw_number_t hwirq) 3054 irq_hw_number_t hwirq)
3031{ 3055{
3032 int ioapic = (int)(long)domain->host_data; 3056 int ioapic = mp_irqdomain_ioapic_idx(domain);
3033 struct mp_pin_info *info = mp_pin_info(ioapic, hwirq); 3057 struct mp_pin_info *info = mp_pin_info(ioapic, hwirq);
3034 struct io_apic_irq_attr attr; 3058 struct io_apic_irq_attr attr;
3035 3059
@@ -3067,7 +3091,7 @@ void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq)
3067{ 3091{
3068 struct irq_data *data = irq_get_irq_data(virq); 3092 struct irq_data *data = irq_get_irq_data(virq);
3069 struct irq_cfg *cfg = irq_cfg(virq); 3093 struct irq_cfg *cfg = irq_cfg(virq);
3070 int ioapic = (int)(long)domain->host_data; 3094 int ioapic = mp_irqdomain_ioapic_idx(domain);
3071 int pin = (int)data->hwirq; 3095 int pin = (int)data->hwirq;
3072 3096
3073 ioapic_mask_entry(ioapic, pin); 3097 ioapic_mask_entry(ioapic, pin);
@@ -3076,6 +3100,130 @@ void mp_irqdomain_unmap(struct irq_domain *domain, unsigned int virq)
3076 arch_teardown_hwirq(virq); 3100 arch_teardown_hwirq(virq);
3077} 3101}
3078 3102
3103static void mp_irqdomain_get_attr(u32 gsi, struct mp_chip_data *data,
3104 struct irq_alloc_info *info)
3105{
3106 if (info && info->ioapic_valid) {
3107 data->trigger = info->ioapic_trigger;
3108 data->polarity = info->ioapic_polarity;
3109 } else if (acpi_get_override_irq(gsi, &data->trigger,
3110 &data->polarity) < 0) {
3111 /* PCI interrupts are always polarity one level triggered. */
3112 data->trigger = 1;
3113 data->polarity = 1;
3114 }
3115}
3116
3117static void mp_setup_entry(struct irq_cfg *cfg, struct mp_chip_data *data,
3118 struct IO_APIC_route_entry *entry)
3119{
3120 memset(entry, 0, sizeof(*entry));
3121 entry->delivery_mode = apic->irq_delivery_mode;
3122 entry->dest_mode = apic->irq_dest_mode;
3123 entry->dest = cfg->dest_apicid;
3124 entry->vector = cfg->vector;
3125 entry->mask = 0; /* enable IRQ */
3126 entry->trigger = data->trigger;
3127 entry->polarity = data->polarity;
3128 /*
3129 * Mask level triggered irqs.
3130 * Use IRQ_DELAYED_DISABLE for edge triggered irqs.
3131 */
3132 if (data->trigger)
3133 entry->mask = 1;
3134}
3135
3136int mp_irqdomain_alloc(struct irq_domain *domain, unsigned int virq,
3137 unsigned int nr_irqs, void *arg)
3138{
3139 int ret, ioapic, pin;
3140 struct irq_cfg *cfg;
3141 struct irq_data *irq_data;
3142 struct mp_chip_data *data;
3143 struct irq_alloc_info *info = arg;
3144
3145 if (!info || nr_irqs > 1)
3146 return -EINVAL;
3147 irq_data = irq_domain_get_irq_data(domain, virq);
3148 if (!irq_data)
3149 return -EINVAL;
3150
3151 ioapic = mp_irqdomain_ioapic_idx(domain);
3152 pin = info->ioapic_pin;
3153 if (irq_find_mapping(domain, (irq_hw_number_t)pin) > 0)
3154 return -EEXIST;
3155
3156 data = kzalloc(sizeof(*data), GFP_KERNEL);
3157 if (!data)
3158 return -ENOMEM;
3159
3160 info->ioapic_entry = &data->entry;
3161 ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, info);
3162 if (ret < 0) {
3163 kfree(data);
3164 return ret;
3165 }
3166
3167 irq_data->hwirq = info->ioapic_pin;
3168 irq_data->chip = &ioapic_chip;
3169 irq_data->chip_data = data;
3170 mp_irqdomain_get_attr(mp_pin_to_gsi(ioapic, pin), data, info);
3171
3172 cfg = irqd_cfg(irq_data);
3173 add_pin_to_irq_node(cfg, info->ioapic_node, ioapic, pin);
3174 if (info->ioapic_entry)
3175 mp_setup_entry(cfg, data, info->ioapic_entry);
3176 mp_register_handler(virq, data->trigger);
3177 if (virq < nr_legacy_irqs())
3178 legacy_pic->mask(virq);
3179
3180 apic_printk(APIC_VERBOSE, KERN_DEBUG
3181 "IOAPIC[%d]: Set routing entry (%d-%d -> 0x%x -> IRQ %d Mode:%i Active:%i Dest:%d)\n",
3182 ioapic, mpc_ioapic_id(ioapic), pin, cfg->vector,
3183 virq, data->trigger, data->polarity, cfg->dest_apicid);
3184
3185 return 0;
3186}
3187
3188void mp_irqdomain_free(struct irq_domain *domain, unsigned int virq,
3189 unsigned int nr_irqs)
3190{
3191 struct irq_cfg *cfg = irq_cfg(virq);
3192 struct irq_data *irq_data;
3193
3194 BUG_ON(nr_irqs != 1);
3195 irq_data = irq_domain_get_irq_data(domain, virq);
3196 if (irq_data && irq_data->chip_data) {
3197 __remove_pin_from_irq(cfg, mp_irqdomain_ioapic_idx(domain),
3198 (int)irq_data->hwirq);
3199 WARN_ON(!list_empty(&cfg->irq_2_pin));
3200 kfree(irq_data->chip_data);
3201 }
3202 irq_domain_free_irqs_top(domain, virq, nr_irqs);
3203}
3204
3205void mp_irqdomain_activate(struct irq_domain *domain,
3206 struct irq_data *irq_data)
3207{
3208 unsigned long flags;
3209 struct irq_pin_list *entry;
3210 struct mp_chip_data *data = irq_data->chip_data;
3211 struct irq_cfg *cfg = irqd_cfg(irq_data);
3212
3213 raw_spin_lock_irqsave(&ioapic_lock, flags);
3214 for_each_irq_pin(entry, cfg->irq_2_pin)
3215 __ioapic_write_entry(entry->apic, entry->pin, data->entry);
3216 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
3217}
3218
3219void mp_irqdomain_deactivate(struct irq_domain *domain,
3220 struct irq_data *irq_data)
3221{
3222 /* It won't be called for IRQ with multiple IOAPIC pins associated */
3223 ioapic_mask_entry(mp_irqdomain_ioapic_idx(domain),
3224 (int)irq_data->hwirq);
3225}
3226
3079int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node) 3227int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node)
3080{ 3228{
3081 int ret = 0; 3229 int ret = 0;
@@ -3104,3 +3252,8 @@ int mp_set_gsi_attr(u32 gsi, int trigger, int polarity, int node)
3104 3252
3105 return ret; 3253 return ret;
3106} 3254}
3255
3256int mp_irqdomain_ioapic_idx(struct irq_domain *domain)
3257{
3258 return (int)(long)domain->host_data;
3259}