diff options
author | Robert Noland <rnoland@2hip.net> | 2008-09-06 21:08:33 -0400 |
---|---|---|
committer | Robert Noland <rnoland@2hip.net> | 2008-09-06 21:08:33 -0400 |
commit | 740f09bffde20d9207497bd107d50941ca21278a (patch) | |
tree | 67fb687214bacc8a2c0fbe9e2875ae3e6a1421c9 | |
parent | be5fad45ee4e81997784f258fcdfaf0a303dd666 (diff) |
[FreeBSD] IGP gart needs to be un-cached.
Airlied inadvertently discovered that the IGP gart needs to be un-cached
for radeon rs485 and rs690 to work. Initial tests by placing a wbinvd()
after allocating the gart were successful. This is an attempt at a more
appropriate method of achieving success.
-rw-r--r-- | bsd-core/ati_pcigart.c | 91 |
1 files changed, 73 insertions, 18 deletions
diff --git a/bsd-core/ati_pcigart.c b/bsd-core/ati_pcigart.c index c4453ed5..5feeeba8 100644 --- a/bsd-core/ati_pcigart.c +++ b/bsd-core/ati_pcigart.c @@ -39,31 +39,86 @@ #define ATI_PCIE_WRITE 0x4 #define ATI_PCIE_READ 0x8 -static int drm_ati_alloc_pcigart_table(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) +static void +drm_ati_alloc_pcigart_table_cb(void *arg, bus_dma_segment_t *segs, + int nsegs, int error) { - drm_dma_handle_t *dmah; + struct drm_dma_handle *dmah = arg; + + if (error != 0) + return; + + KASSERT(nsegs == 1, + ("drm_ati_alloc_pcigart_table_cb: bad dma segment count")); + + dmah->busaddr = segs[0].ds_addr; +} + +static int +drm_ati_alloc_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) +{ + struct drm_dma_handle *dmah; + int flags, ret; + + dmah = malloc(sizeof(struct drm_dma_handle), M_DRM, M_ZERO | M_NOWAIT); + if (dmah == NULL) + return ENOMEM; DRM_UNLOCK(); - dmah = drm_pci_alloc(dev, gart_info->table_size, PAGE_SIZE, - gart_info->table_mask); + ret = bus_dma_tag_create(NULL, PAGE_SIZE, 0, /* tag, align, boundary */ + gart_info->table_mask, BUS_SPACE_MAXADDR, /* lowaddr, highaddr */ + NULL, NULL, /* filtfunc, filtfuncargs */ + gart_info->table_size, 1, /* maxsize, nsegs */ + gart_info->table_size, /* maxsegsize */ + BUS_DMA_ALLOCNOW, NULL, NULL, /* flags, lockfunc, lockfuncargs */ + &dmah->tag); + if (ret != 0) { + free(dmah, M_DRM); + return ENOMEM; + } + + flags = BUS_DMA_NOWAIT | BUS_DMA_ZERO; + if (gart_info->gart_reg_if == DRM_ATI_GART_IGP) + flags |= BUS_DMA_NOCACHE; + + ret = bus_dmamem_alloc(dmah->tag, &dmah->vaddr, flags, &dmah->map); + if (ret != 0) { + bus_dma_tag_destroy(dmah->tag); + free(dmah, M_DRM); + return ENOMEM; + } DRM_LOCK(); - if (dmah == NULL) + + ret = bus_dmamap_load(dmah->tag, dmah->map, dmah->vaddr, + gart_info->table_size, drm_ati_alloc_pcigart_table_cb, dmah, 0); + if (ret != 0) { + bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); + bus_dma_tag_destroy(dmah->tag); + free(dmah, M_DRM); return ENOMEM; + } dev->sg->dmah = dmah; return 0; } -static void drm_ati_free_pcigart_table(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) +static void +drm_ati_free_pcigart_table(struct drm_device *dev, + struct drm_ati_pcigart_info *gart_info) { - drm_pci_free(dev, dev->sg->dmah); + struct drm_dma_handle *dmah = dev->sg->dmah; + + bus_dmamem_free(dmah->tag, dmah->vaddr, dmah->map); + bus_dma_tag_destroy(dmah->tag); + free(dmah, M_DRM); dev->sg->dmah = NULL; } -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) { /* we need to support large memory configurations */ if (dev->sg == NULL) { @@ -82,17 +137,17 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info return 1; } -int drm_ati_pcigart_init(struct drm_device *dev, - struct drm_ati_pcigart_info *gart_info) +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; + dma_addr_t entry_addr; int i, j, ret = 0; int max_pages; - dma_addr_t entry_addr; /* we need to support large memory configurations */ if (dev->sg == NULL) { @@ -134,12 +189,14 @@ int drm_ati_pcigart_init(struct drm_device *dev, page_base = (u32) entry_addr & ATI_PCIGART_PAGE_MASK; switch(gart_info->gart_reg_if) { case DRM_ATI_GART_IGP: - page_base |= (upper_32_bits(entry_addr) & 0xff) << 4; + page_base |= + (upper_32_bits(entry_addr) & 0xff) << 4; page_base |= 0xc; break; case DRM_ATI_GART_PCIE: page_base >>= 8; - page_base |= (upper_32_bits(entry_addr) & 0xff) << 24; + page_base |= + (upper_32_bits(entry_addr) & 0xff) << 24; page_base |= ATI_PCIE_READ | ATI_PCIE_WRITE; break; default: @@ -152,8 +209,6 @@ int drm_ati_pcigart_init(struct drm_device *dev, } } - DRM_MEMORYBARRIER(); - ret = 1; done: |