|
3 | 3 | *
|
4 | 4 | * Copyright (C) 1997, 1998, 1999, 2000, 2009 Ingo Molnar, Hajnalka Szabo
|
5 | 5 | * Moved from arch/x86/kernel/apic/io_apic.c.
|
| 6 | + |
| 7 | + * Convert to hierarchical irqdomain |
6 | 8 | *
|
7 | 9 | * This program is free software; you can redistribute it and/or modify
|
8 | 10 | * it under the terms of the GNU General Public License version 2 as
|
|
21 | 23 | #include <asm/apic.h>
|
22 | 24 | #include <asm/irq_remapping.h>
|
23 | 25 |
|
| 26 | +static struct irq_domain *msi_default_domain; |
| 27 | + |
24 | 28 | void native_compose_msi_msg(struct pci_dev *pdev,
|
25 | 29 | unsigned int irq, unsigned int dest,
|
26 | 30 | struct msi_msg *msg, u8 hpet_id)
|
@@ -114,102 +118,107 @@ static int msi_compose_msg(struct pci_dev *pdev, unsigned int irq,
|
114 | 118 | return 0;
|
115 | 119 | }
|
116 | 120 |
|
117 |
| -static int |
118 |
| -msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force) |
119 |
| -{ |
120 |
| - struct irq_cfg *cfg = irqd_cfg(data); |
121 |
| - struct msi_msg msg; |
122 |
| - unsigned int dest; |
123 |
| - int ret; |
124 |
| - |
125 |
| - ret = apic_set_affinity(data, mask, &dest); |
126 |
| - if (ret) |
127 |
| - return ret; |
128 |
| - |
129 |
| - __get_cached_msi_msg(data->msi_desc, &msg); |
130 |
| - |
131 |
| - msg.data &= ~MSI_DATA_VECTOR_MASK; |
132 |
| - msg.data |= MSI_DATA_VECTOR(cfg->vector); |
133 |
| - msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK; |
134 |
| - msg.address_lo |= MSI_ADDR_DEST_ID(dest); |
135 |
| - |
136 |
| - __pci_write_msi_msg(data->msi_desc, &msg); |
137 |
| - |
138 |
| - return IRQ_SET_MASK_OK_NOCOPY; |
139 |
| -} |
140 |
| - |
141 | 121 | /*
|
142 | 122 | * IRQ Chip for MSI PCI/PCI-X/PCI-Express Devices,
|
143 | 123 | * which implement the MSI or MSI-X Capability Structure.
|
144 | 124 | */
|
145 |
| -static struct irq_chip msi_chip = { |
| 125 | +static struct irq_chip pci_msi_controller = { |
146 | 126 | .name = "PCI-MSI",
|
147 | 127 | .irq_unmask = pci_msi_unmask_irq,
|
148 | 128 | .irq_mask = pci_msi_mask_irq,
|
149 |
| - .irq_ack = apic_ack_edge, |
150 |
| - .irq_set_affinity = msi_set_affinity, |
151 |
| - .irq_retrigger = apic_retrigger_irq, |
| 129 | + .irq_ack = irq_chip_ack_parent, |
| 130 | + .irq_set_affinity = msi_domain_set_affinity, |
| 131 | + .irq_retrigger = irq_chip_retrigger_hierarchy, |
| 132 | + .irq_print_chip = irq_remapping_print_chip, |
| 133 | + .irq_compose_msi_msg = irq_msi_compose_msg, |
| 134 | + .irq_write_msi_msg = pci_msi_domain_write_msg, |
152 | 135 | .flags = IRQCHIP_SKIP_SET_WAKE,
|
153 | 136 | };
|
154 | 137 |
|
155 |
| -int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, |
156 |
| - unsigned int irq_base, unsigned int irq_offset) |
| 138 | +int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
157 | 139 | {
|
158 |
| - struct irq_chip *chip = &msi_chip; |
159 |
| - struct msi_msg msg; |
160 |
| - unsigned int irq = irq_base + irq_offset; |
161 |
| - int ret; |
| 140 | + struct irq_domain *domain; |
| 141 | + struct irq_alloc_info info; |
162 | 142 |
|
163 |
| - ret = msi_compose_msg(dev, irq, &msg, -1); |
164 |
| - if (ret < 0) |
165 |
| - return ret; |
| 143 | + init_irq_alloc_info(&info, NULL); |
| 144 | + info.type = X86_IRQ_ALLOC_TYPE_MSI; |
| 145 | + info.msi_dev = dev; |
166 | 146 |
|
167 |
| - irq_set_msi_desc_off(irq_base, irq_offset, msidesc); |
| 147 | + domain = irq_remapping_get_irq_domain(&info); |
| 148 | + if (domain == NULL) |
| 149 | + domain = msi_default_domain; |
| 150 | + if (domain == NULL) |
| 151 | + return -ENOSYS; |
168 | 152 |
|
169 |
| - /* |
170 |
| - * MSI-X message is written per-IRQ, the offset is always 0. |
171 |
| - * MSI message denotes a contiguous group of IRQs, written for 0th IRQ. |
172 |
| - */ |
173 |
| - if (!irq_offset) |
174 |
| - pci_write_msi_msg(irq, &msg); |
| 153 | + return pci_msi_domain_alloc_irqs(domain, dev, nvec, type); |
| 154 | +} |
175 | 155 |
|
176 |
| - setup_remapped_irq(irq, irq_cfg(irq), chip); |
| 156 | +void native_teardown_msi_irq(unsigned int irq) |
| 157 | +{ |
| 158 | + irq_domain_free_irqs(irq, 1); |
| 159 | +} |
177 | 160 |
|
178 |
| - irq_set_chip_and_handler_name(irq, chip, handle_edge_irq, "edge"); |
| 161 | +static irq_hw_number_t pci_msi_get_hwirq(struct msi_domain_info *info, |
| 162 | + msi_alloc_info_t *arg) |
| 163 | +{ |
| 164 | + return arg->msi_hwirq; |
| 165 | +} |
179 | 166 |
|
180 |
| - dev_dbg(&dev->dev, "irq %d for MSI/MSI-X\n", irq); |
| 167 | +static int pci_msi_prepare(struct irq_domain *domain, struct device *dev, |
| 168 | + int nvec, msi_alloc_info_t *arg) |
| 169 | +{ |
| 170 | + struct pci_dev *pdev = to_pci_dev(dev); |
| 171 | + struct msi_desc *desc = first_pci_msi_entry(pdev); |
| 172 | + |
| 173 | + init_irq_alloc_info(arg, NULL); |
| 174 | + arg->msi_dev = pdev; |
| 175 | + if (desc->msi_attrib.is_msix) { |
| 176 | + arg->type = X86_IRQ_ALLOC_TYPE_MSIX; |
| 177 | + } else { |
| 178 | + arg->type = X86_IRQ_ALLOC_TYPE_MSI; |
| 179 | + arg->flags |= X86_IRQ_ALLOC_CONTIGUOUS_VECTORS; |
| 180 | + } |
181 | 181 |
|
182 | 182 | return 0;
|
183 | 183 | }
|
184 | 184 |
|
185 |
| -int native_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) |
| 185 | +static void pci_msi_set_desc(msi_alloc_info_t *arg, struct msi_desc *desc) |
186 | 186 | {
|
187 |
| - struct msi_desc *msidesc; |
188 |
| - int irq, ret; |
| 187 | + arg->msi_hwirq = pci_msi_domain_calc_hwirq(arg->msi_dev, desc); |
| 188 | +} |
189 | 189 |
|
190 |
| - /* Multiple MSI vectors only supported with interrupt remapping */ |
191 |
| - if (type == PCI_CAP_ID_MSI && nvec > 1) |
192 |
| - return 1; |
| 190 | +static struct msi_domain_ops pci_msi_domain_ops = { |
| 191 | + .get_hwirq = pci_msi_get_hwirq, |
| 192 | + .msi_prepare = pci_msi_prepare, |
| 193 | + .set_desc = pci_msi_set_desc, |
| 194 | +}; |
193 | 195 |
|
194 |
| - list_for_each_entry(msidesc, &dev->msi_list, list) { |
195 |
| - irq = irq_domain_alloc_irqs(NULL, 1, NUMA_NO_NODE, NULL); |
196 |
| - if (irq <= 0) |
197 |
| - return -ENOSPC; |
| 196 | +static struct msi_domain_info pci_msi_domain_info = { |
| 197 | + .flags = MSI_FLAG_USE_DEF_DOM_OPS | MSI_FLAG_USE_DEF_CHIP_OPS | |
| 198 | + MSI_FLAG_MULTI_PCI_MSI | MSI_FLAG_PCI_MSIX, |
| 199 | + .ops = &pci_msi_domain_ops, |
| 200 | + .chip = &pci_msi_controller, |
| 201 | + .handler = handle_edge_irq, |
| 202 | + .handler_name = "edge", |
| 203 | +}; |
198 | 204 |
|
199 |
| - ret = setup_msi_irq(dev, msidesc, irq, 0); |
200 |
| - if (ret < 0) { |
201 |
| - irq_domain_free_irqs(irq, 1); |
202 |
| - return ret; |
203 |
| - } |
| 205 | +void arch_init_msi_domain(struct irq_domain *parent) |
| 206 | +{ |
| 207 | + if (disable_apic) |
| 208 | + return; |
204 | 209 |
|
205 |
| - } |
206 |
| - return 0; |
| 210 | + msi_default_domain = pci_msi_create_irq_domain(NULL, |
| 211 | + &pci_msi_domain_info, parent); |
| 212 | + if (!msi_default_domain) |
| 213 | + pr_warn("failed to initialize irqdomain for MSI/MSI-x.\n"); |
207 | 214 | }
|
208 | 215 |
|
209 |
| -void native_teardown_msi_irq(unsigned int irq) |
| 216 | +#ifdef CONFIG_IRQ_REMAP |
| 217 | +struct irq_domain *arch_create_msi_irq_domain(struct irq_domain *parent) |
210 | 218 | {
|
211 |
| - irq_domain_free_irqs(irq, 1); |
| 219 | + return msi_create_irq_domain(NULL, &pci_msi_domain_info, parent); |
212 | 220 | }
|
| 221 | +#endif |
213 | 222 |
|
214 | 223 | #ifdef CONFIG_DMAR_TABLE
|
215 | 224 | static int
|
|
0 commit comments