From e181a569d8e52d5a5c91cf2ddc3ebcfb81163887 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Tue, 4 Dec 2018 11:20:27 +0000 Subject: [PATCH 01/10] soc: fsl: dpio: cleanup the cpu array on dpaa2_io_down The dpio_by_cpu array should not contain a reference to a freed dpaa2_io object. This patch adds the necessary cleanup in dpaa2_io_down. Signed-off-by: Ioana Ciornei Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-service.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index ec0837ff039a..ab046f241d32 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -160,6 +160,11 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc) */ void dpaa2_io_down(struct dpaa2_io *d) { + spin_lock(&dpio_list_lock); + dpio_by_cpu[d->dpio_desc.cpu] = NULL; + list_del(&d->node); + spin_unlock(&dpio_list_lock); + kfree(d); } From 991e873223e9bcfaf10a0074eec1507c1ddfb6ab Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Tue, 4 Dec 2018 11:20:29 +0000 Subject: [PATCH 02/10] soc: fsl: dpio: use a cpumask to identify which cpus are unused The current implementation of the dpio driver uses a static next_cpu variable to keep track of the index of the next cpu available. This approach does not handle well unbinding and binding dpio devices in a random order. For example, unbinding a dpio and then binding it again with the driver, will generate the below error: $ echo dpio.5 > /sys/bus/fsl-mc/drivers/fsl_mc_dpio/unbind $ echo dpio.5 > /sys/bus/fsl-mc/drivers/fsl_mc_dpio/bind [ 103.946380] fsl_mc_dpio dpio.5: probe failed. Number of DPIOs exceeds NR_CPUS. [ 103.955157] fsl_mc_dpio dpio.5: fsl_mc_driver_probe failed: -34 -bash: echo: write error: No such device Fix this error by keeping a global cpumask of unused cpus that will be updated at every dpaa2_dpio_[probe,remove]. Signed-off-by: Ioana Ciornei Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-driver.c | 25 ++++++++++++++++--------- drivers/soc/fsl/dpio/dpio-service.c | 13 +++++++++++++ include/soc/fsl/dpaa2-io.h | 2 ++ 3 files changed, 31 insertions(+), 9 deletions(-) diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index e58fcc9096e8..832175cac739 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -30,6 +30,8 @@ struct dpio_priv { struct dpaa2_io *io; }; +static cpumask_var_t cpus_unused_mask; + static irqreturn_t dpio_irq_handler(int irq_num, void *arg) { struct device *dev = (struct device *)arg; @@ -86,7 +88,7 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) struct dpio_priv *priv; int err = -ENOMEM; struct device *dev = &dpio_dev->dev; - static int next_cpu = -1; + int possible_next_cpu; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -128,17 +130,14 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) desc.dpio_id = dpio_dev->obj_desc.id; /* get the cpu to use for the affinity hint */ - if (next_cpu == -1) - next_cpu = cpumask_first(cpu_online_mask); - else - next_cpu = cpumask_next(next_cpu, cpu_online_mask); - - if (!cpu_possible(next_cpu)) { + possible_next_cpu = cpumask_first(cpus_unused_mask); + if (possible_next_cpu >= nr_cpu_ids) { dev_err(dev, "probe failed. Number of DPIOs exceeds NR_CPUS.\n"); err = -ERANGE; goto err_allocate_irqs; } - desc.cpu = next_cpu; + desc.cpu = possible_next_cpu; + cpumask_clear_cpu(possible_next_cpu, cpus_unused_mask); /* * Set the CENA regs to be the cache inhibited area of the portal to @@ -211,7 +210,7 @@ static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) { struct device *dev; struct dpio_priv *priv; - int err; + int err = 0, cpu; dev = &dpio_dev->dev; priv = dev_get_drvdata(dev); @@ -220,6 +219,9 @@ static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) dpio_teardown_irqs(dpio_dev); + cpu = dpaa2_io_get_cpu(priv->io); + cpumask_set_cpu(cpu, cpus_unused_mask); + err = fsl_mc_portal_allocate(dpio_dev, 0, &dpio_dev->mc_io); if (err) { dev_err(dev, "MC portal allocation failed\n"); @@ -267,11 +269,16 @@ static struct fsl_mc_driver dpaa2_dpio_driver = { static int dpio_driver_init(void) { + if (!zalloc_cpumask_var(&cpus_unused_mask, GFP_KERNEL)) + return -ENOMEM; + cpumask_copy(cpus_unused_mask, cpu_online_mask); + return fsl_mc_driver_register(&dpaa2_dpio_driver); } static void dpio_driver_exit(void) { + free_cpumask_var(cpus_unused_mask); fsl_mc_driver_unregister(&dpaa2_dpio_driver); } module_init(dpio_driver_init); diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index ab046f241d32..c02bfb18a1f0 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -214,6 +214,19 @@ done: return IRQ_HANDLED; } +/** + * dpaa2_io_get_cpu() - get the cpu associated with a given DPIO object + * + * @d: the given DPIO object. + * + * Return the cpu associated with the DPIO object + */ +int dpaa2_io_get_cpu(struct dpaa2_io *d) +{ + return d->dpio_desc.cpu; +} +EXPORT_SYMBOL(dpaa2_io_get_cpu); + /** * dpaa2_io_service_register() - Prepare for servicing of FQDAN or CDAN * notifications on the given DPIO service. diff --git a/include/soc/fsl/dpaa2-io.h b/include/soc/fsl/dpaa2-io.h index 3fbd71c27ba3..243119c53cdf 100644 --- a/include/soc/fsl/dpaa2-io.h +++ b/include/soc/fsl/dpaa2-io.h @@ -90,6 +90,8 @@ struct dpaa2_io_notification_ctx { void *dpio_private; }; +int dpaa2_io_get_cpu(struct dpaa2_io *d); + int dpaa2_io_service_register(struct dpaa2_io *service, struct dpaa2_io_notification_ctx *ctx); void dpaa2_io_service_deregister(struct dpaa2_io *service, From 11c8bac9b3877fb8d8b4674f4744c1b5937956ba Mon Sep 17 00:00:00 2001 From: Roy Pledge Date: Mon, 10 Dec 2018 16:50:17 +0000 Subject: [PATCH 03/10] soc: fsl: dpio: perform DPIO Reset on Probe Invoke a DPIO reset command when a DPIO device is probed. This will ensure the QBMan portal is in the state the driver expects. Signed-off-by: Roy Pledge Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-cmd.h | 1 + drivers/soc/fsl/dpio/dpio-driver.c | 7 +++++++ drivers/soc/fsl/dpio/dpio.c | 23 +++++++++++++++++++++++ drivers/soc/fsl/dpio/dpio.h | 4 ++++ 4 files changed, 35 insertions(+) diff --git a/drivers/soc/fsl/dpio/dpio-cmd.h b/drivers/soc/fsl/dpio/dpio-cmd.h index ab8f82ee7ee5..5814d2f395a4 100644 --- a/drivers/soc/fsl/dpio/dpio-cmd.h +++ b/drivers/soc/fsl/dpio/dpio-cmd.h @@ -25,6 +25,7 @@ #define DPIO_CMDID_ENABLE DPIO_CMD(0x002) #define DPIO_CMDID_DISABLE DPIO_CMD(0x003) #define DPIO_CMDID_GET_ATTR DPIO_CMD(0x004) +#define DPIO_CMDID_RESET DPIO_CMD(0x005) struct dpio_cmd_open { __le32 dpio_id; diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 832175cac739..38ee9dba1c96 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -110,6 +110,12 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) goto err_open; } + err = dpio_reset(dpio_dev->mc_io, 0, dpio_dev->mc_handle); + if (err) { + dev_err(dev, "dpio_reset() failed\n"); + goto err_reset; + } + err = dpio_get_attributes(dpio_dev->mc_io, 0, dpio_dev->mc_handle, &dpio_attrs); if (err) { @@ -192,6 +198,7 @@ err_register_dpio_irq: err_allocate_irqs: dpio_disable(dpio_dev->mc_io, 0, dpio_dev->mc_handle); err_get_attr: +err_reset: dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); err_open: fsl_mc_portal_free(dpio_dev->mc_io); diff --git a/drivers/soc/fsl/dpio/dpio.c b/drivers/soc/fsl/dpio/dpio.c index ff37c80e11a0..521bc6946317 100644 --- a/drivers/soc/fsl/dpio/dpio.c +++ b/drivers/soc/fsl/dpio/dpio.c @@ -196,3 +196,26 @@ int dpio_get_api_version(struct fsl_mc_io *mc_io, return 0; } + +/** + * dpio_reset() - Reset the DPIO, returns the object to initial state. + * @mc_io: Pointer to MC portal's I/O object + * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_' + * @token: Token of DPIO object + * + * Return: '0' on Success; Error code otherwise. + */ +int dpio_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token) +{ + struct fsl_mc_command cmd = { 0 }; + + /* prepare command */ + cmd.header = mc_encode_cmd_header(DPIO_CMDID_RESET, + cmd_flags, + token); + + /* send command to mc*/ + return mc_send_command(mc_io, &cmd); +} diff --git a/drivers/soc/fsl/dpio/dpio.h b/drivers/soc/fsl/dpio/dpio.h index 49194c8e45f1..b2ac4ba4fb8e 100644 --- a/drivers/soc/fsl/dpio/dpio.h +++ b/drivers/soc/fsl/dpio/dpio.h @@ -80,4 +80,8 @@ int dpio_get_api_version(struct fsl_mc_io *mc_io, u16 *major_ver, u16 *minor_ver); +int dpio_reset(struct fsl_mc_io *mc_io, + u32 cmd_flags, + u16 token); + #endif /* __FSL_DPIO_H */ From 9182ee2840a99d8f3bc7b4332fc93c03c2016fd6 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 10 Dec 2018 16:50:17 +0000 Subject: [PATCH 04/10] soc: fsl: dpio: keep a per dpio device MC portal At the moment, the dpio-driver allocates an MC portal at probe time and frees it right after usage. The same thing happens on the remove path. This behavior could lead to scenarios where an MC portal is available for use at probing but not longer free on the remove path which could lead to unproper unbind of resources. Change the driver's behavior in such a way that an MC portal is allocated at probe and kept until the DPIO device is removed. This will ensure that at any time after a DPIO device was successfully probed, all its dependencies will be met. Signed-off-by: Ioana Ciornei Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-driver.c | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 38ee9dba1c96..5286723d4a14 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -187,7 +187,6 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) dev_dbg(dev, " receives_notifications = %d\n", desc.receives_notifications); dpio_close(dpio_dev->mc_io, 0, dpio_dev->mc_handle); - fsl_mc_portal_free(dpio_dev->mc_io); return 0; @@ -229,12 +228,6 @@ static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) cpu = dpaa2_io_get_cpu(priv->io); cpumask_set_cpu(cpu, cpus_unused_mask); - err = fsl_mc_portal_allocate(dpio_dev, 0, &dpio_dev->mc_io); - if (err) { - dev_err(dev, "MC portal allocation failed\n"); - goto err_mcportal; - } - err = dpio_open(dpio_dev->mc_io, 0, dpio_dev->obj_desc.id, &dpio_dev->mc_handle); if (err) { @@ -252,7 +245,7 @@ static int dpaa2_dpio_remove(struct fsl_mc_device *dpio_dev) err_open: fsl_mc_portal_free(dpio_dev->mc_io); -err_mcportal: + return err; } From cf9ff75d15a9bbd625519997c2ca864d1fa80227 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 10 Dec 2018 16:50:18 +0000 Subject: [PATCH 05/10] soc: fsl: dpio: store a backpointer to the device backing the dpaa2_io Add a new field in the dpaa2_io structure to hold a backpointer to the actual DPIO device. Signed-off-by: Ioana Ciornei Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-driver.c | 2 +- drivers/soc/fsl/dpio/dpio-service.c | 7 ++++++- include/soc/fsl/dpaa2-io.h | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/soc/fsl/dpio/dpio-driver.c b/drivers/soc/fsl/dpio/dpio-driver.c index 5286723d4a14..2d4af32a0dec 100644 --- a/drivers/soc/fsl/dpio/dpio-driver.c +++ b/drivers/soc/fsl/dpio/dpio-driver.c @@ -176,7 +176,7 @@ static int dpaa2_dpio_probe(struct fsl_mc_device *dpio_dev) if (err) goto err_register_dpio_irq; - priv->io = dpaa2_io_create(&desc); + priv->io = dpaa2_io_create(&desc, dev); if (!priv->io) { dev_err(dev, "dpaa2_io_create failed\n"); err = -ENOMEM; diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index c02bfb18a1f0..52d800aa4774 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -27,6 +27,7 @@ struct dpaa2_io { /* protect notifications list */ spinlock_t lock_notifications; struct list_head notifications; + struct device *dev; }; struct dpaa2_io_store { @@ -98,13 +99,15 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_select); /** * dpaa2_io_create() - create a dpaa2_io object. * @desc: the dpaa2_io descriptor + * @dev: the actual DPIO device * * Activates a "struct dpaa2_io" corresponding to the given config of an actual * DPIO object. * * Return a valid dpaa2_io object for success, or NULL for failure. */ -struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc) +struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc, + struct device *dev) { struct dpaa2_io *obj = kmalloc(sizeof(*obj), GFP_KERNEL); @@ -146,6 +149,8 @@ struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc) dpio_by_cpu[desc->cpu] = obj; spin_unlock(&dpio_list_lock); + obj->dev = dev; + return obj; } diff --git a/include/soc/fsl/dpaa2-io.h b/include/soc/fsl/dpaa2-io.h index 243119c53cdf..e252066d1f43 100644 --- a/include/soc/fsl/dpaa2-io.h +++ b/include/soc/fsl/dpaa2-io.h @@ -57,7 +57,8 @@ struct dpaa2_io_desc { u32 qman_version; }; -struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc); +struct dpaa2_io *dpaa2_io_create(const struct dpaa2_io_desc *desc, + struct device *dev); void dpaa2_io_down(struct dpaa2_io *d); From 47441f7f73b7cf0c2d6e7d6372f026ea81193fd6 Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 10 Dec 2018 16:50:19 +0000 Subject: [PATCH 06/10] soc: fsl: dpio: add a device_link at dpaa2_io_service_register Automatically add a device link between the actual device requesting the dpaa2_io_service_register and the underlying dpaa2_io used. This link will ensure that when a DPIO device, which is indirectly used by other devices, is unbound any consumer devices will be also unbound from their drivers. For example, any DPNI, bound to the dpaa2-eth driver, which is using DPIO devices will be unbound before its supplier device. Also, add a new parameter to the dpaa2_io_service_[de]register functions to specify the requesting device (ie the consumer). Signed-off-by: Ioana Ciornei Reviewed-by: Horia Geanta Reviewed-by: Ioana Radulescu Signed-off-by: Li Yang --- drivers/crypto/caam/caamalg_qi2.c | 6 +++--- drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c | 9 +++++---- drivers/soc/fsl/dpio/dpio-service.c | 16 ++++++++++++++-- include/soc/fsl/dpaa2-io.h | 6 ++++-- 4 files changed, 26 insertions(+), 11 deletions(-) diff --git a/drivers/crypto/caam/caamalg_qi2.c b/drivers/crypto/caam/caamalg_qi2.c index 425d5d974613..77f4c0045de2 100644 --- a/drivers/crypto/caam/caamalg_qi2.c +++ b/drivers/crypto/caam/caamalg_qi2.c @@ -4503,7 +4503,7 @@ static int __cold dpaa2_dpseci_dpio_setup(struct dpaa2_caam_priv *priv) nctx->cb = dpaa2_caam_fqdan_cb; /* Register notification callbacks */ - err = dpaa2_io_service_register(NULL, nctx); + err = dpaa2_io_service_register(NULL, nctx, dev); if (unlikely(err)) { dev_dbg(dev, "No affine DPIO for cpu %d\n", cpu); nctx->cb = NULL; @@ -4536,7 +4536,7 @@ err: ppriv = per_cpu_ptr(priv->ppriv, cpu); if (!ppriv->nctx.cb) break; - dpaa2_io_service_deregister(NULL, &ppriv->nctx); + dpaa2_io_service_deregister(NULL, &ppriv->nctx, dev); } for_each_online_cpu(cpu) { @@ -4556,7 +4556,7 @@ static void __cold dpaa2_dpseci_dpio_free(struct dpaa2_caam_priv *priv) for_each_online_cpu(cpu) { ppriv = per_cpu_ptr(priv->ppriv, cpu); - dpaa2_io_service_deregister(NULL, &ppriv->nctx); + dpaa2_io_service_deregister(NULL, &ppriv->nctx, priv->dev); dpaa2_io_store_destroy(ppriv->store); if (++i == priv->num_pairs) diff --git a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c index 1ca9a18139ec..c500ea77aaa0 100644 --- a/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c +++ b/drivers/net/ethernet/freescale/dpaa2/dpaa2-eth.c @@ -1902,7 +1902,7 @@ static int setup_dpio(struct dpaa2_eth_priv *priv) /* Register the new context */ channel->dpio = dpaa2_io_service_select(i); - err = dpaa2_io_service_register(channel->dpio, nctx); + err = dpaa2_io_service_register(channel->dpio, nctx, dev); if (err) { dev_dbg(dev, "No affine DPIO for cpu %d\n", i); /* If no affine DPIO for this core, there's probably @@ -1942,7 +1942,7 @@ static int setup_dpio(struct dpaa2_eth_priv *priv) return 0; err_set_cdan: - dpaa2_io_service_deregister(channel->dpio, nctx); + dpaa2_io_service_deregister(channel->dpio, nctx, dev); err_service_reg: free_channel(priv, channel); err_alloc_ch: @@ -1962,13 +1962,14 @@ err_alloc_ch: static void free_dpio(struct dpaa2_eth_priv *priv) { - int i; + struct device *dev = priv->net_dev->dev.parent; struct dpaa2_eth_channel *ch; + int i; /* deregister CDAN notifications and free channels */ for (i = 0; i < priv->num_channels; i++) { ch = priv->channel[i]; - dpaa2_io_service_deregister(ch->dpio, &ch->nctx); + dpaa2_io_service_deregister(ch->dpio, &ch->nctx, dev); free_channel(priv, ch); } } diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index 52d800aa4774..bc801934602a 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -237,6 +237,7 @@ EXPORT_SYMBOL(dpaa2_io_get_cpu); * notifications on the given DPIO service. * @d: the given DPIO service. * @ctx: the notification context. + * @dev: the device that requests the register * * The caller should make the MC command to attach a DPAA2 object to * a DPIO after this function completes successfully. In that way: @@ -251,14 +252,20 @@ EXPORT_SYMBOL(dpaa2_io_get_cpu); * Return 0 for success, or -ENODEV for failure. */ int dpaa2_io_service_register(struct dpaa2_io *d, - struct dpaa2_io_notification_ctx *ctx) + struct dpaa2_io_notification_ctx *ctx, + struct device *dev) { + struct device_link *link; unsigned long irqflags; d = service_select_by_cpu(d, ctx->desired_cpu); if (!d) return -ENODEV; + link = device_link_add(dev, d->dev, DL_FLAG_AUTOREMOVE_CONSUMER); + if (!link) + return -EINVAL; + ctx->dpio_id = d->dpio_desc.dpio_id; ctx->qman64 = (u64)(uintptr_t)ctx; ctx->dpio_private = d; @@ -279,12 +286,14 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_register); * dpaa2_io_service_deregister - The opposite of 'register'. * @service: the given DPIO service. * @ctx: the notification context. + * @dev: the device that requests to be deregistered * * This function should be called only after sending the MC command to * to detach the notification-producing device from the DPIO. */ void dpaa2_io_service_deregister(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx) + struct dpaa2_io_notification_ctx *ctx, + struct device *dev) { struct dpaa2_io *d = ctx->dpio_private; unsigned long irqflags; @@ -295,6 +304,9 @@ void dpaa2_io_service_deregister(struct dpaa2_io *service, spin_lock_irqsave(&d->lock_notifications, irqflags); list_del(&ctx->node); spin_unlock_irqrestore(&d->lock_notifications, irqflags); + + if (dev) + device_link_remove(dev, d->dev); } EXPORT_SYMBOL_GPL(dpaa2_io_service_deregister); diff --git a/include/soc/fsl/dpaa2-io.h b/include/soc/fsl/dpaa2-io.h index e252066d1f43..3447fd10a3e6 100644 --- a/include/soc/fsl/dpaa2-io.h +++ b/include/soc/fsl/dpaa2-io.h @@ -94,9 +94,11 @@ struct dpaa2_io_notification_ctx { int dpaa2_io_get_cpu(struct dpaa2_io *d); int dpaa2_io_service_register(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx); + struct dpaa2_io_notification_ctx *ctx, + struct device *dev); void dpaa2_io_service_deregister(struct dpaa2_io *service, - struct dpaa2_io_notification_ctx *ctx); + struct dpaa2_io_notification_ctx *ctx, + struct device *dev); int dpaa2_io_service_rearm(struct dpaa2_io *service, struct dpaa2_io_notification_ctx *ctx); From afb77422819ff60612e9b7d36461b9b2bc8e038e Mon Sep 17 00:00:00 2001 From: Ioana Ciornei Date: Mon, 10 Dec 2018 16:50:19 +0000 Subject: [PATCH 07/10] bus: fsl-mc: automatically add a device_link on fsl_mc_[portal,object]_allocate Allocatable devices can be acquired by drivers on the fsl-mc bus using the fsl_mc_portal_allocate or fsl_mc_object_allocate functions. Add a device link between the consumer device and the supplier device so that proper resource management is achieved. Also, adding a link between these devices ensures that a proper unbind order is respected (ie before the supplier device is unbound from its respective driver all consumer devices will be notified and unbound first). Signed-off-by: Ioana Ciornei Reviewed-by: Laurentiu Tudor Signed-off-by: Li Yang --- drivers/bus/fsl-mc/fsl-mc-allocator.c | 11 +++++++++++ drivers/bus/fsl-mc/mc-io.c | 13 +++++++++++++ include/linux/fsl/mc.h | 1 + 3 files changed, 25 insertions(+) diff --git a/drivers/bus/fsl-mc/fsl-mc-allocator.c b/drivers/bus/fsl-mc/fsl-mc-allocator.c index e906ecfe23dd..8ad77246f322 100644 --- a/drivers/bus/fsl-mc/fsl-mc-allocator.c +++ b/drivers/bus/fsl-mc/fsl-mc-allocator.c @@ -295,6 +295,14 @@ int __must_check fsl_mc_object_allocate(struct fsl_mc_device *mc_dev, if (!mc_adev) goto error; + mc_adev->consumer_link = device_link_add(&mc_dev->dev, + &mc_adev->dev, + DL_FLAG_AUTOREMOVE_CONSUMER); + if (!mc_adev->consumer_link) { + error = -EINVAL; + goto error; + } + *new_mc_adev = mc_adev; return 0; error: @@ -321,6 +329,9 @@ void fsl_mc_object_free(struct fsl_mc_device *mc_adev) return; fsl_mc_resource_free(resource); + + device_link_del(mc_adev->consumer_link); + mc_adev->consumer_link = NULL; } EXPORT_SYMBOL_GPL(fsl_mc_object_free); diff --git a/drivers/bus/fsl-mc/mc-io.c b/drivers/bus/fsl-mc/mc-io.c index 7226cfc49b6f..3ae574a58cce 100644 --- a/drivers/bus/fsl-mc/mc-io.c +++ b/drivers/bus/fsl-mc/mc-io.c @@ -209,9 +209,19 @@ int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev, if (error < 0) goto error_cleanup_resource; + dpmcp_dev->consumer_link = device_link_add(&mc_dev->dev, + &dpmcp_dev->dev, + DL_FLAG_AUTOREMOVE_CONSUMER); + if (!dpmcp_dev->consumer_link) { + error = -EINVAL; + goto error_cleanup_mc_io; + } + *new_mc_io = mc_io; return 0; +error_cleanup_mc_io: + fsl_destroy_mc_io(mc_io); error_cleanup_resource: fsl_mc_resource_free(resource); return error; @@ -244,6 +254,9 @@ void fsl_mc_portal_free(struct fsl_mc_io *mc_io) fsl_destroy_mc_io(mc_io); fsl_mc_resource_free(resource); + + device_link_del(dpmcp_dev->consumer_link); + dpmcp_dev->consumer_link = NULL; } EXPORT_SYMBOL_GPL(fsl_mc_portal_free); diff --git a/include/linux/fsl/mc.h b/include/linux/fsl/mc.h index 741f567253ef..975553a9f75d 100644 --- a/include/linux/fsl/mc.h +++ b/include/linux/fsl/mc.h @@ -193,6 +193,7 @@ struct fsl_mc_device { struct resource *regions; struct fsl_mc_device_irq **irqs; struct fsl_mc_resource *resource; + struct device_link *consumer_link; }; #define to_fsl_mc_device(_dev) \ From f1e250bf365962519c96a1255b2fe34b6c0d6c60 Mon Sep 17 00:00:00 2001 From: Ioana Ciocoi Radulescu Date: Fri, 14 Dec 2018 16:04:05 +0000 Subject: [PATCH 08/10] soc: fsl: dpio: Add prefetch instruction In dpaa2_io_store_next(), if the current dequeue entry is not the last, prefetch the next one as most likely it will be requested shortly by the consumer driver. This brings a ~3% improvement for dpaa2 ethernet driver IP forwarding with small size frames. Signed-off-by: Ioana Radulescu Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-service.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index bc801934602a..5389336463c0 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -630,6 +630,7 @@ struct dpaa2_dq *dpaa2_io_store_next(struct dpaa2_io_store *s, int *is_last) if (!(dpaa2_dq_flags(ret) & DPAA2_DQ_STAT_VALIDFRAME)) ret = NULL; } else { + prefetch(&s->vaddr[s->idx]); *is_last = 0; } From 8a533a7de21aa69cf9a3e55223c819858fbc7da2 Mon Sep 17 00:00:00 2001 From: Ioana Ciocoi Radulescu Date: Fri, 14 Dec 2018 16:04:06 +0000 Subject: [PATCH 09/10] soc: fsl: dpio: Change bpid type to u16 In all QBMan registers, the buffer pool id field is two bytes long. The low level qbman APIs reflect this, but the high level DPIO ones use u32. Modify them in order to avoid implicit downcasts. Signed-off-by: Ioana Radulescu Signed-off-by: Li Yang --- drivers/soc/fsl/dpio/dpio-service.c | 4 ++-- include/soc/fsl/dpaa2-io.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/soc/fsl/dpio/dpio-service.c b/drivers/soc/fsl/dpio/dpio-service.c index 5389336463c0..b9539ef2c3cd 100644 --- a/drivers/soc/fsl/dpio/dpio-service.c +++ b/drivers/soc/fsl/dpio/dpio-service.c @@ -473,7 +473,7 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_enqueue_qd); * Return 0 for success, and negative error code for failure. */ int dpaa2_io_service_release(struct dpaa2_io *d, - u32 bpid, + u16 bpid, const u64 *buffers, unsigned int num_buffers) { @@ -502,7 +502,7 @@ EXPORT_SYMBOL_GPL(dpaa2_io_service_release); * Eg. if the buffer pool is empty, this will return zero. */ int dpaa2_io_service_acquire(struct dpaa2_io *d, - u32 bpid, + u16 bpid, u64 *buffers, unsigned int num_buffers) { diff --git a/include/soc/fsl/dpaa2-io.h b/include/soc/fsl/dpaa2-io.h index 3447fd10a3e6..672cfb58046f 100644 --- a/include/soc/fsl/dpaa2-io.h +++ b/include/soc/fsl/dpaa2-io.h @@ -111,9 +111,9 @@ int dpaa2_io_service_enqueue_fq(struct dpaa2_io *d, u32 fqid, const struct dpaa2_fd *fd); int dpaa2_io_service_enqueue_qd(struct dpaa2_io *d, u32 qdid, u8 prio, u16 qdbin, const struct dpaa2_fd *fd); -int dpaa2_io_service_release(struct dpaa2_io *d, u32 bpid, +int dpaa2_io_service_release(struct dpaa2_io *d, u16 bpid, const u64 *buffers, unsigned int num_buffers); -int dpaa2_io_service_acquire(struct dpaa2_io *d, u32 bpid, +int dpaa2_io_service_acquire(struct dpaa2_io *d, u16 bpid, u64 *buffers, unsigned int num_buffers); struct dpaa2_io_store *dpaa2_io_store_create(unsigned int max_frames, From 3c0d64e867ed78a782a8a00d3b519396d9c5a2db Mon Sep 17 00:00:00 2001 From: Li Yang Date: Fri, 11 Jan 2019 15:55:57 -0600 Subject: [PATCH 10/10] soc: fsl: guts: reuse machine name from device tree Reuse the string machine from the device tree data structure instead of duplicating the data again. This also prevents a potential memory allocation failure that was not handled previously. Also fixes an early put of root device node. Reported-by: Nicholas Mc Guire Signed-off-by: Li Yang --- drivers/soc/fsl/guts.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/soc/fsl/guts.c b/drivers/soc/fsl/guts.c index 302e0c8d69d9..4f9655087bd7 100644 --- a/drivers/soc/fsl/guts.c +++ b/drivers/soc/fsl/guts.c @@ -32,6 +32,7 @@ struct fsl_soc_die_attr { static struct guts *guts; static struct soc_device_attribute soc_dev_attr; static struct soc_device *soc_dev; +static struct device_node *root; /* SoC die attribute definition for QorIQ platform */ @@ -132,7 +133,7 @@ EXPORT_SYMBOL(fsl_guts_get_svr); static int fsl_guts_probe(struct platform_device *pdev) { - struct device_node *root, *np = pdev->dev.of_node; + struct device_node *np = pdev->dev.of_node; struct device *dev = &pdev->dev; struct resource *res; const struct fsl_soc_die_attr *soc_die; @@ -155,9 +156,8 @@ static int fsl_guts_probe(struct platform_device *pdev) root = of_find_node_by_path("/"); if (of_property_read_string(root, "model", &machine)) of_property_read_string_index(root, "compatible", 0, &machine); - of_node_put(root); if (machine) - soc_dev_attr.machine = devm_kstrdup(dev, machine, GFP_KERNEL); + soc_dev_attr.machine = machine; svr = fsl_guts_get_svr(); soc_die = fsl_soc_die_match(svr, fsl_soc_die); @@ -192,6 +192,7 @@ static int fsl_guts_probe(struct platform_device *pdev) static int fsl_guts_remove(struct platform_device *dev) { soc_device_unregister(soc_dev); + of_node_put(root); return 0; }