summaryrefslogtreecommitdiff
path: root/drivers/iommu
diff options
context:
space:
mode:
authorVarun Sethi <Varun.Sethi@freescale.com>2014-03-25 10:39:09 (GMT)
committerJose Rivera <German.Rivera@freescale.com>2014-04-03 00:07:50 (GMT)
commit55fdffc214a6693adffb6353e4f2db6ba805a1d4 (patch)
tree069f35f4d1df6e5e2d8099d8bdbbc24ff0d4f07e /drivers/iommu
parent35a87539c61623a476ac1804f59f2f4ff83d91ef (diff)
downloadlinux-fsl-qoriq-55fdffc214a6693adffb6353e4f2db6ba805a1d4.tar.xz
iommu/fsl: Enable default DMA window for PCIe devices once detached from domain.
Once the PCIe device assigned to a guest VM (via VFIO) gets detached from the iommu domain (when guest terminates), its PAMU table entry is disabled. So, this would prevent the device from being used once it's assigned back to the host. This patch allows for creation of a default DMA window corresponding to the device and subsequently enabling the PAMU table entry. Before we enable the entry, we ensure that the device's bus master capability is disabled (device quiesced). Signed-off-by: Varun Sethi <Varun.Sethi@freescale.com> Change-Id: Iab4da4adfac8536a6834011431a395ba3a4982d2 Reviewed-on: http://git.am.freescale.net:8181/10257 Tested-by: Review Code-CDREVIEW <CDREVIEW@freescale.com> Reviewed-by: Stuart Yoder <stuart.yoder@freescale.com> Reviewed-by: Jose Rivera <German.Rivera@freescale.com>
Diffstat (limited to 'drivers/iommu')
-rw-r--r--drivers/iommu/fsl_pamu.c20
-rw-r--r--drivers/iommu/fsl_pamu.h1
-rw-r--r--drivers/iommu/fsl_pamu_domain.c52
3 files changed, 70 insertions, 3 deletions
diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index da707d8..e7b3d45 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -277,6 +277,26 @@ static void setup_default_ppaace(struct paace *ppaace)
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);
+
+ /* Ensure that all other stores to the ppaace complete first */
+ mb();
+ pamu_enable_liodn(liodn);
+}
+
/* Release the subwindows reserved for a particular LIODN */
void pamu_free_subwins(int liodn)
{
diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h
index 853cdb7..89940fa 100644
--- a/drivers/iommu/fsl_pamu.h
+++ b/drivers/iommu/fsl_pamu.h
@@ -412,5 +412,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 844997e..e62048b 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -366,17 +366,63 @@ 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;
+ u16 pci_command;
+
+ pdev = to_pci_dev(info->dev);
+ pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
+ /* disable device bus master capability */
+ if (pci_command & PCI_COMMAND_MASTER) {
+ pci_command &= ~PCI_COMMAND_MASTER;
+ pci_write_config_word(pdev, PCI_COMMAND, pci_command);
+ }
+ }
+#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)
{
unsigned long flags;
+ int enable_dma_window = 0;
list_del(&info->link);
spin_lock_irqsave(&iommu_lock, flags);
- 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_irqrestore(&iommu_lock, flags);
spin_lock_irqsave(&device_domain_lock, flags);
+ disable_device_dma(info, enable_dma_window);
info->dev->archdata.iommu_domain = NULL;
kmem_cache_free(iommu_devinfo_cache, info);
spin_unlock_irqrestore(&device_domain_lock, flags);