OSDN Git Service

[FreeBSD] IGP gart needs to be un-cached.
authorRobert Noland <rnoland@2hip.net>
Sun, 7 Sep 2008 01:08:33 +0000 (21:08 -0400)
committerRobert Noland <rnoland@2hip.net>
Sun, 7 Sep 2008 01:08:33 +0000 (21:08 -0400)
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.

bsd-core/ati_pcigart.c

index c4453ed..5feeeba 100644 (file)
 #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: