Message ID | 1372253045-17042-52-git-send-email-alexdeucher@gmail.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
On Wed, Jun 26, 2013 at 09:22:11AM -0400, alexdeucher@gmail.com wrote: > From: Alex Deucher <alexander.deucher@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@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@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/dri-devel
On Wed, Jun 26, 2013 at 8:57 AM, Jerome Glisse <j.glisse@gmail.com> wrote: > On Wed, Jun 26, 2013 at 09:22:11AM -0400, alexdeucher@gmail.com wrote: >> From: Alex Deucher <alexander.deucher@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. > There's no memory backing it. It's just an aperture that the GPU can selectively listens to. You assign dw offsets from the doorbell aperture for things like the wrptr for compute rings. When the driver or process write a new wtpr value to the offset assigned to it's specific ring, the GPU starts processing it. Like ringing a doorbell. Alex > 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@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@lists.freedesktop.org >> http://lists.freedesktop.org/mailman/listinfo/dri-devel
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); }