]> Pileus Git - ~andy/linux/blobdiff - lib/swiotlb.c
x86: Don't panic if can not alloc buffer for swiotlb
[~andy/linux] / lib / swiotlb.c
index 196b06984decbc0263b74eda9f34e94f425eb070..bfe02b8fc55b3d1c383832148e4e5aa44e0ef87c 100644 (file)
@@ -122,11 +122,18 @@ static dma_addr_t swiotlb_virt_to_bus(struct device *hwdev,
        return phys_to_dma(hwdev, virt_to_phys(address));
 }
 
+static bool no_iotlb_memory;
+
 void swiotlb_print_info(void)
 {
        unsigned long bytes = io_tlb_nslabs << IO_TLB_SHIFT;
        unsigned char *vstart, *vend;
 
+       if (no_iotlb_memory) {
+               pr_warn("software IO TLB: No low mem\n");
+               return;
+       }
+
        vstart = phys_to_virt(io_tlb_start);
        vend = phys_to_virt(io_tlb_end);
 
@@ -136,7 +143,7 @@ void swiotlb_print_info(void)
               bytes >> 20, vstart, vend - 1);
 }
 
-void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
+int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
 {
        void *v_overflow_buffer;
        unsigned long i, bytes;
@@ -150,9 +157,10 @@ void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
        /*
         * Get the overflow emergency buffer
         */
-       v_overflow_buffer = alloc_bootmem_low_pages(PAGE_ALIGN(io_tlb_overflow));
+       v_overflow_buffer = alloc_bootmem_low_pages_nopanic(
+                                               PAGE_ALIGN(io_tlb_overflow));
        if (!v_overflow_buffer)
-               panic("Cannot allocate SWIOTLB overflow buffer!\n");
+               return -ENOMEM;
 
        io_tlb_overflow_buffer = __pa(v_overflow_buffer);
 
@@ -169,15 +177,19 @@ void __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
 
        if (verbose)
                swiotlb_print_info();
+
+       return 0;
 }
 
 /*
  * Statically reserve bounce buffer space and initialize bounce buffer data
  * structures for the software IO TLB used to implement the DMA API.
  */
-static void __init
-swiotlb_init_with_default_size(size_t default_size, int verbose)
+void  __init
+swiotlb_init(int verbose)
 {
+       /* default to 64MB */
+       size_t default_size = 64UL<<20;
        unsigned char *vstart;
        unsigned long bytes;
 
@@ -188,20 +200,16 @@ swiotlb_init_with_default_size(size_t default_size, int verbose)
 
        bytes = io_tlb_nslabs << IO_TLB_SHIFT;
 
-       /*
-        * Get IO TLB memory from the low pages
-        */
-       vstart = alloc_bootmem_low_pages(PAGE_ALIGN(bytes));
-       if (!vstart)
-               panic("Cannot allocate SWIOTLB buffer");
-
-       swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose);
-}
+       /* Get IO TLB memory from the low pages */
+       vstart = alloc_bootmem_low_pages_nopanic(PAGE_ALIGN(bytes));
+       if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose))
+               return;
 
-void __init
-swiotlb_init(int verbose)
-{
-       swiotlb_init_with_default_size(64 * (1<<20), verbose);  /* default to 64MB */
+       if (io_tlb_start)
+               free_bootmem(io_tlb_start,
+                                PAGE_ALIGN(io_tlb_nslabs << IO_TLB_SHIFT));
+       pr_warn("Cannot allocate SWIOTLB buffer");
+       no_iotlb_memory = true;
 }
 
 /*
@@ -405,6 +413,9 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
        unsigned long offset_slots;
        unsigned long max_slots;
 
+       if (no_iotlb_memory)
+               panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer");
+
        mask = dma_get_seg_boundary(hwdev);
 
        tbl_dma_addr &= mask;