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