summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrnoland <rnoland@FreeBSD.org>2008-09-09 02:18:37 +0000
committerrnoland <rnoland@FreeBSD.org>2008-09-09 02:18:37 +0000
commitee52a364f71a599f68bf8297608855b6157c4576 (patch)
treea6ae6913cb7d6368d66e25ce1d1c5fdde2204ef3
parent016be156e0964094bf2d383d94aef409a35dc78c (diff)
downloadFreeBSD-src-ee52a364f71a599f68bf8297608855b6157c4576.zip
FreeBSD-src-ee52a364f71a599f68bf8297608855b6157c4576.tar.gz
IGP based radeon cards such as the rs485 and rs690 require that the GART table
be un-cached. Our previous memory barrier was not sufficient. This patch allocates the IGP GART tables using the BUS_DMA_NOCACHE flag to get these cards working. Approved by: kib
-rw-r--r--sys/dev/drm/ati_pcigart.c91
1 files changed, 73 insertions, 18 deletions
diff --git a/sys/dev/drm/ati_pcigart.c b/sys/dev/drm/ati_pcigart.c
index 597479c..2bd1fdb 100644
--- a/sys/dev/drm/ati_pcigart.c
+++ b/sys/dev/drm/ati_pcigart.c
@@ -42,31 +42,86 @@ __FBSDID("$FreeBSD$");
#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) {
@@ -85,17 +140,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) {
@@ -137,12 +192,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:
@@ -155,8 +212,6 @@ int drm_ati_pcigart_init(struct drm_device *dev,
}
}
- DRM_MEMORYBARRIER();
-
ret = 1;
done:
OpenPOWER on IntegriCloud