Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/char/agp/ati-agp.c
15111 views
1
/*
2
* ATi AGPGART routines.
3
*/
4
5
#include <linux/types.h>
6
#include <linux/module.h>
7
#include <linux/pci.h>
8
#include <linux/init.h>
9
#include <linux/string.h>
10
#include <linux/slab.h>
11
#include <linux/agp_backend.h>
12
#include <asm/agp.h>
13
#include "agp.h"
14
15
#define ATI_GART_MMBASE_ADDR 0x14
16
#define ATI_RS100_APSIZE 0xac
17
#define ATI_RS100_IG_AGPMODE 0xb0
18
#define ATI_RS300_APSIZE 0xf8
19
#define ATI_RS300_IG_AGPMODE 0xfc
20
#define ATI_GART_FEATURE_ID 0x00
21
#define ATI_GART_BASE 0x04
22
#define ATI_GART_CACHE_SZBASE 0x08
23
#define ATI_GART_CACHE_CNTRL 0x0c
24
#define ATI_GART_CACHE_ENTRY_CNTRL 0x10
25
26
27
static const struct aper_size_info_lvl2 ati_generic_sizes[7] =
28
{
29
{2048, 524288, 0x0000000c},
30
{1024, 262144, 0x0000000a},
31
{512, 131072, 0x00000008},
32
{256, 65536, 0x00000006},
33
{128, 32768, 0x00000004},
34
{64, 16384, 0x00000002},
35
{32, 8192, 0x00000000}
36
};
37
38
static struct gatt_mask ati_generic_masks[] =
39
{
40
{ .mask = 1, .type = 0}
41
};
42
43
44
struct ati_page_map {
45
unsigned long *real;
46
unsigned long __iomem *remapped;
47
};
48
49
static struct _ati_generic_private {
50
volatile u8 __iomem *registers;
51
struct ati_page_map **gatt_pages;
52
int num_tables;
53
} ati_generic_private;
54
55
static int ati_create_page_map(struct ati_page_map *page_map)
56
{
57
int i, err = 0;
58
59
page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
60
if (page_map->real == NULL)
61
return -ENOMEM;
62
63
set_memory_uc((unsigned long)page_map->real, 1);
64
err = map_page_into_agp(virt_to_page(page_map->real));
65
page_map->remapped = page_map->real;
66
67
for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++) {
68
writel(agp_bridge->scratch_page, page_map->remapped+i);
69
readl(page_map->remapped+i); /* PCI Posting. */
70
}
71
72
return 0;
73
}
74
75
76
static void ati_free_page_map(struct ati_page_map *page_map)
77
{
78
unmap_page_from_agp(virt_to_page(page_map->real));
79
set_memory_wb((unsigned long)page_map->real, 1);
80
free_page((unsigned long) page_map->real);
81
}
82
83
84
static void ati_free_gatt_pages(void)
85
{
86
int i;
87
struct ati_page_map **tables;
88
struct ati_page_map *entry;
89
90
tables = ati_generic_private.gatt_pages;
91
for (i = 0; i < ati_generic_private.num_tables; i++) {
92
entry = tables[i];
93
if (entry != NULL) {
94
if (entry->real != NULL)
95
ati_free_page_map(entry);
96
kfree(entry);
97
}
98
}
99
kfree(tables);
100
}
101
102
103
static int ati_create_gatt_pages(int nr_tables)
104
{
105
struct ati_page_map **tables;
106
struct ati_page_map *entry;
107
int retval = 0;
108
int i;
109
110
tables = kzalloc((nr_tables + 1) * sizeof(struct ati_page_map *),GFP_KERNEL);
111
if (tables == NULL)
112
return -ENOMEM;
113
114
for (i = 0; i < nr_tables; i++) {
115
entry = kzalloc(sizeof(struct ati_page_map), GFP_KERNEL);
116
tables[i] = entry;
117
if (entry == NULL) {
118
retval = -ENOMEM;
119
break;
120
}
121
retval = ati_create_page_map(entry);
122
if (retval != 0)
123
break;
124
}
125
ati_generic_private.num_tables = i;
126
ati_generic_private.gatt_pages = tables;
127
128
if (retval != 0)
129
ati_free_gatt_pages();
130
131
return retval;
132
}
133
134
static int is_r200(void)
135
{
136
if ((agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS100) ||
137
(agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200) ||
138
(agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS200_B) ||
139
(agp_bridge->dev->device == PCI_DEVICE_ID_ATI_RS250))
140
return 1;
141
return 0;
142
}
143
144
static int ati_fetch_size(void)
145
{
146
int i;
147
u32 temp;
148
struct aper_size_info_lvl2 *values;
149
150
if (is_r200())
151
pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
152
else
153
pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
154
155
temp = (temp & 0x0000000e);
156
values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes);
157
for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
158
if (temp == values[i].size_value) {
159
agp_bridge->previous_size =
160
agp_bridge->current_size = (void *) (values + i);
161
162
agp_bridge->aperture_size_idx = i;
163
return values[i].size;
164
}
165
}
166
167
return 0;
168
}
169
170
static void ati_tlbflush(struct agp_memory * mem)
171
{
172
writel(1, ati_generic_private.registers+ATI_GART_CACHE_CNTRL);
173
readl(ati_generic_private.registers+ATI_GART_CACHE_CNTRL); /* PCI Posting. */
174
}
175
176
static void ati_cleanup(void)
177
{
178
struct aper_size_info_lvl2 *previous_size;
179
u32 temp;
180
181
previous_size = A_SIZE_LVL2(agp_bridge->previous_size);
182
183
/* Write back the previous size and disable gart translation */
184
if (is_r200()) {
185
pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
186
temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
187
pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp);
188
} else {
189
pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
190
temp = ((temp & ~(0x0000000f)) | previous_size->size_value);
191
pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp);
192
}
193
iounmap((volatile u8 __iomem *)ati_generic_private.registers);
194
}
195
196
197
static int ati_configure(void)
198
{
199
u32 temp;
200
201
/* Get the memory mapped registers */
202
pci_read_config_dword(agp_bridge->dev, ATI_GART_MMBASE_ADDR, &temp);
203
temp = (temp & 0xfffff000);
204
ati_generic_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
205
206
if (!ati_generic_private.registers)
207
return -ENOMEM;
208
209
if (is_r200())
210
pci_write_config_dword(agp_bridge->dev, ATI_RS100_IG_AGPMODE, 0x20000);
211
else
212
pci_write_config_dword(agp_bridge->dev, ATI_RS300_IG_AGPMODE, 0x20000);
213
214
/* address to map too */
215
/*
216
pci_read_config_dword(agp_bridge.dev, AGP_APBASE, &temp);
217
agp_bridge.gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
218
printk(KERN_INFO PFX "IGP320 gart_bus_addr: %x\n", agp_bridge.gart_bus_addr);
219
*/
220
writel(0x60000, ati_generic_private.registers+ATI_GART_FEATURE_ID);
221
readl(ati_generic_private.registers+ATI_GART_FEATURE_ID); /* PCI Posting.*/
222
223
/* SIGNALED_SYSTEM_ERROR @ NB_STATUS */
224
pci_read_config_dword(agp_bridge->dev, 4, &temp);
225
pci_write_config_dword(agp_bridge->dev, 4, temp | (1<<14));
226
227
/* Write out the address of the gatt table */
228
writel(agp_bridge->gatt_bus_addr, ati_generic_private.registers+ATI_GART_BASE);
229
readl(ati_generic_private.registers+ATI_GART_BASE); /* PCI Posting. */
230
231
return 0;
232
}
233
234
235
#ifdef CONFIG_PM
236
static int agp_ati_suspend(struct pci_dev *dev, pm_message_t state)
237
{
238
pci_save_state(dev);
239
pci_set_power_state(dev, 3);
240
241
return 0;
242
}
243
244
static int agp_ati_resume(struct pci_dev *dev)
245
{
246
pci_set_power_state(dev, 0);
247
pci_restore_state(dev);
248
249
return ati_configure();
250
}
251
#endif
252
253
/*
254
*Since we don't need contiguous memory we just try
255
* to get the gatt table once
256
*/
257
258
#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
259
#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
260
GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr))
261
#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
262
#undef GET_GATT
263
#define GET_GATT(addr) (ati_generic_private.gatt_pages[\
264
GET_PAGE_DIR_IDX(addr)]->remapped)
265
266
static int ati_insert_memory(struct agp_memory * mem,
267
off_t pg_start, int type)
268
{
269
int i, j, num_entries;
270
unsigned long __iomem *cur_gatt;
271
unsigned long addr;
272
int mask_type;
273
274
num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
275
276
mask_type = agp_generic_type_to_mask_type(mem->bridge, type);
277
if (mask_type != 0 || type != mem->type)
278
return -EINVAL;
279
280
if (mem->page_count == 0)
281
return 0;
282
283
if ((pg_start + mem->page_count) > num_entries)
284
return -EINVAL;
285
286
j = pg_start;
287
while (j < (pg_start + mem->page_count)) {
288
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
289
cur_gatt = GET_GATT(addr);
290
if (!PGE_EMPTY(agp_bridge,readl(cur_gatt+GET_GATT_OFF(addr))))
291
return -EBUSY;
292
j++;
293
}
294
295
if (!mem->is_flushed) {
296
/*CACHE_FLUSH(); */
297
global_cache_flush();
298
mem->is_flushed = true;
299
}
300
301
for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
302
addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
303
cur_gatt = GET_GATT(addr);
304
writel(agp_bridge->driver->mask_memory(agp_bridge,
305
page_to_phys(mem->pages[i]),
306
mem->type),
307
cur_gatt+GET_GATT_OFF(addr));
308
}
309
readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
310
agp_bridge->driver->tlb_flush(mem);
311
return 0;
312
}
313
314
static int ati_remove_memory(struct agp_memory * mem, off_t pg_start,
315
int type)
316
{
317
int i;
318
unsigned long __iomem *cur_gatt;
319
unsigned long addr;
320
int mask_type;
321
322
mask_type = agp_generic_type_to_mask_type(mem->bridge, type);
323
if (mask_type != 0 || type != mem->type)
324
return -EINVAL;
325
326
if (mem->page_count == 0)
327
return 0;
328
329
for (i = pg_start; i < (mem->page_count + pg_start); i++) {
330
addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
331
cur_gatt = GET_GATT(addr);
332
writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
333
}
334
335
readl(GET_GATT(agp_bridge->gart_bus_addr)); /* PCI posting */
336
agp_bridge->driver->tlb_flush(mem);
337
return 0;
338
}
339
340
static int ati_create_gatt_table(struct agp_bridge_data *bridge)
341
{
342
struct aper_size_info_lvl2 *value;
343
struct ati_page_map page_dir;
344
unsigned long __iomem *cur_gatt;
345
unsigned long addr;
346
int retval;
347
u32 temp;
348
int i;
349
struct aper_size_info_lvl2 *current_size;
350
351
value = A_SIZE_LVL2(agp_bridge->current_size);
352
retval = ati_create_page_map(&page_dir);
353
if (retval != 0)
354
return retval;
355
356
retval = ati_create_gatt_pages(value->num_entries / 1024);
357
if (retval != 0) {
358
ati_free_page_map(&page_dir);
359
return retval;
360
}
361
362
agp_bridge->gatt_table_real = (u32 *)page_dir.real;
363
agp_bridge->gatt_table = (u32 __iomem *) page_dir.remapped;
364
agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
365
366
/* Write out the size register */
367
current_size = A_SIZE_LVL2(agp_bridge->current_size);
368
369
if (is_r200()) {
370
pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
371
temp = (((temp & ~(0x0000000e)) | current_size->size_value)
372
| 0x00000001);
373
pci_write_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, temp);
374
pci_read_config_dword(agp_bridge->dev, ATI_RS100_APSIZE, &temp);
375
} else {
376
pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
377
temp = (((temp & ~(0x0000000e)) | current_size->size_value)
378
| 0x00000001);
379
pci_write_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, temp);
380
pci_read_config_dword(agp_bridge->dev, ATI_RS300_APSIZE, &temp);
381
}
382
383
/*
384
* Get the address for the gart region.
385
* This is a bus address even on the alpha, b/c its
386
* used to program the agp master not the cpu
387
*/
388
pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp);
389
addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
390
agp_bridge->gart_bus_addr = addr;
391
392
/* Calculate the agp offset */
393
for (i = 0; i < value->num_entries / 1024; i++, addr += 0x00400000) {
394
writel(virt_to_phys(ati_generic_private.gatt_pages[i]->real) | 1,
395
page_dir.remapped+GET_PAGE_DIR_OFF(addr));
396
readl(page_dir.remapped+GET_PAGE_DIR_OFF(addr)); /* PCI Posting. */
397
}
398
399
for (i = 0; i < value->num_entries; i++) {
400
addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
401
cur_gatt = GET_GATT(addr);
402
writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
403
}
404
405
return 0;
406
}
407
408
static int ati_free_gatt_table(struct agp_bridge_data *bridge)
409
{
410
struct ati_page_map page_dir;
411
412
page_dir.real = (unsigned long *)agp_bridge->gatt_table_real;
413
page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table;
414
415
ati_free_gatt_pages();
416
ati_free_page_map(&page_dir);
417
return 0;
418
}
419
420
static const struct agp_bridge_driver ati_generic_bridge = {
421
.owner = THIS_MODULE,
422
.aperture_sizes = ati_generic_sizes,
423
.size_type = LVL2_APER_SIZE,
424
.num_aperture_sizes = 7,
425
.needs_scratch_page = true,
426
.configure = ati_configure,
427
.fetch_size = ati_fetch_size,
428
.cleanup = ati_cleanup,
429
.tlb_flush = ati_tlbflush,
430
.mask_memory = agp_generic_mask_memory,
431
.masks = ati_generic_masks,
432
.agp_enable = agp_generic_enable,
433
.cache_flush = global_cache_flush,
434
.create_gatt_table = ati_create_gatt_table,
435
.free_gatt_table = ati_free_gatt_table,
436
.insert_memory = ati_insert_memory,
437
.remove_memory = ati_remove_memory,
438
.alloc_by_type = agp_generic_alloc_by_type,
439
.free_by_type = agp_generic_free_by_type,
440
.agp_alloc_page = agp_generic_alloc_page,
441
.agp_alloc_pages = agp_generic_alloc_pages,
442
.agp_destroy_page = agp_generic_destroy_page,
443
.agp_destroy_pages = agp_generic_destroy_pages,
444
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
445
};
446
447
448
static struct agp_device_ids ati_agp_device_ids[] __devinitdata =
449
{
450
{
451
.device_id = PCI_DEVICE_ID_ATI_RS100,
452
.chipset_name = "IGP320/M",
453
},
454
{
455
.device_id = PCI_DEVICE_ID_ATI_RS200,
456
.chipset_name = "IGP330/340/345/350/M",
457
},
458
{
459
.device_id = PCI_DEVICE_ID_ATI_RS200_B,
460
.chipset_name = "IGP345M",
461
},
462
{
463
.device_id = PCI_DEVICE_ID_ATI_RS250,
464
.chipset_name = "IGP7000/M",
465
},
466
{
467
.device_id = PCI_DEVICE_ID_ATI_RS300_100,
468
.chipset_name = "IGP9100/M",
469
},
470
{
471
.device_id = PCI_DEVICE_ID_ATI_RS300_133,
472
.chipset_name = "IGP9100/M",
473
},
474
{
475
.device_id = PCI_DEVICE_ID_ATI_RS300_166,
476
.chipset_name = "IGP9100/M",
477
},
478
{
479
.device_id = PCI_DEVICE_ID_ATI_RS300_200,
480
.chipset_name = "IGP9100/M",
481
},
482
{
483
.device_id = PCI_DEVICE_ID_ATI_RS350_133,
484
.chipset_name = "IGP9000/M",
485
},
486
{
487
.device_id = PCI_DEVICE_ID_ATI_RS350_200,
488
.chipset_name = "IGP9100/M",
489
},
490
{ }, /* dummy final entry, always present */
491
};
492
493
static int __devinit agp_ati_probe(struct pci_dev *pdev,
494
const struct pci_device_id *ent)
495
{
496
struct agp_device_ids *devs = ati_agp_device_ids;
497
struct agp_bridge_data *bridge;
498
u8 cap_ptr;
499
int j;
500
501
cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
502
if (!cap_ptr)
503
return -ENODEV;
504
505
/* probe for known chipsets */
506
for (j = 0; devs[j].chipset_name; j++) {
507
if (pdev->device == devs[j].device_id)
508
goto found;
509
}
510
511
dev_err(&pdev->dev, "unsupported Ati chipset [%04x/%04x])\n",
512
pdev->vendor, pdev->device);
513
return -ENODEV;
514
515
found:
516
bridge = agp_alloc_bridge();
517
if (!bridge)
518
return -ENOMEM;
519
520
bridge->dev = pdev;
521
bridge->capndx = cap_ptr;
522
523
bridge->driver = &ati_generic_bridge;
524
525
dev_info(&pdev->dev, "Ati %s chipset\n", devs[j].chipset_name);
526
527
/* Fill in the mode register */
528
pci_read_config_dword(pdev,
529
bridge->capndx+PCI_AGP_STATUS,
530
&bridge->mode);
531
532
pci_set_drvdata(pdev, bridge);
533
return agp_add_bridge(bridge);
534
}
535
536
static void __devexit agp_ati_remove(struct pci_dev *pdev)
537
{
538
struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
539
540
agp_remove_bridge(bridge);
541
agp_put_bridge(bridge);
542
}
543
544
static struct pci_device_id agp_ati_pci_table[] = {
545
{
546
.class = (PCI_CLASS_BRIDGE_HOST << 8),
547
.class_mask = ~0,
548
.vendor = PCI_VENDOR_ID_ATI,
549
.device = PCI_ANY_ID,
550
.subvendor = PCI_ANY_ID,
551
.subdevice = PCI_ANY_ID,
552
},
553
{ }
554
};
555
556
MODULE_DEVICE_TABLE(pci, agp_ati_pci_table);
557
558
static struct pci_driver agp_ati_pci_driver = {
559
.name = "agpgart-ati",
560
.id_table = agp_ati_pci_table,
561
.probe = agp_ati_probe,
562
.remove = agp_ati_remove,
563
#ifdef CONFIG_PM
564
.suspend = agp_ati_suspend,
565
.resume = agp_ati_resume,
566
#endif
567
};
568
569
static int __init agp_ati_init(void)
570
{
571
if (agp_off)
572
return -EINVAL;
573
return pci_register_driver(&agp_ati_pci_driver);
574
}
575
576
static void __exit agp_ati_cleanup(void)
577
{
578
pci_unregister_driver(&agp_ati_pci_driver);
579
}
580
581
module_init(agp_ati_init);
582
module_exit(agp_ati_cleanup);
583
584
MODULE_AUTHOR("Dave Jones <[email protected]>");
585
MODULE_LICENSE("GPL and additional rights");
586
587
588