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
This commit is contained in:
parent
b7c00cdf6d
commit
f017f1e9cb
|
@ -488,7 +488,7 @@ static int host1x_get_resets(struct host1x *host)
|
||||||
static int host1x_probe(struct platform_device *pdev)
|
static int host1x_probe(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
struct host1x *host;
|
struct host1x *host;
|
||||||
int err;
|
int err, i;
|
||||||
|
|
||||||
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
|
host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
|
||||||
if (!host)
|
if (!host)
|
||||||
|
@ -516,9 +516,30 @@ static int host1x_probe(struct platform_device *pdev)
|
||||||
return PTR_ERR(host->regs);
|
return PTR_ERR(host->regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
host->syncpt_irq = platform_get_irq(pdev, 0);
|
for (i = 0; i < ARRAY_SIZE(host->syncpt_irqs); i++) {
|
||||||
if (host->syncpt_irq < 0)
|
char irq_name[] = "syncptX";
|
||||||
return host->syncpt_irq;
|
|
||||||
|
sprintf(irq_name, "syncpt%d", i);
|
||||||
|
|
||||||
|
err = platform_get_irq_byname_optional(pdev, irq_name);
|
||||||
|
if (err == -ENXIO)
|
||||||
|
break;
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
host->syncpt_irqs[i] = err;
|
||||||
|
}
|
||||||
|
|
||||||
|
host->num_syncpt_irqs = i;
|
||||||
|
|
||||||
|
/* Device tree without irq names */
|
||||||
|
if (i == 0) {
|
||||||
|
host->syncpt_irqs[0] = platform_get_irq(pdev, 0);
|
||||||
|
if (host->syncpt_irqs[0] < 0)
|
||||||
|
return host->syncpt_irqs[0];
|
||||||
|
|
||||||
|
host->num_syncpt_irqs = 1;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_init(&host->devices_lock);
|
mutex_init(&host->devices_lock);
|
||||||
INIT_LIST_HEAD(&host->devices);
|
INIT_LIST_HEAD(&host->devices);
|
||||||
|
|
|
@ -124,7 +124,8 @@ struct host1x {
|
||||||
void __iomem *regs;
|
void __iomem *regs;
|
||||||
void __iomem *hv_regs; /* hypervisor region */
|
void __iomem *hv_regs; /* hypervisor region */
|
||||||
void __iomem *common_regs;
|
void __iomem *common_regs;
|
||||||
int syncpt_irq;
|
int syncpt_irqs[8];
|
||||||
|
int num_syncpt_irqs;
|
||||||
struct host1x_syncpt *syncpt;
|
struct host1x_syncpt *syncpt;
|
||||||
struct host1x_syncpt_base *bases;
|
struct host1x_syncpt_base *bases;
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
|
@ -13,13 +13,20 @@
|
||||||
#include "../intr.h"
|
#include "../intr.h"
|
||||||
#include "../dev.h"
|
#include "../dev.h"
|
||||||
|
|
||||||
|
struct host1x_intr_irq_data {
|
||||||
|
struct host1x *host;
|
||||||
|
u32 offset;
|
||||||
|
};
|
||||||
|
|
||||||
static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
|
static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id)
|
||||||
{
|
{
|
||||||
struct host1x *host = dev_id;
|
struct host1x_intr_irq_data *irq_data = dev_id;
|
||||||
|
struct host1x *host = irq_data->host;
|
||||||
unsigned long reg;
|
unsigned long reg;
|
||||||
unsigned int i, id;
|
unsigned int i, id;
|
||||||
|
|
||||||
for (i = 0; i < DIV_ROUND_UP(host->info->nb_pts, 32); i++) {
|
for (i = irq_data->offset; i < DIV_ROUND_UP(host->info->nb_pts, 32);
|
||||||
|
i += host->num_syncpt_irqs) {
|
||||||
reg = host1x_sync_readl(host,
|
reg = host1x_sync_readl(host,
|
||||||
HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
|
HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(i));
|
||||||
|
|
||||||
|
@ -67,26 +74,41 @@ static void intr_hw_init(struct host1x *host, u32 cpm)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Program threshold interrupt destination among 8 lines per VM,
|
* Program threshold interrupt destination among 8 lines per VM,
|
||||||
* per syncpoint. For now, just direct all to the first interrupt
|
* per syncpoint. For each group of 32 syncpoints (corresponding to one
|
||||||
* line.
|
* interrupt status register), direct to one interrupt line, going
|
||||||
|
* around in a round robin fashion.
|
||||||
*/
|
*/
|
||||||
for (id = 0; id < host->info->nb_pts; id++)
|
for (id = 0; id < host->info->nb_pts; id++) {
|
||||||
host1x_sync_writel(host, 0, HOST1X_SYNC_SYNCPT_INTR_DEST(id));
|
u32 reg_offset = id / 32;
|
||||||
|
u32 irq_index = reg_offset % host->num_syncpt_irqs;
|
||||||
|
|
||||||
|
host1x_sync_writel(host, irq_index, HOST1X_SYNC_SYNCPT_INTR_DEST(id));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
host1x_intr_init_host_sync(struct host1x *host, u32 cpm)
|
host1x_intr_init_host_sync(struct host1x *host, u32 cpm)
|
||||||
{
|
{
|
||||||
int err;
|
int err, i;
|
||||||
|
struct host1x_intr_irq_data *irq_data;
|
||||||
|
|
||||||
|
irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL);
|
||||||
|
if (!irq_data)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
host1x_hw_intr_disable_all_syncpt_intrs(host);
|
host1x_hw_intr_disable_all_syncpt_intrs(host);
|
||||||
|
|
||||||
err = devm_request_irq(host->dev, host->syncpt_irq,
|
for (i = 0; i < host->num_syncpt_irqs; i++) {
|
||||||
syncpt_thresh_isr, IRQF_SHARED,
|
irq_data[i].host = host;
|
||||||
"host1x_syncpt", host);
|
irq_data[i].offset = i;
|
||||||
if (err < 0)
|
|
||||||
return err;
|
err = devm_request_irq(host->dev, host->syncpt_irqs[i],
|
||||||
|
syncpt_thresh_isr, IRQF_SHARED,
|
||||||
|
"host1x_syncpt", &irq_data[i]);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
intr_hw_init(host, cpm);
|
intr_hw_init(host, cpm);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue