diff options
author | Owain Ainsworth <oga@cvs.openbsd.org> | 2008-09-10 02:11:33 +0000 |
---|---|---|
committer | Owain Ainsworth <oga@cvs.openbsd.org> | 2008-09-10 02:11:33 +0000 |
commit | 48ac92e8ee739d7a7fc8a9e9c5d9bbf0ca615f4d (patch) | |
tree | 325bd90c6614b4b510f9f75dc8e7454f3cb0253f | |
parent | fd80257e2ebe4148c596e26a045b325e35353afc (diff) |
40-bit GART support for PCIE devices. From drm git a while ago.
Tested by a few, no regressions for normal use.
-rw-r--r-- | sys/dev/pci/drm/ati_pcigart.c | 140 |
1 files changed, 99 insertions, 41 deletions
diff --git a/sys/dev/pci/drm/ati_pcigart.c b/sys/dev/pci/drm/ati_pcigart.c index 1f3e461aa24..a4627413b21 100644 --- a/sys/dev/pci/drm/ati_pcigart.c +++ b/sys/dev/pci/drm/ati_pcigart.c @@ -34,80 +34,138 @@ #include "drmP.h" #define ATI_PCIGART_PAGE_SIZE 4096 /* PCI GART page size */ +#define ATI_PCIGART_PAGE_MASK (~(ATI_PCIGART_PAGE_SIZE-1)) -int drm_ati_pcigart_init(struct drm_device *dev, +#define ATI_PCIE_WRITE 0x4 +#define ATI_PCIE_READ 0x8 + +int drm_ati_alloc_pcigart_table(struct drm_device *, + struct drm_ati_pcigart_info *); +void drm_ati_free_pcigart_table(struct drm_device *, + struct drm_ati_pcigart_info *); + +int +drm_ati_alloc_pcigart_table(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) { - unsigned long pages; - u32 *pci_gart = NULL, page_base; - int i, j; + dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, PAGE_SIZE, + gart_info->table_mask); + if (dev->sg->dmah == NULL) + return ENOMEM; + return 0; +} + +void +drm_ati_free_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) +{ + drm_pci_free(dev, dev->sg->dmah); + dev->sg->dmah = NULL; +} + +int +drm_ati_pcigart_cleanup(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) +{ + /* we need to support large memory configurations */ if (dev->sg == NULL) { - DRM_ERROR( "no scatter/gather memory!\n" ); + DRM_ERROR("no scatter/gather memory!\n"); return 0; } + if (gart_info->bus_addr) { + if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { + gart_info->bus_addr = 0; + if (dev->sg->dmah) + drm_ati_free_pcigart_table(dev, gart_info); + } + } + + return 1; +} + +int +drm_ati_pcigart_init(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) +{ + + void *address = NULL; + unsigned long pages; + u32 *pci_gart, page_base; + dma_addr_t bus_address = 0; + int i, j, ret = 0; + int max_pages; + dma_addr_t entry_addr; + + /* we need to support large memory configurations */ + if (dev->sg == NULL) { + DRM_ERROR("no scatter/gather memory!\n"); + goto done; + } + if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { - /* GART table in system memory */ - dev->sg->dmah = drm_pci_alloc(dev, gart_info->table_size, 0, - 0xfffffffful); - if (dev->sg->dmah == NULL) { - DRM_ERROR("cannot allocate PCI GART table!\n"); - return 0; + DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); + + ret = drm_ati_alloc_pcigart_table(dev, gart_info); + if (ret) { + DRM_ERROR("cannot allocate PCI GART page!\n"); + goto done; } - - gart_info->addr = (void *)dev->sg->dmah->vaddr; - gart_info->bus_addr = dev->sg->dmah->busaddr; - pci_gart = (u32 *)dev->sg->dmah->vaddr; + + address = (void *)dev->sg->dmah->vaddr; + bus_address = dev->sg->dmah->busaddr; } else { - /* GART table in framebuffer memory */ - pci_gart = gart_info->addr; + address = gart_info->addr; + bus_address = gart_info->bus_addr; + DRM_DEBUG("PCI: Gart Table: VRAM %08X mapped at %08lX\n", + (unsigned int)bus_address, (unsigned long)address); } - - pages = DRM_MIN(dev->sg->pages, gart_info->table_size / sizeof(u32)); - bzero(pci_gart, gart_info->table_size); + pci_gart = (u32 *) address; + + max_pages = (gart_info->table_size / sizeof(u32)); + pages = (dev->sg->pages <= max_pages) + ? dev->sg->pages : max_pages; + + memset(pci_gart, 0, max_pages * sizeof(u32)); -#if defined(__FreeBSD__) +#ifdef __FreeBSD__ KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE, ("page size too small")); #else KASSERT(PAGE_SIZE >= ATI_PCIGART_PAGE_SIZE); #endif - for ( i = 0 ; i < pages ; i++ ) { - page_base = (u32) dev->sg->busaddr[i]; - + for (i = 0; i < pages; i++) { + entry_addr = dev->sg->busaddr[i]; for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) { + page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK; switch(gart_info->gart_reg_if) { case DRM_ATI_GART_IGP: - *pci_gart = cpu_to_le32(page_base | 0xc); + page_base |= (upper_32_bits(entry_addr) & 0xff) << 4; + page_base |= 0xc; break; case DRM_ATI_GART_PCIE: - *pci_gart = cpu_to_le32((page_base >> 8) | 0xc); + page_base >>= 8; + page_base |= (upper_32_bits(entry_addr) & 0xff) << 24; + page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE; break; default: - *pci_gart = cpu_to_le32(page_base); + case DRM_ATI_GART_PCI: break; } + *pci_gart = cpu_to_le32(page_base); pci_gart++; - page_base += ATI_PCIGART_PAGE_SIZE; + entry_addr += ATI_PCIGART_PAGE_SIZE; } } DRM_MEMORYBARRIER(); - return 1; -} - -int drm_ati_pcigart_cleanup(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) -{ - if (dev->sg == NULL) { - DRM_ERROR( "no scatter/gather memory!\n" ); - return 0; - } + ret = 1; - drm_pci_free(dev, dev->sg->dmah); - - return 1; + done: + gart_info->addr = address; + gart_info->bus_addr = bus_address; + return ret; } |