summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2016-01-14 07:56:07 +1000
committerDave Airlie <airlied@redhat.com>2016-01-14 07:56:07 +1000
commit6cfd7775840cad7877b2b43e750105fa0933656b (patch)
treee3803123f725814e2b3f5c9ce9d61a21a7a1f324 /drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
parent8a0d560f3e651808ae0a3d9ab9fe476e59de132b (diff)
parentd8e0cae645504a787b05abfb91afee8cd7fa1701 (diff)
Merge branch 'drm-next-4.5' of git://people.freedesktop.org/~agd5f/linux into drm-next
A few more misc things for radeon and amdgpu for 4.5: - TTM fixes for imported buffers - amdgpu fixes to avoid -ENOMEM in CS ioctl - CZ UVD and VCE clock force options for debugging video issues - A couple of ACP prerequisites - Misc fixes * 'drm-next-4.5' of git://people.freedesktop.org/~agd5f/linux: drm/amdgpu: validate duplicates first drm/amdgpu: move VM page tables to the LRU end on CS v2 drm/ttm: add ttm_bo_move_to_lru_tail function v2 drm/ttm: fix adding foreign BOs to the swap LRU drm/ttm: fix adding foreign BOs to the LRU during init v2 drm/radeon: use kobj_to_dev() drm/amdgpu: use kobj_to_dev() drm/amdgpu/cz: force vce clocks when sclks are forced drm/amdgpu/cz: force uvd clocks when sclks are forced drm/amdgpu/cz: add code to enable forcing VCE clocks drm/amdgpu/cz: add code to enable forcing UVD clocks drm/amdgpu: fix lost sync_to if scheduler is enabled. drm/amd/powerplay: fix static checker warning for return meaningless value. drm/amdgpu: add irq domain support drm/amdgpu/cgs: add an interface to access PCI resources
Diffstat (limited to 'drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c108
1 files changed, 100 insertions, 8 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index 7c42ff670080..3006182c5d0d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -312,6 +312,7 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
}
adev->irq.sources[src_id] = source;
+
return 0;
}
@@ -335,15 +336,19 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
return;
}
- src = adev->irq.sources[src_id];
- if (!src) {
- DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
- return;
- }
+ if (adev->irq.virq[src_id]) {
+ generic_handle_irq(irq_find_mapping(adev->irq.domain, src_id));
+ } else {
+ src = adev->irq.sources[src_id];
+ if (!src) {
+ DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
+ return;
+ }
- r = src->funcs->process(adev, src, entry);
- if (r)
- DRM_ERROR("error processing interrupt (%d)\n", r);
+ r = src->funcs->process(adev, src, entry);
+ if (r)
+ DRM_ERROR("error processing interrupt (%d)\n", r);
+ }
}
/**
@@ -461,3 +466,90 @@ bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
return !!atomic_read(&src->enabled_types[type]);
}
+
+/* gen irq */
+static void amdgpu_irq_mask(struct irq_data *irqd)
+{
+ /* XXX */
+}
+
+static void amdgpu_irq_unmask(struct irq_data *irqd)
+{
+ /* XXX */
+}
+
+static struct irq_chip amdgpu_irq_chip = {
+ .name = "amdgpu-ih",
+ .irq_mask = amdgpu_irq_mask,
+ .irq_unmask = amdgpu_irq_unmask,
+};
+
+static int amdgpu_irqdomain_map(struct irq_domain *d,
+ unsigned int irq, irq_hw_number_t hwirq)
+{
+ if (hwirq >= AMDGPU_MAX_IRQ_SRC_ID)
+ return -EPERM;
+
+ irq_set_chip_and_handler(irq,
+ &amdgpu_irq_chip, handle_simple_irq);
+ return 0;
+}
+
+static struct irq_domain_ops amdgpu_hw_irqdomain_ops = {
+ .map = amdgpu_irqdomain_map,
+};
+
+/**
+ * amdgpu_irq_add_domain - create a linear irq domain
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Create an irq domain for GPU interrupt sources
+ * that may be driven by another driver (e.g., ACP).
+ */
+int amdgpu_irq_add_domain(struct amdgpu_device *adev)
+{
+ adev->irq.domain = irq_domain_add_linear(NULL, AMDGPU_MAX_IRQ_SRC_ID,
+ &amdgpu_hw_irqdomain_ops, adev);
+ if (!adev->irq.domain) {
+ DRM_ERROR("GPU irq add domain failed\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_irq_remove_domain - remove the irq domain
+ *
+ * @adev: amdgpu device pointer
+ *
+ * Remove the irq domain for GPU interrupt sources
+ * that may be driven by another driver (e.g., ACP).
+ */
+void amdgpu_irq_remove_domain(struct amdgpu_device *adev)
+{
+ if (adev->irq.domain) {
+ irq_domain_remove(adev->irq.domain);
+ adev->irq.domain = NULL;
+ }
+}
+
+/**
+ * amdgpu_irq_create_mapping - create a mapping between a domain irq and a
+ * Linux irq
+ *
+ * @adev: amdgpu device pointer
+ * @src_id: IH source id
+ *
+ * Create a mapping between a domain irq (GPU IH src id) and a Linux irq
+ * Use this for components that generate a GPU interrupt, but are driven
+ * by a different driver (e.g., ACP).
+ * Returns the Linux irq.
+ */
+unsigned amdgpu_irq_create_mapping(struct amdgpu_device *adev, unsigned src_id)
+{
+ adev->irq.virq[src_id] = irq_create_mapping(adev->irq.domain, src_id);
+
+ return adev->irq.virq[src_id];
+}