mlx4_core: Support ICM tables in coherent memory
[pandora-kernel.git] / arch / sparc64 / kernel / pci.c
index 81f4a5e..e8dac81 100644 (file)
@@ -283,12 +283,6 @@ int __init pcic_present(void)
        return pci_controller_scan(pci_is_controller);
 }
 
-const struct pci_iommu_ops *pci_iommu_ops;
-EXPORT_SYMBOL(pci_iommu_ops);
-
-extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
-       pci_sun4v_iommu_ops;
-
 /* Find each controller in the system, attach and initialize
  * software state structure for each and link into the
  * pci_pbm_root.  Setup the controller enough such
@@ -296,11 +290,6 @@ extern const struct pci_iommu_ops pci_sun4u_iommu_ops,
  */
 static void __init pci_controller_probe(void)
 {
-       if (tlb_type == hypervisor)
-               pci_iommu_ops = &pci_sun4v_iommu_ops;
-       else
-               pci_iommu_ops = &pci_sun4u_iommu_ops;
-
        printk("PCI: Probing for controllers.\n");
 
        pci_controller_scan(pci_controller_init);
@@ -404,7 +393,10 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        sd->host_controller = pbm;
        sd->prom_node = node;
        sd->op = of_find_device_by_node(node);
-       sd->msi_num = 0xffffffff;
+
+       sd = &sd->op->dev.archdata;
+       sd->iommu = pbm->iommu;
+       sd->stc = &pbm->stc;
 
        type = of_get_property(node, "device_type", NULL);
        if (type == NULL)
@@ -422,10 +414,15 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
        dev->multifunction = 0;         /* maybe a lie? */
 
        if (host_controller) {
-               dev->vendor = 0x108e;
-               dev->device = 0x8000;
-               dev->subsystem_vendor = 0x0000;
-               dev->subsystem_device = 0x0000;
+               if (tlb_type != hypervisor) {
+                       pci_read_config_word(dev, PCI_VENDOR_ID,
+                                            &dev->vendor);
+                       pci_read_config_word(dev, PCI_DEVICE_ID,
+                                            &dev->device);
+               } else {
+                       dev->vendor = PCI_VENDOR_ID_SUN;
+                       dev->device = 0x80f0;
+               }
                dev->cfg_size = 256;
                dev->class = PCI_CLASS_BRIDGE_HOST << 8;
                sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
@@ -448,6 +445,7 @@ struct pci_dev *of_create_pci_dev(struct pci_pbm_info *pbm,
                 */
                pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
                dev->class = class >> 8;
+               dev->revision = class & 0xff;
 
                sprintf(pci_name(dev), "%04x:%02x:%02x.%d", pci_domain_nr(bus),
                        dev->bus->number, PCI_SLOT(devfn), PCI_FUNC(devfn));
@@ -746,7 +744,7 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
 {
        struct device_node *child;
        const u32 *reg;
-       int reglen, devfn;
+       int reglen, devfn, prev_devfn;
        struct pci_dev *dev;
 
        if (ofpci_verbose)
@@ -754,14 +752,25 @@ static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm,
                       node->full_name, bus->number);
 
        child = NULL;
+       prev_devfn = -1;
        while ((child = of_get_next_child(node, child)) != NULL) {
                if (ofpci_verbose)
                        printk("  * %s\n", child->full_name);
                reg = of_get_property(child, "reg", &reglen);
                if (reg == NULL || reglen < 20)
                        continue;
+
                devfn = (reg[0] >> 8) & 0xff;
 
+               /* This is a workaround for some device trees
+                * which list PCI devices twice.  On the V100
+                * for example, device number 3 is listed twice.
+                * Once as "pm" and once again as "lomp".
+                */
+               if (devfn == prev_devfn)
+                       continue;
+               prev_devfn = devfn;
+
                /* create a new pci_dev for this device */
                dev = of_create_pci_dev(pbm, child, bus, devfn, 0);
                if (!dev)
@@ -817,7 +826,7 @@ int pci_host_bridge_read_pci_cfg(struct pci_bus *bus_dev,
 {
        static u8 fake_pci_config[] = {
                0x8e, 0x10, /* Vendor: 0x108e (Sun) */
-               0x00, 0x80, /* Device: 0x8000 (PBM) */
+               0xf0, 0x80, /* Device: 0x80f0 (Fire) */
                0x46, 0x01, /* Command: 0x0146 (SERR, PARITY, MASTER, MEM) */
                0xa0, 0x22, /* Status: 0x02a0 (DEVSEL_MED, FB2B, 66MHZ) */
                0x00, 0x00, 0x00, 0x06, /* Class: 0x06000000 host bridge */
@@ -1220,4 +1229,51 @@ struct device_node *pci_device_to_OF_node(struct pci_dev *pdev)
 }
 EXPORT_SYMBOL(pci_device_to_OF_node);
 
+static void ali_sound_dma_hack(struct pci_dev *pdev, int set_bit)
+{
+       struct pci_dev *ali_isa_bridge;
+       u8 val;
+
+       /* ALI sound chips generate 31-bits of DMA, a special register
+        * determines what bit 31 is emitted as.
+        */
+       ali_isa_bridge = pci_get_device(PCI_VENDOR_ID_AL,
+                                        PCI_DEVICE_ID_AL_M1533,
+                                        NULL);
+
+       pci_read_config_byte(ali_isa_bridge, 0x7e, &val);
+       if (set_bit)
+               val |= 0x01;
+       else
+               val &= ~0x01;
+       pci_write_config_byte(ali_isa_bridge, 0x7e, val);
+       pci_dev_put(ali_isa_bridge);
+}
+
+int pci_dma_supported(struct pci_dev *pdev, u64 device_mask)
+{
+       u64 dma_addr_mask;
+
+       if (pdev == NULL) {
+               dma_addr_mask = 0xffffffff;
+       } else {
+               struct iommu *iommu = pdev->dev.archdata.iommu;
+
+               dma_addr_mask = iommu->dma_addr_mask;
+
+               if (pdev->vendor == PCI_VENDOR_ID_AL &&
+                   pdev->device == PCI_DEVICE_ID_AL_M5451 &&
+                   device_mask == 0x7fffffff) {
+                       ali_sound_dma_hack(pdev,
+                                          (dma_addr_mask & 0x80000000) != 0);
+                       return 1;
+               }
+       }
+
+       if (device_mask >= (1UL << 32UL))
+               return 0;
+
+       return (device_mask & dma_addr_mask) == dma_addr_mask;
+}
+
 #endif /* !(CONFIG_PCI) */