2 * Copyright 2008 Advanced Micro Devices, Inc.
3 * Copyright 2008 Red Hat Inc.
4 * Copyright 2009 Jerome Glisse.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
24 * Authors: Dave Airlie
28 #include <linux/irq.h>
30 #include <drm/drm_crtc_helper.h>
31 #include <drm/amdgpu_drm.h>
33 #include "amdgpu_ih.h"
35 #include "amdgpu_connectors.h"
37 #include <linux/pm_runtime.h>
39 #define AMDGPU_WAIT_IDLE_TIMEOUT 200
42 * Handle hotplug events outside the interrupt handler proper.
45 * amdgpu_hotplug_work_func - display hotplug work handler
49 * This is the hot plug event work handler (all asics).
50 * The work gets scheduled from the irq handler if there
51 * was a hot plug interrupt. It walks the connector table
52 * and calls the hotplug handler for each one, then sends
53 * a drm hotplug event to alert userspace.
55 static void amdgpu_hotplug_work_func(struct work_struct
*work
)
57 struct amdgpu_device
*adev
= container_of(work
, struct amdgpu_device
,
59 struct drm_device
*dev
= adev
->ddev
;
60 struct drm_mode_config
*mode_config
= &dev
->mode_config
;
61 struct drm_connector
*connector
;
63 mutex_lock(&mode_config
->mutex
);
64 if (mode_config
->num_connector
) {
65 list_for_each_entry(connector
, &mode_config
->connector_list
, head
)
66 amdgpu_connector_hotplug(connector
);
68 mutex_unlock(&mode_config
->mutex
);
69 /* Just fire off a uevent and let userspace tell us what to do */
70 drm_helper_hpd_irq_event(dev
);
74 * amdgpu_irq_reset_work_func - execute gpu reset
78 * Execute scheduled gpu reset (cayman+).
79 * This function is called when the irq handler
80 * thinks we need a gpu reset.
82 static void amdgpu_irq_reset_work_func(struct work_struct
*work
)
84 struct amdgpu_device
*adev
= container_of(work
, struct amdgpu_device
,
87 amdgpu_gpu_reset(adev
);
90 /* Disable *all* interrupts */
91 static void amdgpu_irq_disable_all(struct amdgpu_device
*adev
)
93 unsigned long irqflags
;
97 spin_lock_irqsave(&adev
->irq
.lock
, irqflags
);
98 for (i
= 0; i
< AMDGPU_MAX_IRQ_SRC_ID
; ++i
) {
99 struct amdgpu_irq_src
*src
= adev
->irq
.sources
[i
];
101 if (!src
|| !src
->funcs
->set
|| !src
->num_types
)
104 for (j
= 0; j
< src
->num_types
; ++j
) {
105 atomic_set(&src
->enabled_types
[j
], 0);
106 r
= src
->funcs
->set(adev
, src
, j
,
107 AMDGPU_IRQ_STATE_DISABLE
);
109 DRM_ERROR("error disabling interrupt (%d)\n",
113 spin_unlock_irqrestore(&adev
->irq
.lock
, irqflags
);
117 * amdgpu_irq_preinstall - drm irq preinstall callback
119 * @dev: drm dev pointer
121 * Gets the hw ready to enable irqs (all asics).
122 * This function disables all interrupt sources on the GPU.
124 void amdgpu_irq_preinstall(struct drm_device
*dev
)
126 struct amdgpu_device
*adev
= dev
->dev_private
;
128 /* Disable *all* interrupts */
129 amdgpu_irq_disable_all(adev
);
131 amdgpu_ih_process(adev
);
135 * amdgpu_irq_postinstall - drm irq preinstall callback
137 * @dev: drm dev pointer
139 * Handles stuff to be done after enabling irqs (all asics).
140 * Returns 0 on success.
142 int amdgpu_irq_postinstall(struct drm_device
*dev
)
144 dev
->max_vblank_count
= 0x00ffffff;
149 * amdgpu_irq_uninstall - drm irq uninstall callback
151 * @dev: drm dev pointer
153 * This function disables all interrupt sources on the GPU (all asics).
155 void amdgpu_irq_uninstall(struct drm_device
*dev
)
157 struct amdgpu_device
*adev
= dev
->dev_private
;
162 amdgpu_irq_disable_all(adev
);
166 * amdgpu_irq_handler - irq handler
168 * @int irq, void *arg: args
170 * This is the irq handler for the amdgpu driver (all asics).
172 irqreturn_t
amdgpu_irq_handler(int irq
, void *arg
)
174 struct drm_device
*dev
= (struct drm_device
*) arg
;
175 struct amdgpu_device
*adev
= dev
->dev_private
;
178 ret
= amdgpu_ih_process(adev
);
179 if (ret
== IRQ_HANDLED
)
180 pm_runtime_mark_last_busy(dev
->dev
);
185 * amdgpu_msi_ok - asic specific msi checks
187 * @adev: amdgpu device pointer
189 * Handles asic specific MSI checks to determine if
190 * MSIs should be enabled on a particular chip (all asics).
191 * Returns true if MSIs should be enabled, false if MSIs
192 * should not be enabled.
194 static bool amdgpu_msi_ok(struct amdgpu_device
*adev
)
199 else if (amdgpu_msi
== 0)
206 * amdgpu_irq_init - init driver interrupt info
208 * @adev: amdgpu device pointer
210 * Sets up the work irq handlers, vblank init, MSIs, etc. (all asics).
211 * Returns 0 for success, error for failure.
213 int amdgpu_irq_init(struct amdgpu_device
*adev
)
217 spin_lock_init(&adev
->irq
.lock
);
218 r
= drm_vblank_init(adev
->ddev
, adev
->mode_info
.num_crtc
);
224 adev
->irq
.msi_enabled
= false;
226 if (amdgpu_msi_ok(adev
)) {
227 int ret
= pci_enable_msi(adev
->pdev
);
229 adev
->irq
.msi_enabled
= true;
230 dev_info(adev
->dev
, "amdgpu: using MSI.\n");
234 INIT_WORK(&adev
->hotplug_work
, amdgpu_hotplug_work_func
);
235 INIT_WORK(&adev
->reset_work
, amdgpu_irq_reset_work_func
);
237 adev
->irq
.installed
= true;
238 r
= drm_irq_install(adev
->ddev
, adev
->ddev
->pdev
->irq
);
240 adev
->irq
.installed
= false;
241 flush_work(&adev
->hotplug_work
);
245 DRM_INFO("amdgpu: irq initialized.\n");
250 * amdgpu_irq_fini - tear down driver interrupt info
252 * @adev: amdgpu device pointer
254 * Tears down the work irq handlers, vblank handlers, MSIs, etc. (all asics).
256 void amdgpu_irq_fini(struct amdgpu_device
*adev
)
260 drm_vblank_cleanup(adev
->ddev
);
261 if (adev
->irq
.installed
) {
262 drm_irq_uninstall(adev
->ddev
);
263 adev
->irq
.installed
= false;
264 if (adev
->irq
.msi_enabled
)
265 pci_disable_msi(adev
->pdev
);
266 flush_work(&adev
->hotplug_work
);
269 for (i
= 0; i
< AMDGPU_MAX_IRQ_SRC_ID
; ++i
) {
270 struct amdgpu_irq_src
*src
= adev
->irq
.sources
[i
];
275 kfree(src
->enabled_types
);
276 src
->enabled_types
= NULL
;
280 adev
->irq
.sources
[i
] = NULL
;
286 * amdgpu_irq_add_id - register irq source
288 * @adev: amdgpu device pointer
289 * @src_id: source id for this source
290 * @source: irq source
293 int amdgpu_irq_add_id(struct amdgpu_device
*adev
, unsigned src_id
,
294 struct amdgpu_irq_src
*source
)
296 if (src_id
>= AMDGPU_MAX_IRQ_SRC_ID
)
299 if (adev
->irq
.sources
[src_id
] != NULL
)
305 if (source
->num_types
&& !source
->enabled_types
) {
308 types
= kcalloc(source
->num_types
, sizeof(atomic_t
),
313 source
->enabled_types
= types
;
316 adev
->irq
.sources
[src_id
] = source
;
322 * amdgpu_irq_dispatch - dispatch irq to IP blocks
324 * @adev: amdgpu device pointer
325 * @entry: interrupt vector
327 * Dispatches the irq to the different IP blocks
329 void amdgpu_irq_dispatch(struct amdgpu_device
*adev
,
330 struct amdgpu_iv_entry
*entry
)
332 unsigned src_id
= entry
->src_id
;
333 struct amdgpu_irq_src
*src
;
336 if (src_id
>= AMDGPU_MAX_IRQ_SRC_ID
) {
337 DRM_DEBUG("Invalid src_id in IV: %d\n", src_id
);
341 if (adev
->irq
.virq
[src_id
]) {
342 generic_handle_irq(irq_find_mapping(adev
->irq
.domain
, src_id
));
344 src
= adev
->irq
.sources
[src_id
];
346 DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id
);
350 r
= src
->funcs
->process(adev
, src
, entry
);
352 DRM_ERROR("error processing interrupt (%d)\n", r
);
357 * amdgpu_irq_update - update hw interrupt state
359 * @adev: amdgpu device pointer
360 * @src: interrupt src you want to enable
361 * @type: type of interrupt you want to update
363 * Updates the interrupt state for a specific src (all asics).
365 int amdgpu_irq_update(struct amdgpu_device
*adev
,
366 struct amdgpu_irq_src
*src
, unsigned type
)
368 unsigned long irqflags
;
369 enum amdgpu_interrupt_state state
;
372 spin_lock_irqsave(&adev
->irq
.lock
, irqflags
);
374 /* we need to determine after taking the lock, otherwise
375 we might disable just enabled interrupts again */
376 if (amdgpu_irq_enabled(adev
, src
, type
))
377 state
= AMDGPU_IRQ_STATE_ENABLE
;
379 state
= AMDGPU_IRQ_STATE_DISABLE
;
381 r
= src
->funcs
->set(adev
, src
, type
, state
);
382 spin_unlock_irqrestore(&adev
->irq
.lock
, irqflags
);
386 void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device
*adev
)
389 for (i
= 0; i
< AMDGPU_MAX_IRQ_SRC_ID
; i
++) {
390 struct amdgpu_irq_src
*src
= adev
->irq
.sources
[i
];
393 for (j
= 0; j
< src
->num_types
; j
++)
394 amdgpu_irq_update(adev
, src
, j
);
399 * amdgpu_irq_get - enable interrupt
401 * @adev: amdgpu device pointer
402 * @src: interrupt src you want to enable
403 * @type: type of interrupt you want to enable
405 * Enables the interrupt type for a specific src (all asics).
407 int amdgpu_irq_get(struct amdgpu_device
*adev
, struct amdgpu_irq_src
*src
,
410 if (!adev
->ddev
->irq_enabled
)
413 if (type
>= src
->num_types
)
416 if (!src
->enabled_types
|| !src
->funcs
->set
)
419 if (atomic_inc_return(&src
->enabled_types
[type
]) == 1)
420 return amdgpu_irq_update(adev
, src
, type
);
425 bool amdgpu_irq_get_delayed(struct amdgpu_device
*adev
,
426 struct amdgpu_irq_src
*src
,
429 if ((type
>= src
->num_types
) || !src
->enabled_types
)
431 return atomic_inc_return(&src
->enabled_types
[type
]) == 1;
435 * amdgpu_irq_put - disable interrupt
437 * @adev: amdgpu device pointer
438 * @src: interrupt src you want to disable
439 * @type: type of interrupt you want to disable
441 * Disables the interrupt type for a specific src (all asics).
443 int amdgpu_irq_put(struct amdgpu_device
*adev
, struct amdgpu_irq_src
*src
,
446 if (!adev
->ddev
->irq_enabled
)
449 if (type
>= src
->num_types
)
452 if (!src
->enabled_types
|| !src
->funcs
->set
)
455 if (atomic_dec_and_test(&src
->enabled_types
[type
]))
456 return amdgpu_irq_update(adev
, src
, type
);
462 * amdgpu_irq_enabled - test if irq is enabled or not
464 * @adev: amdgpu device pointer
465 * @idx: interrupt src you want to test
467 * Tests if the given interrupt source is enabled or not
469 bool amdgpu_irq_enabled(struct amdgpu_device
*adev
, struct amdgpu_irq_src
*src
,
472 if (!adev
->ddev
->irq_enabled
)
475 if (type
>= src
->num_types
)
478 if (!src
->enabled_types
|| !src
->funcs
->set
)
481 return !!atomic_read(&src
->enabled_types
[type
]);
485 static void amdgpu_irq_mask(struct irq_data
*irqd
)
490 static void amdgpu_irq_unmask(struct irq_data
*irqd
)
495 static struct irq_chip amdgpu_irq_chip
= {
497 .irq_mask
= amdgpu_irq_mask
,
498 .irq_unmask
= amdgpu_irq_unmask
,
501 static int amdgpu_irqdomain_map(struct irq_domain
*d
,
502 unsigned int irq
, irq_hw_number_t hwirq
)
504 if (hwirq
>= AMDGPU_MAX_IRQ_SRC_ID
)
507 irq_set_chip_and_handler(irq
,
508 &amdgpu_irq_chip
, handle_simple_irq
);
512 static const struct irq_domain_ops amdgpu_hw_irqdomain_ops
= {
513 .map
= amdgpu_irqdomain_map
,
517 * amdgpu_irq_add_domain - create a linear irq domain
519 * @adev: amdgpu device pointer
521 * Create an irq domain for GPU interrupt sources
522 * that may be driven by another driver (e.g., ACP).
524 int amdgpu_irq_add_domain(struct amdgpu_device
*adev
)
526 adev
->irq
.domain
= irq_domain_add_linear(NULL
, AMDGPU_MAX_IRQ_SRC_ID
,
527 &amdgpu_hw_irqdomain_ops
, adev
);
528 if (!adev
->irq
.domain
) {
529 DRM_ERROR("GPU irq add domain failed\n");
537 * amdgpu_irq_remove_domain - remove the irq domain
539 * @adev: amdgpu device pointer
541 * Remove the irq domain for GPU interrupt sources
542 * that may be driven by another driver (e.g., ACP).
544 void amdgpu_irq_remove_domain(struct amdgpu_device
*adev
)
546 if (adev
->irq
.domain
) {
547 irq_domain_remove(adev
->irq
.domain
);
548 adev
->irq
.domain
= NULL
;
553 * amdgpu_irq_create_mapping - create a mapping between a domain irq and a
556 * @adev: amdgpu device pointer
557 * @src_id: IH source id
559 * Create a mapping between a domain irq (GPU IH src id) and a Linux irq
560 * Use this for components that generate a GPU interrupt, but are driven
561 * by a different driver (e.g., ACP).
562 * Returns the Linux irq.
564 unsigned amdgpu_irq_create_mapping(struct amdgpu_device
*adev
, unsigned src_id
)
566 adev
->irq
.virq
[src_id
] = irq_create_mapping(adev
->irq
.domain
, src_id
);
568 return adev
->irq
.virq
[src_id
];