mirror of
https://github.com/genesi/linux-legacy.git
synced 2026-07-08 17:56:55 +00:00
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:
@@ -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++)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user