Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/char/agp/sgi-agp.c
15111 views
1
/*
2
* This file is subject to the terms and conditions of the GNU General Public
3
* License. See the file "COPYING" in the main directory of this archive
4
* for more details.
5
*
6
* Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved.
7
*/
8
9
/*
10
* SGI TIOCA AGPGART routines.
11
*
12
*/
13
14
#include <linux/acpi.h>
15
#include <linux/module.h>
16
#include <linux/pci.h>
17
#include <linux/slab.h>
18
#include <linux/init.h>
19
#include <linux/agp_backend.h>
20
#include <asm/sn/addrs.h>
21
#include <asm/sn/io.h>
22
#include <asm/sn/pcidev.h>
23
#include <asm/sn/pcibus_provider_defs.h>
24
#include <asm/sn/tioca_provider.h>
25
#include "agp.h"
26
27
extern int agp_memory_reserved;
28
extern uint32_t tioca_gart_found;
29
extern struct list_head tioca_list;
30
static struct agp_bridge_data **sgi_tioca_agp_bridges;
31
32
/*
33
* The aperature size and related information is set up at TIOCA init time.
34
* Values for this table will be extracted and filled in at
35
* sgi_tioca_fetch_size() time.
36
*/
37
38
static struct aper_size_info_fixed sgi_tioca_sizes[] = {
39
{0, 0, 0},
40
};
41
42
static struct page *sgi_tioca_alloc_page(struct agp_bridge_data *bridge)
43
{
44
struct page *page;
45
int nid;
46
struct tioca_kernel *info =
47
(struct tioca_kernel *)bridge->dev_private_data;
48
49
nid = info->ca_closest_node;
50
page = alloc_pages_node(nid, GFP_KERNEL, 0);
51
if (!page)
52
return NULL;
53
54
get_page(page);
55
atomic_inc(&agp_bridge->current_memory_agp);
56
return page;
57
}
58
59
/*
60
* Flush GART tlb's. Cannot selectively flush based on memory so the mem
61
* arg is ignored.
62
*/
63
64
static void sgi_tioca_tlbflush(struct agp_memory *mem)
65
{
66
tioca_tlbflush(mem->bridge->dev_private_data);
67
}
68
69
/*
70
* Given an address of a host physical page, turn it into a valid gart
71
* entry.
72
*/
73
static unsigned long
74
sgi_tioca_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
75
int type)
76
{
77
return tioca_physpage_to_gart(addr);
78
}
79
80
static void sgi_tioca_agp_enable(struct agp_bridge_data *bridge, u32 mode)
81
{
82
tioca_fastwrite_enable(bridge->dev_private_data);
83
}
84
85
/*
86
* sgi_tioca_configure() doesn't have anything to do since the base CA driver
87
* has alreay set up the GART.
88
*/
89
90
static int sgi_tioca_configure(void)
91
{
92
return 0;
93
}
94
95
/*
96
* Determine gfx aperature size. This has already been determined by the
97
* CA driver init, so just need to set agp_bridge values accordingly.
98
*/
99
100
static int sgi_tioca_fetch_size(void)
101
{
102
struct tioca_kernel *info =
103
(struct tioca_kernel *)agp_bridge->dev_private_data;
104
105
sgi_tioca_sizes[0].size = info->ca_gfxap_size / MB(1);
106
sgi_tioca_sizes[0].num_entries = info->ca_gfxgart_entries;
107
108
return sgi_tioca_sizes[0].size;
109
}
110
111
static int sgi_tioca_create_gatt_table(struct agp_bridge_data *bridge)
112
{
113
struct tioca_kernel *info =
114
(struct tioca_kernel *)bridge->dev_private_data;
115
116
bridge->gatt_table_real = (u32 *) info->ca_gfxgart;
117
bridge->gatt_table = bridge->gatt_table_real;
118
bridge->gatt_bus_addr = info->ca_gfxgart_base;
119
120
return 0;
121
}
122
123
static int sgi_tioca_free_gatt_table(struct agp_bridge_data *bridge)
124
{
125
return 0;
126
}
127
128
static int sgi_tioca_insert_memory(struct agp_memory *mem, off_t pg_start,
129
int type)
130
{
131
int num_entries;
132
size_t i;
133
off_t j;
134
void *temp;
135
struct agp_bridge_data *bridge;
136
u64 *table;
137
138
bridge = mem->bridge;
139
if (!bridge)
140
return -EINVAL;
141
142
table = (u64 *)bridge->gatt_table;
143
144
temp = bridge->current_size;
145
146
switch (bridge->driver->size_type) {
147
case U8_APER_SIZE:
148
num_entries = A_SIZE_8(temp)->num_entries;
149
break;
150
case U16_APER_SIZE:
151
num_entries = A_SIZE_16(temp)->num_entries;
152
break;
153
case U32_APER_SIZE:
154
num_entries = A_SIZE_32(temp)->num_entries;
155
break;
156
case FIXED_APER_SIZE:
157
num_entries = A_SIZE_FIX(temp)->num_entries;
158
break;
159
case LVL2_APER_SIZE:
160
return -EINVAL;
161
break;
162
default:
163
num_entries = 0;
164
break;
165
}
166
167
num_entries -= agp_memory_reserved / PAGE_SIZE;
168
if (num_entries < 0)
169
num_entries = 0;
170
171
if (type != 0 || mem->type != 0) {
172
return -EINVAL;
173
}
174
175
if ((pg_start + mem->page_count) > num_entries)
176
return -EINVAL;
177
178
j = pg_start;
179
180
while (j < (pg_start + mem->page_count)) {
181
if (table[j])
182
return -EBUSY;
183
j++;
184
}
185
186
if (!mem->is_flushed) {
187
bridge->driver->cache_flush();
188
mem->is_flushed = true;
189
}
190
191
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
192
table[j] =
193
bridge->driver->mask_memory(bridge,
194
page_to_phys(mem->pages[i]),
195
mem->type);
196
}
197
198
bridge->driver->tlb_flush(mem);
199
return 0;
200
}
201
202
static int sgi_tioca_remove_memory(struct agp_memory *mem, off_t pg_start,
203
int type)
204
{
205
size_t i;
206
struct agp_bridge_data *bridge;
207
u64 *table;
208
209
bridge = mem->bridge;
210
if (!bridge)
211
return -EINVAL;
212
213
if (type != 0 || mem->type != 0) {
214
return -EINVAL;
215
}
216
217
table = (u64 *)bridge->gatt_table;
218
219
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
220
table[i] = 0;
221
}
222
223
bridge->driver->tlb_flush(mem);
224
return 0;
225
}
226
227
static void sgi_tioca_cache_flush(void)
228
{
229
}
230
231
/*
232
* Cleanup. Nothing to do as the CA driver owns the GART.
233
*/
234
235
static void sgi_tioca_cleanup(void)
236
{
237
}
238
239
static struct agp_bridge_data *sgi_tioca_find_bridge(struct pci_dev *pdev)
240
{
241
struct agp_bridge_data *bridge;
242
243
list_for_each_entry(bridge, &agp_bridges, list) {
244
if (bridge->dev->bus == pdev->bus)
245
break;
246
}
247
return bridge;
248
}
249
250
const struct agp_bridge_driver sgi_tioca_driver = {
251
.owner = THIS_MODULE,
252
.size_type = U16_APER_SIZE,
253
.configure = sgi_tioca_configure,
254
.fetch_size = sgi_tioca_fetch_size,
255
.cleanup = sgi_tioca_cleanup,
256
.tlb_flush = sgi_tioca_tlbflush,
257
.mask_memory = sgi_tioca_mask_memory,
258
.agp_enable = sgi_tioca_agp_enable,
259
.cache_flush = sgi_tioca_cache_flush,
260
.create_gatt_table = sgi_tioca_create_gatt_table,
261
.free_gatt_table = sgi_tioca_free_gatt_table,
262
.insert_memory = sgi_tioca_insert_memory,
263
.remove_memory = sgi_tioca_remove_memory,
264
.alloc_by_type = agp_generic_alloc_by_type,
265
.free_by_type = agp_generic_free_by_type,
266
.agp_alloc_page = sgi_tioca_alloc_page,
267
.agp_destroy_page = agp_generic_destroy_page,
268
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
269
.cant_use_aperture = true,
270
.needs_scratch_page = false,
271
.num_aperture_sizes = 1,
272
};
273
274
static int __devinit agp_sgi_init(void)
275
{
276
unsigned int j;
277
struct tioca_kernel *info;
278
struct pci_dev *pdev = NULL;
279
280
if (tioca_gart_found)
281
printk(KERN_INFO PFX "SGI TIO CA GART driver initialized.\n");
282
else
283
return 0;
284
285
sgi_tioca_agp_bridges = kmalloc(tioca_gart_found *
286
sizeof(struct agp_bridge_data *),
287
GFP_KERNEL);
288
if (!sgi_tioca_agp_bridges)
289
return -ENOMEM;
290
291
j = 0;
292
list_for_each_entry(info, &tioca_list, ca_list) {
293
struct list_head *tmp;
294
if (list_empty(info->ca_devices))
295
continue;
296
list_for_each(tmp, info->ca_devices) {
297
u8 cap_ptr;
298
pdev = pci_dev_b(tmp);
299
if (pdev->class != (PCI_CLASS_DISPLAY_VGA << 8))
300
continue;
301
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
302
if (!cap_ptr)
303
continue;
304
}
305
sgi_tioca_agp_bridges[j] = agp_alloc_bridge();
306
printk(KERN_INFO PFX "bridge %d = 0x%p\n", j,
307
sgi_tioca_agp_bridges[j]);
308
if (sgi_tioca_agp_bridges[j]) {
309
sgi_tioca_agp_bridges[j]->dev = pdev;
310
sgi_tioca_agp_bridges[j]->dev_private_data = info;
311
sgi_tioca_agp_bridges[j]->driver = &sgi_tioca_driver;
312
sgi_tioca_agp_bridges[j]->gart_bus_addr =
313
info->ca_gfxap_base;
314
sgi_tioca_agp_bridges[j]->mode = (0x7D << 24) | /* 126 requests */
315
(0x1 << 9) | /* SBA supported */
316
(0x1 << 5) | /* 64-bit addresses supported */
317
(0x1 << 4) | /* FW supported */
318
(0x1 << 3) | /* AGP 3.0 mode */
319
0x2; /* 8x transfer only */
320
sgi_tioca_agp_bridges[j]->current_size =
321
sgi_tioca_agp_bridges[j]->previous_size =
322
(void *)&sgi_tioca_sizes[0];
323
agp_add_bridge(sgi_tioca_agp_bridges[j]);
324
}
325
j++;
326
}
327
328
agp_find_bridge = &sgi_tioca_find_bridge;
329
return 0;
330
}
331
332
static void __devexit agp_sgi_cleanup(void)
333
{
334
kfree(sgi_tioca_agp_bridges);
335
sgi_tioca_agp_bridges = NULL;
336
}
337
338
module_init(agp_sgi_init);
339
module_exit(agp_sgi_cleanup);
340
341
MODULE_LICENSE("GPL and additional rights");
342
343