From 1f96e9a98245b18c99cc6a7e66372a076b9abf6b Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Mon, 17 Mar 2008 07:05:46 +1000 Subject: drm/pcigart: fix the pci gart to use the drm_pci wrapper. This is the correct fix for the RS690 and hopefully the dma coherent work. For now we limit everybody to a 32-bit DMA mask but it is possible for RS690 to use a 40-bit DMA mask for the GART table itself, and the PCIE cards can use 40-bits for the table entries. Signed-off-by: Dave Airlie --- linux-core/ati_pcigart.c | 101 +++++++++-------------------------------------- linux-core/drmP.h | 4 ++ linux-core/drm_compat.h | 4 ++ linux-core/xgi_pcie.c | 1 + 4 files changed, 28 insertions(+), 82 deletions(-) (limited to 'linux-core') diff --git a/linux-core/ati_pcigart.c b/linux-core/ati_pcigart.c index 74f91bc4..beaa4424 100644 --- a/linux-core/ati_pcigart.c +++ b/linux-core/ati_pcigart.c @@ -34,51 +34,23 @@ #include "drmP.h" # 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; + 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; - DRM_DEBUG("%d order\n", order); - - address = __get_free_pages(GFP_KERNEL | __GFP_COMP | __GFP_DMA32, - order); - if (address == 0UL) { - return NULL; - } - - page = virt_to_page(address); - - for (i = 0; i < order; i++, page++) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) - get_page(page); -#endif - 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++) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15) - __put_page(page); -#endif - 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) @@ -86,8 +58,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) { @@ -95,15 +66,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) @@ -122,10 +85,9 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info 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); - gart_info->addr = NULL; + drm_ati_free_pcigart_table(dev, gart_info); } return 1; @@ -140,9 +102,7 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga 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"); @@ -152,31 +112,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; @@ -225,12 +168,6 @@ 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) - dma_sync_single_for_device(&dev->pdev->dev, - bus_address, - max_pages * sizeof(u32), - PCI_DMA_TODEVICE); - ret = 1; #if defined(__i386__) || defined(__x86_64__) diff --git a/linux-core/drmP.h b/linux-core/drmP.h index 2f76f3df..69d31e14 100644 --- a/linux-core/drmP.h +++ b/linux-core/drmP.h @@ -52,6 +52,7 @@ #include #include #include /* For (un)lock_kernel */ +#include #include #include #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16) @@ -596,6 +597,9 @@ struct drm_ati_pcigart_info { int gart_reg_if; void *addr; dma_addr_t bus_addr; + dma_addr_t table_mask; + dma_addr_t member_mask; + struct drm_dma_handle *table_handle; drm_local_map_t mapping; int table_size; }; diff --git a/linux-core/drm_compat.h b/linux-core/drm_compat.h index 0613b5d2..3b1287e1 100644 --- a/linux-core/drm_compat.h +++ b/linux-core/drm_compat.h @@ -339,4 +339,8 @@ extern void *kmap_atomic_prot_pfn(unsigned long pfn, enum km_type type, #define flush_agp_mappings() do {} while(0) #endif +#ifndef DMA_BIT_MASK +#define DMA_BIT_MASK(n) (((n) == 64) ? ~0ULL : (1ULL<<(n)) - 1) +#endif + #endif diff --git a/linux-core/xgi_pcie.c b/linux-core/xgi_pcie.c index a7d3ea24..614616a9 100644 --- a/linux-core/xgi_pcie.c +++ b/linux-core/xgi_pcie.c @@ -86,6 +86,7 @@ int xgi_pcie_heap_init(struct xgi_info * info) return err; } + info->gart_info.table_mask = DMA_BIT_MASK(32); info->gart_info.gart_table_location = DRM_ATI_GART_MAIN; info->gart_info.gart_reg_if = DRM_ATI_GART_PCI; info->gart_info.table_size = info->dev->sg->pages * sizeof(u32); -- cgit v1.2.3