lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <54EF2769.5020805@suse.de>
Date:	Thu, 26 Feb 2015 15:02:17 +0100
From:	Alexander Graf <agraf@...e.de>
To:	"J. German Rivera" <German.Rivera@...escale.com>,
	gregkh@...uxfoundation.org, arnd@...db.de,
	linux-kernel@...r.kernel.org
CC:	stuart.yoder@...escale.com, Kim.Phillips@...escale.com,
	scottwood@...escale.com, bhamciu1@...escale.com,
	R89243@...escale.com, Geoff.Thorpe@...escale.com,
	bhupesh.sharma@...escale.com, nir.erez@...escale.com,
	richard.schmitt@...escale.com
Subject: Re: [PATCH v7 2/3] drivers/bus: Freescale Management Complex (fsl-mc)
 bus driver



On 24.02.15 23:21, J. German Rivera wrote:
> Platform device driver that sets up the basic bus infrastructure
> for the fsl-mc bus type, including support for adding/removing
> fsl-mc devices, register/unregister of fsl-mc drivers, and bus
> match support to bind devices to drivers.
> 
> Signed-off-by: J. German Rivera <German.Rivera@...escale.com>
> Signed-off-by: Stuart Yoder <stuart.yoder@...escale.com>
> ---
> Changes in v7:
> - Refactored MC bus data structures
> - Removed creation of fsl_mc_io object from fsl_mc_add_device()
> - Addressed comments from Alex Graf:
>   * Use the 'ranges' property for the 'fsl,qoriq-mc' node as a way to
>     translate MC-returned addresses (bus relative addresses) to
>     system physical addresses.
> 
> Changes addressed in v6:
> - Fixed new checkpatch warnings
> 
> Changes addressed in v5:
> - Addressed comments from Alex Graf:
>   * Renamed dprc_get_container_id() call as dpmng_get_container_id().
>   * Added TODO comment to use the 'ranges' property of the
>     fsl-mc DT node.
> 
> Changes addressed in v4:
> - Addressed comments from Alex Graf:
>   * Added missing scope limitations and more descriptive help
>     text for the FSL_MC_BUS config option.
> - Fixed bug related to setting fsl_mc_bus_type.dev_root too
>   late.
> 
> Changes in v3:
> - Addressed changes from Kim Phillips:
>   * Renamed files:
> 	drivers/bus/fsl-mc/fsl_mc_bus.c -> drivers/bus/fsl-mc/mc-bus.c
> 	include/linux/fsl_mc.h -> include/linux/fsl/mc.h
> 	include/linux/fsl_mc_private.h -> include/linux/fsl/mc-private.h
> 
> - Addressed comments from Timur Tabi:
>   * Changed all functions that had goto out/error when no common cleanup
>     was done, to just have multiple return points.
>   * Replaced error cleanup boolean flags with multiple exit points.
> 
> Changes in v2:
> - Addressed comment from Joe Perches:
>   * Changed pr_debug to dev_dbg in fsl_mc_bus_match
> 
> - Addressed comments from Kim Phillips and Alex Graf:
>   * Changed version check to allow the driver to run with MC
>     firmware that has major version number greater than or equal
>     to the driver's major version number.
>   * Removed minor version check
> 
> - Removed unused variable parent_dev in fsl_mc_device_remove
> 
>  drivers/bus/Kconfig            |   3 +
>  drivers/bus/Makefile           |   3 +
>  drivers/bus/fsl-mc/Kconfig     |  24 ++
>  drivers/bus/fsl-mc/Makefile    |  14 +
>  drivers/bus/fsl-mc/mc-bus.c    | 758 +++++++++++++++++++++++++++++++++++++++++
>  include/linux/fsl/mc-private.h |  67 ++++
>  include/linux/fsl/mc.h         | 136 ++++++++
>  7 files changed, 1005 insertions(+)
>  create mode 100644 drivers/bus/fsl-mc/Kconfig
>  create mode 100644 drivers/bus/fsl-mc/Makefile
>  create mode 100644 drivers/bus/fsl-mc/mc-bus.c
>  create mode 100644 include/linux/fsl/mc-private.h
>  create mode 100644 include/linux/fsl/mc.h
> 
> diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
> index b99729e..dde3ec2 100644
> --- a/drivers/bus/Kconfig
> +++ b/drivers/bus/Kconfig
> @@ -67,4 +67,7 @@ config VEXPRESS_CONFIG
>  	help
>  	  Platform configuration infrastructure for the ARM Ltd.
>  	  Versatile Express.
> +
> +source "drivers/bus/fsl-mc/Kconfig"
> +
>  endmenu
> diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
> index 2973c18..6abcab1 100644
> --- a/drivers/bus/Makefile
> +++ b/drivers/bus/Makefile
> @@ -15,3 +15,6 @@ obj-$(CONFIG_ARM_CCI)		+= arm-cci.o
>  obj-$(CONFIG_ARM_CCN)		+= arm-ccn.o
> 
>  obj-$(CONFIG_VEXPRESS_CONFIG)	+= vexpress-config.o
> +
> +# Freescale Management Complex (MC) bus drivers
> +obj-$(CONFIG_FSL_MC_BUS)	+= fsl-mc/
> diff --git a/drivers/bus/fsl-mc/Kconfig b/drivers/bus/fsl-mc/Kconfig
> new file mode 100644
> index 0000000..0d779d9
> --- /dev/null
> +++ b/drivers/bus/fsl-mc/Kconfig
> @@ -0,0 +1,24 @@
> +#
> +# Freescale Management Complex (MC) bus drivers
> +#
> +# Copyright (C) 2014 Freescale Semiconductor, Inc.
> +#
> +# This file is released under the GPLv2
> +#
> +
> +config FSL_MC_BUS
> +	tristate "Freescale Management Complex (MC) bus driver"
> +	depends on OF && ARM64
> +	help
> +	  Driver to enable the bus infrastructure for the Freescale
> +          QorIQ Management Complex (fsl-mc). The fsl-mc is a hardware
> +	  module of the QorIQ LS2 SoCs, that does resource management
> +	  for hardware building-blocks in the SoC that can be used
> +	  to dynamically create networking hardware objects such as
> +	  network interfaces (NICs), crypto accelerator instances,
> +	  or L2 switches.
> +
> +	  Only enable this option when building the kernel for
> +	  Freescale QorQIQ LS2xxxx SoCs.
> +
> +
> diff --git a/drivers/bus/fsl-mc/Makefile b/drivers/bus/fsl-mc/Makefile
> new file mode 100644
> index 0000000..decd339
> --- /dev/null
> +++ b/drivers/bus/fsl-mc/Makefile
> @@ -0,0 +1,14 @@
> +#
> +# Freescale Management Complex (MC) bus drivers
> +#
> +# Copyright (C) 2014 Freescale Semiconductor, Inc.
> +#
> +# This file is released under the GPLv2
> +#
> +obj-$(CONFIG_FSL_MC_BUS) += mc-bus-driver.o
> +
> +mc-bus-driver-objs := mc-bus.o \
> +		      mc-sys.o \
> +		      dprc.o \
> +		      dpmng.o
> +
> diff --git a/drivers/bus/fsl-mc/mc-bus.c b/drivers/bus/fsl-mc/mc-bus.c
> new file mode 100644
> index 0000000..01407cc
> --- /dev/null
> +++ b/drivers/bus/fsl-mc/mc-bus.c
> @@ -0,0 +1,758 @@
> +/*
> + * Freescale Management Complex (MC) bus driver
> + *
> + * Copyright (C) 2014 Freescale Semiconductor, Inc.
> + * Author: German Rivera <German.Rivera@...escale.com>
> + *
> + * This file is licensed under the terms of the GNU General Public
> + * License version 2. This program is licensed "as is" without any
> + * warranty of any kind, whether express or implied.
> + */
> +
> +#include <linux/fsl/mc-private.h>
> +#include <linux/module.h>
> +#include <linux/of_device.h>
> +#include <linux/of_address.h>
> +#include <linux/ioport.h>
> +#include <linux/slab.h>
> +#include <linux/limits.h>
> +#include <linux/fsl/dpmng.h>
> +#include <linux/fsl/mc-sys.h>
> +#include "dprc-cmd.h"
> +
> +static struct kmem_cache *mc_dev_cache;
> +
> +/**
> + * 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;
> +
> +	if (WARN_ON(!fsl_mc_bus_type.dev_root))
> +		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 &&
> +	    &mc_dev->dev != fsl_mc_bus_type.dev_root)

Does this mean there can only be one fsl-mc per machine? Is this a
reasonable limitation?

Wouldn't it be a lot cleaner to have individual buses for each fsl-mc dt
node? If hardware only implements one today that's fine, but it means we
don't have to completely reengineer everything tomorrow then.

> +		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 &&
> +		    id->ver_major == mc_dev->obj_desc.ver_major &&
> +		    id->ver_minor == mc_dev->obj_desc.ver_minor) {
> +			found = true;
> +			break;
> +		}
> +	}
> +
> +out:
> +	dev_dbg(dev, "%smatched\n", found ? "" : "not ");
> +	return found;
> +}
> +
> +/**
> + * fsl_mc_bus_uevent - callback invoked when a device is added
> + */
> +static int fsl_mc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
> +{
> +	pr_debug("%s invoked\n", __func__);
> +	return 0;
> +}
> +
> +struct bus_type fsl_mc_bus_type = {
> +	.name = "fsl-mc",
> +	.match = fsl_mc_bus_match,
> +	.uevent = fsl_mc_bus_uevent,
> +};
> +EXPORT_SYMBOL_GPL(fsl_mc_bus_type);

Why does this have to get exported?

> +
> +static int fsl_mc_driver_probe(struct device *dev)
> +{
> +	struct fsl_mc_driver *mc_drv;
> +	struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
> +	int error;
> +
> +	if (WARN_ON(!dev->driver))
> +		return -EINVAL;
> +
> +	mc_drv = to_fsl_mc_driver(dev->driver);
> +	if (WARN_ON(!mc_drv->probe))
> +		return -EINVAL;
> +
> +	error = mc_drv->probe(mc_dev);
> +	if (error < 0) {
> +		dev_err(dev, "MC object device probe callback failed: %d\n",
> +			error);
> +		return error;
> +	}
> +
> +	return 0;
> +}
> +
> +static int fsl_mc_driver_remove(struct device *dev)
> +{
> +	struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
> +	struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
> +	int error;
> +
> +	if (WARN_ON(!dev->driver))
> +		return -EINVAL;
> +
> +	error = mc_drv->remove(mc_dev);
> +	if (error < 0) {
> +		dev_err(dev,
> +			"MC object device remove callback failed: %d\n",
> +			error);
> +		return error;
> +	}
> +
> +	return 0;
> +}
> +
> +static void fsl_mc_driver_shutdown(struct device *dev)
> +{
> +	struct fsl_mc_driver *mc_drv = to_fsl_mc_driver(dev->driver);
> +	struct fsl_mc_device *mc_dev = to_fsl_mc_device(dev);
> +
> +	mc_drv->shutdown(mc_dev);
> +}
> +
> +/**
> + * __fsl_mc_driver_register - registers a child device driver with the
> + * MC bus
> + *
> + * This function is implicitly invoked from the registration function of
> + * fsl_mc device drivers, which is generated by the
> + * module_fsl_mc_driver() macro.
> + */
> +int __fsl_mc_driver_register(struct fsl_mc_driver *mc_driver,
> +			     struct module *owner)
> +{
> +	int error;
> +
> +	mc_driver->driver.owner = owner;
> +	mc_driver->driver.bus = &fsl_mc_bus_type;
> +
> +	/*
> +	 * Set default driver callbacks, if not set by the child driver:
> +	 */
> +	if (mc_driver->probe)
> +		mc_driver->driver.probe = fsl_mc_driver_probe;

I don't understand this. I thought you want to put them as default in
case they're *not* set?

> +
> +	if (mc_driver->remove)
> +		mc_driver->driver.remove = fsl_mc_driver_remove;
> +
> +	if (mc_driver->shutdown)
> +		mc_driver->driver.shutdown = fsl_mc_driver_shutdown;
> +
> +	error = driver_register(&mc_driver->driver);
> +	if (error < 0) {
> +		pr_err("driver_register() failed for %s: %d\n",
> +		       mc_driver->driver.name, error);
> +		return error;
> +	}
> +
> +	pr_info("MC object device driver %s registered\n",
> +		mc_driver->driver.name);
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(__fsl_mc_driver_register);
> +
> +/**
> + * fsl_mc_driver_unregister - unregisters a device driver from the
> + * MC bus
> + */
> +void fsl_mc_driver_unregister(struct fsl_mc_driver *mc_driver)
> +{
> +	driver_unregister(&mc_driver->driver);
> +}
> +EXPORT_SYMBOL_GPL(fsl_mc_driver_unregister);
> +
> +static int get_dprc_icid(struct fsl_mc_io *mc_io,
> +			 int container_id, uint16_t *icid)
> +{
> +	uint16_t dprc_handle;
> +	struct dprc_attributes attr;
> +	int error;
> +
> +	error = dprc_open(mc_io, container_id, &dprc_handle);
> +	if (error < 0) {
> +		pr_err("dprc_open() failed: %d\n", error);
> +		return error;
> +	}
> +
> +	memset(&attr, 0, sizeof(attr));
> +	error = dprc_get_attributes(mc_io, dprc_handle, &attr);
> +	if (error < 0) {
> +		pr_err("dprc_get_attributes() failed: %d\n", error);
> +		goto common_cleanup;
> +	}
> +
> +	*icid = attr.icid;
> +	error = 0;
> +
> +common_cleanup:
> +	(void)dprc_close(mc_io, dprc_handle);
> +	return error;
> +}
> +
> +static int translate_mc_addr(uint64_t mc_addr, phys_addr_t *phys_addr)

This should probably check that both start and end are within range.

> +{
> +	int i;
> +	struct fsl_mc *mc = dev_get_drvdata(fsl_mc_bus_type.dev_root->parent);
> +
> +	if (mc->num_translation_ranges == 0) {
> +		/*
> +		 * Do identity mapping:
> +		 */
> +		*phys_addr = mc_addr;
> +		return 0;
> +	}
> +

[...]

> +/**
> + * 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) {

I think it'll make the code easier to understand if you extract the
strcmp into a helper function that actually explains what it does.
Something like fsl_mc_dev_is_container().

> +		struct fsl_mc_io *mc_io = mc_dev->mc_io;
> +
> +		mc_bus = to_fsl_mc_bus(mc_dev);
> +		fsl_destroy_mc_io(mc_io);
> +		if (&mc_dev->dev == fsl_mc_bus_type.dev_root)
> +			fsl_mc_bus_type.dev_root = NULL;
> +	}
> +
> +	mc_dev->mc_io = NULL;
> +	if (mc_bus)
> +		devm_kfree(mc_dev->dev.parent, mc_bus);
> +	else
> +		kmem_cache_free(mc_dev_cache, mc_dev);
> +}
> +EXPORT_SYMBOL_GPL(fsl_mc_device_remove);

[...]

> +	dev_info(&pdev->dev,
> +		 "Freescale Management Complex Firmware version: %u.%u.%u\n",
> +		 mc_version.major, mc_version.minor, mc_version.revision);
> +
> +	if (mc_version.major < MC_VER_MAJOR) {
> +		dev_err(&pdev->dev,
> +			"ERROR: MC firmware version not supported by driver (driver version: %u.%u)\n",
> +			MC_VER_MAJOR, MC_VER_MINOR);
> +		error = -ENOTSUPP;
> +		goto error_cleanup_mc_io;
> +	}
> +
> +	if (mc_version.major > MC_VER_MAJOR) {

How about we introduce 2 defines for MIN/MAX from the beginning? Then we
can adjust the range by only touching the defines later :).

> +		dev_warn(&pdev->dev,
> +			 "WARNING: driver may not support newer MC firmware features (driver version: %u.%u)\n",
> +			 MC_VER_MAJOR, MC_VER_MINOR);
> +	}

[...]

> +static int __init fsl_mc_bus_driver_init(void)
> +{
> +	int error;
> +
> +	mc_dev_cache = kmem_cache_create("fsl_mc_device",
> +					 sizeof(struct fsl_mc_device), 0, 0,
> +					 NULL);
> +	if (!mc_dev_cache) {
> +		pr_err("Could not create fsl_mc_device cache\n");
> +		return -ENOMEM;
> +	}
> +
> +	error = bus_register(&fsl_mc_bus_type);
> +	if (error < 0) {
> +		pr_err("fsl-mc bus type registration failed: %d\n", error);
> +		goto error_cleanup_cache;
> +	}
> +
> +	pr_info("fsl-mc bus type registered\n");
> +
> +	error = platform_driver_register(&fsl_mc_bus_driver);
> +	if (error < 0) {
> +		pr_err("platform_driver_register() failed: %d\n", error);
> +		goto error_cleanup_bus;
> +	}
> +
> +	return 0;
> +
> +error_cleanup_bus:
> +	bus_unregister(&fsl_mc_bus_type);
> +
> +error_cleanup_cache:
> +	kmem_cache_destroy(mc_dev_cache);
> +	return error;
> +}
> +
> +postcore_initcall(fsl_mc_bus_driver_init);

How does this get hooked up when compiled as a module?


Alex
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ