Commit d766e6a3 authored by Alex Deucher's avatar Alex Deucher
Browse files

drm/amdgpu: switch ih handling to two levels (v3)



Newer asics have a two levels of irq ids now:
client id - the IP
src id - the interrupt src within the IP

v2: integrated Christian's comments.
v3: fix rebase fail in SI and CIK

Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
Signed-off-by: default avatarKen Wang <Qingqing.Wang@amd.com>
Reviewed-by: default avatarKen Wang <Qingqing.Wang@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 832be404
Loading
Loading
Loading
Loading
+18 −6
Original line number Diff line number Diff line
@@ -571,7 +571,9 @@ static const struct amdgpu_irq_src_funcs cgs_irq_funcs = {
	.process = cgs_process_irq,
};

static int amdgpu_cgs_add_irq_source(struct cgs_device *cgs_device, unsigned src_id,
static int amdgpu_cgs_add_irq_source(void *cgs_device,
				     unsigned client_id,
				     unsigned src_id,
				     unsigned num_types,
				     cgs_irq_source_set_func_t set,
				     cgs_irq_handler_func_t handler,
@@ -597,7 +599,7 @@ static int amdgpu_cgs_add_irq_source(struct cgs_device *cgs_device, unsigned src
	irq_params->handler = handler;
	irq_params->private_data = private_data;
	source->data = (void *)irq_params;
	ret = amdgpu_irq_add_id(adev, src_id, source);
	ret = amdgpu_irq_add_id(adev, client_id, src_id, source);
	if (ret) {
		kfree(irq_params);
		kfree(source);
@@ -606,16 +608,26 @@ static int amdgpu_cgs_add_irq_source(struct cgs_device *cgs_device, unsigned src
	return ret;
}

static int amdgpu_cgs_irq_get(struct cgs_device *cgs_device, unsigned src_id, unsigned type)
static int amdgpu_cgs_irq_get(void *cgs_device, unsigned client_id,
			      unsigned src_id, unsigned type)
{
	CGS_FUNC_ADEV;
	return amdgpu_irq_get(adev, adev->irq.sources[src_id], type);

	if (!adev->irq.client[client_id].sources)
		return -EINVAL;

	return amdgpu_irq_get(adev, adev->irq.client[client_id].sources[src_id], type);
}

static int amdgpu_cgs_irq_put(struct cgs_device *cgs_device, unsigned src_id, unsigned type)
static int amdgpu_cgs_irq_put(void *cgs_device, unsigned client_id,
			      unsigned src_id, unsigned type)
{
	CGS_FUNC_ADEV;
	return amdgpu_irq_put(adev, adev->irq.sources[src_id], type);

	if (!adev->irq.client[client_id].sources)
		return -EINVAL;

	return amdgpu_irq_put(adev, adev->irq.client[client_id].sources[src_id], type);
}

static int amdgpu_cgs_set_clockgating_state(struct cgs_device *cgs_device,
+6 −0
Original line number Diff line number Diff line
@@ -26,6 +26,10 @@

struct amdgpu_device;

#define AMDGPU_IH_CLIENTID_LEGACY 0

#define AMDGPU_IH_CLIENTID_MAX 0x1f

/*
 * R6xx+ IH ring
 */
@@ -47,10 +51,12 @@ struct amdgpu_ih_ring {
};

struct amdgpu_iv_entry {
	unsigned client_id;
	unsigned src_id;
	unsigned src_data;
	unsigned ring_id;
	unsigned vm_id;
	unsigned vm_id_src;
	unsigned pas_id;
	const uint32_t *iv_entry;
};
+76 −35
Original line number Diff line number Diff line
@@ -89,25 +89,30 @@ static void amdgpu_irq_reset_work_func(struct work_struct *work)
static void amdgpu_irq_disable_all(struct amdgpu_device *adev)
{
	unsigned long irqflags;
	unsigned i, j;
	unsigned i, j, k;
	int r;

	spin_lock_irqsave(&adev->irq.lock, irqflags);
	for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; ++i) {
		struct amdgpu_irq_src *src = adev->irq.sources[i];
	for (i = 0; i < AMDGPU_IH_CLIENTID_MAX; ++i) {
		if (!adev->irq.client[i].sources)
			continue;

		for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
			struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];

			if (!src || !src->funcs->set || !src->num_types)
				continue;

		for (j = 0; j < src->num_types; ++j) {
			atomic_set(&src->enabled_types[j], 0);
			r = src->funcs->set(adev, src, j,
			for (k = 0; k < src->num_types; ++k) {
				atomic_set(&src->enabled_types[k], 0);
				r = src->funcs->set(adev, src, k,
						    AMDGPU_IRQ_STATE_DISABLE);
				if (r)
					DRM_ERROR("error disabling interrupt (%d)\n",
						  r);
			}
		}
	}
	spin_unlock_irqrestore(&adev->irq.lock, irqflags);
}

@@ -254,7 +259,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
 */
void amdgpu_irq_fini(struct amdgpu_device *adev)
{
	unsigned i;
	unsigned i, j;

	drm_vblank_cleanup(adev->ddev);
	if (adev->irq.installed) {
@@ -266,8 +271,12 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
		cancel_work_sync(&adev->reset_work);
	}

	for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; ++i) {
		struct amdgpu_irq_src *src = adev->irq.sources[i];
	for (i = 0; i < AMDGPU_IH_CLIENTID_MAX; ++i) {
		if (!adev->irq.client[i].sources)
			continue;

		for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
			struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];

			if (!src)
				continue;
@@ -277,9 +286,11 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
			if (src->data) {
				kfree(src->data);
				kfree(src);
			adev->irq.sources[i] = NULL;
				adev->irq.client[i].sources[j] = NULL;
			}
		}
		kfree(adev->irq.client[i].sources);
	}
}

/**
@@ -290,18 +301,30 @@ void amdgpu_irq_fini(struct amdgpu_device *adev)
 * @source: irq source
 *
 */
int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
int amdgpu_irq_add_id(struct amdgpu_device *adev,
		      unsigned client_id, unsigned src_id,
		      struct amdgpu_irq_src *source)
{
	if (src_id >= AMDGPU_MAX_IRQ_SRC_ID)
	if (client_id >= AMDGPU_IH_CLIENTID_MAX)
		return -EINVAL;

	if (adev->irq.sources[src_id] != NULL)
	if (src_id >= AMDGPU_MAX_IRQ_SRC_ID)
		return -EINVAL;

	if (!source->funcs)
		return -EINVAL;

	if (!adev->irq.client[client_id].sources) {
		adev->irq.client[client_id].sources = kcalloc(AMDGPU_MAX_IRQ_SRC_ID,
							      sizeof(struct amdgpu_irq_src),
							      GFP_KERNEL);
		if (!adev->irq.client[client_id].sources)
			return -ENOMEM;
	}

	if (adev->irq.client[client_id].sources[src_id] != NULL)
		return -EINVAL;

	if (source->num_types && !source->enabled_types) {
		atomic_t *types;

@@ -313,8 +336,7 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
		source->enabled_types = types;
	}

	adev->irq.sources[src_id] = source;

	adev->irq.client[client_id].sources[src_id] = source;
	return 0;
}

@@ -329,10 +351,16 @@ int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
void amdgpu_irq_dispatch(struct amdgpu_device *adev,
			 struct amdgpu_iv_entry *entry)
{
	unsigned client_id = entry->client_id;
	unsigned src_id = entry->src_id;
	struct amdgpu_irq_src *src;
	int r;

	if (client_id >= AMDGPU_IH_CLIENTID_MAX) {
		DRM_DEBUG("Invalid client_id in IV: %d\n", client_id);
		return;
	}

	if (src_id >= AMDGPU_MAX_IRQ_SRC_ID) {
		DRM_DEBUG("Invalid src_id in IV: %d\n", src_id);
		return;
@@ -341,7 +369,13 @@ void amdgpu_irq_dispatch(struct amdgpu_device *adev,
	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 (!adev->irq.client[client_id].sources) {
			DRM_DEBUG("Unregistered interrupt client_id: %d src_id: %d\n",
				  client_id, src_id);
			return;
		}

		src = adev->irq.client[client_id].sources[src_id];
		if (!src) {
			DRM_DEBUG("Unhandled interrupt src_id: %d\n", src_id);
			return;
@@ -385,13 +419,20 @@ int amdgpu_irq_update(struct amdgpu_device *adev,

void amdgpu_irq_gpu_reset_resume_helper(struct amdgpu_device *adev)
{
	int i, j;
	for (i = 0; i < AMDGPU_MAX_IRQ_SRC_ID; i++) {
		struct amdgpu_irq_src *src = adev->irq.sources[i];
	int i, j, k;

	for (i = 0; i < AMDGPU_IH_CLIENTID_MAX; ++i) {
		if (!adev->irq.client[i].sources)
			continue;

		for (j = 0; j < AMDGPU_MAX_IRQ_SRC_ID; ++j) {
			struct amdgpu_irq_src *src = adev->irq.client[i].sources[j];

			if (!src)
				continue;
		for (j = 0; j < src->num_types; j++)
			amdgpu_irq_update(adev, src, j);
			for (k = 0; k < src->num_types; k++)
				amdgpu_irq_update(adev, src, k);
		}
	}
}

+8 −2
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
#include "amdgpu_ih.h"

#define AMDGPU_MAX_IRQ_SRC_ID	0x100
#define AMDGPU_MAX_IRQ_CLIENT_ID	0x100

struct amdgpu_device;
struct amdgpu_iv_entry;
@@ -44,6 +45,10 @@ struct amdgpu_irq_src {
	void *data;
};

struct amdgpu_irq_client {
	struct amdgpu_irq_src **sources;
};

/* provided by interrupt generating IP blocks */
struct amdgpu_irq_src_funcs {
	int (*set)(struct amdgpu_device *adev, struct amdgpu_irq_src *source,
@@ -58,7 +63,7 @@ struct amdgpu_irq {
	bool				installed;
	spinlock_t			lock;
	/* interrupt sources */
	struct amdgpu_irq_src		*sources[AMDGPU_MAX_IRQ_SRC_ID];
	struct amdgpu_irq_client	client[AMDGPU_IH_CLIENTID_MAX];

	/* status, etc. */
	bool				msi_enabled; /* msi enabled */
@@ -80,7 +85,8 @@ irqreturn_t amdgpu_irq_handler(int irq, void *arg);

int amdgpu_irq_init(struct amdgpu_device *adev);
void amdgpu_irq_fini(struct amdgpu_device *adev);
int amdgpu_irq_add_id(struct amdgpu_device *adev, unsigned src_id,
int amdgpu_irq_add_id(struct amdgpu_device *adev,
		      unsigned client_id, unsigned src_id,
		      struct amdgpu_irq_src *source);
void amdgpu_irq_dispatch(struct amdgpu_device *adev,
			 struct amdgpu_iv_entry *entry);
+4 −2
Original line number Diff line number Diff line
@@ -6284,11 +6284,13 @@ static int ci_dpm_sw_init(void *handle)
	int ret;
	struct amdgpu_device *adev = (struct amdgpu_device *)handle;

	ret = amdgpu_irq_add_id(adev, 230, &adev->pm.dpm.thermal.irq);
	ret = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 230,
				&adev->pm.dpm.thermal.irq);
	if (ret)
		return ret;

	ret = amdgpu_irq_add_id(adev, 231, &adev->pm.dpm.thermal.irq);
	ret = amdgpu_irq_add_id(adev, AMDGPU_IH_CLIENTID_LEGACY, 231,
				&adev->pm.dpm.thermal.irq);
	if (ret)
		return ret;

Loading