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 mmu_notifier mn; 57*e0b09ac5SDean Luick struct rb_root root; 58*e0b09ac5SDean Luick void *ops_arg; 59f48ad614SDennis Dalessandro spinlock_t lock; /* protect the RB tree */ 60f48ad614SDennis Dalessandro struct mmu_rb_ops *ops; 613faa3d9aSIra Weiny struct mm_struct *mm; 62f48ad614SDennis Dalessandro }; 63f48ad614SDennis Dalessandro 64f48ad614SDennis Dalessandro static unsigned long mmu_node_start(struct mmu_rb_node *); 65f48ad614SDennis Dalessandro static unsigned long mmu_node_last(struct mmu_rb_node *); 66f48ad614SDennis Dalessandro static inline void mmu_notifier_page(struct mmu_notifier *, struct mm_struct *, 67f48ad614SDennis Dalessandro unsigned long); 68f48ad614SDennis Dalessandro static inline void mmu_notifier_range_start(struct mmu_notifier *, 69f48ad614SDennis Dalessandro struct mm_struct *, 70f48ad614SDennis Dalessandro unsigned long, unsigned long); 71f48ad614SDennis Dalessandro static void mmu_notifier_mem_invalidate(struct mmu_notifier *, 72f48ad614SDennis Dalessandro struct mm_struct *, 73f48ad614SDennis Dalessandro unsigned long, unsigned long); 74f48ad614SDennis Dalessandro static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *, 75f48ad614SDennis Dalessandro unsigned long, unsigned long); 76f48ad614SDennis Dalessandro 77f48ad614SDennis Dalessandro static struct mmu_notifier_ops mn_opts = { 78f48ad614SDennis Dalessandro .invalidate_page = mmu_notifier_page, 79f48ad614SDennis Dalessandro .invalidate_range_start = mmu_notifier_range_start, 80f48ad614SDennis Dalessandro }; 81f48ad614SDennis Dalessandro 82f48ad614SDennis Dalessandro INTERVAL_TREE_DEFINE(struct mmu_rb_node, node, unsigned long, __last, 83f48ad614SDennis Dalessandro mmu_node_start, mmu_node_last, static, __mmu_int_rb); 84f48ad614SDennis Dalessandro 85f48ad614SDennis Dalessandro static unsigned long mmu_node_start(struct mmu_rb_node *node) 86f48ad614SDennis Dalessandro { 87f48ad614SDennis Dalessandro return node->addr & PAGE_MASK; 88f48ad614SDennis Dalessandro } 89f48ad614SDennis Dalessandro 90f48ad614SDennis Dalessandro static unsigned long mmu_node_last(struct mmu_rb_node *node) 91f48ad614SDennis Dalessandro { 92f48ad614SDennis Dalessandro return PAGE_ALIGN(node->addr + node->len) - 1; 93f48ad614SDennis Dalessandro } 94f48ad614SDennis Dalessandro 95*e0b09ac5SDean Luick int hfi1_mmu_rb_register(void *ops_arg, struct mm_struct *mm, 96*e0b09ac5SDean Luick struct mmu_rb_ops *ops, 97*e0b09ac5SDean Luick struct mmu_rb_handler **handler) 98f48ad614SDennis Dalessandro { 99f48ad614SDennis Dalessandro struct mmu_rb_handler *handlr; 1003faa3d9aSIra Weiny int ret; 101f48ad614SDennis Dalessandro 102f48ad614SDennis Dalessandro handlr = kmalloc(sizeof(*handlr), GFP_KERNEL); 103f48ad614SDennis Dalessandro if (!handlr) 104f48ad614SDennis Dalessandro return -ENOMEM; 105f48ad614SDennis Dalessandro 106*e0b09ac5SDean Luick handlr->root = RB_ROOT; 107f48ad614SDennis Dalessandro handlr->ops = ops; 108*e0b09ac5SDean Luick handlr->ops_arg = ops_arg; 109f48ad614SDennis Dalessandro INIT_HLIST_NODE(&handlr->mn.hlist); 110f48ad614SDennis Dalessandro spin_lock_init(&handlr->lock); 111f48ad614SDennis Dalessandro handlr->mn.ops = &mn_opts; 1123faa3d9aSIra Weiny handlr->mm = mm; 1133faa3d9aSIra Weiny 1143faa3d9aSIra Weiny ret = mmu_notifier_register(&handlr->mn, handlr->mm); 1153faa3d9aSIra Weiny if (ret) { 1163faa3d9aSIra Weiny kfree(handlr); 1173faa3d9aSIra Weiny return ret; 1183faa3d9aSIra Weiny } 1193faa3d9aSIra Weiny 120*e0b09ac5SDean Luick *handler = handlr; 121*e0b09ac5SDean Luick return 0; 122f48ad614SDennis Dalessandro } 123f48ad614SDennis Dalessandro 124*e0b09ac5SDean Luick void hfi1_mmu_rb_unregister(struct mmu_rb_handler *handler) 125f48ad614SDennis Dalessandro { 12620a42d08SDean Luick struct mmu_rb_node *rbnode; 12720a42d08SDean Luick struct rb_node *node; 128f48ad614SDennis Dalessandro unsigned long flags; 129f48ad614SDennis Dalessandro 130f48ad614SDennis Dalessandro /* Unregister first so we don't get any more notifications. */ 1313faa3d9aSIra Weiny mmu_notifier_unregister(&handler->mn, handler->mm); 132f48ad614SDennis Dalessandro 133f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 134*e0b09ac5SDean Luick while ((node = rb_first(&handler->root))) { 135f48ad614SDennis Dalessandro rbnode = rb_entry(node, struct mmu_rb_node, node); 136*e0b09ac5SDean Luick rb_erase(node, &handler->root); 137*e0b09ac5SDean Luick handler->ops->remove(handler->ops_arg, rbnode, 138*e0b09ac5SDean Luick NULL); 139f48ad614SDennis Dalessandro } 140f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 141f48ad614SDennis Dalessandro 142f48ad614SDennis Dalessandro kfree(handler); 143f48ad614SDennis Dalessandro } 144f48ad614SDennis Dalessandro 145*e0b09ac5SDean Luick int hfi1_mmu_rb_insert(struct mmu_rb_handler *handler, 146*e0b09ac5SDean Luick struct mmu_rb_node *mnode) 147f48ad614SDennis Dalessandro { 148f48ad614SDennis Dalessandro struct mmu_rb_node *node; 149f48ad614SDennis Dalessandro unsigned long flags; 150f48ad614SDennis Dalessandro int ret = 0; 151f48ad614SDennis Dalessandro 152f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 153f48ad614SDennis Dalessandro hfi1_cdbg(MMU, "Inserting node addr 0x%llx, len %u", mnode->addr, 154f48ad614SDennis Dalessandro mnode->len); 155f48ad614SDennis Dalessandro node = __mmu_rb_search(handler, mnode->addr, mnode->len); 156f48ad614SDennis Dalessandro if (node) { 157f48ad614SDennis Dalessandro ret = -EINVAL; 158f48ad614SDennis Dalessandro goto unlock; 159f48ad614SDennis Dalessandro } 160*e0b09ac5SDean Luick __mmu_int_rb_insert(mnode, &handler->root); 161f48ad614SDennis Dalessandro 162*e0b09ac5SDean Luick ret = handler->ops->insert(handler->ops_arg, mnode); 163f48ad614SDennis Dalessandro if (ret) 164*e0b09ac5SDean Luick __mmu_int_rb_remove(mnode, &handler->root); 165f48ad614SDennis Dalessandro unlock: 166f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 167f48ad614SDennis Dalessandro return ret; 168f48ad614SDennis Dalessandro } 169f48ad614SDennis Dalessandro 170f48ad614SDennis Dalessandro /* Caller must hold handler lock */ 171f48ad614SDennis Dalessandro static struct mmu_rb_node *__mmu_rb_search(struct mmu_rb_handler *handler, 172f48ad614SDennis Dalessandro unsigned long addr, 173f48ad614SDennis Dalessandro unsigned long len) 174f48ad614SDennis Dalessandro { 175f48ad614SDennis Dalessandro struct mmu_rb_node *node = NULL; 176f48ad614SDennis Dalessandro 177f48ad614SDennis Dalessandro hfi1_cdbg(MMU, "Searching for addr 0x%llx, len %u", addr, len); 178f48ad614SDennis Dalessandro if (!handler->ops->filter) { 179*e0b09ac5SDean Luick node = __mmu_int_rb_iter_first(&handler->root, addr, 180f48ad614SDennis Dalessandro (addr + len) - 1); 181f48ad614SDennis Dalessandro } else { 182*e0b09ac5SDean Luick for (node = __mmu_int_rb_iter_first(&handler->root, addr, 183f48ad614SDennis Dalessandro (addr + len) - 1); 184f48ad614SDennis Dalessandro node; 185f48ad614SDennis Dalessandro node = __mmu_int_rb_iter_next(node, addr, 186f48ad614SDennis Dalessandro (addr + len) - 1)) { 187f48ad614SDennis Dalessandro if (handler->ops->filter(node, addr, len)) 188f48ad614SDennis Dalessandro return node; 189f48ad614SDennis Dalessandro } 190f48ad614SDennis Dalessandro } 191f48ad614SDennis Dalessandro return node; 192f48ad614SDennis Dalessandro } 193f48ad614SDennis Dalessandro 194*e0b09ac5SDean Luick struct mmu_rb_node *hfi1_mmu_rb_extract(struct mmu_rb_handler *handler, 195f48ad614SDennis Dalessandro unsigned long addr, unsigned long len) 196f48ad614SDennis Dalessandro { 197f48ad614SDennis Dalessandro struct mmu_rb_node *node; 198f48ad614SDennis Dalessandro unsigned long flags; 199f48ad614SDennis Dalessandro 200f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 201f48ad614SDennis Dalessandro node = __mmu_rb_search(handler, addr, len); 202f48ad614SDennis Dalessandro if (node) 203*e0b09ac5SDean Luick __mmu_int_rb_remove(node, &handler->root); 204f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 205f48ad614SDennis Dalessandro 206f48ad614SDennis Dalessandro return node; 207f48ad614SDennis Dalessandro } 208f48ad614SDennis Dalessandro 209*e0b09ac5SDean Luick void hfi1_mmu_rb_remove(struct mmu_rb_handler *handler, 210*e0b09ac5SDean Luick struct mmu_rb_node *node) 211f48ad614SDennis Dalessandro { 2123c1091aaSIra Weiny unsigned long flags; 213f48ad614SDennis Dalessandro 2143c1091aaSIra Weiny /* Validity of handler and node pointers has been checked by caller. */ 2153c1091aaSIra Weiny hfi1_cdbg(MMU, "Removing node addr 0x%llx, len %u", node->addr, 2163c1091aaSIra Weiny node->len); 2173c1091aaSIra Weiny spin_lock_irqsave(&handler->lock, flags); 218*e0b09ac5SDean Luick __mmu_int_rb_remove(node, &handler->root); 2193c1091aaSIra Weiny spin_unlock_irqrestore(&handler->lock, flags); 2203c1091aaSIra Weiny 221*e0b09ac5SDean Luick handler->ops->remove(handler->ops_arg, node, NULL); 222f48ad614SDennis Dalessandro } 223f48ad614SDennis Dalessandro 224f48ad614SDennis Dalessandro static inline void mmu_notifier_page(struct mmu_notifier *mn, 225f48ad614SDennis Dalessandro struct mm_struct *mm, unsigned long addr) 226f48ad614SDennis Dalessandro { 227f48ad614SDennis Dalessandro mmu_notifier_mem_invalidate(mn, mm, addr, addr + PAGE_SIZE); 228f48ad614SDennis Dalessandro } 229f48ad614SDennis Dalessandro 230f48ad614SDennis Dalessandro static inline void mmu_notifier_range_start(struct mmu_notifier *mn, 231f48ad614SDennis Dalessandro struct mm_struct *mm, 232f48ad614SDennis Dalessandro unsigned long start, 233f48ad614SDennis Dalessandro unsigned long end) 234f48ad614SDennis Dalessandro { 235f48ad614SDennis Dalessandro mmu_notifier_mem_invalidate(mn, mm, start, end); 236f48ad614SDennis Dalessandro } 237f48ad614SDennis Dalessandro 238f48ad614SDennis Dalessandro static void mmu_notifier_mem_invalidate(struct mmu_notifier *mn, 239f48ad614SDennis Dalessandro struct mm_struct *mm, 240f48ad614SDennis Dalessandro unsigned long start, unsigned long end) 241f48ad614SDennis Dalessandro { 242f48ad614SDennis Dalessandro struct mmu_rb_handler *handler = 243f48ad614SDennis Dalessandro container_of(mn, struct mmu_rb_handler, mn); 244*e0b09ac5SDean Luick struct rb_root *root = &handler->root; 245f48ad614SDennis Dalessandro struct mmu_rb_node *node, *ptr = NULL; 246f48ad614SDennis Dalessandro unsigned long flags; 247f48ad614SDennis Dalessandro 248f48ad614SDennis Dalessandro spin_lock_irqsave(&handler->lock, flags); 249f48ad614SDennis Dalessandro for (node = __mmu_int_rb_iter_first(root, start, end - 1); 250f48ad614SDennis Dalessandro node; node = ptr) { 251f48ad614SDennis Dalessandro /* Guard against node removal. */ 252f48ad614SDennis Dalessandro ptr = __mmu_int_rb_iter_next(node, start, end - 1); 253f48ad614SDennis Dalessandro hfi1_cdbg(MMU, "Invalidating node addr 0x%llx, len %u", 254f48ad614SDennis Dalessandro node->addr, node->len); 255*e0b09ac5SDean Luick if (handler->ops->invalidate(handler->ops_arg, node)) { 256f48ad614SDennis Dalessandro __mmu_int_rb_remove(node, root); 257*e0b09ac5SDean Luick handler->ops->remove(handler->ops_arg, node, mm); 258f48ad614SDennis Dalessandro } 259f48ad614SDennis Dalessandro } 260f48ad614SDennis Dalessandro spin_unlock_irqrestore(&handler->lock, flags); 261f48ad614SDennis Dalessandro } 262