Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 212845
b: refs/heads/master
c: 8fb07c0
h: refs/heads/master
i:
  212843: 5a808c4
v: v3
  • Loading branch information
Benjamin Herrenschmidt committed Sep 2, 2010
1 parent 77ef2c7 commit 87489fa
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 11 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 5b6e9ff6deb703b95fb355bb66d86096c1a2df09
refs/heads/master: 8fb07c0444c37caa39a8df7c70a694c6211f2f57
74 changes: 64 additions & 10 deletions trunk/arch/powerpc/sysdev/dart_iommu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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 */
Expand Down

0 comments on commit 87489fa

Please sign in to comment.