Commit 2d44c6f6 authored by Ofir Bitton's avatar Ofir Bitton Committed by Oded Gabbay
Browse files

habanalabs: enable all IRQs for user interrupt support



In order to support user interrupts, driver must enable all MSI-X
interrupts for any case user will trigger them. We differentiate
between a valid user interrupt and a non valid one.

Signed-off-by: default avatarOfir Bitton <obitton@habana.ai>
Reviewed-by: default avatarOded Gabbay <ogabbay@kernel.org>
Signed-off-by: default avatarOded Gabbay <ogabbay@kernel.org>
parent 5d6a198f
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -1251,7 +1251,7 @@ int hl_device_reset(struct hl_device *hdev, bool hard_reset,
 */
int hl_device_init(struct hl_device *hdev, struct class *hclass)
{
	int i, rc, cq_cnt, cq_ready_cnt;
	int i, rc, cq_cnt, user_interrupt_cnt, cq_ready_cnt;
	char *name;
	bool add_cdev_sysfs_on_err = false;

@@ -1340,6 +1340,19 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
		hdev->completion_queue[i].cq_idx = i;
	}

	user_interrupt_cnt = hdev->asic_prop.user_interrupt_count;

	if (user_interrupt_cnt) {
		hdev->user_interrupt = kcalloc(user_interrupt_cnt,
				sizeof(*hdev->user_interrupt),
				GFP_KERNEL);

		if (!hdev->user_interrupt) {
			rc = -ENOMEM;
			goto cq_fini;
		}
	}

	/*
	 * Initialize the event queue. Must be done before hw_init,
	 * because there the address of the event queue is being
@@ -1348,7 +1361,7 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
	rc = hl_eq_init(hdev, &hdev->event_queue);
	if (rc) {
		dev_err(hdev->dev, "failed to initialize event queue\n");
		goto cq_fini;
		goto user_interrupts_fini;
	}

	/* MMU S/W must be initialized before kernel context is created */
@@ -1486,6 +1499,8 @@ int hl_device_init(struct hl_device *hdev, struct class *hclass)
	hl_mmu_fini(hdev);
eq_fini:
	hl_eq_fini(hdev, &hdev->event_queue);
user_interrupts_fini:
	kfree(hdev->user_interrupt);
cq_fini:
	for (i = 0 ; i < cq_ready_cnt ; i++)
		hl_cq_fini(hdev, &hdev->completion_queue[i]);
@@ -1625,6 +1640,7 @@ void hl_device_fini(struct hl_device *hdev)
	for (i = 0 ; i < hdev->asic_prop.completion_queues_count ; i++)
		hl_cq_fini(hdev, &hdev->completion_queue[i]);
	kfree(hdev->completion_queue);
	kfree(hdev->user_interrupt);

	hl_hw_queues_destroy(hdev);

+16 −0
Original line number Diff line number Diff line
@@ -412,6 +412,7 @@ struct hl_mmu_properties {
 * @first_available_user_msix_interrupt: first available msix interrupt
 *                                       reserved for the user
 * @first_available_cq: first available CQ for the user.
 * @user_interrupt_count: number of user interrupts.
 * @tpc_enabled_mask: which TPCs are enabled.
 * @completion_queues_count: number of completion queues.
 * @fw_security_disabled: true if security measures are disabled in firmware,
@@ -475,6 +476,7 @@ struct asic_fixed_properties {
	u16				first_available_user_mon[HL_MAX_DCORES];
	u16				first_available_user_msix_interrupt;
	u16				first_available_cq[HL_MAX_DCORES];
	u16				user_interrupt_count;
	u8				tpc_enabled_mask;
	u8				completion_queues_count;
	u8				fw_security_disabled;
@@ -689,6 +691,16 @@ struct hl_cq {
	atomic_t		free_slots_cnt;
};

/**
 * struct hl_user_interrupt - holds user interrupt information
 * @hdev: pointer to the device structure
 * @interrupt_id: msix interrupt id
 */
struct hl_user_interrupt {
	struct hl_device	*hdev;
	u32			interrupt_id;
};

/**
 * struct hl_eq - describes the event queue (single one per device)
 * @hdev: pointer to the device structure
@@ -1821,6 +1833,7 @@ struct hl_mmu_funcs {
 * @asic_name: ASIC specific name.
 * @asic_type: ASIC specific type.
 * @completion_queue: array of hl_cq.
 * @user_interrupt: array of hl_user_interrupt.
 * @cq_wq: work queues of completion queues for executing work in process
 *         context.
 * @eq_wq: work queue of event queue for executing work in process context.
@@ -1937,6 +1950,7 @@ struct hl_device {
	char				status[HL_DEV_STS_MAX][HL_STR_MAX];
	enum hl_asic_type		asic_type;
	struct hl_cq			*completion_queue;
	struct hl_user_interrupt	*user_interrupt;
	struct workqueue_struct		**cq_wq;
	struct workqueue_struct		*eq_wq;
	struct hl_ctx			*kernel_ctx;
@@ -2158,6 +2172,8 @@ void hl_cq_reset(struct hl_device *hdev, struct hl_cq *q);
void hl_eq_reset(struct hl_device *hdev, struct hl_eq *q);
irqreturn_t hl_irq_handler_cq(int irq, void *arg);
irqreturn_t hl_irq_handler_eq(int irq, void *arg);
irqreturn_t hl_irq_handler_user_cq(int irq, void *arg);
irqreturn_t hl_irq_handler_default(int irq, void *arg);
u32 hl_cq_inc_ptr(u32 ptr);

int hl_asid_init(struct hl_device *hdev);
+40 −0
Original line number Diff line number Diff line
@@ -137,6 +137,46 @@ irqreturn_t hl_irq_handler_cq(int irq, void *arg)
	return IRQ_HANDLED;
}

/**
 * hl_irq_handler_user_cq - irq handler for user completion queues
 *
 * @irq: irq number
 * @arg: pointer to user interrupt structure
 *
 */
irqreturn_t hl_irq_handler_user_cq(int irq, void *arg)
{
	struct hl_user_interrupt *user_cq = arg;
	struct hl_device *hdev = user_cq->hdev;
	u32 interrupt_id = user_cq->interrupt_id;

	dev_info(hdev->dev,
		"got user completion interrupt id %u",
		interrupt_id);

	return IRQ_HANDLED;
}

/**
 * hl_irq_handler_default - default irq handler
 *
 * @irq: irq number
 * @arg: pointer to user interrupt structure
 *
 */
irqreturn_t hl_irq_handler_default(int irq, void *arg)
{
	struct hl_user_interrupt *user_interrupt = arg;
	struct hl_device *hdev = user_interrupt->hdev;
	u32 interrupt_id = user_interrupt->interrupt_id;

	dev_err(hdev->dev,
		"got invalid user interrupt %u",
		interrupt_id);

	return IRQ_HANDLED;
}

/**
 * hl_irq_handler_eq - irq handler for event queue
 *