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

gpu: host1x: Syncpoint interrupt sharding

Support sharded syncpoint interrupts on Tegra234+. This feature
allows specifying one of eight interrupt lines for each syncpoint
to lower processing latency of syncpoint threshold
interrupts.

Signed-off-by: Mikko Perttunen <mperttunen@nvidia.com>
Signed-off-by: Thierry Reding <treding@nvidia.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230901114008.672433-1-cyndis@kapsi.fi

authored by

Mikko Perttunen and committed by
Thierry Reding
f017f1e9 b7c00cdf

+61 -17
+25 -4
drivers/gpu/host1x/dev.c
··· 488 488 static int host1x_probe(struct platform_device *pdev) 489 489 { 490 490 struct host1x *host; 491 - int err; 491 + int err, i; 492 492 493 493 host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL); 494 494 if (!host) ··· 516 516 return PTR_ERR(host->regs); 517 517 } 518 518 519 - host->syncpt_irq = platform_get_irq(pdev, 0); 520 - if (host->syncpt_irq < 0) 521 - return host->syncpt_irq; 519 + for (i = 0; i < ARRAY_SIZE(host->syncpt_irqs); i++) { 520 + char irq_name[] = "syncptX"; 521 + 522 + sprintf(irq_name, "syncpt%d", i); 523 + 524 + err = platform_get_irq_byname_optional(pdev, irq_name); 525 + if (err == -ENXIO) 526 + break; 527 + if (err < 0) 528 + return err; 529 + 530 + host->syncpt_irqs[i] = err; 531 + } 532 + 533 + host->num_syncpt_irqs = i; 534 + 535 + /* Device tree without irq names */ 536 + if (i == 0) { 537 + host->syncpt_irqs[0] = platform_get_irq(pdev, 0); 538 + if (host->syncpt_irqs[0] < 0) 539 + return host->syncpt_irqs[0]; 540 + 541 + host->num_syncpt_irqs = 1; 542 + } 522 543 523 544 mutex_init(&host->devices_lock); 524 545 INIT_LIST_HEAD(&host->devices);
+2 -1
drivers/gpu/host1x/dev.h
··· 124 124 void __iomem *regs; 125 125 void __iomem *hv_regs; /* hypervisor region */ 126 126 void __iomem *common_regs; 127 - int syncpt_irq; 127 + int syncpt_irqs[8]; 128 + int num_syncpt_irqs; 128 129 struct host1x_syncpt *syncpt; 129 130 struct host1x_syncpt_base *bases; 130 131 struct device *dev;
+34 -12
drivers/gpu/host1x/hw/intr_hw.c
··· 13 13 #include "../intr.h" 14 14 #include "../dev.h" 15 15 16 + struct host1x_intr_irq_data { 17 + struct host1x *host; 18 + u32 offset; 19 + }; 20 + 16 21 static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) 17 22 { 18 - struct host1x *host = dev_id; 23 + struct host1x_intr_irq_data *irq_data = dev_id; 24 + struct host1x *host = irq_data->host; 19 25 unsigned long reg; 20 26 unsigned int i, id; 21 27 22 - for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) { 28 + for (i = irq_data->offset; i < DIV_ROUND_UP(host->info->nb_pts, 32); 29 + i += host->num_syncpt_irqs) { 23 30 reg = host1x_sync_readl(host, 24 31 HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i)); 25 32 ··· 74 67 75 68 /* 76 69 * Program threshold interrupt destination among 8 lines per VM, 77 - * per syncpoint. For now, just direct all to the first interrupt 78 - * line. 70 + * per syncpoint. For each group of 32 syncpoints (corresponding to one 71 + * interrupt status register), direct to one interrupt line, going 72 + * around in a round robin fashion. 79 73 */ 80 - for (id = 0; id < host->info->nb_pts; id++) 81 - host1x_sync_writel(host, 0, HOST1X_SYNC_SYNCPT_INTR_DEST(id)); 74 + for (id = 0; id < host->info->nb_pts; id++) { 75 + u32 reg_offset = id / 32; 76 + u32 irq_index = reg_offset % host->num_syncpt_irqs; 77 + 78 + host1x_sync_writel(host, irq_index, HOST1X_SYNC_SYNCPT_INTR_DEST(id)); 79 + } 82 80 #endif 83 81 } 84 82 85 83 static int 86 84 host1x_intr_init_host_sync(struct host1x *host, u32 cpm) 87 85 { 88 - int err; 86 + int err, i; 87 + struct host1x_intr_irq_data *irq_data; 88 + 89 + irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL); 90 + if (!irq_data) 91 + return -ENOMEM; 89 92 90 93 host1x_hw_intr_disable_all_syncpt_intrs(host); 91 94 92 - err = devm_request_irq(host->dev, host->syncpt_irq, 93 - syncpt_thresh_isr, IRQF_SHARED, 94 - "host1x_syncpt", host); 95 - if (err < 0) 96 - return err; 95 + for (i = 0; i < host->num_syncpt_irqs; i++) { 96 + irq_data[i].host = host; 97 + irq_data[i].offset = i; 98 + 99 + err = devm_request_irq(host->dev, host->syncpt_irqs[i], 100 + syncpt_thresh_isr, IRQF_SHARED, 101 + "host1x_syncpt", &irq_data[i]); 102 + if (err < 0) 103 + return err; 104 + } 97 105 98 106 intr_hw_init(host, cpm); 99 107