firewire: ohci: add MSI support
authorClemens Ladisch <clemens@ladisch.de>
Sat, 5 Jun 2010 10:31:25 +0000 (12:31 +0200)
committerStefan Richter <stefanr@s5r6.in-berlin.de>
Wed, 9 Jun 2010 17:42:18 +0000 (19:42 +0200)
This patch adds support for message-signaled interrupts.

Any native PCI-Express OHCI controller should support MSI, but most are
just PCI cores behind a PCI-E/PCI bridge.  The only chips that are known
to claim to support MSI are the Lucent/Agere/LSI FW643 and the VIA
VT6315, none of which I have been able to test.

Due to the high level of trust I have in the competence of these and any
future chip makers, I thought it a good idea to add a disable-MSI quirk.

Signed-off-by: Clemens Ladisch <clemens@ladisch.de>

Tested Agere FW643 rev 07 [11c1:5901] and JMicron JMB381 [197b:2380].
Added a quirks list entry for JMB38X since it kept its count of MSI
events consistently at zero.

Signed-off-by: Stefan Richter <stefanr@s5r6.in-berlin.de>

drivers/firewire/ohci.c

index 9743a40..de5ff37 100644 (file)
@@ -231,12 +231,14 @@ static inline struct fw_ohci *fw_ohci(struct fw_card *card)
 
 static char ohci_driver_name[] = KBUILD_MODNAME;
 
+#define PCI_DEVICE_ID_JMICRON_JMB38X_FW        0x2380
 #define PCI_DEVICE_ID_TI_TSB12LV22     0x8009
 
 #define QUIRK_CYCLE_TIMER              1
 #define QUIRK_RESET_PACKET             2
 #define QUIRK_BE_HEADERS               4
 #define QUIRK_NO_1394A                 8
+#define QUIRK_NO_MSI                   16
 
 /* In case of multiple matches in ohci_quirks[], only the first one is used. */
 static const struct {
@@ -247,6 +249,7 @@ static const struct {
                                                            QUIRK_NO_1394A},
        {PCI_VENDOR_ID_TI,      PCI_ANY_ID,     QUIRK_RESET_PACKET},
        {PCI_VENDOR_ID_AL,      PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
+       {PCI_VENDOR_ID_JMICRON, PCI_DEVICE_ID_JMICRON_JMB38X_FW, QUIRK_NO_MSI},
        {PCI_VENDOR_ID_NEC,     PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
        {PCI_VENDOR_ID_VIA,     PCI_ANY_ID,     QUIRK_CYCLE_TIMER},
        {PCI_VENDOR_ID_APPLE,   PCI_DEVICE_ID_APPLE_UNI_N_FW, QUIRK_BE_HEADERS},
@@ -260,6 +263,7 @@ MODULE_PARM_DESC(quirks, "Chip quirks (default = 0"
        ", reset packet generation = "  __stringify(QUIRK_RESET_PACKET)
        ", AR/selfID endianess = "      __stringify(QUIRK_BE_HEADERS)
        ", no 1394a enhancements = "    __stringify(QUIRK_NO_1394A)
+       ", disable MSI = "              __stringify(QUIRK_NO_MSI)
        ")");
 
 #define OHCI_PARAM_DEBUG_AT_AR         1
@@ -1704,10 +1708,13 @@ static int ohci_enable(struct fw_card *card,
 
        reg_write(ohci, OHCI1394_AsReqFilterHiSet, 0x80000000);
 
+       if (!(ohci->quirks & QUIRK_NO_MSI))
+               pci_enable_msi(dev);
        if (request_irq(dev->irq, irq_handler,
-                       IRQF_SHARED, ohci_driver_name, ohci)) {
-               fw_error("Failed to allocate shared interrupt %d.\n",
-                        dev->irq);
+                       pci_dev_msi_enabled(dev) ? 0 : IRQF_SHARED,
+                       ohci_driver_name, ohci)) {
+               fw_error("Failed to allocate interrupt %d.\n", dev->irq);
+               pci_disable_msi(dev);
                dma_free_coherent(ohci->card.device, CONFIG_ROM_SIZE,
                                  ohci->config_rom, ohci->config_rom_bus);
                return -EIO;
@@ -2622,6 +2629,7 @@ static void pci_remove(struct pci_dev *dev)
        context_release(&ohci->at_response_ctx);
        kfree(ohci->it_context_list);
        kfree(ohci->ir_context_list);
+       pci_disable_msi(dev);
        pci_iounmap(dev, ohci->registers);
        pci_release_region(dev, 0);
        pci_disable_device(dev);
@@ -2639,6 +2647,7 @@ static int pci_suspend(struct pci_dev *dev, pm_message_t state)
 
        software_reset(ohci);
        free_irq(dev->irq, ohci);
+       pci_disable_msi(dev);
        err = pci_save_state(dev);
        if (err) {
                fw_error("pci_save_state failed\n");