/** * dprc_remove_devices - Removes devices for objects removed from a DPRC * * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object * @obj_desc_array: array of object descriptors for child objects currently * present in the DPRC in the MC. * @num_child_objects_in_mc: number of entries in obj_desc_array * * Synchronizes the state of the Linux bus driver with the actual state of * the MC by removing devices that represent MC objects that have * been dynamically removed in the physical DPRC.
*/ 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) { /* * Remove child objects that are in the DPRC in Linux, * but not in the MC:
*/ struct fsl_mc_child_objs objs;
objs.child_count = num_child_objects_in_mc;
objs.child_array = obj_desc_array;
device_for_each_child(&mc_bus_dev->dev, &objs,
__fsl_mc_device_remove_if_not_in_mc);
} else { /* * There are no child objects for this DPRC in the MC. * So, remove all the child devices from Linux:
*/
device_for_each_child(&mc_bus_dev->dev, NULL,
__fsl_mc_device_remove);
}
}
EXPORT_SYMBOL_GPL(dprc_remove_devices);
dev = device_find_child(&mc_bus_dev->dev, obj_desc,
__fsl_mc_device_match);
return dev ? to_fsl_mc_device(dev) : NULL;
}
/** * check_plugged_state_change - Check change in an MC object's plugged state * * @mc_dev: pointer to the fsl-mc device for a given MC object * @obj_desc: pointer to the MC object's descriptor in the MC * * If the plugged state has changed from unplugged to plugged, the fsl-mc * device is bound to the corresponding device driver. * If the plugged state has changed from plugged to unplugged, the fsl-mc * device is unbound from the corresponding device driver.
*/ staticvoid check_plugged_state_change(struct fsl_mc_device *mc_dev, struct fsl_mc_obj_desc *obj_desc)
{ int error;
u32 plugged_flag_at_mc =
obj_desc->state & FSL_MC_OBJ_STATE_PLUGGED;
/* * Check if device is already known to Linux:
*/
child_dev = fsl_mc_device_lookup(obj_desc, mc_bus_dev); if (child_dev) {
check_plugged_state_change(child_dev, obj_desc);
put_device(&child_dev->dev);
} else {
error = fsl_mc_device_add(obj_desc, NULL, &mc_bus_dev->dev,
&child_dev); if (error < 0) return;
}
}
/** * dprc_add_new_devices - Adds devices to the logical bus for a DPRC * * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object * @obj_desc_array: array of device descriptors for child devices currently * present in the physical DPRC. * @num_child_objects_in_mc: number of entries in obj_desc_array * * Synchronizes the state of the Linux bus driver with the actual * state of the MC by adding objects that have been newly discovered * in the physical DPRC.
*/ staticvoid dprc_add_new_devices(struct fsl_mc_device *mc_bus_dev, struct fsl_mc_obj_desc *obj_desc_array, int num_child_objects_in_mc)
{ int i;
/* probe the allocable objects first */ for (i = 0; i < num_child_objects_in_mc; i++) { struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
if (strlen(obj_desc->type) > 0 &&
fsl_mc_obj_desc_is_allocatable(obj_desc))
fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
}
for (i = 0; i < num_child_objects_in_mc; i++) { struct fsl_mc_obj_desc *obj_desc = &obj_desc_array[i];
if (strlen(obj_desc->type) > 0 &&
!fsl_mc_obj_desc_is_allocatable(obj_desc))
fsl_mc_obj_device_add(mc_bus_dev, obj_desc);
}
}
/** * dprc_scan_objects - Discover objects in a DPRC * * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object * @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 * devices accordingly. * Two types of devices can be found in a DPRC: allocatable objects (e.g., * dpbp, dpmcp) and non-allocatable devices (e.g., dprc, dpni). * All allocatable devices needed to be probed before all non-allocatable * devices, to ensure that device drivers for non-allocatable * devices can allocate any type of allocatable devices. * That is, we need to ensure that the corresponding resource pools are * populated before they can get allocation requests from probe callbacks * of the device drivers for the non-allocatable devices.
*/ int dprc_scan_objects(struct fsl_mc_device *mc_bus_dev, bool alloc_interrupts)
{ int num_child_objects; int dprc_get_obj_failures; int error; unsignedint irq_count = mc_bus_dev->obj_desc.irq_count; struct fsl_mc_obj_desc *child_obj_desc_array = NULL; struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_bus_dev);
child_obj_desc_array =
devm_kmalloc_array(&mc_bus_dev->dev, num_child_objects, sizeof(*child_obj_desc_array),
GFP_KERNEL); if (!child_obj_desc_array) return -ENOMEM;
/* * Discover objects currently present in the physical DPRC:
*/
dprc_get_obj_failures = 0; for (i = 0; i < num_child_objects; i++) { struct fsl_mc_obj_desc *obj_desc =
&child_obj_desc_array[i];
error = dprc_get_obj(mc_bus_dev->mc_io,
0,
mc_bus_dev->mc_handle,
i, obj_desc); if (error < 0) {
dev_err(&mc_bus_dev->dev, "dprc_get_obj(i=%d) failed: %d\n",
i, error); /* * Mark the obj entry as "invalid", by using the * empty string as obj type:
*/
obj_desc->type[0] = '\0';
obj_desc->id = error;
dprc_get_obj_failures++; continue;
}
/* * add a quirk for all versions of dpsec < 4.0...none * are coherent regardless of what the MC reports.
*/ if ((strcmp(obj_desc->type, "dpseci") == 0) &&
(obj_desc->ver_major < 4))
obj_desc->flags |=
FSL_MC_OBJ_FLAG_NO_MEM_SHAREABILITY;
irq_count += obj_desc->irq_count;
dev_dbg(&mc_bus_dev->dev, "Discovered object: type %s, id %d\n",
obj_desc->type, obj_desc->id);
}
if (dprc_get_obj_failures != 0) {
dev_err(&mc_bus_dev->dev, "%d out of %d devices could not be retrieved\n",
dprc_get_obj_failures, num_child_objects);
}
}
/* * Allocate IRQ's before binding the scanned devices with their * respective drivers.
*/ 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);
}
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 (child_obj_desc_array)
devm_kfree(&mc_bus_dev->dev, child_obj_desc_array);
return 0;
}
/** * dprc_scan_container - Scans a physical DPRC and synchronizes Linux bus state * * @mc_bus_dev: pointer to the fsl-mc device that represents a DPRC object * @alloc_interrupts: if true the function allocates the interrupt pool, * otherwise the interrupt allocation is delayed * Scans the physical DPRC and synchronizes the state of the Linux * bus driver with the actual state of the MC by adding and removing * devices as appropriate.
*/ int dprc_scan_container(struct fsl_mc_device *mc_bus_dev, bool alloc_interrupts)
{ 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);
/* * Discover objects in the DPRC:
*/
mutex_lock(&mc_bus->scan_mutex);
error = dprc_scan_objects(mc_bus_dev, alloc_interrupts);
mutex_unlock(&mc_bus->scan_mutex);
error = dprc_scan_objects(mc_dev, true); if (error < 0) { /* * If the error is -ENXIO, we ignore it, as it indicates * that the object scan was aborted, as we detected that * an object was removed from the DPRC in the MC, while * we were scanning the DPRC.
*/ if (error != -ENXIO) {
dev_err(dev, "dprc_scan_objects() failed: %d\n",
error);
}
/* * Disable and clear interrupt for a given DPRC object
*/ int disable_dprc_irq(struct fsl_mc_device *mc_dev)
{ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); int error; struct fsl_mc_io *mc_io = mc_dev->mc_io;
/* * Disable generation of interrupt, while we configure it:
*/
error = dprc_set_irq_enable(mc_io, 0, mc_dev->mc_handle, 0, 0); if (error < 0) {
dev_err(&mc_dev->dev, "Disabling DPRC IRQ failed: dprc_set_irq_enable() failed: %d\n",
error); return error;
}
/* * Disable all interrupt causes for the interrupt:
*/
error = dprc_set_irq_mask(mc_io, 0, mc_dev->mc_handle, 0, 0x0); if (error < 0) {
dev_err(&mc_dev->dev, "Disabling DPRC IRQ failed: dprc_set_irq_mask() failed: %d\n",
error); return error;
}
/** * 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 configures the DPRC portal used to communicate with MC
*/
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;
}
if (uapi_created)
fsl_mc_uapi_remove_device_file(mc_bus);
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.
*/ staticint 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, true); if (error < 0) goto dprc_cleanup;
/* * Configure interrupt for the DPRC object associated with this MC bus:
*/
error = dprc_setup_irq(mc_dev); if (error < 0) goto scan_cleanup;
dev_info(&mc_dev->dev, "DPRC device bound to driver"); return 0;
/** * dprc_cleanup - function that cleanups a DPRC * * @mc_dev: Pointer to fsl-mc device representing the DPRC * * It closes the DPRC device in the MC. * It destroys the interrupt pool associated with this MC bus.
*/
int dprc_cleanup(struct fsl_mc_device *mc_dev)
{ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev); int error;
/* 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 (dev_get_msi_domain(&mc_dev->dev)) {
fsl_mc_cleanup_irq_pool(mc_dev);
dev_set_msi_domain(&mc_dev->dev, NULL);
}
/* 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;
}
/** * 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.
*/ staticvoid dprc_remove(struct fsl_mc_device *mc_dev)
{ struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);
if (!mc_bus->irq_resources) {
dev_err(&mc_dev->dev, "No irq resources, so unbinding the device failed\n"); return;
}
if (dev_get_msi_domain(&mc_dev->dev))
dprc_teardown_irq(mc_dev);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.