Fix GE shut-down sequence.
When the GE is shut down, an empty command packet without a begin-link must be sent. After this command is sent, wait for the hardware to go idle. Finally, turn off the GE and disable MMIO.main
parent
01628a430d
commit
2fc697a7d2
|
@ -29,7 +29,7 @@
|
|||
#include "xgi_misc.h"
|
||||
#include "xgi_cmdlist.h"
|
||||
|
||||
static void addFlush2D(struct xgi_info * info);
|
||||
static void xgi_emit_flush(struct xgi_info * info, bool link);
|
||||
static unsigned int get_batch_command(enum xgi_batch_type type);
|
||||
static void triggerHWCommandList(struct xgi_info * info);
|
||||
static void xgi_cmdlist_reset(struct xgi_info * info);
|
||||
|
@ -120,7 +120,7 @@ int xgi_submit_cmdlist(struct drm_device * dev, void * data,
|
|||
DRM_DEBUG("info->cmdring.last_ptr != NULL\n");
|
||||
|
||||
if (pCmdInfo->type == BTYPE_3D) {
|
||||
addFlush2D(info);
|
||||
xgi_emit_flush(info, TRUE);
|
||||
}
|
||||
|
||||
info->cmdring.last_ptr[1] = begin[1];
|
||||
|
@ -190,9 +190,18 @@ void xgi_cmdlist_reset(struct xgi_info * info)
|
|||
info->cmdring.ring_offset = 0;
|
||||
}
|
||||
|
||||
|
||||
void xgi_cmdlist_cleanup(struct xgi_info * info)
|
||||
{
|
||||
if (info->cmdring.ring_hw_base != 0) {
|
||||
/* If command lists have been issued, terminate the command
|
||||
* list chain with a flush command.
|
||||
*/
|
||||
if (info->cmdring.last_ptr != NULL) {
|
||||
xgi_emit_flush(info, FALSE);
|
||||
xgi_waitfor_pci_idle(info);
|
||||
}
|
||||
|
||||
xgi_pcie_free(info, info->cmdring.ring_gart_base, NULL);
|
||||
info->cmdring.ring_hw_base = 0;
|
||||
info->cmdring.ring_offset = 0;
|
||||
|
@ -210,32 +219,43 @@ static void triggerHWCommandList(struct xgi_info * info)
|
|||
}
|
||||
|
||||
|
||||
static void addFlush2D(struct xgi_info * info)
|
||||
/**
|
||||
* Emit a flush to the CRTL command stream.
|
||||
* @info XGI info structure
|
||||
* @link Emit (or don't emit) link information at start of flush command.
|
||||
*
|
||||
* This function assumes info->cmdring.ptr is non-NULL.
|
||||
*/
|
||||
static void xgi_emit_flush(struct xgi_info * info, bool link)
|
||||
{
|
||||
u32 *flushBatchVirtAddr;
|
||||
u32 flushBatchHWAddr;
|
||||
static const u32 flush_command[8] = {
|
||||
(0x10 << 24),
|
||||
BEGIN_LINK_ENABLE_MASK | (0x00004),
|
||||
0x00000000, 0x00000000,
|
||||
|
||||
/* Flush everything with the default 32 clock delay.
|
||||
*/
|
||||
0x003fffff, 0x003fffff, 0x003fffff, 0x003fffff
|
||||
};
|
||||
const unsigned int base = (link) ? 0 : 4;
|
||||
const unsigned int flush_size = (8 - base) * sizeof(u32);
|
||||
u32 *batch_addr;
|
||||
u32 hw_addr;
|
||||
|
||||
/* check buf is large enough to contain a new flush batch */
|
||||
if ((info->cmdring.ring_offset + 0x20) >= info->cmdring.size) {
|
||||
if ((info->cmdring.ring_offset + flush_size) >= info->cmdring.size) {
|
||||
info->cmdring.ring_offset = 0;
|
||||
}
|
||||
|
||||
flushBatchHWAddr = info->cmdring.ring_hw_base + info->cmdring.ring_offset;
|
||||
flushBatchVirtAddr = info->cmdring.ptr
|
||||
hw_addr = info->cmdring.ring_hw_base
|
||||
+ info->cmdring.ring_offset;
|
||||
batch_addr = info->cmdring.ptr
|
||||
+ (info->cmdring.ring_offset / 4);
|
||||
|
||||
/* not using memcpy for I assume the address is discrete */
|
||||
*(flushBatchVirtAddr + 0) = 0x10000000;
|
||||
*(flushBatchVirtAddr + 1) = 0x80000004; /* size = 0x04 dwords */
|
||||
*(flushBatchVirtAddr + 2) = 0x00000000;
|
||||
*(flushBatchVirtAddr + 3) = 0x00000000;
|
||||
*(flushBatchVirtAddr + 4) = FLUSH_2D;
|
||||
*(flushBatchVirtAddr + 5) = FLUSH_2D;
|
||||
*(flushBatchVirtAddr + 6) = FLUSH_2D;
|
||||
*(flushBatchVirtAddr + 7) = FLUSH_2D;
|
||||
(void) memcpy(batch_addr, & flush_command[base], flush_size);
|
||||
|
||||
info->cmdring.last_ptr[1] = BEGIN_LINK_ENABLE_MASK + 0x08;
|
||||
info->cmdring.last_ptr[2] = flushBatchHWAddr >> 4;
|
||||
info->cmdring.last_ptr[1] = BEGIN_LINK_ENABLE_MASK | (flush_size / 4);
|
||||
info->cmdring.last_ptr[2] = hw_addr >> 4;
|
||||
info->cmdring.last_ptr[3] = 0;
|
||||
wmb();
|
||||
info->cmdring.last_ptr[0] = (get_batch_command(BTYPE_CTRL) << 24)
|
||||
|
@ -243,6 +263,6 @@ static void addFlush2D(struct xgi_info * info)
|
|||
|
||||
triggerHWCommandList(info);
|
||||
|
||||
info->cmdring.ring_offset += 0x20;
|
||||
info->cmdring.last_ptr = flushBatchVirtAddr;
|
||||
info->cmdring.ring_offset += flush_size;
|
||||
info->cmdring.last_ptr = (link) ? batch_addr : NULL;
|
||||
}
|
||||
|
|
|
@ -242,6 +242,12 @@ void xgi_driver_lastclose(struct drm_device * dev)
|
|||
struct xgi_info * info = dev->dev_private;
|
||||
|
||||
if (info != NULL) {
|
||||
if (info->mmio_map != NULL) {
|
||||
xgi_cmdlist_cleanup(info);
|
||||
xgi_disable_ge(info);
|
||||
xgi_disable_mmio(info);
|
||||
}
|
||||
|
||||
/* The core DRM lastclose routine will destroy all of our
|
||||
* mappings for us. NULL out the pointers here so that
|
||||
* xgi_bootstrap can do the right thing.
|
||||
|
@ -250,8 +256,6 @@ void xgi_driver_lastclose(struct drm_device * dev)
|
|||
info->mmio_map = NULL;
|
||||
info->fb_map = NULL;
|
||||
|
||||
xgi_cmdlist_cleanup(info);
|
||||
|
||||
if (info->fb_heap.initialized) {
|
||||
xgi_mem_heap_cleanup(&info->fb_heap);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue