2019-05-13 18:05:35

by Roy Pledge

[permalink] [raw]
Subject: [PATCH v1 0/8] soc/fsl/qbman: Enable Kexec for DPAA1 devices

Most DPAA1 devices do not support a soft reset which is an issue if
Kexec starts a new kernel. This patch series allows Kexec to function
by detecting that the QBMan device was previously initialized.

The patches fix some issues with device cleanup as well as ensuring
that the location of the QBMan private memories has not changed
after the execution of the Kexec.

Roy Pledge (8):
soc/fsl/qbman: Rework QBMan private memory setup
soc/fsl/qbman: Cleanup buffer pools if BMan was initialized prior to
bootup
soc/fsl/qbman: Cleanup QMan queues if device was already initialized
soc/fsl/qbman: Use index when accessing device tree properties
soc/fsl/qbman: Fix drain_mr_fqni()
soc/fsl/qbman: Disable interrupts during portal recovery
soc/fsl/qbman: Fixup qman_shutdown_fq()
soc/fsl/qbman: Update device tree with reserved memory

drivers/soc/fsl/qbman/bman.c | 17 ++++----
drivers/soc/fsl/qbman/bman_ccsr.c | 36 +++++++++++++++-
drivers/soc/fsl/qbman/bman_portal.c | 18 +++++++-
drivers/soc/fsl/qbman/bman_priv.h | 5 +++
drivers/soc/fsl/qbman/dpaa_sys.c | 63 ++++++++++++++++------------
drivers/soc/fsl/qbman/qman.c | 83 +++++++++++++++++++++++++++++--------
drivers/soc/fsl/qbman/qman_ccsr.c | 59 +++++++++++++++++++++++---
drivers/soc/fsl/qbman/qman_portal.c | 18 +++++++-
drivers/soc/fsl/qbman/qman_priv.h | 8 ++++
9 files changed, 246 insertions(+), 61 deletions(-)

--
2.7.4


2019-05-13 18:05:58

by Roy Pledge

[permalink] [raw]
Subject: [PATCH v1 5/8] soc/fsl/qbman: Fix drain_mr_fqni()

The drain_mr_fqni() function may be called fron uninterruptable
context so convert the msleep() to an mdelay(). Also ensure that
the valid bit is updated while polling.

Signed-off-by: Roy Pledge <[email protected]>
---
drivers/soc/fsl/qbman/qman.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index f10f77d..2989504 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -1164,6 +1164,7 @@ static int drain_mr_fqrni(struct qm_portal *p)
{
const union qm_mr_entry *msg;
loop:
+ qm_mr_pvb_update(p);
msg = qm_mr_current(p);
if (!msg) {
/*
@@ -1180,7 +1181,8 @@ static int drain_mr_fqrni(struct qm_portal *p)
* entries well before the ring has been fully consumed, so
* we're being *really* paranoid here.
*/
- msleep(1);
+ mdelay(1);
+ qm_mr_pvb_update(p);
msg = qm_mr_current(p);
if (!msg)
return 0;
--
2.7.4

2019-05-13 18:46:04

by Roy Pledge

[permalink] [raw]
Subject: [PATCH v1 4/8] soc/fsl/qbman: Use index when accessing device tree properties

The index value should be passed to the of_parse_phandle()
function to ensure the correct property is read.

Signed-off-by: Roy Pledge <[email protected]>
---
drivers/soc/fsl/qbman/dpaa_sys.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/soc/fsl/qbman/dpaa_sys.c b/drivers/soc/fsl/qbman/dpaa_sys.c
index 3e0a7f3..0b901a8 100644
--- a/drivers/soc/fsl/qbman/dpaa_sys.c
+++ b/drivers/soc/fsl/qbman/dpaa_sys.c
@@ -49,7 +49,7 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
idx, ret);
return -ENODEV;
}
- mem_node = of_parse_phandle(dev->of_node, "memory-region", 0);
+ mem_node = of_parse_phandle(dev->of_node, "memory-region", idx);
if (mem_node) {
ret = of_property_read_u64(mem_node, "size", &size64);
if (ret) {
--
2.7.4

2019-05-13 19:26:34

by Roy Pledge

[permalink] [raw]
Subject: [PATCH v1 6/8] soc/fsl/qbman: Disable interrupts during portal recovery

Disable the QBMan interrupts during recovery.

Signed-off-by: Roy Pledge <[email protected]>
---
drivers/soc/fsl/qbman/qman.c | 22 +++++++++++++++++++---
drivers/soc/fsl/qbman/qman_ccsr.c | 1 +
drivers/soc/fsl/qbman/qman_priv.h | 1 +
3 files changed, 21 insertions(+), 3 deletions(-)

diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 2989504..4a99ce5 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -1070,6 +1070,20 @@ int qman_wq_alloc(void)
return 0;
}

+
+void qman_enable_irqs(void)
+{
+ int i;
+
+ for (i = 0; i < num_possible_cpus(); i++) {
+ if (affine_portals[i]) {
+ qm_out(&affine_portals[i]->p, QM_REG_ISR, 0xffffffff);
+ qm_out(&affine_portals[i]->p, QM_REG_IIR, 0);
+ }
+
+ }
+}
+
/*
* This is what everything can wait on, even if it migrates to a different cpu
* to the one whose affine portal it is waiting on.
@@ -1269,8 +1283,8 @@ static int qman_create_portal(struct qman_portal *portal,
qm_out(p, QM_REG_ISDR, isdr);
portal->irq_sources = 0;
qm_out(p, QM_REG_IER, 0);
- qm_out(p, QM_REG_ISR, 0xffffffff);
snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu);
+ qm_out(p, QM_REG_IIR, 1);
if (request_irq(c->irq, portal_isr, 0, portal->irqname, portal)) {
dev_err(c->dev, "request_irq() failed\n");
goto fail_irq;
@@ -1290,7 +1304,7 @@ static int qman_create_portal(struct qman_portal *portal,
isdr &= ~(QM_PIRQ_DQRI | QM_PIRQ_MRI);
qm_out(p, QM_REG_ISDR, isdr);
if (qm_dqrr_current(p)) {
- dev_err(c->dev, "DQRR unclean\n");
+ dev_dbg(c->dev, "DQRR unclean\n");
qm_dqrr_cdc_consume_n(p, 0xffff);
}
if (qm_mr_current(p) && drain_mr_fqrni(p)) {
@@ -1303,8 +1317,10 @@ static int qman_create_portal(struct qman_portal *portal,
}
/* Success */
portal->config = c;
+ qm_out(p, QM_REG_ISR, 0xffffffff);
qm_out(p, QM_REG_ISDR, 0);
- qm_out(p, QM_REG_IIR, 0);
+ if (!qman_requires_cleanup())
+ qm_out(p, QM_REG_IIR, 0);
/* Write a sane SDQCR */
qm_dqrr_sdqcr_set(p, portal->sdqcr);
return 0;
diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c
index bee2d0e..3894172 100644
--- a/drivers/soc/fsl/qbman/qman_ccsr.c
+++ b/drivers/soc/fsl/qbman/qman_ccsr.c
@@ -735,6 +735,7 @@ int qman_requires_cleanup(void)

void qman_done_cleanup(void)
{
+ qman_enable_irqs();
__qman_requires_cleanup = 0;
}

diff --git a/drivers/soc/fsl/qbman/qman_priv.h b/drivers/soc/fsl/qbman/qman_priv.h
index bf51c17..9d37ddd 100644
--- a/drivers/soc/fsl/qbman/qman_priv.h
+++ b/drivers/soc/fsl/qbman/qman_priv.h
@@ -272,3 +272,4 @@ int qman_shutdown_fq(u32 fqid);

int qman_requires_cleanup(void);
void qman_done_cleanup(void);
+void qman_enable_irqs(void);
--
2.7.4

2019-05-13 19:26:44

by Roy Pledge

[permalink] [raw]
Subject: [PATCH v1 8/8] soc/fsl/qbman: Update device tree with reserved memory

When using the reserved memory node in the device tree there are
two options - dynamic or static. If a dynamic allocation was
selected (where the kernel selects the address for the allocation)
convert it to a static allocation by inserting the reg property.
This will ensure the same memory is reused after a kexec()

Signed-off-by: Roy Pledge <[email protected]>
---
drivers/soc/fsl/qbman/dpaa_sys.c | 58 ++++++++++++++++++++++++----------------
1 file changed, 35 insertions(+), 23 deletions(-)

diff --git a/drivers/soc/fsl/qbman/dpaa_sys.c b/drivers/soc/fsl/qbman/dpaa_sys.c
index 0b901a8..9dd8bb5 100644
--- a/drivers/soc/fsl/qbman/dpaa_sys.c
+++ b/drivers/soc/fsl/qbman/dpaa_sys.c
@@ -37,41 +37,53 @@
int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
size_t *size)
{
- int ret;
struct device_node *mem_node;
- u64 size64;
struct reserved_mem *rmem;
+ struct property *prop;
+ int len, err;
+ __be32 *res_array;

- ret = of_reserved_mem_device_init_by_idx(dev, dev->of_node, idx);
- if (ret) {
- dev_err(dev,
- "of_reserved_mem_device_init_by_idx(%d) failed 0x%x\n",
- idx, ret);
- return -ENODEV;
- }
mem_node = of_parse_phandle(dev->of_node, "memory-region", idx);
- if (mem_node) {
- ret = of_property_read_u64(mem_node, "size", &size64);
- if (ret) {
- dev_err(dev, "of_address_to_resource fails 0x%x\n",
- ret);
- return -ENODEV;
- }
- *size = size64;
- } else {
+ if (!mem_node) {
dev_err(dev, "No memory-region found for index %d\n", idx);
return -ENODEV;
}

rmem = of_reserved_mem_lookup(mem_node);
+ if (!rmem) {
+ dev_err(dev, "of_reserved_mem_lookup() returned NULL\n");
+ return -ENODEV;
+ }
*addr = rmem->base;
+ *size = rmem->size;

/*
- * Disassociate the reserved memory area from the device
- * because a device can only have one DMA memory area. This
- * should be fine since the memory is allocated and initialized
- * and only ever accessed by the QBMan device from now on
+ * Check if the reg property exists - if not insert the node
+ * so upon kexec() the same memory region address will be preserved.
+ * This is needed because QBMan HW does not allow the base address/
+ * size to be modified once set.
*/
- of_reserved_mem_device_release(dev);
+ prop = of_find_property(mem_node, "reg", &len);
+ if (!prop) {
+ prop = devm_kzalloc(dev, sizeof(*prop), GFP_KERNEL);
+ if (!prop)
+ return -ENOMEM;
+ prop->value = res_array = devm_kzalloc(dev, sizeof(__be32) * 4,
+ GFP_KERNEL);
+ if (!prop->value)
+ return -ENOMEM;
+ res_array[0] = cpu_to_be32(upper_32_bits(*addr));
+ res_array[1] = cpu_to_be32(lower_32_bits(*addr));
+ res_array[2] = cpu_to_be32(upper_32_bits(*size));
+ res_array[3] = cpu_to_be32(lower_32_bits(*size));
+ prop->length = sizeof(__be32) * 4;
+ prop->name = devm_kstrdup(dev, "reg", GFP_KERNEL);
+ if (!prop->name)
+ return -ENOMEM;
+ err = of_add_property(mem_node, prop);
+ if (err)
+ return err;
+ }
+
return 0;
}
--
2.7.4

2019-05-13 19:27:12

by Roy Pledge

[permalink] [raw]
Subject: [PATCH v1 3/8] soc/fsl/qbman: Cleanup QMan queues if device was already initialized

If the QMan device was previously initialized make sure all the
frame queues are out of service once all the portals are probed.
This handles the case where the kernel is restarted without the
SoC being reset (kexec for example)

Signed-off-by: Roy Pledge <[email protected]>
---
drivers/soc/fsl/qbman/qman.c | 4 ++--
drivers/soc/fsl/qbman/qman_ccsr.c | 13 ++++++++++++-
drivers/soc/fsl/qbman/qman_portal.c | 18 +++++++++++++++++-
drivers/soc/fsl/qbman/qman_priv.h | 7 +++++++
4 files changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/soc/fsl/qbman/qman.c b/drivers/soc/fsl/qbman/qman.c
index 636f83f..f10f77d 100644
--- a/drivers/soc/fsl/qbman/qman.c
+++ b/drivers/soc/fsl/qbman/qman.c
@@ -2581,7 +2581,7 @@ static int _qm_dqrr_consume_and_match(struct qm_portal *p, u32 fqid, int s,
#define qm_dqrr_drain_nomatch(p) \
_qm_dqrr_consume_and_match(p, 0, 0, false)

-static int qman_shutdown_fq(u32 fqid)
+int qman_shutdown_fq(u32 fqid)
{
struct qman_portal *p;
struct device *dev;
@@ -2754,7 +2754,7 @@ static int qman_shutdown_fq(u32 fqid)

DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
QM_MCR_VERB_ALTER_OOS);
- if (mcr->result) {
+ if (mcr->result != QM_MCR_RESULT_OK) {
dev_err(dev, "OOS fail: FQ 0x%x (0x%x)\n",
fqid, mcr->result);
ret = -EIO;
diff --git a/drivers/soc/fsl/qbman/qman_ccsr.c b/drivers/soc/fsl/qbman/qman_ccsr.c
index d054e37..bee2d0e 100644
--- a/drivers/soc/fsl/qbman/qman_ccsr.c
+++ b/drivers/soc/fsl/qbman/qman_ccsr.c
@@ -483,7 +483,7 @@ RESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr);

#endif

-static unsigned int qm_get_fqid_maxcnt(void)
+unsigned int qm_get_fqid_maxcnt(void)
{
return fqd_sz / 64;
}
@@ -728,6 +728,17 @@ int qman_is_probed(void)
}
EXPORT_SYMBOL_GPL(qman_is_probed);

+int qman_requires_cleanup(void)
+{
+ return __qman_requires_cleanup;
+}
+
+void qman_done_cleanup(void)
+{
+ __qman_requires_cleanup = 0;
+}
+
+
static int fsl_qman_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
diff --git a/drivers/soc/fsl/qbman/qman_portal.c b/drivers/soc/fsl/qbman/qman_portal.c
index 2460802..8295d75 100644
--- a/drivers/soc/fsl/qbman/qman_portal.c
+++ b/drivers/soc/fsl/qbman/qman_portal.c
@@ -233,7 +233,7 @@ static int qman_portal_probe(struct platform_device *pdev)
struct device_node *node = dev->of_node;
struct qm_portal_config *pcfg;
struct resource *addr_phys[2];
- int irq, cpu, err;
+ int irq, cpu, err, i;
u32 val;

err = qman_is_probed();
@@ -327,6 +327,22 @@ static int qman_portal_probe(struct platform_device *pdev)
if (!cpu_online(cpu))
qman_offline_cpu(cpu);

+ if (__qman_portals_probed == 1 && qman_requires_cleanup()) {
+ /*
+ * QMan wasn't reset prior to boot (Kexec for example)
+ * Empty all the frame queues so they are in reset state
+ */
+ for (i = 0; i < qm_get_fqid_maxcnt(); i++) {
+ err = qman_shutdown_fq(i);
+ if (err) {
+ dev_err(dev, "Failed to shutdown frame queue %d\n",
+ i);
+ goto err_portal_init;
+ }
+ }
+ qman_done_cleanup();
+ }
+
return 0;

err_portal_init:
diff --git a/drivers/soc/fsl/qbman/qman_priv.h b/drivers/soc/fsl/qbman/qman_priv.h
index 75a8f90..bf51c17 100644
--- a/drivers/soc/fsl/qbman/qman_priv.h
+++ b/drivers/soc/fsl/qbman/qman_priv.h
@@ -265,3 +265,10 @@ extern struct qman_portal *affine_portals[NR_CPUS];
extern struct qman_portal *qman_dma_portal;
const struct qm_portal_config *qman_get_qm_portal_config(
struct qman_portal *portal);
+
+unsigned int qm_get_fqid_maxcnt(void);
+
+int qman_shutdown_fq(u32 fqid);
+
+int qman_requires_cleanup(void);
+void qman_done_cleanup(void);
--
2.7.4

2019-05-13 19:28:47

by Joakim Tjernlund

[permalink] [raw]
Subject: Re: [PATCH v1 4/8] soc/fsl/qbman: Use index when accessing device tree properties

On Mon, 2019-05-13 at 16:09 +0000, Roy Pledge wrote:
>
> The index value should be passed to the of_parse_phandle()
> function to ensure the correct property is read.

Is this a bug fix? Maybe for stable too?

Jocke

>
> Signed-off-by: Roy Pledge <[email protected]>
> ---
> drivers/soc/fsl/qbman/dpaa_sys.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/soc/fsl/qbman/dpaa_sys.c b/drivers/soc/fsl/qbman/dpaa_sys.c
> index 3e0a7f3..0b901a8 100644
> --- a/drivers/soc/fsl/qbman/dpaa_sys.c
> +++ b/drivers/soc/fsl/qbman/dpaa_sys.c
> @@ -49,7 +49,7 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
> idx, ret);
> return -ENODEV;
> }
> - mem_node = of_parse_phandle(dev->of_node, "memory-region", 0);
> + mem_node = of_parse_phandle(dev->of_node, "memory-region", idx);
> if (mem_node) {
> ret = of_property_read_u64(mem_node, "size", &size64);
> if (ret) {
> --
> 2.7.4
>

2019-05-13 19:33:03

by Roy Pledge

[permalink] [raw]
Subject: Re: [PATCH v1 4/8] soc/fsl/qbman: Use index when accessing device tree properties

On 5/13/2019 12:40 PM, Joakim Tjernlund wrote:
> On Mon, 2019-05-13 at 16:09 +0000, Roy Pledge wrote:
>> The index value should be passed to the of_parse_phandle()
>> function to ensure the correct property is read.
> Is this a bug fix? Maybe for stable too?
>
> Jocke
Yes this could go to stable. I will include [email protected] when
I send the next version.
>
>> Signed-off-by: Roy Pledge <[email protected]>
>> ---
>> drivers/soc/fsl/qbman/dpaa_sys.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/drivers/soc/fsl/qbman/dpaa_sys.c b/drivers/soc/fsl/qbman/dpaa_sys.c
>> index 3e0a7f3..0b901a8 100644
>> --- a/drivers/soc/fsl/qbman/dpaa_sys.c
>> +++ b/drivers/soc/fsl/qbman/dpaa_sys.c
>> @@ -49,7 +49,7 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
>> idx, ret);
>> return -ENODEV;
>> }
>> - mem_node = of_parse_phandle(dev->of_node, "memory-region", 0);
>> + mem_node = of_parse_phandle(dev->of_node, "memory-region", idx);
>> if (mem_node) {
>> ret = of_property_read_u64(mem_node, "size", &size64);
>> if (ret) {
>> --
>> 2.7.4
>>
>

2019-05-14 04:53:21

by Joakim Tjernlund

[permalink] [raw]
Subject: Re: [PATCH v1 4/8] soc/fsl/qbman: Use index when accessing device tree properties

On Mon, 2019-05-13 at 17:40 +0000, Roy Pledge wrote:
> CAUTION: This email originated from outside of the organization. Do not click links or open attachments unless you recognize the sender and know the content is safe.
>
>
> On 5/13/2019 12:40 PM, Joakim Tjernlund wrote:
> > On Mon, 2019-05-13 at 16:09 +0000, Roy Pledge wrote:
> > > The index value should be passed to the of_parse_phandle()
> > > function to ensure the correct property is read.
> > Is this a bug fix? Maybe for stable too?
> >
> > Jocke
> Yes this could go to stable. I will include [email protected] when
> I send the next version.

I think you need to send this patch separately then. The whole series cannot go to stable.

Jocke

> > > Signed-off-by: Roy Pledge <[email protected]>
> > > ---
> > > drivers/soc/fsl/qbman/dpaa_sys.c | 2 +-
> > > 1 file changed, 1 insertion(+), 1 deletion(-)
> > >
> > > diff --git a/drivers/soc/fsl/qbman/dpaa_sys.c b/drivers/soc/fsl/qbman/dpaa_sys.c
> > > index 3e0a7f3..0b901a8 100644
> > > --- a/drivers/soc/fsl/qbman/dpaa_sys.c
> > > +++ b/drivers/soc/fsl/qbman/dpaa_sys.c
> > > @@ -49,7 +49,7 @@ int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
> > > idx, ret);
> > > return -ENODEV;
> > > }
> > > - mem_node = of_parse_phandle(dev->of_node, "memory-region", 0);
> > > + mem_node = of_parse_phandle(dev->of_node, "memory-region", idx);
> > > if (mem_node) {
> > > ret = of_property_read_u64(mem_node, "size", &size64);
> > > if (ret) {
> > > --
> > > 2.7.4
> > >