Commit 75efdee1 authored by Alex Deucher's avatar Alex Deucher
Browse files

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: default avatarAlex Deucher <alexander.deucher@amd.com>
parent f93bdefe
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -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] =
+21 −0
Original line number Diff line number Diff line
@@ -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
 */
+94 −0
Original line number Diff line number Diff line
@@ -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);
}