Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

soc: ti: knav_qmss: Use percpu instead atomic for stats counter

Hwqueue has collect statistics in heavy use queue_pop/queu_push functions
for cache efficiency and make push/pop faster use percpu variables.
For performance reasons, driver should keep descriptor in software handler
as short as possible and quickly return it back to hardware queue.
Descriptors coming into driver from hardware after pop and return back
by push to reduce descriptor lifetime in driver collect statistics on percpu.

Signed-off-by: Vasyl Gomonovych <gomonovych@gmail.com>
Signed-off-by: Santosh Shilimkar <santosh.shilimkar@oracle.com>

authored by

Vasyl Gomonovych and committed by
Santosh Shilimkar
bc3acbb8 8af70cd2

+48 -26
+8 -6
drivers/soc/ti/knav_qmss.h
··· 19 19 #ifndef __KNAV_QMSS_H__ 20 20 #define __KNAV_QMSS_H__ 21 21 22 + #include <linux/percpu.h> 23 + 22 24 #define THRESH_GTE BIT(7) 23 25 #define THRESH_LT 0 24 26 ··· 164 162 * notifies: notifier counts 165 163 */ 166 164 struct knav_queue_stats { 167 - atomic_t pushes; 168 - atomic_t pops; 169 - atomic_t push_errors; 170 - atomic_t pop_errors; 171 - atomic_t notifies; 165 + unsigned int pushes; 166 + unsigned int pops; 167 + unsigned int push_errors; 168 + unsigned int pop_errors; 169 + unsigned int notifies; 172 170 }; 173 171 174 172 /** ··· 285 283 struct knav_queue { 286 284 struct knav_reg_queue __iomem *reg_push, *reg_pop, *reg_peek; 287 285 struct knav_queue_inst *inst; 288 - struct knav_queue_stats stats; 286 + struct knav_queue_stats __percpu *stats; 289 287 knav_queue_notify_fn notifier_fn; 290 288 void *notifier_fn_arg; 291 289 atomic_t notifier_enabled;
+40 -20
drivers/soc/ti/knav_qmss_queue.c
··· 83 83 continue; 84 84 if (WARN_ON(!qh->notifier_fn)) 85 85 continue; 86 - atomic_inc(&qh->stats.notifies); 86 + this_cpu_inc(qh->stats->notifies); 87 87 qh->notifier_fn(qh->notifier_fn_arg); 88 88 } 89 89 rcu_read_unlock(); ··· 214 214 if (!qh) 215 215 return ERR_PTR(-ENOMEM); 216 216 217 + qh->stats = alloc_percpu(struct knav_queue_stats); 218 + if (!qh->stats) { 219 + ret = -ENOMEM; 220 + goto err; 221 + } 222 + 217 223 qh->flags = flags; 218 224 qh->inst = inst; 219 225 id = inst->id - inst->qmgr->start_queue; ··· 235 229 if (range->ops && range->ops->open_queue) 236 230 ret = range->ops->open_queue(range, inst, flags); 237 231 238 - if (ret) { 239 - devm_kfree(inst->kdev->dev, qh); 240 - return ERR_PTR(ret); 241 - } 232 + if (ret) 233 + goto err; 242 234 } 243 235 list_add_tail_rcu(&qh->list, &inst->handles); 244 236 return qh; 237 + 238 + err: 239 + if (qh->stats) 240 + free_percpu(qh->stats); 241 + devm_kfree(inst->kdev->dev, qh); 242 + return ERR_PTR(ret); 245 243 } 246 244 247 245 static struct knav_queue * ··· 421 411 { 422 412 struct knav_device *kdev = inst->kdev; 423 413 struct knav_queue *qh; 414 + int cpu = 0; 415 + int pushes = 0; 416 + int pops = 0; 417 + int push_errors = 0; 418 + int pop_errors = 0; 419 + int notifies = 0; 424 420 425 421 if (!knav_queue_is_busy(inst)) 426 422 return; ··· 434 418 seq_printf(s, "\tqueue id %d (%s)\n", 435 419 kdev->base_id + inst->id, inst->name); 436 420 for_each_handle_rcu(qh, inst) { 437 - seq_printf(s, "\t\thandle %p: ", qh); 438 - seq_printf(s, "pushes %8d, ", 439 - atomic_read(&qh->stats.pushes)); 440 - seq_printf(s, "pops %8d, ", 441 - atomic_read(&qh->stats.pops)); 442 - seq_printf(s, "count %8d, ", 443 - knav_queue_get_count(qh)); 444 - seq_printf(s, "notifies %8d, ", 445 - atomic_read(&qh->stats.notifies)); 446 - seq_printf(s, "push errors %8d, ", 447 - atomic_read(&qh->stats.push_errors)); 448 - seq_printf(s, "pop errors %8d\n", 449 - atomic_read(&qh->stats.pop_errors)); 421 + for_each_possible_cpu(cpu) { 422 + pushes += per_cpu_ptr(qh->stats, cpu)->pushes; 423 + pops += per_cpu_ptr(qh->stats, cpu)->pops; 424 + push_errors += per_cpu_ptr(qh->stats, cpu)->push_errors; 425 + pop_errors += per_cpu_ptr(qh->stats, cpu)->pop_errors; 426 + notifies += per_cpu_ptr(qh->stats, cpu)->notifies; 427 + } 428 + 429 + seq_printf(s, "\t\thandle %p: pushes %8d, pops %8d, count %8d, notifies %8d, push errors %8d, pop errors %8d\n", 430 + qh, 431 + pushes, 432 + pops, 433 + knav_queue_get_count(qh), 434 + notifies, 435 + push_errors, 436 + pop_errors); 450 437 } 451 438 } 452 439 ··· 566 547 if (range->ops && range->ops->close_queue) 567 548 range->ops->close_queue(range, inst); 568 549 } 550 + free_percpu(qh->stats); 569 551 devm_kfree(inst->kdev->dev, qh); 570 552 } 571 553 EXPORT_SYMBOL_GPL(knav_queue_close); ··· 640 620 val = (u32)dma | ((size / 16) - 1); 641 621 writel_relaxed(val, &qh->reg_push[0].ptr_size_thresh); 642 622 643 - atomic_inc(&qh->stats.pushes); 623 + this_cpu_inc(qh->stats->pushes); 644 624 return 0; 645 625 } 646 626 EXPORT_SYMBOL_GPL(knav_queue_push); ··· 678 658 if (size) 679 659 *size = ((val & DESC_SIZE_MASK) + 1) * 16; 680 660 681 - atomic_inc(&qh->stats.pops); 661 + this_cpu_inc(qh->stats->pops); 682 662 return dma; 683 663 } 684 664 EXPORT_SYMBOL_GPL(knav_queue_pop);