Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ati_pcigart.c
Go to the documentation of this file.
1 
8 /*
9  * Created: Wed Dec 13 21:52:19 2000 by [email protected]
10  *
11  * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
12  * All Rights Reserved.
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice (including the next
22  * paragraph) shall be included in all copies or substantial portions of the
23  * Software.
24  *
25  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
26  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
27  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
28  * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
29  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
30  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
31  * DEALINGS IN THE SOFTWARE.
32  */
33 
34 #include <linux/export.h>
35 #include <drm/drmP.h>
36 
37 # define ATI_PCIGART_PAGE_SIZE 4096
39 static int drm_ati_alloc_pcigart_table(struct drm_device *dev,
40  struct drm_ati_pcigart_info *gart_info)
41 {
42  gart_info->table_handle = drm_pci_alloc(dev, gart_info->table_size,
43  PAGE_SIZE);
44  if (gart_info->table_handle == NULL)
45  return -ENOMEM;
46 
47  return 0;
48 }
49 
50 static void drm_ati_free_pcigart_table(struct drm_device *dev,
51  struct drm_ati_pcigart_info *gart_info)
52 {
53  drm_pci_free(dev, gart_info->table_handle);
54  gart_info->table_handle = NULL;
55 }
56 
57 int drm_ati_pcigart_cleanup(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
58 {
59  struct drm_sg_mem *entry = dev->sg;
60  unsigned long pages;
61  int i;
62  int max_pages;
63 
64  /* we need to support large memory configurations */
65  if (!entry) {
66  DRM_ERROR("no scatter/gather memory!\n");
67  return 0;
68  }
69 
70  if (gart_info->bus_addr) {
71 
72  max_pages = (gart_info->table_size / sizeof(u32));
73  pages = (entry->pages <= max_pages)
74  ? entry->pages : max_pages;
75 
76  for (i = 0; i < pages; i++) {
77  if (!entry->busaddr[i])
78  break;
79  pci_unmap_page(dev->pdev, entry->busaddr[i],
81  }
82 
83  if (gart_info->gart_table_location == DRM_ATI_GART_MAIN)
84  gart_info->bus_addr = 0;
85  }
86 
87  if (gart_info->gart_table_location == DRM_ATI_GART_MAIN &&
88  gart_info->table_handle) {
89  drm_ati_free_pcigart_table(dev, gart_info);
90  }
91 
92  return 1;
93 }
95 
96 int drm_ati_pcigart_init(struct drm_device *dev, struct drm_ati_pcigart_info *gart_info)
97 {
98  struct drm_local_map *map = &gart_info->mapping;
99  struct drm_sg_mem *entry = dev->sg;
100  void *address = NULL;
101  unsigned long pages;
102  u32 *pci_gart = NULL, page_base, gart_idx;
103  dma_addr_t bus_address = 0;
104  int i, j, ret = 0;
105  int max_ati_pages, max_real_pages;
106 
107  if (!entry) {
108  DRM_ERROR("no scatter/gather memory!\n");
109  goto done;
110  }
111 
112  if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
113  DRM_DEBUG("PCI: no table in VRAM: using normal RAM\n");
114 
115  if (pci_set_dma_mask(dev->pdev, gart_info->table_mask)) {
116  DRM_ERROR("fail to set dma mask to 0x%Lx\n",
117  (unsigned long long)gart_info->table_mask);
118  ret = 1;
119  goto done;
120  }
121 
122  ret = drm_ati_alloc_pcigart_table(dev, gart_info);
123  if (ret) {
124  DRM_ERROR("cannot allocate PCI GART page!\n");
125  goto done;
126  }
127 
128  pci_gart = gart_info->table_handle->vaddr;
129  address = gart_info->table_handle->vaddr;
130  bus_address = gart_info->table_handle->busaddr;
131  } else {
132  address = gart_info->addr;
133  bus_address = gart_info->bus_addr;
134  DRM_DEBUG("PCI: Gart Table: VRAM %08LX mapped at %08lX\n",
135  (unsigned long long)bus_address,
136  (unsigned long)address);
137  }
138 
139 
140  max_ati_pages = (gart_info->table_size / sizeof(u32));
141  max_real_pages = max_ati_pages / (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE);
142  pages = (entry->pages <= max_real_pages)
143  ? entry->pages : max_real_pages;
144 
145  if (gart_info->gart_table_location == DRM_ATI_GART_MAIN) {
146  memset(pci_gart, 0, max_ati_pages * sizeof(u32));
147  } else {
148  memset_io((void __iomem *)map->handle, 0, max_ati_pages * sizeof(u32));
149  }
150 
151  gart_idx = 0;
152  for (i = 0; i < pages; i++) {
153  /* we need to support large memory configurations */
154  entry->busaddr[i] = pci_map_page(dev->pdev, entry->pagelist[i],
156  if (pci_dma_mapping_error(dev->pdev, entry->busaddr[i])) {
157  DRM_ERROR("unable to map PCIGART pages!\n");
158  drm_ati_pcigart_cleanup(dev, gart_info);
159  address = NULL;
160  bus_address = 0;
161  goto done;
162  }
163  page_base = (u32) entry->busaddr[i];
164 
165  for (j = 0; j < (PAGE_SIZE / ATI_PCIGART_PAGE_SIZE); j++) {
166  u32 val;
167 
168  switch(gart_info->gart_reg_if) {
169  case DRM_ATI_GART_IGP:
170  val = page_base | 0xc;
171  break;
172  case DRM_ATI_GART_PCIE:
173  val = (page_base >> 8) | 0xc;
174  break;
175  default:
176  case DRM_ATI_GART_PCI:
177  val = page_base;
178  break;
179  }
180  if (gart_info->gart_table_location ==
181  DRM_ATI_GART_MAIN)
182  pci_gart[gart_idx] = cpu_to_le32(val);
183  else
184  DRM_WRITE32(map, gart_idx * sizeof(u32), val);
185  gart_idx++;
186  page_base += ATI_PCIGART_PAGE_SIZE;
187  }
188  }
189  ret = 1;
190 
191 #if defined(__i386__) || defined(__x86_64__)
192  wbinvd();
193 #else
194  mb();
195 #endif
196 
197  done:
198  gart_info->addr = address;
199  gart_info->bus_addr = bus_address;
200  return ret;
201 }