summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorVarun Sethi <Varun.Sethi@freescale.com>2013-10-21 18:07:28 (GMT)
committerJ. German Rivera <German.Rivera@freescale.com>2013-10-24 17:14:53 (GMT)
commite312f01b0df471deccfd21a0cd24f7babb5817a0 (patch)
tree0b1eca3e2bce97f32a041404575866103c5948a3 /drivers
parent935a2c63705cb6f0092c8b4876873d164f32b608 (diff)
downloadlinux-fsl-qoriq-e312f01b0df471deccfd21a0cd24f7babb5817a0.tar.xz
iommu/fsl: Allocate a default DMA window for a device once it's detached
from a domain. This allows the device to be assigned back to the host, once a guest VM exits. Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com> Change-Id: I211b4452d2f7fce572ed8828a1fc5457d7f3b0e5 Reviewed-on: http://git.am.freescale.net:8181/5869 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Bhushan Bharat-R65777 <Bharat.Bhushan@freescale.com> Reviewed-by: Rivera Jose-B46482 <German.Rivera@freescale.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/iommu/fsl_pamu.c54
-rw-r--r--drivers/iommu/fsl_pamu.h1
-rw-r--r--drivers/iommu/fsl_pamu_domain.c47
3 files changed, 81 insertions, 21 deletions
diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index 84a5de7..42b903f 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -250,6 +250,40 @@ static unsigned long pamu_get_fspi_and_allocate(u32 subwin_cnt)
return (spaace_addr - (unsigned long)spaact) / (sizeof(struct paace));
}
+/*
+ * Defaul PPAACE settings for an LIODN.
+ */
+static void setup_default_ppaace(struct paace *ppaace)
+{
+ pamu_init_ppaace(ppaace);
+ /* window size is 2^(WSE+1) bytes */
+ set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 35);
+ ppaace->wbah = 0;
+ set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
+ set_bf(ppaace->impl_attr, PAACE_IA_ATM,
+ PAACE_ATM_NO_XLATE);
+ set_bf(ppaace->addr_bitfields, PAACE_AF_AP,
+ PAACE_AP_PERMS_ALL);
+}
+
+/* Reset the PAACE entry to the default state */
+void enable_default_dma_window(int liodn)
+{
+ struct paace *ppaace;
+
+ ppaace = pamu_get_ppaace(liodn);
+ if (!ppaace) {
+ pr_debug("Invalid liodn entry\n");
+ return;
+ }
+
+ memset(ppaace, 0, sizeof(struct paace));
+
+ setup_default_ppaace(ppaace);
+ mb();
+ pamu_enable_liodn(liodn);
+}
+
/* Release the subwindows reserved for a particular LIODN */
void pamu_free_subwins(int liodn)
{
@@ -854,15 +888,7 @@ static void __init enable_remaining_liodns(void)
for (liodn = 0; liodn < PAACE_NUMBER_ENTRIES; liodn++) {
ppaace = pamu_get_ppaace(liodn);
if (!get_bf(ppaace->addr_bitfields, PAACE_AF_V)) {
- pamu_init_ppaace(ppaace);
- /* window size is 2^(WSE+1) bytes */
- set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 35);
- ppaace->wbah = 0;
- set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
- set_bf(ppaace->impl_attr, PAACE_IA_ATM,
- PAACE_ATM_NO_XLATE);
- set_bf(ppaace->addr_bitfields, PAACE_AF_AP,
- PAACE_AP_PERMS_ALL);
+ setup_default_ppaace(ppaace);
mb();
pamu_enable_liodn(liodn);
}
@@ -888,15 +914,7 @@ static void __init setup_liodns(void)
continue;
}
ppaace = pamu_get_ppaace(liodn);
- pamu_init_ppaace(ppaace);
- /* window size is 2^(WSE+1) bytes */
- set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE, 35);
- ppaace->wbah = 0;
- set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
- set_bf(ppaace->impl_attr, PAACE_IA_ATM,
- PAACE_ATM_NO_XLATE);
- set_bf(ppaace->addr_bitfields, PAACE_AF_AP,
- PAACE_AP_PERMS_ALL);
+ setup_default_ppaace(ppaace);
if (of_device_is_compatible(node, "fsl,qman-portal"))
setup_dpaa_paace(ppaace, QMAN_PORTAL_PAACE);
if (of_device_is_compatible(node, "fsl,qman"))
diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h
index fd9dd6d..119ae04 100644
--- a/drivers/iommu/fsl_pamu.h
+++ b/drivers/iommu/fsl_pamu.h
@@ -407,5 +407,6 @@ void get_ome_index(u32 *omi_index, struct device *dev);
int pamu_update_paace_field(int liodn, u32 subwin, int field, u32 value);
int pamu_disable_spaace(int liodn, u32 subwin);
u32 pamu_get_max_subwin_cnt(void);
+void enable_default_dma_window(int liodn);
#endif /* __FSL_PAMU_H */
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index c18b76f..c9eb0f9 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -338,15 +338,56 @@ static inline struct device_domain_info *find_domain(struct device *dev)
return dev->archdata.iommu_domain;
}
+/* Disable device DMA capability and enable default DMA window */
+static void disable_device_dma(struct device_domain_info *info,
+ int enable_dma_window)
+{
+#ifdef CONFIG_PCI
+ if (info->dev->bus == &pci_bus_type) {
+ struct pci_dev *pdev = NULL;
+ pdev = to_pci_dev(info->dev);
+ if (pci_is_enabled(pdev))
+ pci_disable_device(pdev);
+ }
+#endif
+
+ if (enable_dma_window)
+ enable_default_dma_window(info->liodn);
+}
+
+static int check_for_shared_liodn(struct device_domain_info *info)
+{
+ struct device_domain_info *tmp;
+
+ /*
+ * Sanity check, to ensure that this is not a
+ * shared LIODN. In case of a PCIe controller
+ * it's possible that all PCIe devices share
+ * the same LIODN.
+ */
+ list_for_each_entry(tmp, &info->domain->devices, link) {
+ if (info->liodn == tmp->liodn)
+ return 1;
+ }
+
+ return 0;
+}
+
static void remove_device_ref(struct device_domain_info *info, u32 win_cnt)
{
+ int enable_dma_window = 0;
+
list_del(&info->link);
spin_lock(&iommu_lock);
- if (win_cnt > 1)
- pamu_free_subwins(info->liodn);
- pamu_disable_liodn(info->liodn);
+ if (!check_for_shared_liodn(info)) {
+ if (win_cnt > 1)
+ pamu_free_subwins(info->liodn);
+ pamu_disable_liodn(info->liodn);
+ enable_dma_window = 1;
+ }
spin_unlock(&iommu_lock);
spin_lock(&device_domain_lock);
+ disable_device_dma(info, enable_dma_window);
info->dev->archdata.iommu_domain = NULL;
kmem_cache_free(iommu_devinfo_cache, info);
spin_unlock(&device_domain_lock);