diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries/iommu.c')
| -rw-r--r-- | arch/powerpc/platforms/pseries/iommu.c | 35 | 
1 files changed, 33 insertions, 2 deletions
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 01faab9456c..b719d970973 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c @@ -29,6 +29,7 @@  #include <linux/slab.h>  #include <linux/mm.h>  #include <linux/spinlock.h> +#include <linux/sched.h>	/* for show_stack */  #include <linux/string.h>  #include <linux/pci.h>  #include <linux/dma-mapping.h> @@ -939,14 +940,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)  	if (ret) {  		dev_info(&dev->dev, "failed to map direct window for %s: %d\n",  			 dn->full_name, ret); -		goto out_clear_window; +		goto out_free_window;  	}  	ret = prom_add_property(pdn, win64);  	if (ret) {  		dev_err(&dev->dev, "unable to add dma window property for %s: %d",  			 pdn->full_name, ret); -		goto out_clear_window; +		goto out_free_window;  	}  	window->device = pdn; @@ -958,6 +959,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)  	dma_addr = of_read_number(&create.addr_hi, 2);  	goto out_unlock; +out_free_window: +	kfree(window); +  out_clear_window:  	remove_ddw(pdn); @@ -1077,12 +1081,38 @@ check_mask:  	return 0;  } +static u64 dma_get_required_mask_pSeriesLP(struct device *dev) +{ +	if (!dev->dma_mask) +		return 0; + +	if (!disable_ddw && dev_is_pci(dev)) { +		struct pci_dev *pdev = to_pci_dev(dev); +		struct device_node *dn; + +		dn = pci_device_to_OF_node(pdev); + +		/* search upwards for ibm,dma-window */ +		for (; dn && PCI_DN(dn) && !PCI_DN(dn)->iommu_table; +				dn = dn->parent) +			if (of_get_property(dn, "ibm,dma-window", NULL)) +				break; +		/* if there is a ibm,ddw-applicable property require 64 bits */ +		if (dn && PCI_DN(dn) && +				of_get_property(dn, "ibm,ddw-applicable", NULL)) +			return DMA_BIT_MASK(64); +	} + +	return dma_iommu_ops.get_required_mask(dev); +} +  #else  /* CONFIG_PCI */  #define pci_dma_bus_setup_pSeries	NULL  #define pci_dma_dev_setup_pSeries	NULL  #define pci_dma_bus_setup_pSeriesLP	NULL  #define pci_dma_dev_setup_pSeriesLP	NULL  #define dma_set_mask_pSeriesLP		NULL +#define dma_get_required_mask_pSeriesLP	NULL  #endif /* !CONFIG_PCI */  static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action, @@ -1186,6 +1216,7 @@ void iommu_init_early_pSeries(void)  		ppc_md.pci_dma_bus_setup = pci_dma_bus_setup_pSeriesLP;  		ppc_md.pci_dma_dev_setup = pci_dma_dev_setup_pSeriesLP;  		ppc_md.dma_set_mask = dma_set_mask_pSeriesLP; +		ppc_md.dma_get_required_mask = dma_get_required_mask_pSeriesLP;  	} else {  		ppc_md.tce_build = tce_build_pSeries;  		ppc_md.tce_free  = tce_free_pSeries;  |