[PATCH 051/165] drm/radeon: implement simple doorbell page allocator
Jerome Glisse
j.glisse at gmail.com
Wed Jun 26 05:57:28 PDT 2013
On Wed, Jun 26, 2013 at 09:22:11AM -0400, alexdeucher at gmail.com wrote:
> From: Alex Deucher <alexander.deucher at amd.com>
>
> 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.
This doorbell stuff is cryptic, is that some memory on the GPU ? Or is it
more like a register file ? ie what is backing the pci bar.
Also probably want to use bitmap as i dont think gcc will turn bool array
into a bitmap.
Cheers,
Jerome
>
> Signed-off-by: Alex Deucher <alexander.deucher at amd.com>
> ---
> drivers/gpu/drm/radeon/cik.c | 38 +++++++++++++
> drivers/gpu/drm/radeon/radeon.h | 21 +++++++
> drivers/gpu/drm/radeon/radeon_device.c | 94 ++++++++++++++++++++++++++++++++
> 3 files changed, 153 insertions(+), 0 deletions(-)
>
> diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
> index bb7dbc4..5c28fa5 100644
> --- a/drivers/gpu/drm/radeon/cik.c
> +++ b/drivers/gpu/drm/radeon/cik.c
> @@ -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] =
> diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
> index ad4e68a..a2a3430 100644
> --- a/drivers/gpu/drm/radeon/radeon.h
> +++ b/drivers/gpu/drm/radeon/radeon.h
> @@ -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.
> @@ -1711,6 +1725,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;
> @@ -1784,6 +1799,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
> */
> @@ -1833,6 +1851,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
> */
> diff --git a/drivers/gpu/drm/radeon/radeon_device.c b/drivers/gpu/drm/radeon/radeon_device.c
> index 4e97ff7..82335e3 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);
> }
>
> --
> 1.7.7.5
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel
More information about the dri-devel
mailing list