Commit 75efdee1 authored by Alex Deucher's avatar Alex Deucher

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: default avatarAlex Deucher <alexander.deucher@amd.com>
parent f93bdefe
...@@ -121,6 +121,44 @@ u32 cik_get_xclk(struct radeon_device *rdev) ...@@ -121,6 +121,44 @@ u32 cik_get_xclk(struct radeon_device *rdev)
return reference_clock; return reference_clock;
} }
/**
* cik_mm_rdoorbell - read a doorbell dword
*
* @rdev: radeon_device pointer
* @offset: byte offset into the aperture
*
* Returns the value in the doorbell aperture at the
* requested offset (CIK).
*/
u32 cik_mm_rdoorbell(struct radeon_device *rdev, u32 offset)
{
if (offset < rdev->doorbell.size) {
return readl(((void __iomem *)rdev->doorbell.ptr) + offset);
} else {
DRM_ERROR("reading beyond doorbell aperture: 0x%08x!\n", offset);
return 0;
}
}
/**
* cik_mm_wdoorbell - write a doorbell dword
*
* @rdev: radeon_device pointer
* @offset: byte offset into the aperture
* @v: value to write
*
* Writes @v to the doorbell aperture at the
* requested offset (CIK).
*/
void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v)
{
if (offset < rdev->doorbell.size) {
writel(v, ((void __iomem *)rdev->doorbell.ptr) + offset);
} else {
DRM_ERROR("writing beyond doorbell aperture: 0x%08x!\n", offset);
}
}
#define BONAIRE_IO_MC_REGS_SIZE 36 #define BONAIRE_IO_MC_REGS_SIZE 36
static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] = static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
......
...@@ -556,6 +556,20 @@ struct radeon_scratch { ...@@ -556,6 +556,20 @@ struct radeon_scratch {
int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg); int radeon_scratch_get(struct radeon_device *rdev, uint32_t *reg);
void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg); void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg);
/*
* GPU doorbell structures, functions & helpers
*/
struct radeon_doorbell {
u32 num_pages;
bool free[1024];
/* doorbell mmio */
resource_size_t base;
resource_size_t size;
void __iomem *ptr;
};
int radeon_doorbell_get(struct radeon_device *rdev, u32 *page);
void radeon_doorbell_free(struct radeon_device *rdev, u32 doorbell);
/* /*
* IRQS. * IRQS.
...@@ -1710,6 +1724,7 @@ struct radeon_device { ...@@ -1710,6 +1724,7 @@ struct radeon_device {
struct radeon_gart gart; struct radeon_gart gart;
struct radeon_mode_info mode_info; struct radeon_mode_info mode_info;
struct radeon_scratch scratch; struct radeon_scratch scratch;
struct radeon_doorbell doorbell;
struct radeon_mman mman; struct radeon_mman mman;
struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS]; struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS];
wait_queue_head_t fence_queue; wait_queue_head_t fence_queue;
...@@ -1783,6 +1798,9 @@ void r100_mm_wreg(struct radeon_device *rdev, uint32_t reg, uint32_t v, ...@@ -1783,6 +1798,9 @@ 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);
void cik_mm_wdoorbell(struct radeon_device *rdev, u32 offset, u32 v);
/* /*
* Cast helper * Cast helper
*/ */
...@@ -1832,6 +1850,9 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, u32 v); ...@@ -1832,6 +1850,9 @@ void r100_io_wreg(struct radeon_device *rdev, u32 reg, 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 WDOORBELL32(offset, v) cik_mm_wdoorbell(rdev, (offset), (v))
/* /*
* Indirect registers accessor * Indirect registers accessor
*/ */
......
...@@ -231,6 +231,94 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg) ...@@ -231,6 +231,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_*() * radeon_wb_*()
* Writeback is the the method by which the the GPU updates special pages * Writeback is the the method by which the the GPU updates special pages
...@@ -1162,6 +1250,10 @@ int radeon_device_init(struct radeon_device *rdev, ...@@ -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 base: 0x%08X\n", (uint32_t)rdev->rmmio_base);
DRM_INFO("register mmio size: %u\n", (unsigned)rdev->rmmio_size); 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 */ /* io port mapping */
for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) { if (pci_resource_flags(rdev->pdev, i) & IORESOURCE_IO) {
...@@ -1239,6 +1331,8 @@ void radeon_device_fini(struct radeon_device *rdev) ...@@ -1239,6 +1331,8 @@ void radeon_device_fini(struct radeon_device *rdev)
rdev->rio_mem = NULL; rdev->rio_mem = NULL;
iounmap(rdev->rmmio); iounmap(rdev->rmmio);
rdev->rmmio = NULL; rdev->rmmio = NULL;
if (rdev->family >= CHIP_BONAIRE)
radeon_doorbell_fini(rdev);
radeon_debugfs_remove_files(rdev); radeon_debugfs_remove_files(rdev);
} }
......
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