Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/char/agp/backend.c
15109 views
1
/*
2
* AGPGART driver backend routines.
3
* Copyright (C) 2004 Silicon Graphics, Inc.
4
* Copyright (C) 2002-2003 Dave Jones.
5
* Copyright (C) 1999 Jeff Hartmann.
6
* Copyright (C) 1999 Precision Insight, Inc.
7
* Copyright (C) 1999 Xi Graphics, Inc.
8
*
9
* Permission is hereby granted, free of charge, to any person obtaining a
10
* copy of this software and associated documentation files (the "Software"),
11
* to deal in the Software without restriction, including without limitation
12
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
13
* and/or sell copies of the Software, and to permit persons to whom the
14
* Software is furnished to do so, subject to the following conditions:
15
*
16
* The above copyright notice and this permission notice shall be included
17
* in all copies or substantial portions of the Software.
18
*
19
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22
* JEFF HARTMANN, DAVE JONES, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
23
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
25
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
*
27
* TODO:
28
* - Allocate more than order 0 pages to avoid too much linear map splitting.
29
*/
30
#include <linux/module.h>
31
#include <linux/pci.h>
32
#include <linux/init.h>
33
#include <linux/slab.h>
34
#include <linux/pagemap.h>
35
#include <linux/miscdevice.h>
36
#include <linux/pm.h>
37
#include <linux/agp_backend.h>
38
#include <linux/agpgart.h>
39
#include <linux/vmalloc.h>
40
#include <asm/io.h>
41
#include "agp.h"
42
43
/* Due to XFree86 brain-damage, we can't go to 1.0 until they
44
* fix some real stupidity. It's only by chance we can bump
45
* past 0.99 at all due to some boolean logic error. */
46
#define AGPGART_VERSION_MAJOR 0
47
#define AGPGART_VERSION_MINOR 103
48
static const struct agp_version agp_current_version =
49
{
50
.major = AGPGART_VERSION_MAJOR,
51
.minor = AGPGART_VERSION_MINOR,
52
};
53
54
struct agp_bridge_data *(*agp_find_bridge)(struct pci_dev *) =
55
&agp_generic_find_bridge;
56
57
struct agp_bridge_data *agp_bridge;
58
LIST_HEAD(agp_bridges);
59
EXPORT_SYMBOL(agp_bridge);
60
EXPORT_SYMBOL(agp_bridges);
61
EXPORT_SYMBOL(agp_find_bridge);
62
63
/**
64
* agp_backend_acquire - attempt to acquire an agp backend.
65
*
66
*/
67
struct agp_bridge_data *agp_backend_acquire(struct pci_dev *pdev)
68
{
69
struct agp_bridge_data *bridge;
70
71
bridge = agp_find_bridge(pdev);
72
73
if (!bridge)
74
return NULL;
75
76
if (atomic_read(&bridge->agp_in_use))
77
return NULL;
78
atomic_inc(&bridge->agp_in_use);
79
return bridge;
80
}
81
EXPORT_SYMBOL(agp_backend_acquire);
82
83
84
/**
85
* agp_backend_release - release the lock on the agp backend.
86
*
87
* The caller must insure that the graphics aperture translation table
88
* is read for use by another entity.
89
*
90
* (Ensure that all memory it bound is unbound.)
91
*/
92
void agp_backend_release(struct agp_bridge_data *bridge)
93
{
94
95
if (bridge)
96
atomic_dec(&bridge->agp_in_use);
97
}
98
EXPORT_SYMBOL(agp_backend_release);
99
100
101
static const struct { int mem, agp; } maxes_table[] = {
102
{0, 0},
103
{32, 4},
104
{64, 28},
105
{128, 96},
106
{256, 204},
107
{512, 440},
108
{1024, 942},
109
{2048, 1920},
110
{4096, 3932}
111
};
112
113
static int agp_find_max(void)
114
{
115
long memory, index, result;
116
117
#if PAGE_SHIFT < 20
118
memory = totalram_pages >> (20 - PAGE_SHIFT);
119
#else
120
memory = totalram_pages << (PAGE_SHIFT - 20);
121
#endif
122
index = 1;
123
124
while ((memory > maxes_table[index].mem) && (index < 8))
125
index++;
126
127
result = maxes_table[index - 1].agp +
128
( (memory - maxes_table[index - 1].mem) *
129
(maxes_table[index].agp - maxes_table[index - 1].agp)) /
130
(maxes_table[index].mem - maxes_table[index - 1].mem);
131
132
result = result << (20 - PAGE_SHIFT);
133
return result;
134
}
135
136
137
static int agp_backend_initialize(struct agp_bridge_data *bridge)
138
{
139
int size_value, rc, got_gatt=0, got_keylist=0;
140
141
bridge->max_memory_agp = agp_find_max();
142
bridge->version = &agp_current_version;
143
144
if (bridge->driver->needs_scratch_page) {
145
struct page *page = bridge->driver->agp_alloc_page(bridge);
146
147
if (!page) {
148
dev_err(&bridge->dev->dev,
149
"can't get memory for scratch page\n");
150
return -ENOMEM;
151
}
152
153
bridge->scratch_page_page = page;
154
bridge->scratch_page_dma = page_to_phys(page);
155
156
bridge->scratch_page = bridge->driver->mask_memory(bridge,
157
bridge->scratch_page_dma, 0);
158
}
159
160
size_value = bridge->driver->fetch_size();
161
if (size_value == 0) {
162
dev_err(&bridge->dev->dev, "can't determine aperture size\n");
163
rc = -EINVAL;
164
goto err_out;
165
}
166
if (bridge->driver->create_gatt_table(bridge)) {
167
dev_err(&bridge->dev->dev,
168
"can't get memory for graphics translation table\n");
169
rc = -ENOMEM;
170
goto err_out;
171
}
172
got_gatt = 1;
173
174
bridge->key_list = vmalloc(PAGE_SIZE * 4);
175
if (bridge->key_list == NULL) {
176
dev_err(&bridge->dev->dev,
177
"can't allocate memory for key lists\n");
178
rc = -ENOMEM;
179
goto err_out;
180
}
181
got_keylist = 1;
182
183
/* FIXME vmalloc'd memory not guaranteed contiguous */
184
memset(bridge->key_list, 0, PAGE_SIZE * 4);
185
186
if (bridge->driver->configure()) {
187
dev_err(&bridge->dev->dev, "error configuring host chipset\n");
188
rc = -EINVAL;
189
goto err_out;
190
}
191
INIT_LIST_HEAD(&bridge->mapped_list);
192
spin_lock_init(&bridge->mapped_lock);
193
194
return 0;
195
196
err_out:
197
if (bridge->driver->needs_scratch_page) {
198
void *va = page_address(bridge->scratch_page_page);
199
200
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
201
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
202
}
203
if (got_gatt)
204
bridge->driver->free_gatt_table(bridge);
205
if (got_keylist) {
206
vfree(bridge->key_list);
207
bridge->key_list = NULL;
208
}
209
return rc;
210
}
211
212
/* cannot be __exit b/c as it could be called from __init code */
213
static void agp_backend_cleanup(struct agp_bridge_data *bridge)
214
{
215
if (bridge->driver->cleanup)
216
bridge->driver->cleanup();
217
if (bridge->driver->free_gatt_table)
218
bridge->driver->free_gatt_table(bridge);
219
220
vfree(bridge->key_list);
221
bridge->key_list = NULL;
222
223
if (bridge->driver->agp_destroy_page &&
224
bridge->driver->needs_scratch_page) {
225
void *va = page_address(bridge->scratch_page_page);
226
227
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_UNMAP);
228
bridge->driver->agp_destroy_page(va, AGP_PAGE_DESTROY_FREE);
229
}
230
}
231
232
/* When we remove the global variable agp_bridge from all drivers
233
* then agp_alloc_bridge and agp_generic_find_bridge need to be updated
234
*/
235
236
struct agp_bridge_data *agp_alloc_bridge(void)
237
{
238
struct agp_bridge_data *bridge;
239
240
bridge = kzalloc(sizeof(*bridge), GFP_KERNEL);
241
if (!bridge)
242
return NULL;
243
244
atomic_set(&bridge->agp_in_use, 0);
245
atomic_set(&bridge->current_memory_agp, 0);
246
247
if (list_empty(&agp_bridges))
248
agp_bridge = bridge;
249
250
return bridge;
251
}
252
EXPORT_SYMBOL(agp_alloc_bridge);
253
254
255
void agp_put_bridge(struct agp_bridge_data *bridge)
256
{
257
kfree(bridge);
258
259
if (list_empty(&agp_bridges))
260
agp_bridge = NULL;
261
}
262
EXPORT_SYMBOL(agp_put_bridge);
263
264
265
int agp_add_bridge(struct agp_bridge_data *bridge)
266
{
267
int error;
268
269
if (agp_off) {
270
error = -ENODEV;
271
goto err_put_bridge;
272
}
273
274
if (!bridge->dev) {
275
printk (KERN_DEBUG PFX "Erk, registering with no pci_dev!\n");
276
error = -EINVAL;
277
goto err_put_bridge;
278
}
279
280
/* Grab reference on the chipset driver. */
281
if (!try_module_get(bridge->driver->owner)) {
282
dev_info(&bridge->dev->dev, "can't lock chipset driver\n");
283
error = -EINVAL;
284
goto err_put_bridge;
285
}
286
287
error = agp_backend_initialize(bridge);
288
if (error) {
289
dev_info(&bridge->dev->dev,
290
"agp_backend_initialize() failed\n");
291
goto err_out;
292
}
293
294
if (list_empty(&agp_bridges)) {
295
error = agp_frontend_initialize();
296
if (error) {
297
dev_info(&bridge->dev->dev,
298
"agp_frontend_initialize() failed\n");
299
goto frontend_err;
300
}
301
302
dev_info(&bridge->dev->dev, "AGP aperture is %dM @ 0x%lx\n",
303
bridge->driver->fetch_size(), bridge->gart_bus_addr);
304
305
}
306
307
list_add(&bridge->list, &agp_bridges);
308
return 0;
309
310
frontend_err:
311
agp_backend_cleanup(bridge);
312
err_out:
313
module_put(bridge->driver->owner);
314
err_put_bridge:
315
agp_put_bridge(bridge);
316
return error;
317
}
318
EXPORT_SYMBOL_GPL(agp_add_bridge);
319
320
321
void agp_remove_bridge(struct agp_bridge_data *bridge)
322
{
323
agp_backend_cleanup(bridge);
324
list_del(&bridge->list);
325
if (list_empty(&agp_bridges))
326
agp_frontend_cleanup();
327
module_put(bridge->driver->owner);
328
}
329
EXPORT_SYMBOL_GPL(agp_remove_bridge);
330
331
int agp_off;
332
int agp_try_unsupported_boot;
333
EXPORT_SYMBOL(agp_off);
334
EXPORT_SYMBOL(agp_try_unsupported_boot);
335
336
static int __init agp_init(void)
337
{
338
if (!agp_off)
339
printk(KERN_INFO "Linux agpgart interface v%d.%d\n",
340
AGPGART_VERSION_MAJOR, AGPGART_VERSION_MINOR);
341
return 0;
342
}
343
344
static void __exit agp_exit(void)
345
{
346
}
347
348
#ifndef MODULE
349
static __init int agp_setup(char *s)
350
{
351
if (!strcmp(s,"off"))
352
agp_off = 1;
353
if (!strcmp(s,"try_unsupported"))
354
agp_try_unsupported_boot = 1;
355
return 1;
356
}
357
__setup("agp=", agp_setup);
358
#endif
359
360
MODULE_AUTHOR("Dave Jones <[email protected]>");
361
MODULE_DESCRIPTION("AGP GART driver");
362
MODULE_LICENSE("GPL and additional rights");
363
MODULE_ALIAS_MISCDEV(AGPGART_MINOR);
364
365
module_init(agp_init);
366
module_exit(agp_exit);
367
368
369