diff options
Diffstat (limited to 'drivers/soc/ti/knav_qmss_queue.c')
-rw-r--r-- | drivers/soc/ti/knav_qmss_queue.c | 158 |
1 files changed, 116 insertions, 42 deletions
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c index 77d6b5c03aae..6755f2af5619 100644 --- a/drivers/soc/ti/knav_qmss_queue.c +++ b/drivers/soc/ti/knav_qmss_queue.c @@ -42,6 +42,15 @@ static DEFINE_MUTEX(knav_dev_lock); #define KNAV_QUEUE_PUSH_REG_INDEX 4 #define KNAV_QUEUE_POP_REG_INDEX 5 +/* Queue manager register indices in DTS for QMSS in K2G NAVSS. + * There are no status and vbusm push registers on this version + * of QMSS. Push registers are same as pop, So all indices above 1 + * are to be re-defined + */ +#define KNAV_L_QUEUE_CONFIG_REG_INDEX 1 +#define KNAV_L_QUEUE_REGION_REG_INDEX 2 +#define KNAV_L_QUEUE_PUSH_REG_INDEX 3 + /* PDSP register indices in DTS */ #define KNAV_QUEUE_PDSP_IRAM_REG_INDEX 0 #define KNAV_QUEUE_PDSP_REGS_REG_INDEX 1 @@ -65,6 +74,13 @@ static DEFINE_MUTEX(knav_dev_lock); */ const char *knav_acc_firmwares[] = {"ks2_qmss_pdsp_acc48.bin"}; +static bool device_ready; +bool knav_qmss_device_ready(void) +{ + return device_ready; +} +EXPORT_SYMBOL_GPL(knav_qmss_device_ready); + /** * knav_queue_notify: qmss queue notfier call * @@ -83,7 +99,7 @@ void knav_queue_notify(struct knav_queue_inst *inst) continue; if (WARN_ON(!qh->notifier_fn)) continue; - atomic_inc(&qh->stats.notifies); + this_cpu_inc(qh->stats->notifies); qh->notifier_fn(qh->notifier_fn_arg); } rcu_read_unlock(); @@ -214,6 +230,12 @@ static struct knav_queue *__knav_queue_open(struct knav_queue_inst *inst, if (!qh) return ERR_PTR(-ENOMEM); + qh->stats = alloc_percpu(struct knav_queue_stats); + if (!qh->stats) { + ret = -ENOMEM; + goto err; + } + qh->flags = flags; qh->inst = inst; id = inst->id - inst->qmgr->start_queue; @@ -229,13 +251,17 @@ static struct knav_queue *__knav_queue_open(struct knav_queue_inst *inst, if (range->ops && range->ops->open_queue) ret = range->ops->open_queue(range, inst, flags); - if (ret) { - devm_kfree(inst->kdev->dev, qh); - return ERR_PTR(ret); - } + if (ret) + goto err; } list_add_tail_rcu(&qh->list, &inst->handles); return qh; + +err: + if (qh->stats) + free_percpu(qh->stats); + devm_kfree(inst->kdev->dev, qh); + return ERR_PTR(ret); } static struct knav_queue * @@ -411,6 +437,12 @@ static void knav_queue_debug_show_instance(struct seq_file *s, { struct knav_device *kdev = inst->kdev; struct knav_queue *qh; + int cpu = 0; + int pushes = 0; + int pops = 0; + int push_errors = 0; + int pop_errors = 0; + int notifies = 0; if (!knav_queue_is_busy(inst)) return; @@ -418,19 +450,22 @@ static void knav_queue_debug_show_instance(struct seq_file *s, seq_printf(s, "\tqueue id %d (%s)\n", kdev->base_id + inst->id, inst->name); for_each_handle_rcu(qh, inst) { - seq_printf(s, "\t\thandle %p: ", qh); - seq_printf(s, "pushes %8d, ", - atomic_read(&qh->stats.pushes)); - seq_printf(s, "pops %8d, ", - atomic_read(&qh->stats.pops)); - seq_printf(s, "count %8d, ", - knav_queue_get_count(qh)); - seq_printf(s, "notifies %8d, ", - atomic_read(&qh->stats.notifies)); - seq_printf(s, "push errors %8d, ", - atomic_read(&qh->stats.push_errors)); - seq_printf(s, "pop errors %8d\n", - atomic_read(&qh->stats.pop_errors)); + for_each_possible_cpu(cpu) { + pushes += per_cpu_ptr(qh->stats, cpu)->pushes; + pops += per_cpu_ptr(qh->stats, cpu)->pops; + push_errors += per_cpu_ptr(qh->stats, cpu)->push_errors; + pop_errors += per_cpu_ptr(qh->stats, cpu)->pop_errors; + notifies += per_cpu_ptr(qh->stats, cpu)->notifies; + } + + seq_printf(s, "\t\thandle %p: pushes %8d, pops %8d, count %8d, notifies %8d, push errors %8d, pop errors %8d\n", + qh, + pushes, + pops, + knav_queue_get_count(qh), + notifies, + push_errors, + pop_errors); } } @@ -547,6 +582,7 @@ void knav_queue_close(void *qhandle) if (range->ops && range->ops->close_queue) range->ops->close_queue(range, inst); } + free_percpu(qh->stats); devm_kfree(inst->kdev->dev, qh); } EXPORT_SYMBOL_GPL(knav_queue_close); @@ -620,7 +656,7 @@ int knav_queue_push(void *qhandle, dma_addr_t dma, val = (u32)dma | ((size / 16) - 1); writel_relaxed(val, &qh->reg_push[0].ptr_size_thresh); - atomic_inc(&qh->stats.pushes); + this_cpu_inc(qh->stats->pushes); return 0; } EXPORT_SYMBOL_GPL(knav_queue_push); @@ -658,7 +694,7 @@ dma_addr_t knav_queue_pop(void *qhandle, unsigned *size) if (size) *size = ((val & DESC_SIZE_MASK) + 1) * 16; - atomic_inc(&qh->stats.pops); + this_cpu_inc(qh->stats->pops); return dma; } EXPORT_SYMBOL_GPL(knav_queue_pop); @@ -1169,8 +1205,12 @@ static int knav_queue_setup_link_ram(struct knav_device *kdev) dev_dbg(kdev->dev, "linkram0: dma:%pad, virt:%p, size:%x\n", &block->dma, block->virt, block->size); writel_relaxed((u32)block->dma, &qmgr->reg_config->link_ram_base0); - writel_relaxed(block->size, &qmgr->reg_config->link_ram_size0); - + if (kdev->version == QMSS_66AK2G) + writel_relaxed(block->size, + &qmgr->reg_config->link_ram_size0); + else + writel_relaxed(block->size - 1, + &qmgr->reg_config->link_ram_size0); block++; if (!block->size) continue; @@ -1387,42 +1427,64 @@ static int knav_queue_init_qmgrs(struct knav_device *kdev, qmgr->reg_peek = knav_queue_map_reg(kdev, child, KNAV_QUEUE_PEEK_REG_INDEX); - qmgr->reg_status = - knav_queue_map_reg(kdev, child, - KNAV_QUEUE_STATUS_REG_INDEX); + + if (kdev->version == QMSS) { + qmgr->reg_status = + knav_queue_map_reg(kdev, child, + KNAV_QUEUE_STATUS_REG_INDEX); + } + qmgr->reg_config = knav_queue_map_reg(kdev, child, + (kdev->version == QMSS_66AK2G) ? + KNAV_L_QUEUE_CONFIG_REG_INDEX : KNAV_QUEUE_CONFIG_REG_INDEX); qmgr->reg_region = knav_queue_map_reg(kdev, child, + (kdev->version == QMSS_66AK2G) ? + KNAV_L_QUEUE_REGION_REG_INDEX : KNAV_QUEUE_REGION_REG_INDEX); + qmgr->reg_push = knav_queue_map_reg(kdev, child, - KNAV_QUEUE_PUSH_REG_INDEX); - qmgr->reg_pop = - knav_queue_map_reg(kdev, child, - KNAV_QUEUE_POP_REG_INDEX); + (kdev->version == QMSS_66AK2G) ? + KNAV_L_QUEUE_PUSH_REG_INDEX : + KNAV_QUEUE_PUSH_REG_INDEX); + + if (kdev->version == QMSS) { + qmgr->reg_pop = + knav_queue_map_reg(kdev, child, + KNAV_QUEUE_POP_REG_INDEX); + } - if (IS_ERR(qmgr->reg_peek) || IS_ERR(qmgr->reg_status) || + if (IS_ERR(qmgr->reg_peek) || + ((kdev->version == QMSS) && + (IS_ERR(qmgr->reg_status) || IS_ERR(qmgr->reg_pop))) || IS_ERR(qmgr->reg_config) || IS_ERR(qmgr->reg_region) || - IS_ERR(qmgr->reg_push) || IS_ERR(qmgr->reg_pop)) { + IS_ERR(qmgr->reg_push)) { dev_err(dev, "failed to map qmgr regs\n"); + if (kdev->version == QMSS) { + if (!IS_ERR(qmgr->reg_status)) + devm_iounmap(dev, qmgr->reg_status); + if (!IS_ERR(qmgr->reg_pop)) + devm_iounmap(dev, qmgr->reg_pop); + } if (!IS_ERR(qmgr->reg_peek)) devm_iounmap(dev, qmgr->reg_peek); - if (!IS_ERR(qmgr->reg_status)) - devm_iounmap(dev, qmgr->reg_status); if (!IS_ERR(qmgr->reg_config)) devm_iounmap(dev, qmgr->reg_config); if (!IS_ERR(qmgr->reg_region)) devm_iounmap(dev, qmgr->reg_region); if (!IS_ERR(qmgr->reg_push)) devm_iounmap(dev, qmgr->reg_push); - if (!IS_ERR(qmgr->reg_pop)) - devm_iounmap(dev, qmgr->reg_pop); devm_kfree(dev, qmgr); continue; } + /* Use same push register for pop as well */ + if (kdev->version == QMSS_66AK2G) + qmgr->reg_pop = qmgr->reg_push; + list_add_tail(&qmgr->list, &kdev->qmgrs); dev_info(dev, "added qmgr start queue %d, num of queues %d, reg_peek %p, reg_status %p, reg_config %p, reg_region %p, reg_push %p, reg_pop %p\n", qmgr->start_queue, qmgr->num_queues, @@ -1681,10 +1743,24 @@ static int knav_queue_init_queues(struct knav_device *kdev) return 0; } +/* Match table for of_platform binding */ +static const struct of_device_id keystone_qmss_of_match[] = { + { + .compatible = "ti,keystone-navigator-qmss", + }, + { + .compatible = "ti,66ak2g-navss-qm", + .data = (void *)QMSS_66AK2G, + }, + {}, +}; +MODULE_DEVICE_TABLE(of, keystone_qmss_of_match); + static int knav_queue_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; struct device_node *qmgrs, *queue_pools, *regions, *pdsps; + const struct of_device_id *match; struct device *dev = &pdev->dev; u32 temp[2]; int ret; @@ -1700,6 +1776,10 @@ static int knav_queue_probe(struct platform_device *pdev) return -ENOMEM; } + match = of_match_device(of_match_ptr(keystone_qmss_of_match), dev); + if (match && match->data) + kdev->version = QMSS_66AK2G; + platform_set_drvdata(pdev, kdev); kdev->dev = dev; INIT_LIST_HEAD(&kdev->queue_ranges); @@ -1796,6 +1876,7 @@ static int knav_queue_probe(struct platform_device *pdev) debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL, &knav_queue_debug_ops); + device_ready = true; return 0; err: @@ -1815,13 +1896,6 @@ static int knav_queue_remove(struct platform_device *pdev) return 0; } -/* Match table for of_platform binding */ -static struct of_device_id keystone_qmss_of_match[] = { - { .compatible = "ti,keystone-navigator-qmss", }, - {}, -}; -MODULE_DEVICE_TABLE(of, keystone_qmss_of_match); - static struct platform_driver keystone_qmss_driver = { .probe = knav_queue_probe, .remove = knav_queue_remove, |