amd-gpu: wean g12 and yamato parts off kgsl_hwaccess

Also while we're at it don't bother using the device table and many
levels of dereference to just call regread/regwrite.

No functional difference, although tiger now is not as happy as it
once was when running on imxng - on fbdev it's absolutely fine (and
marginally faster over 10 runs).

At some point we're going to find this damned race condition :]

As we are poking around, modify the Yamato idle check to use a
timeout just like QCOM do. Also, no functional difference (never
seems to time out)
This commit is contained in:
Matt Sealey
2012-11-29 08:49:20 -08:00
parent 7dc4089a61
commit a41bc9d07d
3 changed files with 143 additions and 157 deletions

View File

@@ -18,13 +18,13 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/io.h>
#include "kgsl_types.h"
#include "kgsl_hal.h"
#include "kgsl_cmdstream.h"
#include "kgsl_sharedmem.h"
#include "kgsl_driver.h"
#include "kgsl_hwaccess.h"
#include "kgsl_ioctl.h"
#include "g12_reg.h"
@@ -37,6 +37,9 @@
#define GSL_IRQ_TIMEOUT 200
int kgsl_g12_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value);
int kgsl_g12_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value);
//----------------------------------------------------------------------------
#define GSL_HAL_NUMCMDBUFFERS 5
@@ -181,7 +184,7 @@ kgsl_g12_isr(struct kgsl_device *device)
#endif // DEBUG
// determine if G12 is interrupting
device->ftbl.regread(device, (ADDR_VGC_IRQSTATUS >> 2), &status);
kgsl_g12_regread(device, (ADDR_VGC_IRQSTATUS >> 2), &status);
if (status)
{
@@ -190,8 +193,8 @@ kgsl_g12_isr(struct kgsl_device *device)
{
#ifdef _DEBUG
// obtain mh error information
device->ftbl.regread(device, ADDR_MH_MMU_PAGE_FAULT, (unsigned int *)&page_fault);
device->ftbl.regread(device, ADDR_MH_AXI_ERROR, (unsigned int *)&axi_error);
kgsl_g12_regread(device, ADDR_MH_MMU_PAGE_FAULT, (unsigned int *)&page_fault);
kgsl_g12_regread(device, ADDR_MH_AXI_ERROR, (unsigned int *)&axi_error);
#endif // DEBUG
kgsl_intr_decode(device, GSL_INTR_BLOCK_G12_MH);
@@ -214,7 +217,7 @@ kgsl_g12_tlbinvalidate(struct kgsl_device *device, unsigned int reg_invalidate,
// unreferenced formal parameter
(void) pid;
device->ftbl.regwrite(device, reg_invalidate, *(unsigned int *) &mh_mmu_invalidate);
kgsl_g12_regwrite(device, reg_invalidate, *(unsigned int *) &mh_mmu_invalidate);
#else
(void)device;
(void)reg_invalidate;
@@ -231,7 +234,7 @@ kgsl_g12_setpagetable(struct kgsl_device *device, unsigned int reg_ptbase, uint3
(void) pid;
#ifdef CONFIG_KGSL_MMU_ENABLE
device->ftbl.idle(device, GSL_TIMEOUT_DEFAULT);
device->ftbl.regwrite(device, reg_ptbase, ptbase);
kgsl_g12_regwrite(device, reg_ptbase, ptbase);
#else
(void)device;
(void)reg_ptbase;
@@ -245,7 +248,7 @@ kgsl_g12_setpagetable(struct kgsl_device *device, unsigned int reg_ptbase, uint3
static void kgsl_g12_updatetimestamp(struct kgsl_device *device)
{
unsigned int count = 0;
device->ftbl.regread(device, (ADDR_VGC_IRQ_ACTIVE_CNT >> 2), &count);
kgsl_g12_regread(device, (ADDR_VGC_IRQ_ACTIVE_CNT >> 2), &count);
count >>= 8;
count &= 255;
device->timestamp += count;
@@ -287,7 +290,7 @@ kgsl_g12_init(struct kgsl_device *device)
kgsl_hal_setpowerstate(device->id, GSL_PWRFLAGS_POWER_ON, 100);
// setup MH arbiter - MH offsets are considered to be dword based, therefore no down shift
device->ftbl.regwrite(device, ADDR_MH_ARBITER_CONFIG, KGSL_G12_CFG_G12_MHARB);
kgsl_g12_regwrite(device, ADDR_MH_ARBITER_CONFIG, KGSL_G12_CFG_G12_MHARB);
// init interrupt
status = kgsl_intr_init(device);
@@ -298,7 +301,7 @@ kgsl_g12_init(struct kgsl_device *device)
}
// enable irq
device->ftbl.regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0x3);
kgsl_g12_regwrite(device, (ADDR_VGC_IRQENABLE >> 2), 0x3);
#ifdef CONFIG_KGSL_MMU_ENABLE
// enable master interrupt for G12 MH
@@ -536,54 +539,68 @@ kgsl_g12_idle(struct kgsl_device *device, unsigned int timeout)
//----------------------------------------------------------------------------
int
kgsl_g12_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value)
int kgsl_g12_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value)
{
// G12 MH register values can only be retrieved via dedicated read registers
if ((offsetwords >= ADDR_MH_ARBITER_CONFIG && offsetwords <= ADDR_MH_AXI_HALT_CONTROL) ||
(offsetwords >= ADDR_MH_MMU_CONFIG && offsetwords <= ADDR_MH_MMU_MPU_END))
{
unsigned int *reg;
// G12 MH register values can only be retrieved via dedicated read registers
if ((offsetwords >= ADDR_MH_ARBITER_CONFIG &&
offsetwords <= ADDR_MH_AXI_HALT_CONTROL) ||
(offsetwords >= ADDR_MH_MMU_CONFIG &&
offsetwords <= ADDR_MH_MMU_MPU_END)) {
kgsl_g12_regwrite(device, (ADDR_VGC_MH_READ_ADDR >> 2), offsetwords);
#ifdef _Z180
device->ftbl.regwrite(device, (ADDR_VGC_MH_READ_ADDR >> 2), offsetwords);
kgsl_hwaccess_regread(device->id, (unsigned int) device->regspace.mmio_virt_base, (ADDR_VGC_MH_READ_ADDR >> 2), value);
reg = (unsigned int *)(device->regspace.mmio_virt_base
+ (ADDR_VGC_MH_READ_ADDR << 2));
#else
device->ftbl.regwrite(device, (ADDR_VGC_MH_READ_ADDR >> 2), offsetwords);
kgsl_hwaccess_regread(device->id, (unsigned int) device->regspace.mmio_virt_base, (ADDR_VGC_MH_DATA_ADDR >> 2), value);
reg = (unsigned int *)(device->regspace.mmio_virt_base
+ (ADDR_VGC_MH_DATA_ADDR << 2));
#endif
}
else
{
kgsl_hwaccess_regread(device->id, (unsigned int) device->regspace.mmio_virt_base, offsetwords, value);
}
} else {
if (offsetwords * sizeof(unsigned int) >= device->regspace.sizebytes) {
pr_err("g12 read invalid offset %d\n", offsetwords);
return GSL_FAILURE;//-ERANGE
}
return (GSL_SUCCESS);
reg = (unsigned int *)(device->regspace.mmio_virt_base
+ (offsetwords << 2));
}
*value = readl(reg);
return GSL_SUCCESS;
}
//----------------------------------------------------------------------------
int
kgsl_g12_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value)
int kgsl_g12_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value)
{
// G12 MH registers can only be written via the command window
if ((offsetwords >= ADDR_MH_ARBITER_CONFIG && offsetwords <= ADDR_MH_AXI_HALT_CONTROL) ||
(offsetwords >= ADDR_MH_MMU_CONFIG && offsetwords <= ADDR_MH_MMU_MPU_END))
{
kgsl_cmdwindow_write0(device->id, GSL_CMDWINDOW_MMU, offsetwords, value);
}
else
{
kgsl_hwaccess_regwrite(device->id, (unsigned int) device->regspace.mmio_virt_base, offsetwords, value);
}
unsigned int *reg;
// G12 MH registers can only be written via the command window
if ((offsetwords >= ADDR_MH_ARBITER_CONFIG &&
offsetwords <= ADDR_MH_AXI_HALT_CONTROL) ||
(offsetwords >= ADDR_MH_MMU_CONFIG &&
offsetwords <= ADDR_MH_MMU_MPU_END)) {
kgsl_cmdwindow_write0(device->id, GSL_CMDWINDOW_MMU, offsetwords, value);
} else {
if (offsetwords * sizeof(unsigned int) >= device->regspace.sizebytes) {
pr_err("g12 write invalid offset %d\n", offsetwords);
return GSL_FAILURE;//-ERANGE
}
// idle device when running in safe mode
if (device->flags & GSL_FLAGS_SAFEMODE)
{
device->ftbl.idle(device, GSL_TIMEOUT_DEFAULT);
}
reg = (unsigned int *)(device->regspace.mmio_virt_base
+ (offsetwords << 2));
writel(value, reg);
/* Drain write buffer */
dsb();
return (GSL_SUCCESS);
/* Memory fence to ensure all data has posted. On some systems,
* like 7x27, the register block is not allocated as strongly
* ordered memory. Adding a memory fence ensures ordering
* during ringbuffer submits.*/
mb();
}
return GSL_SUCCESS;
}
//----------------------------------------------------------------------------
int
@@ -619,7 +636,7 @@ kgsl_g12_waitirq(struct kgsl_device *device, gsl_intrid_t intr_id, unsigned int
kgsl_device_active(device);
INIT_COMPLETION(*comp);
device->ftbl.regread(device, (ADDR_VGC_IRQ_ACTIVE_CNT >> 2), &cntrs);
kgsl_g12_regread(device, (ADDR_VGC_IRQ_ACTIVE_CNT >> 2), &cntrs);
for (i = 0; i < GSL_G12_INTR_COUNT; i++)
{

View File

@@ -90,32 +90,4 @@ kgsl_hwaccess_memset(unsigned int gpubase, unsigned int gpuoffset, unsigned int
}
}
//----------------------------------------------------------------------------
static __inline void
kgsl_hwaccess_regread(unsigned int device_id, unsigned int gpubase, unsigned int offsetwords, unsigned int *data)
{
unsigned int *reg;
// unreferenced formal parameter
(void) device_id;
reg = (unsigned int *)(gpubase + (offsetwords << 2));
*data = readl(reg);
}
//----------------------------------------------------------------------------
static __inline void
kgsl_hwaccess_regwrite(unsigned int device_id, unsigned int gpubase, unsigned int offsetwords, unsigned int data)
{
unsigned int *reg;
// unreferenced formal parameter
(void) device_id;
reg = (unsigned int *)(gpubase + (offsetwords << 2));
writel(data, reg);
}
#endif // __GSL_HWACCESS_WINCE_MX51_H

View File

@@ -18,6 +18,7 @@
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/io.h>
#include "kgsl_types.h"
#include "kgsl_device.h"
@@ -25,7 +26,6 @@
#include "kgsl_ringbuffer.h" // needed for rb config
#include "kgsl_drawctxt.h"
#include "kgsl_cmdstream.h"
#include "kgsl_hwaccess.h"
#include "yamato_reg.h"
#include "kgsl_pm4types.h"
@@ -756,82 +756,78 @@ kgsl_yamato_setproperty(struct kgsl_device *device, gsl_property_type_t type, vo
//----------------------------------------------------------------------------
int
kgsl_yamato_idle(struct kgsl_device *device, unsigned int timeout)
int kgsl_yamato_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value)
{
int status = GSL_FAILURE;
struct kgsl_ringbuffer *rb = &device->ringbuffer;
unsigned int rbbm_status;
unsigned int *reg;
(void) timeout; // unreferenced formal parameter
if (offsetwords * sizeof(unsigned int) >= device->regspace.sizebytes) {
return GSL_FAILURE; // -ERANGE, print some debug about invalid offset
}
KGSL_DEBUG(GSL_DBGFLAGS_DUMPX, KGSL_DEBUG_DUMPX(BB_DUMP_REGPOLL, device->id, REG_RBBM_STATUS, 0x80000000, "kgsl_yamato_idle"));
reg = (unsigned int *)(device->regspace.mmio_virt_base + (offsetwords << 2));
// first, wait until the CP has consumed all the commands in the ring buffer
if (rb->flags & GSL_FLAGS_STARTED)
{
do
{
GSL_RB_GET_READPTR(rb, &rb->rptr);
*value = readl(reg);
} while (rb->rptr != rb->wptr);
}
// now, wait for the GPU to finish its operations
for ( ; ; )
{
device->ftbl.regread(device, REG_RBBM_STATUS, (unsigned int *)&rbbm_status);
// qcom uses 0x110
if (!(rbbm_status & 0x80000000))
{
status = GSL_SUCCESS;
break;
}
}
return (status);
return GSL_SUCCESS;
}
//----------------------------------------------------------------------------
int
kgsl_yamato_regread(struct kgsl_device *device, unsigned int offsetwords, unsigned int *value)
int kgsl_yamato_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value)
{
KGSL_DEBUG(GSL_DBGFLAGS_DUMPX,
{
if (!(gsl_driver.flags_debug & GSL_DBGFLAGS_DUMPX_WITHOUT_IFH))
{
if(offsetwords == REG_CP_RB_RPTR || offsetwords == REG_CP_RB_WPTR)
{
*value = device->ringbuffer.wptr;
return (GSL_SUCCESS);
}
}
});
unsigned int *reg;
kgsl_hwaccess_regread(device->id, (unsigned int) device->regspace.mmio_virt_base, offsetwords, value);
if (offsetwords * sizeof(unsigned int) >= device->regspace.sizebytes) {
return GSL_FAILURE; // -ERANGE, invalid offset
}
return (GSL_SUCCESS);
reg = (unsigned int *)(device->regspace.mmio_virt_base + (offsetwords << 2));
writel(value, reg);
return (GSL_SUCCESS);
}
//----------------------------------------------------------------------------
int
kgsl_yamato_regwrite(struct kgsl_device *device, unsigned int offsetwords, unsigned int value)
int kgsl_yamato_idle(struct kgsl_device *device, unsigned int timeout)
{
KGSL_DEBUG(GSL_DBGFLAGS_PM4, KGSL_DEBUG_DUMPREGWRITE(offsetwords, value));
int status = GSL_FAILURE;
struct kgsl_ringbuffer *rb = &device->ringbuffer;
unsigned int rbbm_status;
int idle_count = 0;
#define IDLE_COUNT_MAX 1500000
kgsl_hwaccess_regwrite(device->id, (unsigned int) device->regspace.mmio_virt_base, offsetwords, value);
(void) timeout;
// idle device when running in safe mode
if (device->flags & GSL_FLAGS_SAFEMODE)
{
device->ftbl.idle(device, GSL_TIMEOUT_DEFAULT);
}
// first, wait until the CP has consumed all the commands in the ring buffer
if (rb->flags & GSL_FLAGS_STARTED) {
do {
idle_count++;
GSL_RB_GET_READPTR(rb, &rb->rptr);
} while ((rb->rptr != rb->wptr) && (idle_count < IDLE_COUNT_MAX));
return (GSL_SUCCESS);
if (idle_count == IDLE_COUNT_MAX) {
pr_err("spun too long waiting for RB to idle\n");
// -EINVAL, now do a ringbuffer dump, mmu dump
goto done;
}
}
// now, wait for the GPU to finish its operations
for (idle_count = 0; idle_count < IDLE_COUNT_MAX; idle_count++) {
kgsl_yamato_regread(device, REG_RBBM_STATUS, &rbbm_status);
//if (!(rbbm_status & 0x80000000)) {
if (rbbm_status == 0x110) {
status = GSL_SUCCESS;
break;
}
}
if (idle_count == IDLE_COUNT_MAX) {
pr_err("spun too long waiting for rbbm status to idle\n");
// -EINVAL, now do a ringbuffer dump, mmu dump
goto done;
}
done:
return status;
}
//----------------------------------------------------------------------------
@@ -869,45 +865,46 @@ kgsl_yamato_waitirq(struct kgsl_device *device, gsl_intrid_t intr_id, unsigned i
return (status);
}
int kgsl_yamato_check_timestamp(unsigned int device_id, unsigned int timestamp)
int kgsl_yamato_check_timestamp(struct kgsl_device *device, unsigned int timestamp)
{
int i;
/* Reason to use a wait loop:
* When bus is busy, for example vpu is working too, the timestamp is
* possiblly not yet refreshed to memory by yamato. For most cases, it
* possibly not yet refreshed to memory by yamato. For most cases, it
* will hit on first loop cycle. So it don't effect performance.
*/
for (i = 0; i < 10; i++) {
if (kgsl_cmdstream_check_timestamp(device_id, timestamp))
if (kgsl_cmdstream_check_timestamp(device->id, timestamp))
return 1;
udelay(10);
}
return 0;
}
int
kgsl_yamato_waittimestamp(struct kgsl_device *device, unsigned int timestamp, unsigned int timeout)
int kgsl_yamato_waittimestamp(struct kgsl_device *device, unsigned int timestamp, unsigned int msecs)
{
#if defined GSL_RB_TIMESTAMP_INTERUPT
int status = wait_event_interruptible_timeout(device->timestamp_waitq,
kgsl_yamato_check_timestamp(device->id, timestamp),
msecs_to_jiffies(timeout));
if (status > 0)
return GSL_SUCCESS;
else
return GSL_FAILURE;
#else
return (GSL_SUCCESS);
#endif
int status = GSL_SUCCESS;
long timeout;
timeout = wait_event_interruptible_timeout(device->timestamp_waitq,
kgsl_yamato_check_timestamp(device, timestamp),
msecs_to_jiffies(msecs));
if (timeout > 0)
status = GSL_SUCCESS; // 0
else if (timeout == 0) {
// check timestamp?
status = GSL_FAILURE; // -ETIMEDOUT
// register dump?
}
return status;
}
//----------------------------------------------------------------------------
int
kgsl_yamato_runpending(struct kgsl_device *device)
int kgsl_yamato_runpending(struct kgsl_device *device)
{
(void) device;
return (GSL_SUCCESS);
(void) device;
return GSL_SUCCESS;
}
//----------------------------------------------------------------------------