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