Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / arch / ia64 / sn / pci / pci_dma.c
index 5da9bdb..b4b84c2 100644 (file)
 
 #include <linux/module.h>
 #include <asm/dma.h>
-#include <asm/sn/sn_sal.h>
+#include <asm/sn/pcibr_provider.h>
 #include <asm/sn/pcibus_provider_defs.h>
 #include <asm/sn/pcidev.h>
+#include <asm/sn/sn_sal.h>
 
 #define SG_ENT_VIRT_ADDRESS(sg)        (page_address((sg)->page) + (sg)->offset)
 #define SG_ENT_PHYS_ADDRESS(SG)        virt_to_phys(SG_ENT_VIRT_ADDRESS(SG))
@@ -74,10 +75,11 @@ EXPORT_SYMBOL(sn_dma_set_mask);
  * more information.
  */
 void *sn_dma_alloc_coherent(struct device *dev, size_t size,
-                           dma_addr_t * dma_handle, int flags)
+                           dma_addr_t * dma_handle, gfp_t flags)
 {
        void *cpuaddr;
        unsigned long phys_addr;
+       int node;
        struct pci_dev *pdev = to_pci_dev(dev);
        struct sn_pcibus_provider *provider = SN_PCIDEV_BUSPROVIDER(pdev);
 
@@ -85,10 +87,19 @@ void *sn_dma_alloc_coherent(struct device *dev, size_t size,
 
        /*
         * Allocate the memory.
-        * FIXME: We should be doing alloc_pages_node for the node closest
-        *        to the PCI device.
         */
-       if (!(cpuaddr = (void *)__get_free_pages(GFP_ATOMIC, get_order(size))))
+       node = pcibus_to_node(pdev->bus);
+       if (likely(node >=0)) {
+               struct page *p = alloc_pages_node(node, flags, get_order(size));
+
+               if (likely(p))
+                       cpuaddr = page_address(p);
+               else
+                       return NULL;
+       } else
+               cpuaddr = (void *)__get_free_pages(flags, get_order(size));
+
+       if (unlikely(!cpuaddr))
                return NULL;
 
        memset(cpuaddr, 0x0, size);
@@ -315,6 +326,29 @@ int sn_pci_legacy_read(struct pci_bus *bus, u16 port, u32 *val, u8 size)
 {
        unsigned long addr;
        int ret;
+       struct ia64_sal_retval isrv;
+
+       /*
+        * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work
+        * around hw issues at the pci bus level.  SGI proms older than
+        * 4.10 don't implment this.
+        */
+
+       SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE,
+                pci_domain_nr(bus), bus->number,
+                0, /* io */
+                0, /* read */
+                port, size, __pa(val));
+
+       if (isrv.status == 0)
+               return size;
+
+       /*
+        * If the above failed, retry using the SAL_PROBE call which should
+        * be present in all proms (but which cannot work round PCI chipset
+        * bugs).  This code is retained for compatability with old
+        * pre-4.10 proms, and should be removed at some point in the future.
+        */
 
        if (!SN_PCIBUS_BUSSOFT(bus))
                return -ENODEV;
@@ -338,6 +372,29 @@ int sn_pci_legacy_write(struct pci_bus *bus, u16 port, u32 val, u8 size)
        int ret = size;
        unsigned long paddr;
        unsigned long *addr;
+       struct ia64_sal_retval isrv;
+
+       /*
+        * First, try the SN_SAL_IOIF_PCI_SAFE SAL call which can work
+        * around hw issues at the pci bus level.  SGI proms older than
+        * 4.10 don't implment this.
+        */
+
+       SAL_CALL(isrv, SN_SAL_IOIF_PCI_SAFE,
+                pci_domain_nr(bus), bus->number,
+                0, /* io */
+                1, /* write */
+                port, size, __pa(&val));
+
+       if (isrv.status == 0)
+               return size;
+
+       /*
+        * If the above failed, retry using the SAL_PROBE call which should
+        * be present in all proms (but which cannot work round PCI chipset
+        * bugs).  This code is retained for compatability with old
+        * pre-4.10 proms, and should be removed at some point in the future.
+        */
 
        if (!SN_PCIBUS_BUSSOFT(bus)) {
                ret = -ENODEV;