diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-15 20:01:51 +0300 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-10-15 20:01:51 +0300 |
commit | 726eb70e0d34dc4bc4dada71f52bba8ed638431e (patch) | |
tree | e49674616f4513c8c6a4746a08e93c9441708d34 /drivers/bus/fsl-mc | |
parent | c6dbef7307629cce855aa6b482b60cbf7777ed88 (diff) | |
parent | f3277cbfba763cd2826396521b9296de67cf1bbc (diff) | |
download | linux-726eb70e0d34dc4bc4dada71f52bba8ed638431e.tar.xz |
Merge tag 'char-misc-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc
Pull char/misc driver updates from Greg KH:
"Here is the big set of char, misc, and other assorted driver subsystem
patches for 5.10-rc1.
There's a lot of different things in here, all over the drivers/
directory. Some summaries:
- soundwire driver updates
- habanalabs driver updates
- extcon driver updates
- nitro_enclaves new driver
- fsl-mc driver and core updates
- mhi core and bus updates
- nvmem driver updates
- eeprom driver updates
- binder driver updates and fixes
- vbox minor bugfixes
- fsi driver updates
- w1 driver updates
- coresight driver updates
- interconnect driver updates
- misc driver updates
- other minor driver updates
All of these have been in linux-next for a while with no reported
issues"
* tag 'char-misc-5.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/char-misc: (396 commits)
binder: fix UAF when releasing todo list
docs: w1: w1_therm: Fix broken xref, mistakes, clarify text
misc: Kconfig: fix a HISI_HIKEY_USB dependency
LSM: Fix type of id parameter in kernel_post_load_data prototype
misc: Kconfig: add a new dependency for HISI_HIKEY_USB
firmware_loader: fix a kernel-doc markup
w1: w1_therm: make w1_poll_completion static
binder: simplify the return expression of binder_mmap
test_firmware: Test partial read support
firmware: Add request_partial_firmware_into_buf()
firmware: Store opt_flags in fw_priv
fs/kernel_file_read: Add "offset" arg for partial reads
IMA: Add support for file reads without contents
LSM: Add "contents" flag to kernel_read_file hook
module: Call security_kernel_post_load_data()
firmware_loader: Use security_post_load_data()
LSM: Introduce kernel_post_load_data() hook
fs/kernel_read_file: Add file_size output argument
fs/kernel_read_file: Switch buffer size arg to size_t
fs/kernel_read_file: Remove redundant size argument
...
Diffstat (limited to 'drivers/bus/fsl-mc')
-rw-r--r-- | drivers/bus/fsl-mc/dprc-driver.c | 190 | ||||
-rw-r--r-- | drivers/bus/fsl-mc/dprc.c | 141 | ||||
-rw-r--r-- | drivers/bus/fsl-mc/fsl-mc-allocator.c | 12 | ||||
-rw-r--r-- | drivers/bus/fsl-mc/fsl-mc-bus.c | 75 | ||||
-rw-r--r-- | drivers/bus/fsl-mc/fsl-mc-private.h | 31 | ||||
-rw-r--r-- | drivers/bus/fsl-mc/mc-io.c | 7 |
6 files changed, 323 insertions, 133 deletions
diff --git a/drivers/bus/fsl-mc/dprc-driver.c b/drivers/bus/fsl-mc/dprc-driver.c index 2a473c09bc33..91dc015963a8 100644 --- a/drivers/bus/fsl-mc/dprc-driver.c +++ b/drivers/bus/fsl-mc/dprc-driver.c @@ -3,6 +3,7 @@ * Freescale data path resource container (DPRC) driver * * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + * Copyright 2019-2020 NXP * Author: German Rivera <German.Rivera@freescale.com> * */ @@ -80,9 +81,9 @@ static int __fsl_mc_device_remove(struct device *dev, void *data) * the MC by removing devices that represent MC objects that have * been dynamically removed in the physical DPRC. */ -static void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev, - struct fsl_mc_obj_desc *obj_desc_array, - int num_child_objects_in_mc) +void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev, + struct fsl_mc_obj_desc *obj_desc_array, + int num_child_objects_in_mc) { if (num_child_objects_in_mc != 0) { /* @@ -104,6 +105,7 @@ static void dprc_remove_devices(struct fsl_mc_device *mc_bus_dev, __fsl_mc_device_remove); } } +EXPORT_SYMBOL_GPL(dprc_remove_devices); static int __fsl_mc_device_match(struct device *dev, void *data) { @@ -220,8 +222,8 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, * dprc_scan_objects - Discover objects in a DPRC * * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object - * @total_irq_count: If argument is provided the function populates the - * total number of IRQs created by objects in the DPRC. + * @alloc_interrupts: if true the function allocates the interrupt pool, + * otherwise the interrupt allocation is delayed * * Detects objects added and removed from a DPRC and synchronizes the * state of the Linux bus driver, MC by adding and removing @@ -236,7 +238,7 @@ static void dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, * of the device drivers for the non-allocatable devices. */ static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, - unsigned int *total_irq_count) + bool alloc_interrupts) { int num_child_objects; int dprc_get_obj_failures; @@ -317,22 +319,21 @@ static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, * Allocate IRQ's before binding the scanned devices with their * respective drivers. */ - if (dev_get_msi_domain(&mc_bus_dev->dev) && !mc_bus->irq_resources) { + if (dev_get_msi_domain(&mc_bus_dev->dev)) { if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { dev_warn(&mc_bus_dev->dev, "IRQs needed (%u) exceed IRQs preallocated (%u)\n", irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); } - error = fsl_mc_populate_irq_pool(mc_bus, - FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); - if (error < 0) - return error; + if (alloc_interrupts && !mc_bus->irq_resources) { + error = fsl_mc_populate_irq_pool(mc_bus_dev, + FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); + if (error < 0) + return error; + } } - if (total_irq_count) - *total_irq_count = irq_count; - dprc_remove_devices(mc_bus_dev, child_obj_desc_array, num_child_objects); @@ -354,9 +355,10 @@ static int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, * bus driver with the actual state of the MC by adding and removing * devices as appropriate. */ -static int dprc_scan_container(struct fsl_mc_device *mc_bus_dev) +int dprc_scan_container(struct fsl_mc_device *mc_bus_dev, + bool alloc_interrupts) { - int error; + int error = 0; struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); fsl_mc_init_all_resource_pools(mc_bus_dev); @@ -365,16 +367,12 @@ static int dprc_scan_container(struct fsl_mc_device *mc_bus_dev) * Discover objects in the DPRC: */ mutex_lock(&mc_bus->scan_mutex); - error = dprc_scan_objects(mc_bus_dev, NULL); + error = dprc_scan_objects(mc_bus_dev, alloc_interrupts); mutex_unlock(&mc_bus->scan_mutex); - if (error < 0) { - fsl_mc_cleanup_all_resource_pools(mc_bus_dev); - return error; - } - return 0; + return error; } - +EXPORT_SYMBOL_GPL(dprc_scan_container); /** * dprc_irq0_handler - Regular ISR for DPRC interrupt 0 * @@ -434,9 +432,8 @@ static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg) DPRC_IRQ_EVENT_CONTAINER_DESTROYED | DPRC_IRQ_EVENT_OBJ_DESTROYED | DPRC_IRQ_EVENT_OBJ_CREATED)) { - unsigned int irq_count; - error = dprc_scan_objects(mc_dev, &irq_count); + error = dprc_scan_objects(mc_dev, true); if (error < 0) { /* * If the error is -ENXIO, we ignore it, as it indicates @@ -451,12 +448,6 @@ static irqreturn_t dprc_irq0_handler_thread(int irq_num, void *arg) goto out; } - - if (irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) { - dev_warn(dev, - "IRQs needed (%u) exceed IRQs preallocated (%u)\n", - irq_count, FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS); - } } out: @@ -597,25 +588,24 @@ error_free_irqs: } /** - * dprc_probe - callback invoked when a DPRC is being bound to this driver + * dprc_setup - opens and creates a mc_io for DPRC * * @mc_dev: Pointer to fsl-mc device representing a DPRC * * It opens the physical DPRC in the MC. - * It scans the DPRC to discover the MC objects contained in it. - * It creates the interrupt pool for the MC bus associated with the DPRC. - * It configures the interrupts for the DPRC device itself. + * It configures the DPRC portal used to communicate with MC */ -static int dprc_probe(struct fsl_mc_device *mc_dev) + +int dprc_setup(struct fsl_mc_device *mc_dev) { - int error; - size_t region_size; struct device *parent_dev = mc_dev->dev.parent; struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); + struct irq_domain *mc_msi_domain; bool mc_io_created = false; bool msi_domain_set = false; u16 major_ver, minor_ver; - struct irq_domain *mc_msi_domain; + size_t region_size; + int error; if (!is_fsl_mc_bus_dprc(mc_dev)) return -EINVAL; @@ -690,37 +680,63 @@ static int dprc_probe(struct fsl_mc_device *mc_dev) goto error_cleanup_open; } - mutex_init(&mc_bus->scan_mutex); + return 0; + +error_cleanup_open: + (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); + +error_cleanup_msi_domain: + if (msi_domain_set) + dev_set_msi_domain(&mc_dev->dev, NULL); + + if (mc_io_created) { + fsl_destroy_mc_io(mc_dev->mc_io); + mc_dev->mc_io = NULL; + } + + return error; +} +EXPORT_SYMBOL_GPL(dprc_setup); + +/** + * dprc_probe - callback invoked when a DPRC is being bound to this driver + * + * @mc_dev: Pointer to fsl-mc device representing a DPRC + * + * It opens the physical DPRC in the MC. + * It scans the DPRC to discover the MC objects contained in it. + * It creates the interrupt pool for the MC bus associated with the DPRC. + * It configures the interrupts for the DPRC device itself. + */ +static int dprc_probe(struct fsl_mc_device *mc_dev) +{ + int error; + + error = dprc_setup(mc_dev); + if (error < 0) + return error; /* * Discover MC objects in DPRC object: */ - error = dprc_scan_container(mc_dev); + error = dprc_scan_container(mc_dev, true); if (error < 0) - goto error_cleanup_open; + goto dprc_cleanup; /* * Configure interrupt for the DPRC object associated with this MC bus: */ error = dprc_setup_irq(mc_dev); if (error < 0) - goto error_cleanup_open; + goto scan_cleanup; dev_info(&mc_dev->dev, "DPRC device bound to driver"); return 0; -error_cleanup_open: - (void)dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); - -error_cleanup_msi_domain: - if (msi_domain_set) - dev_set_msi_domain(&mc_dev->dev, NULL); - - if (mc_io_created) { - fsl_destroy_mc_io(mc_dev->mc_io); - mc_dev->mc_io = NULL; - } - +scan_cleanup: + device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); +dprc_cleanup: + dprc_cleanup(mc_dev); return error; } @@ -739,40 +755,39 @@ static void dprc_teardown_irq(struct fsl_mc_device *mc_dev) } /** - * dprc_remove - callback invoked when a DPRC is being unbound from this driver + * dprc_cleanup - function that cleanups a DPRC * * @mc_dev: Pointer to fsl-mc device representing the DPRC * - * It removes the DPRC's child objects from Linux (not from the MC) and - * closes the DPRC device in the MC. - * It tears down the interrupts that were configured for the DPRC device. + * It closes the DPRC device in the MC. * It destroys the interrupt pool associated with this MC bus. */ -static int dprc_remove(struct fsl_mc_device *mc_dev) + +int dprc_cleanup(struct fsl_mc_device *mc_dev) { int error; - struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); + /* this function should be called only for DPRCs, it + * is an error to call it for regular objects + */ if (!is_fsl_mc_bus_dprc(mc_dev)) return -EINVAL; - if (!mc_dev->mc_io) - return -EINVAL; - - if (!mc_bus->irq_resources) - return -EINVAL; - - if (dev_get_msi_domain(&mc_dev->dev)) - dprc_teardown_irq(mc_dev); - - device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); if (dev_get_msi_domain(&mc_dev->dev)) { - fsl_mc_cleanup_irq_pool(mc_bus); + fsl_mc_cleanup_irq_pool(mc_dev); dev_set_msi_domain(&mc_dev->dev, NULL); } fsl_mc_cleanup_all_resource_pools(mc_dev); + /* if this step fails we cannot go further with cleanup as there is no way of + * communicating with the firmware + */ + if (!mc_dev->mc_io) { + dev_err(&mc_dev->dev, "mc_io is NULL, tear down cannot be performed in firmware\n"); + return -EINVAL; + } + error = dprc_close(mc_dev->mc_io, 0, mc_dev->mc_handle); if (error < 0) dev_err(&mc_dev->dev, "dprc_close() failed: %d\n", error); @@ -782,6 +797,37 @@ static int dprc_remove(struct fsl_mc_device *mc_dev) mc_dev->mc_io = NULL; } + return 0; +} +EXPORT_SYMBOL_GPL(dprc_cleanup); + +/** + * dprc_remove - callback invoked when a DPRC is being unbound from this driver + * + * @mc_dev: Pointer to fsl-mc device representing the DPRC + * + * It removes the DPRC's child objects from Linux (not from the MC) and + * closes the DPRC device in the MC. + * It tears down the interrupts that were configured for the DPRC device. + * It destroys the interrupt pool associated with this MC bus. + */ +static int dprc_remove(struct fsl_mc_device *mc_dev) +{ + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); + + if (!is_fsl_mc_bus_dprc(mc_dev)) + return -EINVAL; + + if (!mc_bus->irq_resources) + return -EINVAL; + + if (dev_get_msi_domain(&mc_dev->dev)) + dprc_teardown_irq(mc_dev); + + device_for_each_child(&mc_dev->dev, NULL, __fsl_mc_device_remove); + + dprc_cleanup(mc_dev); + dev_info(&mc_dev->dev, "DPRC device unbound from driver"); return 0; } diff --git a/drivers/bus/fsl-mc/dprc.c b/drivers/bus/fsl-mc/dprc.c index 602f030d84eb..57b097caf255 100644 --- a/drivers/bus/fsl-mc/dprc.c +++ b/drivers/bus/fsl-mc/dprc.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) /* * Copyright 2013-2016 Freescale Semiconductor Inc. + * Copyright 2020 NXP * */ #include <linux/kernel.h> @@ -8,6 +9,13 @@ #include "fsl-mc-private.h" +/* + * cache the DPRC version to reduce the number of commands + * towards the mc firmware + */ +static u16 dprc_major_ver; +static u16 dprc_minor_ver; + /** * dprc_open() - Open DPRC object for use * @mc_io: Pointer to MC portal's I/O object @@ -73,6 +81,77 @@ int dprc_close(struct fsl_mc_io *mc_io, EXPORT_SYMBOL_GPL(dprc_close); /** + * dprc_reset_container - Reset child container. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPRC object + * @child_container_id: ID of the container to reset + * @options: 32 bit options: + * - 0 (no bits set) - all the objects inside the container are + * reset. The child containers are entered recursively and the + * objects reset. All the objects (including the child containers) + * are closed. + * - bit 0 set - all the objects inside the container are reset. + * However the child containers are not entered recursively. + * This option is supported for API versions >= 6.5 + * In case a software context crashes or becomes non-responsive, the parent + * may wish to reset its resources container before the software context is + * restarted. + * + * This routine informs all objects assigned to the child container that the + * container is being reset, so they may perform any cleanup operations that are + * needed. All objects handles that were owned by the child container shall be + * closed. + * + * Note that such request may be submitted even if the child software context + * has not crashed, but the resulting object cleanup operations will not be + * aware of that. + * + * Return: '0' on Success; Error code otherwise. + */ +int dprc_reset_container(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token, + int child_container_id, + u32 options) +{ + struct fsl_mc_command cmd = { 0 }; + struct dprc_cmd_reset_container *cmd_params; + u32 cmdid = DPRC_CMDID_RESET_CONT; + int err; + + /* + * If the DPRC object version was not yet cached, cache it now. + * Otherwise use the already cached value. + */ + if (!dprc_major_ver && !dprc_minor_ver) { + err = dprc_get_api_version(mc_io, 0, + &dprc_major_ver, + &dprc_minor_ver); + if (err) + return err; + } + + /* + * MC API 6.5 introduced a new field in the command used to pass + * some flags. + * Bit 0 indicates that the child containers are not recursively reset. + */ + if (dprc_major_ver > 6 || (dprc_major_ver == 6 && dprc_minor_ver >= 5)) + cmdid = DPRC_CMDID_RESET_CONT_V2; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(cmdid, cmd_flags, token); + cmd_params = (struct dprc_cmd_reset_container *)cmd.params; + cmd_params->child_container_id = cpu_to_le32(child_container_id); + cmd_params->options = cpu_to_le32(options); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} +EXPORT_SYMBOL_GPL(dprc_reset_container); + +/** * dprc_set_irq() - Set IRQ information for the DPRC to trigger an interrupt. * @mc_io: Pointer to MC portal's I/O object * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' @@ -281,7 +360,7 @@ int dprc_get_attributes(struct fsl_mc_io *mc_io, /* retrieve response parameters */ rsp_params = (struct dprc_rsp_get_attributes *)cmd.params; attr->container_id = le32_to_cpu(rsp_params->container_id); - attr->icid = le16_to_cpu(rsp_params->icid); + attr->icid = le32_to_cpu(rsp_params->icid); attr->options = le32_to_cpu(rsp_params->options); attr->portal_id = le32_to_cpu(rsp_params->portal_id); @@ -443,30 +522,44 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io, struct fsl_mc_command cmd = { 0 }; struct dprc_cmd_get_obj_region *cmd_params; struct dprc_rsp_get_obj_region *rsp_params; - u16 major_ver, minor_ver; int err; - /* prepare command */ - err = dprc_get_api_version(mc_io, 0, - &major_ver, - &minor_ver); - if (err) - return err; - - /** - * MC API version 6.3 introduced a new field to the region - * descriptor: base_address. If the older API is in use then the base - * address is set to zero to indicate it needs to be obtained elsewhere - * (typically the device tree). - */ - if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3)) - cmd.header = - mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V2, - cmd_flags, token); - else - cmd.header = - mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, - cmd_flags, token); + /* + * If the DPRC object version was not yet cached, cache it now. + * Otherwise use the already cached value. + */ + if (!dprc_major_ver && !dprc_minor_ver) { + err = dprc_get_api_version(mc_io, 0, + &dprc_major_ver, + &dprc_minor_ver); + if (err) + return err; + } + + if (dprc_major_ver > 6 || (dprc_major_ver == 6 && dprc_minor_ver >= 6)) { + /* + * MC API version 6.6 changed the size of the MC portals and software + * portals to 64K (as implemented by hardware). If older API is in use the + * size reported is less (64 bytes for mc portals and 4K for software + * portals). + */ + + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V3, + cmd_flags, token); + + } else if (dprc_major_ver == 6 && dprc_minor_ver >= 3) { + /* + * MC API version 6.3 introduced a new field to the region + * descriptor: base_address. If the older API is in use then the base + * address is set to zero to indicate it needs to be obtained elsewhere + * (typically the device tree). + */ + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG_V2, + cmd_flags, token); + } else { + cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_OBJ_REG, + cmd_flags, token); + } cmd_params = (struct dprc_cmd_get_obj_region *)cmd.params; cmd_params->obj_id = cpu_to_le32(obj_id); @@ -483,7 +576,7 @@ int dprc_get_obj_region(struct fsl_mc_io *mc_io, rsp_params = (struct dprc_rsp_get_obj_region *)cmd.params; region_desc->base_offset = le64_to_cpu(rsp_params->base_offset); region_desc->size = le32_to_cpu(rsp_params->size); - if (major_ver > 6 || (major_ver == 6 && minor_ver >= 3)) + if (dprc_major_ver > 6 || (dprc_major_ver == 6 && dprc_minor_ver >= 3)) region_desc->base_address = le64_to_cpu(rsp_params->base_addr); else region_desc->base_address = 0; diff --git a/drivers/bus/fsl-mc/fsl-mc-allocator.c b/drivers/bus/fsl-mc/fsl-mc-allocator.c index cc7bb900f524..e71a6f52ea0c 100644 --- a/drivers/bus/fsl-mc/fsl-mc-allocator.c +++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c @@ -344,7 +344,7 @@ EXPORT_SYMBOL_GPL(fsl_mc_object_free); * Initialize the interrupt pool associated with an fsl-mc bus. * It allocates a block of IRQs from the GIC-ITS. */ -int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, +int fsl_mc_populate_irq_pool(struct fsl_mc_device *mc_bus_dev, unsigned int irq_count) { unsigned int i; @@ -352,10 +352,14 @@ int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, struct fsl_mc_device_irq *irq_resources; struct fsl_mc_device_irq *mc_dev_irq; int error; - struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); struct fsl_mc_resource_pool *res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; + /* do nothing if the IRQ pool is already populated */ + if (mc_bus->irq_resources) + return 0; + if (irq_count == 0 || irq_count > FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS) return -EINVAL; @@ -407,9 +411,9 @@ EXPORT_SYMBOL_GPL(fsl_mc_populate_irq_pool); * Teardown the interrupt pool associated with an fsl-mc bus. * It frees the IRQs that were allocated to the pool, back to the GIC-ITS. */ -void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus) +void fsl_mc_cleanup_irq_pool(struct fsl_mc_device *mc_bus_dev) { - struct fsl_mc_device *mc_bus_dev = &mc_bus->mc_dev; + struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev); struct fsl_mc_resource_pool *res_pool = &mc_bus->resource_pools[FSL_MC_POOL_IRQ]; diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c index b69794e7364d..76a6ee505d33 100644 --- a/drivers/bus/fsl-mc/fsl-mc-bus.c +++ b/drivers/bus/fsl-mc/fsl-mc-bus.c @@ -3,6 +3,7 @@ * Freescale Management Complex (MC) bus driver * * Copyright (C) 2014-2016 Freescale Semiconductor, Inc. + * Copyright 2019-2020 NXP * Author: German Rivera <German.Rivera@freescale.com> * */ @@ -78,6 +79,12 @@ static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv) struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv); bool found = false; + /* When driver_override is set, only bind to the matching driver */ + if (mc_dev->driver_override) { + found = !strcmp(mc_dev->driver_override, mc_drv->driver.name); + goto out; + } + if (!mc_drv->match_id_table) goto out; @@ -147,8 +154,52 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, } static DEVICE_ATTR_RO(modalias); +static ssize_t driver_override_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); + char *driver_override, *old = mc_dev->driver_override; + char *cp; + + if (WARN_ON(dev->bus != &fsl_mc_bus_type)) + return -EINVAL; + + if (count >= (PAGE_SIZE - 1)) + return -EINVAL; + + driver_override = kstrndup(buf, count, GFP_KERNEL); + if (!driver_override) + return -ENOMEM; + + cp = strchr(driver_override, '\n'); + if (cp) + *cp = '\0'; + + if (strlen(driver_override)) { + mc_dev->driver_override = driver_override; + } else { + kfree(driver_override); + mc_dev->driver_override = NULL; + } + + kfree(old); + + return count; +} + +static ssize_t driver_override_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev); + + return snprintf(buf, PAGE_SIZE, "%s\n", mc_dev->driver_override); +} +static DEVICE_ATTR_RW(driver_override); + static struct attribute *fsl_mc_dev_attrs[] = { &dev_attr_modalias.attr, + &dev_attr_driver_override.attr, NULL, }; @@ -452,7 +503,7 @@ common_cleanup: } static int get_dprc_icid(struct fsl_mc_io *mc_io, - int container_id, u16 *icid) + int container_id, u32 *icid) { struct dprc_attributes attr; int error; @@ -564,11 +615,8 @@ static int fsl_mc_device_get_mmio_regions(struct fsl_mc_device *mc_dev, regions[i].end = regions[i].start + region_desc.size - 1; regions[i].name = "fsl-mc object MMIO region"; - regions[i].flags = IORESOURCE_IO; - if (region_desc.flags & DPRC_REGION_CACHEABLE) - regions[i].flags |= IORESOURCE_CACHEABLE; - if (region_desc.flags & DPRC_REGION_SHAREABLE) - regions[i].flags |= IORESOURCE_MEM; + regions[i].flags = region_desc.flags & IORESOURCE_BITS; + regions[i].flags |= IORESOURCE_MEM; } mc_dev->regions = regions; @@ -630,6 +678,7 @@ int fsl_mc_device_add(struct fsl_mc_obj_desc *obj_desc, if (!mc_bus) return -ENOMEM; + mutex_init(&mc_bus->scan_mutex); mc_dev = &mc_bus->mc_dev; } else { /* @@ -748,6 +797,9 @@ EXPORT_SYMBOL_GPL(fsl_mc_device_add); */ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev) { + kfree(mc_dev->driver_override); + mc_dev->driver_override = NULL; + /* * The device-specific remove callback will get invoked by device_del() */ @@ -908,9 +960,6 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) u32 mc_portal_size, mc_stream_id; struct resource *plat_res; - if (!iommu_present(&fsl_mc_bus_type)) - return -EPROBE_DEFER; - mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL); if (!mc) return -ENOMEM; @@ -918,11 +967,11 @@ static int fsl_mc_bus_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mc); plat_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); - mc->fsl_mc_regs = devm_ioremap_resource(&pdev->dev, plat_res); - if (IS_ERR(mc->fsl_mc_regs)) - return PTR_ERR(mc->fsl_mc_regs); + if (plat_res) + mc->fsl_mc_regs = devm_ioremap_resource(&pdev->dev, plat_res); - if (IS_ENABLED(CONFIG_ACPI) && !dev_of_node(&pdev->dev)) { + if (mc->fsl_mc_regs && IS_ENABLED(CONFIG_ACPI) && + !dev_of_node(&pdev->dev)) { mc_stream_id = readl(mc->fsl_mc_regs + FSL_MC_FAPR); /* * HW ORs the PL and BMT bit, places the result in bit 15 of diff --git a/drivers/bus/fsl-mc/fsl-mc-private.h b/drivers/bus/fsl-mc/fsl-mc-private.h index 7a46a12eb747..85ca5fdee581 100644 --- a/drivers/bus/fsl-mc/fsl-mc-private.h +++ b/drivers/bus/fsl-mc/fsl-mc-private.h @@ -80,10 +80,12 @@ int dpmcp_reset(struct fsl_mc_io *mc_io, /* DPRC command versioning */ #define DPRC_CMD_BASE_VERSION 1 #define DPRC_CMD_2ND_VERSION 2 +#define DPRC_CMD_3RD_VERSION 3 #define DPRC_CMD_ID_OFFSET 4 #define DPRC_CMD(id) (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_BASE_VERSION) #define DPRC_CMD_V2(id) (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_2ND_VERSION) +#define DPRC_CMD_V3(id) (((id) << DPRC_CMD_ID_OFFSET) | DPRC_CMD_3RD_VERSION) /* DPRC command IDs */ #define DPRC_CMDID_CLOSE DPRC_CMD(0x800) @@ -91,6 +93,8 @@ int dpmcp_reset(struct fsl_mc_io *mc_io, #define DPRC_CMDID_GET_API_VERSION DPRC_CMD(0xa05) #define DPRC_CMDID_GET_ATTR DPRC_CMD(0x004) +#define DPRC_CMDID_RESET_CONT DPRC_CMD(0x005) +#define DPRC_CMDID_RESET_CONT_V2 DPRC_CMD_V2(0x005) #define DPRC_CMDID_SET_IRQ DPRC_CMD(0x010) #define DPRC_CMDID_SET_IRQ_ENABLE DPRC_CMD(0x012) @@ -103,6 +107,7 @@ int dpmcp_reset(struct fsl_mc_io *mc_io, #define DPRC_CMDID_GET_OBJ DPRC_CMD(0x15A) #define DPRC_CMDID_GET_OBJ_REG DPRC_CMD(0x15E) #define DPRC_CMDID_GET_OBJ_REG_V2 DPRC_CMD_V2(0x15E) +#define DPRC_CMDID_GET_OBJ_REG_V3 DPRC_CMD_V3(0x15E) #define DPRC_CMDID_SET_OBJ_IRQ DPRC_CMD(0x15F) #define DPRC_CMDID_GET_CONNECTION DPRC_CMD(0x16C) @@ -111,6 +116,11 @@ struct dprc_cmd_open { __le32 container_id; }; +struct dprc_cmd_reset_container { + __le32 child_container_id; + __le32 options; +}; + struct dprc_cmd_set_irq { /* cmd word 0 */ __le32 irq_val; @@ -152,8 +162,7 @@ struct dprc_cmd_clear_irq_status { struct dprc_rsp_get_attributes { /* response word 0 */ __le32 container_id; - __le16 icid; - __le16 pad; + __le32 icid; /* response word 1 */ __le32 options; __le32 portal_id; @@ -330,7 +339,7 @@ int dprc_clear_irq_status(struct fsl_mc_io *mc_io, */ struct dprc_attributes { int container_id; - u16 icid; + u32 icid; int portal_id; u64 options; }; @@ -358,12 +367,6 @@ int dprc_set_obj_irq(struct fsl_mc_io *mc_io, int obj_id, u8 irq_index, struct dprc_irq_cfg *irq_cfg); - -/* Region flags */ -/* Cacheable - Indicates that region should be mapped as cacheable */ -#define DPRC_REGION_CACHEABLE 0x00000001 -#define DPRC_REGION_SHAREABLE 0x00000002 - /** * enum dprc_region_type - Region type * @DPRC_REGION_TYPE_MC_PORTAL: MC portal region @@ -518,11 +521,6 @@ struct dpcon_cmd_set_notification { __le64 user_ctx; }; -/** - * Maximum number of total IRQs that can be pre-allocated for an MC bus' - * IRQ pool - */ -#define FSL_MC_IRQ_POOL_MAX_TOTAL_IRQS 256 /** * struct fsl_mc_resource_pool - Pool of MC resources of a given @@ -597,11 +595,6 @@ void fsl_mc_msi_domain_free_irqs(struct device *dev); struct irq_domain *fsl_mc_find_msi_domain(struct device *dev); -int fsl_mc_populate_irq_pool(struct fsl_mc_bus *mc_bus, - unsigned int irq_count); - -void fsl_mc_cleanup_irq_pool(struct fsl_mc_bus *mc_bus); - int __must_check fsl_create_mc_io(struct device *dev, phys_addr_t mc_portal_phys_addr, u32 mc_portal_size, diff --git a/drivers/bus/fsl-mc/mc-io.c b/drivers/bus/fsl-mc/mc-io.c index a30b53f1d87d..305015486b91 100644 --- a/drivers/bus/fsl-mc/mc-io.c +++ b/drivers/bus/fsl-mc/mc-io.c @@ -129,7 +129,12 @@ error_destroy_mc_io: */ void fsl_destroy_mc_io(struct fsl_mc_io *mc_io) { - struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev; + struct fsl_mc_device *dpmcp_dev; + + if (!mc_io) + return; + + dpmcp_dev = mc_io->dpmcp_dev; if (dpmcp_dev) fsl_mc_io_unset_dpmcp(mc_io); |