18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/string.h> 38c2ecf20Sopenharmony_ci#include <linux/kernel.h> 48c2ecf20Sopenharmony_ci#include <linux/of.h> 58c2ecf20Sopenharmony_ci#include <linux/of_device.h> 68c2ecf20Sopenharmony_ci#include <linux/of_address.h> 78c2ecf20Sopenharmony_ci#include <linux/of_iommu.h> 88c2ecf20Sopenharmony_ci#include <linux/dma-direct.h> /* for bus_dma_region */ 98c2ecf20Sopenharmony_ci#include <linux/dma-map-ops.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/module.h> 128c2ecf20Sopenharmony_ci#include <linux/mod_devicetable.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/errno.h> 178c2ecf20Sopenharmony_ci#include "of_private.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/** 208c2ecf20Sopenharmony_ci * of_match_device - Tell if a struct device matches an of_device_id list 218c2ecf20Sopenharmony_ci * @matches: array of of device match structures to search in 228c2ecf20Sopenharmony_ci * @dev: the of device structure to match against 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Used by a driver to check whether an platform_device present in the 258c2ecf20Sopenharmony_ci * system is in its list of supported devices. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_ciconst struct of_device_id *of_match_device(const struct of_device_id *matches, 288c2ecf20Sopenharmony_ci const struct device *dev) 298c2ecf20Sopenharmony_ci{ 308c2ecf20Sopenharmony_ci if ((!matches) || (!dev->of_node)) 318c2ecf20Sopenharmony_ci return NULL; 328c2ecf20Sopenharmony_ci return of_match_node(matches, dev->of_node); 338c2ecf20Sopenharmony_ci} 348c2ecf20Sopenharmony_ciEXPORT_SYMBOL(of_match_device); 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_cistruct platform_device *of_dev_get(struct platform_device *dev) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci struct device *tmp; 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci if (!dev) 418c2ecf20Sopenharmony_ci return NULL; 428c2ecf20Sopenharmony_ci tmp = get_device(&dev->dev); 438c2ecf20Sopenharmony_ci if (tmp) 448c2ecf20Sopenharmony_ci return to_platform_device(tmp); 458c2ecf20Sopenharmony_ci else 468c2ecf20Sopenharmony_ci return NULL; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ciEXPORT_SYMBOL(of_dev_get); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_civoid of_dev_put(struct platform_device *dev) 518c2ecf20Sopenharmony_ci{ 528c2ecf20Sopenharmony_ci if (dev) 538c2ecf20Sopenharmony_ci put_device(&dev->dev); 548c2ecf20Sopenharmony_ci} 558c2ecf20Sopenharmony_ciEXPORT_SYMBOL(of_dev_put); 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ciint of_device_add(struct platform_device *ofdev) 588c2ecf20Sopenharmony_ci{ 598c2ecf20Sopenharmony_ci BUG_ON(ofdev->dev.of_node == NULL); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci /* name and id have to be set so that the platform bus doesn't get 628c2ecf20Sopenharmony_ci * confused on matching */ 638c2ecf20Sopenharmony_ci ofdev->name = dev_name(&ofdev->dev); 648c2ecf20Sopenharmony_ci ofdev->id = PLATFORM_DEVID_NONE; 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* 678c2ecf20Sopenharmony_ci * If this device has not binding numa node in devicetree, that is 688c2ecf20Sopenharmony_ci * of_node_to_nid returns NUMA_NO_NODE. device_add will assume that this 698c2ecf20Sopenharmony_ci * device is on the same node as the parent. 708c2ecf20Sopenharmony_ci */ 718c2ecf20Sopenharmony_ci set_dev_node(&ofdev->dev, of_node_to_nid(ofdev->dev.of_node)); 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return device_add(&ofdev->dev); 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/** 778c2ecf20Sopenharmony_ci * of_dma_configure - Setup DMA configuration 788c2ecf20Sopenharmony_ci * @dev: Device to apply DMA configuration 798c2ecf20Sopenharmony_ci * @np: Pointer to OF node having DMA configuration 808c2ecf20Sopenharmony_ci * @force_dma: Whether device is to be set up by of_dma_configure() even if 818c2ecf20Sopenharmony_ci * DMA capability is not explicitly described by firmware. 828c2ecf20Sopenharmony_ci * @id: Optional const pointer value input id 838c2ecf20Sopenharmony_ci * 848c2ecf20Sopenharmony_ci * Try to get devices's DMA configuration from DT and update it 858c2ecf20Sopenharmony_ci * accordingly. 868c2ecf20Sopenharmony_ci * 878c2ecf20Sopenharmony_ci * If platform code needs to use its own special DMA configuration, it 888c2ecf20Sopenharmony_ci * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events 898c2ecf20Sopenharmony_ci * to fix up DMA configuration. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_ciint of_dma_configure_id(struct device *dev, struct device_node *np, 928c2ecf20Sopenharmony_ci bool force_dma, const u32 *id) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci const struct iommu_ops *iommu; 958c2ecf20Sopenharmony_ci const struct bus_dma_region *map = NULL; 968c2ecf20Sopenharmony_ci u64 dma_start = 0; 978c2ecf20Sopenharmony_ci u64 mask, end, size = 0; 988c2ecf20Sopenharmony_ci bool coherent; 998c2ecf20Sopenharmony_ci int ret; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci ret = of_dma_get_range(np, &map); 1028c2ecf20Sopenharmony_ci if (ret < 0) { 1038c2ecf20Sopenharmony_ci /* 1048c2ecf20Sopenharmony_ci * For legacy reasons, we have to assume some devices need 1058c2ecf20Sopenharmony_ci * DMA configuration regardless of whether "dma-ranges" is 1068c2ecf20Sopenharmony_ci * correctly specified or not. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ci if (!force_dma) 1098c2ecf20Sopenharmony_ci return ret == -ENODEV ? 0 : ret; 1108c2ecf20Sopenharmony_ci } else { 1118c2ecf20Sopenharmony_ci const struct bus_dma_region *r = map; 1128c2ecf20Sopenharmony_ci u64 dma_end = 0; 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci /* Determine the overall bounds of all DMA regions */ 1158c2ecf20Sopenharmony_ci for (dma_start = ~0; r->size; r++) { 1168c2ecf20Sopenharmony_ci /* Take lower and upper limits */ 1178c2ecf20Sopenharmony_ci if (r->dma_start < dma_start) 1188c2ecf20Sopenharmony_ci dma_start = r->dma_start; 1198c2ecf20Sopenharmony_ci if (r->dma_start + r->size > dma_end) 1208c2ecf20Sopenharmony_ci dma_end = r->dma_start + r->size; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci size = dma_end - dma_start; 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci /* 1258c2ecf20Sopenharmony_ci * Add a work around to treat the size as mask + 1 in case 1268c2ecf20Sopenharmony_ci * it is defined in DT as a mask. 1278c2ecf20Sopenharmony_ci */ 1288c2ecf20Sopenharmony_ci if (size & 1) { 1298c2ecf20Sopenharmony_ci dev_warn(dev, "Invalid size 0x%llx for dma-range(s)\n", 1308c2ecf20Sopenharmony_ci size); 1318c2ecf20Sopenharmony_ci size = size + 1; 1328c2ecf20Sopenharmony_ci } 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci if (!size) { 1358c2ecf20Sopenharmony_ci dev_err(dev, "Adjusted size 0x%llx invalid\n", size); 1368c2ecf20Sopenharmony_ci kfree(map); 1378c2ecf20Sopenharmony_ci return -EINVAL; 1388c2ecf20Sopenharmony_ci } 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* 1428c2ecf20Sopenharmony_ci * If @dev is expected to be DMA-capable then the bus code that created 1438c2ecf20Sopenharmony_ci * it should have initialised its dma_mask pointer by this point. For 1448c2ecf20Sopenharmony_ci * now, we'll continue the legacy behaviour of coercing it to the 1458c2ecf20Sopenharmony_ci * coherent mask if not, but we'll no longer do so quietly. 1468c2ecf20Sopenharmony_ci */ 1478c2ecf20Sopenharmony_ci if (!dev->dma_mask) { 1488c2ecf20Sopenharmony_ci dev_warn(dev, "DMA mask not set\n"); 1498c2ecf20Sopenharmony_ci dev->dma_mask = &dev->coherent_dma_mask; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (!size && dev->coherent_dma_mask) 1538c2ecf20Sopenharmony_ci size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); 1548c2ecf20Sopenharmony_ci else if (!size) 1558c2ecf20Sopenharmony_ci size = 1ULL << 32; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci /* 1588c2ecf20Sopenharmony_ci * Limit coherent and dma mask based on size and default mask 1598c2ecf20Sopenharmony_ci * set by the driver. 1608c2ecf20Sopenharmony_ci */ 1618c2ecf20Sopenharmony_ci end = dma_start + size - 1; 1628c2ecf20Sopenharmony_ci mask = DMA_BIT_MASK(ilog2(end) + 1); 1638c2ecf20Sopenharmony_ci dev->coherent_dma_mask &= mask; 1648c2ecf20Sopenharmony_ci *dev->dma_mask &= mask; 1658c2ecf20Sopenharmony_ci /* ...but only set bus limit and range map if we found valid dma-ranges earlier */ 1668c2ecf20Sopenharmony_ci if (!ret) { 1678c2ecf20Sopenharmony_ci dev->bus_dma_limit = end; 1688c2ecf20Sopenharmony_ci dev->dma_range_map = map; 1698c2ecf20Sopenharmony_ci } 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci coherent = of_dma_is_coherent(np); 1728c2ecf20Sopenharmony_ci dev_dbg(dev, "device is%sdma coherent\n", 1738c2ecf20Sopenharmony_ci coherent ? " " : " not "); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci iommu = of_iommu_configure(dev, np, id); 1768c2ecf20Sopenharmony_ci if (PTR_ERR(iommu) == -EPROBE_DEFER) { 1778c2ecf20Sopenharmony_ci /* Don't touch range map if it wasn't set from a valid dma-ranges */ 1788c2ecf20Sopenharmony_ci if (!ret) 1798c2ecf20Sopenharmony_ci dev->dma_range_map = NULL; 1808c2ecf20Sopenharmony_ci kfree(map); 1818c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 1828c2ecf20Sopenharmony_ci } 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci dev_dbg(dev, "device is%sbehind an iommu\n", 1858c2ecf20Sopenharmony_ci iommu ? " " : " not "); 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci arch_setup_dma_ops(dev, dma_start, size, iommu, coherent); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci return 0; 1908c2ecf20Sopenharmony_ci} 1918c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_dma_configure_id); 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ciint of_device_register(struct platform_device *pdev) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci device_initialize(&pdev->dev); 1968c2ecf20Sopenharmony_ci return of_device_add(pdev); 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ciEXPORT_SYMBOL(of_device_register); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_civoid of_device_unregister(struct platform_device *ofdev) 2018c2ecf20Sopenharmony_ci{ 2028c2ecf20Sopenharmony_ci device_unregister(&ofdev->dev); 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ciEXPORT_SYMBOL(of_device_unregister); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ciconst void *of_device_get_match_data(const struct device *dev) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci const struct of_device_id *match; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci match = of_match_device(dev->driver->of_match_table, dev); 2118c2ecf20Sopenharmony_ci if (!match) 2128c2ecf20Sopenharmony_ci return NULL; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci return match->data; 2158c2ecf20Sopenharmony_ci} 2168c2ecf20Sopenharmony_ciEXPORT_SYMBOL(of_device_get_match_data); 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_cistatic ssize_t of_device_get_modalias(struct device *dev, char *str, ssize_t len) 2198c2ecf20Sopenharmony_ci{ 2208c2ecf20Sopenharmony_ci const char *compat; 2218c2ecf20Sopenharmony_ci char *c; 2228c2ecf20Sopenharmony_ci struct property *p; 2238c2ecf20Sopenharmony_ci ssize_t csize; 2248c2ecf20Sopenharmony_ci ssize_t tsize; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if ((!dev) || (!dev->of_node)) 2278c2ecf20Sopenharmony_ci return -ENODEV; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci /* Name & Type */ 2308c2ecf20Sopenharmony_ci /* %p eats all alphanum characters, so %c must be used here */ 2318c2ecf20Sopenharmony_ci csize = snprintf(str, len, "of:N%pOFn%c%s", dev->of_node, 'T', 2328c2ecf20Sopenharmony_ci of_node_get_device_type(dev->of_node)); 2338c2ecf20Sopenharmony_ci tsize = csize; 2348c2ecf20Sopenharmony_ci len -= csize; 2358c2ecf20Sopenharmony_ci if (str) 2368c2ecf20Sopenharmony_ci str += csize; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci of_property_for_each_string(dev->of_node, "compatible", p, compat) { 2398c2ecf20Sopenharmony_ci csize = strlen(compat) + 1; 2408c2ecf20Sopenharmony_ci tsize += csize; 2418c2ecf20Sopenharmony_ci if (csize > len) 2428c2ecf20Sopenharmony_ci continue; 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci csize = snprintf(str, len, "C%s", compat); 2458c2ecf20Sopenharmony_ci for (c = str; c; ) { 2468c2ecf20Sopenharmony_ci c = strchr(c, ' '); 2478c2ecf20Sopenharmony_ci if (c) 2488c2ecf20Sopenharmony_ci *c++ = '_'; 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci len -= csize; 2518c2ecf20Sopenharmony_ci str += csize; 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci return tsize; 2558c2ecf20Sopenharmony_ci} 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ciint of_device_request_module(struct device *dev) 2588c2ecf20Sopenharmony_ci{ 2598c2ecf20Sopenharmony_ci char *str; 2608c2ecf20Sopenharmony_ci ssize_t size; 2618c2ecf20Sopenharmony_ci int ret; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci size = of_device_get_modalias(dev, NULL, 0); 2648c2ecf20Sopenharmony_ci if (size < 0) 2658c2ecf20Sopenharmony_ci return size; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* Reserve an additional byte for the trailing '\0' */ 2688c2ecf20Sopenharmony_ci size++; 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci str = kmalloc(size, GFP_KERNEL); 2718c2ecf20Sopenharmony_ci if (!str) 2728c2ecf20Sopenharmony_ci return -ENOMEM; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci of_device_get_modalias(dev, str, size); 2758c2ecf20Sopenharmony_ci str[size - 1] = '\0'; 2768c2ecf20Sopenharmony_ci ret = request_module(str); 2778c2ecf20Sopenharmony_ci kfree(str); 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci return ret; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_device_request_module); 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci/** 2848c2ecf20Sopenharmony_ci * of_device_modalias - Fill buffer with newline terminated modalias string 2858c2ecf20Sopenharmony_ci */ 2868c2ecf20Sopenharmony_cissize_t of_device_modalias(struct device *dev, char *str, ssize_t len) 2878c2ecf20Sopenharmony_ci{ 2888c2ecf20Sopenharmony_ci ssize_t sl = of_device_get_modalias(dev, str, len - 2); 2898c2ecf20Sopenharmony_ci if (sl < 0) 2908c2ecf20Sopenharmony_ci return sl; 2918c2ecf20Sopenharmony_ci if (sl > len - 2) 2928c2ecf20Sopenharmony_ci return -ENOMEM; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci str[sl++] = '\n'; 2958c2ecf20Sopenharmony_ci str[sl] = 0; 2968c2ecf20Sopenharmony_ci return sl; 2978c2ecf20Sopenharmony_ci} 2988c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_device_modalias); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci/** 3018c2ecf20Sopenharmony_ci * of_device_uevent - Display OF related uevent information 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_civoid of_device_uevent(struct device *dev, struct kobj_uevent_env *env) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci const char *compat, *type; 3068c2ecf20Sopenharmony_ci struct alias_prop *app; 3078c2ecf20Sopenharmony_ci struct property *p; 3088c2ecf20Sopenharmony_ci int seen = 0; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci if ((!dev) || (!dev->of_node)) 3118c2ecf20Sopenharmony_ci return; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci add_uevent_var(env, "OF_NAME=%pOFn", dev->of_node); 3148c2ecf20Sopenharmony_ci add_uevent_var(env, "OF_FULLNAME=%pOF", dev->of_node); 3158c2ecf20Sopenharmony_ci type = of_node_get_device_type(dev->of_node); 3168c2ecf20Sopenharmony_ci if (type) 3178c2ecf20Sopenharmony_ci add_uevent_var(env, "OF_TYPE=%s", type); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Since the compatible field can contain pretty much anything 3208c2ecf20Sopenharmony_ci * it's not really legal to split it out with commas. We split it 3218c2ecf20Sopenharmony_ci * up using a number of environment variables instead. */ 3228c2ecf20Sopenharmony_ci of_property_for_each_string(dev->of_node, "compatible", p, compat) { 3238c2ecf20Sopenharmony_ci add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat); 3248c2ecf20Sopenharmony_ci seen++; 3258c2ecf20Sopenharmony_ci } 3268c2ecf20Sopenharmony_ci add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci seen = 0; 3298c2ecf20Sopenharmony_ci mutex_lock(&of_mutex); 3308c2ecf20Sopenharmony_ci list_for_each_entry(app, &aliases_lookup, link) { 3318c2ecf20Sopenharmony_ci if (dev->of_node == app->np) { 3328c2ecf20Sopenharmony_ci add_uevent_var(env, "OF_ALIAS_%d=%s", seen, 3338c2ecf20Sopenharmony_ci app->alias); 3348c2ecf20Sopenharmony_ci seen++; 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci } 3378c2ecf20Sopenharmony_ci mutex_unlock(&of_mutex); 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ciint of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci int sl; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci if ((!dev) || (!dev->of_node)) 3458c2ecf20Sopenharmony_ci return -ENODEV; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* Devicetree modalias is tricky, we add it in 2 steps */ 3488c2ecf20Sopenharmony_ci if (add_uevent_var(env, "MODALIAS=")) 3498c2ecf20Sopenharmony_ci return -ENOMEM; 3508c2ecf20Sopenharmony_ci 3518c2ecf20Sopenharmony_ci sl = of_device_get_modalias(dev, &env->buf[env->buflen-1], 3528c2ecf20Sopenharmony_ci sizeof(env->buf) - env->buflen); 3538c2ecf20Sopenharmony_ci if (sl >= (sizeof(env->buf) - env->buflen)) 3548c2ecf20Sopenharmony_ci return -ENOMEM; 3558c2ecf20Sopenharmony_ci env->buflen += sl; 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci return 0; 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_device_uevent_modalias); 360