1*29c8d9ebSAdit Ranadive /* 2*29c8d9ebSAdit Ranadive * Copyright (c) 2012-2016 VMware, Inc. All rights reserved. 3*29c8d9ebSAdit Ranadive * 4*29c8d9ebSAdit Ranadive * This program is free software; you can redistribute it and/or 5*29c8d9ebSAdit Ranadive * modify it under the terms of EITHER the GNU General Public License 6*29c8d9ebSAdit Ranadive * version 2 as published by the Free Software Foundation or the BSD 7*29c8d9ebSAdit Ranadive * 2-Clause License. This program is distributed in the hope that it 8*29c8d9ebSAdit Ranadive * will be useful, but WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED 9*29c8d9ebSAdit Ranadive * WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 10*29c8d9ebSAdit Ranadive * See the GNU General Public License version 2 for more details at 11*29c8d9ebSAdit Ranadive * http://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html. 12*29c8d9ebSAdit Ranadive * 13*29c8d9ebSAdit Ranadive * You should have received a copy of the GNU General Public License 14*29c8d9ebSAdit Ranadive * along with this program available in the file COPYING in the main 15*29c8d9ebSAdit Ranadive * directory of this source tree. 16*29c8d9ebSAdit Ranadive * 17*29c8d9ebSAdit Ranadive * The BSD 2-Clause License 18*29c8d9ebSAdit Ranadive * 19*29c8d9ebSAdit Ranadive * Redistribution and use in source and binary forms, with or 20*29c8d9ebSAdit Ranadive * without modification, are permitted provided that the following 21*29c8d9ebSAdit Ranadive * conditions are met: 22*29c8d9ebSAdit Ranadive * 23*29c8d9ebSAdit Ranadive * - Redistributions of source code must retain the above 24*29c8d9ebSAdit Ranadive * copyright notice, this list of conditions and the following 25*29c8d9ebSAdit Ranadive * disclaimer. 26*29c8d9ebSAdit Ranadive * 27*29c8d9ebSAdit Ranadive * - Redistributions in binary form must reproduce the above 28*29c8d9ebSAdit Ranadive * copyright notice, this list of conditions and the following 29*29c8d9ebSAdit Ranadive * disclaimer in the documentation and/or other materials 30*29c8d9ebSAdit Ranadive * provided with the distribution. 31*29c8d9ebSAdit Ranadive * 32*29c8d9ebSAdit Ranadive * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 33*29c8d9ebSAdit Ranadive * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 34*29c8d9ebSAdit Ranadive * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 35*29c8d9ebSAdit Ranadive * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 36*29c8d9ebSAdit Ranadive * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 37*29c8d9ebSAdit Ranadive * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 38*29c8d9ebSAdit Ranadive * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 39*29c8d9ebSAdit Ranadive * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 40*29c8d9ebSAdit Ranadive * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 41*29c8d9ebSAdit Ranadive * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 42*29c8d9ebSAdit Ranadive * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 43*29c8d9ebSAdit Ranadive * OF THE POSSIBILITY OF SUCH DAMAGE. 44*29c8d9ebSAdit Ranadive */ 45*29c8d9ebSAdit Ranadive 46*29c8d9ebSAdit Ranadive #include <linux/bitmap.h> 47*29c8d9ebSAdit Ranadive #include <linux/errno.h> 48*29c8d9ebSAdit Ranadive #include <linux/slab.h> 49*29c8d9ebSAdit Ranadive 50*29c8d9ebSAdit Ranadive #include "pvrdma.h" 51*29c8d9ebSAdit Ranadive 52*29c8d9ebSAdit Ranadive int pvrdma_uar_table_init(struct pvrdma_dev *dev) 53*29c8d9ebSAdit Ranadive { 54*29c8d9ebSAdit Ranadive u32 num = dev->dsr->caps.max_uar; 55*29c8d9ebSAdit Ranadive u32 mask = num - 1; 56*29c8d9ebSAdit Ranadive struct pvrdma_id_table *tbl = &dev->uar_table.tbl; 57*29c8d9ebSAdit Ranadive 58*29c8d9ebSAdit Ranadive if (!is_power_of_2(num)) 59*29c8d9ebSAdit Ranadive return -EINVAL; 60*29c8d9ebSAdit Ranadive 61*29c8d9ebSAdit Ranadive tbl->last = 0; 62*29c8d9ebSAdit Ranadive tbl->top = 0; 63*29c8d9ebSAdit Ranadive tbl->max = num; 64*29c8d9ebSAdit Ranadive tbl->mask = mask; 65*29c8d9ebSAdit Ranadive spin_lock_init(&tbl->lock); 66*29c8d9ebSAdit Ranadive tbl->table = kcalloc(BITS_TO_LONGS(num), sizeof(long), GFP_KERNEL); 67*29c8d9ebSAdit Ranadive if (!tbl->table) 68*29c8d9ebSAdit Ranadive return -ENOMEM; 69*29c8d9ebSAdit Ranadive 70*29c8d9ebSAdit Ranadive /* 0th UAR is taken by the device. */ 71*29c8d9ebSAdit Ranadive set_bit(0, tbl->table); 72*29c8d9ebSAdit Ranadive 73*29c8d9ebSAdit Ranadive return 0; 74*29c8d9ebSAdit Ranadive } 75*29c8d9ebSAdit Ranadive 76*29c8d9ebSAdit Ranadive void pvrdma_uar_table_cleanup(struct pvrdma_dev *dev) 77*29c8d9ebSAdit Ranadive { 78*29c8d9ebSAdit Ranadive struct pvrdma_id_table *tbl = &dev->uar_table.tbl; 79*29c8d9ebSAdit Ranadive 80*29c8d9ebSAdit Ranadive kfree(tbl->table); 81*29c8d9ebSAdit Ranadive } 82*29c8d9ebSAdit Ranadive 83*29c8d9ebSAdit Ranadive int pvrdma_uar_alloc(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar) 84*29c8d9ebSAdit Ranadive { 85*29c8d9ebSAdit Ranadive struct pvrdma_id_table *tbl; 86*29c8d9ebSAdit Ranadive unsigned long flags; 87*29c8d9ebSAdit Ranadive u32 obj; 88*29c8d9ebSAdit Ranadive 89*29c8d9ebSAdit Ranadive tbl = &dev->uar_table.tbl; 90*29c8d9ebSAdit Ranadive 91*29c8d9ebSAdit Ranadive spin_lock_irqsave(&tbl->lock, flags); 92*29c8d9ebSAdit Ranadive obj = find_next_zero_bit(tbl->table, tbl->max, tbl->last); 93*29c8d9ebSAdit Ranadive if (obj >= tbl->max) { 94*29c8d9ebSAdit Ranadive tbl->top = (tbl->top + tbl->max) & tbl->mask; 95*29c8d9ebSAdit Ranadive obj = find_first_zero_bit(tbl->table, tbl->max); 96*29c8d9ebSAdit Ranadive } 97*29c8d9ebSAdit Ranadive 98*29c8d9ebSAdit Ranadive if (obj >= tbl->max) { 99*29c8d9ebSAdit Ranadive spin_unlock_irqrestore(&tbl->lock, flags); 100*29c8d9ebSAdit Ranadive return -ENOMEM; 101*29c8d9ebSAdit Ranadive } 102*29c8d9ebSAdit Ranadive 103*29c8d9ebSAdit Ranadive set_bit(obj, tbl->table); 104*29c8d9ebSAdit Ranadive obj |= tbl->top; 105*29c8d9ebSAdit Ranadive 106*29c8d9ebSAdit Ranadive spin_unlock_irqrestore(&tbl->lock, flags); 107*29c8d9ebSAdit Ranadive 108*29c8d9ebSAdit Ranadive uar->index = obj; 109*29c8d9ebSAdit Ranadive uar->pfn = (pci_resource_start(dev->pdev, PVRDMA_PCI_RESOURCE_UAR) >> 110*29c8d9ebSAdit Ranadive PAGE_SHIFT) + uar->index; 111*29c8d9ebSAdit Ranadive 112*29c8d9ebSAdit Ranadive return 0; 113*29c8d9ebSAdit Ranadive } 114*29c8d9ebSAdit Ranadive 115*29c8d9ebSAdit Ranadive void pvrdma_uar_free(struct pvrdma_dev *dev, struct pvrdma_uar_map *uar) 116*29c8d9ebSAdit Ranadive { 117*29c8d9ebSAdit Ranadive struct pvrdma_id_table *tbl = &dev->uar_table.tbl; 118*29c8d9ebSAdit Ranadive unsigned long flags; 119*29c8d9ebSAdit Ranadive u32 obj; 120*29c8d9ebSAdit Ranadive 121*29c8d9ebSAdit Ranadive obj = uar->index & (tbl->max - 1); 122*29c8d9ebSAdit Ranadive spin_lock_irqsave(&tbl->lock, flags); 123*29c8d9ebSAdit Ranadive clear_bit(obj, tbl->table); 124*29c8d9ebSAdit Ranadive tbl->last = min(tbl->last, obj); 125*29c8d9ebSAdit Ranadive tbl->top = (tbl->top + tbl->max) & tbl->mask; 126*29c8d9ebSAdit Ranadive spin_unlock_irqrestore(&tbl->lock, flags); 127*29c8d9ebSAdit Ranadive } 128