Home | History | Annotate | Line # | Download | only in amdgpu
amdgpu_irq.c revision 1.1
      1 /*	$NetBSD: amdgpu_irq.c,v 1.1 2018/08/27 01:34:44 riastradh Exp $	*/
      2 
      3 /*
      4  * Copyright 2008 Advanced Micro Devices, Inc.
      5  * Copyright 2008 Red Hat Inc.
      6  * Copyright 2009 Jerome Glisse.
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the "Software"),
     10  * to deal in the Software without restriction, including without limitation
     11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     12  * and/or sell copies of the Software, and to permit persons to whom the
     13  * Software is furnished to do so, subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice shall be included in
     16  * all copies or substantial portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     21  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     24  * OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  * Authors: Dave Airlie
     27  *          Alex Deucher
     28  *          Jerome Glisse
     29  */
     30 #include <sys/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: amdgpu_irq.c,v 1.1 2018/08/27 01:34:44 riastradh Exp $");
     32 
     33 #include <linux/irq.h>
     34 #include <drm/drmP.h>
     35 #include <drm/drm_crtc_helper.h>
     36 #include <drm/amdgpu_drm.h>
     37 #include "amdgpu.h"
     38 #include "amdgpu_ih.h"
     39 #include "atom.h"
     40 #include "amdgpu_connectors.h"
     41 
     42 #include <linux/pm_runtime.h>
     43 
     44 #define AMDGPU_WAIT_IDLE_TIMEOUT 200
     45 
     46 /*
     47  * Handle hotplug events outside the interrupt handler proper.
     48  */
     49 /**
     50  * amdgpu_hotplug_work_func - display hotplug work handler
     51  *
     52  * @work: work struct
     53  *
     54  * This is the hot plug event work handler (all asics).
     55  * The work gets scheduled from the irq handler if there
     56  * was a hot plug interrupt.  It walks the connector table
     57  * and calls the hotplug handler for each one, then sends
     58  * a drm hotplug event to alert userspace.
     59  */
     60 static void amdgpu_hotplug_work_func(struct work_struct *work)
     61 {
     62 	struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
     63 						  hotplug_work);
     64 	struct drm_device *dev = adev->ddev;
     65 	struct drm_mode_config *mode_config = &dev->mode_config;
     66 	struct drm_connector *connector;
     67 
     68 	mutex_lock(&mode_config->mutex);
     69 	if (mode_config->num_connector) {
     70 		list_for_each_entry(connector, &mode_config->connector_list, head)
     71 			amdgpu_connector_hotplug(connector);
     72 	}
     73 	mutex_unlock(&mode_config->mutex);
     74 	/* Just fire off a uevent and let userspace tell us what to do */
     75 	drm_helper_hpd_irq_event(dev);
     76 }
     77 
     78 /**
     79  * amdgpu_irq_reset_work_func - execute gpu reset
     80  *
     81  * @work: work struct
     82  *
     83  * Execute scheduled gpu reset (cayman+).
     84  * This function is called when the irq handler
     85  * thinks we need a gpu reset.
     86  */
     87 static void amdgpu_irq_reset_work_func(struct work_struct *work)
     88 {
     89 	struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
     90 						  reset_work);
     91 
     92 	amdgpu_gpu_reset(adev);
     93 }
     94 
     95 /* Disable *all* interrupts */
     96 static void amdgpu_irq_disable_all(struct amdgpu_device *adev)
     97 {
     98 	unsigned long irqflags;
     99 	unsigned i, j;
    100 	int r;
    101 
    102 	spin_lock_irqsave(&adev->irq.lock, irqflags);
    103 	for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; ++i) {
    104 		struct amdgpu_irq_src *src = adev->irq.sources[i];
    105 
    106 		if (!src || !src->funcs->set || !src->num_types)
    107 			continue;
    108 
    109 		for (j = 0; j < src->num_types; ++j) {
    110 			atomic_set(&src->enabled_types[j], 0);
    111 			r = src->funcs->set(adev, src, j,
    112 					    AMDGPU_IRQ_STATE_DISABLE);
    113 			if (r)
    114 				DRM_ERROR("error disabling interrupt (%d)\n",
    115 					  r);
    116 		}
    117 	}
    118 	spin_unlock_irqrestore(&adev->irq.lock, irqflags);
    119 }
    120 
    121 /**
    122  * amdgpu_irq_preinstall - drm irq preinstall callback
    123  *
    124  * @dev: drm dev pointer
    125  *
    126  * Gets the hw ready to enable irqs (all asics).
    127  * This function disables all interrupt sources on the GPU.
    128  */
    129 void amdgpu_irq_preinstall(struct drm_device *dev)
    130 {
    131 	struct amdgpu_device *adev = dev->dev_private;
    132 
    133 	/* Disable *all* interrupts */
    134 	amdgpu_irq_disable_all(adev);
    135 	/* Clear bits */
    136 	amdgpu_ih_process(adev);
    137 }
    138 
    139 /**
    140  * amdgpu_irq_postinstall - drm irq preinstall callback
    141  *
    142  * @dev: drm dev pointer
    143  *
    144  * Handles stuff to be done after enabling irqs (all asics).
    145  * Returns 0 on success.
    146  */
    147 int amdgpu_irq_postinstall(struct drm_device *dev)
    148 {
    149 	dev->max_vblank_count = 0x00ffffff;
    150 	return 0;
    151 }
    152 
    153 /**
    154  * amdgpu_irq_uninstall - drm irq uninstall callback
    155  *
    156  * @dev: drm dev pointer
    157  *
    158  * This function disables all interrupt sources on the GPU (all asics).
    159  */
    160 void amdgpu_irq_uninstall(struct drm_device *dev)
    161 {
    162 	struct amdgpu_device *adev = dev->dev_private;
    163 
    164 	if (adev == NULL) {
    165 		return;
    166 	}
    167 	amdgpu_irq_disable_all(adev);
    168 }
    169 
    170 /**
    171  * amdgpu_irq_handler - irq handler
    172  *
    173  * @int irq, void *arg: args
    174  *
    175  * This is the irq handler for the amdgpu driver (all asics).
    176  */
    177 irqreturn_t amdgpu_irq_handler(int irq, void *arg)
    178 {
    179 	struct drm_device *dev = (struct drm_device *) arg;
    180 	struct amdgpu_device *adev = dev->dev_private;
    181 	irqreturn_t ret;
    182 
    183 	ret = amdgpu_ih_process(adev);
    184 	if (ret == IRQ_HANDLED)
    185 		pm_runtime_mark_last_busy(dev->dev);
    186 	return ret;
    187 }
    188 
    189 /**
    190  * amdgpu_msi_ok - asic specific msi checks
    191  *
    192  * @adev: amdgpu device pointer
    193  *
    194  * Handles asic specific MSI checks to determine if
    195  * MSIs should be enabled on a particular chip (all asics).
    196  * Returns true if MSIs should be enabled, false if MSIs
    197  * should not be enabled.
    198  */
    199 static bool amdgpu_msi_ok(struct amdgpu_device *adev)
    200 {
    201 	/* force MSI on */
    202 	if (amdgpu_msi == 1)
    203 		return true;
    204 	else if (amdgpu_msi == 0)
    205 		return false;
    206 
    207 	return true;
    208 }
    209 
    210 /**
    211  * amdgpu_irq_init - init driver interrupt info
    212  *
    213  * @adev: amdgpu device pointer
    214  *
    215  * Sets up the work irq handlers, vblank init, MSIs, etc. (all asics).
    216  * Returns 0 for success, error for failure.
    217  */
    218 int amdgpu_irq_init(struct amdgpu_device *adev)
    219 {
    220 	int r = 0;
    221 
    222 	spin_lock_init(&adev->irq.lock);
    223 	r = drm_vblank_init(adev->ddev, adev->mode_info.num_crtc);
    224 	if (r) {
    225 		return r;
    226 	}
    227 	/* enable msi */
    228 	adev->irq.msi_enabled = false;
    229 
    230 	if (amdgpu_msi_ok(adev)) {
    231 		int ret = pci_enable_msi(adev->pdev);
    232 		if (!ret) {
    233 			adev->irq.msi_enabled = true;
    234 			dev_info(adev->dev, "amdgpu: using MSI.\n");
    235 		}
    236 	}
    237 
    238 	INIT_WORK(&adev->hotplug_work, amdgpu_hotplug_work_func);
    239 	INIT_WORK(&adev->reset_work, amdgpu_irq_reset_work_func);
    240 
    241 	adev->irq.installed = true;
    242 	r = drm_irq_install(adev->ddev, adev->ddev->pdev->irq);
    243 	if (r) {
    244 		adev->irq.installed = false;
    245 		flush_work(&adev->hotplug_work);
    246 		return r;
    247 	}
    248 
    249 	DRM_INFO("amdgpu: irq initialized.\n");
    250 	return 0;
    251 }
    252 
    253 /**
    254  * amdgpu_irq_fini - tear down driver interrupt info
    255  *
    256  * @adev: amdgpu device pointer
    257  *
    258  * Tears down the work irq handlers, vblank handlers, MSIs, etc. (all asics).
    259  */
    260 void amdgpu_irq_fini(struct amdgpu_device *adev)
    261 {
    262 	unsigned i;
    263 
    264 	drm_vblank_cleanup(adev->ddev);
    265 	if (adev->irq.installed) {
    266 		drm_irq_uninstall(adev->ddev);
    267 		adev->irq.installed = false;
    268 		if (adev->irq.msi_enabled)
    269 			pci_disable_msi(adev->pdev);
    270 		flush_work(&adev->hotplug_work);
    271 	}
    272 
    273 	for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; ++i) {
    274 		struct amdgpu_irq_src *src = adev->irq.sources[i];
    275 
    276 		if (!src)
    277 			continue;
    278 
    279 		kfree(src->enabled_types);
    280 		src->enabled_types = NULL;
    281 		if (src->data) {
    282 			kfree(src->data);
    283 			kfree(src);
    284 			adev->irq.sources[i] = NULL;
    285 		}
    286 	}
    287 }
    288 
    289 /**
    290  * amdgpu_irq_add_id - register irq source
    291  *
    292  * @adev: amdgpu device pointer
    293  * @src_id: source id for this source
    294  * @source: irq source
    295  *
    296  */
    297 int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
    298 		      struct amdgpu_irq_src *source)
    299 {
    300 	if (src_id >= AMDGPU_MAX_IRQ_SRC_ID)
    301 		return -EINVAL;
    302 
    303 	if (adev->irq.sources[src_id] != NULL)
    304 		return -EINVAL;
    305 
    306 	if (!source->funcs)
    307 		return -EINVAL;
    308 
    309 	if (source->num_types && !source->enabled_types) {
    310 		atomic_t *types;
    311 
    312 		types = kcalloc(source->num_types, sizeof(atomic_t),
    313 				GFP_KERNEL);
    314 		if (!types)
    315 			return -ENOMEM;
    316 
    317 		source->enabled_types = types;
    318 	}
    319 
    320 	adev->irq.sources[src_id] = source;
    321 	return 0;
    322 }
    323 
    324 /**
    325  * amdgpu_irq_dispatch - dispatch irq to IP blocks
    326  *
    327  * @adev: amdgpu device pointer
    328  * @entry: interrupt vector
    329  *
    330  * Dispatches the irq to the different IP blocks
    331  */
    332 void amdgpu_irq_dispatch(struct amdgpu_device *adev,
    333 			 struct amdgpu_iv_entry *entry)
    334 {
    335 	unsigned src_id = entry->src_id;
    336 	struct amdgpu_irq_src *src;
    337 	int r;
    338 
    339 	if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) {
    340 		DRM_DEBUG("Invalid src_id in IV: %d\n", src_id);
    341 		return;
    342 	}
    343 
    344 	src = adev->irq.sources[src_id];
    345 	if (!src) {
    346 		DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
    347 		return;
    348 	}
    349 
    350 	r = src->funcs->process(adev, src, entry);
    351 	if (r)
    352 		DRM_ERROR("error processing interrupt (%d)\n", r);
    353 }
    354 
    355 /**
    356  * amdgpu_irq_update - update hw interrupt state
    357  *
    358  * @adev: amdgpu device pointer
    359  * @src: interrupt src you want to enable
    360  * @type: type of interrupt you want to update
    361  *
    362  * Updates the interrupt state for a specific src (all asics).
    363  */
    364 int amdgpu_irq_update(struct amdgpu_device *adev,
    365 			     struct amdgpu_irq_src *src, unsigned type)
    366 {
    367 	unsigned long irqflags;
    368 	enum amdgpu_interrupt_state state;
    369 	int r;
    370 
    371 	spin_lock_irqsave(&adev->irq.lock, irqflags);
    372 
    373 	/* we need to determine after taking the lock, otherwise
    374 	   we might disable just enabled interrupts again */
    375 	if (amdgpu_irq_enabled(adev, src, type))
    376 		state = AMDGPU_IRQ_STATE_ENABLE;
    377 	else
    378 		state = AMDGPU_IRQ_STATE_DISABLE;
    379 
    380 	r = src->funcs->set(adev, src, type, state);
    381 	spin_unlock_irqrestore(&adev->irq.lock, irqflags);
    382 	return r;
    383 }
    384 
    385 /**
    386  * amdgpu_irq_get - enable interrupt
    387  *
    388  * @adev: amdgpu device pointer
    389  * @src: interrupt src you want to enable
    390  * @type: type of interrupt you want to enable
    391  *
    392  * Enables the interrupt type for a specific src (all asics).
    393  */
    394 int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
    395 		   unsigned type)
    396 {
    397 	if (!adev->ddev->irq_enabled)
    398 		return -ENOENT;
    399 
    400 	if (type >= src->num_types)
    401 		return -EINVAL;
    402 
    403 	if (!src->enabled_types || !src->funcs->set)
    404 		return -EINVAL;
    405 
    406 	if (atomic_inc_return(&src->enabled_types[type]) == 1)
    407 		return amdgpu_irq_update(adev, src, type);
    408 
    409 	return 0;
    410 }
    411 
    412 bool amdgpu_irq_get_delayed(struct amdgpu_device *adev,
    413 			struct amdgpu_irq_src *src,
    414 			unsigned type)
    415 {
    416 	if ((type >= src->num_types) || !src->enabled_types)
    417 		return false;
    418 	return atomic_inc_return(&src->enabled_types[type]) == 1;
    419 }
    420 
    421 /**
    422  * amdgpu_irq_put - disable interrupt
    423  *
    424  * @adev: amdgpu device pointer
    425  * @src: interrupt src you want to disable
    426  * @type: type of interrupt you want to disable
    427  *
    428  * Disables the interrupt type for a specific src (all asics).
    429  */
    430 int amdgpu_irq_put(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
    431 		   unsigned type)
    432 {
    433 	if (!adev->ddev->irq_enabled)
    434 		return -ENOENT;
    435 
    436 	if (type >= src->num_types)
    437 		return -EINVAL;
    438 
    439 	if (!src->enabled_types || !src->funcs->set)
    440 		return -EINVAL;
    441 
    442 	if (atomic_dec_and_test(&src->enabled_types[type]))
    443 		return amdgpu_irq_update(adev, src, type);
    444 
    445 	return 0;
    446 }
    447 
    448 /**
    449  * amdgpu_irq_enabled - test if irq is enabled or not
    450  *
    451  * @adev: amdgpu device pointer
    452  * @idx: interrupt src you want to test
    453  *
    454  * Tests if the given interrupt source is enabled or not
    455  */
    456 bool amdgpu_irq_enabled(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
    457 			unsigned type)
    458 {
    459 	if (!adev->ddev->irq_enabled)
    460 		return false;
    461 
    462 	if (type >= src->num_types)
    463 		return false;
    464 
    465 	if (!src->enabled_types || !src->funcs->set)
    466 		return false;
    467 
    468 	return !!atomic_read(&src->enabled_types[type]);
    469 }
    470