[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