amd-iommu: handle page table allocation failures in dma_ops code
[sfrench/cifs-2.6.git] / arch / x86 / kernel / amd_iommu.c
index a97db99dad52fedd4bbcf6fe9d46bed8784f5e1f..a467addb44b7b93d14fb556649042b5c47f46a1e 100644 (file)
@@ -55,7 +55,9 @@ struct iommu_cmd {
 static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
                             struct unity_map_entry *e);
 static struct dma_ops_domain *find_protection_domain(u16 devid);
-
+static u64* alloc_pte(struct protection_domain *dom,
+                     unsigned long address, u64
+                     **pte_page, gfp_t gfp);
 
 #ifdef CONFIG_AMD_IOMMU_STATS
 
@@ -468,7 +470,7 @@ static int iommu_map_page(struct protection_domain *dom,
                          unsigned long phys_addr,
                          int prot)
 {
-       u64 __pte, *pte, *page;
+       u64 __pte, *pte;
 
        bus_addr  = PAGE_ALIGN(bus_addr);
        phys_addr = PAGE_ALIGN(phys_addr);
@@ -477,27 +479,7 @@ static int iommu_map_page(struct protection_domain *dom,
        if (bus_addr > IOMMU_MAP_SIZE_L3 || !(prot & IOMMU_PROT_MASK))
                return -EINVAL;
 
-       pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(bus_addr)];
-
-       if (!IOMMU_PTE_PRESENT(*pte)) {
-               page = (u64 *)get_zeroed_page(GFP_KERNEL);
-               if (!page)
-                       return -ENOMEM;
-               *pte = IOMMU_L2_PDE(virt_to_phys(page));
-       }
-
-       pte = IOMMU_PTE_PAGE(*pte);
-       pte = &pte[IOMMU_PTE_L1_INDEX(bus_addr)];
-
-       if (!IOMMU_PTE_PRESENT(*pte)) {
-               page = (u64 *)get_zeroed_page(GFP_KERNEL);
-               if (!page)
-                       return -ENOMEM;
-               *pte = IOMMU_L1_PDE(virt_to_phys(page));
-       }
-
-       pte = IOMMU_PTE_PAGE(*pte);
-       pte = &pte[IOMMU_PTE_L0_INDEX(bus_addr)];
+       pte = alloc_pte(dom, bus_addr, NULL, GFP_KERNEL);
 
        if (IOMMU_PTE_PRESENT(*pte))
                return -EBUSY;
@@ -595,7 +577,8 @@ static int dma_ops_unity_map(struct dma_ops_domain *dma_dom,
                 * as allocated in the aperture
                 */
                if (addr < dma_dom->aperture_size)
-                       __set_bit(addr >> PAGE_SHIFT, dma_dom->bitmap);
+                       __set_bit(addr >> PAGE_SHIFT,
+                                 dma_dom->aperture.bitmap);
        }
 
        return 0;
@@ -656,11 +639,12 @@ static unsigned long dma_ops_alloc_addresses(struct device *dev,
                dom->need_flush = true;
        }
 
-       address = iommu_area_alloc(dom->bitmap, limit, dom->next_bit, pages,
-                                  0 , boundary_size, align_mask);
+       address = iommu_area_alloc(dom->aperture.bitmap, limit, dom->next_bit,
+                                  pages, 0 , boundary_size, align_mask);
        if (address == -1) {
-               address = iommu_area_alloc(dom->bitmap, limit, 0, pages,
-                               0, boundary_size, align_mask);
+               address = iommu_area_alloc(dom->aperture.bitmap, limit, 0,
+                                          pages, 0, boundary_size,
+                                          align_mask);
                dom->need_flush = true;
        }
 
@@ -685,7 +669,7 @@ static void dma_ops_free_addresses(struct dma_ops_domain *dom,
                                   unsigned int pages)
 {
        address >>= PAGE_SHIFT;
-       iommu_area_free(dom->bitmap, address, pages);
+       iommu_area_free(dom->aperture.bitmap, address, pages);
 
        if (address >= dom->next_bit)
                dom->need_flush = true;
@@ -741,7 +725,7 @@ static void dma_ops_reserve_addresses(struct dma_ops_domain *dom,
        if (start_page + pages > last_page)
                pages = last_page - start_page;
 
-       iommu_area_reserve(dom->bitmap, start_page, pages);
+       iommu_area_reserve(dom->aperture.bitmap, start_page, pages);
 }
 
 static void free_pagetable(struct protection_domain *domain)
@@ -785,9 +769,7 @@ static void dma_ops_domain_free(struct dma_ops_domain *dom)
 
        free_pagetable(&dom->domain);
 
-       kfree(dom->pte_pages);
-
-       kfree(dom->bitmap);
+       free_page((unsigned long)dom->aperture.bitmap);
 
        kfree(dom);
 }
@@ -826,16 +808,15 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
        dma_dom->domain.priv = dma_dom;
        if (!dma_dom->domain.pt_root)
                goto free_dma_dom;
-       dma_dom->aperture_size = (1ULL << order);
-       dma_dom->bitmap = kzalloc(dma_dom->aperture_size / (PAGE_SIZE * 8),
-                                 GFP_KERNEL);
-       if (!dma_dom->bitmap)
+       dma_dom->aperture_size = APERTURE_RANGE_SIZE;
+       dma_dom->aperture.bitmap = (void *)get_zeroed_page(GFP_KERNEL);
+       if (!dma_dom->aperture.bitmap)
                goto free_dma_dom;
        /*
         * mark the first page as allocated so we never return 0 as
         * a valid dma-address. So we can use 0 as error value
         */
-       dma_dom->bitmap[0] = 1;
+       dma_dom->aperture.bitmap[0] = 1;
        dma_dom->next_bit = 0;
 
        dma_dom->need_flush = false;
@@ -854,13 +835,9 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
        /*
         * At the last step, build the page tables so we don't need to
         * allocate page table pages in the dma_ops mapping/unmapping
-        * path.
+        * path for the first 128MB of dma address space.
         */
        num_pte_pages = dma_dom->aperture_size / (PAGE_SIZE * 512);
-       dma_dom->pte_pages = kzalloc(num_pte_pages * sizeof(void *),
-                       GFP_KERNEL);
-       if (!dma_dom->pte_pages)
-               goto free_dma_dom;
 
        l2_pde = (u64 *)get_zeroed_page(GFP_KERNEL);
        if (l2_pde == NULL)
@@ -869,10 +846,11 @@ static struct dma_ops_domain *dma_ops_domain_alloc(struct amd_iommu *iommu,
        dma_dom->domain.pt_root[0] = IOMMU_L2_PDE(virt_to_phys(l2_pde));
 
        for (i = 0; i < num_pte_pages; ++i) {
-               dma_dom->pte_pages[i] = (u64 *)get_zeroed_page(GFP_KERNEL);
-               if (!dma_dom->pte_pages[i])
+               u64 **pte_page = &dma_dom->aperture.pte_pages[i];
+               *pte_page = (u64 *)get_zeroed_page(GFP_KERNEL);
+               if (!*pte_page)
                        goto free_dma_dom;
-               address = virt_to_phys(dma_dom->pte_pages[i]);
+               address = virt_to_phys(*pte_page);
                l2_pde[i] = IOMMU_L1_PDE(address);
        }
 
@@ -1143,6 +1121,61 @@ static int get_device_resources(struct device *dev,
        return 1;
 }
 
+/*
+ * If the pte_page is not yet allocated this function is called
+ */
+static u64* alloc_pte(struct protection_domain *dom,
+                     unsigned long address, u64 **pte_page, gfp_t gfp)
+{
+       u64 *pte, *page;
+
+       pte = &dom->pt_root[IOMMU_PTE_L2_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte)) {
+               page = (u64 *)get_zeroed_page(gfp);
+               if (!page)
+                       return NULL;
+               *pte = IOMMU_L2_PDE(virt_to_phys(page));
+       }
+
+       pte = IOMMU_PTE_PAGE(*pte);
+       pte = &pte[IOMMU_PTE_L1_INDEX(address)];
+
+       if (!IOMMU_PTE_PRESENT(*pte)) {
+               page = (u64 *)get_zeroed_page(gfp);
+               if (!page)
+                       return NULL;
+               *pte = IOMMU_L1_PDE(virt_to_phys(page));
+       }
+
+       pte = IOMMU_PTE_PAGE(*pte);
+
+       if (pte_page)
+               *pte_page = pte;
+
+       pte = &pte[IOMMU_PTE_L0_INDEX(address)];
+
+       return pte;
+}
+
+/*
+ * This function fetches the PTE for a given address in the aperture
+ */
+static u64* dma_ops_get_pte(struct dma_ops_domain *dom,
+                           unsigned long address)
+{
+       struct aperture_range *aperture = &dom->aperture;
+       u64 *pte, *pte_page;
+
+       pte = aperture->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+       if (!pte) {
+               pte = alloc_pte(&dom->domain, address, &pte_page, GFP_ATOMIC);
+               aperture->pte_pages[IOMMU_PTE_L1_INDEX(address)] = pte_page;
+       }
+
+       return pte;
+}
+
 /*
  * This is the generic map function. It maps one 4kb page at paddr to
  * the given address in the DMA address space for the domain.
@@ -1159,8 +1192,9 @@ static dma_addr_t dma_ops_domain_map(struct amd_iommu *iommu,
 
        paddr &= PAGE_MASK;
 
-       pte  = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
-       pte += IOMMU_PTE_L0_INDEX(address);
+       pte  = dma_ops_get_pte(dom, address);
+       if (!pte)
+               return bad_dma_address;
 
        __pte = paddr | IOMMU_PTE_P | IOMMU_PTE_FC;
 
@@ -1192,7 +1226,7 @@ static void dma_ops_domain_unmap(struct amd_iommu *iommu,
 
        WARN_ON(address & ~PAGE_MASK || address >= dom->aperture_size);
 
-       pte  = dom->pte_pages[IOMMU_PTE_L1_INDEX(address)];
+       pte  = dom->aperture.pte_pages[IOMMU_PTE_L1_INDEX(address)];
        pte += IOMMU_PTE_L0_INDEX(address);
 
        WARN_ON(!*pte);
@@ -1216,7 +1250,7 @@ static dma_addr_t __map_single(struct device *dev,
                               u64 dma_mask)
 {
        dma_addr_t offset = paddr & ~PAGE_MASK;
-       dma_addr_t address, start;
+       dma_addr_t address, start, ret;
        unsigned int pages;
        unsigned long align_mask = 0;
        int i;
@@ -1239,7 +1273,10 @@ static dma_addr_t __map_single(struct device *dev,
 
        start = address;
        for (i = 0; i < pages; ++i) {
-               dma_ops_domain_map(iommu, dma_dom, start, paddr, dir);
+               ret = dma_ops_domain_map(iommu, dma_dom, start, paddr, dir);
+               if (ret == bad_dma_address)
+                       goto out_unmap;
+
                paddr += PAGE_SIZE;
                start += PAGE_SIZE;
        }
@@ -1255,6 +1292,17 @@ static dma_addr_t __map_single(struct device *dev,
 
 out:
        return address;
+
+out_unmap:
+
+       for (--i; i >= 0; --i) {
+               start -= PAGE_SIZE;
+               dma_ops_domain_unmap(iommu, dma_dom, start);
+       }
+
+       dma_ops_free_addresses(dma_dom, address, pages);
+
+       return bad_dma_address;
 }
 
 /*