|
@@ -70,6 +70,8 @@ static int iommu_table_dart_inited;
|
|
|
static int dart_dirty;
|
|
|
static int dart_is_u4;
|
|
|
|
|
|
+#define DART_U4_BYPASS_BASE 0x8000000000ull
|
|
|
+
|
|
|
#define DBG(...)
|
|
|
|
|
|
static inline void dart_tlb_invalidate_all(void)
|
|
@@ -292,12 +294,20 @@ static void iommu_table_dart_setup(void)
|
|
|
set_bit(iommu_table_dart.it_size - 1, iommu_table_dart.it_map);
|
|
|
}
|
|
|
|
|
|
-static void pci_dma_dev_setup_dart(struct pci_dev *dev)
|
|
|
+static void dma_dev_setup_dart(struct device *dev)
|
|
|
{
|
|
|
/* We only have one iommu table on the mac for now, which makes
|
|
|
* things simple. Setup all PCI devices to point to this table
|
|
|
*/
|
|
|
- set_iommu_table_base(&dev->dev, &iommu_table_dart);
|
|
|
+ if (get_dma_ops(dev) == &dma_direct_ops)
|
|
|
+ set_dma_offset(dev, DART_U4_BYPASS_BASE);
|
|
|
+ else
|
|
|
+ set_iommu_table_base(dev, &iommu_table_dart);
|
|
|
+}
|
|
|
+
|
|
|
+static void pci_dma_dev_setup_dart(struct pci_dev *dev)
|
|
|
+{
|
|
|
+ dma_dev_setup_dart(&dev->dev);
|
|
|
}
|
|
|
|
|
|
static void pci_dma_bus_setup_dart(struct pci_bus *bus)
|
|
@@ -315,6 +325,45 @@ static void pci_dma_bus_setup_dart(struct pci_bus *bus)
|
|
|
PCI_DN(dn)->iommu_table = &iommu_table_dart;
|
|
|
}
|
|
|
|
|
|
+static bool dart_device_on_pcie(struct device *dev)
|
|
|
+{
|
|
|
+ struct device_node *np = of_node_get(dev->of_node);
|
|
|
+
|
|
|
+ while(np) {
|
|
|
+ if (of_device_is_compatible(np, "U4-pcie") ||
|
|
|
+ of_device_is_compatible(np, "u4-pcie")) {
|
|
|
+ of_node_put(np);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ np = of_get_next_parent(np);
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static int dart_dma_set_mask(struct device *dev, u64 dma_mask)
|
|
|
+{
|
|
|
+ if (!dev->dma_mask || !dma_supported(dev, dma_mask))
|
|
|
+ return -EIO;
|
|
|
+
|
|
|
+ /* U4 supports a DART bypass, we use it for 64-bit capable
|
|
|
+ * devices to improve performances. However, that only works
|
|
|
+ * for devices connected to U4 own PCIe interface, not bridged
|
|
|
+ * through hypertransport. We need the device to support at
|
|
|
+ * least 40 bits of addresses.
|
|
|
+ */
|
|
|
+ if (dart_device_on_pcie(dev) && dma_mask >= DMA_BIT_MASK(40)) {
|
|
|
+ dev_info(dev, "Using 64-bit DMA iommu bypass\n");
|
|
|
+ set_dma_ops(dev, &dma_direct_ops);
|
|
|
+ } else {
|
|
|
+ dev_info(dev, "Using 32-bit DMA via iommu\n");
|
|
|
+ set_dma_ops(dev, &dma_iommu_ops);
|
|
|
+ }
|
|
|
+ dma_dev_setup_dart(dev);
|
|
|
+
|
|
|
+ *dev->dma_mask = dma_mask;
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
void __init iommu_init_early_dart(void)
|
|
|
{
|
|
|
struct device_node *dn;
|
|
@@ -328,20 +377,25 @@ void __init iommu_init_early_dart(void)
|
|
|
dart_is_u4 = 1;
|
|
|
}
|
|
|
|
|
|
+ /* Initialize the DART HW */
|
|
|
+ if (dart_init(dn) != 0)
|
|
|
+ goto bail;
|
|
|
+
|
|
|
/* Setup low level TCE operations for the core IOMMU code */
|
|
|
ppc_md.tce_build = dart_build;
|
|
|
ppc_md.tce_free = dart_free;
|
|
|
ppc_md.tce_flush = dart_flush;
|
|
|
|
|
|
- /* Initialize the DART HW */
|
|
|
- if (dart_init(dn) == 0) {
|
|
|
- ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart;
|
|
|
- ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
|
|
|
+ /* Setup bypass if supported */
|
|
|
+ if (dart_is_u4)
|
|
|
+ ppc_md.dma_set_mask = dart_dma_set_mask;
|
|
|
|
|
|
- /* Setup pci_dma ops */
|
|
|
- set_pci_dma_ops(&dma_iommu_ops);
|
|
|
- return;
|
|
|
- }
|
|
|
+ ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_dart;
|
|
|
+ ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_dart;
|
|
|
+
|
|
|
+ /* Setup pci_dma ops */
|
|
|
+ set_pci_dma_ops(&dma_iommu_ops);
|
|
|
+ return;
|
|
|
|
|
|
bail:
|
|
|
/* If init failed, use direct iommu and null setup functions */
|