From 5a7aad9a559a5488cbef7aa3d4d96fc28220b8ae Mon Sep 17 00:00:00 2001 From: David Miller Date: Thu, 12 Feb 2009 02:15:27 -0800 Subject: drm: ati_pcigart: Do not access I/O MEM space using pointer derefs. The PCI GART table initialization code treats the GART table mapping unconditionally as a kernel virtual address. But it could be in the framebuffer, for example, and thus we're dealing with a PCI MEM space ioremap() cookie. Treating that as a virtual address is illegal and will crash some system types (such as sparc64 where the ioremap() return value is actually a physical I/O address). So access the area correctly, using gart_info->gart_table_location as our guide. Signed-off-by: David S. Miller Signed-off-by: Dave Airlie --- drivers/gpu/drm/ati_pcigart.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/ati_pcigart.c') diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c index c533d0c9ec61..2cd827a56ffe 100644 --- a/drivers/gpu/drm/ati_pcigart.c +++ b/drivers/gpu/drm/ati_pcigart.c @@ -95,10 +95,11 @@ EXPORT_SYMBOL(drm_ati_pcigart_cleanup); int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { + struct drm_local_map *map = &gart_info->mapping; struct drm_sg_mem *entry = dev->sg; void *address = NULL; unsigned long pages; - u32 *pci_gart, page_base; + u32 *pci_gart, page_base, gart_idx; dma_addr_t bus_address = 0; int i, j, ret = 0; int max_pages; @@ -133,8 +134,14 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga pages = (entry->pages <= max_pages) ? entry->pages : max_pages; - memset(pci_gart, 0, max_pages * sizeof(u32)); + if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { + memset(pci_gart, 0, max_pages * sizeof(u32)); + } else { + for (gart_idx = 0; gart_idx < max_pages; gart_idx++) + DRM_WRITE32(map, gart_idx * sizeof(u32), 0); + } + gart_idx = 0; for (i = 0; i < pages; i++) { /* we need to support large memory configurations */ entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i], @@ -149,19 +156,26 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga page_base = (u32) entry->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { + u32 val; + switch(gart_info->gart_reg_if) { case DRM_ATI_GART_IGP: - *pci_gart = cpu_to_le32((page_base) | 0xc); + val = page_base | 0xc; break; case DRM_ATI_GART_PCIE: - *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); + val = (page_base >> 8) | 0xc; break; default: case DRM_ATI_GART_PCI: - *pci_gart = cpu_to_le32(page_base); + val = page_base; break; } - pci_gart++; + if (gart_info->gart_table_location == + DRM_ATI_GART_MAIN) + pci_gart[gart_idx] = cpu_to_le32(val); + else + DRM_WRITE32(map, gart_idx * sizeof(u32), val); + gart_idx++; page_base += ATI_PCIGART_PAGE_SIZE; } } -- cgit v1.2.3 From 296c6ae0e9b5ced1060b43a68b5f7e41a18509f6 Mon Sep 17 00:00:00 2001 From: David Miller Date: Thu, 12 Feb 2009 02:15:34 -0800 Subject: drm: ati_pcigart: Need to use PCI_DMA_BIDIRECTIONAL. The buffers mapped by the PCI GART can be written to by the device, not just read. For example, this happens via the RB_RPTR writeback on Radeon. So we can't use PCI_DMA_TODEVICE else we'll get protection faults on IOMMU platforms. Signed-off-by: David S. Miller Signed-off-by: Dave Airlie --- drivers/gpu/drm/ati_pcigart.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpu/drm/ati_pcigart.c') diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c index 2cd827a56ffe..7972ec8762c7 100644 --- a/drivers/gpu/drm/ati_pcigart.c +++ b/drivers/gpu/drm/ati_pcigart.c @@ -77,7 +77,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info if (!entry->busaddr[i]) break; pci_unmap_page(dev->pdev, entry->busaddr[i], - PAGE_SIZE, PCI_DMA_TODEVICE); + PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); } if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) @@ -145,7 +145,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga for (i = 0; i < pages; i++) { /* we need to support large memory configurations */ entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i], - 0, PAGE_SIZE, PCI_DMA_TODEVICE); + 0, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL); if (entry->busaddr[i] == 0) { DRM_ERROR("unable to map PCIGART pages!\n"); drm_ati_pcigart_cleanup(dev, gart_info); -- cgit v1.2.3 From d30333bbabb4a2cfad1f1a45c48a4e4d0065c1f6 Mon Sep 17 00:00:00 2001 From: David Miller Date: Sun, 15 Feb 2009 01:08:07 -0800 Subject: drm: ati_pcigart: Fix limit check in drm_ati_pcigart_init(). The variable 'max_pages' is ambiguous. There are two concepts of "pages" being used in this function. First, we have ATI GART pages which are always 4096 bytes. Then, we have system pages which are of size PAGE_SIZE. Eliminate the confusion by creating max_ati_pages and max_real_pages. Calculate and use them as appropriate. Signed-off-by: David S. Miller Signed-off-by: Dave Airlie --- drivers/gpu/drm/ati_pcigart.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'drivers/gpu/drm/ati_pcigart.c') diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c index 7972ec8762c7..4d86a629a517 100644 --- a/drivers/gpu/drm/ati_pcigart.c +++ b/drivers/gpu/drm/ati_pcigart.c @@ -102,7 +102,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga u32 *pci_gart, page_base, gart_idx; dma_addr_t bus_address = 0; int i, j, ret = 0; - int max_pages; + int max_ati_pages, max_real_pages; if (!entry) { DRM_ERROR("no scatter/gather memory!\n"); @@ -130,14 +130,15 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga pci_gart = (u32 *) address; - max_pages = (gart_info->table_size / sizeof(u32)); - pages = (entry->pages <= max_pages) - ? entry->pages : max_pages; + max_ati_pages = (gart_info->table_size / sizeof(u32)); + max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); + pages = (entry->pages <= max_real_pages) + ? entry->pages : max_real_pages; if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { - memset(pci_gart, 0, max_pages * sizeof(u32)); + memset(pci_gart, 0, max_ati_pages * sizeof(u32)); } else { - for (gart_idx = 0; gart_idx < max_pages; gart_idx++) + for (gart_idx = 0; gart_idx < max_ati_pages; gart_idx++) DRM_WRITE32(map, gart_idx * sizeof(u32), 0); } -- cgit v1.2.3 From 6abf66018f7fe231720e50f9a47b142182388869 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Thu, 26 Feb 2009 10:13:47 +1000 Subject: drm/ati_pcigart: use memset_io to reset the memory Also don't setup pci_gart if we aren't going to need it. Signed-off-by: Dave Airlie --- drivers/gpu/drm/ati_pcigart.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/ati_pcigart.c') diff --git a/drivers/gpu/drm/ati_pcigart.c b/drivers/gpu/drm/ati_pcigart.c index 4d86a629a517..628eae3e9b83 100644 --- a/drivers/gpu/drm/ati_pcigart.c +++ b/drivers/gpu/drm/ati_pcigart.c @@ -99,7 +99,7 @@ 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, gart_idx; + u32 *pci_gart = NULL, page_base, gart_idx; dma_addr_t bus_address = 0; int i, j, ret = 0; int max_ati_pages, max_real_pages; @@ -118,6 +118,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga goto done; } + pci_gart = gart_info->table_handle->vaddr; address = gart_info->table_handle->vaddr; bus_address = gart_info->table_handle->busaddr; } else { @@ -128,7 +129,6 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga (unsigned long)address); } - pci_gart = (u32 *) address; max_ati_pages = (gart_info->table_size / sizeof(u32)); max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); @@ -138,8 +138,7 @@ 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) { memset(pci_gart, 0, max_ati_pages * sizeof(u32)); } else { - for (gart_idx = 0; gart_idx < max_ati_pages; gart_idx++) - DRM_WRITE32(map, gart_idx * sizeof(u32), 0); + memset_io((void __iomem *)map->handle, 0, max_ati_pages * sizeof(u32)); } gart_idx = 0; -- cgit v1.2.3