aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/host
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/host')
-rw-r--r--drivers/pci/host/pcie-designware.c49
1 files changed, 37 insertions, 12 deletions
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index e33b68be0391..61345a18a6d1 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -209,6 +209,25 @@ static int find_valid_pos0(struct pcie_port *pp, int msgvec, int pos, int *pos0)
209 return 0; 209 return 0;
210} 210}
211 211
212static void clear_irq_range(struct pcie_port *pp, unsigned int irq_base,
213 unsigned int nvec, unsigned int pos)
214{
215 unsigned int i, res, bit, val;
216
217 i = 0;
218 while (i < nvec) {
219 irq_set_msi_desc_off(irq_base, i, NULL);
220 clear_bit(pos + i, pp->msi_irq_in_use);
221 /* Disable corresponding interrupt on MSI interrupt controller */
222 res = ((pos + i) / 32) * 12;
223 bit = (pos + i) % 32;
224 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
225 val &= ~(1 << bit);
226 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
227 ++i;
228 }
229}
230
212static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos) 231static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
213{ 232{
214 int res, bit, irq, pos0, pos1, i; 233 int res, bit, irq, pos0, pos1, i;
@@ -242,11 +261,20 @@ static int assign_irq(int no_irqs, struct msi_desc *desc, int *pos)
242 if (!irq) 261 if (!irq)
243 goto no_valid_irq; 262 goto no_valid_irq;
244 263
264 /*
265 * irq_create_mapping (called from dw_pcie_host_init) pre-allocates
266 * descs so there is no need to allocate descs here. We can therefore
267 * assume that if irq_find_mapping above returns non-zero, then the
268 * descs are also successfully allocated.
269 */
270
245 i = 0; 271 i = 0;
246 while (i < no_irqs) { 272 while (i < no_irqs) {
273 if (irq_set_msi_desc_off(irq, i, desc) != 0) {
274 clear_irq_range(pp, irq, i, pos0);
275 goto no_valid_irq;
276 }
247 set_bit(pos0 + i, pp->msi_irq_in_use); 277 set_bit(pos0 + i, pp->msi_irq_in_use);
248 irq_alloc_descs((irq + i), (irq + i), 1, 0);
249 irq_set_msi_desc(irq + i, desc);
250 /*Enable corresponding interrupt in MSI interrupt controller */ 278 /*Enable corresponding interrupt in MSI interrupt controller */
251 res = ((pos0 + i) / 32) * 12; 279 res = ((pos0 + i) / 32) * 12;
252 bit = (pos0 + i) % 32; 280 bit = (pos0 + i) % 32;
@@ -266,7 +294,7 @@ no_valid_irq:
266 294
267static void clear_irq(unsigned int irq) 295static void clear_irq(unsigned int irq)
268{ 296{
269 int res, bit, val, pos; 297 unsigned int pos, nvec;
270 struct irq_desc *desc; 298 struct irq_desc *desc;
271 struct msi_desc *msi; 299 struct msi_desc *msi;
272 struct pcie_port *pp; 300 struct pcie_port *pp;
@@ -281,18 +309,15 @@ static void clear_irq(unsigned int irq)
281 return; 309 return;
282 } 310 }
283 311
312 /* undo what was done in assign_irq */
284 pos = data->hwirq; 313 pos = data->hwirq;
314 nvec = 1 << msi->msi_attrib.multiple;
285 315
286 irq_free_desc(irq); 316 clear_irq_range(pp, irq, nvec, pos);
287
288 clear_bit(pos, pp->msi_irq_in_use);
289 317
290 /* Disable corresponding interrupt on MSI interrupt controller */ 318 /* all irqs cleared; reset attributes */
291 res = (pos / 32) * 12; 319 msi->irq = 0;
292 bit = pos % 32; 320 msi->msi_attrib.multiple = 0;
293 dw_pcie_rd_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, &val);
294 val &= ~(1 << bit);
295 dw_pcie_wr_own_conf(pp, PCIE_MSI_INTR0_ENABLE + res, 4, val);
296} 321}
297 322
298static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev, 323static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,