hw_addr, cur_addr, next_addr);
return -1;
}
+ if ((cur_addr < hw_addr) && (next_addr >= hw_addr))
+ msleep(1);
} while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
return 0;
}
}
if (dev_priv->ring.virtual_start != NULL) {
- DRM_ERROR("%s called again without calling cleanup\n",
- __FUNCTION__);
+ DRM_ERROR("called again without calling cleanup\n");
return -EFAULT;
}
if (!dev->agp || !dev->agp->base) {
- DRM_ERROR("%s called with no agp memory available\n",
- __FUNCTION__);
+ DRM_ERROR("called with no agp memory available\n");
return -EFAULT;
}
return 0;
}
-static int via_dma_init(DRM_IOCTL_ARGS)
+static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
- drm_via_dma_init_t init;
+ drm_via_dma_init_t *init = data;
int retcode = 0;
- DRM_COPY_FROM_USER_IOCTL(init, (drm_via_dma_init_t __user *) data,
- sizeof(init));
-
- switch (init.func) {
+ switch (init->func) {
case VIA_INIT_DMA:
if (!DRM_SUSER(DRM_CURPROC))
retcode = -EPERM;
else
- retcode = via_initialize(dev, dev_priv, &init);
+ retcode = via_initialize(dev, dev_priv, init);
break;
case VIA_CLEANUP_DMA:
if (!DRM_SUSER(DRM_CURPROC))
dev_priv = (drm_via_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start == NULL) {
- DRM_ERROR("%s called without initializing AGP ring buffer.\n",
- __FUNCTION__);
+ DRM_ERROR("called without initializing AGP ring buffer.\n");
return -EFAULT;
}
return 0;
}
-static int via_flush_ioctl(DRM_IOCTL_ARGS)
+static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
LOCK_TEST_WITH_RETURN(dev, file_priv);
return via_driver_dma_quiescent(dev);
}
-static int via_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_cmdbuffer_t cmdbuf;
+ drm_via_cmdbuffer_t *cmdbuf = data;
int ret;
LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
- sizeof(cmdbuf));
-
- DRM_DEBUG("via cmdbuffer, buf %p size %lu\n", cmdbuf.buf, cmdbuf.size);
+ DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
- ret = via_dispatch_cmdbuffer(dev, &cmdbuf);
+ ret = via_dispatch_cmdbuffer(dev, cmdbuf);
if (ret) {
return ret;
}
return ret;
}
-static int via_pci_cmdbuffer(DRM_IOCTL_ARGS)
+static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_cmdbuffer_t cmdbuf;
+ drm_via_cmdbuffer_t *cmdbuf = data;
int ret;
LOCK_TEST_WITH_RETURN(dev, file_priv);
- DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_via_cmdbuffer_t __user *) data,
- sizeof(cmdbuf));
-
- DRM_DEBUG("via_pci_cmdbuffer, buf %p size %lu\n", cmdbuf.buf,
- cmdbuf.size);
+ DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
- ret = via_dispatch_pci_cmdbuffer(dev, &cmdbuf);
+ ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf);
if (ret) {
return ret;
}
}
/*
- * This function is used internally by ring buffer mangement code.
+ * This function is used internally by ring buffer management code.
*
* Returns virtual pointer to ring buffer.
*/
int paused, count;
volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
uint32_t reader,ptr;
+ uint32_t diff;
paused = 0;
via_flush_write_combine();
(void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1);
+
*paused_at = pause_addr_lo;
via_flush_write_combine();
(void) *paused_at;
+
reader = *(dev_priv->hw_addr_ptr);
ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
+
dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
- if ((ptr - reader) <= dev_priv->dma_diff ) {
- count = 10000000;
- while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
+ /*
+ * If there is a possibility that the command reader will
+ * miss the new pause address and pause on the old one,
+ * In that case we need to program the new start address
+ * using PCI.
+ */
+
+ diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
+ count = 10000000;
+ while(diff == 0 && count--) {
+ paused = (VIA_READ(0x41c) & 0x80000000);
+ if (paused)
+ break;
+ reader = *(dev_priv->hw_addr_ptr);
+ diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
}
+ paused = VIA_READ(0x41c) & 0x80000000;
+
if (paused && !no_pci_fire) {
reader = *(dev_priv->hw_addr_ptr);
- if ((ptr - reader) == dev_priv->dma_diff) {
-
+ 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) {
/*
* There is a concern that these writes may stall the PCI bus
* if the GPU is not idle. However, idling the GPU first
uint32_t pause_addr_lo, pause_addr_hi;
uint32_t jump_addr_lo, jump_addr_hi;
volatile uint32_t *last_pause_ptr;
+ uint32_t dma_low_save1, dma_low_save2;
agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
&pause_addr_lo, 0);
*last_pause_ptr = pause_addr_lo;
+ dma_low_save1 = dev_priv->dma_low;
+
+ /*
+ * Now, set a trap that will pause the regulator if it tries to rerun the old
+ * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
+ * and reissues the jump command over PCI, while the regulator has already taken the jump
+ * and actually paused at the current buffer end).
+ * There appears to be no other way to detect this condition, since the hw_addr_pointer
+ * does not seem to get updated immediately when a jump occurs.
+ */
- via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0);
+ last_pause_ptr =
+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
+ &pause_addr_lo, 0) - 1;
+ via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
+ &pause_addr_lo, 0);
+ *last_pause_ptr = pause_addr_lo;
+
+ dma_low_save2 = dev_priv->dma_low;
+ dev_priv->dma_low = dma_low_save1;
+ via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0);
+ dev_priv->dma_low = dma_low_save2;
+ via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
}
* User interface to the space and lag functions.
*/
-static int via_cmdbuf_size(DRM_IOCTL_ARGS)
+static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
- DRM_DEVICE;
- drm_via_cmdbuf_size_t d_siz;
+ drm_via_cmdbuf_size_t *d_siz = data;
int ret = 0;
uint32_t tmp_size, count;
drm_via_private_t *dev_priv;
- DRM_DEBUG("via cmdbuf_size\n");
+ DRM_DEBUG("\n");
LOCK_TEST_WITH_RETURN(dev, file_priv);
dev_priv = (drm_via_private_t *) dev->dev_private;
if (dev_priv->ring.virtual_start == NULL) {
- DRM_ERROR("%s called without initializing AGP ring buffer.\n",
- __FUNCTION__);
+ DRM_ERROR("called without initializing AGP ring buffer.\n");
return -EFAULT;
}
- DRM_COPY_FROM_USER_IOCTL(d_siz, (drm_via_cmdbuf_size_t __user *) data,
- sizeof(d_siz));
-
count = 1000000;
- tmp_size = d_siz.size;
- switch (d_siz.func) {
+ tmp_size = d_siz->size;
+ switch (d_siz->func) {
case VIA_CMDBUF_SPACE:
- while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz.size)
+ while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size)
&& count--) {
- if (!d_siz.wait) {
+ if (!d_siz->wait) {
break;
}
}
}
break;
case VIA_CMDBUF_LAG:
- while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz.size)
+ while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size)
&& count--) {
- if (!d_siz.wait) {
+ if (!d_siz->wait) {
break;
}
}
default:
ret = -EFAULT;
}
- d_siz.size = tmp_size;
+ d_siz->size = tmp_size;
- DRM_COPY_TO_USER_IOCTL((drm_via_cmdbuf_size_t __user *) data, d_siz,
- sizeof(d_siz));
return ret;
}
-drm_ioctl_desc_t via_ioctls[] = {
- [DRM_IOCTL_NR(DRM_VIA_ALLOCMEM)] = {via_mem_alloc, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_FREEMEM)] = {via_mem_free, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_AGP_INIT)] = {via_agp_init, DRM_AUTH|DRM_MASTER},
- [DRM_IOCTL_NR(DRM_VIA_FB_INIT)] = {via_fb_init, DRM_AUTH|DRM_MASTER},
- [DRM_IOCTL_NR(DRM_VIA_MAP_INIT)] = {via_map_init, DRM_AUTH|DRM_MASTER},
- [DRM_IOCTL_NR(DRM_VIA_DEC_FUTEX)] = {via_decoder_futex, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_DMA_INIT)] = {via_dma_init, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_CMDBUFFER)] = {via_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_FLUSH)] = {via_flush_ioctl, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_PCICMD)] = {via_pci_cmdbuffer, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_CMDBUF_SIZE)] = {via_cmdbuf_size, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_WAIT_IRQ)] = {via_wait_irq, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_DMA_BLIT)] = {via_dma_blit, DRM_AUTH},
- [DRM_IOCTL_NR(DRM_VIA_BLIT_SYNC)] = {via_dma_blit_sync, DRM_AUTH}
+struct drm_ioctl_desc via_ioctls[] = {
+ DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER),
+ DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH),
+ DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH)
};
int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls);