iommu.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug
       [not found] ` <1331018040-30725-1-git-send-email-yinghai-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
@ 2012-03-06  7:13   ` Yinghai Lu
  2012-03-09  1:06     ` Bjorn Helgaas
  2012-03-06  7:13   ` [PATCH 09/23] IOMMU: Fix tboot force iommu logic Yinghai Lu
  1 sibling, 1 reply; 8+ messages in thread
From: Yinghai Lu @ 2012-03-06  7:13 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: Vinod Koul, linux-pci-u79uwXL29TY76Z2rM5mHXA,
	linux-kernel-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA, Yinghai Lu,
	Dan Williams, David Woodhouse

When do pci remove/rescan on system that have more iommus, got

[  894.089745] Set context mapping for c4:00.0
[  894.110890] mpt2sas3: Allocated physical memory: size(4293 kB)
[  894.112556] mpt2sas3: Current Controller Queue Depth(1883), Max Controller Queue Depth(2144)
[  894.127278] mpt2sas3: Scatter Gather Elements per IO(128)
[  894.361295] DRHD: handling fault status reg 2
[  894.364053] DMAR:[DMA Read] Request device [c4:00.0] fault addr fffbe000
[  894.364056] DMAR:[fault reason 02] Present bit in context entry is cl

it turns out when remove/rescan, pci dev will be freed and will get another new dev.
but drhd units still keep old one... so dmar_find_matched_drhd_unit will
return wrong drhd and iommu for the device that is not on first iommu.

So need to update devices in drhd_units during pci remove/rescan.

Could save domain/bus/device/function aside in the list and according that info
restore new dev to drhd_units later.
Then dmar_find_matched_drdh_unit and device_to_iommu could return right drhd and iommu.

Add remove_dev_from_drhd/restore_dev_to_drhd functions to do the real work.
call them in device ADD_DEVICE and UNBOUND_DRIVER

Need to do the samething to atsr.  (expose dmar_atsr_units and add atsru->segment)

After patch, will right iommu for the new dev and will not get DMAR error any more.

-v2: add pci_dev_put/pci_dev_get to make refcount consistent.

Signed-off-by: Yinghai Lu <yinghai-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: David Woodhouse <dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
Cc: Vinod Koul <vinod.koul-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Cc: Dan Williams <dan.j.williams-ral2JQCrhuEAvxtiuMwx3w@public.gmane.org>
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
---
 drivers/iommu/intel-iommu.c |  187 ++++++++++++++++++++++++++++++++++++++++---
 include/linux/dmar.h        |    4 +
 2 files changed, 181 insertions(+), 10 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index c9c6053..39ef2ce 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -665,6 +665,159 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
 	return NULL;
 }
 
+#ifdef CONFIG_HOTPLUG
+struct dev_dmaru {
+	struct list_head list;
+	void *dmaru;
+	int index;
+	int segment;
+	unsigned char bus;
+	unsigned int devfn;
+};
+
+static int
+save_dev_dmaru(int segment, unsigned char bus, unsigned int devfn,
+		 void *dmaru, int index, struct list_head *lh)
+{
+	struct dev_dmaru *m;
+
+	m = kzalloc(sizeof(*m), GFP_KERNEL);
+	if (!m)
+		return -ENOMEM;
+
+	m->segment = segment;
+	m->bus     = bus;
+	m->devfn   = devfn;
+	m->dmaru   = dmaru;
+	m->index   = index;
+
+	list_add(&m->list, lh);
+
+	return 0;
+}
+
+static void
+*get_dev_dmaru(int segment, unsigned char bus, unsigned int devfn,
+		int *index, struct list_head *lh)
+{
+	struct dev_dmaru *m;
+	void *dmaru = NULL;
+
+	list_for_each_entry(m, lh, list) {
+		if (m->segment == segment &&
+		    m->bus == bus && m->devfn == devfn) {
+			*index = m->index;
+			dmaru  = m->dmaru;
+			list_del(&m->list);
+			kfree(m);
+			break;
+		}
+	}
+
+	return dmaru;
+}
+
+static LIST_HEAD(saved_dev_drhd_list);
+
+static void remove_dev_from_drhd(struct pci_dev *dev)
+{
+	struct dmar_drhd_unit *drhd = NULL;
+	int segment = pci_domain_nr(dev->bus);
+	int i;
+
+	for_each_drhd_unit(drhd) {
+		if (drhd->ignored)
+			continue;
+		if (segment != drhd->segment)
+			continue;
+
+		for (i = 0; i < drhd->devices_cnt; i++) {
+			if (drhd->devices[i] == dev) {
+				/* save it at first if it is in drhd */
+				save_dev_dmaru(segment, dev->bus->number,
+						dev->devfn, drhd, i,
+						&saved_dev_drhd_list);
+				/* always remove it */
+				pci_dev_put(dev);
+				drhd->devices[i] = NULL;
+				return;
+			}
+		}
+	}
+}
+
+static void restore_dev_to_drhd(struct pci_dev *dev)
+{
+	struct dmar_drhd_unit *drhd = NULL;
+	int i;
+
+	/* find the stored drhd */
+	drhd = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
+				 dev->devfn, &i, &saved_dev_drhd_list);
+	/* restore that into drhd */
+	if (drhd)
+		drhd->devices[i] = pci_dev_get(dev);
+}
+#else
+static void remove_dev_from_drhd(struct pci_dev *dev)
+{
+}
+
+static void restore_dev_to_drhd(struct pci_dev *dev)
+{
+}
+#endif
+
+#if defined(CONFIG_DMAR) && defined(CONFIG_HOTPLUG)
+static LIST_HEAD(saved_dev_atsr_list);
+
+static void remove_dev_from_atsr(struct pci_dev *dev)
+{
+	struct dmar_atsr_unit *atsr = NULL;
+	int segment = pci_domain_nr(dev->bus);
+	int i;
+
+	for_each_atsr_unit(atsr) {
+		if (segment != atsr->segment)
+			continue;
+
+		for (i = 0; i < atsr->devices_cnt; i++) {
+			if (atsr->devices[i] == dev) {
+				/* save it at first if it is in drhd */
+				save_dev_dmaru(segment, dev->bus->number,
+						dev->devfn, atsr, i,
+						&saved_dev_atsr_list);
+				/* always remove it */
+				pci_dev_put(dev);
+				atsr->devices[i] = NULL;
+				return;
+			}
+		}
+	}
+}
+
+static void restore_dev_to_atsr(struct pci_dev *dev)
+{
+	struct dmar_atsr_unit *atsr = NULL;
+	int i;
+
+	/* find the stored atsr */
+	atsr = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
+				 dev->devfn, &i, &saved_dev_atsr_list);
+	/* restore that into atsr */
+	if (atsr)
+		atsr->devices[i] = pci_dev_get(dev);
+}
+#else
+static void remove_dev_from_atsr(struct pci_dev *dev)
+{
+}
+
+static void restore_dev_to_atsr(struct pci_dev *dev)
+{
+}
+#endif
+
 static void domain_flush_cache(struct dmar_domain *domain,
 			       void *addr, int size)
 {
@@ -3474,6 +3627,7 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 
 	atsru->hdr = hdr;
 	atsru->include_all = atsr->flags & 0x1;
+	atsru->segment = atsr->segment;
 
 	list_add(&atsru->list, &dmar_atsr_units);
 
@@ -3505,16 +3659,13 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
 {
 	int i;
 	struct pci_bus *bus;
-	struct acpi_dmar_atsr *atsr;
 	struct dmar_atsr_unit *atsru;
 
 	dev = pci_physfn(dev);
 
-	list_for_each_entry(atsru, &dmar_atsr_units, list) {
-		atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
-		if (atsr->segment == pci_domain_nr(dev->bus))
+	list_for_each_entry(atsru, &dmar_atsr_units, list)
+		if (atsru->segment == pci_domain_nr(dev->bus))
 			goto found;
-	}
 
 	return 0;
 
@@ -3574,20 +3725,36 @@ static int device_notifier(struct notifier_block *nb,
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct dmar_domain *domain;
 
-	if (iommu_no_mapping(dev))
+	if (unlikely(dev->bus != &pci_bus_type))
 		return 0;
 
-	domain = find_domain(pdev);
-	if (!domain)
-		return 0;
+	switch (action) {
+	case BUS_NOTIFY_UNBOUND_DRIVER:
+		if (iommu_no_mapping(dev))
+			goto out;
+
+		if (iommu_pass_through)
+			goto out;
+
+		domain = find_domain(pdev);
+		if (!domain)
+			goto out;
 
-	if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
 		domain_remove_one_dev_info(domain, pdev);
 
 		if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
 		    !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
 		    list_empty(&domain->devices))
 			domain_exit(domain);
+out:
+		remove_dev_from_drhd(pdev);
+		remove_dev_from_atsr(pdev);
+
+		break;
+	case BUS_NOTIFY_ADD_DEVICE:
+		restore_dev_to_drhd(pdev);
+		restore_dev_to_atsr(pdev);
+		break;
 	}
 
 	return 0;
diff --git a/include/linux/dmar.h b/include/linux/dmar.h
index 731a609..57e1375 100644
--- a/include/linux/dmar.h
+++ b/include/linux/dmar.h
@@ -236,9 +236,13 @@ struct dmar_atsr_unit {
 	struct acpi_dmar_header *hdr;	/* ACPI header */
 	struct pci_dev **devices;	/* target devices */
 	int devices_cnt;		/* target device count */
+	u16 segment;			/* PCI domain */
 	u8 include_all:1;		/* include all ports */
 };
 
+#define for_each_atsr_unit(atsr) \
+	list_for_each_entry(atsr, &dmar_atsr_units, list)
+
 int dmar_parse_rmrr_atsr_dev(void);
 extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
 extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
-- 
1.7.7

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 09/23] IOMMU: Fix tboot force iommu logic
       [not found] ` <1331018040-30725-1-git-send-email-yinghai-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
  2012-03-06  7:13   ` [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug Yinghai Lu
@ 2012-03-06  7:13   ` Yinghai Lu
  1 sibling, 0 replies; 8+ messages in thread
From: Yinghai Lu @ 2012-03-06  7:13 UTC (permalink / raw)
  To: Jesse Barnes, x86
  Cc: linux-pci-u79uwXL29TY76Z2rM5mHXA,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	David Woodhouse, Yinghai Lu, linux-kernel-u79uwXL29TY76Z2rM5mHXA

Should check dmar_disabled just after tboot_force_iommu.

otherwise when tboot is not used, and intel_iommu=off, and nointrmap
still get dmar_table_init() called. that will cause some get_device
calling, and it will have some device refcount leaking.

Signed-off-by: Yinghai Lu <yinghai-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
Cc: David Woodhouse <dwmw2-wEGCiKHe2LqWVfeAwA7xHQ@public.gmane.org>
Cc: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA@public.gmane.org
---
 drivers/iommu/intel-iommu.c |    6 +++---
 1 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 39ef2ce..f1879d3 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -3771,6 +3771,9 @@ int __init intel_iommu_init(void)
 	/* VT-d is required for a TXT/tboot launch, so enforce that */
 	force_on = tboot_force_iommu();
 
+	if (no_iommu || dmar_disabled)
+		return -ENODEV;
+
 	if (dmar_table_init()) {
 		if (force_on)
 			panic("tboot: Failed to initialize DMAR table\n");
@@ -3783,9 +3786,6 @@ int __init intel_iommu_init(void)
 		return 	-ENODEV;
 	}
 
-	if (no_iommu || dmar_disabled)
-		return -ENODEV;
-
 	if (iommu_init_mempool()) {
 		if (force_on)
 			panic("tboot: Failed to initialize iommu memory\n");
-- 
1.7.7

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug
  2012-03-06  7:13   ` [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug Yinghai Lu
@ 2012-03-09  1:06     ` Bjorn Helgaas
  2012-03-09  7:06       ` Yinghai Lu
  0 siblings, 1 reply; 8+ messages in thread
From: Bjorn Helgaas @ 2012-03-09  1:06 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Jesse Barnes, x86, linux-pci, linux-kernel, David Woodhouse,
	Vinod Koul, Dan Williams, iommu

On Tue, Mar 6, 2012 at 12:13 AM, Yinghai Lu <yinghai@kernel.org> wrote:
> When do pci remove/rescan on system that have more iommus, got
>
> [  894.089745] Set context mapping for c4:00.0
> [  894.110890] mpt2sas3: Allocated physical memory: size(4293 kB)
> [  894.112556] mpt2sas3: Current Controller Queue Depth(1883), Max Controller Queue Depth(2144)
> [  894.127278] mpt2sas3: Scatter Gather Elements per IO(128)
> [  894.361295] DRHD: handling fault status reg 2
> [  894.364053] DMAR:[DMA Read] Request device [c4:00.0] fault addr fffbe000
> [  894.364056] DMAR:[fault reason 02] Present bit in context entry is cl
>
> it turns out when remove/rescan, pci dev will be freed and will get another new dev.
> but drhd units still keep old one... so dmar_find_matched_drhd_unit will
> return wrong drhd and iommu for the device that is not on first iommu.
>
> So need to update devices in drhd_units during pci remove/rescan.
>
> Could save domain/bus/device/function aside in the list and according that info
> restore new dev to drhd_units later.
> Then dmar_find_matched_drdh_unit and device_to_iommu could return right drhd and iommu.
>
> Add remove_dev_from_drhd/restore_dev_to_drhd functions to do the real work.
> call them in device ADD_DEVICE and UNBOUND_DRIVER
>
> Need to do the samething to atsr.  (expose dmar_atsr_units and add atsru->segment)
>
> After patch, will right iommu for the new dev and will not get DMAR error any more.
>
> -v2: add pci_dev_put/pci_dev_get to make refcount consistent.
>
> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
> Cc: David Woodhouse <dwmw2@infradead.org>
> Cc: Vinod Koul <vinod.koul@intel.com>
> Cc: Dan Williams <dan.j.williams@intel.com>
> Cc: iommu@lists.linux-foundation.org
> ---
>  drivers/iommu/intel-iommu.c |  187 ++++++++++++++++++++++++++++++++++++++++---
>  include/linux/dmar.h        |    4 +
>  2 files changed, 181 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
> index c9c6053..39ef2ce 100644
> --- a/drivers/iommu/intel-iommu.c
> +++ b/drivers/iommu/intel-iommu.c
> @@ -665,6 +665,159 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
>        return NULL;
>  }
>
> +#ifdef CONFIG_HOTPLUG
> +struct dev_dmaru {
> +       struct list_head list;
> +       void *dmaru;
> +       int index;
> +       int segment;
> +       unsigned char bus;
> +       unsigned int devfn;
> +};
> +
> +static int
> +save_dev_dmaru(int segment, unsigned char bus, unsigned int devfn,
> +                void *dmaru, int index, struct list_head *lh)

Follow the indentation style used elsewhere in the file: as much of
the declaration on one line as will fit (here and below).

I think the callers would read more naturally if you passed in the
struct pci_dev * to save_dev_dmaru() and extracted the
segment/bus/devfn here rather than in the callers.

> +{
> +       struct dev_dmaru *m;
> +
> +       m = kzalloc(sizeof(*m), GFP_KERNEL);
> +       if (!m)
> +               return -ENOMEM;
> +
> +       m->segment = segment;
> +       m->bus     = bus;
> +       m->devfn   = devfn;
> +       m->dmaru   = dmaru;
> +       m->index   = index;
> +
> +       list_add(&m->list, lh);
> +
> +       return 0;
> +}
> +
> +static void
> +*get_dev_dmaru(int segment, unsigned char bus, unsigned int devfn,
> +               int *index, struct list_head *lh)
> +{
> +       struct dev_dmaru *m;
> +       void *dmaru = NULL;
> +
> +       list_for_each_entry(m, lh, list) {
> +               if (m->segment == segment &&
> +                   m->bus == bus && m->devfn == devfn) {
> +                       *index = m->index;
> +                       dmaru  = m->dmaru;
> +                       list_del(&m->list);
> +                       kfree(m);
> +                       break;
> +               }
> +       }
> +
> +       return dmaru;
> +}
> +
> +static LIST_HEAD(saved_dev_drhd_list);
> +
> +static void remove_dev_from_drhd(struct pci_dev *dev)
> +{
> +       struct dmar_drhd_unit *drhd = NULL;
> +       int segment = pci_domain_nr(dev->bus);
> +       int i;
> +
> +       for_each_drhd_unit(drhd) {
> +               if (drhd->ignored)
> +                       continue;
> +               if (segment != drhd->segment)
> +                       continue;
> +
> +               for (i = 0; i < drhd->devices_cnt; i++) {
> +                       if (drhd->devices[i] == dev) {
> +                               /* save it at first if it is in drhd */
> +                               save_dev_dmaru(segment, dev->bus->number,
> +                                               dev->devfn, drhd, i,
> +                                               &saved_dev_drhd_list);
> +                               /* always remove it */
> +                               pci_dev_put(dev);
> +                               drhd->devices[i] = NULL;
> +                               return;
> +                       }
> +               }
> +       }
> +}
> +
> +static void restore_dev_to_drhd(struct pci_dev *dev)
> +{
> +       struct dmar_drhd_unit *drhd = NULL;
> +       int i;
> +
> +       /* find the stored drhd */
> +       drhd = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
> +                                dev->devfn, &i, &saved_dev_drhd_list);
> +       /* restore that into drhd */
> +       if (drhd)
> +               drhd->devices[i] = pci_dev_get(dev);
> +}
> +#else
> +static void remove_dev_from_drhd(struct pci_dev *dev)
> +{
> +}
> +
> +static void restore_dev_to_drhd(struct pci_dev *dev)
> +{
> +}
> +#endif
> +
> +#if defined(CONFIG_DMAR) && defined(CONFIG_HOTPLUG)
> +static LIST_HEAD(saved_dev_atsr_list);
> +
> +static void remove_dev_from_atsr(struct pci_dev *dev)
> +{
> +       struct dmar_atsr_unit *atsr = NULL;
> +       int segment = pci_domain_nr(dev->bus);
> +       int i;
> +
> +       for_each_atsr_unit(atsr) {
> +               if (segment != atsr->segment)
> +                       continue;
> +
> +               for (i = 0; i < atsr->devices_cnt; i++) {
> +                       if (atsr->devices[i] == dev) {
> +                               /* save it at first if it is in drhd */
> +                               save_dev_dmaru(segment, dev->bus->number,
> +                                               dev->devfn, atsr, i,
> +                                               &saved_dev_atsr_list);
> +                               /* always remove it */
> +                               pci_dev_put(dev);
> +                               atsr->devices[i] = NULL;
> +                               return;
> +                       }
> +               }
> +       }
> +}
> +
> +static void restore_dev_to_atsr(struct pci_dev *dev)
> +{
> +       struct dmar_atsr_unit *atsr = NULL;
> +       int i;
> +
> +       /* find the stored atsr */
> +       atsr = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
> +                                dev->devfn, &i, &saved_dev_atsr_list);
> +       /* restore that into atsr */
> +       if (atsr)
> +               atsr->devices[i] = pci_dev_get(dev);
> +}
> +#else
> +static void remove_dev_from_atsr(struct pci_dev *dev)
> +{
> +}
> +
> +static void restore_dev_to_atsr(struct pci_dev *dev)
> +{
> +}
> +#endif
> +
>  static void domain_flush_cache(struct dmar_domain *domain,
>                               void *addr, int size)
>  {
> @@ -3474,6 +3627,7 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
>
>        atsru->hdr = hdr;
>        atsru->include_all = atsr->flags & 0x1;
> +       atsru->segment = atsr->segment;
>
>        list_add(&atsru->list, &dmar_atsr_units);
>
> @@ -3505,16 +3659,13 @@ int dmar_find_matched_atsr_unit(struct pci_dev *dev)
>  {
>        int i;
>        struct pci_bus *bus;
> -       struct acpi_dmar_atsr *atsr;
>        struct dmar_atsr_unit *atsru;
>
>        dev = pci_physfn(dev);
>
> -       list_for_each_entry(atsru, &dmar_atsr_units, list) {
> -               atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
> -               if (atsr->segment == pci_domain_nr(dev->bus))
> +       list_for_each_entry(atsru, &dmar_atsr_units, list)
> +               if (atsru->segment == pci_domain_nr(dev->bus))
>                        goto found;
> -       }
>
>        return 0;
>
> @@ -3574,20 +3725,36 @@ static int device_notifier(struct notifier_block *nb,
>        struct pci_dev *pdev = to_pci_dev(dev);
>        struct dmar_domain *domain;
>
> -       if (iommu_no_mapping(dev))
> +       if (unlikely(dev->bus != &pci_bus_type))
>                return 0;
>
> -       domain = find_domain(pdev);
> -       if (!domain)
> -               return 0;
> +       switch (action) {
> +       case BUS_NOTIFY_UNBOUND_DRIVER:
> +               if (iommu_no_mapping(dev))
> +                       goto out;
> +
> +               if (iommu_pass_through)
> +                       goto out;
> +
> +               domain = find_domain(pdev);
> +               if (!domain)
> +                       goto out;
>
> -       if (action == BUS_NOTIFY_UNBOUND_DRIVER && !iommu_pass_through) {
>                domain_remove_one_dev_info(domain, pdev);
>
>                if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
>                    !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY) &&
>                    list_empty(&domain->devices))
>                        domain_exit(domain);
> +out:
> +               remove_dev_from_drhd(pdev);
> +               remove_dev_from_atsr(pdev);
> +
> +               break;
> +       case BUS_NOTIFY_ADD_DEVICE:
> +               restore_dev_to_drhd(pdev);
> +               restore_dev_to_atsr(pdev);
> +               break;
>        }
>
>        return 0;
> diff --git a/include/linux/dmar.h b/include/linux/dmar.h
> index 731a609..57e1375 100644
> --- a/include/linux/dmar.h
> +++ b/include/linux/dmar.h
> @@ -236,9 +236,13 @@ struct dmar_atsr_unit {
>        struct acpi_dmar_header *hdr;   /* ACPI header */
>        struct pci_dev **devices;       /* target devices */
>        int devices_cnt;                /* target device count */
> +       u16 segment;                    /* PCI domain */
>        u8 include_all:1;               /* include all ports */
>  };
>
> +#define for_each_atsr_unit(atsr) \
> +       list_for_each_entry(atsr, &dmar_atsr_units, list)
> +
>  int dmar_parse_rmrr_atsr_dev(void);
>  extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
>  extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
> --
> 1.7.7
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pci" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug
  2012-03-09  1:06     ` Bjorn Helgaas
@ 2012-03-09  7:06       ` Yinghai Lu
  2012-03-09 17:25         ` Bjorn Helgaas
  0 siblings, 1 reply; 8+ messages in thread
From: Yinghai Lu @ 2012-03-09  7:06 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Jesse Barnes, x86, linux-pci, linux-kernel, David Woodhouse,
	Vinod Koul, Dan Williams, iommu

On Thu, Mar 8, 2012 at 5:06 PM, Bjorn Helgaas <bhelgaas@google.com> wrote:
> On Tue, Mar 6, 2012 at 12:13 AM, Yinghai Lu <yinghai@kernel.org> wrote:
>> When do pci remove/rescan on system that have more iommus, got
>>
>> [  894.089745] Set context mapping for c4:00.0
>> [  894.110890] mpt2sas3: Allocated physical memory: size(4293 kB)
>> [  894.112556] mpt2sas3: Current Controller Queue Depth(1883), Max Controller Queue Depth(2144)
>> [  894.127278] mpt2sas3: Scatter Gather Elements per IO(128)
>> [  894.361295] DRHD: handling fault status reg 2
>> [  894.364053] DMAR:[DMA Read] Request device [c4:00.0] fault addr fffbe000
>> [  894.364056] DMAR:[fault reason 02] Present bit in context entry is cl
>>
>> it turns out when remove/rescan, pci dev will be freed and will get another new dev.
>> but drhd units still keep old one... so dmar_find_matched_drhd_unit will
>> return wrong drhd and iommu for the device that is not on first iommu.
>>
>> So need to update devices in drhd_units during pci remove/rescan.
>>
>> Could save domain/bus/device/function aside in the list and according that info
>> restore new dev to drhd_units later.
>> Then dmar_find_matched_drdh_unit and device_to_iommu could return right drhd and iommu.
>>
>> Add remove_dev_from_drhd/restore_dev_to_drhd functions to do the real work.
>> call them in device ADD_DEVICE and UNBOUND_DRIVER
>>
>> Need to do the samething to atsr.  (expose dmar_atsr_units and add atsru->segment)
>>
>> After patch, will right iommu for the new dev and will not get DMAR error any more.
>>
>> -v2: add pci_dev_put/pci_dev_get to make refcount consistent.
>>
>> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
>> Cc: David Woodhouse <dwmw2@infradead.org>
>> Cc: Vinod Koul <vinod.koul@intel.com>
>> Cc: Dan Williams <dan.j.williams@intel.com>
>> Cc: iommu@lists.linux-foundation.org
>> ---
>>  drivers/iommu/intel-iommu.c |  187 ++++++++++++++++++++++++++++++++++++++++---
>>  include/linux/dmar.h        |    4 +
>>  2 files changed, 181 insertions(+), 10 deletions(-)
>>
>> diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
>> index c9c6053..39ef2ce 100644
>> --- a/drivers/iommu/intel-iommu.c
>> +++ b/drivers/iommu/intel-iommu.c
>> @@ -665,6 +665,159 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
>>        return NULL;
>>  }
>>
>> +#ifdef CONFIG_HOTPLUG
>> +struct dev_dmaru {
>> +       struct list_head list;
>> +       void *dmaru;
>> +       int index;
>> +       int segment;
>> +       unsigned char bus;
>> +       unsigned int devfn;
>> +};
>> +
>> +static int
>> +save_dev_dmaru(int segment, unsigned char bus, unsigned int devfn,
>> +                void *dmaru, int index, struct list_head *lh)
>
> Follow the indentation style used elsewhere in the file: as much of
> the declaration on one line as will fit (here and below).
>
> I think the callers would read more naturally if you passed in the
> struct pci_dev * to save_dev_dmaru() and extracted the
> segment/bus/devfn here rather than in the callers.

Just want to keep save_dev_dmaru more consistent to get_dev_dmaru...

Anyway, will change to pass struct pci_dev *dev instead.

Yinghai

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug
  2012-03-09  7:06       ` Yinghai Lu
@ 2012-03-09 17:25         ` Bjorn Helgaas
  2012-03-09 17:32           ` Yinghai Lu
  0 siblings, 1 reply; 8+ messages in thread
From: Bjorn Helgaas @ 2012-03-09 17:25 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Jesse Barnes, x86, linux-pci, linux-kernel, David Woodhouse,
	Vinod Koul, Dan Williams, iommu

On Fri, Mar 9, 2012 at 12:06 AM, Yinghai Lu <yinghai@kernel.org> wrote:
> On Thu, Mar 8, 2012 at 5:06 PM, Bjorn Helgaas <bhelgaas@google.com> wrote:
>> On Tue, Mar 6, 2012 at 12:13 AM, Yinghai Lu <yinghai@kernel.org> wrote:
>>> When do pci remove/rescan on system that have more iommus, got
>>>
>>> [  894.089745] Set context mapping for c4:00.0
>>> [  894.110890] mpt2sas3: Allocated physical memory: size(4293 kB)
>>> [  894.112556] mpt2sas3: Current Controller Queue Depth(1883), Max Controller Queue Depth(2144)
>>> [  894.127278] mpt2sas3: Scatter Gather Elements per IO(128)
>>> [  894.361295] DRHD: handling fault status reg 2
>>> [  894.364053] DMAR:[DMA Read] Request device [c4:00.0] fault addr fffbe000
>>> [  894.364056] DMAR:[fault reason 02] Present bit in context entry is cl
>>>
>>> it turns out when remove/rescan, pci dev will be freed and will get another new dev.
>>> but drhd units still keep old one... so dmar_find_matched_drhd_unit will
>>> return wrong drhd and iommu for the device that is not on first iommu.
>>>
>>> So need to update devices in drhd_units during pci remove/rescan.
>>>
>>> Could save domain/bus/device/function aside in the list and according that info
>>> restore new dev to drhd_units later.
>>> Then dmar_find_matched_drdh_unit and device_to_iommu could return right drhd and iommu.
>>>
>>> Add remove_dev_from_drhd/restore_dev_to_drhd functions to do the real work.
>>> call them in device ADD_DEVICE and UNBOUND_DRIVER
>>>
>>> Need to do the samething to atsr.  (expose dmar_atsr_units and add atsru->segment)
>>>
>>> After patch, will right iommu for the new dev and will not get DMAR error any more.
>>>
>>> -v2: add pci_dev_put/pci_dev_get to make refcount consistent.
>>>
>>> Signed-off-by: Yinghai Lu <yinghai@kernel.org>
>>> Cc: David Woodhouse <dwmw2@infradead.org>
>>> Cc: Vinod Koul <vinod.koul@intel.com>
>>> Cc: Dan Williams <dan.j.williams@intel.com>
>>> Cc: iommu@lists.linux-foundation.org
>>> ---
>>>  drivers/iommu/intel-iommu.c |  187 ++++++++++++++++++++++++++++++++++++++++---
>>>  include/linux/dmar.h        |    4 +
>>>  2 files changed, 181 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
>>> index c9c6053..39ef2ce 100644
>>> --- a/drivers/iommu/intel-iommu.c
>>> +++ b/drivers/iommu/intel-iommu.c
>>> @@ -665,6 +665,159 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
>>>        return NULL;
>>>  }
>>>
>>> +#ifdef CONFIG_HOTPLUG
>>> +struct dev_dmaru {
>>> +       struct list_head list;
>>> +       void *dmaru;
>>> +       int index;
>>> +       int segment;
>>> +       unsigned char bus;
>>> +       unsigned int devfn;
>>> +};
>>> +
>>> +static int
>>> +save_dev_dmaru(int segment, unsigned char bus, unsigned int devfn,
>>> +                void *dmaru, int index, struct list_head *lh)
>>
>> Follow the indentation style used elsewhere in the file: as much of
>> the declaration on one line as will fit (here and below).
>>
>> I think the callers would read more naturally if you passed in the
>> struct pci_dev * to save_dev_dmaru() and extracted the
>> segment/bus/devfn here rather than in the callers.
>
> Just want to keep save_dev_dmaru more consistent to get_dev_dmaru...

Well, it looks like you can change both save_dev_dmaru() *and*
get_dev_dmaru() to take a struct pci_dev *.  I assumed that would be
obvious.

Bjorn

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug
  2012-03-09 17:25         ` Bjorn Helgaas
@ 2012-03-09 17:32           ` Yinghai Lu
  2012-03-09 17:37             ` Bjorn Helgaas
  0 siblings, 1 reply; 8+ messages in thread
From: Yinghai Lu @ 2012-03-09 17:32 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Jesse Barnes, x86, linux-pci, linux-kernel, David Woodhouse,
	Vinod Koul, Dan Williams, iommu

On Fri, Mar 9, 2012 at 9:25 AM, Bjorn Helgaas <bhelgaas@google.com> wrote:
>
> Well, it looks like you can change both save_dev_dmaru() *and*
> get_dev_dmaru() to take a struct pci_dev *.  I assumed that would be
> obvious.

no.

get_dev_dmaru() have to use bus/devfn to retrieve the dev pointer.

Yinghai

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug
  2012-03-09 17:32           ` Yinghai Lu
@ 2012-03-09 17:37             ` Bjorn Helgaas
  2012-03-09 18:29               ` Yinghai Lu
  0 siblings, 1 reply; 8+ messages in thread
From: Bjorn Helgaas @ 2012-03-09 17:37 UTC (permalink / raw)
  To: Yinghai Lu
  Cc: Jesse Barnes, x86, linux-pci, linux-kernel, David Woodhouse,
	Vinod Koul, Dan Williams, iommu

On Fri, Mar 9, 2012 at 10:32 AM, Yinghai Lu <yinghai@kernel.org> wrote:
> On Fri, Mar 9, 2012 at 9:25 AM, Bjorn Helgaas <bhelgaas@google.com> wrote:
>>
>> Well, it looks like you can change both save_dev_dmaru() *and*
>> get_dev_dmaru() to take a struct pci_dev *.  I assumed that would be
>> obvious.
>
> no.
>
> get_dev_dmaru() have to use bus/devfn to retrieve the dev pointer.

I expected something like that, but all I see in the patch is this:

+static void restore_dev_to_drhd(struct pci_dev *dev)
+       drhd = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
+                                dev->devfn, &i, &saved_dev_drhd_list);

+static void restore_dev_to_atsr(struct pci_dev *dev)
+       atsr = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
+                                dev->devfn, &i, &saved_dev_atsr_list);

In both those cases, you have the struct pci_dev *.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug
  2012-03-09 17:37             ` Bjorn Helgaas
@ 2012-03-09 18:29               ` Yinghai Lu
  0 siblings, 0 replies; 8+ messages in thread
From: Yinghai Lu @ 2012-03-09 18:29 UTC (permalink / raw)
  To: Bjorn Helgaas
  Cc: Jesse Barnes, x86, linux-pci, linux-kernel, David Woodhouse,
	Vinod Koul, Dan Williams, iommu

On Fri, Mar 9, 2012 at 9:37 AM, Bjorn Helgaas <bhelgaas@google.com> wrote:
> On Fri, Mar 9, 2012 at 10:32 AM, Yinghai Lu <yinghai@kernel.org> wrote:
>> On Fri, Mar 9, 2012 at 9:25 AM, Bjorn Helgaas <bhelgaas@google.com> wrote:
>>>
>>> Well, it looks like you can change both save_dev_dmaru() *and*
>>> get_dev_dmaru() to take a struct pci_dev *.  I assumed that would be
>>> obvious.
>>
>> no.
>>
>> get_dev_dmaru() have to use bus/devfn to retrieve the dev pointer.
>
> I expected something like that, but all I see in the patch is this:
>
> +static void restore_dev_to_drhd(struct pci_dev *dev)
> +       drhd = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
> +                                dev->devfn, &i, &saved_dev_drhd_list);
>
> +static void restore_dev_to_atsr(struct pci_dev *dev)
> +       atsr = get_dev_dmaru(pci_domain_nr(dev->bus), dev->bus->number,
> +                                dev->devfn, &i, &saved_dev_atsr_list);
>
> In both those cases, you have the struct pci_dev *.

OK, i missed that. will update that accordingly.

Thanks

Yinghai

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2012-03-09 18:29 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <1331018040-30725-1-git-send-email-yinghai@kernel.org>
     [not found] ` <1331018040-30725-1-git-send-email-yinghai-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
2012-03-06  7:13   ` [PATCH 07/23] pci, dmar: Update dmar units devices list during hotplug Yinghai Lu
2012-03-09  1:06     ` Bjorn Helgaas
2012-03-09  7:06       ` Yinghai Lu
2012-03-09 17:25         ` Bjorn Helgaas
2012-03-09 17:32           ` Yinghai Lu
2012-03-09 17:37             ` Bjorn Helgaas
2012-03-09 18:29               ` Yinghai Lu
2012-03-06  7:13   ` [PATCH 09/23] IOMMU: Fix tboot force iommu logic Yinghai Lu

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).