summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--drivers/char/drm/ati_pcigart.c91
-rw-r--r--drivers/char/drm/drmP.h3
-rw-r--r--drivers/char/drm/drm_fops.c7
-rw-r--r--drivers/char/drm/drm_lock.c35
-rw-r--r--drivers/char/drm/drm_pciids.h7
-rw-r--r--drivers/char/drm/r128_cce.c1
-rw-r--r--drivers/char/drm/radeon_cp.c1
-rw-r--r--drivers/char/drm/via_dma.c59
-rw-r--r--drivers/char/drm/via_dmablit.c2
9 files changed, 110 insertions, 96 deletions
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c
index d352dbb4ccf7..e5a0e97cfdda 100644
--- a/drivers/char/drm/ati_pcigart.c
+++ b/drivers/char/drm/ati_pcigart.c
@@ -35,42 +35,23 @@
 
 # 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;
-	struct page *page;
-	int i;
-
-	DRM_DEBUG("%d order\n", order);
-
-	address = __get_free_pages(GFP_KERNEL | __GFP_COMP,
-				   order);
-	if (address == 0UL) {
-		return NULL;
-	}
-
-	page = virt_to_page(address);
+	gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size,
+						PAGE_SIZE,
+						gart_info->table_mask);
+	if (gart_info->table_handle == NULL)
+		return -ENOMEM;
 
-	for (i = 0; i < order; i++, page++)
-		SetPageReserved(page);
-
-	DRM_DEBUG("returning 0x%08lx\n", address);
-	return (void *)address;
+	return 0;
 }
 
-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;
-	int i;
-	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);
+	drm_pci_free(dev, gart_info->table_handle);
+	gart_info->table_handle = NULL;
 }
 
 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;
 	unsigned long pages;
 	int i;
-	int order;
-	int num_pages, max_pages;
+	int max_pages;
 
 	/* we need to support large memory configurations */
 	if (!entry) {
@@ -87,15 +67,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info
 		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->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));
 		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;
 	}
 
-	if (gart_info->gart_table_location == DRM_ATI_GART_MAIN
-	    && gart_info->addr) {
-		drm_ati_free_pcigart_table(gart_info->addr, order);
-		gart_info->addr = NULL;
+	if (gart_info->gart_table_location == DRM_ATI_GART_MAIN &&
+	    gart_info->table_handle) {
+		drm_ati_free_pcigart_table(dev, gart_info);
 	}
 
 	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;
 	void *address = NULL;
 	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 order;
 	int max_pages;
-	int num_pages;
 
 	if (!entry) {
 		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) {
 		DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
 
-		order = drm_order((gart_info->table_size +
-				   (PAGE_SIZE-1)) / PAGE_SIZE);
-		num_pages = 1 << order;
-		address = drm_ati_alloc_pcigart_table(order);
-		if (!address) {
+		ret = drm_ati_alloc_pcigart_table(dev, gart_info);
+		if (ret) {
 			DRM_ERROR("cannot allocate PCI GART page!\n");
 			goto done;
 		}
 
-		if (!dev->pdev) {
-			DRM_ERROR("PCI device unknown!\n");
-			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;
-		}
+		address = gart_info->table_handle->vaddr;
+		bus_address = gart_info->table_handle->busaddr;
 	} else {
 		address = gart_info->addr;
 		bus_address = gart_info->bus_addr;
diff --git a/drivers/char/drm/drmP.h b/drivers/char/drm/drmP.h
index a6789f25009b..8ea9dd1717a9 100644
--- a/drivers/char/drm/drmP.h
+++ b/drivers/char/drm/drmP.h
@@ -54,6 +54,7 @@
 #include <linux/pci.h>
 #include <linux/jiffies.h>
 #include <linux/smp_lock.h>	/* For (un)lock_kernel */
+#include <linux/dma-mapping.h>
 #include <linux/mm.h>
 #include <linux/cdev.h>
 #include <linux/mutex.h>
@@ -551,6 +552,8 @@ struct drm_ati_pcigart_info {
 	int gart_reg_if;
 	void *addr;
 	dma_addr_t bus_addr;
+	dma_addr_t table_mask;
+	struct drm_dma_handle *table_handle;
 	drm_local_map_t mapping;
 	int table_size;
 };
diff --git a/drivers/char/drm/drm_fops.c b/drivers/char/drm/drm_fops.c
index 3992f73299cc..f09d4b5002b0 100644
--- a/drivers/char/drm/drm_fops.c
+++ b/drivers/char/drm/drm_fops.c
@@ -326,6 +326,7 @@ int drm_release(struct inode *inode, struct file *filp)
 	struct drm_file *file_priv = filp->private_data;
 	struct drm_device *dev = file_priv->head->dev;
 	int retcode = 0;
+	unsigned long irqflags;
 
 	lock_kernel();
 
@@ -357,9 +358,11 @@ int drm_release(struct inode *inode, struct file *filp)
 			 */
 
 			do{
-				spin_lock(&dev->lock.spinlock);
+				spin_lock_irqsave(&dev->lock.spinlock,
+						  irqflags);
 				locked = dev->lock.idle_has_lock;
-				spin_unlock(&dev->lock.spinlock);
+				spin_unlock_irqrestore(&dev->lock.spinlock,
+						       irqflags);
 				if (locked)
 					break;
 				schedule();
diff --git a/drivers/char/drm/drm_lock.c b/drivers/char/drm/drm_lock.c
index bea2a7d5b2b2..12dcdd1832f0 100644
--- a/drivers/char/drm/drm_lock.c
+++ b/drivers/char/drm/drm_lock.c
@@ -53,6 +53,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 	DECLARE_WAITQUEUE(entry, current);
 	struct drm_lock *lock = data;
 	int ret = 0;
+	unsigned long irqflags;
 
 	++file_priv->lock_count;
 
@@ -71,9 +72,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 			return -EINVAL;
 
 	add_wait_queue(&dev->lock.lock_queue, &entry);
-	spin_lock(&dev->lock.spinlock);
+	spin_lock_irqsave(&dev->lock.spinlock, irqflags);
 	dev->lock.user_waiters++;
-	spin_unlock(&dev->lock.spinlock);
+	spin_unlock_irqrestore(&dev->lock.spinlock, irqflags);
 	for (;;) {
 		__set_current_state(TASK_INTERRUPTIBLE);
 		if (!dev->lock.hw_lock) {
@@ -95,9 +96,9 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
 			break;
 		}
 	}
-	spin_lock(&dev->lock.spinlock);
+	spin_lock_irqsave(&dev->lock.spinlock, irqflags);
 	dev->lock.user_waiters--;
-	spin_unlock(&dev->lock.spinlock);
+	spin_unlock_irqrestore(&dev->lock.spinlock, irqflags);
 	__set_current_state(TASK_RUNNING);
 	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;
 	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 {
 		old = *lock;
 		if (old & _DRM_LOCK_HELD)
@@ -211,7 +213,7 @@ int drm_lock_take(struct drm_lock_data *lock_data,
 		}
 		prev = cmpxchg(lock, old, new);
 	} while (prev != old);
-	spin_unlock(&lock_data->spinlock);
+	spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
 
 	if (_DRM_LOCKING_CONTEXT(old) == context) {
 		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;
 	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) {
 		drm_lock_transfer(lock_data, 0);
 		lock_data->idle_has_lock = 1;
-		spin_unlock(&lock_data->spinlock);
+		spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
 		return 1;
 	}
-	spin_unlock(&lock_data->spinlock);
+	spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
 
 	do {
 		old = *lock;
@@ -344,19 +347,20 @@ static int drm_notifier(void *priv)
 void drm_idlelock_take(struct drm_lock_data *lock_data)
 {
 	int ret = 0;
+	unsigned long irqflags;
 
-	spin_lock(&lock_data->spinlock);
+	spin_lock_irqsave(&lock_data->spinlock, irqflags);
 	lock_data->kernel_waiters++;
 	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);
-		spin_lock(&lock_data->spinlock);
+		spin_lock_irqsave(&lock_data->spinlock, irqflags);
 
 		if (ret == 1)
 			lock_data->idle_has_lock = 1;
 	}
-	spin_unlock(&lock_data->spinlock);
+	spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
 }
 EXPORT_SYMBOL(drm_idlelock_take);
 
@@ -364,8 +368,9 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
 {
 	unsigned int old, prev;
 	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->idle_has_lock) {
 			do {
@@ -376,7 +381,7 @@ void drm_idlelock_release(struct drm_lock_data *lock_data)
 			lock_data->idle_has_lock = 0;
 		}
 	}
-	spin_unlock(&lock_data->spinlock);
+	spin_unlock_irqrestore(&lock_data->spinlock, irqflags);
 }
 EXPORT_SYMBOL(drm_idlelock_release);
 
diff --git a/drivers/char/drm/drm_pciids.h b/drivers/char/drm/drm_pciids.h
index 715b361f0c2b..a6a499f97e22 100644
--- a/drivers/char/drm/drm_pciids.h
+++ b/drivers/char/drm/drm_pciids.h
@@ -205,9 +205,9 @@
 	{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, 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, 0x7210, 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_RV530|RADEON_IS_MOBILITY|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_RV515|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, 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}, \
@@ -238,6 +238,7 @@
 	{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, 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}
 
 #define r128_PCI_IDS \
diff --git a/drivers/char/drm/r128_cce.c b/drivers/char/drm/r128_cce.c
index 892e0a589846..f36adbd3aaf5 100644
--- a/drivers/char/drm/r128_cce.c
+++ b/drivers/char/drm/r128_cce.c
@@ -558,6 +558,7 @@ static int r128_do_init_cce(struct drm_device * dev, drm_r128_init_t * init)
 #if __OS_HAS_AGP
 	if (dev_priv->is_pci) {
 #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.table_size = R128_PCIGART_TABLE_SIZE;
 		dev_priv->gart_info.addr = NULL;
diff --git a/drivers/char/drm/radeon_cp.c b/drivers/char/drm/radeon_cp.c
index 833abc7e55fb..9072e4a1894e 100644
--- a/drivers/char/drm/radeon_cp.c
+++ b/drivers/char/drm/radeon_cp.c
@@ -1807,6 +1807,7 @@ static int radeon_do_init_cp(struct drm_device * dev, drm_radeon_init_t * init)
 	} else
 #endif
 	{
+		dev_priv->gart_info.table_mask = DMA_BIT_MASK(32);
 		/* if we have an offset set from userspace */
 		if (dev_priv->pcigart_offset_set) {
 			dev_priv->gart_info.bus_addr =
diff --git a/drivers/char/drm/via_dma.c b/drivers/char/drm/via_dma.c
index 94baec692b57..7a339dba6a69 100644
--- a/drivers/char/drm/via_dma.c
+++ b/drivers/char/drm/via_dma.c
@@ -126,6 +126,8 @@ via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
 			     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;
 }
@@ -416,27 +418,50 @@ static int via_hook_segment(drm_via_private_t * dev_priv,
 	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
@@ -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 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,
@@ -603,8 +629,29 @@ static void via_cmdbuf_jump(drm_via_private_t * dev_priv)
 		      &pause_addr_lo, 0);
 
 	*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);
 }
 
 
diff --git a/drivers/char/drm/via_dmablit.c b/drivers/char/drm/via_dmablit.c
index 33c5197b73c4..409e00afdd07 100644
--- a/drivers/char/drm/via_dmablit.c
+++ b/drivers/char/drm/via_dmablit.c
@@ -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.)
 	 */
 
-	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, "
 			  "Length: %d\n", xfer->mem_stride, xfer->line_length);
 		return -EINVAL;