Commit c81e1f64 authored by Mitko Haralanov's avatar Mitko Haralanov Committed by Doug Ledford

IB/hfi1: Allow MMU function execution in IRQ context

Future users of the MMU/RB functions might be searching or
manipulating the MMU RB trees in interrupt context. Therefore,
the MMU/RB functions need to be able to run in interrupt
context. This requires that we use the IRQ-aware API for
spin locks.
Reviewed-by: default avatarDennis Dalessandro <dennis.dalessandro@intel.com>
Reviewed-by: default avatarDean Luick <dean.luick@intel.com>
Signed-off-by: default avatarMitko Haralanov <mitko.haralanov@intel.com>
Signed-off-by: default avatarJubin John <jubin.john@intel.com>
Signed-off-by: default avatarDoug Ledford <dledford@redhat.com>
parent 06e0ffa6
...@@ -81,6 +81,7 @@ static struct mmu_notifier_ops mn_opts = { ...@@ -81,6 +81,7 @@ static struct mmu_notifier_ops mn_opts = {
int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops) int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops)
{ {
struct mmu_rb_handler *handlr; struct mmu_rb_handler *handlr;
unsigned long flags;
if (!ops->compare || !ops->invalidate) if (!ops->compare || !ops->invalidate)
return -EINVAL; return -EINVAL;
...@@ -94,9 +95,9 @@ int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops) ...@@ -94,9 +95,9 @@ int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops)
INIT_HLIST_NODE(&handlr->mn.hlist); INIT_HLIST_NODE(&handlr->mn.hlist);
spin_lock_init(&handlr->lock); spin_lock_init(&handlr->lock);
handlr->mn.ops = &mn_opts; handlr->mn.ops = &mn_opts;
spin_lock(&mmu_rb_lock); spin_lock_irqsave(&mmu_rb_lock, flags);
list_add_tail(&handlr->list, &mmu_rb_handlers); list_add_tail(&handlr->list, &mmu_rb_handlers);
spin_unlock(&mmu_rb_lock); spin_unlock_irqrestore(&mmu_rb_lock, flags);
return mmu_notifier_register(&handlr->mn, current->mm); return mmu_notifier_register(&handlr->mn, current->mm);
} }
...@@ -104,10 +105,11 @@ int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops) ...@@ -104,10 +105,11 @@ int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops)
void hfi1_mmu_rb_unregister(struct rb_root *root) void hfi1_mmu_rb_unregister(struct rb_root *root)
{ {
struct mmu_rb_handler *handler = find_mmu_handler(root); struct mmu_rb_handler *handler = find_mmu_handler(root);
unsigned long flags;
spin_lock(&mmu_rb_lock); spin_lock_irqsave(&mmu_rb_lock, flags);
list_del(&handler->list); list_del(&handler->list);
spin_unlock(&mmu_rb_lock); spin_unlock_irqrestore(&mmu_rb_lock, flags);
if (!RB_EMPTY_ROOT(root)) { if (!RB_EMPTY_ROOT(root)) {
struct rb_node *node; struct rb_node *node;
...@@ -132,13 +134,14 @@ int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode) ...@@ -132,13 +134,14 @@ int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode)
struct rb_node **new, *parent = NULL; struct rb_node **new, *parent = NULL;
struct mmu_rb_handler *handler = find_mmu_handler(root); struct mmu_rb_handler *handler = find_mmu_handler(root);
struct mmu_rb_node *this; struct mmu_rb_node *this;
unsigned long flags;
int res, ret = 0; int res, ret = 0;
if (!handler) if (!handler)
return -EINVAL; return -EINVAL;
new = &handler->root->rb_node; new = &handler->root->rb_node;
spin_lock(&handler->lock); spin_lock_irqsave(&handler->lock, flags);
while (*new) { while (*new) {
this = container_of(*new, struct mmu_rb_node, node); this = container_of(*new, struct mmu_rb_node, node);
res = handler->ops->compare(this, mnode->addr, mnode->len); res = handler->ops->compare(this, mnode->addr, mnode->len);
...@@ -163,7 +166,7 @@ int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode) ...@@ -163,7 +166,7 @@ int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode)
rb_link_node(&mnode->node, parent, new); rb_link_node(&mnode->node, parent, new);
rb_insert_color(&mnode->node, root); rb_insert_color(&mnode->node, root);
unlock: unlock:
spin_unlock(&handler->lock); spin_unlock_irqrestore(&handler->lock, flags);
return ret; return ret;
} }
...@@ -204,13 +207,14 @@ struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *root, unsigned long addr, ...@@ -204,13 +207,14 @@ struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *root, unsigned long addr,
{ {
struct mmu_rb_handler *handler = find_mmu_handler(root); struct mmu_rb_handler *handler = find_mmu_handler(root);
struct mmu_rb_node *node; struct mmu_rb_node *node;
unsigned long flags;
if (!handler) if (!handler)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
spin_lock(&handler->lock); spin_lock_irqsave(&handler->lock, flags);
node = __mmu_rb_search(handler, addr, len); node = __mmu_rb_search(handler, addr, len);
spin_unlock(&handler->lock); spin_unlock_irqrestore(&handler->lock, flags);
return node; return node;
} }
...@@ -218,27 +222,29 @@ struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *root, unsigned long addr, ...@@ -218,27 +222,29 @@ struct mmu_rb_node *hfi1_mmu_rb_search(struct rb_root *root, unsigned long addr,
void hfi1_mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node) void hfi1_mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node)
{ {
struct mmu_rb_handler *handler = find_mmu_handler(root); struct mmu_rb_handler *handler = find_mmu_handler(root);
unsigned long flags;
if (!handler || !node) if (!handler || !node)
return; return;
spin_lock(&handler->lock); spin_lock_irqsave(&handler->lock, flags);
__mmu_rb_remove(handler, node); __mmu_rb_remove(handler, node);
spin_unlock(&handler->lock); spin_unlock_irqrestore(&handler->lock, flags);
} }
static struct mmu_rb_handler *find_mmu_handler(struct rb_root *root) static struct mmu_rb_handler *find_mmu_handler(struct rb_root *root)
{ {
struct mmu_rb_handler *handler; struct mmu_rb_handler *handler;
unsigned long flags;
spin_lock(&mmu_rb_lock); spin_lock_irqsave(&mmu_rb_lock, flags);
list_for_each_entry(handler, &mmu_rb_handlers, list) { list_for_each_entry(handler, &mmu_rb_handlers, list) {
if (handler->root == root) if (handler->root == root)
goto unlock; goto unlock;
} }
handler = NULL; handler = NULL;
unlock: unlock:
spin_unlock(&mmu_rb_lock); spin_unlock_irqrestore(&mmu_rb_lock, flags);
return handler; return handler;
} }
...@@ -263,9 +269,9 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn, ...@@ -263,9 +269,9 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn,
container_of(mn, struct mmu_rb_handler, mn); container_of(mn, struct mmu_rb_handler, mn);
struct rb_root *root = handler->root; struct rb_root *root = handler->root;
struct mmu_rb_node *node; struct mmu_rb_node *node;
unsigned long addr = start; unsigned long addr = start, flags;
spin_lock(&handler->lock); spin_lock_irqsave(&handler->lock, flags);
while (addr < end) { while (addr < end) {
/* /*
* There is no good way to provide a reasonable length to the * There is no good way to provide a reasonable length to the
...@@ -300,5 +306,5 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn, ...@@ -300,5 +306,5 @@ static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn,
*/ */
addr = node->addr + node->len; addr = node->addr + node->len;
} }
spin_unlock(&handler->lock); spin_unlock_irqrestore(&handler->lock, flags);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment