Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a005a80 authored by Joerg Roedel's avatar Joerg Roedel
Browse files

iommu/iova: Add flush timer



Add a timer to flush entries from the Flush-Queues every
10ms. This makes sure that no stale TLB entries remain for
too long after an IOVA has been unmapped.

Signed-off-by: default avatarJoerg Roedel <jroedel@suse.de>
parent 8109c2a2
Loading
Loading
Loading
Loading
+32 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@ static unsigned long iova_rcache_get(struct iova_domain *iovad,
static void init_iova_rcaches(struct iova_domain *iovad);
static void init_iova_rcaches(struct iova_domain *iovad);
static void free_iova_rcaches(struct iova_domain *iovad);
static void free_iova_rcaches(struct iova_domain *iovad);
static void fq_destroy_all_entries(struct iova_domain *iovad);
static void fq_destroy_all_entries(struct iova_domain *iovad);
static void fq_flush_timeout(unsigned long data);


void
void
init_iova_domain(struct iova_domain *iovad, unsigned long granule,
init_iova_domain(struct iova_domain *iovad, unsigned long granule,
@@ -62,7 +63,11 @@ static void free_iova_flush_queue(struct iova_domain *iovad)
	if (!iovad->fq)
	if (!iovad->fq)
		return;
		return;


	if (timer_pending(&iovad->fq_timer))
		del_timer(&iovad->fq_timer);

	fq_destroy_all_entries(iovad);
	fq_destroy_all_entries(iovad);

	free_percpu(iovad->fq);
	free_percpu(iovad->fq);


	iovad->fq         = NULL;
	iovad->fq         = NULL;
@@ -95,6 +100,9 @@ int init_iova_flush_queue(struct iova_domain *iovad,
		spin_lock_init(&fq->lock);
		spin_lock_init(&fq->lock);
	}
	}


	setup_timer(&iovad->fq_timer, fq_flush_timeout, (unsigned long)iovad);
	atomic_set(&iovad->fq_timer_on, 0);

	return 0;
	return 0;
}
}
EXPORT_SYMBOL_GPL(init_iova_flush_queue);
EXPORT_SYMBOL_GPL(init_iova_flush_queue);
@@ -539,6 +547,25 @@ static void fq_destroy_all_entries(struct iova_domain *iovad)
	}
	}
}
}


static void fq_flush_timeout(unsigned long data)
{
	struct iova_domain *iovad = (struct iova_domain *)data;
	int cpu;

	atomic_set(&iovad->fq_timer_on, 0);
	iova_domain_flush(iovad);

	for_each_possible_cpu(cpu) {
		unsigned long flags;
		struct iova_fq *fq;

		fq = per_cpu_ptr(iovad->fq, cpu);
		spin_lock_irqsave(&fq->lock, flags);
		fq_ring_free(iovad, fq);
		spin_unlock_irqrestore(&fq->lock, flags);
	}
}

void queue_iova(struct iova_domain *iovad,
void queue_iova(struct iova_domain *iovad,
		unsigned long pfn, unsigned long pages,
		unsigned long pfn, unsigned long pages,
		unsigned long data)
		unsigned long data)
@@ -569,6 +596,11 @@ void queue_iova(struct iova_domain *iovad,
	fq->entries[idx].counter  = atomic64_read(&iovad->fq_flush_start_cnt);
	fq->entries[idx].counter  = atomic64_read(&iovad->fq_flush_start_cnt);


	spin_unlock_irqrestore(&fq->lock, flags);
	spin_unlock_irqrestore(&fq->lock, flags);

	if (atomic_cmpxchg(&iovad->fq_timer_on, 0, 1) == 0)
		mod_timer(&iovad->fq_timer,
			  jiffies + msecs_to_jiffies(IOVA_FQ_TIMEOUT));

	put_cpu_ptr(iovad->fq);
	put_cpu_ptr(iovad->fq);
}
}
EXPORT_SYMBOL_GPL(queue_iova);
EXPORT_SYMBOL_GPL(queue_iova);
+8 −0
Original line number Original line Diff line number Diff line
@@ -48,6 +48,9 @@ typedef void (* iova_entry_dtor)(unsigned long data);
/* Number of entries per Flush Queue */
/* Number of entries per Flush Queue */
#define IOVA_FQ_SIZE	256
#define IOVA_FQ_SIZE	256


/* Timeout (in ms) after which entries are flushed from the Flush-Queue */
#define IOVA_FQ_TIMEOUT	10

/* Flush Queue entry for defered flushing */
/* Flush Queue entry for defered flushing */
struct iova_fq_entry {
struct iova_fq_entry {
	unsigned long iova_pfn;
	unsigned long iova_pfn;
@@ -86,6 +89,11 @@ struct iova_domain {


	atomic64_t	fq_flush_finish_cnt;	/* Number of TLB flushes that
	atomic64_t	fq_flush_finish_cnt;	/* Number of TLB flushes that
						   have been finished */
						   have been finished */

	struct timer_list fq_timer;		/* Timer to regularily empty the
						   flush-queues */
	atomic_t fq_timer_on;			/* 1 when timer is active, 0
						   when not */
};
};


static inline unsigned long iova_size(struct iova *iova)
static inline unsigned long iova_size(struct iova *iova)