Linux 4.1.18
[linux/fpc-iii.git] / arch / x86 / kernel / apic / htirq.c
blob816f36e979ad03c6b052b1ec5c1ca34b6dc566e4
1 /*
2 * Support Hypertransport IRQ
4 * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
5 * Moved from arch/x86/kernel/apic/io_apic.c.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 #include <linux/mm.h>
12 #include <linux/interrupt.h>
13 #include <linux/init.h>
14 #include <linux/device.h>
15 #include <linux/pci.h>
16 #include <linux/htirq.h>
17 #include <asm/hw_irq.h>
18 #include <asm/apic.h>
19 #include <asm/hypertransport.h>
22 * Hypertransport interrupt support
24 static void target_ht_irq(unsigned int irq, unsigned int dest, u8 vector)
26 struct ht_irq_msg msg;
28 fetch_ht_irq_msg(irq, &msg);
30 msg.address_lo &= ~(HT_IRQ_LOW_VECTOR_MASK | HT_IRQ_LOW_DEST_ID_MASK);
31 msg.address_hi &= ~(HT_IRQ_HIGH_DEST_ID_MASK);
33 msg.address_lo |= HT_IRQ_LOW_VECTOR(vector) | HT_IRQ_LOW_DEST_ID(dest);
34 msg.address_hi |= HT_IRQ_HIGH_DEST_ID(dest);
36 write_ht_irq_msg(irq, &msg);
39 static int
40 ht_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
42 struct irq_cfg *cfg = irqd_cfg(data);
43 unsigned int dest;
44 int ret;
46 ret = apic_set_affinity(data, mask, &dest);
47 if (ret)
48 return ret;
50 target_ht_irq(data->irq, dest, cfg->vector);
51 return IRQ_SET_MASK_OK_NOCOPY;
54 static struct irq_chip ht_irq_chip = {
55 .name = "PCI-HT",
56 .irq_mask = mask_ht_irq,
57 .irq_unmask = unmask_ht_irq,
58 .irq_ack = apic_ack_edge,
59 .irq_set_affinity = ht_set_affinity,
60 .irq_retrigger = apic_retrigger_irq,
61 .flags = IRQCHIP_SKIP_SET_WAKE,
64 int arch_setup_ht_irq(unsigned int irq, struct pci_dev *dev)
66 struct irq_cfg *cfg;
67 struct ht_irq_msg msg;
68 unsigned dest;
69 int err;
71 if (disable_apic)
72 return -ENXIO;
74 cfg = irq_cfg(irq);
75 err = assign_irq_vector(irq, cfg, apic->target_cpus());
76 if (err)
77 return err;
79 err = apic->cpu_mask_to_apicid_and(cfg->domain,
80 apic->target_cpus(), &dest);
81 if (err)
82 return err;
84 msg.address_hi = HT_IRQ_HIGH_DEST_ID(dest);
86 msg.address_lo =
87 HT_IRQ_LOW_BASE |
88 HT_IRQ_LOW_DEST_ID(dest) |
89 HT_IRQ_LOW_VECTOR(cfg->vector) |
90 ((apic->irq_dest_mode == 0) ?
91 HT_IRQ_LOW_DM_PHYSICAL :
92 HT_IRQ_LOW_DM_LOGICAL) |
93 HT_IRQ_LOW_RQEOI_EDGE |
94 ((apic->irq_delivery_mode != dest_LowestPrio) ?
95 HT_IRQ_LOW_MT_FIXED :
96 HT_IRQ_LOW_MT_ARBITRATED) |
97 HT_IRQ_LOW_IRQ_MASKED;
99 write_ht_irq_msg(irq, &msg);
101 irq_set_chip_and_handler_name(irq, &ht_irq_chip,
102 handle_edge_irq, "edge");
104 dev_dbg(&dev->dev, "irq %d for HT\n", irq);
106 return 0;