pccard: configure CLS on attach
authorTejun Heo <tj@kernel.org>
Tue, 22 Sep 2009 08:34:48 +0000 (17:34 +0900)
committerJesse Barnes <jbarnes@virtuousgeek.org>
Wed, 4 Nov 2009 16:47:11 +0000 (08:47 -0800)
For non hotplug PCI devices, the system firmware usually configures
CLS correctly.  For pccard devices system firmware can't do it and
Linux PCI layer doesn't do it either.  Unfortunately this leads to
poor performance for certain devices (sata_sil).  Unless MWI, which
requires separate configuration, is to be used, CLS doesn't affect
correctness, so the configuration should be harmless.

This patch makes pci_set_cacheline_size() always built and export it
and make pccard call it during attach.

Please note that some other PCI hotplug drivers (shpchp and pciehp)
also configure CLS on hotplug.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: Daniel Ritz <daniel.ritz@gmx.ch>
Cc: Dominik Brodowski <linux@dominikbrodowski.net>
Cc: Greg KH <greg@kroah.com>
Cc: Kenji Kaneshige <kaneshige.kenji@jp.fujitsu.com>
Cc: Axel Birndt <towerlexa@gmx.de>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
drivers/pci/pci.c
drivers/pcmcia/cardbus.c
include/linux/pci.h

index 01337b7a215f6560c54715adc85fe02d5454d4c5..d1afbae5b1fbb190fc92a292c8c27aa056fb8e82 100644 (file)
@@ -1875,23 +1875,6 @@ void pci_clear_master(struct pci_dev *dev)
        __pci_set_master(dev, false);
 }
 
-#ifdef PCI_DISABLE_MWI
-int pci_set_mwi(struct pci_dev *dev)
-{
-       return 0;
-}
-
-int pci_try_set_mwi(struct pci_dev *dev)
-{
-       return 0;
-}
-
-void pci_clear_mwi(struct pci_dev *dev)
-{
-}
-
-#else
-
 /**
  * pci_set_cacheline_size - ensure the CACHE_LINE_SIZE register is programmed
  * @dev: the PCI device for which MWI is to be enabled
@@ -1902,13 +1885,12 @@ void pci_clear_mwi(struct pci_dev *dev)
  *
  * RETURNS: An appropriate -ERRNO error value on error, or zero for success.
  */
-static int
-pci_set_cacheline_size(struct pci_dev *dev)
+int pci_set_cacheline_size(struct pci_dev *dev)
 {
        u8 cacheline_size;
 
        if (!pci_cache_line_size)
-               return -EINVAL;         /* The system doesn't support MWI. */
+               return -EINVAL;
 
        /* Validate current setting: the PCI_CACHE_LINE_SIZE must be
           equal to or multiple of the right value. */
@@ -1929,6 +1911,24 @@ pci_set_cacheline_size(struct pci_dev *dev)
 
        return -EINVAL;
 }
+EXPORT_SYMBOL_GPL(pci_set_cacheline_size);
+
+#ifdef PCI_DISABLE_MWI
+int pci_set_mwi(struct pci_dev *dev)
+{
+       return 0;
+}
+
+int pci_try_set_mwi(struct pci_dev *dev)
+{
+       return 0;
+}
+
+void pci_clear_mwi(struct pci_dev *dev)
+{
+}
+
+#else
 
 /**
  * pci_set_mwi - enables memory-write-invalidate PCI transaction
index db77e1f3309a087a6c93c06d251284981df80311..98789c031a7cc3359e652c450652f0c07c4c0164 100644 (file)
@@ -184,26 +184,33 @@ fail:
     
 =====================================================================*/
 
-/*
- * Since there is only one interrupt available to CardBus
- * devices, all devices downstream of this device must
- * be using this IRQ.
- */
-static void cardbus_assign_irqs(struct pci_bus *bus, int irq)
+static void cardbus_config_irq_and_cls(struct pci_bus *bus, int irq)
 {
        struct pci_dev *dev;
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
                u8 irq_pin;
 
+               /*
+                * Since there is only one interrupt available to
+                * CardBus devices, all devices downstream of this
+                * device must be using this IRQ.
+                */
                pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &irq_pin);
                if (irq_pin) {
                        dev->irq = irq;
                        pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
                }
 
+               /*
+                * Some controllers transfer very slowly with 0 CLS.
+                * Configure it.  This may fail as CLS configuration
+                * is mandatory only for MWI.
+                */
+               pci_set_cacheline_size(dev);
+
                if (dev->subordinate)
-                       cardbus_assign_irqs(dev->subordinate, irq);
+                       cardbus_config_irq_and_cls(dev->subordinate, irq);
        }
 }
 
@@ -228,7 +235,7 @@ int __ref cb_alloc(struct pcmcia_socket * s)
         */
        pci_bus_size_bridges(bus);
        pci_bus_assign_resources(bus);
-       cardbus_assign_irqs(bus, s->pci_irq);
+       cardbus_config_irq_and_cls(bus, s->pci_irq);
 
        /* socket specific tune function */
        if (s->tune_bridge)
index b849861d78e65b7acd73cb9a71b1f33c9e60750c..da4128f6e916d0476392c56a1ba1e9e2123d0f03 100644 (file)
@@ -701,6 +701,7 @@ void pci_disable_device(struct pci_dev *dev);
 void pci_set_master(struct pci_dev *dev);
 void pci_clear_master(struct pci_dev *dev);
 int pci_set_pcie_reset_state(struct pci_dev *dev, enum pcie_reset_state state);
+int pci_set_cacheline_size(struct pci_dev *dev);
 #define HAVE_PCI_SET_MWI
 int __must_check pci_set_mwi(struct pci_dev *dev);
 int pci_try_set_mwi(struct pci_dev *dev);