1*fa765ca7SBjoern A. Zeeb /*- 2*fa765ca7SBjoern A. Zeeb * SPDX-License-Identifier: BSD-2-Clause 3*fa765ca7SBjoern A. Zeeb * 4*fa765ca7SBjoern A. Zeeb * Copyright (c) 2020-2021 The FreeBSD Foundation 5*fa765ca7SBjoern A. Zeeb * 6*fa765ca7SBjoern A. Zeeb * This software was developed by Bj\xc3\xb6rn Zeeb under sponsorship from 7*fa765ca7SBjoern A. Zeeb * the FreeBSD Foundation. 8*fa765ca7SBjoern A. Zeeb * 9*fa765ca7SBjoern A. Zeeb * Redistribution and use in source and binary forms, with or without 10*fa765ca7SBjoern A. Zeeb * modification, are permitted provided that the following conditions 11*fa765ca7SBjoern A. Zeeb * are met: 12*fa765ca7SBjoern A. Zeeb * 1. Redistributions of source code must retain the above copyright 13*fa765ca7SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer. 14*fa765ca7SBjoern A. Zeeb * 2. Redistributions in binary form must reproduce the above copyright 15*fa765ca7SBjoern A. Zeeb * notice, this list of conditions and the following disclaimer in the 16*fa765ca7SBjoern A. Zeeb * documentation and/or other materials provided with the distribution. 17*fa765ca7SBjoern A. Zeeb * 18*fa765ca7SBjoern A. Zeeb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19*fa765ca7SBjoern A. Zeeb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20*fa765ca7SBjoern A. Zeeb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21*fa765ca7SBjoern A. Zeeb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22*fa765ca7SBjoern A. Zeeb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23*fa765ca7SBjoern A. Zeeb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24*fa765ca7SBjoern A. Zeeb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25*fa765ca7SBjoern A. Zeeb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26*fa765ca7SBjoern A. Zeeb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27*fa765ca7SBjoern A. Zeeb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*fa765ca7SBjoern A. Zeeb * SUCH DAMAGE. 29*fa765ca7SBjoern A. Zeeb */ 30*fa765ca7SBjoern A. Zeeb 31*fa765ca7SBjoern A. Zeeb #include <sys/cdefs.h> 32*fa765ca7SBjoern A. Zeeb __FBSDID("$FreeBSD$"); 33*fa765ca7SBjoern A. Zeeb 34*fa765ca7SBjoern A. Zeeb #include <linux/kernel.h> 35*fa765ca7SBjoern A. Zeeb #include <linux/device.h> 36*fa765ca7SBjoern A. Zeeb #include <linux/slab.h> 37*fa765ca7SBjoern A. Zeeb #include <linux/list.h> 38*fa765ca7SBjoern A. Zeeb 39*fa765ca7SBjoern A. Zeeb /* 40*fa765ca7SBjoern A. Zeeb * Linux devres KPI implementation. 41*fa765ca7SBjoern A. Zeeb */ 42*fa765ca7SBjoern A. Zeeb 43*fa765ca7SBjoern A. Zeeb struct devres { 44*fa765ca7SBjoern A. Zeeb struct list_head entry; 45*fa765ca7SBjoern A. Zeeb void (*release)(struct device *, void *); 46*fa765ca7SBjoern A. Zeeb 47*fa765ca7SBjoern A. Zeeb /* Must come last. */ 48*fa765ca7SBjoern A. Zeeb uint8_t __drdata[0] __aligned(CACHE_LINE_SIZE); 49*fa765ca7SBjoern A. Zeeb }; 50*fa765ca7SBjoern A. Zeeb 51*fa765ca7SBjoern A. Zeeb void * 52*fa765ca7SBjoern A. Zeeb lkpi_devres_alloc(void(*release)(struct device *, void *), 53*fa765ca7SBjoern A. Zeeb size_t size, gfp_t gfp) 54*fa765ca7SBjoern A. Zeeb { 55*fa765ca7SBjoern A. Zeeb void *p; 56*fa765ca7SBjoern A. Zeeb struct devres *dr; 57*fa765ca7SBjoern A. Zeeb size_t total; 58*fa765ca7SBjoern A. Zeeb 59*fa765ca7SBjoern A. Zeeb if (size == 0) 60*fa765ca7SBjoern A. Zeeb return (NULL); 61*fa765ca7SBjoern A. Zeeb 62*fa765ca7SBjoern A. Zeeb total = sizeof(*dr) + size; 63*fa765ca7SBjoern A. Zeeb dr = kmalloc(total, gfp); 64*fa765ca7SBjoern A. Zeeb if (dr == NULL) 65*fa765ca7SBjoern A. Zeeb return (NULL); 66*fa765ca7SBjoern A. Zeeb 67*fa765ca7SBjoern A. Zeeb INIT_LIST_HEAD(&dr->entry); 68*fa765ca7SBjoern A. Zeeb dr->release = release; 69*fa765ca7SBjoern A. Zeeb p = (void *)(dr+1); 70*fa765ca7SBjoern A. Zeeb 71*fa765ca7SBjoern A. Zeeb return (p); 72*fa765ca7SBjoern A. Zeeb } 73*fa765ca7SBjoern A. Zeeb 74*fa765ca7SBjoern A. Zeeb static void 75*fa765ca7SBjoern A. Zeeb lkpi_devres_free_dr(struct devres *dr) 76*fa765ca7SBjoern A. Zeeb { 77*fa765ca7SBjoern A. Zeeb 78*fa765ca7SBjoern A. Zeeb /* 79*fa765ca7SBjoern A. Zeeb * We have no dev, so cannot lock. This means someone else has 80*fa765ca7SBjoern A. Zeeb * to do this prior to us if devres_add() had been called. 81*fa765ca7SBjoern A. Zeeb */ 82*fa765ca7SBjoern A. Zeeb KASSERT(list_empty_careful(&dr->entry), 83*fa765ca7SBjoern A. Zeeb ("%s: dr %p still on devres_head\n", __func__, dr)); 84*fa765ca7SBjoern A. Zeeb kfree(dr); 85*fa765ca7SBjoern A. Zeeb } 86*fa765ca7SBjoern A. Zeeb 87*fa765ca7SBjoern A. Zeeb void 88*fa765ca7SBjoern A. Zeeb lkpi_devres_free(void *p) 89*fa765ca7SBjoern A. Zeeb { 90*fa765ca7SBjoern A. Zeeb struct devres *dr; 91*fa765ca7SBjoern A. Zeeb 92*fa765ca7SBjoern A. Zeeb if (p == NULL) 93*fa765ca7SBjoern A. Zeeb return; 94*fa765ca7SBjoern A. Zeeb 95*fa765ca7SBjoern A. Zeeb dr = container_of(p, struct devres, __drdata); 96*fa765ca7SBjoern A. Zeeb lkpi_devres_free_dr(dr); 97*fa765ca7SBjoern A. Zeeb } 98*fa765ca7SBjoern A. Zeeb 99*fa765ca7SBjoern A. Zeeb void 100*fa765ca7SBjoern A. Zeeb lkpi_devres_add(struct device *dev, void *p) 101*fa765ca7SBjoern A. Zeeb { 102*fa765ca7SBjoern A. Zeeb struct devres *dr; 103*fa765ca7SBjoern A. Zeeb 104*fa765ca7SBjoern A. Zeeb KASSERT(dev != NULL && p != NULL, ("%s: dev %p p %p\n", 105*fa765ca7SBjoern A. Zeeb __func__, dev, p)); 106*fa765ca7SBjoern A. Zeeb 107*fa765ca7SBjoern A. Zeeb dr = container_of(p, struct devres, __drdata); 108*fa765ca7SBjoern A. Zeeb spin_lock(&dev->devres_lock); 109*fa765ca7SBjoern A. Zeeb list_add(&dr->entry, &dev->devres_head); 110*fa765ca7SBjoern A. Zeeb spin_unlock(&dev->devres_lock); 111*fa765ca7SBjoern A. Zeeb } 112*fa765ca7SBjoern A. Zeeb 113*fa765ca7SBjoern A. Zeeb static struct devres * 114*fa765ca7SBjoern A. Zeeb lkpi_devres_find_dr(struct device *dev, void(*release)(struct device *, void *), 115*fa765ca7SBjoern A. Zeeb int (*match)(struct device *, void *, void *), void *mp) 116*fa765ca7SBjoern A. Zeeb { 117*fa765ca7SBjoern A. Zeeb struct devres *dr, *next; 118*fa765ca7SBjoern A. Zeeb void *p; 119*fa765ca7SBjoern A. Zeeb 120*fa765ca7SBjoern A. Zeeb KASSERT(dev != NULL, ("%s: dev %p\n", __func__, dev)); 121*fa765ca7SBjoern A. Zeeb assert_spin_locked(&dev->devres_lock); 122*fa765ca7SBjoern A. Zeeb 123*fa765ca7SBjoern A. Zeeb list_for_each_entry_safe(dr, next, &dev->devres_head, entry) { 124*fa765ca7SBjoern A. Zeeb if (dr->release != release) 125*fa765ca7SBjoern A. Zeeb continue; 126*fa765ca7SBjoern A. Zeeb p = (void *)(dr+1); 127*fa765ca7SBjoern A. Zeeb if (match != NULL && match(dev, p, mp) == false) 128*fa765ca7SBjoern A. Zeeb continue; 129*fa765ca7SBjoern A. Zeeb return (dr); 130*fa765ca7SBjoern A. Zeeb } 131*fa765ca7SBjoern A. Zeeb 132*fa765ca7SBjoern A. Zeeb return (NULL); 133*fa765ca7SBjoern A. Zeeb } 134*fa765ca7SBjoern A. Zeeb 135*fa765ca7SBjoern A. Zeeb void * 136*fa765ca7SBjoern A. Zeeb lkpi_devres_find(struct device *dev, void(*release)(struct device *, void *), 137*fa765ca7SBjoern A. Zeeb int (*match)(struct device *, void *, void *), void *mp) 138*fa765ca7SBjoern A. Zeeb { 139*fa765ca7SBjoern A. Zeeb struct devres *dr; 140*fa765ca7SBjoern A. Zeeb 141*fa765ca7SBjoern A. Zeeb KASSERT(dev != NULL, ("%s: dev %p\n", __func__, dev)); 142*fa765ca7SBjoern A. Zeeb 143*fa765ca7SBjoern A. Zeeb spin_lock(&dev->devres_lock); 144*fa765ca7SBjoern A. Zeeb dr = lkpi_devres_find_dr(dev, release, match, mp); 145*fa765ca7SBjoern A. Zeeb spin_unlock(&dev->devres_lock); 146*fa765ca7SBjoern A. Zeeb 147*fa765ca7SBjoern A. Zeeb if (dr == NULL) 148*fa765ca7SBjoern A. Zeeb return (NULL); 149*fa765ca7SBjoern A. Zeeb 150*fa765ca7SBjoern A. Zeeb return ((void *)(dr + 1)); 151*fa765ca7SBjoern A. Zeeb } 152*fa765ca7SBjoern A. Zeeb 153*fa765ca7SBjoern A. Zeeb static void 154*fa765ca7SBjoern A. Zeeb lkpi_devres_unlink_locked(struct device *dev, struct devres *dr) 155*fa765ca7SBjoern A. Zeeb { 156*fa765ca7SBjoern A. Zeeb KASSERT(dev != NULL, ("%s: dev %p\n", __func__, dev)); 157*fa765ca7SBjoern A. Zeeb KASSERT(dr != NULL, ("%s: dr %p\n", __func__, dr)); 158*fa765ca7SBjoern A. Zeeb assert_spin_locked(&dev->devres_lock); 159*fa765ca7SBjoern A. Zeeb 160*fa765ca7SBjoern A. Zeeb list_del_init(&dr->entry); 161*fa765ca7SBjoern A. Zeeb } 162*fa765ca7SBjoern A. Zeeb 163*fa765ca7SBjoern A. Zeeb void 164*fa765ca7SBjoern A. Zeeb lkpi_devres_unlink(struct device *dev, void *p) 165*fa765ca7SBjoern A. Zeeb { 166*fa765ca7SBjoern A. Zeeb struct devres *dr; 167*fa765ca7SBjoern A. Zeeb 168*fa765ca7SBjoern A. Zeeb KASSERT(dev != NULL && p != NULL, ("%s: dev %p p %p\n", 169*fa765ca7SBjoern A. Zeeb __func__, dev, p)); 170*fa765ca7SBjoern A. Zeeb 171*fa765ca7SBjoern A. Zeeb dr = container_of(p, struct devres, __drdata); 172*fa765ca7SBjoern A. Zeeb spin_lock(&dev->devres_lock); 173*fa765ca7SBjoern A. Zeeb lkpi_devres_unlink_locked(dev, dr); 174*fa765ca7SBjoern A. Zeeb spin_unlock(&dev->devres_lock); 175*fa765ca7SBjoern A. Zeeb } 176*fa765ca7SBjoern A. Zeeb 177*fa765ca7SBjoern A. Zeeb /* This is called on device free. */ 178*fa765ca7SBjoern A. Zeeb void 179*fa765ca7SBjoern A. Zeeb lkpi_devres_release_free_list(struct device *dev) 180*fa765ca7SBjoern A. Zeeb { 181*fa765ca7SBjoern A. Zeeb struct devres *dr, *next; 182*fa765ca7SBjoern A. Zeeb void *p; 183*fa765ca7SBjoern A. Zeeb 184*fa765ca7SBjoern A. Zeeb /* Free any resources allocated on the device. */ 185*fa765ca7SBjoern A. Zeeb /* No need to lock anymore. */ 186*fa765ca7SBjoern A. Zeeb list_for_each_entry_safe(dr, next, &dev->devres_head, entry) { 187*fa765ca7SBjoern A. Zeeb p = (void *)(dr+1); 188*fa765ca7SBjoern A. Zeeb if (dr->release != NULL) 189*fa765ca7SBjoern A. Zeeb dr->release(dev, p); 190*fa765ca7SBjoern A. Zeeb /* This should probably be a function of some kind. */ 191*fa765ca7SBjoern A. Zeeb list_del_init(&dr->entry); 192*fa765ca7SBjoern A. Zeeb lkpi_devres_free(p); 193*fa765ca7SBjoern A. Zeeb } 194*fa765ca7SBjoern A. Zeeb } 195*fa765ca7SBjoern A. Zeeb 196*fa765ca7SBjoern A. Zeeb int 197*fa765ca7SBjoern A. Zeeb lkpi_devres_destroy(struct device *dev, void(*release)(struct device *, void *), 198*fa765ca7SBjoern A. Zeeb int (*match)(struct device *, void *, void *), void *mp) 199*fa765ca7SBjoern A. Zeeb { 200*fa765ca7SBjoern A. Zeeb struct devres *dr; 201*fa765ca7SBjoern A. Zeeb 202*fa765ca7SBjoern A. Zeeb spin_lock(&dev->devres_lock); 203*fa765ca7SBjoern A. Zeeb dr = lkpi_devres_find_dr(dev, release, match, mp); 204*fa765ca7SBjoern A. Zeeb if (dr != NULL) 205*fa765ca7SBjoern A. Zeeb lkpi_devres_unlink_locked(dev, dr); 206*fa765ca7SBjoern A. Zeeb spin_unlock(&dev->devres_lock); 207*fa765ca7SBjoern A. Zeeb 208*fa765ca7SBjoern A. Zeeb if (dr == NULL) 209*fa765ca7SBjoern A. Zeeb return (-ENOENT); 210*fa765ca7SBjoern A. Zeeb lkpi_devres_free_dr(dr); 211*fa765ca7SBjoern A. Zeeb 212*fa765ca7SBjoern A. Zeeb return (0); 213*fa765ca7SBjoern A. Zeeb } 214*fa765ca7SBjoern A. Zeeb 215*fa765ca7SBjoern A. Zeeb /* 216*fa765ca7SBjoern A. Zeeb * Devres release function for k*malloc(). 217*fa765ca7SBjoern A. Zeeb * While there is nothing to do here adding, e.g., tracing would be 218*fa765ca7SBjoern A. Zeeb * possible so we leave the empty function here. 219*fa765ca7SBjoern A. Zeeb * Also good for documentation as it is the simplest example. 220*fa765ca7SBjoern A. Zeeb */ 221*fa765ca7SBjoern A. Zeeb void 222*fa765ca7SBjoern A. Zeeb lkpi_devm_kmalloc_release(struct device *dev __unused, void *p __unused) 223*fa765ca7SBjoern A. Zeeb { 224*fa765ca7SBjoern A. Zeeb 225*fa765ca7SBjoern A. Zeeb /* Nothing to do. Freed with the devres. */ 226*fa765ca7SBjoern A. Zeeb } 227