Message ID | 1386246319-17851-5-git-send-email-hdoyu@nvidia.com |
---|---|
State | Superseded, archived |
Headers | show |
On 12/05/2013 08:25 PM, Hiroshi Doyu wrote: > Add support for more than 32 bit physical address. If physical > address space is 32bit, there will be no register write > happening. Based on Pavan's internal patch. > > Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com> > Cc: Pavan Kunapuli <pkunapuli@nvidia.com> > --- > drivers/iommu/tegra-smmu.c | 32 +++++++++++++++++++++++++------- > 1 file changed, 25 insertions(+), 7 deletions(-) > > diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c > index b5737f9..04e7199 100644 > --- a/drivers/iommu/tegra-smmu.c > +++ b/drivers/iommu/tegra-smmu.c > @@ -101,6 +101,8 @@ enum { > #define SMMU_PTC_FLUSH_TYPE_ADR 1 > #define SMMU_PTC_FLUSH_ADR_SHIFT 4 > > +#define SMMU_PTC_FLUSH_1 0x9b8 > + > #define SMMU_ASID_SECURITY 0x38 > > #define SMMU_STATS_CACHE_COUNT_BASE 0x1f0 > @@ -143,7 +145,7 @@ enum { > #define SMMU_PDIR_SHIFT 12 > #define SMMU_PDE_SHIFT 12 > #define SMMU_PTE_SHIFT 12 > -#define SMMU_PFN_MASK 0x000fffff > +#define SMMU_PFN_MASK 0x0fffffff > > #define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12) > #define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22) > @@ -301,6 +303,8 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) > #define VA_PAGE_TO_PA(va, page) \ > (page_to_phys(page) + ((unsigned long)(va) & ~PAGE_MASK)) > > +#define VA_PAGE_TO_PA_HI(va, page) (u32)((u64)page_to_phys(page) >> 32) > + > #define FLUSH_CPU_DCACHE(va, page, size) \ > do { \ > unsigned long _pa_ = VA_PAGE_TO_PA(va, page); \ > @@ -526,6 +530,21 @@ static int smmu_setup_regs(struct smmu_device *smmu) > return 0; > } > > +static void flush_ptc_by_addr(struct smmu_device *smmu, unsigned long *pte, > + struct page *page) > +{ > + u32 val; > + > + val = VA_PAGE_TO_PA_HI(pte, page); > + if (val) > + smmu_write(smmu, val, SMMU_PTC_FLUSH_1); > + This is not correct, according to my tests. We should write "SMMU_PTC_FLUSH_1" even when the "val" is zero. So I just copied Pavan's original work here, after applied this, the SMMU works correctly: - val = VA_PAGE_TO_PA_HI(pte, page); - if (val) + if (!pte) { + smmu_write(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH); + return; + } + + if (of_machine_is_compatible("nvidia,tegra124")) { + val = VA_PAGE_TO_PA_HI(pte, page); smmu_write(smmu, val, SMMU_PTC_FLUSH_1); + } Mark > + val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page); > + smmu_write(smmu, val, SMMU_PTC_FLUSH); > + > + FLUSH_SMMU_REGS(smmu); > +} > + > static void flush_ptc_and_tlb(struct smmu_device *smmu, > struct smmu_as *as, dma_addr_t iova, > unsigned long *pte, struct page *page, int is_pde) > @@ -535,9 +554,8 @@ static void flush_ptc_and_tlb(struct smmu_device *smmu, > ? SMMU_TLB_FLUSH_VA(iova, SECTION) > : SMMU_TLB_FLUSH_VA(iova, GROUP); > > - val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page); > - smmu_write(smmu, val, SMMU_PTC_FLUSH); > - FLUSH_SMMU_REGS(smmu); > + flush_ptc_by_addr(smmu, pte, page); > + > val = tlb_flush_va | > SMMU_TLB_FLUSH_ASID_MATCH__ENABLE | > (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT); > @@ -702,9 +720,9 @@ static int alloc_pdir(struct smmu_as *as) > for (pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++) > pdir[pdn] = _PDE_VACANT(pdn); > FLUSH_CPU_DCACHE(pdir, as->pdir_page, SMMU_PDIR_SIZE); > - val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pdir, as->pdir_page); > - smmu_write(smmu, val, SMMU_PTC_FLUSH); > - FLUSH_SMMU_REGS(as->smmu); > + > + flush_ptc_by_addr(as->smmu, pdir, page); > + > val = SMMU_TLB_FLUSH_VA_MATCH_ALL | > SMMU_TLB_FLUSH_ASID_MATCH__ENABLE | > (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT); > -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Tue, Jan 07, 2014 at 01:25:37PM +0800, Mark Zhang wrote: > On 12/05/2013 08:25 PM, Hiroshi Doyu wrote: [...] > > @@ -526,6 +530,21 @@ static int smmu_setup_regs(struct smmu_device *smmu) > > return 0; > > } > > > > +static void flush_ptc_by_addr(struct smmu_device *smmu, unsigned long *pte, > > + struct page *page) > > +{ > > + u32 val; > > + > > + val = VA_PAGE_TO_PA_HI(pte, page); > > + if (val) > > + smmu_write(smmu, val, SMMU_PTC_FLUSH_1); > > + > > This is not correct, according to my tests. We should write > "SMMU_PTC_FLUSH_1" even when the "val" is zero. > > So I just copied Pavan's original work here, after applied this, the > SMMU works correctly: > > - val = VA_PAGE_TO_PA_HI(pte, page); > - if (val) > + if (!pte) { > + smmu_write(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH); > + return; > + } > + > + if (of_machine_is_compatible("nvidia,tegra124")) { This check should be replaced by some flag so we don't have to compare strings every time the PTC is flushed. Thierry
On 01/08/2014 09:45 PM, Thierry Reding wrote: > On Tue, Jan 07, 2014 at 01:25:37PM +0800, Mark Zhang wrote: >> On 12/05/2013 08:25 PM, Hiroshi Doyu wrote: > [...] >>> @@ -526,6 +530,21 @@ static int smmu_setup_regs(struct smmu_device *smmu) >>> return 0; >>> } >>> >>> +static void flush_ptc_by_addr(struct smmu_device *smmu, unsigned long *pte, >>> + struct page *page) >>> +{ >>> + u32 val; >>> + >>> + val = VA_PAGE_TO_PA_HI(pte, page); >>> + if (val) >>> + smmu_write(smmu, val, SMMU_PTC_FLUSH_1); >>> + >> >> This is not correct, according to my tests. We should write >> "SMMU_PTC_FLUSH_1" even when the "val" is zero. >> >> So I just copied Pavan's original work here, after applied this, the >> SMMU works correctly: >> >> - val = VA_PAGE_TO_PA_HI(pte, page); >> - if (val) >> + if (!pte) { >> + smmu_write(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH); >> + return; >> + } >> + >> + if (of_machine_is_compatible("nvidia,tegra124")) { > > This check should be replaced by some flag so we don't have to compare > strings every time the PTC is flushed. > Yes, I believe Hiroshi will consider this in his v8 series. Mark > Thierry > -- To unsubscribe from this list: send the line "unsubscribe linux-tegra" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c index b5737f9..04e7199 100644 --- a/drivers/iommu/tegra-smmu.c +++ b/drivers/iommu/tegra-smmu.c @@ -101,6 +101,8 @@ enum { #define SMMU_PTC_FLUSH_TYPE_ADR 1 #define SMMU_PTC_FLUSH_ADR_SHIFT 4 +#define SMMU_PTC_FLUSH_1 0x9b8 + #define SMMU_ASID_SECURITY 0x38 #define SMMU_STATS_CACHE_COUNT_BASE 0x1f0 @@ -143,7 +145,7 @@ enum { #define SMMU_PDIR_SHIFT 12 #define SMMU_PDE_SHIFT 12 #define SMMU_PTE_SHIFT 12 -#define SMMU_PFN_MASK 0x000fffff +#define SMMU_PFN_MASK 0x0fffffff #define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12) #define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22) @@ -301,6 +303,8 @@ static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs) #define VA_PAGE_TO_PA(va, page) \ (page_to_phys(page) + ((unsigned long)(va) & ~PAGE_MASK)) +#define VA_PAGE_TO_PA_HI(va, page) (u32)((u64)page_to_phys(page) >> 32) + #define FLUSH_CPU_DCACHE(va, page, size) \ do { \ unsigned long _pa_ = VA_PAGE_TO_PA(va, page); \ @@ -526,6 +530,21 @@ static int smmu_setup_regs(struct smmu_device *smmu) return 0; } +static void flush_ptc_by_addr(struct smmu_device *smmu, unsigned long *pte, + struct page *page) +{ + u32 val; + + val = VA_PAGE_TO_PA_HI(pte, page); + if (val) + smmu_write(smmu, val, SMMU_PTC_FLUSH_1); + + val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page); + smmu_write(smmu, val, SMMU_PTC_FLUSH); + + FLUSH_SMMU_REGS(smmu); +} + static void flush_ptc_and_tlb(struct smmu_device *smmu, struct smmu_as *as, dma_addr_t iova, unsigned long *pte, struct page *page, int is_pde) @@ -535,9 +554,8 @@ static void flush_ptc_and_tlb(struct smmu_device *smmu, ? SMMU_TLB_FLUSH_VA(iova, SECTION) : SMMU_TLB_FLUSH_VA(iova, GROUP); - val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page); - smmu_write(smmu, val, SMMU_PTC_FLUSH); - FLUSH_SMMU_REGS(smmu); + flush_ptc_by_addr(smmu, pte, page); + val = tlb_flush_va | SMMU_TLB_FLUSH_ASID_MATCH__ENABLE | (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT); @@ -702,9 +720,9 @@ static int alloc_pdir(struct smmu_as *as) for (pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++) pdir[pdn] = _PDE_VACANT(pdn); FLUSH_CPU_DCACHE(pdir, as->pdir_page, SMMU_PDIR_SIZE); - val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pdir, as->pdir_page); - smmu_write(smmu, val, SMMU_PTC_FLUSH); - FLUSH_SMMU_REGS(as->smmu); + + flush_ptc_by_addr(as->smmu, pdir, page); + val = SMMU_TLB_FLUSH_VA_MATCH_ALL | SMMU_TLB_FLUSH_ASID_MATCH__ENABLE | (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
Add support for more than 32 bit physical address. If physical address space is 32bit, there will be no register write happening. Based on Pavan's internal patch. Signed-off-by: Hiroshi Doyu <hdoyu@nvidia.com> Cc: Pavan Kunapuli <pkunapuli@nvidia.com> --- drivers/iommu/tegra-smmu.c | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-)