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
6 * Copyright (C) 2003-2005 Silicon Graphics, Inc. All Rights Reserved.
10 * SGI TIOCA AGPGART routines.
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>
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
;
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.
38 static struct aper_size_info_fixed sgi_tioca_sizes
[] = {
42 static struct page
*sgi_tioca_alloc_page(struct agp_bridge_data
*bridge
)
46 struct tioca_kernel
*info
=
47 (struct tioca_kernel
*)bridge
->dev_private_data
;
49 nid
= info
->ca_closest_node
;
50 page
= alloc_pages_node(nid
, GFP_KERNEL
, 0);
55 atomic_inc(&agp_bridge
->current_memory_agp
);
60 * Flush GART tlb's. Cannot selectively flush based on memory so the mem
64 static void sgi_tioca_tlbflush(struct agp_memory
*mem
)
66 tioca_tlbflush(mem
->bridge
->dev_private_data
);
70 * Given an address of a host physical page, turn it into a valid gart
74 sgi_tioca_mask_memory(struct agp_bridge_data
*bridge
, dma_addr_t addr
,
77 return tioca_physpage_to_gart(addr
);
80 static void sgi_tioca_agp_enable(struct agp_bridge_data
*bridge
, u32 mode
)
82 tioca_fastwrite_enable(bridge
->dev_private_data
);
86 * sgi_tioca_configure() doesn't have anything to do since the base CA driver
87 * has alreay set up the GART.
90 static int sgi_tioca_configure(void)
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.
100 static int sgi_tioca_fetch_size(void)
102 struct tioca_kernel
*info
=
103 (struct tioca_kernel
*)agp_bridge
->dev_private_data
;
105 sgi_tioca_sizes
[0].size
= info
->ca_gfxap_size
/ MB(1);
106 sgi_tioca_sizes
[0].num_entries
= info
->ca_gfxgart_entries
;
108 return sgi_tioca_sizes
[0].size
;
111 static int sgi_tioca_create_gatt_table(struct agp_bridge_data
*bridge
)
113 struct tioca_kernel
*info
=
114 (struct tioca_kernel
*)bridge
->dev_private_data
;
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
;
123 static int sgi_tioca_free_gatt_table(struct agp_bridge_data
*bridge
)
128 static int sgi_tioca_insert_memory(struct agp_memory
*mem
, off_t pg_start
,
135 struct agp_bridge_data
*bridge
;
138 bridge
= mem
->bridge
;
142 table
= (u64
*)bridge
->gatt_table
;
144 temp
= bridge
->current_size
;
146 switch (bridge
->driver
->size_type
) {
148 num_entries
= A_SIZE_8(temp
)->num_entries
;
151 num_entries
= A_SIZE_16(temp
)->num_entries
;
154 num_entries
= A_SIZE_32(temp
)->num_entries
;
156 case FIXED_APER_SIZE
:
157 num_entries
= A_SIZE_FIX(temp
)->num_entries
;
167 num_entries
-= agp_memory_reserved
/ PAGE_SIZE
;
171 if (type
!= 0 || mem
->type
!= 0) {
175 if ((pg_start
+ mem
->page_count
) > num_entries
)
180 while (j
< (pg_start
+ mem
->page_count
)) {
186 if (!mem
->is_flushed
) {
187 bridge
->driver
->cache_flush();
188 mem
->is_flushed
= true;
191 for (i
= 0, j
= pg_start
; i
< mem
->page_count
; i
++, j
++) {
193 bridge
->driver
->mask_memory(bridge
,
194 page_to_phys(mem
->pages
[i
]),
198 bridge
->driver
->tlb_flush(mem
);
202 static int sgi_tioca_remove_memory(struct agp_memory
*mem
, off_t pg_start
,
206 struct agp_bridge_data
*bridge
;
209 bridge
= mem
->bridge
;
213 if (type
!= 0 || mem
->type
!= 0) {
217 table
= (u64
*)bridge
->gatt_table
;
219 for (i
= pg_start
; i
< (mem
->page_count
+ pg_start
); i
++) {
223 bridge
->driver
->tlb_flush(mem
);
227 static void sgi_tioca_cache_flush(void)
232 * Cleanup. Nothing to do as the CA driver owns the GART.
235 static void sgi_tioca_cleanup(void)
239 static struct agp_bridge_data
*sgi_tioca_find_bridge(struct pci_dev
*pdev
)
241 struct agp_bridge_data
*bridge
;
243 list_for_each_entry(bridge
, &agp_bridges
, list
) {
244 if (bridge
->dev
->bus
== pdev
->bus
)
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,
274 static int __devinit
agp_sgi_init(void)
277 struct tioca_kernel
*info
;
278 struct pci_dev
*pdev
= NULL
;
280 if (tioca_gart_found
)
281 printk(KERN_INFO PFX
"SGI TIO CA GART driver initialized.\n");
285 sgi_tioca_agp_bridges
= kmalloc(tioca_gart_found
*
286 sizeof(struct agp_bridge_data
*),
288 if (!sgi_tioca_agp_bridges
)
292 list_for_each_entry(info
, &tioca_list
, ca_list
) {
293 struct list_head
*tmp
;
294 if (list_empty(info
->ca_devices
))
296 list_for_each(tmp
, info
->ca_devices
) {
298 pdev
= pci_dev_b(tmp
);
299 if (pdev
->class != (PCI_CLASS_DISPLAY_VGA
<< 8))
301 cap_ptr
= pci_find_capability(pdev
, PCI_CAP_ID_AGP
);
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
=
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
]);
328 agp_find_bridge
= &sgi_tioca_find_bridge
;
332 static void __devexit
agp_sgi_cleanup(void)
334 kfree(sgi_tioca_agp_bridges
);
335 sgi_tioca_agp_bridges
= NULL
;
338 module_init(agp_sgi_init
);
339 module_exit(agp_sgi_cleanup
);
341 MODULE_LICENSE("GPL and additional rights");