1*608f26c5SMasahiro Yamada /* 2*608f26c5SMasahiro Yamada * Copyright (C) 2015 Masahiro Yamada <yamada.masahiro@socionext.com> 3*608f26c5SMasahiro Yamada * 4*608f26c5SMasahiro Yamada * Based on the original work in Linux by 5*608f26c5SMasahiro Yamada * Copyright (c) 2006 SUSE Linux Products GmbH 6*608f26c5SMasahiro Yamada * Copyright (c) 2006 Tejun Heo <teheo@suse.de> 7*608f26c5SMasahiro Yamada * 8*608f26c5SMasahiro Yamada * SPDX-License-Identifier: GPL-2.0+ 9*608f26c5SMasahiro Yamada */ 10*608f26c5SMasahiro Yamada 11*608f26c5SMasahiro Yamada #include <common.h> 12*608f26c5SMasahiro Yamada #include <linux/compat.h> 13*608f26c5SMasahiro Yamada #include <linux/kernel.h> 14*608f26c5SMasahiro Yamada #include <linux/list.h> 15*608f26c5SMasahiro Yamada #include <dm/device.h> 16*608f26c5SMasahiro Yamada 17*608f26c5SMasahiro Yamada /** 18*608f26c5SMasahiro Yamada * struct devres - Bookkeeping info for managed device resource 19*608f26c5SMasahiro Yamada * @entry: List to associate this structure with a device 20*608f26c5SMasahiro Yamada * @release: Callback invoked when this resource is released 21*608f26c5SMasahiro Yamada * @probe: Flag to show when this resource was allocated 22*608f26c5SMasahiro Yamada (true = probe, false = bind) 23*608f26c5SMasahiro Yamada * @name: Name of release function 24*608f26c5SMasahiro Yamada * @size: Size of resource data 25*608f26c5SMasahiro Yamada * @data: Resource data 26*608f26c5SMasahiro Yamada */ 27*608f26c5SMasahiro Yamada struct devres { 28*608f26c5SMasahiro Yamada struct list_head entry; 29*608f26c5SMasahiro Yamada dr_release_t release; 30*608f26c5SMasahiro Yamada bool probe; 31*608f26c5SMasahiro Yamada #ifdef CONFIG_DEBUG_DEVRES 32*608f26c5SMasahiro Yamada const char *name; 33*608f26c5SMasahiro Yamada size_t size; 34*608f26c5SMasahiro Yamada #endif 35*608f26c5SMasahiro Yamada unsigned long long data[]; 36*608f26c5SMasahiro Yamada }; 37*608f26c5SMasahiro Yamada 38*608f26c5SMasahiro Yamada #ifdef CONFIG_DEBUG_DEVRES 39*608f26c5SMasahiro Yamada static void set_node_dbginfo(struct devres *dr, const char *name, size_t size) 40*608f26c5SMasahiro Yamada { 41*608f26c5SMasahiro Yamada dr->name = name; 42*608f26c5SMasahiro Yamada dr->size = size; 43*608f26c5SMasahiro Yamada } 44*608f26c5SMasahiro Yamada 45*608f26c5SMasahiro Yamada static void devres_log(struct udevice *dev, struct devres *dr, 46*608f26c5SMasahiro Yamada const char *op) 47*608f26c5SMasahiro Yamada { 48*608f26c5SMasahiro Yamada printf("%s: DEVRES %3s %p %s (%lu bytes)\n", 49*608f26c5SMasahiro Yamada dev->name, op, dr, dr->name, (unsigned long)dr->size); 50*608f26c5SMasahiro Yamada } 51*608f26c5SMasahiro Yamada #else /* CONFIG_DEBUG_DEVRES */ 52*608f26c5SMasahiro Yamada #define set_node_dbginfo(dr, n, s) do {} while (0) 53*608f26c5SMasahiro Yamada #define devres_log(dev, dr, op) do {} while (0) 54*608f26c5SMasahiro Yamada #endif 55*608f26c5SMasahiro Yamada 56*608f26c5SMasahiro Yamada #if CONFIG_DEBUG_DEVRES 57*608f26c5SMasahiro Yamada void *__devres_alloc(dr_release_t release, size_t size, gfp_t gfp, 58*608f26c5SMasahiro Yamada const char *name) 59*608f26c5SMasahiro Yamada #else 60*608f26c5SMasahiro Yamada void *_devres_alloc(dr_release_t release, size_t size, gfp_t gfp) 61*608f26c5SMasahiro Yamada #endif 62*608f26c5SMasahiro Yamada { 63*608f26c5SMasahiro Yamada size_t tot_size = sizeof(struct devres) + size; 64*608f26c5SMasahiro Yamada struct devres *dr; 65*608f26c5SMasahiro Yamada 66*608f26c5SMasahiro Yamada dr = kmalloc(tot_size, gfp); 67*608f26c5SMasahiro Yamada if (unlikely(!dr)) 68*608f26c5SMasahiro Yamada return NULL; 69*608f26c5SMasahiro Yamada 70*608f26c5SMasahiro Yamada INIT_LIST_HEAD(&dr->entry); 71*608f26c5SMasahiro Yamada dr->release = release; 72*608f26c5SMasahiro Yamada set_node_dbginfo(dr, name, size); 73*608f26c5SMasahiro Yamada 74*608f26c5SMasahiro Yamada return dr->data; 75*608f26c5SMasahiro Yamada } 76*608f26c5SMasahiro Yamada 77*608f26c5SMasahiro Yamada void devres_free(void *res) 78*608f26c5SMasahiro Yamada { 79*608f26c5SMasahiro Yamada if (res) { 80*608f26c5SMasahiro Yamada struct devres *dr = container_of(res, struct devres, data); 81*608f26c5SMasahiro Yamada 82*608f26c5SMasahiro Yamada BUG_ON(!list_empty(&dr->entry)); 83*608f26c5SMasahiro Yamada kfree(dr); 84*608f26c5SMasahiro Yamada } 85*608f26c5SMasahiro Yamada } 86*608f26c5SMasahiro Yamada 87*608f26c5SMasahiro Yamada void devres_add(struct udevice *dev, void *res) 88*608f26c5SMasahiro Yamada { 89*608f26c5SMasahiro Yamada struct devres *dr = container_of(res, struct devres, data); 90*608f26c5SMasahiro Yamada 91*608f26c5SMasahiro Yamada devres_log(dev, dr, "ADD"); 92*608f26c5SMasahiro Yamada BUG_ON(!list_empty(&dr->entry)); 93*608f26c5SMasahiro Yamada dr->probe = dev->flags & DM_FLAG_BOUND ? true : false; 94*608f26c5SMasahiro Yamada list_add_tail(&dr->entry, &dev->devres_head); 95*608f26c5SMasahiro Yamada } 96*608f26c5SMasahiro Yamada 97*608f26c5SMasahiro Yamada void *devres_find(struct udevice *dev, dr_release_t release, 98*608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 99*608f26c5SMasahiro Yamada { 100*608f26c5SMasahiro Yamada struct devres *dr; 101*608f26c5SMasahiro Yamada 102*608f26c5SMasahiro Yamada list_for_each_entry_reverse(dr, &dev->devres_head, entry) { 103*608f26c5SMasahiro Yamada if (dr->release != release) 104*608f26c5SMasahiro Yamada continue; 105*608f26c5SMasahiro Yamada if (match && !match(dev, dr->data, match_data)) 106*608f26c5SMasahiro Yamada continue; 107*608f26c5SMasahiro Yamada return dr->data; 108*608f26c5SMasahiro Yamada } 109*608f26c5SMasahiro Yamada 110*608f26c5SMasahiro Yamada return NULL; 111*608f26c5SMasahiro Yamada } 112*608f26c5SMasahiro Yamada 113*608f26c5SMasahiro Yamada void *devres_get(struct udevice *dev, void *new_res, 114*608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 115*608f26c5SMasahiro Yamada { 116*608f26c5SMasahiro Yamada struct devres *new_dr = container_of(new_res, struct devres, data); 117*608f26c5SMasahiro Yamada void *res; 118*608f26c5SMasahiro Yamada 119*608f26c5SMasahiro Yamada res = devres_find(dev, new_dr->release, match, match_data); 120*608f26c5SMasahiro Yamada if (!res) { 121*608f26c5SMasahiro Yamada devres_add(dev, new_res); 122*608f26c5SMasahiro Yamada res = new_res; 123*608f26c5SMasahiro Yamada new_res = NULL; 124*608f26c5SMasahiro Yamada } 125*608f26c5SMasahiro Yamada devres_free(new_res); 126*608f26c5SMasahiro Yamada 127*608f26c5SMasahiro Yamada return res; 128*608f26c5SMasahiro Yamada } 129*608f26c5SMasahiro Yamada 130*608f26c5SMasahiro Yamada void *devres_remove(struct udevice *dev, dr_release_t release, 131*608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 132*608f26c5SMasahiro Yamada { 133*608f26c5SMasahiro Yamada void *res; 134*608f26c5SMasahiro Yamada 135*608f26c5SMasahiro Yamada res = devres_find(dev, release, match, match_data); 136*608f26c5SMasahiro Yamada if (res) { 137*608f26c5SMasahiro Yamada struct devres *dr = container_of(res, struct devres, data); 138*608f26c5SMasahiro Yamada 139*608f26c5SMasahiro Yamada list_del_init(&dr->entry); 140*608f26c5SMasahiro Yamada devres_log(dev, dr, "REM"); 141*608f26c5SMasahiro Yamada } 142*608f26c5SMasahiro Yamada 143*608f26c5SMasahiro Yamada return res; 144*608f26c5SMasahiro Yamada } 145*608f26c5SMasahiro Yamada 146*608f26c5SMasahiro Yamada int devres_destroy(struct udevice *dev, dr_release_t release, 147*608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 148*608f26c5SMasahiro Yamada { 149*608f26c5SMasahiro Yamada void *res; 150*608f26c5SMasahiro Yamada 151*608f26c5SMasahiro Yamada res = devres_remove(dev, release, match, match_data); 152*608f26c5SMasahiro Yamada if (unlikely(!res)) 153*608f26c5SMasahiro Yamada return -ENOENT; 154*608f26c5SMasahiro Yamada 155*608f26c5SMasahiro Yamada devres_free(res); 156*608f26c5SMasahiro Yamada return 0; 157*608f26c5SMasahiro Yamada } 158*608f26c5SMasahiro Yamada 159*608f26c5SMasahiro Yamada int devres_release(struct udevice *dev, dr_release_t release, 160*608f26c5SMasahiro Yamada dr_match_t match, void *match_data) 161*608f26c5SMasahiro Yamada { 162*608f26c5SMasahiro Yamada void *res; 163*608f26c5SMasahiro Yamada 164*608f26c5SMasahiro Yamada res = devres_remove(dev, release, match, match_data); 165*608f26c5SMasahiro Yamada if (unlikely(!res)) 166*608f26c5SMasahiro Yamada return -ENOENT; 167*608f26c5SMasahiro Yamada 168*608f26c5SMasahiro Yamada (*release)(dev, res); 169*608f26c5SMasahiro Yamada devres_free(res); 170*608f26c5SMasahiro Yamada return 0; 171*608f26c5SMasahiro Yamada } 172*608f26c5SMasahiro Yamada 173*608f26c5SMasahiro Yamada static void release_nodes(struct udevice *dev, struct list_head *head, 174*608f26c5SMasahiro Yamada bool probe_only) 175*608f26c5SMasahiro Yamada { 176*608f26c5SMasahiro Yamada struct devres *dr, *tmp; 177*608f26c5SMasahiro Yamada 178*608f26c5SMasahiro Yamada list_for_each_entry_safe_reverse(dr, tmp, head, entry) { 179*608f26c5SMasahiro Yamada if (probe_only && !dr->probe) 180*608f26c5SMasahiro Yamada break; 181*608f26c5SMasahiro Yamada devres_log(dev, dr, "REL"); 182*608f26c5SMasahiro Yamada dr->release(dev, dr->data); 183*608f26c5SMasahiro Yamada list_del(&dr->entry); 184*608f26c5SMasahiro Yamada kfree(dr); 185*608f26c5SMasahiro Yamada } 186*608f26c5SMasahiro Yamada } 187*608f26c5SMasahiro Yamada 188*608f26c5SMasahiro Yamada void devres_release_probe(struct udevice *dev) 189*608f26c5SMasahiro Yamada { 190*608f26c5SMasahiro Yamada release_nodes(dev, &dev->devres_head, true); 191*608f26c5SMasahiro Yamada } 192*608f26c5SMasahiro Yamada 193*608f26c5SMasahiro Yamada void devres_release_all(struct udevice *dev) 194*608f26c5SMasahiro Yamada { 195*608f26c5SMasahiro Yamada release_nodes(dev, &dev->devres_head, false); 196*608f26c5SMasahiro Yamada } 197