[patch] via_dma.c
Ian FREISLICH
ianf at clue.co.za
Wed Oct 27 08:01:10 UTC 2010
Hi
While trying to make googleearth work on a Via Epia LN board with
openchrome and GL we noticed that the X server crashed after about
30 seconds of use. I got a flood of the following messages.
Oct 26 12:13:24 test kernel: error: [drm:pid97391:via_hook_segment] *ERROR*
Paused at incorrect address. 0xe1fcf300, 0xe1fc4900 0x00000000
Oct 26 12:13:24 test kernel: error: [drm:pid97391:via_hook_segment] *ERROR*
Paused at incorrect address. 0xe1fd0300, 0xe1fc4900 0x00000000
Oct 26 12:13:24 test kernel: error: [drm:pid97391:via_cmdbuf_size] *ERROR*
VIA_CMDBUF_LAG timed out.
Some research showed that occasionally the GPU pauses and when the
pipe is restarted, commands are reordered and the next command after
the paused command is dropped.
I located a patch which I hand applied because every chunk failed.
It has fixed the stability issue and gpu pipe restarting issue.
I still have a problem with googleearth only displaying its image
in part of the window. It looks like the plane size is correct but
it gets the offset wrong so there is a blank on the right side the
size of the left menu pane and a blank at the bottom the size of
the window bar and menu bar at the top of the window.
Do you have any ideas how to fix this?
Ian
--
Ian Freislich
-------------- next part --------------
Index: sys/dev/drm/via_dma.c
===================================================================
RCS file: /home/ncvs/src/sys/dev/drm/via_dma.c,v
retrieving revision 1.2
diff -u -d -r1.2 via_dma.c
--- sys/dev/drm/via_dma.c 22 Apr 2010 18:21:25 -0000 1.2
+++ sys/dev/drm/via_dma.c 26 Oct 2010 15:03:04 -0000
@@ -119,10 +119,12 @@
uint32_t count;
hw_addr_ptr = dev_priv->hw_addr_ptr;
cur_addr = dev_priv->dma_low;
- next_addr = cur_addr + size + 512 * 1024;
+ next_addr = cur_addr + size + 64 * 1024;
count = 1000000;
do {
- hw_addr = *hw_addr_ptr - agp_base;
+ (void) *hw_addr_ptr;
+ DRM_MEMORYBARRIER();
+ hw_addr = (*hw_addr_ptr - agp_base);
if (count-- == 0) {
DRM_ERROR
("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n",
@@ -272,7 +274,9 @@
{
drm_via_private_t *dev_priv;
uint32_t *vb;
+#if 0
int ret;
+#endif
dev_priv = (drm_via_private_t *) dev->dev_private;
@@ -285,7 +289,12 @@
return -ENOMEM;
}
- if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
+ vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
+ if (vb == NULL) {
+ return -EAGAIN;
+ }
+
+ if (DRM_COPY_FROM_USER(vb, cmd->buf, cmd->size))
return -EFAULT;
/*
@@ -294,19 +303,15 @@
* copy it to AGP memory when ready.
*/
+#if 0
if ((ret =
via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
cmd->size, dev, 1))) {
return ret;
}
- vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
- if (vb == NULL) {
- return -EAGAIN;
- }
-
memcpy(vb, dev_priv->pci_buf, cmd->size);
-
+#endif
dev_priv->dma_low += cmd->size;
/*
@@ -467,11 +472,28 @@
reader = *(dev_priv->hw_addr_ptr);
diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
diff &= (dev_priv->dma_high - 1);
- if (diff != 0 && diff < (dev_priv->dma_high >> 1)) {
- DRM_ERROR("Paused at incorrect address. "
- "0x%08x, 0x%08x 0x%08x\n",
- ptr, reader, dev_priv->dma_diff);
- } else if (diff == 0) {
+ if (diff < (dev_priv->dma_high >> 1)) {
+ if (diff != 0) {
+ volatile uint32_t *rekick;
+
+ DRM_INFO("Paused at incorrect address. "
+ "0x%08x, 0x%08x 0x%08x. Restarting.\n",
+ ptr, reader, dev_priv->dma_diff);
+
+ /*
+ * Obtain the new pause address the command
+ * reader was supposed to pick up.
+ */
+
+ rekick = (volatile uint32_t *)
+ dev_priv->dma_ptr +
+ ((reader - dev_priv->dma_offset -
+ (uint32_t) dev_priv->agpAddr +
+ dev_priv->dma_diff - 4) >> 2);
+ pause_addr_lo = *rekick;
+ pause_addr_hi = *(--rekick);
+ }
+
/*
* There is a concern that these writes may stall the PCI bus
* if the GPU is not idle. However, idling the GPU first
@@ -612,13 +634,16 @@
{
uint32_t agp_base;
uint32_t pause_addr_lo, pause_addr_hi;
- uint32_t jump_addr_lo, jump_addr_hi;
- volatile uint32_t *last_pause_ptr;
+ uint32_t jump_addr_lo, jump_addr_hi, hook_addr;
+ volatile uint32_t *hook_ptr;
uint32_t dma_low_save1, dma_low_save2;
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
+ hook_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0,
+ &jump_addr_hi, &jump_addr_lo, 0);
via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
- &jump_addr_lo, 0);
+ &hook_addr, 0);
+ *(--hook_ptr) = hook_addr;
dev_priv->dma_wrap = dev_priv->dma_low;
@@ -634,13 +659,13 @@
via_dummy_bitblt(dev_priv);
via_dummy_bitblt(dev_priv);
- last_pause_ptr =
+ hook_ptr =
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0) - 1;
+ &pause_addr_lo, 0);
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
&pause_addr_lo, 0);
- *last_pause_ptr = pause_addr_lo;
+ *(--hook_ptr) = pause_addr_lo;
dma_low_save1 = dev_priv->dma_low;
/*
@@ -652,12 +677,12 @@
* does not seem to get updated immediately when a jump occurs.
*/
- last_pause_ptr =
+ hook_ptr =
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
- &pause_addr_lo, 0) - 1;
+ &pause_addr_lo, 0);
via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
&pause_addr_lo, 0);
- *last_pause_ptr = pause_addr_lo;
+ *(--hook_ptr) = pause_addr_lo;
dma_low_save2 = dev_priv->dma_low;
dev_priv->dma_low = dma_low_save1;
@@ -674,9 +699,16 @@
static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type)
{
- uint32_t pause_addr_lo, pause_addr_hi;
+ uint32_t pause_addr_lo, pause_addr_hi, hook;
+ volatile uint32_t *hook_addr;
- via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0);
+ hook_addr = via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0);
+#if 1
+ if (cmd_type == HC_HAGPBpID_PAUSE) {
+ via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &hook, 0);
+ *(--hook_addr) = hook;
+ }
+#endif
via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
}
More information about the freebsd-current
mailing list