On Wed, Jun 26, 2013 at 09:22:11AM -0400, alexdeucher@xxxxxxxxx wrote: > From: Alex Deucher <alexander.deucher@xxxxxxx> > > 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@xxxxxxx> > --- > 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@xxxxxxxxxxxxxxxxxxxxx > http://lists.freedesktop.org/mailman/listinfo/dri-devel _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/dri-devel