Commit d5754ab8 authored by Andrew Lewycky's avatar Andrew Lewycky Committed by Alex Deucher

drm/radeon: use a single doorbell for cik kms compute

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: default avatarAndrew Lewycky <Andrew.Lewycky@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 4cc948b9
...@@ -1560,17 +1560,17 @@ u32 cik_get_xclk(struct radeon_device *rdev) ...@@ -1560,17 +1560,17 @@ u32 cik_get_xclk(struct radeon_device *rdev)
* cik_mm_rdoorbell - read a doorbell dword * cik_mm_rdoorbell - read a doorbell dword
* *
* @rdev: radeon_device pointer * @rdev: radeon_device pointer
* @offset: byte offset into the aperture * @index: doorbell index
* *
* Returns the value in the doorbell aperture at the * 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) { if (index < rdev->doorbell.num_doorbells) {
return readl(((void __iomem *)rdev->doorbell.ptr) + offset); return readl(rdev->doorbell.ptr + index);
} else { } else {
DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset); DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", index);
return 0; return 0;
} }
} }
...@@ -1579,18 +1579,18 @@ u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset) ...@@ -1579,18 +1579,18 @@ u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
* cik_mm_wdoorbell - write a doorbell dword * cik_mm_wdoorbell - write a doorbell dword
* *
* @rdev: radeon_device pointer * @rdev: radeon_device pointer
* @offset: byte offset into the aperture * @index: doorbell index
* @v: value to write * @v: value to write
* *
* Writes @v to the doorbell aperture at the * 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) { if (index < rdev->doorbell.num_doorbells) {
writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset); writel(v, rdev->doorbell.ptr + index);
} else { } 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, ...@@ -4054,7 +4054,7 @@ void cik_compute_ring_set_wptr(struct radeon_device *rdev,
struct radeon_ring *ring) struct radeon_ring *ring)
{ {
rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(ring->wptr); 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) ...@@ -4395,10 +4395,6 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
return r; return r;
} }
/* doorbell offset */
rdev->ring[idx].doorbell_offset =
(rdev->ring[idx].doorbell_page_num * PAGE_SIZE) + 0;
/* init the mqd struct */ /* init the mqd struct */
memset(buf, 0, sizeof(struct bonaire_mqd)); memset(buf, 0, sizeof(struct bonaire_mqd));
...@@ -4510,7 +4506,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev) ...@@ -4510,7 +4506,7 @@ static int cik_cp_compute_resume(struct radeon_device *rdev)
RREG32(CP_HQD_PQ_DOORBELL_CONTROL); 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_MASK;
mqd->queue_state.cp_hqd_pq_doorbell_control |= 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_EN;
mqd->queue_state.cp_hqd_pq_doorbell_control &= mqd->queue_state.cp_hqd_pq_doorbell_control &=
~(DOORBELL_SOURCE | DOORBELL_HIT); ~(DOORBELL_SOURCE | DOORBELL_HIT);
...@@ -7841,14 +7837,14 @@ int cik_init(struct radeon_device *rdev) ...@@ -7841,14 +7837,14 @@ int cik_init(struct radeon_device *rdev)
ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX]; ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
ring->ring_obj = NULL; ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 1024 * 1024); 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) if (r)
return r; return r;
ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX]; ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
ring->ring_obj = NULL; ring->ring_obj = NULL;
r600_ring_init(rdev, ring, 1024 * 1024); 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) if (r)
return r; return r;
......
...@@ -649,13 +649,15 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg); ...@@ -649,13 +649,15 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
/* /*
* GPU doorbell structures, functions & helpers * GPU doorbell structures, functions & helpers
*/ */
#define RADEON_MAX_DOORBELLS 1024 /* Reserve at most 1024 doorbell slots for radeon-owned rings. */
struct radeon_doorbell { struct radeon_doorbell {
u32 num_pages;
bool free[1024];
/* doorbell mmio */ /* doorbell mmio */
resource_size_t base; resource_size_t base;
resource_size_t size; resource_size_t size;
void __iomem *ptr; 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); int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
...@@ -802,8 +804,7 @@ struct radeon_ring { ...@@ -802,8 +804,7 @@ struct radeon_ring {
u32 pipe; u32 pipe;
u32 queue; u32 queue;
struct radeon_bo *mqd_obj; struct radeon_bo *mqd_obj;
u32 doorbell_page_num; u32 doorbell_index;
u32 doorbell_offset;
unsigned wptr_offs; unsigned wptr_offs;
}; };
...@@ -2241,8 +2242,8 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, ...@@ -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); u32 r100_io_rreg(struct radeon_device *rdev, u32 reg);
void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v); void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v);
u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset); u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 index);
void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v); void cik_mm_wdoorbell(struct radeon_device *rdev, u32 index, u32 v);
/* /*
* Cast helper * Cast helper
...@@ -2305,8 +2306,8 @@ void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v); ...@@ -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 RREG32_IO(reg) r100_io_rreg(rdev, (reg))
#define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v)) #define WREG32_IO(reg, v) r100_io_wreg(rdev, (reg), (v))
#define RDOORBELL32(offset) cik_mm_rdoorbell(rdev, (offset)) #define RDOORBELL32(index) cik_mm_rdoorbell(rdev, (index))
#define WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v)) #define WDOORBELL32(index, v) cik_mm_wdoorbell(rdev, (index), (v))
/* /*
* Indirect registers accessor * Indirect registers accessor
......
...@@ -251,28 +251,23 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg) ...@@ -251,28 +251,23 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
*/ */
int radeon_doorbell_init(struct radeon_device *rdev) int radeon_doorbell_init(struct radeon_device *rdev)
{ {
int i;
/* doorbell bar mapping */ /* doorbell bar mapping */
rdev->doorbell.base = pci_resource_start(rdev->pdev, 2); rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
rdev->doorbell.size = pci_resource_len(rdev->pdev, 2); rdev->doorbell.size = pci_resource_len(rdev->pdev, 2);
/* limit to 4 MB for now */ rdev->doorbell.num_doorbells = min_t(u32, rdev->doorbell.size / sizeof(u32), RADEON_MAX_DOORBELLS);
if (rdev->doorbell.size > (4 * 1024 * 1024)) if (rdev->doorbell.num_doorbells == 0)
rdev->doorbell.size = 4 * 1024 * 1024; 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) { if (rdev->doorbell.ptr == NULL) {
return -ENOMEM; return -ENOMEM;
} }
DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base); DRM_INFO("doorbell mmio base: 0x%08X\n", (uint32_t)rdev->doorbell.base);
DRM_INFO("doorbell mmio size: %u\n", (unsigned)rdev->doorbell.size); 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; return 0;
} }
...@@ -290,40 +285,38 @@ void radeon_doorbell_fini(struct radeon_device *rdev) ...@@ -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 * @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. * Returns 0 on success or -EINVAL on failure.
*/ */
int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell) int radeon_doorbell_get(struct radeon_device *rdev, u32 *doorbell)
{ {
int i; unsigned long offset = find_first_zero_bit(rdev->doorbell.used, rdev->doorbell.num_doorbells);
if (offset < rdev->doorbell.num_doorbells) {
for (i = 0; i < rdev->doorbell.num_pages; i++) { __set_bit(offset, rdev->doorbell.used);
if (rdev->doorbell.free[i]) { *doorbell = offset;
rdev->doorbell.free[i] = false; return 0;
*doorbell = i; } else {
return 0; return -EINVAL;
}
} }
return -EINVAL;
} }
/** /**
* radeon_doorbell_free - Free a doorbell page * radeon_doorbell_free - Free a doorbell entry
* *
* @rdev: radeon_device pointer * @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) void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell)
{ {
if (doorbell < rdev->doorbell.num_pages) if (doorbell < rdev->doorbell.num_doorbells)
rdev->doorbell.free[doorbell] = true; __clear_bit(doorbell, rdev->doorbell.used);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment