예제 #1
0
파일: mc-bus.c 프로젝트: 020gzh/linux
/**
 * fsl_mc_device_remove - Remove a MC object device from being visible to
 * Linux
 *
 * @mc_dev: Pointer to a MC object device object
 */
void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
{
	struct fsl_mc_bus *mc_bus = NULL;

	kfree(mc_dev->regions);

	/*
	 * The device-specific remove callback will get invoked by device_del()
	 */
	device_del(&mc_dev->dev);
	put_device(&mc_dev->dev);

	if (strcmp(mc_dev->obj_desc.type, "dprc") == 0) {
		mc_bus = to_fsl_mc_bus(mc_dev);
		if (mc_dev->mc_io) {
			fsl_destroy_mc_io(mc_dev->mc_io);
			mc_dev->mc_io = NULL;
		}

		if (fsl_mc_is_root_dprc(&mc_dev->dev)) {
			if (atomic_read(&root_dprc_count) > 0)
				atomic_dec(&root_dprc_count);
			else
				WARN_ON(1);
		}
	}

	if (mc_bus)
		devm_kfree(mc_dev->dev.parent, mc_bus);
	else
		kmem_cache_free(mc_dev_cache, mc_dev);
}
예제 #2
0
파일: mc-bus.c 프로젝트: 020gzh/linux
/**
 * fsl_mc_bus_match - device to driver matching callback
 * @dev: the MC object device structure to match against
 * @drv: the device driver to search for matching MC object device id
 * structures
 *
 * Returns 1 on success, 0 otherwise.
 */
static int fsl_mc_bus_match(struct device *dev, struct device_driver *drv)
{
	const struct fsl_mc_device_match_id *id;
	struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
	struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(drv);
	bool found = false;
	bool major_version_mismatch = false;
	bool minor_version_mismatch = false;

	if (WARN_ON(!fsl_mc_bus_exists()))
		goto out;

	if (!mc_drv->match_id_table)
		goto out;

	/*
	 * If the object is not 'plugged' don't match.
	 * Only exception is the root DPRC, which is a special case.
	 */
	if ((mc_dev->obj_desc.state & DPRC_OBJ_STATE_PLUGGED) == 0 &&
	    !fsl_mc_is_root_dprc(&mc_dev->dev))
		goto out;

	/*
	 * Traverse the match_id table of the given driver, trying to find
	 * a matching for the given MC object device.
	 */
	for (id = mc_drv->match_id_table; id->vendor != 0x0; id++) {
		if (id->vendor == mc_dev->obj_desc.vendor &&
		    strcmp(id->obj_type, mc_dev->obj_desc.type) == 0) {
			if (id->ver_major == mc_dev->obj_desc.ver_major) {
				found = true;
				if (id->ver_minor != mc_dev->obj_desc.ver_minor)
					minor_version_mismatch = true;
			} else {
				major_version_mismatch = true;
			}

			break;
		}
	}

	if (major_version_mismatch) {
		dev_warn(dev,
			 "Major version mismatch: driver version %u.%u, MC object version %u.%u\n",
			 id->ver_major, id->ver_minor,
			 mc_dev->obj_desc.ver_major,
			 mc_dev->obj_desc.ver_minor);
	} else if (minor_version_mismatch) {
		dev_warn(dev,
			 "Minor version mismatch: driver version %u.%u, MC object version %u.%u\n",
			 id->ver_major, id->ver_minor,
			 mc_dev->obj_desc.ver_major,
			 mc_dev->obj_desc.ver_minor);
	}

out:
	dev_dbg(dev, "%smatched\n", found ? "" : "not ");
	return found;
}
예제 #3
0
파일: mc-bus.c 프로젝트: 020gzh/linux
/**
 * fsl_mc_bus_remove - callback invoked when the root MC bus is being
 * removed
 */
static int fsl_mc_bus_remove(struct platform_device *pdev)
{
	struct fsl_mc *mc = platform_get_drvdata(pdev);

	if (WARN_ON(!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev)))
		return -EINVAL;

	fsl_mc_device_remove(mc->root_mc_bus_dev);
	dev_info(&pdev->dev, "Root MC bus device removed");
	return 0;
}
예제 #4
0
/**
 * 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)
{
	int error;
	struct fsl_mc_bus *mc_bus = to_fsl_mc_bus(mc_dev);

	if (WARN_ON(strcmp(mc_dev->obj_desc.type, "dprc") != 0))
		return -EINVAL;
	if (WARN_ON(!mc_dev->mc_io))
		return -EINVAL;

	if (WARN_ON(!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);
		dev_set_msi_domain(&mc_dev->dev, NULL);
	}

	fsl_mc_cleanup_all_resource_pools(mc_dev);

	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);

	if (!fsl_mc_is_root_dprc(&mc_dev->dev)) {
		fsl_destroy_mc_io(mc_dev->mc_io);
		mc_dev->mc_io = NULL;
	}

	dev_info(&mc_dev->dev, "DPRC device unbound from driver");
	return 0;
}