aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/radeon/radeon_device.c
diff options
context:
space:
mode:
authorAlex Deucher <alexander.deucher@amd.com>2013-03-04 12:47:46 -0500
committerAlex Deucher <alexander.deucher@amd.com>2013-06-27 10:49:07 -0400
commit75efdee11b5da3acbbeb43a9b93a9c4fe6d5bec8 (patch)
treedfdb40d6b02d6a613a5d20ae8a343ac0d024dfcc /drivers/gpu/drm/radeon/radeon_device.c
parentf93bdefe6269067afc85688d45c646cde350e0d8 (diff)
drm/radeon: implement simple doorbell page allocator
The doorbell aperture is a PCI BAR whose pages can be mapped to compute resources for things like wptrs for userspace queues. This patch maps the BAR and sets up a simple allocator to allocate pages from the BAR. Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Diffstat (limited to 'drivers/gpu/drm/radeon/radeon_device.c')
-rw-r--r--drivers/gpu/drm/radeon/radeon_device.c94
1 files changed, 94 insertions, 0 deletions
diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
index 4e97ff79b7f..82335e38ec4 100644
--- a/drivers/gpu/drm/radeon/radeon_device.c
+++ b/drivers/gpu/drm/radeon/radeon_device.c
@@ -232,6 +232,94 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
}
/*
+ * GPU doorbell aperture helpers function.
+ */
+/**
+ * radeon_doorbell_init - Init doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Init doorbell driver information (CIK)
+ * Returns 0 on success, error on failure.
+ */
+int radeon_doorbell_init(struct radeon_device *rdev)
+{
+ int i;
+
+ /* doorbell bar mapping */
+ rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
+ rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
+
+ /* limit to 4 MB for now */
+ if (rdev->doorbell.size > (4 * 1024 * 1024))
+ rdev->doorbell.size = 4 * 1024 * 1024;
+
+ rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size);
+ if (rdev->doorbell.ptr == NULL) {
+ return -ENOMEM;
+ }
+ DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
+ DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size);
+
+ rdev->doorbell.num_pages = rdev->doorbell.size / PAGE_SIZE;
+
+ for (i = 0; i < rdev->doorbell.num_pages; i++) {
+ rdev->doorbell.free[i] = true;
+ }
+ return 0;
+}
+
+/**
+ * radeon_doorbell_fini - Tear down doorbell driver information.
+ *
+ * @rdev: radeon_device pointer
+ *
+ * Tear down doorbell driver information (CIK)
+ */
+void radeon_doorbell_fini(struct radeon_device *rdev)
+{
+ iounmap(rdev->doorbell.ptr);
+ rdev->doorbell.ptr = NULL;
+}
+
+/**
+ * radeon_doorbell_get - Allocate a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Allocate a doorbell page for use by the driver (all asics).
+ * Returns 0 on success or -EINVAL on failure.
+ */
+int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
+{
+ int i;
+
+ for (i = 0; i < rdev->doorbell.num_pages; i++) {
+ if (rdev->doorbell.free[i]) {
+ rdev->doorbell.free[i] = false;
+ *doorbell = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/**
+ * radeon_doorbell_free - Free a doorbell page
+ *
+ * @rdev: radeon_device pointer
+ * @doorbell: doorbell page number
+ *
+ * Free a doorbell page allocated for use by the driver (all asics)
+ */
+void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
+{
+ if (doorbell < rdev->doorbell.num_pages)
+ rdev->doorbell.free[doorbell] = true;
+}
+
+/*
* radeon_wb_*()
* Writeback is the the method by which the the GPU updates special pages
* in memory with the status of certain GPU events (fences, ring pointers,
@@ -1162,6 +1250,10 @@ int radeon_device_init(struct radeon_device *rdev,
DRM_INFO("register mmio base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size);
+ /* doorbell bar mapping */
+ if (rdev->family >= CHIP_BONAIRE)
+ radeon_doorbell_init(rdev);
+
/* io port mapping */
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) {
@@ -1239,6 +1331,8 @@ void radeon_device_fini(struct radeon_device *rdev)
rdev->rio_mem = NULL;
iounmap(rdev->rmmio);
rdev->rmmio = NULL;
+ if (rdev->family >= CHIP_BONAIRE)
+ radeon_doorbell_fini(rdev);
radeon_debugfs_remove_files(rdev);
}