5 #include <linux/module.h>
8 #include <linux/string.h>
9 #include <linux/slab.h>
14 #define SVWRKS_COMMAND 0x04
15 #define SVWRKS_APSIZE 0x10
16 #define SVWRKS_MMBASE 0x14
17 #define SVWRKS_CACHING 0x4b
18 #define SVWRKS_AGP_ENABLE 0x60
19 #define SVWRKS_FEATURE 0x68
21 #define SVWRKS_SIZE_MASK 0xfe000000
24 #define SVWRKS_GART_CACHE 0x02
25 #define SVWRKS_GATTBASE 0x04
26 #define SVWRKS_TLBFLUSH 0x10
27 #define SVWRKS_POSTFLUSH 0x14
28 #define SVWRKS_DIRFLUSH 0x0c
36 static struct _serverworks_private {
45 } serverworks_private;
72 static void serverworks_free_gatt_pages(
void)
78 tables = serverworks_private.gatt_pages;
79 for (i = 0; i < serverworks_private.num_tables; i++) {
83 serverworks_free_page_map(entry);
91 static int serverworks_create_gatt_pages(
int nr_tables)
103 for (i = 0; i < nr_tables; i++) {
110 retval = serverworks_create_page_map(entry);
111 if (retval != 0)
break;
113 serverworks_private.num_tables = nr_tables;
114 serverworks_private.gatt_pages =
tables;
116 if (retval != 0) serverworks_free_gatt_pages();
121 #define SVRWRKS_GET_GATT(addr) (serverworks_private.gatt_pages[\
122 GET_PAGE_DIR_IDX(addr)]->remapped)
124 #ifndef GET_PAGE_DIR_OFF
125 #define GET_PAGE_DIR_OFF(addr) (addr >> 22)
128 #ifndef GET_PAGE_DIR_IDX
129 #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
130 GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr))
134 #define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
137 static int serverworks_create_gatt_table(
struct agp_bridge_data *bridge)
146 retval = serverworks_create_page_map(&page_dir);
150 retval = serverworks_create_page_map(&serverworks_private.scratch_dir);
152 serverworks_free_page_map(&page_dir);
156 for (i = 0; i < 1024; i++) {
157 writel(
agp_bridge->scratch_page, serverworks_private.scratch_dir.remapped+i);
161 retval = serverworks_create_gatt_pages(value->
num_entries / 1024);
163 serverworks_free_page_map(&page_dir);
164 serverworks_free_page_map(&serverworks_private.scratch_dir);
177 pci_read_config_dword(
agp_bridge->dev,serverworks_private.gart_addr_ofs,&temp);
194 serverworks_free_gatt_pages();
195 serverworks_free_page_map(&page_dir);
196 serverworks_free_page_map(&serverworks_private.scratch_dir);
200 static int serverworks_fetch_size(
void)
208 pci_read_config_dword(
agp_bridge->dev,serverworks_private.gart_addr_ofs,&temp);
209 pci_write_config_dword(
agp_bridge->dev,serverworks_private.gart_addr_ofs,
211 pci_read_config_dword(
agp_bridge->dev,serverworks_private.gart_addr_ofs,&temp2);
212 pci_write_config_dword(
agp_bridge->dev,serverworks_private.gart_addr_ofs,temp);
215 for (i = 0; i <
agp_bridge->driver->num_aperture_sizes; i++) {
218 agp_bridge->current_size = (
void *) (values + i);
221 return values[
i].
size;
235 static void serverworks_tlbflush(
struct agp_memory *temp)
244 dev_err(&serverworks_private.svrwrks_dev->dev,
245 "TLB post flush took more than 3 seconds\n");
255 dev_err(&serverworks_private.svrwrks_dev->dev,
256 "TLB Dir flush took more than 3 seconds\n");
262 static int serverworks_configure(
void)
272 pci_read_config_dword(
agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp);
274 serverworks_private.registers = (
volatile u8 __iomem *)
ioremap(temp, 4096);
275 if (!serverworks_private.registers) {
292 pci_read_config_byte(serverworks_private.svrwrks_dev,
SVWRKS_AGP_ENABLE, &enable_reg);
294 pci_write_config_byte(serverworks_private.svrwrks_dev,
SVWRKS_AGP_ENABLE, enable_reg);
295 serverworks_tlbflush(
NULL);
300 pci_read_config_dword(serverworks_private.svrwrks_dev,
308 enable_reg |= (1<<6);
314 static void serverworks_cleanup(
void)
323 unsigned long __iomem *cur_gatt;
328 if (type != 0 || mem->
type != 0) {
331 if ((pg_start + mem->
page_count) > num_entries) {
349 for (i = 0, j = pg_start; i < mem->
page_count; i++, j++) {
356 serverworks_tlbflush(mem);
360 static int serverworks_remove_memory(
struct agp_memory *mem,
off_t pg_start,
364 unsigned long __iomem *cur_gatt;
367 if (type != 0 || mem->
type != 0) {
372 serverworks_tlbflush(mem);
374 for (i = pg_start; i < (mem->
page_count + pg_start); i++) {
380 serverworks_tlbflush(mem);
384 static const struct gatt_mask serverworks_masks[] =
386 {.mask = 1, .type = 0}
391 {2048, 524288, 0x80000000},
392 {1024, 262144, 0xc0000000},
393 {512, 131072, 0xe0000000},
394 {256, 65536, 0xf0000000},
395 {128, 32768, 0xf8000000},
396 {64, 16384, 0xfc000000},
397 {32, 8192, 0xfe000000}
404 pci_read_config_dword(serverworks_private.svrwrks_dev,
415 pci_write_config_dword(serverworks_private.svrwrks_dev,
424 .aperture_sizes = serverworks_sizes,
426 .num_aperture_sizes = 7,
427 .configure = serverworks_configure,
428 .fetch_size = serverworks_fetch_size,
429 .cleanup = serverworks_cleanup,
430 .tlb_flush = serverworks_tlbflush,
432 .masks = serverworks_masks,
433 .agp_enable = serverworks_agp_enable,
435 .create_gatt_table = serverworks_create_gatt_table,
436 .free_gatt_table = serverworks_free_gatt_table,
437 .insert_memory = serverworks_insert_memory,
438 .remove_memory = serverworks_remove_memory,
460 dev_err(&pdev->
dev,
"ServerWorks CNB20HE is unsupported due to lack of documentation\n");
470 dev_err(&pdev->
dev,
"unsupported Serverworks chipset "
479 dev_info(&pdev->
dev,
"can't find secondary device\n");
483 serverworks_private.svrwrks_dev = bridge_dev;
484 serverworks_private.gart_addr_ofs = 0x10;
491 "but top bits are not zero; disabling AGP\n");
494 serverworks_private.mm_addr_ofs = 0x18;
496 serverworks_private.mm_addr_ofs = 0x14;
498 pci_read_config_dword(pdev, serverworks_private.mm_addr_ofs, &temp);
499 if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
500 pci_read_config_dword(pdev,
501 serverworks_private.mm_addr_ofs + 4, &temp2);
503 dev_info(&pdev->
dev,
"64 bit MMIO address, but top "
504 "bits are not zero; disabling AGP\n");
513 bridge->
driver = &sworks_driver;
517 pci_set_drvdata(pdev, bridge);
529 serverworks_private.svrwrks_dev =
NULL;
546 static struct pci_driver agp_serverworks_pci_driver = {
547 .name =
"agpgart-serverworks",
548 .id_table = agp_serverworks_pci_table,
549 .probe = agp_serverworks_probe,
550 .remove = agp_serverworks_remove,
553 static int __init agp_serverworks_init(
void)
557 return pci_register_driver(&agp_serverworks_pci_driver);
560 static void __exit agp_serverworks_cleanup(
void)