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; 61*3faa3d9aSIra Weiny struct mm_struct *mm; 62f48ad614SDennis Dalessandro }; 63f48ad614SDennis Dalessandro 64f48ad614SDennis Dalessandro static LIST_HEAD(mmu_rb_handlers); 65f48ad614SDennis Dalessandro static DEFINE_SPINLOCK(mmu_rb_lock); /* protect mmu_rb_handlers list */ 66f48ad614SDennis Dalessandro 67f48ad614SDennis Dalessandro static unsigned long mmu_node_start(struct mmu_rb_node *); 68f48ad614SDennis Dalessandro static unsigned long mmu_node_last(struct mmu_rb_node *); 69f48ad614SDennis Dalessandro static struct mmu_rb_handler *find_mmu_handler(struct rb_root *); 70f48ad614SDennis Dalessandro static inline void mmu_notifier_page(struct mmu_notifier *, struct mm_struct *, 71f48ad614SDennis Dalessandro unsigned long); 72f48ad614SDennis Dalessandro static inline void mmu_notifier_range_start(struct mmu_notifier *, 73f48ad614SDennis Dalessandro struct mm_struct *, 74f48ad614SDennis Dalessandro unsigned long, unsigned long); 75f48ad614SDennis Dalessandro static void mmu_notifier_mem_invalidate(struct mmu_notifier *, 76f48ad614SDennis Dalessandro struct mm_struct *, 77f48ad614SDennis Dalessandro unsigned long, unsigned long); 78f48ad614SDennis Dalessandro static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *, 79f48ad614SDennis Dalessandro unsigned long, unsigned long); 80f48ad614SDennis Dalessandro 81f48ad614SDennis Dalessandro static struct mmu_notifier_ops mn_opts = { 82f48ad614SDennis Dalessandro .invalidate_page = mmu_notifier_page, 83f48ad614SDennis Dalessandro .invalidate_range_start = mmu_notifier_range_start, 84f48ad614SDennis Dalessandro }; 85f48ad614SDennis Dalessandro 86f48ad614SDennis Dalessandro INTERVAL_TREE_DEFINE(struct mmu_rb_node, node, unsigned long, __last, 87f48ad614SDennis Dalessandro mmu_node_start, mmu_node_last, static, __mmu_int_rb); 88f48ad614SDennis Dalessandro 89f48ad614SDennis Dalessandro static unsigned long mmu_node_start(struct mmu_rb_node *node) 90f48ad614SDennis Dalessandro { 91f48ad614SDennis Dalessandro return node->addr & PAGE_MASK; 92f48ad614SDennis Dalessandro } 93f48ad614SDennis Dalessandro 94f48ad614SDennis Dalessandro static unsigned long mmu_node_last(struct mmu_rb_node *node) 95f48ad614SDennis Dalessandro { 96f48ad614SDennis Dalessandro return PAGE_ALIGN(node->addr + node->len) - 1; 97f48ad614SDennis Dalessandro } 98f48ad614SDennis Dalessandro 99*3faa3d9aSIra Weiny int hfi1_mmu_rb_register(struct mm_struct *mm, struct rb_root *root, 100*3faa3d9aSIra Weiny struct mmu_rb_ops *ops) 101f48ad614SDennis Dalessandro { 102f48ad614SDennis Dalessandro struct mmu_rb_handler *handlr; 103*3faa3d9aSIra Weiny int ret; 104f48ad614SDennis Dalessandro 105f48ad614SDennis Dalessandro handlr = kmalloc(sizeof(*handlr), GFP_KERNEL); 106f48ad614SDennis Dalessandro if (!handlr) 107f48ad614SDennis Dalessandro return -ENOMEM; 108f48ad614SDennis Dalessandro 109f48ad614SDennis Dalessandro handlr->root = root; 110f48ad614SDennis Dalessandro handlr->ops = ops; 111f48ad614SDennis Dalessandro INIT_HLIST_NODE(&handlr->mn.hlist); 112f48ad614SDennis Dalessandro spin_lock_init(&handlr->lock); 113f48ad614SDennis Dalessandro handlr->mn.ops = &mn_opts; 114*3faa3d9aSIra Weiny handlr->mm = mm; 115*3faa3d9aSIra Weiny 116*3faa3d9aSIra Weiny ret = mmu_notifier_register(&handlr->mn, handlr->mm); 117*3faa3d9aSIra Weiny if (ret) { 118*3faa3d9aSIra Weiny kfree(handlr); 119*3faa3d9aSIra Weiny return ret; 120*3faa3d9aSIra Weiny } 121*3faa3d9aSIra Weiny 122f48ad614SDennis Dalessandro spin_lock(&mmu_rb_lock); 123f48ad614SDennis Dalessandro list_add_tail_rcu(&handlr->list, &mmu_rb_handlers); 124f48ad614SDennis Dalessandro spin_unlock(&mmu_rb_lock); 125f48ad614SDennis Dalessandro 126*3faa3d9aSIra Weiny return ret; 127f48ad614SDennis Dalessandro } 128f48ad614SDennis Dalessandro 129f48ad614SDennis Dalessandro void hfi1_mmu_rb_unregister(struct rb_root *root) 130f48ad614SDennis Dalessandro { 131f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = find_mmu_handler(root); 13220a42d08SDean Luick struct mmu_rb_node *rbnode; 13320a42d08SDean Luick struct rb_node *node; 134f48ad614SDennis Dalessandro unsigned long flags; 135f48ad614SDennis Dalessandro 136f48ad614SDennis Dalessandro if (!handler) 137f48ad614SDennis Dalessandro return; 138f48ad614SDennis Dalessandro 139f48ad614SDennis Dalessandro /* Unregister first so we don't get any more notifications. */ 140*3faa3d9aSIra Weiny mmu_notifier_unregister(&handler->mn, handler->mm); 141f48ad614SDennis Dalessandro 142f48ad614SDennis Dalessandro spin_lock(&mmu_rb_lock); 143f48ad614SDennis Dalessandro list_del_rcu(&handler->list); 144f48ad614SDennis Dalessandro spin_unlock(&mmu_rb_lock); 145f48ad614SDennis Dalessandro synchronize_rcu(); 146f48ad614SDennis Dalessandro 147f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 148f48ad614SDennis Dalessandro while ((node = rb_first(root))) { 149f48ad614SDennis Dalessandro rbnode = rb_entry(node, struct mmu_rb_node, node); 150f48ad614SDennis Dalessandro rb_erase(node, root); 151f48ad614SDennis Dalessandro handler->ops->remove(root, rbnode, NULL); 152f48ad614SDennis Dalessandro } 153f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 154f48ad614SDennis Dalessandro 155f48ad614SDennis Dalessandro kfree(handler); 156f48ad614SDennis Dalessandro } 157f48ad614SDennis Dalessandro 158f48ad614SDennis Dalessandro int hfi1_mmu_rb_insert(struct rb_root *root, struct mmu_rb_node *mnode) 159f48ad614SDennis Dalessandro { 160f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = find_mmu_handler(root); 161f48ad614SDennis Dalessandro struct mmu_rb_node *node; 162f48ad614SDennis Dalessandro unsigned long flags; 163f48ad614SDennis Dalessandro int ret = 0; 164f48ad614SDennis Dalessandro 165f48ad614SDennis Dalessandro if (!handler) 166f48ad614SDennis Dalessandro return -EINVAL; 167f48ad614SDennis Dalessandro 168f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 169f48ad614SDennis Dalessandro hfi1_cdbg(MMU, "Inserting node addr 0x%llx, len %u", mnode->addr, 170f48ad614SDennis Dalessandro mnode->len); 171f48ad614SDennis Dalessandro node = __mmu_rb_search(handler, mnode->addr, mnode->len); 172f48ad614SDennis Dalessandro if (node) { 173f48ad614SDennis Dalessandro ret = -EINVAL; 174f48ad614SDennis Dalessandro goto unlock; 175f48ad614SDennis Dalessandro } 176f48ad614SDennis Dalessandro __mmu_int_rb_insert(mnode, root); 177f48ad614SDennis Dalessandro 178f48ad614SDennis Dalessandro ret = handler->ops->insert(root, mnode); 179f48ad614SDennis Dalessandro if (ret) 180f48ad614SDennis Dalessandro __mmu_int_rb_remove(mnode, root); 181f48ad614SDennis Dalessandro unlock: 182f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 183f48ad614SDennis Dalessandro return ret; 184f48ad614SDennis Dalessandro } 185f48ad614SDennis Dalessandro 186f48ad614SDennis Dalessandro /* Caller must hold handler lock */ 187f48ad614SDennis Dalessandro static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler, 188f48ad614SDennis Dalessandro unsigned long addr, 189f48ad614SDennis Dalessandro unsigned long len) 190f48ad614SDennis Dalessandro { 191f48ad614SDennis Dalessandro struct mmu_rb_node *node = NULL; 192f48ad614SDennis Dalessandro 193f48ad614SDennis Dalessandro hfi1_cdbg(MMU, "Searching for addr 0x%llx, len %u", addr, len); 194f48ad614SDennis Dalessandro if (!handler->ops->filter) { 195f48ad614SDennis Dalessandro node = __mmu_int_rb_iter_first(handler->root, addr, 196f48ad614SDennis Dalessandro (addr + len) - 1); 197f48ad614SDennis Dalessandro } else { 198f48ad614SDennis Dalessandro for (node = __mmu_int_rb_iter_first(handler->root, addr, 199f48ad614SDennis Dalessandro (addr + len) - 1); 200f48ad614SDennis Dalessandro node; 201f48ad614SDennis Dalessandro node = __mmu_int_rb_iter_next(node, addr, 202f48ad614SDennis Dalessandro (addr + len) - 1)) { 203f48ad614SDennis Dalessandro if (handler->ops->filter(node, addr, len)) 204f48ad614SDennis Dalessandro return node; 205f48ad614SDennis Dalessandro } 206f48ad614SDennis Dalessandro } 207f48ad614SDennis Dalessandro return node; 208f48ad614SDennis Dalessandro } 209f48ad614SDennis Dalessandro 210f48ad614SDennis Dalessandro struct mmu_rb_node *hfi1_mmu_rb_extract(struct rb_root *root, 211f48ad614SDennis Dalessandro unsigned long addr, unsigned long len) 212f48ad614SDennis Dalessandro { 213f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = find_mmu_handler(root); 214f48ad614SDennis Dalessandro struct mmu_rb_node *node; 215f48ad614SDennis Dalessandro unsigned long flags; 216f48ad614SDennis Dalessandro 217f48ad614SDennis Dalessandro if (!handler) 218f48ad614SDennis Dalessandro return ERR_PTR(-EINVAL); 219f48ad614SDennis Dalessandro 220f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 221f48ad614SDennis Dalessandro node = __mmu_rb_search(handler, addr, len); 222f48ad614SDennis Dalessandro if (node) 223f48ad614SDennis Dalessandro __mmu_int_rb_remove(node, handler->root); 224f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 225f48ad614SDennis Dalessandro 226f48ad614SDennis Dalessandro return node; 227f48ad614SDennis Dalessandro } 228f48ad614SDennis Dalessandro 229f48ad614SDennis Dalessandro void hfi1_mmu_rb_remove(struct rb_root *root, struct mmu_rb_node *node) 230f48ad614SDennis Dalessandro { 2313c1091aaSIra Weiny unsigned long flags; 232f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = find_mmu_handler(root); 233f48ad614SDennis Dalessandro 234f48ad614SDennis Dalessandro if (!handler || !node) 235f48ad614SDennis Dalessandro return; 236f48ad614SDennis Dalessandro 2373c1091aaSIra Weiny /* Validity of handler and node pointers has been checked by caller. */ 2383c1091aaSIra Weiny hfi1_cdbg(MMU, "Removing node addr 0x%llx, len %u", node->addr, 2393c1091aaSIra Weiny node->len); 2403c1091aaSIra Weiny spin_lock_irqsave(&handler->lock, flags); 2413c1091aaSIra Weiny __mmu_int_rb_remove(node, handler->root); 2423c1091aaSIra Weiny spin_unlock_irqrestore(&handler->lock, flags); 2433c1091aaSIra Weiny 2443c1091aaSIra Weiny handler->ops->remove(handler->root, node, NULL); 245f48ad614SDennis Dalessandro } 246f48ad614SDennis Dalessandro 247f48ad614SDennis Dalessandro static struct mmu_rb_handler *find_mmu_handler(struct rb_root *root) 248f48ad614SDennis Dalessandro { 249f48ad614SDennis Dalessandro struct mmu_rb_handler *handler; 250f48ad614SDennis Dalessandro 251f48ad614SDennis Dalessandro rcu_read_lock(); 252f48ad614SDennis Dalessandro list_for_each_entry_rcu(handler, &mmu_rb_handlers, list) { 253f48ad614SDennis Dalessandro if (handler->root == root) 254f48ad614SDennis Dalessandro goto unlock; 255f48ad614SDennis Dalessandro } 256f48ad614SDennis Dalessandro handler = NULL; 257f48ad614SDennis Dalessandro unlock: 258f48ad614SDennis Dalessandro rcu_read_unlock(); 259f48ad614SDennis Dalessandro return handler; 260f48ad614SDennis Dalessandro } 261f48ad614SDennis Dalessandro 262f48ad614SDennis Dalessandro static inline void mmu_notifier_page(struct mmu_notifier *mn, 263f48ad614SDennis Dalessandro struct mm_struct *mm, unsigned long addr) 264f48ad614SDennis Dalessandro { 265f48ad614SDennis Dalessandro mmu_notifier_mem_invalidate(mn, mm, addr, addr + PAGE_SIZE); 266f48ad614SDennis Dalessandro } 267f48ad614SDennis Dalessandro 268f48ad614SDennis Dalessandro static inline void mmu_notifier_range_start(struct mmu_notifier *mn, 269f48ad614SDennis Dalessandro struct mm_struct *mm, 270f48ad614SDennis Dalessandro unsigned long start, 271f48ad614SDennis Dalessandro unsigned long end) 272f48ad614SDennis Dalessandro { 273f48ad614SDennis Dalessandro mmu_notifier_mem_invalidate(mn, mm, start, end); 274f48ad614SDennis Dalessandro } 275f48ad614SDennis Dalessandro 276f48ad614SDennis Dalessandro static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn, 277f48ad614SDennis Dalessandro struct mm_struct *mm, 278f48ad614SDennis Dalessandro unsigned long start, unsigned long end) 279f48ad614SDennis Dalessandro { 280f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = 281f48ad614SDennis Dalessandro container_of(mn, struct mmu_rb_handler, mn); 282f48ad614SDennis Dalessandro struct rb_root *root = handler->root; 283f48ad614SDennis Dalessandro struct mmu_rb_node *node, *ptr = NULL; 284f48ad614SDennis Dalessandro unsigned long flags; 285f48ad614SDennis Dalessandro 286f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 287f48ad614SDennis Dalessandro for (node = __mmu_int_rb_iter_first(root, start, end - 1); 288f48ad614SDennis Dalessandro node; node = ptr) { 289f48ad614SDennis Dalessandro /* Guard against node removal. */ 290f48ad614SDennis Dalessandro ptr = __mmu_int_rb_iter_next(node, start, end - 1); 291f48ad614SDennis Dalessandro hfi1_cdbg(MMU, "Invalidating node addr 0x%llx, len %u", 292f48ad614SDennis Dalessandro node->addr, node->len); 293f48ad614SDennis Dalessandro if (handler->ops->invalidate(root, node)) { 294f48ad614SDennis Dalessandro __mmu_int_rb_remove(node, root); 295f48ad614SDennis Dalessandro handler->ops->remove(root, node, mm); 296f48ad614SDennis Dalessandro } 297f48ad614SDennis Dalessandro } 298f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 299f48ad614SDennis Dalessandro } 300