NXP/FSL SoC driver updates for v5.4

DPAA2 DPIO/MC driver
 - Remove explicit device_link_remove() and device_link_del() calls due to
 framework change
 
 DPAA QBman driver
 - Various changes to make it working with kexec
 - Remove dev_err() usage after platform_get_irq()
 
 GUTS driver
 - Add LS1028 SoC support
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCgAdFiEEhb3UXAyxp6UQ0v6khtxQDvusFVQFAl1XCAYACgkQhtxQDvus
 FVThUQ//bf+El82sfxyLDUeGo8OZ/tN82AOsoKpVSw8pFNIXJdsPOLavGaJF2ILv
 klWC6/gjFiusiXWuQkxPU3XD/tvgxnxwbwR0HojQIZDD8xPiY3LhK5gLLahnyu4N
 4dYrXguSaJB2t+I8Pn5S+1QtHvdLiHptbwWfg0DBd4WstPPmO2W2TMFSQMgfTzRv
 Y1vy9cJ/ybvnUu0ZpSAmUyUMY9cWLoKKgXONmIYBZg3Ar2bkBhYnFRfDXavuHpJQ
 LJMkRXkPsiq9cbuI/DiMcDOGwwYGG+7norrGYohTl9sSy+gfvSgszYgI7b0w5Sx/
 /NXmigojmRXOCICGCFXX+PVC2gWy9WAJhgSRXXEs+qHy03qJkSh8YbqP1lLyOZ/+
 r+hj7uHvyqxn2t5YThEYxpOURt7ztQdGvrzhiQEplmNYF1SOwKk+nypg9M2DYYG0
 OIZzjrUe3nMpBHbnGJJDcjQievI1xsqdyla9fby6w9wmfV9U3Xn9LVmCWNyOpl6k
 lcp7ayQHNxChsqFujyyyEhg4E7IyfvRCSCY+QT6aWb7ZIOuOAK0qsSZ76JxhqjDQ
 HXBcDTXsHZmkG5Cq3zcWUktehOgXsyuY4SXJUVIzMzQP07sMFxj08/zz3yKutl4O
 JLsXlXoJBl0peVJ6pXIiHbFr1jVvACjs2D1mnSuBP/OO+++HDM0=
 =KjF7
 -----END PGP SIGNATURE-----

Merge tag 'soc-fsl-next-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/leo/linux into arm/drivers

NXP/FSL SoC driver updates for v5.4

DPAA2 DPIO/MC driver
- Remove explicit device_link_remove() and device_link_del() calls due to
framework change

DPAA QBman driver
- Various changes to make it working with kexec
- Remove dev_err() usage after platform_get_irq()

GUTS driver
- Add LS1028 SoC support

* tag 'soc-fsl-next-v5.4' of git://git.kernel.org/pub/scm/linux/kernel/git/leo/linux:
  bus: fsl-mc: remove explicit device_link_del
  soc: fsl: dpio: remove explicit device_link_remove
  soc: fsl: guts: Add definition for LS1028A
  soc/fsl/qbman: Update device tree with reserved memory
  soc/fsl/qbman: Fixup qman_shutdown_fq()
  soc/fsl/qbman: Disable interrupts during portal recovery
  soc/fsl/qbman: Fix drain_mr_fqni()
  soc/fsl/qbman: Cleanup QMan queues if device was already initialized
  soc/fsl/qbman: Cleanup buffer pools if BMan was initialized prior to bootup
  soc/fsl/qbman: Rework QBMan private memory setup
  soc: fsl: qbman: Remove dev_err() usage after platform_get_irq()

Link: https://lore.kernel.org/r/20190816195301.26660-1-leoyang.li@nxp.com
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
This commit is contained in:
Arnd Bergmann 2019-09-03 22:06:07 +02:00
commit 9ddb2526eb
13 changed files with 264 additions and 72 deletions

View File

@ -330,7 +330,6 @@ void fsl_mc_object_free(struct fsl_mc_device *mc_adev)
fsl_mc_resource_free(resource); fsl_mc_resource_free(resource);
device_link_del(mc_adev->consumer_link);
mc_adev->consumer_link = NULL; mc_adev->consumer_link = NULL;
} }
EXPORT_SYMBOL_GPL(fsl_mc_object_free); EXPORT_SYMBOL_GPL(fsl_mc_object_free);

View File

@ -255,7 +255,6 @@ void fsl_mc_portal_free(struct fsl_mc_io *mc_io)
fsl_destroy_mc_io(mc_io); fsl_destroy_mc_io(mc_io);
fsl_mc_resource_free(resource); fsl_mc_resource_free(resource);
device_link_del(dpmcp_dev->consumer_link);
dpmcp_dev->consumer_link = NULL; dpmcp_dev->consumer_link = NULL;
} }
EXPORT_SYMBOL_GPL(fsl_mc_portal_free); EXPORT_SYMBOL_GPL(fsl_mc_portal_free);

View File

@ -305,8 +305,6 @@ void dpaa2_io_service_deregister(struct dpaa2_io *service,
list_del(&ctx->node); list_del(&ctx->node);
spin_unlock_irqrestore(&d->lock_notifications, irqflags); spin_unlock_irqrestore(&d->lock_notifications, irqflags);
if (dev)
device_link_remove(dev, d->dev);
} }
EXPORT_SYMBOL_GPL(dpaa2_io_service_deregister); EXPORT_SYMBOL_GPL(dpaa2_io_service_deregister);

View File

@ -102,6 +102,11 @@ static const struct fsl_soc_die_attr fsl_soc_die[] = {
.svr = 0x87360000, .svr = 0x87360000,
.mask = 0xff3f0000, .mask = 0xff3f0000,
}, },
/* Die: LS1028A, SoC: LS1028A */
{ .die = "LS1028A",
.svr = 0x870b0000,
.mask = 0xff3f0000,
},
{ }, { },
}; };
@ -224,6 +229,7 @@ static const struct of_device_id fsl_guts_of_match[] = {
{ .compatible = "fsl,ls1012a-dcfg", }, { .compatible = "fsl,ls1012a-dcfg", },
{ .compatible = "fsl,ls1046a-dcfg", }, { .compatible = "fsl,ls1046a-dcfg", },
{ .compatible = "fsl,lx2160a-dcfg", }, { .compatible = "fsl,lx2160a-dcfg", },
{ .compatible = "fsl,ls1028a-dcfg", },
{} {}
}; };
MODULE_DEVICE_TABLE(of, fsl_guts_of_match); MODULE_DEVICE_TABLE(of, fsl_guts_of_match);

View File

@ -635,30 +635,31 @@ int bman_p_irqsource_add(struct bman_portal *p, u32 bits)
return 0; return 0;
} }
static int bm_shutdown_pool(u32 bpid) int bm_shutdown_pool(u32 bpid)
{ {
int err = 0;
struct bm_mc_command *bm_cmd; struct bm_mc_command *bm_cmd;
union bm_mc_result *bm_res; union bm_mc_result *bm_res;
while (1) {
struct bman_portal *p = get_affine_portal(); struct bman_portal *p = get_affine_portal();
while (1) {
/* Acquire buffers until empty */ /* Acquire buffers until empty */
bm_cmd = bm_mc_start(&p->p); bm_cmd = bm_mc_start(&p->p);
bm_cmd->bpid = bpid; bm_cmd->bpid = bpid;
bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | 1); bm_mc_commit(&p->p, BM_MCC_VERB_CMD_ACQUIRE | 1);
if (!bm_mc_result_timeout(&p->p, &bm_res)) { if (!bm_mc_result_timeout(&p->p, &bm_res)) {
put_affine_portal();
pr_crit("BMan Acquire Command timedout\n"); pr_crit("BMan Acquire Command timedout\n");
return -ETIMEDOUT; err = -ETIMEDOUT;
goto done;
} }
if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) { if (!(bm_res->verb & BM_MCR_VERB_ACQUIRE_BUFCOUNT)) {
put_affine_portal();
/* Pool is empty */ /* Pool is empty */
return 0; goto done;
} }
}
done:
put_affine_portal(); put_affine_portal();
}
return 0; return 0;
} }

View File

@ -97,17 +97,40 @@ static void bm_get_version(u16 *id, u8 *major, u8 *minor)
/* signal transactions for FBPRs with higher priority */ /* signal transactions for FBPRs with higher priority */
#define FBPR_AR_RPRIO_HI BIT(30) #define FBPR_AR_RPRIO_HI BIT(30)
static void bm_set_memory(u64 ba, u32 size) /* Track if probe has occurred and if cleanup is required */
static int __bman_probed;
static int __bman_requires_cleanup;
static int bm_set_memory(u64 ba, u32 size)
{ {
u32 bar, bare;
u32 exp = ilog2(size); u32 exp = ilog2(size);
/* choke if size isn't within range */ /* choke if size isn't within range */
DPAA_ASSERT(size >= 4096 && size <= 1024*1024*1024 && DPAA_ASSERT(size >= 4096 && size <= 1024*1024*1024 &&
is_power_of_2(size)); is_power_of_2(size));
/* choke if '[e]ba' has lower-alignment than 'size' */ /* choke if '[e]ba' has lower-alignment than 'size' */
DPAA_ASSERT(!(ba & (size - 1))); DPAA_ASSERT(!(ba & (size - 1)));
/* Check to see if BMan has already been initialized */
bar = bm_ccsr_in(REG_FBPR_BAR);
if (bar) {
/* Maker sure ba == what was programmed) */
bare = bm_ccsr_in(REG_FBPR_BARE);
if (bare != upper_32_bits(ba) || bar != lower_32_bits(ba)) {
pr_err("Attempted to reinitialize BMan with different BAR, got 0x%llx read BARE=0x%x BAR=0x%x\n",
ba, bare, bar);
return -ENOMEM;
}
pr_info("BMan BAR already configured\n");
__bman_requires_cleanup = 1;
return 1;
}
bm_ccsr_out(REG_FBPR_BARE, upper_32_bits(ba)); bm_ccsr_out(REG_FBPR_BARE, upper_32_bits(ba));
bm_ccsr_out(REG_FBPR_BAR, lower_32_bits(ba)); bm_ccsr_out(REG_FBPR_BAR, lower_32_bits(ba));
bm_ccsr_out(REG_FBPR_AR, exp - 1); bm_ccsr_out(REG_FBPR_AR, exp - 1);
return 0;
} }
/* /*
@ -120,7 +143,6 @@ static void bm_set_memory(u64 ba, u32 size)
*/ */
static dma_addr_t fbpr_a; static dma_addr_t fbpr_a;
static size_t fbpr_sz; static size_t fbpr_sz;
static int __bman_probed;
static int bman_fbpr(struct reserved_mem *rmem) static int bman_fbpr(struct reserved_mem *rmem)
{ {
@ -173,6 +195,16 @@ int bman_is_probed(void)
} }
EXPORT_SYMBOL_GPL(bman_is_probed); EXPORT_SYMBOL_GPL(bman_is_probed);
int bman_requires_cleanup(void)
{
return __bman_requires_cleanup;
}
void bman_done_cleanup(void)
{
__bman_requires_cleanup = 0;
}
static int fsl_bman_probe(struct platform_device *pdev) static int fsl_bman_probe(struct platform_device *pdev)
{ {
int ret, err_irq; int ret, err_irq;

View File

@ -100,7 +100,7 @@ static int bman_portal_probe(struct platform_device *pdev)
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct bm_portal_config *pcfg; struct bm_portal_config *pcfg;
struct resource *addr_phys[2]; struct resource *addr_phys[2];
int irq, cpu, err; int irq, cpu, err, i;
err = bman_is_probed(); err = bman_is_probed();
if (!err) if (!err)
@ -135,10 +135,8 @@ static int bman_portal_probe(struct platform_device *pdev)
pcfg->cpu = -1; pcfg->cpu = -1;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq <= 0) { if (irq <= 0)
dev_err(dev, "Can't get %pOF IRQ'\n", node);
goto err_ioremap1; goto err_ioremap1;
}
pcfg->irq = irq; pcfg->irq = irq;
pcfg->addr_virt_ce = memremap(addr_phys[0]->start, pcfg->addr_virt_ce = memremap(addr_phys[0]->start,
@ -178,6 +176,22 @@ static int bman_portal_probe(struct platform_device *pdev)
if (!cpu_online(cpu)) if (!cpu_online(cpu))
bman_offline_cpu(cpu); bman_offline_cpu(cpu);
if (__bman_portals_probed == 1 && bman_requires_cleanup()) {
/*
* BMan wasn't reset prior to boot (Kexec for example)
* Empty all the buffer pools so they are in reset state
*/
for (i = 0; i < BM_POOL_MAX; i++) {
err = bm_shutdown_pool(i);
if (err) {
dev_err(dev, "Failed to shutdown bpool %d\n",
i);
goto err_portal_init;
}
}
bman_done_cleanup();
}
return 0; return 0;
err_portal_init: err_portal_init:

View File

@ -76,3 +76,8 @@ int bman_p_irqsource_add(struct bman_portal *p, u32 bits);
const struct bm_portal_config * const struct bm_portal_config *
bman_get_bm_portal_config(const struct bman_portal *portal); bman_get_bm_portal_config(const struct bman_portal *portal);
int bman_requires_cleanup(void);
void bman_done_cleanup(void);
int bm_shutdown_pool(u32 bpid);

View File

@ -37,42 +37,53 @@
int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr, int qbman_init_private_mem(struct device *dev, int idx, dma_addr_t *addr,
size_t *size) size_t *size)
{ {
int ret;
struct device_node *mem_node; 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); mem_node = of_parse_phandle(dev->of_node, "memory-region", idx);
if (ret) { if (!mem_node) {
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", 0);
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 {
dev_err(dev, "No memory-region found for index %d\n", idx); dev_err(dev, "No memory-region found for index %d\n", idx);
return -ENODEV; return -ENODEV;
} }
if (!dma_alloc_coherent(dev, *size, addr, 0)) { rmem = of_reserved_mem_lookup(mem_node);
dev_err(dev, "DMA Alloc memory failed\n"); if (!rmem) {
dev_err(dev, "of_reserved_mem_lookup() returned NULL\n");
return -ENODEV; return -ENODEV;
} }
*addr = rmem->base;
*size = rmem->size;
/* /*
* Disassociate the reserved memory area from the device * Check if the reg property exists - if not insert the node
* because a device can only have one DMA memory area. This * so upon kexec() the same memory region address will be preserved.
* should be fine since the memory is allocated and initialized * This is needed because QBMan HW does not allow the base address/
* and only ever accessed by the QBMan device from now on * 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; return 0;
} }

View File

@ -1018,6 +1018,20 @@ static inline void put_affine_portal(void)
put_cpu_var(qman_affine_portal); put_cpu_var(qman_affine_portal);
} }
static inline struct qman_portal *get_portal_for_channel(u16 channel)
{
int i;
for (i = 0; i < num_possible_cpus(); i++) {
if (affine_portals[i] &&
affine_portals[i]->config->channel == channel)
return affine_portals[i];
}
return NULL;
}
static struct workqueue_struct *qm_portal_wq; static struct workqueue_struct *qm_portal_wq;
int qman_dqrr_set_ithresh(struct qman_portal *portal, u8 ithresh) int qman_dqrr_set_ithresh(struct qman_portal *portal, u8 ithresh)
@ -1070,6 +1084,20 @@ int qman_wq_alloc(void)
return 0; 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 * 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. * to the one whose affine portal it is waiting on.
@ -1164,6 +1192,7 @@ static int drain_mr_fqrni(struct qm_portal *p)
{ {
const union qm_mr_entry *msg; const union qm_mr_entry *msg;
loop: loop:
qm_mr_pvb_update(p);
msg = qm_mr_current(p); msg = qm_mr_current(p);
if (!msg) { if (!msg) {
/* /*
@ -1180,7 +1209,8 @@ static int drain_mr_fqrni(struct qm_portal *p)
* entries well before the ring has been fully consumed, so * entries well before the ring has been fully consumed, so
* we're being *really* paranoid here. * we're being *really* paranoid here.
*/ */
msleep(1); mdelay(1);
qm_mr_pvb_update(p);
msg = qm_mr_current(p); msg = qm_mr_current(p);
if (!msg) if (!msg)
return 0; return 0;
@ -1267,8 +1297,8 @@ static int qman_create_portal(struct qman_portal *portal,
qm_out(p, QM_REG_ISDR, isdr); qm_out(p, QM_REG_ISDR, isdr);
portal->irq_sources = 0; portal->irq_sources = 0;
qm_out(p, QM_REG_IER, 0); qm_out(p, QM_REG_IER, 0);
qm_out(p, QM_REG_ISR, 0xffffffff);
snprintf(portal->irqname, MAX_IRQNAME, IRQNAME, c->cpu); 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)) { if (request_irq(c->irq, portal_isr, 0, portal->irqname, portal)) {
dev_err(c->dev, "request_irq() failed\n"); dev_err(c->dev, "request_irq() failed\n");
goto fail_irq; goto fail_irq;
@ -1288,7 +1318,7 @@ static int qman_create_portal(struct qman_portal *portal,
isdr &= ~(QM_PIRQ_DQRI | QM_PIRQ_MRI); isdr &= ~(QM_PIRQ_DQRI | QM_PIRQ_MRI);
qm_out(p, QM_REG_ISDR, isdr); qm_out(p, QM_REG_ISDR, isdr);
if (qm_dqrr_current(p)) { 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); qm_dqrr_cdc_consume_n(p, 0xffff);
} }
if (qm_mr_current(p) && drain_mr_fqrni(p)) { if (qm_mr_current(p) && drain_mr_fqrni(p)) {
@ -1301,7 +1331,9 @@ static int qman_create_portal(struct qman_portal *portal,
} }
/* Success */ /* Success */
portal->config = c; portal->config = c;
qm_out(p, QM_REG_ISR, 0xffffffff);
qm_out(p, QM_REG_ISDR, 0); qm_out(p, QM_REG_ISDR, 0);
if (!qman_requires_cleanup())
qm_out(p, QM_REG_IIR, 0); qm_out(p, QM_REG_IIR, 0);
/* Write a sane SDQCR */ /* Write a sane SDQCR */
qm_dqrr_sdqcr_set(p, portal->sdqcr); qm_dqrr_sdqcr_set(p, portal->sdqcr);
@ -2581,9 +2613,9 @@ static int _qm_dqrr_consume_and_match(struct qm_portal *p, u32 fqid, int s,
#define qm_dqrr_drain_nomatch(p) \ #define qm_dqrr_drain_nomatch(p) \
_qm_dqrr_consume_and_match(p, 0, 0, false) _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 qman_portal *p, *channel_portal;
struct device *dev; struct device *dev;
union qm_mc_command *mcc; union qm_mc_command *mcc;
union qm_mc_result *mcr; union qm_mc_result *mcr;
@ -2623,17 +2655,28 @@ static int qman_shutdown_fq(u32 fqid)
channel = qm_fqd_get_chan(&mcr->queryfq.fqd); channel = qm_fqd_get_chan(&mcr->queryfq.fqd);
wq = qm_fqd_get_wq(&mcr->queryfq.fqd); wq = qm_fqd_get_wq(&mcr->queryfq.fqd);
if (channel < qm_channel_pool1) {
channel_portal = get_portal_for_channel(channel);
if (channel_portal == NULL) {
dev_err(dev, "Can't find portal for dedicated channel 0x%x\n",
channel);
ret = -EIO;
goto out;
}
} else
channel_portal = p;
switch (state) { switch (state) {
case QM_MCR_NP_STATE_TEN_SCHED: case QM_MCR_NP_STATE_TEN_SCHED:
case QM_MCR_NP_STATE_TRU_SCHED: case QM_MCR_NP_STATE_TRU_SCHED:
case QM_MCR_NP_STATE_ACTIVE: case QM_MCR_NP_STATE_ACTIVE:
case QM_MCR_NP_STATE_PARKED: case QM_MCR_NP_STATE_PARKED:
orl_empty = 0; orl_empty = 0;
mcc = qm_mc_start(&p->p); mcc = qm_mc_start(&channel_portal->p);
qm_fqid_set(&mcc->fq, fqid); qm_fqid_set(&mcc->fq, fqid);
qm_mc_commit(&p->p, QM_MCC_VERB_ALTER_RETIRE); qm_mc_commit(&channel_portal->p, QM_MCC_VERB_ALTER_RETIRE);
if (!qm_mc_result_timeout(&p->p, &mcr)) { if (!qm_mc_result_timeout(&channel_portal->p, &mcr)) {
dev_err(dev, "QUERYFQ_NP timeout\n"); dev_err(dev, "ALTER_RETIRE timeout\n");
ret = -ETIMEDOUT; ret = -ETIMEDOUT;
goto out; goto out;
} }
@ -2641,6 +2684,9 @@ static int qman_shutdown_fq(u32 fqid)
QM_MCR_VERB_ALTER_RETIRE); QM_MCR_VERB_ALTER_RETIRE);
res = mcr->result; /* Make a copy as we reuse MCR below */ res = mcr->result; /* Make a copy as we reuse MCR below */
if (res == QM_MCR_RESULT_OK)
drain_mr_fqrni(&channel_portal->p);
if (res == QM_MCR_RESULT_PENDING) { if (res == QM_MCR_RESULT_PENDING) {
/* /*
* Need to wait for the FQRN in the message ring, which * Need to wait for the FQRN in the message ring, which
@ -2670,21 +2716,25 @@ static int qman_shutdown_fq(u32 fqid)
} }
/* Set the sdqcr to drain this channel */ /* Set the sdqcr to drain this channel */
if (channel < qm_channel_pool1) if (channel < qm_channel_pool1)
qm_dqrr_sdqcr_set(&p->p, qm_dqrr_sdqcr_set(&channel_portal->p,
QM_SDQCR_TYPE_ACTIVE | QM_SDQCR_TYPE_ACTIVE |
QM_SDQCR_CHANNELS_DEDICATED); QM_SDQCR_CHANNELS_DEDICATED);
else else
qm_dqrr_sdqcr_set(&p->p, qm_dqrr_sdqcr_set(&channel_portal->p,
QM_SDQCR_TYPE_ACTIVE | QM_SDQCR_TYPE_ACTIVE |
QM_SDQCR_CHANNELS_POOL_CONV QM_SDQCR_CHANNELS_POOL_CONV
(channel)); (channel));
do { do {
/* Keep draining DQRR while checking the MR*/ /* Keep draining DQRR while checking the MR*/
qm_dqrr_drain_nomatch(&p->p); qm_dqrr_drain_nomatch(&channel_portal->p);
/* Process message ring too */ /* Process message ring too */
found_fqrn = qm_mr_drain(&p->p, FQRN); found_fqrn = qm_mr_drain(&channel_portal->p,
FQRN);
cpu_relax(); cpu_relax();
} while (!found_fqrn); } while (!found_fqrn);
/* Restore SDQCR */
qm_dqrr_sdqcr_set(&channel_portal->p,
channel_portal->sdqcr);
} }
if (res != QM_MCR_RESULT_OK && if (res != QM_MCR_RESULT_OK &&
@ -2715,9 +2765,8 @@ static int qman_shutdown_fq(u32 fqid)
* Wait for a dequeue and process the dequeues, * Wait for a dequeue and process the dequeues,
* making sure to empty the ring completely * making sure to empty the ring completely
*/ */
} while (qm_dqrr_drain_wait(&p->p, fqid, FQ_EMPTY)); } while (!qm_dqrr_drain_wait(&p->p, fqid, FQ_EMPTY));
} }
qm_dqrr_sdqcr_set(&p->p, 0);
while (!orl_empty) { while (!orl_empty) {
/* Wait for the ORL to have been completely drained */ /* Wait for the ORL to have been completely drained */
@ -2754,7 +2803,7 @@ static int qman_shutdown_fq(u32 fqid)
DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) == DPAA_ASSERT((mcr->verb & QM_MCR_VERB_MASK) ==
QM_MCR_VERB_ALTER_OOS); 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", dev_err(dev, "OOS fail: FQ 0x%x (0x%x)\n",
fqid, mcr->result); fqid, mcr->result);
ret = -EIO; ret = -EIO;

View File

@ -274,6 +274,7 @@ static u32 __iomem *qm_ccsr_start;
/* A SDQCR mask comprising all the available/visible pool channels */ /* A SDQCR mask comprising all the available/visible pool channels */
static u32 qm_pools_sdqcr; static u32 qm_pools_sdqcr;
static int __qman_probed; static int __qman_probed;
static int __qman_requires_cleanup;
static inline u32 qm_ccsr_in(u32 offset) static inline u32 qm_ccsr_in(u32 offset)
{ {
@ -340,19 +341,55 @@ static void qm_get_version(u16 *id, u8 *major, u8 *minor)
} }
#define PFDR_AR_EN BIT(31) #define PFDR_AR_EN BIT(31)
static void qm_set_memory(enum qm_memory memory, u64 ba, u32 size) static int qm_set_memory(enum qm_memory memory, u64 ba, u32 size)
{ {
void *ptr;
u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE; u32 offset = (memory == qm_memory_fqd) ? REG_FQD_BARE : REG_PFDR_BARE;
u32 exp = ilog2(size); u32 exp = ilog2(size);
u32 bar, bare;
/* choke if size isn't within range */ /* choke if size isn't within range */
DPAA_ASSERT((size >= 4096) && (size <= 1024*1024*1024) && DPAA_ASSERT((size >= 4096) && (size <= 1024*1024*1024) &&
is_power_of_2(size)); is_power_of_2(size));
/* choke if 'ba' has lower-alignment than 'size' */ /* choke if 'ba' has lower-alignment than 'size' */
DPAA_ASSERT(!(ba & (size - 1))); DPAA_ASSERT(!(ba & (size - 1)));
/* Check to see if QMan has already been initialized */
bar = qm_ccsr_in(offset + REG_offset_BAR);
if (bar) {
/* Maker sure ba == what was programmed) */
bare = qm_ccsr_in(offset);
if (bare != upper_32_bits(ba) || bar != lower_32_bits(ba)) {
pr_err("Attempted to reinitialize QMan with different BAR, got 0x%llx read BARE=0x%x BAR=0x%x\n",
ba, bare, bar);
return -ENOMEM;
}
__qman_requires_cleanup = 1;
/* Return 1 to indicate memory was previously programmed */
return 1;
}
/* Need to temporarily map the area to make sure it is zeroed */
ptr = memremap(ba, size, MEMREMAP_WB);
if (!ptr) {
pr_crit("memremap() of QMan private memory failed\n");
return -ENOMEM;
}
memset(ptr, 0, size);
#ifdef CONFIG_PPC
/*
* PPC doesn't appear to flush the cache on memunmap() but the
* cache must be flushed since QMan does non coherent accesses
* to this memory
*/
flush_dcache_range((unsigned long) ptr, (unsigned long) ptr+size);
#endif
memunmap(ptr);
qm_ccsr_out(offset, upper_32_bits(ba)); qm_ccsr_out(offset, upper_32_bits(ba));
qm_ccsr_out(offset + REG_offset_BAR, lower_32_bits(ba)); qm_ccsr_out(offset + REG_offset_BAR, lower_32_bits(ba));
qm_ccsr_out(offset + REG_offset_AR, PFDR_AR_EN | (exp - 1)); qm_ccsr_out(offset + REG_offset_AR, PFDR_AR_EN | (exp - 1));
return 0;
} }
static void qm_set_pfdr_threshold(u32 th, u8 k) static void qm_set_pfdr_threshold(u32 th, u8 k)
@ -455,7 +492,7 @@ RESERVEDMEM_OF_DECLARE(qman_pfdr, "fsl,qman-pfdr", qman_pfdr);
#endif #endif
static unsigned int qm_get_fqid_maxcnt(void) unsigned int qm_get_fqid_maxcnt(void)
{ {
return fqd_sz / 64; return fqd_sz / 64;
} }
@ -571,12 +608,19 @@ static int qman_init_ccsr(struct device *dev)
int i, err; int i, err;
/* FQD memory */ /* FQD memory */
qm_set_memory(qm_memory_fqd, fqd_a, fqd_sz); err = qm_set_memory(qm_memory_fqd, fqd_a, fqd_sz);
if (err < 0)
return err;
/* PFDR memory */ /* PFDR memory */
qm_set_memory(qm_memory_pfdr, pfdr_a, pfdr_sz); err = qm_set_memory(qm_memory_pfdr, pfdr_a, pfdr_sz);
if (err < 0)
return err;
/* Only initialize PFDRs if the QMan was not initialized before */
if (err == 0) {
err = qm_init_pfdr(dev, 8, pfdr_sz / 64 - 8); err = qm_init_pfdr(dev, 8, pfdr_sz / 64 - 8);
if (err) if (err)
return err; return err;
}
/* thresholds */ /* thresholds */
qm_set_pfdr_threshold(512, 64); qm_set_pfdr_threshold(512, 64);
qm_set_sfdr_threshold(128); qm_set_sfdr_threshold(128);
@ -693,6 +737,18 @@ int qman_is_probed(void)
} }
EXPORT_SYMBOL_GPL(qman_is_probed); EXPORT_SYMBOL_GPL(qman_is_probed);
int qman_requires_cleanup(void)
{
return __qman_requires_cleanup;
}
void qman_done_cleanup(void)
{
qman_enable_irqs();
__qman_requires_cleanup = 0;
}
static int fsl_qman_probe(struct platform_device *pdev) static int fsl_qman_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;

View File

@ -233,7 +233,7 @@ static int qman_portal_probe(struct platform_device *pdev)
struct device_node *node = dev->of_node; struct device_node *node = dev->of_node;
struct qm_portal_config *pcfg; struct qm_portal_config *pcfg;
struct resource *addr_phys[2]; struct resource *addr_phys[2];
int irq, cpu, err; int irq, cpu, err, i;
u32 val; u32 val;
err = qman_is_probed(); err = qman_is_probed();
@ -275,10 +275,8 @@ static int qman_portal_probe(struct platform_device *pdev)
pcfg->channel = val; pcfg->channel = val;
pcfg->cpu = -1; pcfg->cpu = -1;
irq = platform_get_irq(pdev, 0); irq = platform_get_irq(pdev, 0);
if (irq <= 0) { if (irq <= 0)
dev_err(dev, "Can't get %pOF IRQ\n", node);
goto err_ioremap1; goto err_ioremap1;
}
pcfg->irq = irq; pcfg->irq = irq;
pcfg->addr_virt_ce = memremap(addr_phys[0]->start, pcfg->addr_virt_ce = memremap(addr_phys[0]->start,
@ -325,6 +323,22 @@ static int qman_portal_probe(struct platform_device *pdev)
if (!cpu_online(cpu)) if (!cpu_online(cpu))
qman_offline_cpu(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; return 0;
err_portal_init: err_portal_init:

View File

@ -272,3 +272,11 @@ extern struct qman_portal *affine_portals[NR_CPUS];
extern struct qman_portal *qman_dma_portal; extern struct qman_portal *qman_dma_portal;
const struct qm_portal_config *qman_get_qm_portal_config( const struct qm_portal_config *qman_get_qm_portal_config(
struct qman_portal *portal); 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);
void qman_enable_irqs(void);