diff options
Diffstat (limited to 'drivers/pci')
-rw-r--r-- | drivers/pci/msi.c | 144 |
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 | ||
41 | static 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 | |||
56 | static 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 | |||
41 | static void msi_set_mask_bit(unsigned int irq, int flag) | 71 | static 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 | ||
195 | static 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 | |||
214 | static 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 |
234 | static int __pci_save_msi_state(struct pci_dev *dev) | 226 | static 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 | ||
392 | void pci_restore_msi_state(struct pci_dev *dev) | 386 | void 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) | |||
625 | void pci_disable_msi(struct pci_dev* dev) | 626 | void 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) | |||
760 | void pci_disable_msix(struct pci_dev* dev) | 752 | void 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) { |