aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2007-03-05 03:30:10 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-03-05 10:57:50 -0500
commitb1cbf4e4dddd708ba268c3a2bf38383a269d490a (patch)
treea04eaf9e80e3ad30d9d062bab3ea94fca2d29376 /drivers
parentf5f2b13129a6541debf8851bae843cbbf48298b7 (diff)
[PATCH] msi: fix up the msi enable/disable logic
enable/disable_msi_mode have several side effects which keeps them from being generally useful. So this patch replaces them with with two much more targeted functions: msi_set_enable and msix_set_enable. This patch makes pci_dev->msi_enabled and pci_dev->msix_enabled the definitive way to test if linux has enabled the msi capability, and has the appropriate msi data structures set up. This patch ensures that while writing the msi messages in save/restore and during device initialization we have the msi capability disabled so we don't get into races. The pci spec requires that we do not have the msi capability enabled and the msi messages unmasked while we write the messages. Completely disabling the capability is overkill but it is easy :) Care has been taken so we never have both a msi capability and intx enabled simultaneously. We haven't run into a problem yet but better safe then sorry. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Cc: Michael Ellerman <michael@ellerman.id.au> Cc: Paul Mackerras <paulus@samba.org> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/pci/msi.c144
1 files changed, 64 insertions, 80 deletions
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index fd1068b59b0c..c43e7d22e180 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -38,6 +38,36 @@ static int msi_cache_init(void)
38 return 0; 38 return 0;
39} 39}
40 40
41static void msi_set_enable(struct pci_dev *dev, int enable)
42{
43 int pos;
44 u16 control;
45
46 pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
47 if (pos) {
48 pci_read_config_word(dev, pos + PCI_MSI_FLAGS, &control);
49 control &= ~PCI_MSI_FLAGS_ENABLE;
50 if (enable)
51 control |= PCI_MSI_FLAGS_ENABLE;
52 pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
53 }
54}
55
56static void msix_set_enable(struct pci_dev *dev, int enable)
57{
58 int pos;
59 u16 control;
60
61 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
62 if (pos) {
63 pci_read_config_word(dev, pos + PCI_MSIX_FLAGS, &control);
64 control &= ~PCI_MSIX_FLAGS_ENABLE;
65 if (enable)
66 control |= PCI_MSIX_FLAGS_ENABLE;
67 pci_write_config_word(dev, pos + PCI_MSIX_FLAGS, control);
68 }
69}
70
41static void msi_set_mask_bit(unsigned int irq, int flag) 71static void msi_set_mask_bit(unsigned int irq, int flag)
42{ 72{
43 struct msi_desc *entry; 73 struct msi_desc *entry;
@@ -192,44 +222,6 @@ static struct msi_desc* alloc_msi_entry(void)
192 return entry; 222 return entry;
193} 223}
194 224
195static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
196{
197 u16 control;
198
199 pci_read_config_word(dev, msi_control_reg(pos), &control);
200 if (type == PCI_CAP_ID_MSI) {
201 /* Set enabled bits to single MSI & enable MSI_enable bit */
202 msi_enable(control, 1);
203 pci_write_config_word(dev, msi_control_reg(pos), control);
204 dev->msi_enabled = 1;
205 } else {
206 msix_enable(control);
207 pci_write_config_word(dev, msi_control_reg(pos), control);
208 dev->msix_enabled = 1;
209 }
210
211 pci_intx(dev, 0); /* disable intx */
212}
213
214static void disable_msi_mode(struct pci_dev *dev, int pos, int type)
215{
216 u16 control;
217
218 pci_read_config_word(dev, msi_control_reg(pos), &control);
219 if (type == PCI_CAP_ID_MSI) {
220 /* Set enabled bits to single MSI & enable MSI_enable bit */
221 msi_disable(control);
222 pci_write_config_word(dev, msi_control_reg(pos), control);
223 dev->msi_enabled = 0;
224 } else {
225 msix_disable(control);
226 pci_write_config_word(dev, msi_control_reg(pos), control);
227 dev->msix_enabled = 0;
228 }
229
230 pci_intx(dev, 1); /* enable intx */
231}
232
233#ifdef CONFIG_PM 225#ifdef CONFIG_PM
234static int __pci_save_msi_state(struct pci_dev *dev) 226static int __pci_save_msi_state(struct pci_dev *dev)
235{ 227{
@@ -238,12 +230,11 @@ static int __pci_save_msi_state(struct pci_dev *dev)
238 struct pci_cap_saved_state *save_state; 230 struct pci_cap_saved_state *save_state;
239 u32 *cap; 231 u32 *cap;
240 232
241 pos = pci_find_capability(dev, PCI_CAP_ID_MSI); 233 if (!dev->msi_enabled)
242 if (pos <= 0 || dev->no_msi)
243 return 0; 234 return 0;
244 235
245 pci_read_config_word(dev, msi_control_reg(pos), &control); 236 pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
246 if (!(control & PCI_MSI_FLAGS_ENABLE)) 237 if (pos <= 0)
247 return 0; 238 return 0;
248 239
249 save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5, 240 save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u32) * 5,
@@ -276,13 +267,18 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
276 struct pci_cap_saved_state *save_state; 267 struct pci_cap_saved_state *save_state;
277 u32 *cap; 268 u32 *cap;
278 269
270 if (!dev->msi_enabled)
271 return;
272
279 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI); 273 save_state = pci_find_saved_cap(dev, PCI_CAP_ID_MSI);
280 pos = pci_find_capability(dev, PCI_CAP_ID_MSI); 274 pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
281 if (!save_state || pos <= 0) 275 if (!save_state || pos <= 0)
282 return; 276 return;
283 cap = &save_state->data[0]; 277 cap = &save_state->data[0];
284 278
279 pci_intx(dev, 0); /* disable intx */
285 control = cap[i++] >> 16; 280 control = cap[i++] >> 16;
281 msi_set_enable(dev, 0);
286 pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]); 282 pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_LO, cap[i++]);
287 if (control & PCI_MSI_FLAGS_64BIT) { 283 if (control & PCI_MSI_FLAGS_64BIT) {
288 pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]); 284 pci_write_config_dword(dev, pos + PCI_MSI_ADDRESS_HI, cap[i++]);
@@ -292,7 +288,6 @@ static void __pci_restore_msi_state(struct pci_dev *dev)
292 if (control & PCI_MSI_FLAGS_MASKBIT) 288 if (control & PCI_MSI_FLAGS_MASKBIT)
293 pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]); 289 pci_write_config_dword(dev, pos + PCI_MSI_MASK_BIT, cap[i++]);
294 pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control); 290 pci_write_config_word(dev, pos + PCI_MSI_FLAGS, control);
295 enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
296 pci_remove_saved_cap(save_state); 291 pci_remove_saved_cap(save_state);
297 kfree(save_state); 292 kfree(save_state);
298} 293}
@@ -308,13 +303,11 @@ static int __pci_save_msix_state(struct pci_dev *dev)
308 return 0; 303 return 0;
309 304
310 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); 305 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
311 if (pos <= 0 || dev->no_msi) 306 if (pos <= 0)
312 return 0; 307 return 0;
313 308
314 /* save the capability */ 309 /* save the capability */
315 pci_read_config_word(dev, msi_control_reg(pos), &control); 310 pci_read_config_word(dev, msi_control_reg(pos), &control);
316 if (!(control & PCI_MSIX_FLAGS_ENABLE))
317 return 0;
318 save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16), 311 save_state = kzalloc(sizeof(struct pci_cap_saved_state) + sizeof(u16),
319 GFP_KERNEL); 312 GFP_KERNEL);
320 if (!save_state) { 313 if (!save_state) {
@@ -376,6 +369,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
376 return; 369 return;
377 370
378 /* route the table */ 371 /* route the table */
372 pci_intx(dev, 0); /* disable intx */
373 msix_set_enable(dev, 0);
379 irq = head = dev->first_msi_irq; 374 irq = head = dev->first_msi_irq;
380 while (head != tail) { 375 while (head != tail) {
381 entry = get_irq_msi(irq); 376 entry = get_irq_msi(irq);
@@ -386,7 +381,6 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
386 } 381 }
387 382
388 pci_write_config_word(dev, msi_control_reg(pos), save); 383 pci_write_config_word(dev, msi_control_reg(pos), save);
389 enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
390} 384}
391 385
392void pci_restore_msi_state(struct pci_dev *dev) 386void pci_restore_msi_state(struct pci_dev *dev)
@@ -411,6 +405,8 @@ static int msi_capability_init(struct pci_dev *dev)
411 int pos, irq; 405 int pos, irq;
412 u16 control; 406 u16 control;
413 407
408 msi_set_enable(dev, 0); /* Ensure msi is disabled as I set it up */
409
414 pos = pci_find_capability(dev, PCI_CAP_ID_MSI); 410 pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
415 pci_read_config_word(dev, msi_control_reg(pos), &control); 411 pci_read_config_word(dev, msi_control_reg(pos), &control);
416 /* MSI Entry Initialization */ 412 /* MSI Entry Initialization */
@@ -454,7 +450,9 @@ static int msi_capability_init(struct pci_dev *dev)
454 set_irq_msi(irq, entry); 450 set_irq_msi(irq, entry);
455 451
456 /* Set MSI enabled bits */ 452 /* Set MSI enabled bits */
457 enable_msi_mode(dev, pos, PCI_CAP_ID_MSI); 453 pci_intx(dev, 0); /* disable intx */
454 msi_set_enable(dev, 1);
455 dev->msi_enabled = 1;
458 456
459 dev->irq = irq; 457 dev->irq = irq;
460 return 0; 458 return 0;
@@ -481,6 +479,8 @@ static int msix_capability_init(struct pci_dev *dev,
481 u8 bir; 479 u8 bir;
482 void __iomem *base; 480 void __iomem *base;
483 481
482 msix_set_enable(dev, 0);/* Ensure msix is disabled as I set it up */
483
484 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); 484 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
485 /* Request & Map MSI-X table region */ 485 /* Request & Map MSI-X table region */
486 pci_read_config_word(dev, msi_control_reg(pos), &control); 486 pci_read_config_word(dev, msi_control_reg(pos), &control);
@@ -549,7 +549,9 @@ static int msix_capability_init(struct pci_dev *dev,
549 } 549 }
550 dev->first_msi_irq = entries[0].vector; 550 dev->first_msi_irq = entries[0].vector;
551 /* Set MSI-X enabled bits */ 551 /* Set MSI-X enabled bits */
552 enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX); 552 pci_intx(dev, 0); /* disable intx */
553 msix_set_enable(dev, 1);
554 dev->msix_enabled = 1;
553 555
554 return 0; 556 return 0;
555} 557}
@@ -611,12 +613,11 @@ int pci_enable_msi(struct pci_dev* dev)
611 WARN_ON(!!dev->msi_enabled); 613 WARN_ON(!!dev->msi_enabled);
612 614
613 /* Check whether driver already requested for MSI-X irqs */ 615 /* Check whether driver already requested for MSI-X irqs */
614 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); 616 if (dev->msix_enabled) {
615 if (pos > 0 && dev->msix_enabled) { 617 printk(KERN_INFO "PCI: %s: Can't enable MSI. "
616 printk(KERN_INFO "PCI: %s: Can't enable MSI. " 618 "Device already has MSI-X enabled\n",
617 "Device already has MSI-X enabled\n", 619 pci_name(dev));
618 pci_name(dev)); 620 return -EINVAL;
619 return -EINVAL;
620 } 621 }
621 status = msi_capability_init(dev); 622 status = msi_capability_init(dev);
622 return status; 623 return status;
@@ -625,8 +626,7 @@ int pci_enable_msi(struct pci_dev* dev)
625void pci_disable_msi(struct pci_dev* dev) 626void pci_disable_msi(struct pci_dev* dev)
626{ 627{
627 struct msi_desc *entry; 628 struct msi_desc *entry;
628 int pos, default_irq; 629 int default_irq;
629 u16 control;
630 630
631 if (!pci_msi_enable) 631 if (!pci_msi_enable)
632 return; 632 return;
@@ -636,16 +636,9 @@ void pci_disable_msi(struct pci_dev* dev)
636 if (!dev->msi_enabled) 636 if (!dev->msi_enabled)
637 return; 637 return;
638 638
639 pos = pci_find_capability(dev, PCI_CAP_ID_MSI); 639 msi_set_enable(dev, 0);
640 if (!pos) 640 pci_intx(dev, 1); /* enable intx */
641 return; 641 dev->msi_enabled = 0;
642
643 pci_read_config_word(dev, msi_control_reg(pos), &control);
644 if (!(control & PCI_MSI_FLAGS_ENABLE))
645 return;
646
647
648 disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
649 642
650 entry = get_irq_msi(dev->first_msi_irq); 643 entry = get_irq_msi(dev->first_msi_irq);
651 if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) { 644 if (!entry || !entry->dev || entry->msi_attrib.type != PCI_CAP_ID_MSI) {
@@ -746,8 +739,7 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
746 WARN_ON(!!dev->msix_enabled); 739 WARN_ON(!!dev->msix_enabled);
747 740
748 /* Check whether driver already requested for MSI irq */ 741 /* Check whether driver already requested for MSI irq */
749 if (pci_find_capability(dev, PCI_CAP_ID_MSI) > 0 && 742 if (dev->msi_enabled) {
750 dev->msi_enabled) {
751 printk(KERN_INFO "PCI: %s: Can't enable MSI-X. " 743 printk(KERN_INFO "PCI: %s: Can't enable MSI-X. "
752 "Device already has an MSI irq assigned\n", 744 "Device already has an MSI irq assigned\n",
753 pci_name(dev)); 745 pci_name(dev));
@@ -760,8 +752,6 @@ int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
760void pci_disable_msix(struct pci_dev* dev) 752void pci_disable_msix(struct pci_dev* dev)
761{ 753{
762 int irq, head, tail = 0, warning = 0; 754 int irq, head, tail = 0, warning = 0;
763 int pos;
764 u16 control;
765 755
766 if (!pci_msi_enable) 756 if (!pci_msi_enable)
767 return; 757 return;
@@ -771,15 +761,9 @@ void pci_disable_msix(struct pci_dev* dev)
771 if (!dev->msix_enabled) 761 if (!dev->msix_enabled)
772 return; 762 return;
773 763
774 pos = pci_find_capability(dev, PCI_CAP_ID_MSIX); 764 msix_set_enable(dev, 0);
775 if (!pos) 765 pci_intx(dev, 1); /* enable intx */
776 return; 766 dev->msix_enabled = 0;
777
778 pci_read_config_word(dev, msi_control_reg(pos), &control);
779 if (!(control & PCI_MSIX_FLAGS_ENABLE))
780 return;
781
782 disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
783 767
784 irq = head = dev->first_msi_irq; 768 irq = head = dev->first_msi_irq;
785 while (head != tail) { 769 while (head != tail) {