1/* drm_agpsupport.h -- DRM support for AGP/GART backend -*- linux-c -*-
2 * Created: Mon Dec 13 09:56:45 1999 by faith@precisioninsight.com
3 *
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
22 * VA LINUX SYSTEMS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
26 *
27 * Author:
28 *    Rickard E. (Rik) Faith <faith@valinux.com>
29 *    Gareth Hughes <gareth@valinux.com>
30 */
31
32#include "drmP.h"
33#include <linux/module.h>
34
35#if __REALLY_HAVE_AGP
36
37#define DRM_AGP_GET (drm_agp_t *)inter_module_get("drm_agp")
38#define DRM_AGP_PUT inter_module_put("drm_agp")
39
40static const drm_agp_t *drm_agp = NULL;
41
42int DRM(agp_info)(struct inode *inode, struct file *filp,
43		  unsigned int cmd, unsigned long arg)
44{
45	drm_file_t	 *priv	 = filp->private_data;
46	drm_device_t	 *dev	 = priv->dev;
47	agp_kern_info    *kern;
48	drm_agp_info_t   info;
49
50	if (!dev->agp || !dev->agp->acquired || !drm_agp->copy_info)
51		return -EINVAL;
52
53	kern                   = &dev->agp->agp_info;
54	info.agp_version_major = kern->version.major;
55	info.agp_version_minor = kern->version.minor;
56	info.mode              = kern->mode;
57	info.aperture_base     = kern->aper_base;
58	info.aperture_size     = kern->aper_size * 1024 * 1024;
59	info.memory_allowed    = kern->max_memory << PAGE_SHIFT;
60	info.memory_used       = kern->current_memory << PAGE_SHIFT;
61	info.id_vendor         = kern->device->vendor;
62	info.id_device         = kern->device->device;
63
64	if (copy_to_user((drm_agp_info_t *)arg, &info, sizeof(info)))
65		return -EFAULT;
66	return 0;
67}
68
69int DRM(agp_acquire)(struct inode *inode, struct file *filp,
70		     unsigned int cmd, unsigned long arg)
71{
72	drm_file_t	 *priv	 = filp->private_data;
73	drm_device_t	 *dev	 = priv->dev;
74	int              retcode;
75
76	if (!dev->agp || dev->agp->acquired || !drm_agp->acquire)
77		return -EINVAL;
78	if ((retcode = drm_agp->acquire())) return retcode;
79	dev->agp->acquired = 1;
80	return 0;
81}
82
83int DRM(agp_release)(struct inode *inode, struct file *filp,
84		     unsigned int cmd, unsigned long arg)
85{
86	drm_file_t	 *priv	 = filp->private_data;
87	drm_device_t	 *dev	 = priv->dev;
88
89	if (!dev->agp || !dev->agp->acquired || !drm_agp->release)
90		return -EINVAL;
91	drm_agp->release();
92	dev->agp->acquired = 0;
93	return 0;
94
95}
96
97void DRM(agp_do_release)(void)
98{
99	if (drm_agp->release) drm_agp->release();
100}
101
102int DRM(agp_enable)(struct inode *inode, struct file *filp,
103		    unsigned int cmd, unsigned long arg)
104{
105	drm_file_t	 *priv	 = filp->private_data;
106	drm_device_t	 *dev	 = priv->dev;
107	drm_agp_mode_t   mode;
108
109	if (!dev->agp || !dev->agp->acquired || !drm_agp->enable)
110		return -EINVAL;
111
112	if (copy_from_user(&mode, (drm_agp_mode_t *)arg, sizeof(mode)))
113		return -EFAULT;
114
115	dev->agp->mode    = mode.mode;
116	drm_agp->enable(mode.mode);
117	dev->agp->base    = dev->agp->agp_info.aper_base;
118	dev->agp->enabled = 1;
119	return 0;
120}
121
122int DRM(agp_alloc)(struct inode *inode, struct file *filp,
123		   unsigned int cmd, unsigned long arg)
124{
125	drm_file_t	 *priv	 = filp->private_data;
126	drm_device_t	 *dev	 = priv->dev;
127	drm_agp_buffer_t request;
128	drm_agp_mem_t    *entry;
129	agp_memory       *memory;
130	unsigned long    pages;
131	u32 		 type;
132
133	if (!dev->agp || !dev->agp->acquired) return -EINVAL;
134	if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
135		return -EFAULT;
136	if (!(entry = DRM(alloc)(sizeof(*entry), DRM_MEM_AGPLISTS)))
137		return -ENOMEM;
138
139   	memset(entry, 0, sizeof(*entry));
140
141	pages = (request.size + PAGE_SIZE - 1) / PAGE_SIZE;
142	type = (u32) request.type;
143
144	if (!(memory = DRM(alloc_agp)(pages, type))) {
145		DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
146		return -ENOMEM;
147	}
148
149	entry->handle    = (unsigned long)memory->memory;
150	entry->memory    = memory;
151	entry->bound     = 0;
152	entry->pages     = pages;
153	entry->prev      = NULL;
154	entry->next      = dev->agp->memory;
155	if (dev->agp->memory) dev->agp->memory->prev = entry;
156	dev->agp->memory = entry;
157
158	request.handle   = entry->handle;
159        request.physical = memory->physical;
160
161	if (copy_to_user((drm_agp_buffer_t *)arg, &request, sizeof(request))) {
162		dev->agp->memory       = entry->next;
163		dev->agp->memory->prev = NULL;
164		DRM(free_agp)(memory, pages);
165		DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
166		return -EFAULT;
167	}
168	return 0;
169}
170
171static drm_agp_mem_t *DRM(agp_lookup_entry)(drm_device_t *dev,
172					    unsigned long handle)
173{
174	drm_agp_mem_t *entry;
175
176	for (entry = dev->agp->memory; entry; entry = entry->next) {
177		if (entry->handle == handle) return entry;
178	}
179	return NULL;
180}
181
182int DRM(agp_unbind)(struct inode *inode, struct file *filp,
183		    unsigned int cmd, unsigned long arg)
184{
185	drm_file_t	  *priv	 = filp->private_data;
186	drm_device_t	  *dev	 = priv->dev;
187	drm_agp_binding_t request;
188	drm_agp_mem_t     *entry;
189
190	if (!dev->agp || !dev->agp->acquired) return -EINVAL;
191	if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
192		return -EFAULT;
193	if (!(entry = DRM(agp_lookup_entry)(dev, request.handle)))
194		return -EINVAL;
195	if (!entry->bound) return -EINVAL;
196	return DRM(unbind_agp)(entry->memory);
197}
198
199int DRM(agp_bind)(struct inode *inode, struct file *filp,
200		  unsigned int cmd, unsigned long arg)
201{
202	drm_file_t	  *priv	 = filp->private_data;
203	drm_device_t	  *dev	 = priv->dev;
204	drm_agp_binding_t request;
205	drm_agp_mem_t     *entry;
206	int               retcode;
207	int               page;
208
209	if (!dev->agp || !dev->agp->acquired || !drm_agp->bind_memory)
210		return -EINVAL;
211	if (copy_from_user(&request, (drm_agp_binding_t *)arg, sizeof(request)))
212		return -EFAULT;
213	if (!(entry = DRM(agp_lookup_entry)(dev, request.handle)))
214		return -EINVAL;
215	if (entry->bound) return -EINVAL;
216	page = (request.offset + PAGE_SIZE - 1) / PAGE_SIZE;
217	if ((retcode = DRM(bind_agp)(entry->memory, page))) return retcode;
218	entry->bound = dev->agp->base + (page << PAGE_SHIFT);
219	DRM_DEBUG("base = 0x%lx entry->bound = 0x%lx\n",
220		  dev->agp->base, entry->bound);
221	return 0;
222}
223
224int DRM(agp_free)(struct inode *inode, struct file *filp,
225		  unsigned int cmd, unsigned long arg)
226{
227	drm_file_t	 *priv	 = filp->private_data;
228	drm_device_t	 *dev	 = priv->dev;
229	drm_agp_buffer_t request;
230	drm_agp_mem_t    *entry;
231
232	if (!dev->agp || !dev->agp->acquired) return -EINVAL;
233	if (copy_from_user(&request, (drm_agp_buffer_t *)arg, sizeof(request)))
234		return -EFAULT;
235	if (!(entry = DRM(agp_lookup_entry)(dev, request.handle)))
236		return -EINVAL;
237	if (entry->bound) DRM(unbind_agp)(entry->memory);
238
239	if (entry->prev) entry->prev->next = entry->next;
240	else             dev->agp->memory  = entry->next;
241	if (entry->next) entry->next->prev = entry->prev;
242	DRM(free_agp)(entry->memory, entry->pages);
243	DRM(free)(entry, sizeof(*entry), DRM_MEM_AGPLISTS);
244	return 0;
245}
246
247drm_agp_head_t *DRM(agp_init)(void)
248{
249	drm_agp_head_t *head         = NULL;
250
251	drm_agp = DRM_AGP_GET;
252	if (drm_agp) {
253		if (!(head = DRM(alloc)(sizeof(*head), DRM_MEM_AGPLISTS)))
254			return NULL;
255		memset((void *)head, 0, sizeof(*head));
256		drm_agp->copy_info(&head->agp_info);
257		if (head->agp_info.chipset == NOT_SUPPORTED) {
258			DRM(free)(head, sizeof(*head), DRM_MEM_AGPLISTS);
259			return NULL;
260		}
261		head->memory = NULL;
262		switch (head->agp_info.chipset) {
263		case INTEL_GENERIC:	head->chipset = "Intel";         break;
264		case INTEL_LX:		head->chipset = "Intel 440LX";   break;
265		case INTEL_BX:		head->chipset = "Intel 440BX";   break;
266		case INTEL_GX:		head->chipset = "Intel 440GX";   break;
267		case INTEL_I810:	head->chipset = "Intel i810";    break;
268		case INTEL_I815:	head->chipset = "Intel i815";	 break;
269	 	case INTEL_I820:	head->chipset = "Intel i820";	 break;
270		case INTEL_I840:	head->chipset = "Intel i840";    break;
271		case INTEL_I845:	head->chipset = "Intel i845";    break;
272		case INTEL_I850:	head->chipset = "Intel i850";	 break;
273
274		case VIA_GENERIC:	head->chipset = "VIA";           break;
275		case VIA_VP3:		head->chipset = "VIA VP3";       break;
276		case VIA_MVP3:		head->chipset = "VIA MVP3";      break;
277		case VIA_MVP4:		head->chipset = "VIA MVP4";      break;
278		case VIA_APOLLO_KX133:	head->chipset = "VIA Apollo KX133";
279			break;
280		case VIA_APOLLO_KT133:	head->chipset = "VIA Apollo KT133";
281			break;
282		case VIA_APOLLO_PRO: 	head->chipset = "VIA Apollo Pro";
283			break;
284
285		case SIS_GENERIC:	head->chipset = "SiS";           break;
286		case AMD_GENERIC:	head->chipset = "AMD";           break;
287		case AMD_IRONGATE:	head->chipset = "AMD Irongate";  break;
288		case AMD_8151:		head->chipset = "AMD 8151";      break;
289		case ALI_GENERIC:	head->chipset = "ALi";           break;
290		case ALI_M1541: 	head->chipset = "ALi M1541";     break;
291
292		case ALI_M1621: 	head->chipset = "ALi M1621";	 break;
293		case ALI_M1631: 	head->chipset = "ALi M1631";	 break;
294		case ALI_M1632: 	head->chipset = "ALi M1632";	 break;
295		case ALI_M1641: 	head->chipset = "ALi M1641";	 break;
296		case ALI_M1644: 	head->chipset = "ALi M1644";	 break;
297		case ALI_M1647: 	head->chipset = "ALi M1647";	 break;
298		case ALI_M1651: 	head->chipset = "ALi M1651";	 break;
299
300		case SVWRKS_HE: 	head->chipset = "Serverworks HE";
301			break;
302		case SVWRKS_LE: 	head->chipset = "Serverworks LE";
303			break;
304		case SVWRKS_GENERIC: 	head->chipset = "Serverworks Generic";
305			break;
306
307		case HP_ZX1:		head->chipset = "HP ZX1";	 break;
308
309		default:		head->chipset = "Unknown";       break;
310		}
311
312		head->cant_use_aperture = head->agp_info.cant_use_aperture;
313		head->page_mask = head->agp_info.page_mask;
314
315		DRM_INFO("AGP %d.%d on %s @ 0x%08lx %ZuMB\n",
316			 head->agp_info.version.major,
317			 head->agp_info.version.minor,
318			 head->chipset,
319			 head->agp_info.aper_base,
320			 head->agp_info.aper_size);
321	}
322	return head;
323}
324
325void DRM(agp_uninit)(void)
326{
327	DRM_AGP_PUT;
328	drm_agp = NULL;
329}
330
331agp_memory *DRM(agp_allocate_memory)(size_t pages, u32 type)
332{
333	if (!drm_agp->allocate_memory) return NULL;
334	return drm_agp->allocate_memory(pages, type);
335}
336
337int DRM(agp_free_memory)(agp_memory *handle)
338{
339	if (!handle || !drm_agp->free_memory) return 0;
340	drm_agp->free_memory(handle);
341	return 1;
342}
343
344int DRM(agp_bind_memory)(agp_memory *handle, off_t start)
345{
346	if (!handle || !drm_agp->bind_memory) return -EINVAL;
347	return drm_agp->bind_memory(handle, start);
348}
349
350int DRM(agp_unbind_memory)(agp_memory *handle)
351{
352	if (!handle || !drm_agp->unbind_memory) return -EINVAL;
353	return drm_agp->unbind_memory(handle);
354}
355
356#endif /* __REALLY_HAVE_AGP */
357