Commit ff69c00f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6

* 'drm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied/drm-2.6:
  drm/ati_pcigart: fix the PCIGART to use drm_pci to allocate GART table.
  drm/radeon: fixup RV550 chip family
  drm/via: attempt again to stabilise the AGP DMA command submission.
  drm: Fix race that can lockup the kernel
parents 9e585824 b05c2385
...@@ -35,42 +35,23 @@ ...@@ -35,42 +35,23 @@
# define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */
static void *drm_ati_alloc_pcigart_table(int order) static int drm_ati_alloc_pcigart_table(struct drm_device *dev,
struct drm_ati_pcigart_info *gart_info)
{ {
unsigned long address; gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size,
struct page *page; PAGE_SIZE,
int i; gart_info->table_mask);
if (gart_info->table_handle == NULL)
DRM_DEBUG("%d order\n", order); return -ENOMEM;
address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
order);
if (address == 0UL) {
return NULL;
}
page = virt_to_page(address);
for (i = 0; i < order; i++, page++)
SetPageReserved(page);
DRM_DEBUG("returning 0x%08lx\n", address); return 0;
return (void *)address;
} }
static void drm_ati_free_pcigart_table(void *address, int order) static void drm_ati_free_pcigart_table(struct drm_device *dev,
struct drm_ati_pcigart_info *gart_info)
{ {
struct page *page; drm_pci_free(dev, gart_info->table_handle);
int i; gart_info->table_handle = NULL;
int num_pages = 1 << order;
DRM_DEBUG("\n");
page = virt_to_page((unsigned long)address);
for (i = 0; i < num_pages; i++, page++)
ClearPageReserved(page);
free_pages((unsigned long)address, order);
} }
int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
...@@ -78,8 +59,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info ...@@ -78,8 +59,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info
struct drm_sg_mem *entry = dev->sg; struct drm_sg_mem *entry = dev->sg;
unsigned long pages; unsigned long pages;
int i; int i;
int order; int max_pages;
int num_pages, max_pages;
/* we need to support large memory configurations */ /* we need to support large memory configurations */
if (!entry) { if (!entry) {
...@@ -87,15 +67,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info ...@@ -87,15 +67,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info
return 0; return 0;
} }
order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE);
num_pages = 1 << order;
if (gart_info->bus_addr) { if (gart_info->bus_addr) {
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
pci_unmap_single(dev->pdev, gart_info->bus_addr,
num_pages * PAGE_SIZE,
PCI_DMA_TODEVICE);
}
max_pages = (gart_info->table_size / sizeof(u32)); max_pages = (gart_info->table_size / sizeof(u32));
pages = (entry->pages <= max_pages) pages = (entry->pages <= max_pages)
...@@ -112,10 +84,9 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info ...@@ -112,10 +84,9 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info
gart_info->bus_addr = 0; gart_info->bus_addr = 0;
} }
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN if (gart_info->gart_table_location == DRM_ATI_GART_MAIN &&
&& gart_info->addr) { gart_info->table_handle) {
drm_ati_free_pcigart_table(gart_info->addr, order); drm_ati_free_pcigart_table(dev, gart_info);
gart_info->addr = NULL;
} }
return 1; return 1;
...@@ -127,11 +98,10 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga ...@@ -127,11 +98,10 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
struct drm_sg_mem *entry = dev->sg; struct drm_sg_mem *entry = dev->sg;
void *address = NULL; void *address = NULL;
unsigned long pages; unsigned long pages;
u32 *pci_gart, page_base, bus_address = 0; u32 *pci_gart, page_base;
dma_addr_t bus_address = 0;
int i, j, ret = 0; int i, j, ret = 0;
int order;
int max_pages; int max_pages;
int num_pages;
if (!entry) { if (!entry) {
DRM_ERROR("no scatter/gather memory!\n"); DRM_ERROR("no scatter/gather memory!\n");
...@@ -141,31 +111,14 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga ...@@ -141,31 +111,14 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga
if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
order = drm_order((gart_info->table_size + ret = drm_ati_alloc_pcigart_table(dev, gart_info);
(PAGE_SIZE-1)) / PAGE_SIZE); if (ret) {
num_pages = 1 << order;
address = drm_ati_alloc_pcigart_table(order);
if (!address) {
DRM_ERROR("cannot allocate PCI GART page!\n"); DRM_ERROR("cannot allocate PCI GART page!\n");
goto done; goto done;
} }
if (!dev->pdev) { address = gart_info->table_handle->vaddr;
DRM_ERROR("PCI device unknown!\n"); bus_address = gart_info->table_handle->busaddr;
goto done;
}
bus_address = pci_map_single(dev->pdev, address,
num_pages * PAGE_SIZE,
PCI_DMA_TODEVICE);
if (bus_address == 0) {
DRM_ERROR("unable to map PCIGART pages!\n");
order = drm_order((gart_info->table_size +
(PAGE_SIZE-1)) / PAGE_SIZE);
drm_ati_free_pcigart_table(address, order);
address = NULL;
goto done;
}
} else { } else {
address = gart_info->addr; address = gart_info->addr;
bus_address = gart_info->bus_addr; bus_address = gart_info->bus_addr;
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/smp_lock.h> /* For (un)lock_kernel */ #include <linux/smp_lock.h> /* For (un)lock_kernel */
#include <linux/dma-mapping.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/mutex.h> #include <linux/mutex.h>
...@@ -551,6 +552,8 @@ struct drm_ati_pcigart_info { ...@@ -551,6 +552,8 @@ struct drm_ati_pcigart_info {
int gart_reg_if; int gart_reg_if;
void *addr; void *addr;
dma_addr_t bus_addr; dma_addr_t bus_addr;
dma_addr_t table_mask;
struct drm_dma_handle *table_handle;
drm_local_map_t mapping; drm_local_map_t mapping;
int table_size; int table_size;
}; };
......
...@@ -326,6 +326,7 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -326,6 +326,7 @@ int drm_release(struct inode *inode, struct file *filp)
struct drm_file *file_priv = filp->private_data; struct drm_file *file_priv = filp->private_data;
struct drm_device *dev = file_priv->head->dev; struct drm_device *dev = file_priv->head->dev;
int retcode = 0; int retcode = 0;
unsigned long irqflags;
lock_kernel(); lock_kernel();
...@@ -357,9 +358,11 @@ int drm_release(struct inode *inode, struct file *filp) ...@@ -357,9 +358,11 @@ int drm_release(struct inode *inode, struct file *filp)
*/ */
do{ do{
spin_lock(&dev->lock.spinlock); spin_lock_irqsave(&dev->lock.spinlock,
irqflags);
locked = dev->lock.idle_has_lock; locked = dev->lock.idle_has_lock;
spin_unlock(&dev->lock.spinlock); spin_unlock_irqrestore(&dev->lock.spinlock,
irqflags);
if (locked) if (locked)
break; break;
schedule(); schedule();
......
...@@ -53,6 +53,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -53,6 +53,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
DECLARE_WAITQUEUE(entry, current); DECLARE_WAITQUEUE(entry, current);
struct drm_lock *lock = data; struct drm_lock *lock = data;
int ret = 0; int ret = 0;
unsigned long irqflags;
++file_priv->lock_count; ++file_priv->lock_count;
...@@ -71,9 +72,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -71,9 +72,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
return -EINVAL; return -EINVAL;
add_wait_queue(&dev->lock.lock_queue, &entry); add_wait_queue(&dev->lock.lock_queue, &entry);
spin_lock(&dev->lock.spinlock); spin_lock_irqsave(&dev->lock.spinlock, irqflags);
dev->lock.user_waiters++; dev->lock.user_waiters++;
spin_unlock(&dev->lock.spinlock); spin_unlock_irqrestore(&dev->lock.spinlock, irqflags);
for (;;) { for (;;) {
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
if (!dev->lock.hw_lock) { if (!dev->lock.hw_lock) {
...@@ -95,9 +96,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv) ...@@ -95,9 +96,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
break; break;
} }
} }
spin_lock(&dev->lock.spinlock); spin_lock_irqsave(&dev->lock.spinlock, irqflags);
dev->lock.user_waiters--; dev->lock.user_waiters--;
spin_unlock(&dev->lock.spinlock); spin_unlock_irqrestore(&dev->lock.spinlock, irqflags);
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
remove_wait_queue(&dev->lock.lock_queue, &entry); remove_wait_queue(&dev->lock.lock_queue, &entry);
...@@ -198,8 +199,9 @@ int drm_lock_take(struct drm_lock_data *lock_data, ...@@ -198,8 +199,9 @@ int drm_lock_take(struct drm_lock_data *lock_data,
{ {
unsigned int old, new, prev; unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock; volatile unsigned int *lock = &lock_data->hw_lock->lock;
unsigned long irqflags;
spin_lock(&lock_data->spinlock); spin_lock_irqsave(&lock_data->spinlock, irqflags);
do { do {
old = *lock; old = *lock;
if (old & _DRM_LOCK_HELD) if (old & _DRM_LOCK_HELD)
...@@ -211,7 +213,7 @@ int drm_lock_take(struct drm_lock_data *lock_data, ...@@ -211,7 +213,7 @@ int drm_lock_take(struct drm_lock_data *lock_data,
} }
prev = cmpxchg(lock, old, new); prev = cmpxchg(lock, old, new);
} while (prev != old); } while (prev != old);
spin_unlock(&lock_data->spinlock); spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
if (_DRM_LOCKING_CONTEXT(old) == context) { if (_DRM_LOCKING_CONTEXT(old) == context) {
if (old & _DRM_LOCK_HELD) { if (old & _DRM_LOCK_HELD) {
...@@ -272,15 +274,16 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context) ...@@ -272,15 +274,16 @@ int drm_lock_free(struct drm_lock_data *lock_data, unsigned int context)
{ {
unsigned int old, new, prev; unsigned int old, new, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock; volatile unsigned int *lock = &lock_data->hw_lock->lock;
unsigned long irqflags;
spin_lock(&lock_data->spinlock); spin_lock_irqsave(&lock_data->spinlock, irqflags);
if (lock_data->kernel_waiters != 0) { if (lock_data->kernel_waiters != 0) {
drm_lock_transfer(lock_data, 0); drm_lock_transfer(lock_data, 0);
lock_data->idle_has_lock = 1; lock_data->idle_has_lock = 1;
spin_unlock(&lock_data->spinlock); spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
return 1; return 1;
} }
spin_unlock(&lock_data->spinlock); spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
do { do {
old = *lock; old = *lock;
...@@ -344,19 +347,20 @@ static int drm_notifier(void *priv) ...@@ -344,19 +347,20 @@ static int drm_notifier(void *priv)
void drm_idlelock_take(struct drm_lock_data *lock_data) void drm_idlelock_take(struct drm_lock_data *lock_data)
{ {
int ret = 0; int ret = 0;
unsigned long irqflags;
spin_lock(&lock_data->spinlock); spin_lock_irqsave(&lock_data->spinlock, irqflags);
lock_data->kernel_waiters++; lock_data->kernel_waiters++;
if (!lock_data->idle_has_lock) { if (!lock_data->idle_has_lock) {
spin_unlock(&lock_data->spinlock); spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT); ret = drm_lock_take(lock_data, DRM_KERNEL_CONTEXT);
spin_lock(&lock_data->spinlock); spin_lock_irqsave(&lock_data->spinlock, irqflags);
if (ret == 1) if (ret == 1)
lock_data->idle_has_lock = 1; lock_data->idle_has_lock = 1;
} }
spin_unlock(&lock_data->spinlock); spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
} }
EXPORT_SYMBOL(drm_idlelock_take); EXPORT_SYMBOL(drm_idlelock_take);
...@@ -364,8 +368,9 @@ void drm_idlelock_release(struct drm_lock_data *lock_data) ...@@ -364,8 +368,9 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
{ {
unsigned int old, prev; unsigned int old, prev;
volatile unsigned int *lock = &lock_data->hw_lock->lock; volatile unsigned int *lock = &lock_data->hw_lock->lock;
unsigned long irqflags;
spin_lock(&lock_data->spinlock); spin_lock_irqsave(&lock_data->spinlock, irqflags);
if (--lock_data->kernel_waiters == 0) { if (--lock_data->kernel_waiters == 0) {
if (lock_data->idle_has_lock) { if (lock_data->idle_has_lock) {
do { do {
...@@ -376,7 +381,7 @@ void drm_idlelock_release(struct drm_lock_data *lock_data) ...@@ -376,7 +381,7 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
lock_data->idle_has_lock = 0; lock_data->idle_has_lock = 0;
} }
} }
spin_unlock(&lock_data->spinlock); spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
} }
EXPORT_SYMBOL(drm_idlelock_release); EXPORT_SYMBOL(drm_idlelock_release);
......
...@@ -205,9 +205,9 @@ ...@@ -205,9 +205,9 @@
{0x1002, 0x71D6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x71D6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x71DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ {0x1002, 0x71DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \
{0x1002, 0x71DE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x71DE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x7200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_NEW_MEMMAP}, \
{0x1002, 0x7210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7210, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x7211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV530|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7211, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RV515|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x7240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
{0x1002, 0x7243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7243, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
{0x1002, 0x7244, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7244, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_R580|RADEON_NEW_MEMMAP}, \
...@@ -238,6 +238,7 @@ ...@@ -238,6 +238,7 @@
{0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7834, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_NEW_MEMMAP}, \
{0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \
{0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ {0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
{0x1002, 0x791f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \
{0, 0, 0} {0, 0, 0}
#define r128_PCI_IDS \ #define r128_PCI_IDS \
......
...@@ -558,6 +558,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init) ...@@ -558,6 +558,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
#if __OS_HAS_AGP #if __OS_HAS_AGP
if (dev_priv->is_pci) { if (dev_priv->is_pci) {
#endif #endif
dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN; dev_priv->gart_info.gart_table_location = DRM_ATI_GART_MAIN;
dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE; dev_priv->gart_info.table_size = R128_PCIGART_TABLE_SIZE;
dev_priv->gart_info.addr = NULL; dev_priv->gart_info.addr = NULL;
......
...@@ -1807,6 +1807,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init) ...@@ -1807,6 +1807,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
} else } else
#endif #endif
{ {
dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
/* if we have an offset set from userspace */ /* if we have an offset set from userspace */
if (dev_priv->pcigart_offset_set) { if (dev_priv->pcigart_offset_set) {
dev_priv->gart_info.bus_addr = dev_priv->gart_info.bus_addr =
......
...@@ -126,6 +126,8 @@ via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size) ...@@ -126,6 +126,8 @@ via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
hw_addr, cur_addr, next_addr); hw_addr, cur_addr, next_addr);
return -1; return -1;
} }
if ((cur_addr < hw_addr) && (next_addr >= hw_addr))
msleep(1);
} while ((cur_addr < hw_addr) && (next_addr >= hw_addr)); } while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
return 0; return 0;
} }
...@@ -416,27 +418,50 @@ static int via_hook_segment(drm_via_private_t * dev_priv, ...@@ -416,27 +418,50 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
int paused, count; int paused, count;
volatile uint32_t *paused_at = dev_priv->last_pause_ptr; volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
uint32_t reader,ptr; uint32_t reader,ptr;
uint32_t diff;
paused = 0; paused = 0;
via_flush_write_combine(); via_flush_write_combine();
(void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1); (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1);
*paused_at = pause_addr_lo; *paused_at = pause_addr_lo;
via_flush_write_combine(); via_flush_write_combine();
(void) *paused_at; (void) *paused_at;
reader = *(dev_priv->hw_addr_ptr); reader = *(dev_priv->hw_addr_ptr);
ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
if ((ptr - reader) <= dev_priv->dma_diff ) { /*
* 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; count = 10000000;
while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--); 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) { if (paused && !no_pci_fire) {
reader = *(dev_priv->hw_addr_ptr); 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 * There is a concern that these writes may stall the PCI bus
* if the GPU is not idle. However, idling the GPU first * if the GPU is not idle. However, idling the GPU first
...@@ -577,6 +602,7 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) ...@@ -577,6 +602,7 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
uint32_t pause_addr_lo, pause_addr_hi; uint32_t pause_addr_lo, pause_addr_hi;
uint32_t jump_addr_lo, jump_addr_hi; uint32_t jump_addr_lo, jump_addr_hi;
volatile uint32_t *last_pause_ptr; 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; agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
...@@ -603,8 +629,29 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv) ...@@ -603,8 +629,29 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
&pause_addr_lo, 0); &pause_addr_lo, 0);
*last_pause_ptr = pause_addr_lo; *last_pause_ptr = pause_addr_lo;
dma_low_save1 = dev_priv->dma_low;
via_hook_segment( dev_priv, jump_addr_hi, jump_addr_lo, 0); /*
* 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.
*/
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);
} }
......
...@@ -603,7 +603,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli ...@@ -603,7 +603,7 @@ via_build_sg_info(struct drm_device *dev, drm_via_sg_info_t *vsg, drm_via_dmabli
* (Not a big limitation anyway.) * (Not a big limitation anyway.)
*/ */
if ((xfer->mem_stride - xfer->line_length) >= PAGE_SIZE) { if ((xfer->mem_stride - xfer->line_length) > 2*PAGE_SIZE) {
DRM_ERROR("Too large system memory stride. Stride: %d, " DRM_ERROR("Too large system memory stride. Stride: %d, "
"Length: %d\n", xfer->mem_stride, xfer->line_length); "Length: %d\n", xfer->mem_stride, xfer->line_length);
return -EINVAL; return -EINVAL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment