Merge branch 'stable/for-linus-5.12' of git://git.kernel.org/pub/scm/linux/kernel...
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Feb 2021 21:59:32 +0000 (13:59 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 26 Feb 2021 21:59:32 +0000 (13:59 -0800)
Pull swiotlb updates from Konrad Rzeszutek Wilk:
 "Two memory encryption related patches (SWIOTLB is enabled by default
  for AMD-SEV):

   - Add support for alignment so that NVME can properly work

   - Keep track of requested DMA buffers length, as underlaying hardware
     devices can trip SWIOTLB to bounce too much and crash the kernel

  And a tiny fix to use proper APIs in drivers"

* 'stable/for-linus-5.12' of git://git.kernel.org/pub/scm/linux/kernel/git/konrad/swiotlb:
  swiotlb: Validate bounce size in the sync/unmap path
  nvme-pci: set min_align_mask
  swiotlb: respect min_align_mask
  swiotlb: don't modify orig_addr in swiotlb_tbl_sync_single
  swiotlb: refactor swiotlb_tbl_map_single
  swiotlb: clean up swiotlb_tbl_unmap_single
  swiotlb: factor out a nr_slots helper
  swiotlb: factor out an io_tlb_offset helper
  swiotlb: add a IO_TLB_SIZE define
  driver core: add a min_align_mask field to struct device_dma_parameters
  sdhci: stop poking into swiotlb internals

drivers/mmc/host/sdhci.c
drivers/nvme/host/pci.c
include/linux/device.h
include/linux/dma-mapping.h
include/linux/swiotlb.h
kernel/dma/swiotlb.c

index 646823ddd31715479cbbf63516a2fdfff956ec01..2d73407ee52ec7188e73eaf399549d4c7743df24 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/slab.h>
 #include <linux/scatterlist.h>
 #include <linux/sizes.h>
-#include <linux/swiotlb.h>
 #include <linux/regulator/consumer.h>
 #include <linux/pm_runtime.h>
 #include <linux/of.h>
@@ -4582,12 +4581,8 @@ int sdhci_setup_host(struct sdhci_host *host)
                mmc->max_segs = SDHCI_MAX_SEGS;
        } else if (host->flags & SDHCI_USE_SDMA) {
                mmc->max_segs = 1;
-               if (swiotlb_max_segment()) {
-                       unsigned int max_req_size = (1 << IO_TLB_SHIFT) *
-                                               IO_TLB_SEGSIZE;
-                       mmc->max_req_size = min(mmc->max_req_size,
-                                               max_req_size);
-               }
+               mmc->max_req_size = min_t(size_t, mmc->max_req_size,
+                                         dma_max_mapping_size(mmc_dev(mmc)));
        } else { /* PIO */
                mmc->max_segs = SDHCI_MAX_SEGS;
        }
index 7b6632c00ffd01072d5b3aff63f175d57278938a..38b0d694dfc9102b4c40d6cdec00e2ed8018dfea 100644 (file)
@@ -2632,6 +2632,7 @@ static void nvme_reset_work(struct work_struct *work)
         * Don't limit the IOMMU merged segment size.
         */
        dma_set_max_seg_size(dev->dev, 0xffffffff);
+       dma_set_min_align_mask(dev->dev, NVME_CTRL_PAGE_SIZE - 1);
 
        mutex_unlock(&dev->shutdown_lock);
 
index 7619a84f8ce4abef94579bb1881bb95b8c08e834..ba660731bd258279d8c9b5513a90015b22fad3e0 100644 (file)
@@ -291,6 +291,7 @@ struct device_dma_parameters {
         * sg limitations.
         */
        unsigned int max_segment_size;
+       unsigned int min_align_mask;
        unsigned long segment_boundary_mask;
 };
 
index fbfa3f5abd9498183e19ad6ab1b809d2aca9d62a..2a984cb4d1e037645c8e599223508f1b6d663abe 100644 (file)
@@ -509,6 +509,22 @@ static inline int dma_set_seg_boundary(struct device *dev, unsigned long mask)
        return -EIO;
 }
 
+static inline unsigned int dma_get_min_align_mask(struct device *dev)
+{
+       if (dev->dma_parms)
+               return dev->dma_parms->min_align_mask;
+       return 0;
+}
+
+static inline int dma_set_min_align_mask(struct device *dev,
+               unsigned int min_align_mask)
+{
+       if (WARN_ON_ONCE(!dev->dma_parms))
+               return -EIO;
+       dev->dma_parms->min_align_mask = min_align_mask;
+       return 0;
+}
+
 static inline int dma_get_cache_alignment(void)
 {
 #ifdef ARCH_DMA_MINALIGN
index d9c9fc9ca5d217fb74c58a3f3a7abfde395ccfbe..5857a937c63722a3c75a24e098fa4740de0c32e8 100644 (file)
@@ -29,6 +29,7 @@ enum swiotlb_force {
  * controllable.
  */
 #define IO_TLB_SHIFT 11
+#define IO_TLB_SIZE (1 << IO_TLB_SHIFT)
 
 /* default to 64MB */
 #define IO_TLB_DEFAULT_SIZE (64UL<<20)
index 7c42df6e61001dc0c35160109f9a8fbeae629bef..c10e855a03bc1690b473e44e4c3e1c3b6ecc0d50 100644 (file)
@@ -50,9 +50,6 @@
 #define CREATE_TRACE_POINTS
 #include <trace/events/swiotlb.h>
 
-#define OFFSET(val,align) ((unsigned long)     \
-                          ( (val) & ( (align) - 1)))
-
 #define SLABS_PER_PAGE (1 << (PAGE_SHIFT - IO_TLB_SHIFT))
 
 /*
@@ -102,6 +99,11 @@ static unsigned int max_segment;
 #define INVALID_PHYS_ADDR (~(phys_addr_t)0)
 static phys_addr_t *io_tlb_orig_addr;
 
+/*
+ * The mapped buffer's size should be validated during a sync operation.
+ */
+static size_t *io_tlb_orig_size;
+
 /*
  * Protect the above data structures in the map and unmap calls
  */
@@ -171,7 +173,7 @@ void __init swiotlb_adjust_size(unsigned long new_size)
         * adjust/expand SWIOTLB size for their use.
         */
        if (!io_tlb_nslabs) {
-               size = ALIGN(new_size, 1 << IO_TLB_SHIFT);
+               size = ALIGN(new_size, IO_TLB_SIZE);
                io_tlb_nslabs = size >> IO_TLB_SHIFT;
                io_tlb_nslabs = ALIGN(io_tlb_nslabs, IO_TLB_SEGSIZE);
 
@@ -192,6 +194,16 @@ void swiotlb_print_info(void)
               bytes >> 20);
 }
 
+static inline unsigned long io_tlb_offset(unsigned long val)
+{
+       return val & (IO_TLB_SEGSIZE - 1);
+}
+
+static inline unsigned long nr_slots(u64 val)
+{
+       return DIV_ROUND_UP(val, IO_TLB_SIZE);
+}
+
 /*
  * Early SWIOTLB allocation may be too early to allow an architecture to
  * perform the desired operations.  This function allows the architecture to
@@ -240,9 +252,16 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
                panic("%s: Failed to allocate %zu bytes align=0x%lx\n",
                      __func__, alloc_size, PAGE_SIZE);
 
+       alloc_size = PAGE_ALIGN(io_tlb_nslabs * sizeof(size_t));
+       io_tlb_orig_size = memblock_alloc(alloc_size, PAGE_SIZE);
+       if (!io_tlb_orig_size)
+               panic("%s: Failed to allocate %zu bytes align=0x%lx\n",
+                     __func__, alloc_size, PAGE_SIZE);
+
        for (i = 0; i < io_tlb_nslabs; i++) {
-               io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
+               io_tlb_list[i] = IO_TLB_SEGSIZE - io_tlb_offset(i);
                io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
+               io_tlb_orig_size[i] = 0;
        }
        io_tlb_index = 0;
        no_iotlb_memory = false;
@@ -363,7 +382,7 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
         * between io_tlb_start and io_tlb_end.
         */
        io_tlb_list = (unsigned int *)__get_free_pages(GFP_KERNEL,
-                                     get_order(io_tlb_nslabs * sizeof(int)));
+                                     get_order(io_tlb_nslabs * sizeof(int)));
        if (!io_tlb_list)
                goto cleanup3;
 
@@ -374,9 +393,18 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
        if (!io_tlb_orig_addr)
                goto cleanup4;
 
+       io_tlb_orig_size = (size_t *)
+               __get_free_pages(GFP_KERNEL,
+                                get_order(io_tlb_nslabs *
+                                          sizeof(size_t)));
+       if (!io_tlb_orig_size)
+               goto cleanup5;
+
+
        for (i = 0; i < io_tlb_nslabs; i++) {
-               io_tlb_list[i] = IO_TLB_SEGSIZE - OFFSET(i, IO_TLB_SEGSIZE);
+               io_tlb_list[i] = IO_TLB_SEGSIZE - io_tlb_offset(i);
                io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
+               io_tlb_orig_size[i] = 0;
        }
        io_tlb_index = 0;
        no_iotlb_memory = false;
@@ -389,6 +417,10 @@ swiotlb_late_init_with_tbl(char *tlb, unsigned long nslabs)
 
        return 0;
 
+cleanup5:
+       free_pages((unsigned long)io_tlb_orig_addr, get_order(io_tlb_nslabs *
+                                                             sizeof(phys_addr_t)));
+
 cleanup4:
        free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
                                                         sizeof(int)));
@@ -404,6 +436,8 @@ void __init swiotlb_exit(void)
                return;
 
        if (late_alloc) {
+               free_pages((unsigned long)io_tlb_orig_size,
+                          get_order(io_tlb_nslabs * sizeof(size_t)));
                free_pages((unsigned long)io_tlb_orig_addr,
                           get_order(io_tlb_nslabs * sizeof(phys_addr_t)));
                free_pages((unsigned long)io_tlb_list, get_order(io_tlb_nslabs *
@@ -413,6 +447,8 @@ void __init swiotlb_exit(void)
        } else {
                memblock_free_late(__pa(io_tlb_orig_addr),
                                   PAGE_ALIGN(io_tlb_nslabs * sizeof(phys_addr_t)));
+               memblock_free_late(__pa(io_tlb_orig_size),
+                                  PAGE_ALIGN(io_tlb_nslabs * sizeof(size_t)));
                memblock_free_late(__pa(io_tlb_list),
                                   PAGE_ALIGN(io_tlb_nslabs * sizeof(int)));
                memblock_free_late(io_tlb_start,
@@ -461,79 +497,71 @@ static void swiotlb_bounce(phys_addr_t orig_addr, phys_addr_t tlb_addr,
        }
 }
 
-phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
-               size_t mapping_size, size_t alloc_size,
-               enum dma_data_direction dir, unsigned long attrs)
-{
-       dma_addr_t tbl_dma_addr = phys_to_dma_unencrypted(hwdev, io_tlb_start);
-       unsigned long flags;
-       phys_addr_t tlb_addr;
-       unsigned int nslots, stride, index, wrap;
-       int i;
-       unsigned long mask;
-       unsigned long offset_slots;
-       unsigned long max_slots;
-       unsigned long tmp_io_tlb_used;
-
-       if (no_iotlb_memory)
-               panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer");
-
-       if (mem_encrypt_active())
-               pr_warn_once("Memory encryption is active and system is using DMA bounce buffers\n");
+#define slot_addr(start, idx)  ((start) + ((idx) << IO_TLB_SHIFT))
 
-       if (mapping_size > alloc_size) {
-               dev_warn_once(hwdev, "Invalid sizes (mapping: %zd bytes, alloc: %zd bytes)",
-                             mapping_size, alloc_size);
-               return (phys_addr_t)DMA_MAPPING_ERROR;
-       }
+/*
+ * Return the offset into a iotlb slot required to keep the device happy.
+ */
+static unsigned int swiotlb_align_offset(struct device *dev, u64 addr)
+{
+       return addr & dma_get_min_align_mask(dev) & (IO_TLB_SIZE - 1);
+}
 
-       mask = dma_get_seg_boundary(hwdev);
+/*
+ * Carefully handle integer overflow which can occur when boundary_mask == ~0UL.
+ */
+static inline unsigned long get_max_slots(unsigned long boundary_mask)
+{
+       if (boundary_mask == ~0UL)
+               return 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
+       return nr_slots(boundary_mask + 1);
+}
 
-       tbl_dma_addr &= mask;
+static unsigned int wrap_index(unsigned int index)
+{
+       if (index >= io_tlb_nslabs)
+               return 0;
+       return index;
+}
 
-       offset_slots = ALIGN(tbl_dma_addr, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+/*
+ * Find a suitable number of IO TLB entries size that will fit this request and
+ * allocate a buffer from that IO TLB pool.
+ */
+static int find_slots(struct device *dev, phys_addr_t orig_addr,
+               size_t alloc_size)
+{
+       unsigned long boundary_mask = dma_get_seg_boundary(dev);
+       dma_addr_t tbl_dma_addr =
+               phys_to_dma_unencrypted(dev, io_tlb_start) & boundary_mask;
+       unsigned long max_slots = get_max_slots(boundary_mask);
+       unsigned int iotlb_align_mask =
+               dma_get_min_align_mask(dev) & ~(IO_TLB_SIZE - 1);
+       unsigned int nslots = nr_slots(alloc_size), stride;
+       unsigned int index, wrap, count = 0, i;
+       unsigned long flags;
 
-       /*
-        * Carefully handle integer overflow which can occur when mask == ~0UL.
-        */
-       max_slots = mask + 1
-                   ? ALIGN(mask + 1, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT
-                   : 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
+       BUG_ON(!nslots);
 
        /*
-        * For mappings greater than or equal to a page, we limit the stride
-        * (and hence alignment) to a page size.
+        * For mappings with an alignment requirement don't bother looping to
+        * unaligned slots once we found an aligned one.  For allocations of
+        * PAGE_SIZE or larger only look for page aligned allocations.
         */
-       nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
+       stride = (iotlb_align_mask >> IO_TLB_SHIFT) + 1;
        if (alloc_size >= PAGE_SIZE)
-               stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
-       else
-               stride = 1;
-
-       BUG_ON(!nslots);
+               stride = max(stride, stride << (PAGE_SHIFT - IO_TLB_SHIFT));
 
-       /*
-        * Find suitable number of IO TLB entries size that will fit this
-        * request and allocate a buffer from that IO TLB pool.
-        */
        spin_lock_irqsave(&io_tlb_lock, flags);
-
        if (unlikely(nslots > io_tlb_nslabs - io_tlb_used))
                goto not_found;
 
-       index = ALIGN(io_tlb_index, stride);
-       if (index >= io_tlb_nslabs)
-               index = 0;
-       wrap = index;
-
+       index = wrap = wrap_index(ALIGN(io_tlb_index, stride));
        do {
-               while (iommu_is_span_boundary(index, nslots, offset_slots,
-                                             max_slots)) {
-                       index += stride;
-                       if (index >= io_tlb_nslabs)
-                               index = 0;
-                       if (index == wrap)
-                               goto not_found;
+               if ((slot_addr(tbl_dma_addr, index) & iotlb_align_mask) !=
+                   (orig_addr & iotlb_align_mask)) {
+                       index = wrap_index(index + 1);
+                       continue;
                }
 
                /*
@@ -541,55 +569,96 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
                 * contiguous buffers, we allocate the buffers from that slot
                 * and mark the entries as '0' indicating unavailable.
                 */
-               if (io_tlb_list[index] >= nslots) {
-                       int count = 0;
-
-                       for (i = index; i < (int) (index + nslots); i++)
-                               io_tlb_list[i] = 0;
-                       for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE - 1) && io_tlb_list[i]; i--)
-                               io_tlb_list[i] = ++count;
-                       tlb_addr = io_tlb_start + (index << IO_TLB_SHIFT);
-
-                       /*
-                        * Update the indices to avoid searching in the next
-                        * round.
-                        */
-                       io_tlb_index = ((index + nslots) < io_tlb_nslabs
-                                       ? (index + nslots) : 0);
-
-                       goto found;
+               if (!iommu_is_span_boundary(index, nslots,
+                                           nr_slots(tbl_dma_addr),
+                                           max_slots)) {
+                       if (io_tlb_list[index] >= nslots)
+                               goto found;
                }
-               index += stride;
-               if (index >= io_tlb_nslabs)
-                       index = 0;
+               index = wrap_index(index + stride);
        } while (index != wrap);
 
 not_found:
-       tmp_io_tlb_used = io_tlb_used;
-
        spin_unlock_irqrestore(&io_tlb_lock, flags);
-       if (!(attrs & DMA_ATTR_NO_WARN) && printk_ratelimit())
-               dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes), total %lu (slots), used %lu (slots)\n",
-                        alloc_size, io_tlb_nslabs, tmp_io_tlb_used);
-       return (phys_addr_t)DMA_MAPPING_ERROR;
+       return -1;
+
 found:
+       for (i = index; i < index + nslots; i++)
+               io_tlb_list[i] = 0;
+       for (i = index - 1;
+            io_tlb_offset(i) != IO_TLB_SEGSIZE - 1 &&
+            io_tlb_list[i]; i--)
+               io_tlb_list[i] = ++count;
+
+       /*
+        * Update the indices to avoid searching in the next round.
+        */
+       if (index + nslots < io_tlb_nslabs)
+               io_tlb_index = index + nslots;
+       else
+               io_tlb_index = 0;
        io_tlb_used += nslots;
+
        spin_unlock_irqrestore(&io_tlb_lock, flags);
+       return index;
+}
+
+phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr,
+               size_t mapping_size, size_t alloc_size,
+               enum dma_data_direction dir, unsigned long attrs)
+{
+       unsigned int offset = swiotlb_align_offset(dev, orig_addr);
+       unsigned int index, i;
+       phys_addr_t tlb_addr;
+
+       if (no_iotlb_memory)
+               panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer");
+
+       if (mem_encrypt_active())
+               pr_warn_once("Memory encryption is active and system is using DMA bounce buffers\n");
+
+       if (mapping_size > alloc_size) {
+               dev_warn_once(dev, "Invalid sizes (mapping: %zd bytes, alloc: %zd bytes)",
+                             mapping_size, alloc_size);
+               return (phys_addr_t)DMA_MAPPING_ERROR;
+       }
+
+       index = find_slots(dev, orig_addr, alloc_size + offset);
+       if (index == -1) {
+               if (!(attrs & DMA_ATTR_NO_WARN))
+                       dev_warn_ratelimited(dev,
+       "swiotlb buffer is full (sz: %zd bytes), total %lu (slots), used %lu (slots)\n",
+                                alloc_size, io_tlb_nslabs, io_tlb_used);
+               return (phys_addr_t)DMA_MAPPING_ERROR;
+       }
 
        /*
         * Save away the mapping from the original address to the DMA address.
         * This is needed when we sync the memory.  Then we sync the buffer if
         * needed.
         */
-       for (i = 0; i < nslots; i++)
-               io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT);
+       for (i = 0; i < nr_slots(alloc_size + offset); i++) {
+               io_tlb_orig_addr[index + i] = slot_addr(orig_addr, i);
+               io_tlb_orig_size[index+i] = alloc_size - (i << IO_TLB_SHIFT);
+       }
+       tlb_addr = slot_addr(io_tlb_start, index) + offset;
        if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
            (dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
                swiotlb_bounce(orig_addr, tlb_addr, mapping_size, DMA_TO_DEVICE);
-
        return tlb_addr;
 }
 
+static void validate_sync_size_and_truncate(struct device *hwdev, size_t orig_size, size_t *size)
+{
+       if (*size > orig_size) {
+               /* Warn and truncate mapping_size */
+               dev_WARN_ONCE(hwdev, 1,
+                       "Attempt for buffer overflow. Original size: %zu. Mapping size: %zu.\n",
+                       orig_size, *size);
+               *size = orig_size;
+       }
+}
+
 /*
  * tlb_addr is the physical address of the bounce buffer to unmap.
  */
@@ -598,10 +667,13 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
                              enum dma_data_direction dir, unsigned long attrs)
 {
        unsigned long flags;
-       int i, count, nslots = ALIGN(alloc_size, 1 << IO_TLB_SHIFT) >> IO_TLB_SHIFT;
-       int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
+       unsigned int offset = swiotlb_align_offset(hwdev, tlb_addr);
+       int i, count, nslots = nr_slots(alloc_size + offset);
+       int index = (tlb_addr - offset - io_tlb_start) >> IO_TLB_SHIFT;
        phys_addr_t orig_addr = io_tlb_orig_addr[index];
 
+       validate_sync_size_and_truncate(hwdev, io_tlb_orig_size[index], &mapping_size);
+
        /*
         * First, sync the memory before unmapping the entry
         */
@@ -617,26 +689,30 @@ void swiotlb_tbl_unmap_single(struct device *hwdev, phys_addr_t tlb_addr,
         * with slots below and above the pool being returned.
         */
        spin_lock_irqsave(&io_tlb_lock, flags);
-       {
-               count = ((index + nslots) < ALIGN(index + 1, IO_TLB_SEGSIZE) ?
-                        io_tlb_list[index + nslots] : 0);
-               /*
-                * Step 1: return the slots to the free list, merging the
-                * slots with superceeding slots
-                */
-               for (i = index + nslots - 1; i >= index; i--) {
-                       io_tlb_list[i] = ++count;
-                       io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
-               }
-               /*
-                * Step 2: merge the returned slots with the preceding slots,
-                * if available (non zero)
-                */
-               for (i = index - 1; (OFFSET(i, IO_TLB_SEGSIZE) != IO_TLB_SEGSIZE -1) && io_tlb_list[i]; i--)
-                       io_tlb_list[i] = ++count;
+       if (index + nslots < ALIGN(index + 1, IO_TLB_SEGSIZE))
+               count = io_tlb_list[index + nslots];
+       else
+               count = 0;
 
-               io_tlb_used -= nslots;
+       /*
+        * Step 1: return the slots to the free list, merging the slots with
+        * superceeding slots
+        */
+       for (i = index + nslots - 1; i >= index; i--) {
+               io_tlb_list[i] = ++count;
+               io_tlb_orig_addr[i] = INVALID_PHYS_ADDR;
+               io_tlb_orig_size[i] = 0;
        }
+
+       /*
+        * Step 2: merge the returned slots with the preceding slots, if
+        * available (non zero)
+        */
+       for (i = index - 1;
+            io_tlb_offset(i) != IO_TLB_SEGSIZE - 1 && io_tlb_list[i];
+            i--)
+               io_tlb_list[i] = ++count;
+       io_tlb_used -= nslots;
        spin_unlock_irqrestore(&io_tlb_lock, flags);
 }
 
@@ -645,11 +721,13 @@ void swiotlb_tbl_sync_single(struct device *hwdev, phys_addr_t tlb_addr,
                             enum dma_sync_target target)
 {
        int index = (tlb_addr - io_tlb_start) >> IO_TLB_SHIFT;
+       size_t orig_size = io_tlb_orig_size[index];
        phys_addr_t orig_addr = io_tlb_orig_addr[index];
 
        if (orig_addr == INVALID_PHYS_ADDR)
                return;
-       orig_addr += (unsigned long)tlb_addr & ((1 << IO_TLB_SHIFT) - 1);
+
+       validate_sync_size_and_truncate(hwdev, orig_size, &size);
 
        switch (target) {
        case SYNC_FOR_CPU:
@@ -707,7 +785,7 @@ dma_addr_t swiotlb_map(struct device *dev, phys_addr_t paddr, size_t size,
 
 size_t swiotlb_max_mapping_size(struct device *dev)
 {
-       return ((size_t)1 << IO_TLB_SHIFT) * IO_TLB_SEGSIZE;
+       return ((size_t)IO_TLB_SIZE) * IO_TLB_SEGSIZE;
 }
 
 bool is_swiotlb_active(void)