1608f26c5SMasahiro Yamada /* 2608f26c5SMasahiro Yamada * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> 3608f26c5SMasahiro Yamada * 4608f26c5SMasahiro Yamada * Based on the original work in Linux by 5608f26c5SMasahiro Yamada * Copyright (c) 2006 SUSE Linux Products GmbH 6608f26c5SMasahiro Yamada * Copyright (c) 2006 Tejun Heo <teheo@suse.de> 7608f26c5SMasahiro Yamada * 8608f26c5SMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+ 9608f26c5SMasahiro Yamada */ 10608f26c5SMasahiro Yamada 11608f26c5SMasahiro Yamada #include <common.h> 12608f26c5SMasahiro Yamada #include <linux/compat.h> 13608f26c5SMasahiro Yamada #include <linux/kernel.h> 14608f26c5SMasahiro Yamada #include <linux/list.h> 15608f26c5SMasahiro Yamada #include <dm/device.h> 16608f26c5SMasahiro Yamada 17608f26c5SMasahiro Yamada /** 18608f26c5SMasahiro Yamada * struct devres - Bookkeeping info for managed device resource 19608f26c5SMasahiro Yamada * @entry: List to associate this structure with a device 20608f26c5SMasahiro Yamada * @release: Callback invoked when this resource is released 21608f26c5SMasahiro Yamada * @probe: Flag to show when this resource was allocated 22608f26c5SMasahiro Yamada (true = probe, false = bind) 23608f26c5SMasahiro Yamada * @name: Name of release function 24608f26c5SMasahiro Yamada * @size: Size of resource data 25608f26c5SMasahiro Yamada * @data: Resource data 26608f26c5SMasahiro Yamada */ 27608f26c5SMasahiro Yamada struct devres { 28608f26c5SMasahiro Yamada struct list_head entry; 29608f26c5SMasahiro Yamada dr_release_t release; 30608f26c5SMasahiro Yamada bool probe; 31608f26c5SMasahiro Yamada #ifdef CONFIG_DEBUG_DEVRES 32608f26c5SMasahiro Yamada const char *name; 33608f26c5SMasahiro Yamada size_t size; 34608f26c5SMasahiro Yamada #endif 35608f26c5SMasahiro Yamada unsigned long long data[]; 36608f26c5SMasahiro Yamada }; 37608f26c5SMasahiro Yamada 38608f26c5SMasahiro Yamada #ifdef CONFIG_DEBUG_DEVRES 39608f26c5SMasahiro Yamada static void set_node_dbginfo(struct devres *dr, const char *name, size_t size) 40608f26c5SMasahiro Yamada { 41608f26c5SMasahiro Yamada dr->name = name; 42608f26c5SMasahiro Yamada dr->size = size; 43608f26c5SMasahiro Yamada } 44608f26c5SMasahiro Yamada 45608f26c5SMasahiro Yamada static void devres_log(struct udevice *dev, struct devres *dr, 46608f26c5SMasahiro Yamada const char *op) 47608f26c5SMasahiro Yamada { 48608f26c5SMasahiro Yamada printf("%s: DEVRES %3s %p %s (%lu bytes)\n", 49608f26c5SMasahiro Yamada dev->name, op, dr, dr->name, (unsigned long)dr->size); 50608f26c5SMasahiro Yamada } 51608f26c5SMasahiro Yamada #else /* CONFIG_DEBUG_DEVRES */ 52608f26c5SMasahiro Yamada #define set_node_dbginfo(dr, n, s) do {} while (0) 53608f26c5SMasahiro Yamada #define devres_log(dev, dr, op) do {} while (0) 54608f26c5SMasahiro Yamada #endif 55608f26c5SMasahiro Yamada 56608f26c5SMasahiro Yamada #if CONFIG_DEBUG_DEVRES 57608f26c5SMasahiro Yamada void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp, 58608f26c5SMasahiro Yamada const char *name) 59608f26c5SMasahiro Yamada #else 60608f26c5SMasahiro Yamada void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp) 61608f26c5SMasahiro Yamada #endif 62608f26c5SMasahiro Yamada { 63608f26c5SMasahiro Yamada size_t tot_size = sizeof(struct devres) + size; 64608f26c5SMasahiro Yamada struct devres *dr; 65608f26c5SMasahiro Yamada 66608f26c5SMasahiro Yamada dr = kmalloc(tot_size, gfp); 67608f26c5SMasahiro Yamada if (unlikely(!dr)) 68608f26c5SMasahiro Yamada return NULL; 69608f26c5SMasahiro Yamada 70608f26c5SMasahiro Yamada INIT_LIST_HEAD(&dr->entry); 71608f26c5SMasahiro Yamada dr->release = release; 72608f26c5SMasahiro Yamada set_node_dbginfo(dr, name, size); 73608f26c5SMasahiro Yamada 74608f26c5SMasahiro Yamada return dr->data; 75608f26c5SMasahiro Yamada } 76608f26c5SMasahiro Yamada 77608f26c5SMasahiro Yamada void devres_free(void *res) 78608f26c5SMasahiro Yamada { 79608f26c5SMasahiro Yamada if (res) { 80608f26c5SMasahiro Yamada struct devres *dr = container_of(res, struct devres, data); 81608f26c5SMasahiro Yamada 82608f26c5SMasahiro Yamada BUG_ON(!list_empty(&dr->entry)); 83608f26c5SMasahiro Yamada kfree(dr); 84608f26c5SMasahiro Yamada } 85608f26c5SMasahiro Yamada } 86608f26c5SMasahiro Yamada 87608f26c5SMasahiro Yamada void devres_add(struct udevice *dev, void *res) 88608f26c5SMasahiro Yamada { 89608f26c5SMasahiro Yamada struct devres *dr = container_of(res, struct devres, data); 90608f26c5SMasahiro Yamada 91608f26c5SMasahiro Yamada devres_log(dev, dr, "ADD"); 92608f26c5SMasahiro Yamada BUG_ON(!list_empty(&dr->entry)); 93608f26c5SMasahiro Yamada dr->probe = dev->flags & DM_FLAG_BOUND ? true : false; 94608f26c5SMasahiro Yamada list_add_tail(&dr->entry, &dev->devres_head); 95608f26c5SMasahiro Yamada } 96608f26c5SMasahiro Yamada 97608f26c5SMasahiro Yamada void *devres_find(struct udevice *dev, dr_release_t release, 98608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 99608f26c5SMasahiro Yamada { 100608f26c5SMasahiro Yamada struct devres *dr; 101608f26c5SMasahiro Yamada 102608f26c5SMasahiro Yamada list_for_each_entry_reverse(dr, &dev->devres_head, entry) { 103608f26c5SMasahiro Yamada if (dr->release != release) 104608f26c5SMasahiro Yamada continue; 105608f26c5SMasahiro Yamada if (match && !match(dev, dr->data, match_data)) 106608f26c5SMasahiro Yamada continue; 107608f26c5SMasahiro Yamada return dr->data; 108608f26c5SMasahiro Yamada } 109608f26c5SMasahiro Yamada 110608f26c5SMasahiro Yamada return NULL; 111608f26c5SMasahiro Yamada } 112608f26c5SMasahiro Yamada 113608f26c5SMasahiro Yamada void *devres_get(struct udevice *dev, void *new_res, 114608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 115608f26c5SMasahiro Yamada { 116608f26c5SMasahiro Yamada struct devres *new_dr = container_of(new_res, struct devres, data); 117608f26c5SMasahiro Yamada void *res; 118608f26c5SMasahiro Yamada 119608f26c5SMasahiro Yamada res = devres_find(dev, new_dr->release, match, match_data); 120608f26c5SMasahiro Yamada if (!res) { 121608f26c5SMasahiro Yamada devres_add(dev, new_res); 122608f26c5SMasahiro Yamada res = new_res; 123608f26c5SMasahiro Yamada new_res = NULL; 124608f26c5SMasahiro Yamada } 125608f26c5SMasahiro Yamada devres_free(new_res); 126608f26c5SMasahiro Yamada 127608f26c5SMasahiro Yamada return res; 128608f26c5SMasahiro Yamada } 129608f26c5SMasahiro Yamada 130608f26c5SMasahiro Yamada void *devres_remove(struct udevice *dev, dr_release_t release, 131608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 132608f26c5SMasahiro Yamada { 133608f26c5SMasahiro Yamada void *res; 134608f26c5SMasahiro Yamada 135608f26c5SMasahiro Yamada res = devres_find(dev, release, match, match_data); 136608f26c5SMasahiro Yamada if (res) { 137608f26c5SMasahiro Yamada struct devres *dr = container_of(res, struct devres, data); 138608f26c5SMasahiro Yamada 139608f26c5SMasahiro Yamada list_del_init(&dr->entry); 140608f26c5SMasahiro Yamada devres_log(dev, dr, "REM"); 141608f26c5SMasahiro Yamada } 142608f26c5SMasahiro Yamada 143608f26c5SMasahiro Yamada return res; 144608f26c5SMasahiro Yamada } 145608f26c5SMasahiro Yamada 146608f26c5SMasahiro Yamada int devres_destroy(struct udevice *dev, dr_release_t release, 147608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 148608f26c5SMasahiro Yamada { 149608f26c5SMasahiro Yamada void *res; 150608f26c5SMasahiro Yamada 151608f26c5SMasahiro Yamada res = devres_remove(dev, release, match, match_data); 152608f26c5SMasahiro Yamada if (unlikely(!res)) 153608f26c5SMasahiro Yamada return -ENOENT; 154608f26c5SMasahiro Yamada 155608f26c5SMasahiro Yamada devres_free(res); 156608f26c5SMasahiro Yamada return 0; 157608f26c5SMasahiro Yamada } 158608f26c5SMasahiro Yamada 159608f26c5SMasahiro Yamada int devres_release(struct udevice *dev, dr_release_t release, 160608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 161608f26c5SMasahiro Yamada { 162608f26c5SMasahiro Yamada void *res; 163608f26c5SMasahiro Yamada 164608f26c5SMasahiro Yamada res = devres_remove(dev, release, match, match_data); 165608f26c5SMasahiro Yamada if (unlikely(!res)) 166608f26c5SMasahiro Yamada return -ENOENT; 167608f26c5SMasahiro Yamada 168608f26c5SMasahiro Yamada (*release)(dev, res); 169608f26c5SMasahiro Yamada devres_free(res); 170608f26c5SMasahiro Yamada return 0; 171608f26c5SMasahiro Yamada } 172608f26c5SMasahiro Yamada 173608f26c5SMasahiro Yamada static void release_nodes(struct udevice *dev, struct list_head *head, 174608f26c5SMasahiro Yamada bool probe_only) 175608f26c5SMasahiro Yamada { 176608f26c5SMasahiro Yamada struct devres *dr, *tmp; 177608f26c5SMasahiro Yamada 178608f26c5SMasahiro Yamada list_for_each_entry_safe_reverse(dr, tmp, head, entry) { 179608f26c5SMasahiro Yamada if (probe_only && !dr->probe) 180608f26c5SMasahiro Yamada break; 181608f26c5SMasahiro Yamada devres_log(dev, dr, "REL"); 182608f26c5SMasahiro Yamada dr->release(dev, dr->data); 183608f26c5SMasahiro Yamada list_del(&dr->entry); 184608f26c5SMasahiro Yamada kfree(dr); 185608f26c5SMasahiro Yamada } 186608f26c5SMasahiro Yamada } 187608f26c5SMasahiro Yamada 188608f26c5SMasahiro Yamada void devres_release_probe(struct udevice *dev) 189608f26c5SMasahiro Yamada { 190608f26c5SMasahiro Yamada release_nodes(dev, &dev->devres_head, true); 191608f26c5SMasahiro Yamada } 192608f26c5SMasahiro Yamada 193608f26c5SMasahiro Yamada void devres_release_all(struct udevice *dev) 194608f26c5SMasahiro Yamada { 195608f26c5SMasahiro Yamada release_nodes(dev, &dev->devres_head, false); 196608f26c5SMasahiro Yamada } 197*2b07f685SMasahiro Yamada 198*2b07f685SMasahiro Yamada /* 199*2b07f685SMasahiro Yamada * Managed kmalloc/kfree 200*2b07f685SMasahiro Yamada */ 201*2b07f685SMasahiro Yamada static void devm_kmalloc_release(struct udevice *dev, void *res) 202*2b07f685SMasahiro Yamada { 203*2b07f685SMasahiro Yamada /* noop */ 204*2b07f685SMasahiro Yamada } 205*2b07f685SMasahiro Yamada 206*2b07f685SMasahiro Yamada static int devm_kmalloc_match(struct udevice *dev, void *res, void *data) 207*2b07f685SMasahiro Yamada { 208*2b07f685SMasahiro Yamada return res == data; 209*2b07f685SMasahiro Yamada } 210*2b07f685SMasahiro Yamada 211*2b07f685SMasahiro Yamada void *devm_kmalloc(struct udevice *dev, size_t size, gfp_t gfp) 212*2b07f685SMasahiro Yamada { 213*2b07f685SMasahiro Yamada void *data; 214*2b07f685SMasahiro Yamada 215*2b07f685SMasahiro Yamada data = _devres_alloc(devm_kmalloc_release, size, gfp); 216*2b07f685SMasahiro Yamada if (unlikely(!data)) 217*2b07f685SMasahiro Yamada return NULL; 218*2b07f685SMasahiro Yamada 219*2b07f685SMasahiro Yamada devres_add(dev, data); 220*2b07f685SMasahiro Yamada 221*2b07f685SMasahiro Yamada return data; 222*2b07f685SMasahiro Yamada } 223*2b07f685SMasahiro Yamada 224*2b07f685SMasahiro Yamada void devm_kfree(struct udevice *dev, void *p) 225*2b07f685SMasahiro Yamada { 226*2b07f685SMasahiro Yamada int rc; 227*2b07f685SMasahiro Yamada 228*2b07f685SMasahiro Yamada rc = devres_destroy(dev, devm_kmalloc_release, devm_kmalloc_match, p); 229*2b07f685SMasahiro Yamada WARN_ON(rc); 230*2b07f685SMasahiro Yamada } 231