1f48ad614SDennis Dalessandro /* 2f48ad614SDennis Dalessandro * Copyright(c) 2016 Intel Corporation. 3f48ad614SDennis Dalessandro * 4f48ad614SDennis Dalessandro * This file is provided under a dual BSD/GPLv2 license. When using or 5f48ad614SDennis Dalessandro * redistributing this file, you may do so under either license. 6f48ad614SDennis Dalessandro * 7f48ad614SDennis Dalessandro * GPL LICENSE SUMMARY 8f48ad614SDennis Dalessandro * 9f48ad614SDennis Dalessandro * This program is free software; you can redistribute it and/or modify 10f48ad614SDennis Dalessandro * it under the terms of version 2 of the GNU General Public License as 11f48ad614SDennis Dalessandro * published by the Free Software Foundation. 12f48ad614SDennis Dalessandro * 13f48ad614SDennis Dalessandro * This program is distributed in the hope that it will be useful, but 14f48ad614SDennis Dalessandro * WITHOUT ANY WARRANTY; without even the implied warranty of 15f48ad614SDennis Dalessandro * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16f48ad614SDennis Dalessandro * General Public License for more details. 17f48ad614SDennis Dalessandro * 18f48ad614SDennis Dalessandro * BSD LICENSE 19f48ad614SDennis Dalessandro * 20f48ad614SDennis Dalessandro * Redistribution and use in source and binary forms, with or without 21f48ad614SDennis Dalessandro * modification, are permitted provided that the following conditions 22f48ad614SDennis Dalessandro * are met: 23f48ad614SDennis Dalessandro * 24f48ad614SDennis Dalessandro * - Redistributions of source code must retain the above copyright 25f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer. 26f48ad614SDennis Dalessandro * - Redistributions in binary form must reproduce the above copyright 27f48ad614SDennis Dalessandro * notice, this list of conditions and the following disclaimer in 28f48ad614SDennis Dalessandro * the documentation and/or other materials provided with the 29f48ad614SDennis Dalessandro * distribution. 30f48ad614SDennis Dalessandro * - Neither the name of Intel Corporation nor the names of its 31f48ad614SDennis Dalessandro * contributors may be used to endorse or promote products derived 32f48ad614SDennis Dalessandro * from this software without specific prior written permission. 33f48ad614SDennis Dalessandro * 34f48ad614SDennis Dalessandro * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 35f48ad614SDennis Dalessandro * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 36f48ad614SDennis Dalessandro * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 37f48ad614SDennis Dalessandro * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 38f48ad614SDennis Dalessandro * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 39f48ad614SDennis Dalessandro * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 40f48ad614SDennis Dalessandro * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 41f48ad614SDennis Dalessandro * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 42f48ad614SDennis Dalessandro * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 43f48ad614SDennis Dalessandro * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 44f48ad614SDennis Dalessandro * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 45f48ad614SDennis Dalessandro * 46f48ad614SDennis Dalessandro */ 47f48ad614SDennis Dalessandro #include <linux/list.h> 48f48ad614SDennis Dalessandro #include <linux/rculist.h> 49f48ad614SDennis Dalessandro #include <linux/mmu_notifier.h> 50f48ad614SDennis Dalessandro #include <linux/interval_tree_generic.h> 51f48ad614SDennis Dalessandro 52f48ad614SDennis Dalessandro #include "mmu_rb.h" 53f48ad614SDennis Dalessandro #include "trace.h" 54f48ad614SDennis Dalessandro 55f48ad614SDennis Dalessandro struct mmu_rb_handler { 56f48ad614SDennis Dalessandro struct list_head list; 57f48ad614SDennis Dalessandro struct mmu_notifier mn; 58f48ad614SDennis Dalessandro struct rb_root *root; 59f48ad614SDennis Dalessandro spinlock_t lock; /* protect the RB tree */ 60f48ad614SDennis Dalessandro struct mmu_rb_ops *ops; 61f48ad614SDennis Dalessandro }; 62f48ad614SDennis Dalessandro 63f48ad614SDennis Dalessandro static LIST_HEAD(mmu_rb_handlers); 64f48ad614SDennis Dalessandro static DEFINE_SPINLOCK(mmu_rb_lock); /* protect mmu_rb_handlers list */ 65f48ad614SDennis Dalessandro 66f48ad614SDennis Dalessandro static unsigned long mmu_node_start(struct mmu_rb_node *); 67f48ad614SDennis Dalessandro static unsigned long mmu_node_last(struct mmu_rb_node *); 68f48ad614SDennis Dalessandro static struct mmu_rb_handler *find_mmu_handler(struct rb_root *); 69f48ad614SDennis Dalessandro static inline void mmu_notifier_page(struct mmu_notifier *, struct mm_struct *, 70f48ad614SDennis Dalessandro unsigned long); 71f48ad614SDennis Dalessandro static inline void mmu_notifier_range_start(struct mmu_notifier *, 72f48ad614SDennis Dalessandro struct mm_struct *, 73f48ad614SDennis Dalessandro unsigned long, unsigned long); 74f48ad614SDennis Dalessandro static void mmu_notifier_mem_invalidate(struct mmu_notifier *, 75f48ad614SDennis Dalessandro struct mm_struct *, 76f48ad614SDennis Dalessandro unsigned long, unsigned long); 77f48ad614SDennis Dalessandro static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *, 78f48ad614SDennis Dalessandro unsigned long, unsigned long); 79f48ad614SDennis Dalessandro 80f48ad614SDennis Dalessandro static struct mmu_notifier_ops mn_opts = { 81f48ad614SDennis Dalessandro .invalidate_page = mmu_notifier_page, 82f48ad614SDennis Dalessandro .invalidate_range_start = mmu_notifier_range_start, 83f48ad614SDennis Dalessandro }; 84f48ad614SDennis Dalessandro 85f48ad614SDennis Dalessandro INTERVAL_TREE_DEFINE(struct mmu_rb_node, node, unsigned long, __last, 86f48ad614SDennis Dalessandro mmu_node_start, mmu_node_last, static, __mmu_int_rb); 87f48ad614SDennis Dalessandro 88f48ad614SDennis Dalessandro static unsigned long mmu_node_start(struct mmu_rb_node *node) 89f48ad614SDennis Dalessandro { 90f48ad614SDennis Dalessandro return node->addr & PAGE_MASK; 91f48ad614SDennis Dalessandro } 92f48ad614SDennis Dalessandro 93f48ad614SDennis Dalessandro static unsigned long mmu_node_last(struct mmu_rb_node *node) 94f48ad614SDennis Dalessandro { 95f48ad614SDennis Dalessandro return PAGE_ALIGN(node->addr + node->len) - 1; 96f48ad614SDennis Dalessandro } 97f48ad614SDennis Dalessandro 98f48ad614SDennis Dalessandro int hfi1_mmu_rb_register(struct rb_root *root, struct mmu_rb_ops *ops) 99f48ad614SDennis Dalessandro { 100f48ad614SDennis Dalessandro struct mmu_rb_handler *handlr; 101f48ad614SDennis Dalessandro 102f48ad614SDennis Dalessandro handlr = kmalloc(sizeof(*handlr), GFP_KERNEL); 103f48ad614SDennis Dalessandro if (!handlr) 104f48ad614SDennis Dalessandro return -ENOMEM; 105f48ad614SDennis Dalessandro 106f48ad614SDennis Dalessandro handlr->root = root; 107f48ad614SDennis Dalessandro handlr->ops = ops; 108f48ad614SDennis Dalessandro INIT_HLIST_NODE(&handlr->mn.hlist); 109f48ad614SDennis Dalessandro spin_lock_init(&handlr->lock); 110f48ad614SDennis Dalessandro handlr->mn.ops = &mn_opts; 111f48ad614SDennis Dalessandro spin_lock(&mmu_rb_lock); 112f48ad614SDennis Dalessandro list_add_tail_rcu(&handlr->list, &mmu_rb_handlers); 113f48ad614SDennis Dalessandro spin_unlock(&mmu_rb_lock); 114f48ad614SDennis Dalessandro 115f48ad614SDennis Dalessandro return mmu_notifier_register(&handlr->mn, current->mm); 116f48ad614SDennis Dalessandro } 117f48ad614SDennis Dalessandro 118f48ad614SDennis Dalessandro void hfi1_mmu_rb_unregister(struct rb_root *root) 119f48ad614SDennis Dalessandro { 120f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = find_mmu_handler(root); 121*20a42d08SDean Luick struct mmu_rb_node *rbnode; 122*20a42d08SDean Luick struct rb_node *node; 123f48ad614SDennis Dalessandro unsigned long flags; 124f48ad614SDennis Dalessandro 125f48ad614SDennis Dalessandro if (!handler) 126f48ad614SDennis Dalessandro return; 127f48ad614SDennis Dalessandro 128f48ad614SDennis Dalessandro /* Unregister first so we don't get any more notifications. */ 129f48ad614SDennis Dalessandro if (current->mm) 130f48ad614SDennis Dalessandro mmu_notifier_unregister(&handler->mn, current->mm); 131f48ad614SDennis Dalessandro 132f48ad614SDennis Dalessandro spin_lock(&mmu_rb_lock); 133f48ad614SDennis Dalessandro list_del_rcu(&handler->list); 134f48ad614SDennis Dalessandro spin_unlock(&mmu_rb_lock); 135f48ad614SDennis Dalessandro synchronize_rcu(); 136f48ad614SDennis Dalessandro 137f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 138f48ad614SDennis Dalessandro while ((node = rb_first(root))) { 139f48ad614SDennis Dalessandro rbnode = rb_entry(node, struct mmu_rb_node, node); 140f48ad614SDennis Dalessandro rb_erase(node, root); 141f48ad614SDennis Dalessandro handler->ops->remove(root, rbnode, NULL); 142f48ad614SDennis Dalessandro } 143f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 144f48ad614SDennis Dalessandro 145f48ad614SDennis Dalessandro kfree(handler); 146f48ad614SDennis Dalessandro } 147f48ad614SDennis Dalessandro 148f48ad614SDennis Dalessandro int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode) 149f48ad614SDennis Dalessandro { 150f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = find_mmu_handler(root); 151f48ad614SDennis Dalessandro struct mmu_rb_node *node; 152f48ad614SDennis Dalessandro unsigned long flags; 153f48ad614SDennis Dalessandro int ret = 0; 154f48ad614SDennis Dalessandro 155f48ad614SDennis Dalessandro if (!handler) 156f48ad614SDennis Dalessandro return -EINVAL; 157f48ad614SDennis Dalessandro 158f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 159f48ad614SDennis Dalessandro hfi1_cdbg(MMU, "Inserting node addr 0x%llx, len %u", mnode->addr, 160f48ad614SDennis Dalessandro mnode->len); 161f48ad614SDennis Dalessandro node = __mmu_rb_search(handler, mnode->addr, mnode->len); 162f48ad614SDennis Dalessandro if (node) { 163f48ad614SDennis Dalessandro ret = -EINVAL; 164f48ad614SDennis Dalessandro goto unlock; 165f48ad614SDennis Dalessandro } 166f48ad614SDennis Dalessandro __mmu_int_rb_insert(mnode, root); 167f48ad614SDennis Dalessandro 168f48ad614SDennis Dalessandro ret = handler->ops->insert(root, mnode); 169f48ad614SDennis Dalessandro if (ret) 170f48ad614SDennis Dalessandro __mmu_int_rb_remove(mnode, root); 171f48ad614SDennis Dalessandro unlock: 172f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 173f48ad614SDennis Dalessandro return ret; 174f48ad614SDennis Dalessandro } 175f48ad614SDennis Dalessandro 176f48ad614SDennis Dalessandro /* Caller must hold handler lock */ 177f48ad614SDennis Dalessandro static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler, 178f48ad614SDennis Dalessandro unsigned long addr, 179f48ad614SDennis Dalessandro unsigned long len) 180f48ad614SDennis Dalessandro { 181f48ad614SDennis Dalessandro struct mmu_rb_node *node = NULL; 182f48ad614SDennis Dalessandro 183f48ad614SDennis Dalessandro hfi1_cdbg(MMU, "Searching for addr 0x%llx, len %u", addr, len); 184f48ad614SDennis Dalessandro if (!handler->ops->filter) { 185f48ad614SDennis Dalessandro node = __mmu_int_rb_iter_first(handler->root, addr, 186f48ad614SDennis Dalessandro (addr + len) - 1); 187f48ad614SDennis Dalessandro } else { 188f48ad614SDennis Dalessandro for (node = __mmu_int_rb_iter_first(handler->root, addr, 189f48ad614SDennis Dalessandro (addr + len) - 1); 190f48ad614SDennis Dalessandro node; 191f48ad614SDennis Dalessandro node = __mmu_int_rb_iter_next(node, addr, 192f48ad614SDennis Dalessandro (addr + len) - 1)) { 193f48ad614SDennis Dalessandro if (handler->ops->filter(node, addr, len)) 194f48ad614SDennis Dalessandro return node; 195f48ad614SDennis Dalessandro } 196f48ad614SDennis Dalessandro } 197f48ad614SDennis Dalessandro return node; 198f48ad614SDennis Dalessandro } 199f48ad614SDennis Dalessandro 200f48ad614SDennis Dalessandro struct mmu_rb_node *hfi1_mmu_rb_extract(struct rb_root *root, 201f48ad614SDennis Dalessandro unsigned long addr, unsigned long len) 202f48ad614SDennis Dalessandro { 203f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = find_mmu_handler(root); 204f48ad614SDennis Dalessandro struct mmu_rb_node *node; 205f48ad614SDennis Dalessandro unsigned long flags; 206f48ad614SDennis Dalessandro 207f48ad614SDennis Dalessandro if (!handler) 208f48ad614SDennis Dalessandro return ERR_PTR(-EINVAL); 209f48ad614SDennis Dalessandro 210f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 211f48ad614SDennis Dalessandro node = __mmu_rb_search(handler, addr, len); 212f48ad614SDennis Dalessandro if (node) 213f48ad614SDennis Dalessandro __mmu_int_rb_remove(node, handler->root); 214f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 215f48ad614SDennis Dalessandro 216f48ad614SDennis Dalessandro return node; 217f48ad614SDennis Dalessandro } 218f48ad614SDennis Dalessandro 219f48ad614SDennis Dalessandro void hfi1_mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node) 220f48ad614SDennis Dalessandro { 2213c1091aaSIra Weiny unsigned long flags; 222f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = find_mmu_handler(root); 223f48ad614SDennis Dalessandro 224f48ad614SDennis Dalessandro if (!handler || !node) 225f48ad614SDennis Dalessandro return; 226f48ad614SDennis Dalessandro 2273c1091aaSIra Weiny /* Validity of handler and node pointers has been checked by caller. */ 2283c1091aaSIra Weiny hfi1_cdbg(MMU, "Removing node addr 0x%llx, len %u", node->addr, 2293c1091aaSIra Weiny node->len); 2303c1091aaSIra Weiny spin_lock_irqsave(&handler->lock, flags); 2313c1091aaSIra Weiny __mmu_int_rb_remove(node, handler->root); 2323c1091aaSIra Weiny spin_unlock_irqrestore(&handler->lock, flags); 2333c1091aaSIra Weiny 2343c1091aaSIra Weiny handler->ops->remove(handler->root, node, NULL); 235f48ad614SDennis Dalessandro } 236f48ad614SDennis Dalessandro 237f48ad614SDennis Dalessandro static struct mmu_rb_handler *find_mmu_handler(struct rb_root *root) 238f48ad614SDennis Dalessandro { 239f48ad614SDennis Dalessandro struct mmu_rb_handler *handler; 240f48ad614SDennis Dalessandro 241f48ad614SDennis Dalessandro rcu_read_lock(); 242f48ad614SDennis Dalessandro list_for_each_entry_rcu(handler, &mmu_rb_handlers, list) { 243f48ad614SDennis Dalessandro if (handler->root == root) 244f48ad614SDennis Dalessandro goto unlock; 245f48ad614SDennis Dalessandro } 246f48ad614SDennis Dalessandro handler = NULL; 247f48ad614SDennis Dalessandro unlock: 248f48ad614SDennis Dalessandro rcu_read_unlock(); 249f48ad614SDennis Dalessandro return handler; 250f48ad614SDennis Dalessandro } 251f48ad614SDennis Dalessandro 252f48ad614SDennis Dalessandro static inline void mmu_notifier_page(struct mmu_notifier *mn, 253f48ad614SDennis Dalessandro struct mm_struct *mm, unsigned long addr) 254f48ad614SDennis Dalessandro { 255f48ad614SDennis Dalessandro mmu_notifier_mem_invalidate(mn, mm, addr, addr + PAGE_SIZE); 256f48ad614SDennis Dalessandro } 257f48ad614SDennis Dalessandro 258f48ad614SDennis Dalessandro static inline void mmu_notifier_range_start(struct mmu_notifier *mn, 259f48ad614SDennis Dalessandro struct mm_struct *mm, 260f48ad614SDennis Dalessandro unsigned long start, 261f48ad614SDennis Dalessandro unsigned long end) 262f48ad614SDennis Dalessandro { 263f48ad614SDennis Dalessandro mmu_notifier_mem_invalidate(mn, mm, start, end); 264f48ad614SDennis Dalessandro } 265f48ad614SDennis Dalessandro 266f48ad614SDennis Dalessandro static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn, 267f48ad614SDennis Dalessandro struct mm_struct *mm, 268f48ad614SDennis Dalessandro unsigned long start, unsigned long end) 269f48ad614SDennis Dalessandro { 270f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = 271f48ad614SDennis Dalessandro container_of(mn, struct mmu_rb_handler, mn); 272f48ad614SDennis Dalessandro struct rb_root *root = handler->root; 273f48ad614SDennis Dalessandro struct mmu_rb_node *node, *ptr = NULL; 274f48ad614SDennis Dalessandro unsigned long flags; 275f48ad614SDennis Dalessandro 276f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 277f48ad614SDennis Dalessandro for (node = __mmu_int_rb_iter_first(root, start, end - 1); 278f48ad614SDennis Dalessandro node; node = ptr) { 279f48ad614SDennis Dalessandro /* Guard against node removal. */ 280f48ad614SDennis Dalessandro ptr = __mmu_int_rb_iter_next(node, start, end - 1); 281f48ad614SDennis Dalessandro hfi1_cdbg(MMU, "Invalidating node addr 0x%llx, len %u", 282f48ad614SDennis Dalessandro node->addr, node->len); 283f48ad614SDennis Dalessandro if (handler->ops->invalidate(root, node)) { 284f48ad614SDennis Dalessandro __mmu_int_rb_remove(node, root); 285f48ad614SDennis Dalessandro handler->ops->remove(root, node, mm); 286f48ad614SDennis Dalessandro } 287f48ad614SDennis Dalessandro } 288f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 289f48ad614SDennis Dalessandro } 290