drm/radeon: use a single doorbell for cik kms compute
authorAndrew Lewycky <Andrew.Lewycky@amd.com>
Wed, 13 Nov 2013 20:54:17 +0000 (15:54 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 15 Nov 2013 20:56:22 +0000 (15:56 -0500)
A single doorbell page is plenty for cik kms compute.
Use a single page and manage doorbell allocation by
individual doorbells rather than pages.  Identify
doorbells by their index rather than byte offset.

Signed-off-by: Andrew Lewycky <Andrew.Lewycky@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/radeon.h
drivers/gpu/drm/radeon/radeon_device.c

index c1698978a8f1a109201cfa395cebdb04902e8a32..08aa58ef8d0a8d8cf74f870d98c98bffdb39b8c6 100644 (file)
@@ -1560,17 +1560,17 @@ u32 cik_get_xclk(struct radeon_device *rdev)
  * cik_mm_rdoorbell - read a doorbell dword
  *
  * @rdev: radeon_device pointer
- * @offset: byte offset into the aperture
+ * @index: doorbell index
  *
  * Returns the value in the doorbell aperture at the
- * requested offset (CIK).
+ * requested doorbell index (CIK).
  */
-u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 index)
 {
-       if (offset < rdev->doorbell.size) {
-               return readl(((void __iomem *)rdev->doorbell.ptr) + offset);
+       if (index < rdev->doorbell.num_doorbells) {
+               return readl(rdev->doorbell.ptr + index);
        } else {
-               DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset);
+               DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index);
                return 0;
        }
 }
@@ -1579,18 +1579,18 @@ u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
  * cik_mm_wdoorbell - write a doorbell dword
  *
  * @rdev: radeon_device pointer
- * @offset: byte offset into the aperture
+ * @index: doorbell index
  * @v: value to write
  *
  * Writes @v to the doorbell aperture at the
- * requested offset (CIK).
+ * requested doorbell index (CIK).
  */
-void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v)
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v)
 {
-       if (offset < rdev->doorbell.size) {
-               writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset);
+       if (index < rdev->doorbell.num_doorbells) {
+               writel(v, rdev->doorbell.ptr + index);
        } else {
-               DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset);
+               DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", index);
        }
 }
 
@@ -4054,7 +4054,7 @@ void cik_compute_ring_set_wptr(struct radeon_device *rdev,
                               struct radeon_ring *ring)
 {
        rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(ring->wptr);
-       WDOORBELL32(ring->doorbell_offset, ring->wptr);
+       WDOORBELL32(ring->doorbell_index, ring->wptr);
 }
 
 /**
@@ -4395,10 +4395,6 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
                        return r;
                }
 
-               /* doorbell offset */
-               rdev->ring[idx].doorbell_offset =
-                       (rdev->ring[idx].doorbell_page_num * PAGE_SIZE) + 0;
-
                /* init the mqd struct */
                memset(buf, 0, sizeof(struct bonaire_mqd));
 
@@ -4510,7 +4506,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
                                RREG32(CP_HQD_PQ_DOORBELL_CONTROL);
                        mqd->queue_state.cp_hqd_pq_doorbell_control &= ~DOORBELL_OFFSET_MASK;
                        mqd->queue_state.cp_hqd_pq_doorbell_control |=
-                               DOORBELL_OFFSET(rdev->ring[idx].doorbell_offset / 4);
+                               DOORBELL_OFFSET(rdev->ring[idx].doorbell_index);
                        mqd->queue_state.cp_hqd_pq_doorbell_control |= DOORBELL_EN;
                        mqd->queue_state.cp_hqd_pq_doorbell_control &=
                                ~(DOORBELL_SOURCE | DOORBELL_HIT);
@@ -7841,14 +7837,14 @@ int cik_init(struct radeon_device *rdev)
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
        ring->ring_obj = NULL;
        r600_ring_init(rdev, ring, 1024 * 1024);
-       r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+       r = radeon_doorbell_get(rdev, &ring->doorbell_index);
        if (r)
                return r;
 
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
        ring->ring_obj = NULL;
        r600_ring_init(rdev, ring, 1024 * 1024);
-       r = radeon_doorbell_get(rdev, &ring->doorbell_page_num);
+       r = radeon_doorbell_get(rdev, &ring->doorbell_index);
        if (r)
                return r;
 
index 2fe2f6332d44779973e23e5e13964787d68640e0..4970ac0ebc80ede4de5b64bf4acd434aded8cf61 100644 (file)
@@ -649,13 +649,15 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
 /*
  * GPU doorbell structures, functions & helpers
  */
+#define RADEON_MAX_DOORBELLS 1024      /* Reserve at most 1024 doorbell slots for radeon-owned rings. */
+
 struct radeon_doorbell {
-       u32                     num_pages;
-       bool                    free[1024];
        /* doorbell mmio */
-       resource_size_t                 base;
-       resource_size_t                 size;
-       void __iomem                    *ptr;
+       resource_size_t         base;
+       resource_size_t         size;
+       u32 __iomem             *ptr;
+       u32                     num_doorbells;  /* Number of doorbells actually reserved for radeon. */
+       unsigned long           used[DIV_ROUND_UP(RADEON_MAX_DOORBELLS, BITS_PER_LONG)];
 };
 
 int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
@@ -802,8 +804,7 @@ struct radeon_ring {
        u32 pipe;
        u32 queue;
        struct radeon_bo        *mqd_obj;
-       u32 doorbell_page_num;
-       u32 doorbell_offset;
+       u32 doorbell_index;
        unsigned                wptr_offs;
 };
 
@@ -2241,8 +2242,8 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v,
 u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
 void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
 
-u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset);
-void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
+u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 index);
+void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v);
 
 /*
  * Cast helper
@@ -2305,8 +2306,8 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
 #define RREG32_IO(reg) r100_io_rreg(rdev, (reg))
 #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
 
-#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset))
-#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v))
+#define RDOORBELL32(index) cik_mm_rdoorbell(rdev, (index))
+#define WDOORBELL32(index, v) cik_mm_wdoorbell(rdev, (index), (v))
 
 /*
  * Indirect registers accessor
index b9234c43f43d4309a18ce7bc327eceb75084cc7a..39b033b441d2a6f76e8d021df7085568538887b3 100644 (file)
@@ -251,28 +251,23 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
  */
 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.num_doorbells = min_t(u32, rdev->doorbell.size / sizeof(u32), RADEON_MAX_DOORBELLS);
+       if (rdev->doorbell.num_doorbells == 0)
+               return -EINVAL;
 
-       rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.size);
+       rdev->doorbell.ptr = ioremap(rdev->doorbell.base, rdev->doorbell.num_doorbells * sizeof(u32));
        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;
+       memset(&rdev->doorbell.used, 0, sizeof(rdev->doorbell.used));
 
-       for (i = 0; i < rdev->doorbell.num_pages; i++) {
-               rdev->doorbell.free[i] = true;
-       }
        return 0;
 }
 
@@ -290,40 +285,38 @@ void radeon_doorbell_fini(struct radeon_device *rdev)
 }
 
 /**
- * radeon_doorbell_get - Allocate a doorbell page
+ * radeon_doorbell_get - Allocate a doorbell entry
  *
  * @rdev: radeon_device pointer
- * @doorbell: doorbell page number
+ * @doorbell: doorbell index
  *
- * Allocate a doorbell page for use by the driver (all asics).
+ * Allocate a doorbell 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;
-               }
+       unsigned long offset = find_first_zero_bit(rdev->doorbell.used, rdev->doorbell.num_doorbells);
+       if (offset < rdev->doorbell.num_doorbells) {
+               __set_bit(offset, rdev->doorbell.used);
+               *doorbell = offset;
+               return 0;
+       } else {
+               return -EINVAL;
        }
-       return -EINVAL;
 }
 
 /**
- * radeon_doorbell_free - Free a doorbell page
+ * radeon_doorbell_free - Free a doorbell entry
  *
  * @rdev: radeon_device pointer
- * @doorbell: doorbell page number
+ * @doorbell: doorbell index
  *
- * Free a doorbell page allocated for use by the driver (all asics)
+ * Free a doorbell 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;
+       if (doorbell < rdev->doorbell.num_doorbells)
+               __clear_bit(doorbell, rdev->doorbell.used);
 }
 
 /*