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
This commit is contained in:
@@ -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)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
DRM_DEBUG("%d order\n", order);
|
return 0;
|
||||||
|
|
||||||
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 (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
|
|||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
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
|
|||||||
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 @@
|
|||||||
#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 {
|
|||||||
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)
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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 @@
|
|||||||
{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 @@
|
|||||||
{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)
|
|||||||
#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)
|
|||||||
} 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)
|
|||||||
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,
|
|||||||
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 ) {
|
/*
|
||||||
count = 10000000;
|
* If there is a possibility that the command reader will
|
||||||
while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--);
|
* 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) {
|
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)
|
|||||||
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)
|
|||||||
&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
|
|||||||
* (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;
|
||||||
|
Reference in New Issue
Block a user