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>
This commit is contained in:
parent
f93bdefe62
commit
75efdee11b
|
@ -121,6 +121,44 @@ u32 cik_get_xclk(struct radeon_device *rdev)
|
|||
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
|
||||
|
||||
static const u32 bonaire_io_mc_regs[BONAIRE_IO_MC_REGS_SIZE][2] =
|
||||
|
|
|
@ -556,6 +556,20 @@ struct radeon_scratch {
|
|||
int radeon_scratch_get(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.
|
||||
|
@ -1710,6 +1724,7 @@ struct radeon_device {
|
|||
struct radeon_gart gart;
|
||||
struct radeon_mode_info mode_info;
|
||||
struct radeon_scratch scratch;
|
||||
struct radeon_doorbell doorbell;
|
||||
struct radeon_mman mman;
|
||||
struct radeon_fence_driver fence_drv[RADEON_NUM_RINGS];
|
||||
wait_queue_head_t fence_queue;
|
||||
|
@ -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);
|
||||
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
|
||||
*/
|
||||
|
@ -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 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
|
||||
*/
|
||||
|
|
|
@ -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_*()
|
||||
* 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,
|
|||
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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue