Skip to content

Commit 26a7e09

Browse files
Christoph Hellwigkonradwilk
authored andcommitted
swiotlb: refactor swiotlb_tbl_map_single
Split out a bunch of a self-contained helpers to make the function easier to follow. Signed-off-by: Christoph Hellwig <[email protected]> Acked-by: Jianxiong Gao <[email protected]> Tested-by: Jianxiong Gao <[email protected]> Signed-off-by: Konrad Rzeszutek Wilk <[email protected]>
1 parent ca10d0f commit 26a7e09

File tree

1 file changed

+89
-90
lines changed

1 file changed

+89
-90
lines changed

kernel/dma/swiotlb.c

Lines changed: 89 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -468,134 +468,133 @@ static void swiotlb_bounce(phys_addr_t orig_addr, phys_addr_t tlb_addr,
468468
}
469469
}
470470

471-
phys_addr_t swiotlb_tbl_map_single(struct device *hwdev, phys_addr_t orig_addr,
472-
size_t mapping_size, size_t alloc_size,
473-
enum dma_data_direction dir, unsigned long attrs)
474-
{
475-
dma_addr_t tbl_dma_addr = phys_to_dma_unencrypted(hwdev, io_tlb_start);
476-
unsigned long flags;
477-
phys_addr_t tlb_addr;
478-
unsigned int nslots, stride, index, wrap;
479-
int i;
480-
unsigned long mask;
481-
unsigned long offset_slots;
482-
unsigned long max_slots;
483-
unsigned long tmp_io_tlb_used;
484-
485-
if (no_iotlb_memory)
486-
panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer");
487-
488-
if (mem_encrypt_active())
489-
pr_warn_once("Memory encryption is active and system is using DMA bounce buffers\n");
471+
#define slot_addr(start, idx) ((start) + ((idx) << IO_TLB_SHIFT))
490472

491-
if (mapping_size > alloc_size) {
492-
dev_warn_once(hwdev, "Invalid sizes (mapping: %zd bytes, alloc: %zd bytes)",
493-
mapping_size, alloc_size);
494-
return (phys_addr_t)DMA_MAPPING_ERROR;
495-
}
496-
497-
mask = dma_get_seg_boundary(hwdev);
473+
/*
474+
* Carefully handle integer overflow which can occur when boundary_mask == ~0UL.
475+
*/
476+
static inline unsigned long get_max_slots(unsigned long boundary_mask)
477+
{
478+
if (boundary_mask == ~0UL)
479+
return 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
480+
return nr_slots(boundary_mask + 1);
481+
}
498482

499-
tbl_dma_addr &= mask;
483+
static unsigned int wrap_index(unsigned int index)
484+
{
485+
if (index >= io_tlb_nslabs)
486+
return 0;
487+
return index;
488+
}
500489

501-
offset_slots = nr_slots(tbl_dma_addr);
490+
/*
491+
* Find a suitable number of IO TLB entries size that will fit this request and
492+
* allocate a buffer from that IO TLB pool.
493+
*/
494+
static int find_slots(struct device *dev, size_t alloc_size)
495+
{
496+
unsigned long boundary_mask = dma_get_seg_boundary(dev);
497+
dma_addr_t tbl_dma_addr =
498+
phys_to_dma_unencrypted(dev, io_tlb_start) & boundary_mask;
499+
unsigned long max_slots = get_max_slots(boundary_mask);
500+
unsigned int nslots = nr_slots(alloc_size), stride = 1;
501+
unsigned int index, wrap, count = 0, i;
502+
unsigned long flags;
502503

503-
/*
504-
* Carefully handle integer overflow which can occur when mask == ~0UL.
505-
*/
506-
max_slots = mask + 1
507-
? nr_slots(mask + 1)
508-
: 1UL << (BITS_PER_LONG - IO_TLB_SHIFT);
504+
BUG_ON(!nslots);
509505

510506
/*
511507
* For mappings greater than or equal to a page, we limit the stride
512508
* (and hence alignment) to a page size.
513509
*/
514-
nslots = nr_slots(alloc_size);
515510
if (alloc_size >= PAGE_SIZE)
516-
stride = (1 << (PAGE_SHIFT - IO_TLB_SHIFT));
517-
else
518-
stride = 1;
511+
stride <<= (PAGE_SHIFT - IO_TLB_SHIFT);
519512

520-
BUG_ON(!nslots);
521-
522-
/*
523-
* Find suitable number of IO TLB entries size that will fit this
524-
* request and allocate a buffer from that IO TLB pool.
525-
*/
526513
spin_lock_irqsave(&io_tlb_lock, flags);
527-
528514
if (unlikely(nslots > io_tlb_nslabs - io_tlb_used))
529515
goto not_found;
530516

531-
index = ALIGN(io_tlb_index, stride);
532-
if (index >= io_tlb_nslabs)
533-
index = 0;
534-
wrap = index;
535-
517+
index = wrap = wrap_index(ALIGN(io_tlb_index, stride));
536518
do {
537-
while (iommu_is_span_boundary(index, nslots, offset_slots,
538-
max_slots)) {
539-
index += stride;
540-
if (index >= io_tlb_nslabs)
541-
index = 0;
542-
if (index == wrap)
543-
goto not_found;
544-
}
545-
546519
/*
547520
* If we find a slot that indicates we have 'nslots' number of
548521
* contiguous buffers, we allocate the buffers from that slot
549522
* and mark the entries as '0' indicating unavailable.
550523
*/
551-
if (io_tlb_list[index] >= nslots) {
552-
int count = 0;
553-
554-
for (i = index; i < (int) (index + nslots); i++)
555-
io_tlb_list[i] = 0;
556-
for (i = index - 1;
557-
io_tlb_offset(i) != IO_TLB_SEGSIZE - 1 &&
558-
io_tlb_list[i]; i--)
559-
io_tlb_list[i] = ++count;
560-
tlb_addr = io_tlb_start + (index << IO_TLB_SHIFT);
561-
562-
/*
563-
* Update the indices to avoid searching in the next
564-
* round.
565-
*/
566-
io_tlb_index = ((index + nslots) < io_tlb_nslabs
567-
? (index + nslots) : 0);
568-
569-
goto found;
524+
if (!iommu_is_span_boundary(index, nslots,
525+
nr_slots(tbl_dma_addr),
526+
max_slots)) {
527+
if (io_tlb_list[index] >= nslots)
528+
goto found;
570529
}
571-
index += stride;
572-
if (index >= io_tlb_nslabs)
573-
index = 0;
530+
index = wrap_index(index + stride);
574531
} while (index != wrap);
575532

576533
not_found:
577-
tmp_io_tlb_used = io_tlb_used;
578-
579534
spin_unlock_irqrestore(&io_tlb_lock, flags);
580-
if (!(attrs & DMA_ATTR_NO_WARN) && printk_ratelimit())
581-
dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes), total %lu (slots), used %lu (slots)\n",
582-
alloc_size, io_tlb_nslabs, tmp_io_tlb_used);
583-
return (phys_addr_t)DMA_MAPPING_ERROR;
535+
return -1;
536+
584537
found:
538+
for (i = index; i < index + nslots; i++)
539+
io_tlb_list[i] = 0;
540+
for (i = index - 1;
541+
io_tlb_offset(i) != IO_TLB_SEGSIZE - 1 &&
542+
io_tlb_list[i]; i--)
543+
io_tlb_list[i] = ++count;
544+
545+
/*
546+
* Update the indices to avoid searching in the next round.
547+
*/
548+
if (index + nslots < io_tlb_nslabs)
549+
io_tlb_index = index + nslots;
550+
else
551+
io_tlb_index = 0;
585552
io_tlb_used += nslots;
553+
586554
spin_unlock_irqrestore(&io_tlb_lock, flags);
555+
return index;
556+
}
557+
558+
phys_addr_t swiotlb_tbl_map_single(struct device *dev, phys_addr_t orig_addr,
559+
size_t mapping_size, size_t alloc_size,
560+
enum dma_data_direction dir, unsigned long attrs)
561+
{
562+
unsigned int index, i;
563+
phys_addr_t tlb_addr;
564+
565+
if (no_iotlb_memory)
566+
panic("Can not allocate SWIOTLB buffer earlier and can't now provide you with the DMA bounce buffer");
567+
568+
if (mem_encrypt_active())
569+
pr_warn_once("Memory encryption is active and system is using DMA bounce buffers\n");
570+
571+
if (mapping_size > alloc_size) {
572+
dev_warn_once(dev, "Invalid sizes (mapping: %zd bytes, alloc: %zd bytes)",
573+
mapping_size, alloc_size);
574+
return (phys_addr_t)DMA_MAPPING_ERROR;
575+
}
576+
577+
index = find_slots(dev, alloc_size);
578+
if (index == -1) {
579+
if (!(attrs & DMA_ATTR_NO_WARN))
580+
dev_warn_ratelimited(dev,
581+
"swiotlb buffer is full (sz: %zd bytes), total %lu (slots), used %lu (slots)\n",
582+
alloc_size, io_tlb_nslabs, io_tlb_used);
583+
return (phys_addr_t)DMA_MAPPING_ERROR;
584+
}
587585

588586
/*
589587
* Save away the mapping from the original address to the DMA address.
590588
* This is needed when we sync the memory. Then we sync the buffer if
591589
* needed.
592590
*/
593-
for (i = 0; i < nslots; i++)
594-
io_tlb_orig_addr[index+i] = orig_addr + (i << IO_TLB_SHIFT);
591+
for (i = 0; i < nr_slots(alloc_size); i++)
592+
io_tlb_orig_addr[index + i] = slot_addr(orig_addr, i);
593+
594+
tlb_addr = slot_addr(io_tlb_start, index);
595595
if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC) &&
596596
(dir == DMA_TO_DEVICE || dir == DMA_BIDIRECTIONAL))
597597
swiotlb_bounce(orig_addr, tlb_addr, mapping_size, DMA_TO_DEVICE);
598-
599598
return tlb_addr;
600599
}
601600

0 commit comments

Comments
 (0)