Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S965384AbbFJPij (ORCPT ); Wed, 10 Jun 2015 11:38:39 -0400 Received: from ip4-83-240-67-251.cust.nbox.cz ([83.240.67.251]:36154 "EHLO ip4-83-240-18-248.cust.nbox.cz" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933862AbbFJP1w (ORCPT ); Wed, 10 Jun 2015 11:27:52 -0400 From: Jiri Slaby To: stable@vger.kernel.org Cc: linux-kernel@vger.kernel.org, Joerg Roedel , Jiri Slaby Subject: [PATCH 3.12 097/111] iommu/amd: Return the pte page-size in fetch_pte Date: Wed, 10 Jun 2015 17:27:26 +0200 Message-Id: <57bdeb720c85f309ffeb487963d3f46b370b551f.1433943052.git.jslaby@suse.cz> X-Mailer: git-send-email 2.4.2 In-Reply-To: <93091169a673f49c2574cddf1ef858cf0704f646.1433943052.git.jslaby@suse.cz> References: <93091169a673f49c2574cddf1ef858cf0704f646.1433943052.git.jslaby@suse.cz> In-Reply-To: References: Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5172 Lines: 162 From: Joerg Roedel 3.12-stable review patch. If anyone has any objections, please let me know. =============== commit 3039ca1b1c37e61cc9239dbb3903db55141ecabd upstream. Extend the fetch_pte function to also return the page-size that is mapped by the returned pte. Tested-by: Suravee Suthikulpanit Signed-off-by: Joerg Roedel Signed-off-by: Jiri Slaby --- drivers/iommu/amd_iommu.c | 52 ++++++++++++++++++++++++----------------- drivers/iommu/amd_iommu_types.h | 6 +++++ 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c index 67644e960592..976cf15744a9 100644 --- a/drivers/iommu/amd_iommu.c +++ b/drivers/iommu/amd_iommu.c @@ -1376,7 +1376,9 @@ static u64 *alloc_pte(struct protection_domain *domain, * This function checks if there is a PTE for a given dma address. If * there is one, it returns the pointer to it. */ -static u64 *fetch_pte(struct protection_domain *domain, unsigned long address) +static u64 *fetch_pte(struct protection_domain *domain, + unsigned long address, + unsigned long *page_size) { int level; u64 *pte; @@ -1384,8 +1386,9 @@ static u64 *fetch_pte(struct protection_domain *domain, unsigned long address) if (address > PM_LEVEL_SIZE(domain->mode)) return NULL; - level = domain->mode - 1; - pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; + level = domain->mode - 1; + pte = &domain->pt_root[PM_LEVEL_INDEX(level, address)]; + *page_size = PTE_LEVEL_PAGE_SIZE(level); while (level > 0) { @@ -1394,19 +1397,9 @@ static u64 *fetch_pte(struct protection_domain *domain, unsigned long address) return NULL; /* Large PTE */ - if (PM_PTE_LEVEL(*pte) == 0x07) { - unsigned long pte_mask, __pte; - - /* - * If we have a series of large PTEs, make - * sure to return a pointer to the first one. - */ - pte_mask = PTE_PAGE_SIZE(*pte); - pte_mask = ~((PAGE_SIZE_PTE_COUNT(pte_mask) << 3) - 1); - __pte = ((unsigned long)pte) & pte_mask; - - return (u64 *)__pte; - } + if (PM_PTE_LEVEL(*pte) == 7 || + PM_PTE_LEVEL(*pte) == 0) + break; /* No level skipping support yet */ if (PM_PTE_LEVEL(*pte) != level) @@ -1415,8 +1408,21 @@ static u64 *fetch_pte(struct protection_domain *domain, unsigned long address) level -= 1; /* Walk to the next level */ - pte = IOMMU_PTE_PAGE(*pte); - pte = &pte[PM_LEVEL_INDEX(level, address)]; + pte = IOMMU_PTE_PAGE(*pte); + pte = &pte[PM_LEVEL_INDEX(level, address)]; + *page_size = PTE_LEVEL_PAGE_SIZE(level); + } + + if (PM_PTE_LEVEL(*pte) == 0x07) { + unsigned long pte_mask; + + /* + * If we have a series of large PTEs, make + * sure to return a pointer to the first one. + */ + *page_size = pte_mask = PTE_PAGE_SIZE(*pte); + pte_mask = ~((PAGE_SIZE_PTE_COUNT(pte_mask) << 3) - 1); + pte = (u64 *)(((unsigned long)pte) & pte_mask); } return pte; @@ -1474,6 +1480,7 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom, unsigned long page_size) { unsigned long long unmap_size, unmapped; + unsigned long pte_pgsize; u64 *pte; BUG_ON(!is_power_of_2(page_size)); @@ -1482,7 +1489,7 @@ static unsigned long iommu_unmap_page(struct protection_domain *dom, while (unmapped < page_size) { - pte = fetch_pte(dom, bus_addr); + pte = fetch_pte(dom, bus_addr, &pte_pgsize); if (!pte) { /* @@ -1725,7 +1732,8 @@ static int alloc_new_range(struct dma_ops_domain *dma_dom, for (i = dma_dom->aperture[index]->offset; i < dma_dom->aperture_size; i += PAGE_SIZE) { - u64 *pte = fetch_pte(&dma_dom->domain, i); + unsigned long pte_pgsize; + u64 *pte = fetch_pte(&dma_dom->domain, i, &pte_pgsize); if (!pte || !IOMMU_PTE_PRESENT(*pte)) continue; @@ -3439,14 +3447,14 @@ static phys_addr_t amd_iommu_iova_to_phys(struct iommu_domain *dom, dma_addr_t iova) { struct protection_domain *domain = dom->priv; - unsigned long offset_mask; + unsigned long offset_mask, pte_pgsize; phys_addr_t paddr; u64 *pte, __pte; if (domain->mode == PAGE_MODE_NONE) return iova; - pte = fetch_pte(domain, iova); + pte = fetch_pte(domain, iova, &pte_pgsize); if (!pte || !IOMMU_PTE_PRESENT(*pte)) return 0; diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h index e400fbe411de..97e81fe5c330 100644 --- a/drivers/iommu/amd_iommu_types.h +++ b/drivers/iommu/amd_iommu_types.h @@ -276,6 +276,12 @@ #define PTE_PAGE_SIZE(pte) \ (1ULL << (1 + ffz(((pte) | 0xfffULL)))) +/* + * Takes a page-table level and returns the default page-size for this level + */ +#define PTE_LEVEL_PAGE_SIZE(level) \ + (1ULL << (12 + (9 * (level)))) + #define IOMMU_PTE_P (1ULL << 0) #define IOMMU_PTE_TV (1ULL << 1) #define IOMMU_PTE_U (1ULL << 59) -- 2.4.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/