public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Oded Gabbay <oded.gabbay@amd.com>
To: <dri-devel@lists.freedesktop.org>
Cc: David Airlie <airlied@linux.ie>,
	Jerome Glisse <j.glisse@gmail.com>,
	Joerg Roedel <joro@8bytes.org>, <linux-kernel@vger.kernel.org>,
	"John Bridgman" <John.Bridgman@amd.com>,
	<Alexander.Deucher@amd.com>
Subject: [PATCH 3/3] amdkfd: Use workqueue for GPU init
Date: Sat, 20 Dec 2014 22:46:14 +0200	[thread overview]
Message-ID: <1419108374-7020-4-git-send-email-oded.gabbay@amd.com> (raw)
In-Reply-To: <1419108374-7020-1-git-send-email-oded.gabbay@amd.com>

When amd_iommu_v2, amdkfd and radeon are all compiled inside the kernel image
(not as modules), radeon probes the existing GPU before amdkfd and amd_iommu_v2
are even loaded. When radeon encounters an AMD GPU, it will pass that
information to amdkfd. However, that call will fail and will cause a kernel BUG.

We could poll in radeon on when amdkfd and amd_iommu_v2 have been loaded, but
that would stall radeon.

Therefore, this patch moves the amdkfd part of GPU initialization to a
workqueue. When radeon calls amdkfd to perform GPU related initialization, it
will check if both amdkfd and amd_iommu_v2 have been loaded. If so, which is
the situation when the three drivers are compiled as modules, it will call the
relevant amdkfd function directly. If not, it will queue the initialization
work on the workqueue. The work function will schedule itself until both amdkfd
and amd_iommu_v2 have been loaded. Then, it will call the relevant amdkfd
function.

The workqueue is defined per kfd_dev structure (per GPU).

Signed-off-by: Oded Gabbay <oded.gabbay@amd.com>
---
 drivers/gpu/drm/amd/amdkfd/kfd_device.c | 72 +++++++++++++++++++++++++++++++--
 drivers/gpu/drm/amd/amdkfd/kfd_priv.h   |  2 +
 2 files changed, 70 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index 43884eb..cec5b4b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -24,6 +24,7 @@
 #include <linux/bsearch.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 #include "kfd_priv.h"
 #include "kfd_device_queue_manager.h"
 
@@ -40,6 +41,11 @@ struct kfd_deviceid {
 	const struct kfd_device_info *device_info;
 };
 
+struct kfd_device_init_work {
+	struct work_struct kfd_work;
+	struct kfd_dev *dev;
+};
+
 /* Please keep this sorted by increasing device id. */
 static const struct kfd_deviceid supported_devices[] = {
 	{ 0x1304, &kaveri_device_info },	/* Kaveri */
@@ -99,6 +105,8 @@ struct kfd_dev *kgd2kfd_probe(struct kgd_dev *kgd, struct pci_dev *pdev)
 	kfd->pdev = pdev;
 	kfd->init_complete = false;
 
+	kfd->kfd_dev_wq = create_workqueue("kfd_dev_wq");
+
 	return kfd;
 }
 
@@ -161,13 +169,10 @@ static void iommu_pasid_shutdown_callback(struct pci_dev *pdev, int pasid)
 		kfd_unbind_process_from_device(dev, pasid);
 }
 
-bool kgd2kfd_device_init(struct kfd_dev *kfd,
-			 const struct kgd2kfd_shared_resources *gpu_resources)
+static bool kfd_kgd_device_init(struct kfd_dev *kfd)
 {
 	unsigned int size;
 
-	kfd->shared_resources = *gpu_resources;
-
 	/* calculate max size of mqds needed for queues */
 	size = max_num_of_processes *
 		max_num_of_queues_per_process *
@@ -249,6 +254,63 @@ out:
 	return kfd->init_complete;
 }
 
+static void kfd_device_wq_init_device(struct work_struct *work)
+{
+	struct kfd_device_init_work *my_work;
+	struct kfd_dev *kfd;
+
+	my_work = (struct kfd_device_init_work *) work;
+
+	kfd = my_work->dev;
+
+	/*
+	 * As long as amdkfd or amd_iommu_v2 are not initialized, we
+	 * yield the processor
+	 */
+	while ((!amdkfd_is_init_completed()) ||
+		(!amd_iommu_v2_is_init_completed()))
+		schedule();
+
+	kfd_kgd_device_init(kfd);
+}
+
+bool kgd2kfd_device_init(struct kfd_dev *kfd,
+			 const struct kgd2kfd_shared_resources *gpu_resources)
+{
+	struct kfd_device_init_work *work;
+
+	kfd->shared_resources = *gpu_resources;
+
+	/*
+	 * When amd_iommu_v2, amdkfd and radeon are compiled inside the kernel,
+	 * there is no mechanism to enforce order of loading between the
+	 * drivers. Therefore, we need to use an explicit form of
+	 * synchronization to know when amdkfd and amd_iommu_v2 have finished
+	 * there initialization routines
+	 */
+	if ((!amdkfd_is_init_completed()) ||
+		(!amd_iommu_v2_is_init_completed())) {
+		BUG_ON(!kfd->kfd_dev_wq);
+
+		work = (struct kfd_device_init_work *)
+			kmalloc(sizeof(struct kfd_device_init_work),
+				GFP_ATOMIC);
+
+		if (!work) {
+			pr_err("kfd: no memory for device work queue\n");
+			return false;
+		}
+
+		INIT_WORK((struct work_struct *) work,
+				kfd_device_wq_init_device);
+		work->dev = kfd;
+		queue_work(kfd->kfd_dev_wq, (struct work_struct *) work);
+		return true;
+	}
+
+	return kfd_kgd_device_init(kfd);
+}
+
 void kgd2kfd_device_exit(struct kfd_dev *kfd)
 {
 	if (kfd->init_complete) {
@@ -258,6 +320,8 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
 		kfd_topology_remove_device(kfd);
 	}
 
+	flush_workqueue(kfd->kfd_dev_wq);
+	destroy_workqueue(kfd->kfd_dev_wq);
 	kfree(kfd);
 }
 
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 01df7e6..fc000a2 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -151,6 +151,8 @@ struct kfd_dev {
 	 * from the HW ring into a SW ring.
 	 */
 	bool interrupts_active;
+
+	struct workqueue_struct *kfd_dev_wq;
 };
 
 int amdkfd_is_init_completed(void);
-- 
2.1.0


      parent reply	other threads:[~2014-12-20 20:46 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-12-20 20:46 [PATCH 0/3] Use workqueue for device init in amdkfd Oded Gabbay
2014-12-20 20:46 ` [PATCH 1/3] amdkfd: Don't clear *kfd2kgd on kfd_module_init Oded Gabbay
2014-12-20 21:25   ` Greg KH
2014-12-21 11:12     ` Oded Gabbay
2014-12-21 11:27   ` Christian König
2014-12-21 11:34     ` Oded Gabbay
2014-12-21 12:19       ` Christian König
2014-12-21 13:06         ` Oded Gabbay
2014-12-21 13:24           ` Oded Gabbay
2014-12-21 15:57             ` Christian König
2014-12-21 16:03               ` Oded Gabbay
2014-12-21 16:10                 ` Christian König
2014-12-22  7:34                   ` Oded Gabbay
2014-12-22  7:40                     ` Dave Airlie
2014-12-22  7:43                       ` Oded Gabbay
2014-12-22  8:57                         ` Christian König
2014-12-22  9:26                           ` Oded Gabbay
2014-12-22 10:22                             ` Oded Gabbay
2014-12-20 20:46 ` [PATCH 2/3] amdkfd: Track when amdkfd init is complete Oded Gabbay
2014-12-20 20:46 ` Oded Gabbay [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1419108374-7020-4-git-send-email-oded.gabbay@amd.com \
    --to=oded.gabbay@amd.com \
    --cc=Alexander.Deucher@amd.com \
    --cc=John.Bridgman@amd.com \
    --cc=airlied@linux.ie \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=j.glisse@gmail.com \
    --cc=joro@8bytes.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox