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

gpu: host1x: Request syncpoint IRQs only during probe

Syncpoint IRQs are currently requested in a code path that runs
during resume. Due to this, we get multiple overlapping registered
interrupt handlers as host1x is suspended and resumed.

Rearrange interrupt code to only request IRQs during initialization.

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

authored by

Mikko Perttunen and committed by
Thierry Reding
4c27ac45 bad928d2

+30 -35
+2
drivers/gpu/host1x/dev.h
··· 9 9 #include <linux/device.h> 10 10 #include <linux/iommu.h> 11 11 #include <linux/iova.h> 12 + #include <linux/irqreturn.h> 12 13 #include <linux/platform_device.h> 13 14 #include <linux/reset.h> 14 15 ··· 82 81 void (*disable_syncpt_intr)(struct host1x *host, unsigned int id); 83 82 void (*disable_all_syncpt_intrs)(struct host1x *host); 84 83 int (*free_syncpt_irq)(struct host1x *host); 84 + irqreturn_t (*isr)(int irq, void *dev_id); 85 85 }; 86 86 87 87 struct host1x_sid_entry {
+3 -34
drivers/gpu/host1x/hw/intr_hw.c
··· 6 6 * Copyright (c) 2010-2013, NVIDIA Corporation. 7 7 */ 8 8 9 - #include <linux/interrupt.h> 10 - #include <linux/irq.h> 11 9 #include <linux/io.h> 12 10 13 11 #include "../intr.h" 14 12 #include "../dev.h" 15 - 16 - struct host1x_intr_irq_data { 17 - struct host1x *host; 18 - u32 offset; 19 - }; 20 13 21 14 static irqreturn_t syncpt_thresh_isr(int irq, void *dev_id) 22 15 { ··· 47 54 } 48 55 } 49 56 50 - static void intr_hw_init(struct host1x *host, u32 cpm) 57 + static int 58 + host1x_intr_init_host_sync(struct host1x *host, u32 cpm) 51 59 { 52 60 #if HOST1X_HW < 6 53 61 /* disable the ip_busy_timeout. this prevents write drops */ ··· 79 85 host1x_sync_writel(host, irq_index, HOST1X_SYNC_SYNCPT_INTR_DEST(id)); 80 86 } 81 87 #endif 82 - } 83 - 84 - static int 85 - host1x_intr_init_host_sync(struct host1x *host, u32 cpm) 86 - { 87 - int err, i; 88 - struct host1x_intr_irq_data *irq_data; 89 - 90 - irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL); 91 - if (!irq_data) 92 - return -ENOMEM; 93 - 94 - host1x_hw_intr_disable_all_syncpt_intrs(host); 95 - 96 - for (i = 0; i < host->num_syncpt_irqs; i++) { 97 - irq_data[i].host = host; 98 - irq_data[i].offset = i; 99 - 100 - err = devm_request_irq(host->dev, host->syncpt_irqs[i], 101 - syncpt_thresh_isr, IRQF_SHARED, 102 - "host1x_syncpt", &irq_data[i]); 103 - if (err < 0) 104 - return err; 105 - } 106 - 107 - intr_hw_init(host, cpm); 108 88 109 89 return 0; 110 90 } ··· 112 144 .enable_syncpt_intr = host1x_intr_enable_syncpt_intr, 113 145 .disable_syncpt_intr = host1x_intr_disable_syncpt_intr, 114 146 .disable_all_syncpt_intrs = host1x_intr_disable_all_syncpt_intrs, 147 + .isr = syncpt_thresh_isr, 115 148 };
+20 -1
drivers/gpu/host1x/intr.c
··· 6 6 */ 7 7 8 8 #include <linux/clk.h> 9 - 9 + #include <linux/interrupt.h> 10 10 #include "dev.h" 11 11 #include "fence.h" 12 12 #include "intr.h" ··· 100 100 101 101 int host1x_intr_init(struct host1x *host) 102 102 { 103 + struct host1x_intr_irq_data *irq_data; 103 104 unsigned int id; 105 + int i, err; 104 106 105 107 mutex_init(&host->intr_mutex); 106 108 ··· 111 109 112 110 spin_lock_init(&syncpt->fences.lock); 113 111 INIT_LIST_HEAD(&syncpt->fences.list); 112 + } 113 + 114 + irq_data = devm_kcalloc(host->dev, host->num_syncpt_irqs, sizeof(irq_data[0]), GFP_KERNEL); 115 + if (!irq_data) 116 + return -ENOMEM; 117 + 118 + host1x_hw_intr_disable_all_syncpt_intrs(host); 119 + 120 + for (i = 0; i < host->num_syncpt_irqs; i++) { 121 + irq_data[i].host = host; 122 + irq_data[i].offset = i; 123 + 124 + err = devm_request_irq(host->dev, host->syncpt_irqs[i], 125 + host->intr_op->isr, IRQF_SHARED, 126 + "host1x_syncpt", &irq_data[i]); 127 + if (err < 0) 128 + return err; 114 129 } 115 130 116 131 return 0;
+5
drivers/gpu/host1x/intr.h
··· 11 11 struct host1x; 12 12 struct host1x_syncpt_fence; 13 13 14 + struct host1x_intr_irq_data { 15 + struct host1x *host; 16 + u32 offset; 17 + }; 18 + 14 19 /* Initialize host1x sync point interrupt */ 15 20 int host1x_intr_init(struct host1x *host); 16 21