From: Jiang Liu <jiang.liu@linux.intel.com>
To: Joerg Roedel <joro@8bytes.org>,
David Woodhouse <dwmw2@infradead.org>,
Yinghai Lu <yinghai@kernel.org>,
Bjorn Helgaas <bhelgaas@google.com>,
Dan Williams <dan.j.williams@intel.com>,
Vinod Koul <vinod.koul@intel.com>,
"Rafael J . Wysocki" <rafael.j.wysocki@intel.com>
Cc: Jiang Liu <jiang.liu@linux.intel.com>,
Ashok Raj <ashok.raj@intel.com>,
Yijing Wang <wangyijing@huawei.com>,
Tony Luck <tony.luck@intel.com>,
iommu@lists.linux-foundation.org, linux-pci@vger.kernel.org,
linux-kernel@vger.kernel.org, dmaengine@vger.kernel.org
Subject: [Patch Part3 V1 16/22] iommu/vt-d: enhance intel-iommu driver to support DMAR unit hotplug
Date: Tue, 22 Apr 2014 15:07:27 +0800 [thread overview]
Message-ID: <1398150453-28141-17-git-send-email-jiang.liu@linux.intel.com> (raw)
In-Reply-To: <1398150453-28141-1-git-send-email-jiang.liu@linux.intel.com>
Implement required callback functions for intel-iommu driver
to support DMAR unit hotplug.
Signed-off-by: Jiang Liu <jiang.liu@linux.intel.com>
---
drivers/iommu/intel-iommu.c | 194 +++++++++++++++++++++++++++++++------------
1 file changed, 139 insertions(+), 55 deletions(-)
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 33e636c246a6..f2143b59ad68 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -1116,8 +1116,11 @@ static int iommu_alloc_root_entry(struct intel_iommu *iommu)
unsigned long flags;
root = (struct root_entry *)alloc_pgtable_page(iommu->node);
- if (!root)
+ if (!root) {
+ pr_err("IOMMU: allocating root entry for %s failed\n",
+ iommu->name);
return -ENOMEM;
+ }
__iommu_flush_cache(iommu, root, ROOT_SIZE);
@@ -1457,7 +1460,7 @@ static int iommu_init_domains(struct intel_iommu *iommu)
return 0;
}
-static void free_dmar_iommu(struct intel_iommu *iommu)
+static void disable_dmar_iommu(struct intel_iommu *iommu)
{
struct dmar_domain *domain;
int i;
@@ -1481,11 +1484,16 @@ static void free_dmar_iommu(struct intel_iommu *iommu)
if (iommu->gcmd & DMA_GCMD_TE)
iommu_disable_translation(iommu);
+}
- kfree(iommu->domains);
- kfree(iommu->domain_ids);
- iommu->domains = NULL;
- iommu->domain_ids = NULL;
+static void free_dmar_iommu(struct intel_iommu *iommu)
+{
+ if ((iommu->domains) && (iommu->domain_ids)) {
+ kfree(iommu->domains);
+ kfree(iommu->domain_ids);
+ iommu->domains = NULL;
+ iommu->domain_ids = NULL;
+ }
g_iommus[iommu->seq_id] = NULL;
@@ -2680,6 +2688,41 @@ static int __init iommu_prepare_static_identity_mapping(int hw)
return 0;
}
+static void intel_iommu_init_qi(struct intel_iommu *iommu)
+{
+ /*
+ * Start from the sane iommu hardware state.
+ * If the queued invalidation is already initialized by us
+ * (for example, while enabling interrupt-remapping) then
+ * we got the things already rolling from a sane state.
+ */
+ if (!iommu->qi) {
+ /*
+ * Clear any previous faults.
+ */
+ dmar_fault(-1, iommu);
+ /*
+ * Disable queued invalidation if supported and already enabled
+ * before OS handover.
+ */
+ dmar_disable_qi(iommu);
+ }
+
+ if (dmar_enable_qi(iommu)) {
+ /*
+ * Queued Invalidate not enabled, use Register Based Invalidate
+ */
+ iommu->flush.flush_context = __iommu_flush_context;
+ iommu->flush.flush_iotlb = __iommu_flush_iotlb;
+ pr_info("IOMMU: %s using Register based invalidation\n",
+ iommu->name);
+ } else {
+ iommu->flush.flush_context = qi_flush_context;
+ iommu->flush.flush_iotlb = qi_flush_iotlb;
+ pr_info("IOMMU: %s using Queued invalidation\n", iommu->name);
+ }
+}
+
static int __init init_dmars(void)
{
struct dmar_drhd_unit *drhd;
@@ -2708,6 +2751,10 @@ static int __init init_dmars(void)
DMAR_UNITS_SUPPORTED);
}
+ /* Preallocate enough resources for IOMMU hot-addition */
+ if (g_num_of_iommus < DMAR_UNITS_SUPPORTED)
+ g_num_of_iommus = DMAR_UNITS_SUPPORTED;
+
g_iommus = kcalloc(g_num_of_iommus, sizeof(struct intel_iommu *),
GFP_KERNEL);
if (!g_iommus) {
@@ -2736,58 +2783,14 @@ static int __init init_dmars(void)
* among all IOMMU's. Need to Split it later.
*/
ret = iommu_alloc_root_entry(iommu);
- if (ret) {
- printk(KERN_ERR "IOMMU: allocate root entry failed\n");
+ if (ret)
goto free_iommu;
- }
if (!ecap_pass_through(iommu->ecap))
hw_pass_through = 0;
}
- /*
- * Start from the sane iommu hardware state.
- */
- for_each_active_iommu(iommu, drhd) {
- /*
- * If the queued invalidation is already initialized by us
- * (for example, while enabling interrupt-remapping) then
- * we got the things already rolling from a sane state.
- */
- if (iommu->qi)
- continue;
-
- /*
- * Clear any previous faults.
- */
- dmar_fault(-1, iommu);
- /*
- * Disable queued invalidation if supported and already enabled
- * before OS handover.
- */
- dmar_disable_qi(iommu);
- }
-
- for_each_active_iommu(iommu, drhd) {
- if (dmar_enable_qi(iommu)) {
- /*
- * Queued Invalidate not enabled, use Register Based
- * Invalidate
- */
- iommu->flush.flush_context = __iommu_flush_context;
- iommu->flush.flush_iotlb = __iommu_flush_iotlb;
- printk(KERN_INFO "IOMMU %d 0x%Lx: using Register based "
- "invalidation\n",
- iommu->seq_id,
- (unsigned long long)drhd->reg_base_addr);
- } else {
- iommu->flush.flush_context = qi_flush_context;
- iommu->flush.flush_iotlb = qi_flush_iotlb;
- printk(KERN_INFO "IOMMU %d 0x%Lx: using Queued "
- "invalidation\n",
- iommu->seq_id,
- (unsigned long long)drhd->reg_base_addr);
- }
- }
+ for_each_active_iommu(iommu, drhd)
+ intel_iommu_init_qi(iommu);
if (iommu_pass_through)
iommu_identity_mapping |= IDENTMAP_ALL;
@@ -2873,8 +2876,10 @@ static int __init init_dmars(void)
return 0;
free_iommu:
- for_each_active_iommu(iommu, drhd)
+ for_each_active_iommu(iommu, drhd) {
+ disable_dmar_iommu(iommu);
free_dmar_iommu(iommu);
+ }
kfree(deferred_flush);
free_g_iommus:
kfree(g_iommus);
@@ -3800,9 +3805,88 @@ int dmar_check_one_atsr(struct acpi_dmar_header *hdr, void *arg)
return 0;
}
+static int intel_iommu_add(struct dmar_drhd_unit *dmaru)
+{
+ int ret = 0;
+ struct intel_iommu *iommu = dmaru->iommu;
+
+ if (g_iommus[iommu->seq_id])
+ return 0;
+
+ if (hw_pass_through && !ecap_pass_through(iommu->ecap)) {
+ pr_warn("IOMMU: %s doesn't support hardware pass through.\n",
+ iommu->name);
+ return -ENXIO;
+ }
+
+ /*
+ * Disable translation if already enabled prior to OS handover.
+ */
+ if (iommu->gcmd & DMA_GCMD_TE)
+ iommu_disable_translation(iommu);
+
+ g_iommus[iommu->seq_id] = iommu;
+ ret = iommu_init_domains(iommu);
+ if (ret == 0)
+ ret = iommu_alloc_root_entry(iommu);
+ if (ret)
+ goto out;
+
+ if (dmaru->ignored) {
+ /*
+ * we always have to disable PMRs or DMA may fail on this device
+ */
+ if (force_on)
+ iommu_disable_protect_mem_regions(iommu);
+ return 0;
+ }
+
+ intel_iommu_init_qi(iommu);
+ iommu_flush_write_buffer(iommu);
+ ret = dmar_set_interrupt(iommu);
+ if (ret)
+ goto disable_iommu;
+
+ iommu_set_root_entry(iommu);
+ iommu->flush.flush_context(iommu, 0, 0, 0, DMA_CCMD_GLOBAL_INVL);
+ iommu->flush.flush_iotlb(iommu, 0, 0, 0, DMA_TLB_GLOBAL_FLUSH);
+ iommu_enable_translation(iommu);
+
+ if (si_domain) {
+ ret = iommu_attach_domain(si_domain, iommu);
+ if (ret < 0 || si_domain->id != ret)
+ goto disable_iommu;
+ domain_attach_iommu(si_domain, iommu);
+ }
+
+ iommu_disable_protect_mem_regions(iommu);
+ return 0;
+
+disable_iommu:
+ disable_dmar_iommu(iommu);
+out:
+ free_dmar_iommu(iommu);
+ return ret;
+}
+
int dmar_iommu_hotplug(struct dmar_drhd_unit *dmaru, bool insert)
{
- return intel_iommu_enabled ? -ENOSYS : 0;
+ int ret = 0;
+ struct intel_iommu *iommu = dmaru->iommu;
+
+ if (!intel_iommu_enabled)
+ return 0;
+ if (iommu == NULL)
+ return -EINVAL;
+
+ if (insert) {
+ ret = intel_iommu_add(dmaru);
+ } else {
+ disable_dmar_iommu(iommu);
+ free_dmar_iommu(iommu);
+ }
+
+ return ret;
}
static void intel_iommu_free_dmars(void)
--
1.7.10.4
next prev parent reply other threads:[~2014-04-22 7:07 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-22 7:07 [RFC Patch Part3 V1 00/22] Enable Intel DMAR device hotplug Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 01/22] iommu/vt-d: match segment number when searching for dev_iotlb capable devices Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 02/22] iommu/vt-d: use correct domain id to flush virtual machine domains Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 03/22] iommu/vt-d: introduce helper functions to improve code readability Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 04/22] iommu/vt-d: introduce helper functions to make code symmetric for readability Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 05/22] iommu/vt-d: only dynamically allocate domain id for virtual domains Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 06/22] iommu/vt-d: fix possible invalid memory access caused by free_dmar_iommu() Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 07/22] iommu/vt-d: avoid freeing virtual machine domain in free_dmar_iommu() Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 08/22] iommu/VT-d: simplify include/linux/dmar.h Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 09/22] iommu/vt-d: change iommu_enable/disable_translation to return void Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 10/22] iommu/vt-d: dynamically allocate and free seq_id for DMAR units Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 11/22] IOMMU/vt-d: introduce helper function dmar_walk_resources() Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 12/22] iommu/vt-d: implement DMAR unit hotplug framework Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 13/22] iommu/vt-d: search _DSM method for DMAR hotplug Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 14/22] iommu/vt-d: enhance intel_irq_remapping driver to support DMAR unit hotplug Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 15/22] iommu/vt-d: enhance error recovery in function intel_enable_irq_remapping() Jiang Liu
2014-04-22 7:07 ` Jiang Liu [this message]
2014-04-22 7:07 ` [Patch Part3 V1 17/22] pci, ACPI, iommu: enhance pci_root to support DMAR device hotplug Jiang Liu
2014-04-22 9:49 ` Rafael J. Wysocki
2014-05-05 8:31 ` Jiang Liu
2014-04-24 17:33 ` Bjorn Helgaas
2014-05-05 8:22 ` Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 18/22] iommu/vt-d: update proximity information when a new node with memory available Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 19/22] iommu/vt-d: simplify intel_unmap_sg() and kill duplicated code Jiang Liu
2014-04-22 7:38 ` David Woodhouse
2014-04-22 7:42 ` Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 20/22] iommu/vt-d: introduce helper domain_pfn_within_range() to simplify code Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 21/22] iommu/vt-d: introduce helper function iova_size() to improve code readability Jiang Liu
2014-04-22 7:07 ` [Patch Part3 V1 22/22] iommu/vt-d: fix bug in computing domain's iommu_snooping flag Jiang Liu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1398150453-28141-17-git-send-email-jiang.liu@linux.intel.com \
--to=jiang.liu@linux.intel.com \
--cc=ashok.raj@intel.com \
--cc=bhelgaas@google.com \
--cc=dan.j.williams@intel.com \
--cc=dmaengine@vger.kernel.org \
--cc=dwmw2@infradead.org \
--cc=iommu@lists.linux-foundation.org \
--cc=joro@8bytes.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=rafael.j.wysocki@intel.com \
--cc=tony.luck@intel.com \
--cc=vinod.koul@intel.com \
--cc=wangyijing@huawei.com \
--cc=yinghai@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).