Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/char/agp/parisc-agp.c
15111 views
1
/*
2
* HP Quicksilver AGP GART routines
3
*
4
* Copyright (c) 2006, Kyle McMartin <[email protected]>
5
*
6
* Based on drivers/char/agpgart/hp-agp.c which is
7
* (c) Copyright 2002, 2003 Hewlett-Packard Development Company, L.P.
8
* Bjorn Helgaas <[email protected]>
9
*
10
* This program is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License version 2 as
12
* published by the Free Software Foundation.
13
*
14
*/
15
16
#include <linux/module.h>
17
#include <linux/pci.h>
18
#include <linux/init.h>
19
#include <linux/klist.h>
20
#include <linux/agp_backend.h>
21
#include <linux/log2.h>
22
#include <linux/slab.h>
23
24
#include <asm/parisc-device.h>
25
#include <asm/ropes.h>
26
27
#include "agp.h"
28
29
#define DRVNAME "quicksilver"
30
#define DRVPFX DRVNAME ": "
31
32
#define AGP8X_MODE_BIT 3
33
#define AGP8X_MODE (1 << AGP8X_MODE_BIT)
34
35
static unsigned long
36
parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
37
int type);
38
39
static struct _parisc_agp_info {
40
void __iomem *ioc_regs;
41
void __iomem *lba_regs;
42
43
int lba_cap_offset;
44
45
u64 *gatt;
46
u64 gatt_entries;
47
48
u64 gart_base;
49
u64 gart_size;
50
51
int io_page_size;
52
int io_pages_per_kpage;
53
} parisc_agp_info;
54
55
static struct gatt_mask parisc_agp_masks[] =
56
{
57
{
58
.mask = SBA_PDIR_VALID_BIT,
59
.type = 0
60
}
61
};
62
63
static struct aper_size_info_fixed parisc_agp_sizes[] =
64
{
65
{0, 0, 0}, /* filled in by parisc_agp_fetch_size() */
66
};
67
68
static int
69
parisc_agp_fetch_size(void)
70
{
71
int size;
72
73
size = parisc_agp_info.gart_size / MB(1);
74
parisc_agp_sizes[0].size = size;
75
agp_bridge->current_size = (void *) &parisc_agp_sizes[0];
76
77
return size;
78
}
79
80
static int
81
parisc_agp_configure(void)
82
{
83
struct _parisc_agp_info *info = &parisc_agp_info;
84
85
agp_bridge->gart_bus_addr = info->gart_base;
86
agp_bridge->capndx = info->lba_cap_offset;
87
agp_bridge->mode = readl(info->lba_regs+info->lba_cap_offset+PCI_AGP_STATUS);
88
89
return 0;
90
}
91
92
static void
93
parisc_agp_tlbflush(struct agp_memory *mem)
94
{
95
struct _parisc_agp_info *info = &parisc_agp_info;
96
97
writeq(info->gart_base | ilog2(info->gart_size), info->ioc_regs+IOC_PCOM);
98
readq(info->ioc_regs+IOC_PCOM); /* flush */
99
}
100
101
static int
102
parisc_agp_create_gatt_table(struct agp_bridge_data *bridge)
103
{
104
struct _parisc_agp_info *info = &parisc_agp_info;
105
int i;
106
107
for (i = 0; i < info->gatt_entries; i++) {
108
info->gatt[i] = (unsigned long)agp_bridge->scratch_page;
109
}
110
111
return 0;
112
}
113
114
static int
115
parisc_agp_free_gatt_table(struct agp_bridge_data *bridge)
116
{
117
struct _parisc_agp_info *info = &parisc_agp_info;
118
119
info->gatt[0] = SBA_AGPGART_COOKIE;
120
121
return 0;
122
}
123
124
static int
125
parisc_agp_insert_memory(struct agp_memory *mem, off_t pg_start, int type)
126
{
127
struct _parisc_agp_info *info = &parisc_agp_info;
128
int i, k;
129
off_t j, io_pg_start;
130
int io_pg_count;
131
132
if (type != 0 || mem->type != 0) {
133
return -EINVAL;
134
}
135
136
io_pg_start = info->io_pages_per_kpage * pg_start;
137
io_pg_count = info->io_pages_per_kpage * mem->page_count;
138
if ((io_pg_start + io_pg_count) > info->gatt_entries) {
139
return -EINVAL;
140
}
141
142
j = io_pg_start;
143
while (j < (io_pg_start + io_pg_count)) {
144
if (info->gatt[j])
145
return -EBUSY;
146
j++;
147
}
148
149
if (!mem->is_flushed) {
150
global_cache_flush();
151
mem->is_flushed = true;
152
}
153
154
for (i = 0, j = io_pg_start; i < mem->page_count; i++) {
155
unsigned long paddr;
156
157
paddr = page_to_phys(mem->pages[i]);
158
for (k = 0;
159
k < info->io_pages_per_kpage;
160
k++, j++, paddr += info->io_page_size) {
161
info->gatt[j] =
162
parisc_agp_mask_memory(agp_bridge,
163
paddr, type);
164
}
165
}
166
167
agp_bridge->driver->tlb_flush(mem);
168
169
return 0;
170
}
171
172
static int
173
parisc_agp_remove_memory(struct agp_memory *mem, off_t pg_start, int type)
174
{
175
struct _parisc_agp_info *info = &parisc_agp_info;
176
int i, io_pg_start, io_pg_count;
177
178
if (type != 0 || mem->type != 0) {
179
return -EINVAL;
180
}
181
182
io_pg_start = info->io_pages_per_kpage * pg_start;
183
io_pg_count = info->io_pages_per_kpage * mem->page_count;
184
for (i = io_pg_start; i < io_pg_count + io_pg_start; i++) {
185
info->gatt[i] = agp_bridge->scratch_page;
186
}
187
188
agp_bridge->driver->tlb_flush(mem);
189
return 0;
190
}
191
192
static unsigned long
193
parisc_agp_mask_memory(struct agp_bridge_data *bridge, dma_addr_t addr,
194
int type)
195
{
196
return SBA_PDIR_VALID_BIT | addr;
197
}
198
199
static void
200
parisc_agp_enable(struct agp_bridge_data *bridge, u32 mode)
201
{
202
struct _parisc_agp_info *info = &parisc_agp_info;
203
u32 command;
204
205
command = readl(info->lba_regs + info->lba_cap_offset + PCI_AGP_STATUS);
206
207
command = agp_collect_device_status(bridge, mode, command);
208
command |= 0x00000100;
209
210
writel(command, info->lba_regs + info->lba_cap_offset + PCI_AGP_COMMAND);
211
212
agp_device_command(command, (mode & AGP8X_MODE) != 0);
213
}
214
215
static const struct agp_bridge_driver parisc_agp_driver = {
216
.owner = THIS_MODULE,
217
.size_type = FIXED_APER_SIZE,
218
.configure = parisc_agp_configure,
219
.fetch_size = parisc_agp_fetch_size,
220
.tlb_flush = parisc_agp_tlbflush,
221
.mask_memory = parisc_agp_mask_memory,
222
.masks = parisc_agp_masks,
223
.agp_enable = parisc_agp_enable,
224
.cache_flush = global_cache_flush,
225
.create_gatt_table = parisc_agp_create_gatt_table,
226
.free_gatt_table = parisc_agp_free_gatt_table,
227
.insert_memory = parisc_agp_insert_memory,
228
.remove_memory = parisc_agp_remove_memory,
229
.alloc_by_type = agp_generic_alloc_by_type,
230
.free_by_type = agp_generic_free_by_type,
231
.agp_alloc_page = agp_generic_alloc_page,
232
.agp_alloc_pages = agp_generic_alloc_pages,
233
.agp_destroy_page = agp_generic_destroy_page,
234
.agp_destroy_pages = agp_generic_destroy_pages,
235
.agp_type_to_mask_type = agp_generic_type_to_mask_type,
236
.cant_use_aperture = true,
237
};
238
239
static int __init
240
agp_ioc_init(void __iomem *ioc_regs)
241
{
242
struct _parisc_agp_info *info = &parisc_agp_info;
243
u64 iova_base, *io_pdir, io_tlb_ps;
244
int io_tlb_shift;
245
246
printk(KERN_INFO DRVPFX "IO PDIR shared with sba_iommu\n");
247
248
info->ioc_regs = ioc_regs;
249
250
io_tlb_ps = readq(info->ioc_regs+IOC_TCNFG);
251
switch (io_tlb_ps) {
252
case 0: io_tlb_shift = 12; break;
253
case 1: io_tlb_shift = 13; break;
254
case 2: io_tlb_shift = 14; break;
255
case 3: io_tlb_shift = 16; break;
256
default:
257
printk(KERN_ERR DRVPFX "Invalid IOTLB page size "
258
"configuration 0x%llx\n", io_tlb_ps);
259
info->gatt = NULL;
260
info->gatt_entries = 0;
261
return -ENODEV;
262
}
263
info->io_page_size = 1 << io_tlb_shift;
264
info->io_pages_per_kpage = PAGE_SIZE / info->io_page_size;
265
266
iova_base = readq(info->ioc_regs+IOC_IBASE) & ~0x1;
267
info->gart_base = iova_base + PLUTO_IOVA_SIZE - PLUTO_GART_SIZE;
268
269
info->gart_size = PLUTO_GART_SIZE;
270
info->gatt_entries = info->gart_size / info->io_page_size;
271
272
io_pdir = phys_to_virt(readq(info->ioc_regs+IOC_PDIR_BASE));
273
info->gatt = &io_pdir[(PLUTO_IOVA_SIZE/2) >> PAGE_SHIFT];
274
275
if (info->gatt[0] != SBA_AGPGART_COOKIE) {
276
info->gatt = NULL;
277
info->gatt_entries = 0;
278
printk(KERN_ERR DRVPFX "No reserved IO PDIR entry found; "
279
"GART disabled\n");
280
return -ENODEV;
281
}
282
283
return 0;
284
}
285
286
static int
287
lba_find_capability(int cap)
288
{
289
struct _parisc_agp_info *info = &parisc_agp_info;
290
u16 status;
291
u8 pos, id;
292
int ttl = 48;
293
294
status = readw(info->lba_regs + PCI_STATUS);
295
if (!(status & PCI_STATUS_CAP_LIST))
296
return 0;
297
pos = readb(info->lba_regs + PCI_CAPABILITY_LIST);
298
while (ttl-- && pos >= 0x40) {
299
pos &= ~3;
300
id = readb(info->lba_regs + pos + PCI_CAP_LIST_ID);
301
if (id == 0xff)
302
break;
303
if (id == cap)
304
return pos;
305
pos = readb(info->lba_regs + pos + PCI_CAP_LIST_NEXT);
306
}
307
return 0;
308
}
309
310
static int __init
311
agp_lba_init(void __iomem *lba_hpa)
312
{
313
struct _parisc_agp_info *info = &parisc_agp_info;
314
int cap;
315
316
info->lba_regs = lba_hpa;
317
info->lba_cap_offset = lba_find_capability(PCI_CAP_ID_AGP);
318
319
cap = readl(lba_hpa + info->lba_cap_offset) & 0xff;
320
if (cap != PCI_CAP_ID_AGP) {
321
printk(KERN_ERR DRVPFX "Invalid capability ID 0x%02x at 0x%x\n",
322
cap, info->lba_cap_offset);
323
return -ENODEV;
324
}
325
326
return 0;
327
}
328
329
static int __init
330
parisc_agp_setup(void __iomem *ioc_hpa, void __iomem *lba_hpa)
331
{
332
struct pci_dev *fake_bridge_dev = NULL;
333
struct agp_bridge_data *bridge;
334
int error = 0;
335
336
fake_bridge_dev = alloc_pci_dev();
337
if (!fake_bridge_dev) {
338
error = -ENOMEM;
339
goto fail;
340
}
341
342
error = agp_ioc_init(ioc_hpa);
343
if (error)
344
goto fail;
345
346
error = agp_lba_init(lba_hpa);
347
if (error)
348
goto fail;
349
350
bridge = agp_alloc_bridge();
351
if (!bridge) {
352
error = -ENOMEM;
353
goto fail;
354
}
355
bridge->driver = &parisc_agp_driver;
356
357
fake_bridge_dev->vendor = PCI_VENDOR_ID_HP;
358
fake_bridge_dev->device = PCI_DEVICE_ID_HP_PCIX_LBA;
359
bridge->dev = fake_bridge_dev;
360
361
error = agp_add_bridge(bridge);
362
if (error)
363
goto fail;
364
return 0;
365
366
fail:
367
kfree(fake_bridge_dev);
368
return error;
369
}
370
371
static int
372
find_quicksilver(struct device *dev, void *data)
373
{
374
struct parisc_device **lba = data;
375
struct parisc_device *padev = to_parisc_device(dev);
376
377
if (IS_QUICKSILVER(padev))
378
*lba = padev;
379
380
return 0;
381
}
382
383
static int
384
parisc_agp_init(void)
385
{
386
extern struct sba_device *sba_list;
387
388
int err = -1;
389
struct parisc_device *sba = NULL, *lba = NULL;
390
struct lba_device *lbadev = NULL;
391
392
if (!sba_list)
393
goto out;
394
395
/* Find our parent Pluto */
396
sba = sba_list->dev;
397
if (!IS_PLUTO(sba)) {
398
printk(KERN_INFO DRVPFX "No Pluto found, so no AGPGART for you.\n");
399
goto out;
400
}
401
402
/* Now search our Pluto for our precious AGP device... */
403
device_for_each_child(&sba->dev, &lba, find_quicksilver);
404
405
if (!lba) {
406
printk(KERN_INFO DRVPFX "No AGP devices found.\n");
407
goto out;
408
}
409
410
lbadev = parisc_get_drvdata(lba);
411
412
/* w00t, let's go find our cookies... */
413
parisc_agp_setup(sba_list->ioc[0].ioc_hpa, lbadev->hba.base_addr);
414
415
return 0;
416
417
out:
418
return err;
419
}
420
421
module_init(parisc_agp_init);
422
423
MODULE_AUTHOR("Kyle McMartin <[email protected]>");
424
MODULE_LICENSE("GPL");
425
426