Skip to content

Commit

Permalink
iommu/iova: Add locking to Flush-Queues
Browse files Browse the repository at this point in the history
The lock is taken from the same CPU most of the time. But
having it allows to flush the queue also from another CPU if
necessary.

This will be used by a timer to regularily flush any pending
IOVAs from the Flush-Queues.

Signed-off-by: Joerg Roedel <jroedel@suse.de>
  • Loading branch information
Joerg Roedel committed Aug 15, 2017
1 parent fb418da commit 8109c2a
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 0 deletions.
11 changes: 11 additions & 0 deletions drivers/iommu/iova.c
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ int init_iova_flush_queue(struct iova_domain *iovad,
fq = per_cpu_ptr(iovad->fq, cpu);
fq->head = 0;
fq->tail = 0;

spin_lock_init(&fq->lock);
}

return 0;
Expand Down Expand Up @@ -471,13 +473,16 @@ EXPORT_SYMBOL_GPL(free_iova_fast);

static inline bool fq_full(struct iova_fq *fq)
{
assert_spin_locked(&fq->lock);
return (((fq->tail + 1) % IOVA_FQ_SIZE) == fq->head);
}

static inline unsigned fq_ring_add(struct iova_fq *fq)
{
unsigned idx = fq->tail;

assert_spin_locked(&fq->lock);

fq->tail = (idx + 1) % IOVA_FQ_SIZE;

return idx;
Expand All @@ -488,6 +493,8 @@ static void fq_ring_free(struct iova_domain *iovad, struct iova_fq *fq)
u64 counter = atomic64_read(&iovad->fq_flush_finish_cnt);
unsigned idx;

assert_spin_locked(&fq->lock);

fq_ring_for_each(idx, fq) {

if (fq->entries[idx].counter >= counter)
Expand Down Expand Up @@ -537,8 +544,11 @@ void queue_iova(struct iova_domain *iovad,
unsigned long data)
{
struct iova_fq *fq = get_cpu_ptr(iovad->fq);
unsigned long flags;
unsigned idx;

spin_lock_irqsave(&fq->lock, flags);

/*
* First remove all entries from the flush queue that have already been
* flushed out on another CPU. This makes the fq_full() check below less
Expand All @@ -558,6 +568,7 @@ void queue_iova(struct iova_domain *iovad,
fq->entries[idx].data = data;
fq->entries[idx].counter = atomic64_read(&iovad->fq_flush_start_cnt);

spin_unlock_irqrestore(&fq->lock, flags);
put_cpu_ptr(iovad->fq);
}
EXPORT_SYMBOL_GPL(queue_iova);
Expand Down
1 change: 1 addition & 0 deletions include/linux/iova.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct iova_fq_entry {
struct iova_fq {
struct iova_fq_entry entries[IOVA_FQ_SIZE];
unsigned head, tail;
spinlock_t lock;
};

/* holds all the iova translations for a domain */
Expand Down

0 comments on commit 8109c2a

Please sign in to comment.