162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <linux/kernel.h> 362306a36Sopenharmony_ci#include <linux/of.h> 462306a36Sopenharmony_ci#include <linux/of_device.h> 562306a36Sopenharmony_ci#include <linux/of_address.h> 662306a36Sopenharmony_ci#include <linux/of_iommu.h> 762306a36Sopenharmony_ci#include <linux/of_reserved_mem.h> 862306a36Sopenharmony_ci#include <linux/dma-direct.h> /* for bus_dma_region */ 962306a36Sopenharmony_ci#include <linux/dma-map-ops.h> 1062306a36Sopenharmony_ci#include <linux/init.h> 1162306a36Sopenharmony_ci#include <linux/mod_devicetable.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/platform_device.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include <asm/errno.h> 1662306a36Sopenharmony_ci#include "of_private.h" 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci/** 1962306a36Sopenharmony_ci * of_match_device - Tell if a struct device matches an of_device_id list 2062306a36Sopenharmony_ci * @matches: array of of device match structures to search in 2162306a36Sopenharmony_ci * @dev: the of device structure to match against 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * Used by a driver to check whether an platform_device present in the 2462306a36Sopenharmony_ci * system is in its list of supported devices. 2562306a36Sopenharmony_ci */ 2662306a36Sopenharmony_ciconst struct of_device_id *of_match_device(const struct of_device_id *matches, 2762306a36Sopenharmony_ci const struct device *dev) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci if (!matches || !dev->of_node || dev->of_node_reused) 3062306a36Sopenharmony_ci return NULL; 3162306a36Sopenharmony_ci return of_match_node(matches, dev->of_node); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ciEXPORT_SYMBOL(of_match_device); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_cistatic void 3662306a36Sopenharmony_ciof_dma_set_restricted_buffer(struct device *dev, struct device_node *np) 3762306a36Sopenharmony_ci{ 3862306a36Sopenharmony_ci struct device_node *node, *of_node = dev->of_node; 3962306a36Sopenharmony_ci int count, i; 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_DMA_RESTRICTED_POOL)) 4262306a36Sopenharmony_ci return; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci count = of_property_count_elems_of_size(of_node, "memory-region", 4562306a36Sopenharmony_ci sizeof(u32)); 4662306a36Sopenharmony_ci /* 4762306a36Sopenharmony_ci * If dev->of_node doesn't exist or doesn't contain memory-region, try 4862306a36Sopenharmony_ci * the OF node having DMA configuration. 4962306a36Sopenharmony_ci */ 5062306a36Sopenharmony_ci if (count <= 0) { 5162306a36Sopenharmony_ci of_node = np; 5262306a36Sopenharmony_ci count = of_property_count_elems_of_size( 5362306a36Sopenharmony_ci of_node, "memory-region", sizeof(u32)); 5462306a36Sopenharmony_ci } 5562306a36Sopenharmony_ci 5662306a36Sopenharmony_ci for (i = 0; i < count; i++) { 5762306a36Sopenharmony_ci node = of_parse_phandle(of_node, "memory-region", i); 5862306a36Sopenharmony_ci /* 5962306a36Sopenharmony_ci * There might be multiple memory regions, but only one 6062306a36Sopenharmony_ci * restricted-dma-pool region is allowed. 6162306a36Sopenharmony_ci */ 6262306a36Sopenharmony_ci if (of_device_is_compatible(node, "restricted-dma-pool") && 6362306a36Sopenharmony_ci of_device_is_available(node)) { 6462306a36Sopenharmony_ci of_node_put(node); 6562306a36Sopenharmony_ci break; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci of_node_put(node); 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* 7162306a36Sopenharmony_ci * Attempt to initialize a restricted-dma-pool region if one was found. 7262306a36Sopenharmony_ci * Note that count can hold a negative error code. 7362306a36Sopenharmony_ci */ 7462306a36Sopenharmony_ci if (i < count && of_reserved_mem_device_init_by_idx(dev, of_node, i)) 7562306a36Sopenharmony_ci dev_warn(dev, "failed to initialise \"restricted-dma-pool\" memory node\n"); 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci/** 7962306a36Sopenharmony_ci * of_dma_configure_id - Setup DMA configuration 8062306a36Sopenharmony_ci * @dev: Device to apply DMA configuration 8162306a36Sopenharmony_ci * @np: Pointer to OF node having DMA configuration 8262306a36Sopenharmony_ci * @force_dma: Whether device is to be set up by of_dma_configure() even if 8362306a36Sopenharmony_ci * DMA capability is not explicitly described by firmware. 8462306a36Sopenharmony_ci * @id: Optional const pointer value input id 8562306a36Sopenharmony_ci * 8662306a36Sopenharmony_ci * Try to get devices's DMA configuration from DT and update it 8762306a36Sopenharmony_ci * accordingly. 8862306a36Sopenharmony_ci * 8962306a36Sopenharmony_ci * If platform code needs to use its own special DMA configuration, it 9062306a36Sopenharmony_ci * can use a platform bus notifier and handle BUS_NOTIFY_ADD_DEVICE events 9162306a36Sopenharmony_ci * to fix up DMA configuration. 9262306a36Sopenharmony_ci */ 9362306a36Sopenharmony_ciint of_dma_configure_id(struct device *dev, struct device_node *np, 9462306a36Sopenharmony_ci bool force_dma, const u32 *id) 9562306a36Sopenharmony_ci{ 9662306a36Sopenharmony_ci const struct iommu_ops *iommu; 9762306a36Sopenharmony_ci const struct bus_dma_region *map = NULL; 9862306a36Sopenharmony_ci struct device_node *bus_np; 9962306a36Sopenharmony_ci u64 dma_start = 0; 10062306a36Sopenharmony_ci u64 mask, end, size = 0; 10162306a36Sopenharmony_ci bool coherent; 10262306a36Sopenharmony_ci int ret; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (np == dev->of_node) 10562306a36Sopenharmony_ci bus_np = __of_get_dma_parent(np); 10662306a36Sopenharmony_ci else 10762306a36Sopenharmony_ci bus_np = of_node_get(np); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci ret = of_dma_get_range(bus_np, &map); 11062306a36Sopenharmony_ci of_node_put(bus_np); 11162306a36Sopenharmony_ci if (ret < 0) { 11262306a36Sopenharmony_ci /* 11362306a36Sopenharmony_ci * For legacy reasons, we have to assume some devices need 11462306a36Sopenharmony_ci * DMA configuration regardless of whether "dma-ranges" is 11562306a36Sopenharmony_ci * correctly specified or not. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ci if (!force_dma) 11862306a36Sopenharmony_ci return ret == -ENODEV ? 0 : ret; 11962306a36Sopenharmony_ci } else { 12062306a36Sopenharmony_ci const struct bus_dma_region *r = map; 12162306a36Sopenharmony_ci u64 dma_end = 0; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* Determine the overall bounds of all DMA regions */ 12462306a36Sopenharmony_ci for (dma_start = ~0; r->size; r++) { 12562306a36Sopenharmony_ci /* Take lower and upper limits */ 12662306a36Sopenharmony_ci if (r->dma_start < dma_start) 12762306a36Sopenharmony_ci dma_start = r->dma_start; 12862306a36Sopenharmony_ci if (r->dma_start + r->size > dma_end) 12962306a36Sopenharmony_ci dma_end = r->dma_start + r->size; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci size = dma_end - dma_start; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci /* 13462306a36Sopenharmony_ci * Add a work around to treat the size as mask + 1 in case 13562306a36Sopenharmony_ci * it is defined in DT as a mask. 13662306a36Sopenharmony_ci */ 13762306a36Sopenharmony_ci if (size & 1) { 13862306a36Sopenharmony_ci dev_warn(dev, "Invalid size 0x%llx for dma-range(s)\n", 13962306a36Sopenharmony_ci size); 14062306a36Sopenharmony_ci size = size + 1; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci if (!size) { 14462306a36Sopenharmony_ci dev_err(dev, "Adjusted size 0x%llx invalid\n", size); 14562306a36Sopenharmony_ci kfree(map); 14662306a36Sopenharmony_ci return -EINVAL; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* 15162306a36Sopenharmony_ci * If @dev is expected to be DMA-capable then the bus code that created 15262306a36Sopenharmony_ci * it should have initialised its dma_mask pointer by this point. For 15362306a36Sopenharmony_ci * now, we'll continue the legacy behaviour of coercing it to the 15462306a36Sopenharmony_ci * coherent mask if not, but we'll no longer do so quietly. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci if (!dev->dma_mask) { 15762306a36Sopenharmony_ci dev_warn(dev, "DMA mask not set\n"); 15862306a36Sopenharmony_ci dev->dma_mask = &dev->coherent_dma_mask; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci if (!size && dev->coherent_dma_mask) 16262306a36Sopenharmony_ci size = max(dev->coherent_dma_mask, dev->coherent_dma_mask + 1); 16362306a36Sopenharmony_ci else if (!size) 16462306a36Sopenharmony_ci size = 1ULL << 32; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* 16762306a36Sopenharmony_ci * Limit coherent and dma mask based on size and default mask 16862306a36Sopenharmony_ci * set by the driver. 16962306a36Sopenharmony_ci */ 17062306a36Sopenharmony_ci end = dma_start + size - 1; 17162306a36Sopenharmony_ci mask = DMA_BIT_MASK(ilog2(end) + 1); 17262306a36Sopenharmony_ci dev->coherent_dma_mask &= mask; 17362306a36Sopenharmony_ci *dev->dma_mask &= mask; 17462306a36Sopenharmony_ci /* ...but only set bus limit and range map if we found valid dma-ranges earlier */ 17562306a36Sopenharmony_ci if (!ret) { 17662306a36Sopenharmony_ci dev->bus_dma_limit = end; 17762306a36Sopenharmony_ci dev->dma_range_map = map; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci coherent = of_dma_is_coherent(np); 18162306a36Sopenharmony_ci dev_dbg(dev, "device is%sdma coherent\n", 18262306a36Sopenharmony_ci coherent ? " " : " not "); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci iommu = of_iommu_configure(dev, np, id); 18562306a36Sopenharmony_ci if (PTR_ERR(iommu) == -EPROBE_DEFER) { 18662306a36Sopenharmony_ci /* Don't touch range map if it wasn't set from a valid dma-ranges */ 18762306a36Sopenharmony_ci if (!ret) 18862306a36Sopenharmony_ci dev->dma_range_map = NULL; 18962306a36Sopenharmony_ci kfree(map); 19062306a36Sopenharmony_ci return -EPROBE_DEFER; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci dev_dbg(dev, "device is%sbehind an iommu\n", 19462306a36Sopenharmony_ci iommu ? " " : " not "); 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci arch_setup_dma_ops(dev, dma_start, size, iommu, coherent); 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (!iommu) 19962306a36Sopenharmony_ci of_dma_set_restricted_buffer(dev, np); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci return 0; 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_dma_configure_id); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ciconst void *of_device_get_match_data(const struct device *dev) 20662306a36Sopenharmony_ci{ 20762306a36Sopenharmony_ci const struct of_device_id *match; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci match = of_match_device(dev->driver->of_match_table, dev); 21062306a36Sopenharmony_ci if (!match) 21162306a36Sopenharmony_ci return NULL; 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci return match->data; 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ciEXPORT_SYMBOL(of_device_get_match_data); 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/** 21862306a36Sopenharmony_ci * of_device_modalias - Fill buffer with newline terminated modalias string 21962306a36Sopenharmony_ci * @dev: Calling device 22062306a36Sopenharmony_ci * @str: Modalias string 22162306a36Sopenharmony_ci * @len: Size of @str 22262306a36Sopenharmony_ci */ 22362306a36Sopenharmony_cissize_t of_device_modalias(struct device *dev, char *str, ssize_t len) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci ssize_t sl; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (!dev || !dev->of_node || dev->of_node_reused) 22862306a36Sopenharmony_ci return -ENODEV; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci sl = of_modalias(dev->of_node, str, len - 2); 23162306a36Sopenharmony_ci if (sl < 0) 23262306a36Sopenharmony_ci return sl; 23362306a36Sopenharmony_ci if (sl > len - 2) 23462306a36Sopenharmony_ci return -ENOMEM; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci str[sl++] = '\n'; 23762306a36Sopenharmony_ci str[sl] = 0; 23862306a36Sopenharmony_ci return sl; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_device_modalias); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/** 24362306a36Sopenharmony_ci * of_device_uevent - Display OF related uevent information 24462306a36Sopenharmony_ci * @dev: Device to display the uevent information for 24562306a36Sopenharmony_ci * @env: Kernel object's userspace event reference to fill up 24662306a36Sopenharmony_ci */ 24762306a36Sopenharmony_civoid of_device_uevent(const struct device *dev, struct kobj_uevent_env *env) 24862306a36Sopenharmony_ci{ 24962306a36Sopenharmony_ci const char *compat, *type; 25062306a36Sopenharmony_ci struct alias_prop *app; 25162306a36Sopenharmony_ci struct property *p; 25262306a36Sopenharmony_ci int seen = 0; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if ((!dev) || (!dev->of_node)) 25562306a36Sopenharmony_ci return; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci add_uevent_var(env, "OF_NAME=%pOFn", dev->of_node); 25862306a36Sopenharmony_ci add_uevent_var(env, "OF_FULLNAME=%pOF", dev->of_node); 25962306a36Sopenharmony_ci type = of_node_get_device_type(dev->of_node); 26062306a36Sopenharmony_ci if (type) 26162306a36Sopenharmony_ci add_uevent_var(env, "OF_TYPE=%s", type); 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci /* Since the compatible field can contain pretty much anything 26462306a36Sopenharmony_ci * it's not really legal to split it out with commas. We split it 26562306a36Sopenharmony_ci * up using a number of environment variables instead. */ 26662306a36Sopenharmony_ci of_property_for_each_string(dev->of_node, "compatible", p, compat) { 26762306a36Sopenharmony_ci add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat); 26862306a36Sopenharmony_ci seen++; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci seen = 0; 27362306a36Sopenharmony_ci mutex_lock(&of_mutex); 27462306a36Sopenharmony_ci list_for_each_entry(app, &aliases_lookup, link) { 27562306a36Sopenharmony_ci if (dev->of_node == app->np) { 27662306a36Sopenharmony_ci add_uevent_var(env, "OF_ALIAS_%d=%s", seen, 27762306a36Sopenharmony_ci app->alias); 27862306a36Sopenharmony_ci seen++; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci mutex_unlock(&of_mutex); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_device_uevent); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ciint of_device_uevent_modalias(const struct device *dev, struct kobj_uevent_env *env) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci int sl; 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if ((!dev) || (!dev->of_node) || dev->of_node_reused) 29062306a36Sopenharmony_ci return -ENODEV; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* Devicetree modalias is tricky, we add it in 2 steps */ 29362306a36Sopenharmony_ci if (add_uevent_var(env, "MODALIAS=")) 29462306a36Sopenharmony_ci return -ENOMEM; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci sl = of_modalias(dev->of_node, &env->buf[env->buflen-1], 29762306a36Sopenharmony_ci sizeof(env->buf) - env->buflen); 29862306a36Sopenharmony_ci if (sl < 0) 29962306a36Sopenharmony_ci return sl; 30062306a36Sopenharmony_ci if (sl >= (sizeof(env->buf) - env->buflen)) 30162306a36Sopenharmony_ci return -ENOMEM; 30262306a36Sopenharmony_ci env->buflen += sl; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(of_device_uevent_modalias); 307