On Thu, Sep 25, 2014 at 02:14:20PM +1000, Gavin Shan wrote:

Please ignore this. I was told by Ben some drivers don't call
set_dev_mask(). So I have to fix it in another way.

Thanks,
Gavin

>When using bypass window on IODA2, the incorrect DMA operations
>"dma_iommu_ops" is used by devices. The device driver calls
>dma_get_required_mask() to determine using 32-bits or bypass DMA
>window. Unfortunately, the returned DMA mask always forces the
>driver to use 32-bits DMA window. The problem was reported on
>the device as follows:
>
>0004:03:00.0 0107: 1000:0087 (rev 05)
>0004:03:00.0 Serial Attached SCSI controller: LSI Logic / Symbios \
>             Logic SAS2308 PCI-Express Fusion-MPT SAS-2 (rev 05)
>
>The patch fixes above issue by keeping things consistent: when
>enabling bypass window, we switch to "dma_direct_ops". Instead,
>switch to "pci_dma_ops" when disabling bypass window.
>
>Reported-by: Murali N. Iyer <mni...@us.ibm.com>
>Signed-off-by: Gavin Shan <gws...@linux.vnet.ibm.com>
>---
> arch/powerpc/platforms/powernv/pci-ioda.c | 76 +++++++++++++++++++------------
> 1 file changed, 46 insertions(+), 30 deletions(-)
>
>diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c 
>b/arch/powerpc/platforms/powernv/pci-ioda.c
>index 36b1a7a..60e44d9 100644
>--- a/arch/powerpc/platforms/powernv/pci-ioda.c
>+++ b/arch/powerpc/platforms/powernv/pci-ioda.c
>@@ -883,13 +883,29 @@ static int pnv_pci_ioda_dma_set_mask(struct pnv_phb *phb,
>               set_dma_offset(&pdev->dev, pe->tce_bypass_base);
>       } else {
>               dev_info(&pdev->dev, "Using 32-bit DMA via iommu\n");
>-              set_dma_ops(&pdev->dev, &dma_iommu_ops);
>+              set_dma_ops(&pdev->dev, get_pci_dma_ops());
>               set_iommu_table_base(&pdev->dev, &pe->tce32_table);
>       }
>       *pdev->dev.dma_mask = dma_mask;
>       return 0;
> }
>
>+static void pnv_ioda_setup_dev_dma(struct pnv_ioda_pe *pe,
>+                                 struct pci_dev *pdev,
>+                                 bool add_to_iommu_group)
>+{
>+      if (pe->tce_bypass_enabled) {
>+              set_dma_ops(&pdev->dev, &dma_direct_ops);
>+              set_dma_offset(&pdev->dev, pe->tce_bypass_base);
>+      } else {
>+              set_dma_ops(&pdev->dev, get_pci_dma_ops());
>+              set_iommu_table_base(&pdev->dev, &pe->tce32_table);
>+      }
>+
>+      if (add_to_iommu_group)
>+              iommu_add_device(&pdev->dev);
>+}
>+
> static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
>                                  struct pci_bus *bus,
>                                  bool add_to_iommu_group)
>@@ -897,11 +913,7 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
>       struct pci_dev *dev;
>
>       list_for_each_entry(dev, &bus->devices, bus_list) {
>-              if (add_to_iommu_group)
>-                      set_iommu_table_base_and_group(&dev->dev,
>-                                                     &pe->tce32_table);
>-              else
>-                      set_iommu_table_base(&dev->dev, &pe->tce32_table);
>+              pnv_ioda_setup_dev_dma(pe, dev, add_to_iommu_group);
>
>               if (dev->subordinate)
>                       pnv_ioda_setup_bus_dma(pe, dev->subordinate,
>@@ -909,6 +921,15 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe,
>       }
> }
>
>+static void pnv_ioda_setup_pe_dma(struct pnv_ioda_pe *pe,
>+                                bool add_to_iommu_group)
>+{
>+      if (pe->pdev)
>+              pnv_ioda_setup_dev_dma(pe, pe->pdev, add_to_iommu_group);
>+      else
>+              pnv_ioda_setup_bus_dma(pe, pe->pbus, add_to_iommu_group);
>+}
>+
> static void pnv_pci_ioda1_tce_invalidate(struct pnv_ioda_pe *pe,
>                                        struct iommu_table *tbl,
>                                        __be64 *startp, __be64 *endp, bool rm)
>@@ -1080,11 +1101,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb 
>*phb,
>       iommu_init_table(tbl, phb->hose->node);
>       iommu_register_group(tbl, phb->hose->global_number, pe->pe_number);
>
>-      if (pe->pdev)
>-              set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
>-      else
>-              pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
>-
>+      pnv_ioda_setup_pe_dma(pe, true);
>       return;
>  fail:
>       /* XXX Failure: Try to fallback to 64-bit only ? */
>@@ -1101,7 +1118,13 @@ static void pnv_pci_ioda2_set_bypass(struct iommu_table 
>*tbl, bool enable)
>       uint16_t window_id = (pe->pe_number << 1 ) + 1;
>       int64_t rc;
>
>+      /* Check if we really need do something */
>+      if (pe->tce_bypass_enabled == enable)
>+              return;
>+
>       pe_info(pe, "%sabling 64-bit DMA bypass\n", enable ? "En" : "Dis");
>+      pe->tce_bypass_enabled = enable;
>+
>       if (enable) {
>               phys_addr_t top = memblock_end_of_DRAM();
>
>@@ -1117,22 +1140,15 @@ static void pnv_pci_ioda2_set_bypass(struct 
>iommu_table *tbl, bool enable)
>                                                    window_id,
>                                                    pe->tce_bypass_base,
>                                                    0);
>-
>-              /*
>-               * EEH needs the mapping between IOMMU table and group
>-               * of those VFIO/KVM pass-through devices. We can postpone
>-               * resetting DMA ops until the DMA mask is configured in
>-               * host side.
>-               */
>-              if (pe->pdev)
>-                      set_iommu_table_base(&pe->pdev->dev, tbl);
>-              else
>-                      pnv_ioda_setup_bus_dma(pe, pe->pbus, false);
>       }
>-      if (rc)
>+      if (rc != OPAL_SUCCESS) {
>               pe_err(pe, "OPAL error %lld configuring bypass window\n", rc);
>-      else
>-              pe->tce_bypass_enabled = enable;
>+              return;
>+      }
>+
>+      /* Update base and operations */
>+      pe->tce_bypass_enabled = enable;
>+      pnv_ioda_setup_pe_dma(pe, false);
> }
>
> static void pnv_pci_ioda2_setup_bypass_pe(struct pnv_phb *phb,
>@@ -1213,12 +1229,12 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb 
>*phb,
>       iommu_init_table(tbl, phb->hose->node);
>       iommu_register_group(tbl, phb->hose->global_number, pe->pe_number);
>
>-      if (pe->pdev)
>-              set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
>-      else
>-              pnv_ioda_setup_bus_dma(pe, pe->pbus, true);
>+      /* If the bypass window fails to be created, we still
>+       * can use 32-bits window.
>+       */
>+      pnv_ioda_setup_pe_dma(pe, true);
>
>-      /* Also create a bypass window */
>+      /* Create bypass window */
>       pnv_pci_ioda2_setup_bypass_pe(phb, pe);
>       return;
> fail:
>-- 
>1.8.3.2
>

_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to