aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/msi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/pci/msi.c')
-rw-r--r--drivers/pci/msi.c155
1 files changed, 75 insertions, 80 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index fcde04df6dfe..adcc78242571 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -105,17 +105,14 @@ static inline __attribute_const__ u32 msi_mask(unsigned x)
105 return (1 << (1 << x)) - 1; 105 return (1 << (1 << x)) - 1;
106} 106}
107 107
108static void msix_flush_writes(struct irq_desc *desc) 108static inline __attribute_const__ u32 msi_capable_mask(u16 control)
109{ 109{
110 struct msi_desc *entry; 110 return msi_mask((control >> 1) & 7);
111}
111 112
112 entry = get_irq_desc_msi(desc); 113static inline __attribute_const__ u32 msi_enabled_mask(u16 control)
113 BUG_ON(!entry); 114{
114 if (entry->msi_attrib.is_msix) { 115 return msi_mask((control >> 4) & 7);
115 int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
116 PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
117 readl(entry->mask_base + offset);
118 }
119} 116}
120 117
121/* 118/*
@@ -127,32 +124,57 @@ static void msix_flush_writes(struct irq_desc *desc)
127 * Returns 1 if it succeeded in masking the interrupt and 0 if the device 124 * Returns 1 if it succeeded in masking the interrupt and 0 if the device
128 * doesn't support MSI masking. 125 * doesn't support MSI masking.
129 */ 126 */
130static int msi_set_mask_bits(struct irq_desc *desc, u32 mask, u32 flag) 127static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
131{ 128{
132 struct msi_desc *entry; 129 u32 mask_bits = desc->masked;
133 130
134 entry = get_irq_desc_msi(desc); 131 if (!desc->msi_attrib.maskbit)
135 BUG_ON(!entry); 132 return;
136 if (entry->msi_attrib.is_msix) { 133
137 int offset = entry->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE + 134 mask_bits &= ~mask;
138 PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET; 135 mask_bits |= flag;
139 writel(flag, entry->mask_base + offset); 136 pci_write_config_dword(desc->dev, desc->mask_pos, mask_bits);
140 readl(entry->mask_base + offset); 137 desc->masked = mask_bits;
141 } else { 138}
142 int pos; 139
143 u32 mask_bits; 140/*
141 * This internal function does not flush PCI writes to the device.
142 * All users must ensure that they read from the device before either
143 * assuming that the device state is up to date, or returning out of this
144 * file. This saves a few milliseconds when initialising devices with lots
145 * of MSI-X interrupts.
146 */
147static void msix_mask_irq(struct msi_desc *desc, u32 flag)
148{
149 u32 mask_bits = desc->masked;
150 unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
151 PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET;
152 mask_bits &= ~1;
153 mask_bits |= flag;
154 writel(mask_bits, desc->mask_base + offset);
155 desc->masked = mask_bits;
156}
144 157
145 if (!entry->msi_attrib.maskbit) 158static void msi_set_mask_bit(unsigned irq, u32 flag)
146 return 0; 159{
160 struct msi_desc *desc = get_irq_msi(irq);
147 161
148 pos = entry->mask_pos; 162 if (desc->msi_attrib.is_msix) {
149 pci_read_config_dword(entry->dev, pos, &mask_bits); 163 msix_mask_irq(desc, flag);
150 mask_bits &= ~mask; 164 readl(desc->mask_base); /* Flush write to device */
151 mask_bits |= flag & mask; 165 } else {
152 pci_write_config_dword(entry->dev, pos, mask_bits); 166 msi_mask_irq(desc, 1, flag);
153 } 167 }
154 entry->msi_attrib.masked = !!flag; 168}
155 return 1; 169
170void mask_msi_irq(unsigned int irq)
171{
172 msi_set_mask_bit(irq, 1);
173}
174
175void unmask_msi_irq(unsigned int irq)
176{
177 msi_set_mask_bit(irq, 0);
156} 178}
157 179
158void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg) 180void read_msi_msg_desc(struct irq_desc *desc, struct msi_msg *msg)
@@ -230,22 +252,6 @@ void write_msi_msg(unsigned int irq, struct msi_msg *msg)
230 write_msi_msg_desc(desc, msg); 252 write_msi_msg_desc(desc, msg);
231} 253}
232 254
233void mask_msi_irq(unsigned int irq)
234{
235 struct irq_desc *desc = irq_to_desc(irq);
236
237 msi_set_mask_bits(desc, 1, 1);
238 msix_flush_writes(desc);
239}
240
241void unmask_msi_irq(unsigned int irq)
242{
243 struct irq_desc *desc = irq_to_desc(irq);
244
245 msi_set_mask_bits(desc, 1, 0);
246 msix_flush_writes(desc);
247}
248
249static int msi_free_irqs(struct pci_dev* dev); 255static int msi_free_irqs(struct pci_dev* dev);
250 256
251static struct msi_desc *alloc_msi_entry(struct pci_dev *dev) 257static struct msi_desc *alloc_msi_entry(struct pci_dev *dev)
@@ -281,13 +287,9 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
281 pci_intx_for_msi(dev, 0); 287 pci_intx_for_msi(dev, 0);
282 msi_set_enable(dev, 0); 288 msi_set_enable(dev, 0);
283 write_msi_msg(dev->irq, &entry->msg); 289 write_msi_msg(dev->irq, &entry->msg);
284 if (entry->msi_attrib.maskbit) {
285 struct irq_desc *desc = irq_to_desc(dev->irq);
286 msi_set_mask_bits(desc, entry->msi_attrib.maskbits_mask,
287 entry->msi_attrib.masked);
288 }
289 290
290 pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control); 291 pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
292 msi_mask_irq(entry, msi_capable_mask(control), entry->masked);
291 control &= ~PCI_MSI_FLAGS_QSIZE; 293 control &= ~PCI_MSI_FLAGS_QSIZE;
292 control |= PCI_MSI_FLAGS_ENABLE; 294 control |= PCI_MSI_FLAGS_ENABLE;
293 pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); 295 pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
@@ -307,9 +309,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
307 msix_set_enable(dev, 0); 309 msix_set_enable(dev, 0);
308 310
309 list_for_each_entry(entry, &dev->msi_list, list) { 311 list_for_each_entry(entry, &dev->msi_list, list) {
310 struct irq_desc *desc = irq_to_desc(entry->irq);
311 write_msi_msg(entry->irq, &entry->msg); 312 write_msi_msg(entry->irq, &entry->msg);
312 msi_set_mask_bits(desc, 1, entry->msi_attrib.masked); 313 msix_mask_irq(entry, entry->masked);
313 } 314 }
314 315
315 BUG_ON(list_empty(&dev->msi_list)); 316 BUG_ON(list_empty(&dev->msi_list));
@@ -342,6 +343,7 @@ static int msi_capability_init(struct pci_dev *dev)
342 struct msi_desc *entry; 343 struct msi_desc *entry;
343 int pos, ret; 344 int pos, ret;
344 u16 control; 345 u16 control;
346 unsigned mask;
345 347
346 msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */ 348 msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */
347 349
@@ -356,21 +358,16 @@ static int msi_capability_init(struct pci_dev *dev)
356 entry->msi_attrib.is_64 = is_64bit_address(control); 358 entry->msi_attrib.is_64 = is_64bit_address(control);
357 entry->msi_attrib.entry_nr = 0; 359 entry->msi_attrib.entry_nr = 0;
358 entry->msi_attrib.maskbit = is_mask_bit_support(control); 360 entry->msi_attrib.maskbit = is_mask_bit_support(control);
359 entry->msi_attrib.masked = 1;
360 entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */ 361 entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
361 entry->msi_attrib.pos = pos; 362 entry->msi_attrib.pos = pos;
362 if (entry->msi_attrib.maskbit) { 363
363 unsigned int base, maskbits, temp; 364 entry->mask_pos = msi_mask_bits_reg(pos, entry->msi_attrib.is_64);
364 365 /* All MSIs are unmasked by default, Mask them all */
365 base = msi_mask_bits_reg(pos, entry->msi_attrib.is_64); 366 if (entry->msi_attrib.maskbit)
366 entry->mask_pos = base; 367 pci_read_config_dword(dev, entry->mask_pos, &entry->masked);
367 /* All MSIs are unmasked by default, Mask them all */ 368 mask = msi_capable_mask(control);
368 pci_read_config_dword(dev, base, &maskbits); 369 msi_mask_irq(entry, mask, mask);
369 temp = msi_mask((control & PCI_MSI_FLAGS_QMASK) >> 1); 370
370 maskbits |= temp;
371 pci_write_config_dword(dev, base, maskbits);
372 entry->msi_attrib.maskbits_mask = temp;
373 }
374 list_add_tail(&entry->list, &dev->msi_list); 371 list_add_tail(&entry->list, &dev->msi_list);
375 372
376 /* Configure MSI capability structure */ 373 /* Configure MSI capability structure */
@@ -435,11 +432,12 @@ static int msix_capability_init(struct pci_dev *dev,
435 entry->msi_attrib.is_msix = 1; 432 entry->msi_attrib.is_msix = 1;
436 entry->msi_attrib.is_64 = 1; 433 entry->msi_attrib.is_64 = 1;
437 entry->msi_attrib.entry_nr = j; 434 entry->msi_attrib.entry_nr = j;
438 entry->msi_attrib.maskbit = 1;
439 entry->msi_attrib.masked = 1;
440 entry->msi_attrib.default_irq = dev->irq; 435 entry->msi_attrib.default_irq = dev->irq;
441 entry->msi_attrib.pos = pos; 436 entry->msi_attrib.pos = pos;
442 entry->mask_base = base; 437 entry->mask_base = base;
438 entry->masked = readl(base + j * PCI_MSIX_ENTRY_SIZE +
439 PCI_MSIX_ENTRY_VECTOR_CTRL_OFFSET);
440 msix_mask_irq(entry, 1);
443 441
444 list_add_tail(&entry->list, &dev->msi_list); 442 list_add_tail(&entry->list, &dev->msi_list);
445 } 443 }
@@ -556,9 +554,11 @@ int pci_enable_msi(struct pci_dev* dev)
556} 554}
557EXPORT_SYMBOL(pci_enable_msi); 555EXPORT_SYMBOL(pci_enable_msi);
558 556
559void pci_msi_shutdown(struct pci_dev* dev) 557void pci_msi_shutdown(struct pci_dev *dev)
560{ 558{
561 struct msi_desc *entry; 559 struct msi_desc *desc;
560 u32 mask;
561 u16 ctrl;
562 562
563 if (!pci_msi_enable || !dev || !dev->msi_enabled) 563 if (!pci_msi_enable || !dev || !dev->msi_enabled)
564 return; 564 return;
@@ -568,18 +568,13 @@ void pci_msi_shutdown(struct pci_dev* dev)
568 dev->msi_enabled = 0; 568 dev->msi_enabled = 0;
569 569
570 BUG_ON(list_empty(&dev->msi_list)); 570 BUG_ON(list_empty(&dev->msi_list));
571 entry = list_entry(dev->msi_list.next, struct msi_desc, list); 571 desc = list_first_entry(&dev->msi_list, struct msi_desc, list);
572 /* Return the the pci reset with msi irqs unmasked */ 572 pci_read_config_word(dev, desc->msi_attrib.pos + PCI_MSI_FLAGS, &ctrl);
573 if (entry->msi_attrib.maskbit) { 573 mask = msi_capable_mask(ctrl);
574 u32 mask = entry->msi_attrib.maskbits_mask; 574 msi_mask_irq(desc, mask, ~mask);
575 struct irq_desc *desc = irq_to_desc(dev->irq);
576 msi_set_mask_bits(desc, mask, ~mask);
577 }
578 if (entry->msi_attrib.is_msix)
579 return;
580 575
581 /* Restore dev->irq to its default pin-assertion irq */ 576 /* Restore dev->irq to its default pin-assertion irq */
582 dev->irq = entry->msi_attrib.default_irq; 577 dev->irq = desc->msi_attrib.default_irq;
583} 578}
584 579
585void pci_disable_msi(struct pci_dev* dev) 580void pci_disable_msi(struct pci_dev* dev)