diff options
author | Dave Airlie <airlied@redhat.com> | 2008-03-16 20:24:24 -0400 |
---|---|---|
committer | Dave Airlie <airlied@redhat.com> | 2008-03-16 20:24:24 -0400 |
commit | b05c23851ab820b1957cd2f322eaa1ac44c196bd (patch) | |
tree | 59e1a38a36cadf683559dae629fc6583d1ca5141 /drivers/char/drm/ati_pcigart.c | |
parent | 16d3be46d9ffbc2c562b25d66d59666db2cf2cd5 (diff) |
drm/ati_pcigart: fix the PCIGART to use drm_pci to allocate GART table.
This fixes a problem on 64-bit with 4GB with ATI RS690 chipsets. It
makes sure the pcigart table is allocated in coherent memory for DMA operations.
Signed-off-by: Dave Airlie <airlied@redhat.com>
Diffstat (limited to 'drivers/char/drm/ati_pcigart.c')
-rw-r--r-- | drivers/char/drm/ati_pcigart.c | 91 |
1 files changed, 22 insertions, 69 deletions
diff --git a/drivers/char/drm/ati_pcigart.c b/drivers/char/drm/ati_pcigart.c index d352dbb4ccf7..e5a0e97cfdda 100644 --- a/drivers/char/drm/ati_pcigart.c +++ b/drivers/char/drm/ati_pcigart.c | |||
@@ -35,42 +35,23 @@ | |||
35 | 35 | ||
36 | # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ | 36 | # define ATI_PCIGART_PAGE_SIZE 4096 /**< PCI GART page size */ |
37 | 37 | ||
38 | static void *drm_ati_alloc_pcigart_table(int order) | 38 | static int drm_ati_alloc_pcigart_table(struct drm_device *dev, |
39 | struct drm_ati_pcigart_info *gart_info) | ||
39 | { | 40 | { |
40 | unsigned long address; | 41 | gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size, |
41 | struct page *page; | 42 | PAGE_SIZE, |
42 | int i; | 43 | gart_info->table_mask); |
43 | 44 | if (gart_info->table_handle == NULL) | |
44 | DRM_DEBUG("%d order\n", order); | 45 | return -ENOMEM; |
45 | |||
46 | address = __get_free_pages(GFP_KERNEL | __GFP_COMP, | ||
47 | order); | ||
48 | if (address == 0UL) { | ||
49 | return NULL; | ||
50 | } | ||
51 | |||
52 | page = virt_to_page(address); | ||
53 | 46 | ||
54 | for (i = 0; i < order; i++, page++) | 47 | return 0; |
55 | SetPageReserved(page); | ||
56 | |||
57 | DRM_DEBUG("returning 0x%08lx\n", address); | ||
58 | return (void *)address; | ||
59 | } | 48 | } |
60 | 49 | ||
61 | static void drm_ati_free_pcigart_table(void *address, int order) | 50 | static void drm_ati_free_pcigart_table(struct drm_device *dev, |
51 | struct drm_ati_pcigart_info *gart_info) | ||
62 | { | 52 | { |
63 | struct page *page; | 53 | drm_pci_free(dev, gart_info->table_handle); |
64 | int i; | 54 | gart_info->table_handle = NULL; |
65 | int num_pages = 1 << order; | ||
66 | DRM_DEBUG("\n"); | ||
67 | |||
68 | page = virt_to_page((unsigned long)address); | ||
69 | |||
70 | for (i = 0; i < num_pages; i++, page++) | ||
71 | ClearPageReserved(page); | ||
72 | |||
73 | free_pages((unsigned long)address, order); | ||
74 | } | 55 | } |
75 | 56 | ||
76 | int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) | 57 | int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info) |
@@ -78,8 +59,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info | |||
78 | struct drm_sg_mem *entry = dev->sg; | 59 | struct drm_sg_mem *entry = dev->sg; |
79 | unsigned long pages; | 60 | unsigned long pages; |
80 | int i; | 61 | int i; |
81 | int order; | 62 | int max_pages; |
82 | int num_pages, max_pages; | ||
83 | 63 | ||
84 | /* we need to support large memory configurations */ | 64 | /* we need to support large memory configurations */ |
85 | if (!entry) { | 65 | if (!entry) { |
@@ -87,15 +67,7 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info | |||
87 | return 0; | 67 | return 0; |
88 | } | 68 | } |
89 | 69 | ||
90 | order = drm_order((gart_info->table_size + (PAGE_SIZE-1)) / PAGE_SIZE); | ||
91 | num_pages = 1 << order; | ||
92 | |||
93 | if (gart_info->bus_addr) { | 70 | if (gart_info->bus_addr) { |
94 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { | ||
95 | pci_unmap_single(dev->pdev, gart_info->bus_addr, | ||
96 | num_pages * PAGE_SIZE, | ||
97 | PCI_DMA_TODEVICE); | ||
98 | } | ||
99 | 71 | ||
100 | max_pages = (gart_info->table_size / sizeof(u32)); | 72 | max_pages = (gart_info->table_size / sizeof(u32)); |
101 | pages = (entry->pages <= max_pages) | 73 | pages = (entry->pages <= max_pages) |
@@ -112,10 +84,9 @@ int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info | |||
112 | gart_info->bus_addr = 0; | 84 | gart_info->bus_addr = 0; |
113 | } | 85 | } |
114 | 86 | ||
115 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN | 87 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN && |
116 | && gart_info->addr) { | 88 | gart_info->table_handle) { |
117 | drm_ati_free_pcigart_table(gart_info->addr, order); | 89 | drm_ati_free_pcigart_table(dev, gart_info); |
118 | gart_info->addr = NULL; | ||
119 | } | 90 | } |
120 | 91 | ||
121 | return 1; | 92 | return 1; |
@@ -127,11 +98,10 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga | |||
127 | struct drm_sg_mem *entry = dev->sg; | 98 | struct drm_sg_mem *entry = dev->sg; |
128 | void *address = NULL; | 99 | void *address = NULL; |
129 | unsigned long pages; | 100 | unsigned long pages; |
130 | u32 *pci_gart, page_base, bus_address = 0; | 101 | u32 *pci_gart, page_base; |
102 | dma_addr_t bus_address = 0; | ||
131 | int i, j, ret = 0; | 103 | int i, j, ret = 0; |
132 | int order; | ||
133 | int max_pages; | 104 | int max_pages; |
134 | int num_pages; | ||
135 | 105 | ||
136 | if (!entry) { | 106 | if (!entry) { |
137 | DRM_ERROR("no scatter/gather memory!\n"); | 107 | DRM_ERROR("no scatter/gather memory!\n"); |
@@ -141,31 +111,14 @@ int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *ga | |||
141 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { | 111 | if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) { |
142 | DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); | 112 | DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n"); |
143 | 113 | ||
144 | order = drm_order((gart_info->table_size + | 114 | ret = drm_ati_alloc_pcigart_table(dev, gart_info); |
145 | (PAGE_SIZE-1)) / PAGE_SIZE); | 115 | if (ret) { |
146 | num_pages = 1 << order; | ||
147 | address = drm_ati_alloc_pcigart_table(order); | ||
148 | if (!address) { | ||
149 | DRM_ERROR("cannot allocate PCI GART page!\n"); | 116 | DRM_ERROR("cannot allocate PCI GART page!\n"); |
150 | goto done; | 117 | goto done; |
151 | } | 118 | } |
152 | 119 | ||
153 | if (!dev->pdev) { | 120 | address = gart_info->table_handle->vaddr; |
154 | DRM_ERROR("PCI device unknown!\n"); | 121 | bus_address = gart_info->table_handle->busaddr; |
155 | goto done; | ||
156 | } | ||
157 | |||
158 | bus_address = pci_map_single(dev->pdev, address, | ||
159 | num_pages * PAGE_SIZE, | ||
160 | PCI_DMA_TODEVICE); | ||
161 | if (bus_address == 0) { | ||
162 | DRM_ERROR("unable to map PCIGART pages!\n"); | ||
163 | order = drm_order((gart_info->table_size + | ||
164 | (PAGE_SIZE-1)) / PAGE_SIZE); | ||
165 | drm_ati_free_pcigart_table(address, order); | ||
166 | address = NULL; | ||
167 | goto done; | ||
168 | } | ||
169 | } else { | 122 | } else { |
170 | address = gart_info->addr; | 123 | address = gart_info->addr; |
171 | bus_address = gart_info->bus_addr; | 124 | bus_address = gart_info->bus_addr; |