Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Serverworks AGPGART routines.
0003  */
0004 
0005 #include <linux/module.h>
0006 #include <linux/pci.h>
0007 #include <linux/init.h>
0008 #include <linux/string.h>
0009 #include <linux/slab.h>
0010 #include <linux/jiffies.h>
0011 #include <linux/agp_backend.h>
0012 #include <asm/set_memory.h>
0013 #include "agp.h"
0014 
0015 #define SVWRKS_COMMAND      0x04
0016 #define SVWRKS_APSIZE       0x10
0017 #define SVWRKS_MMBASE       0x14
0018 #define SVWRKS_CACHING      0x4b
0019 #define SVWRKS_AGP_ENABLE   0x60
0020 #define SVWRKS_FEATURE      0x68
0021 
0022 #define SVWRKS_SIZE_MASK    0xfe000000
0023 
0024 /* Memory mapped registers */
0025 #define SVWRKS_GART_CACHE   0x02
0026 #define SVWRKS_GATTBASE     0x04
0027 #define SVWRKS_TLBFLUSH     0x10
0028 #define SVWRKS_POSTFLUSH    0x14
0029 #define SVWRKS_DIRFLUSH     0x0c
0030 
0031 
0032 struct serverworks_page_map {
0033     unsigned long *real;
0034     unsigned long __iomem *remapped;
0035 };
0036 
0037 static struct _serverworks_private {
0038     struct pci_dev *svrwrks_dev;    /* device one */
0039     volatile u8 __iomem *registers;
0040     struct serverworks_page_map **gatt_pages;
0041     int num_tables;
0042     struct serverworks_page_map scratch_dir;
0043 
0044     int gart_addr_ofs;
0045     int mm_addr_ofs;
0046 } serverworks_private;
0047 
0048 static int serverworks_create_page_map(struct serverworks_page_map *page_map)
0049 {
0050     int i;
0051 
0052     page_map->real = (unsigned long *) __get_free_page(GFP_KERNEL);
0053     if (page_map->real == NULL) {
0054         return -ENOMEM;
0055     }
0056 
0057     set_memory_uc((unsigned long)page_map->real, 1);
0058     page_map->remapped = page_map->real;
0059 
0060     for (i = 0; i < PAGE_SIZE / sizeof(unsigned long); i++)
0061         writel(agp_bridge->scratch_page, page_map->remapped+i);
0062         /* Red Pen: Everyone else does pci posting flush here */
0063 
0064     return 0;
0065 }
0066 
0067 static void serverworks_free_page_map(struct serverworks_page_map *page_map)
0068 {
0069     set_memory_wb((unsigned long)page_map->real, 1);
0070     free_page((unsigned long) page_map->real);
0071 }
0072 
0073 static void serverworks_free_gatt_pages(void)
0074 {
0075     int i;
0076     struct serverworks_page_map **tables;
0077     struct serverworks_page_map *entry;
0078 
0079     tables = serverworks_private.gatt_pages;
0080     for (i = 0; i < serverworks_private.num_tables; i++) {
0081         entry = tables[i];
0082         if (entry != NULL) {
0083             if (entry->real != NULL) {
0084                 serverworks_free_page_map(entry);
0085             }
0086             kfree(entry);
0087         }
0088     }
0089     kfree(tables);
0090 }
0091 
0092 static int serverworks_create_gatt_pages(int nr_tables)
0093 {
0094     struct serverworks_page_map **tables;
0095     struct serverworks_page_map *entry;
0096     int retval = 0;
0097     int i;
0098 
0099     tables = kcalloc(nr_tables + 1, sizeof(struct serverworks_page_map *),
0100              GFP_KERNEL);
0101     if (tables == NULL)
0102         return -ENOMEM;
0103 
0104     for (i = 0; i < nr_tables; i++) {
0105         entry = kzalloc(sizeof(struct serverworks_page_map), GFP_KERNEL);
0106         if (entry == NULL) {
0107             retval = -ENOMEM;
0108             break;
0109         }
0110         tables[i] = entry;
0111         retval = serverworks_create_page_map(entry);
0112         if (retval != 0) break;
0113     }
0114     serverworks_private.num_tables = nr_tables;
0115     serverworks_private.gatt_pages = tables;
0116 
0117     if (retval != 0) serverworks_free_gatt_pages();
0118 
0119     return retval;
0120 }
0121 
0122 #define SVRWRKS_GET_GATT(addr) (serverworks_private.gatt_pages[\
0123     GET_PAGE_DIR_IDX(addr)]->remapped)
0124 
0125 #ifndef GET_PAGE_DIR_OFF
0126 #define GET_PAGE_DIR_OFF(addr) (addr >> 22)
0127 #endif
0128 
0129 #ifndef GET_PAGE_DIR_IDX
0130 #define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr) - \
0131     GET_PAGE_DIR_OFF(agp_bridge->gart_bus_addr))
0132 #endif
0133 
0134 #ifndef GET_GATT_OFF
0135 #define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
0136 #endif
0137 
0138 static int serverworks_create_gatt_table(struct agp_bridge_data *bridge)
0139 {
0140     struct aper_size_info_lvl2 *value;
0141     struct serverworks_page_map page_dir;
0142     int retval;
0143     u32 temp;
0144     int i;
0145 
0146     value = A_SIZE_LVL2(agp_bridge->current_size);
0147     retval = serverworks_create_page_map(&page_dir);
0148     if (retval != 0) {
0149         return retval;
0150     }
0151     retval = serverworks_create_page_map(&serverworks_private.scratch_dir);
0152     if (retval != 0) {
0153         serverworks_free_page_map(&page_dir);
0154         return retval;
0155     }
0156     /* Create a fake scratch directory */
0157     for (i = 0; i < 1024; i++) {
0158         writel(agp_bridge->scratch_page, serverworks_private.scratch_dir.remapped+i);
0159         writel(virt_to_phys(serverworks_private.scratch_dir.real) | 1, page_dir.remapped+i);
0160     }
0161 
0162     retval = serverworks_create_gatt_pages(value->num_entries / 1024);
0163     if (retval != 0) {
0164         serverworks_free_page_map(&page_dir);
0165         serverworks_free_page_map(&serverworks_private.scratch_dir);
0166         return retval;
0167     }
0168 
0169     agp_bridge->gatt_table_real = (u32 *)page_dir.real;
0170     agp_bridge->gatt_table = (u32 __iomem *)page_dir.remapped;
0171     agp_bridge->gatt_bus_addr = virt_to_phys(page_dir.real);
0172 
0173     /* Get the address for the gart region.
0174      * This is a bus address even on the alpha, b/c its
0175      * used to program the agp master not the cpu
0176      */
0177 
0178     pci_read_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,&temp);
0179     agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK);
0180 
0181     /* Calculate the agp offset */
0182     for (i = 0; i < value->num_entries / 1024; i++)
0183         writel(virt_to_phys(serverworks_private.gatt_pages[i]->real)|1, page_dir.remapped+i);
0184 
0185     return 0;
0186 }
0187 
0188 static int serverworks_free_gatt_table(struct agp_bridge_data *bridge)
0189 {
0190     struct serverworks_page_map page_dir;
0191 
0192     page_dir.real = (unsigned long *)agp_bridge->gatt_table_real;
0193     page_dir.remapped = (unsigned long __iomem *)agp_bridge->gatt_table;
0194 
0195     serverworks_free_gatt_pages();
0196     serverworks_free_page_map(&page_dir);
0197     serverworks_free_page_map(&serverworks_private.scratch_dir);
0198     return 0;
0199 }
0200 
0201 static int serverworks_fetch_size(void)
0202 {
0203     int i;
0204     u32 temp;
0205     u32 temp2;
0206     struct aper_size_info_lvl2 *values;
0207 
0208     values = A_SIZE_LVL2(agp_bridge->driver->aperture_sizes);
0209     pci_read_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,&temp);
0210     pci_write_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,
0211                     SVWRKS_SIZE_MASK);
0212     pci_read_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,&temp2);
0213     pci_write_config_dword(agp_bridge->dev,serverworks_private.gart_addr_ofs,temp);
0214     temp2 &= SVWRKS_SIZE_MASK;
0215 
0216     for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) {
0217         if (temp2 == values[i].size_value) {
0218             agp_bridge->previous_size =
0219                 agp_bridge->current_size = (void *) (values + i);
0220 
0221             agp_bridge->aperture_size_idx = i;
0222             return values[i].size;
0223         }
0224     }
0225 
0226     return 0;
0227 }
0228 
0229 /*
0230  * This routine could be implemented by taking the addresses
0231  * written to the GATT, and flushing them individually.  However
0232  * currently it just flushes the whole table.  Which is probably
0233  * more efficient, since agp_memory blocks can be a large number of
0234  * entries.
0235  */
0236 static void serverworks_tlbflush(struct agp_memory *temp)
0237 {
0238     unsigned long timeout;
0239 
0240     writeb(1, serverworks_private.registers+SVWRKS_POSTFLUSH);
0241     timeout = jiffies + 3*HZ;
0242     while (readb(serverworks_private.registers+SVWRKS_POSTFLUSH) == 1) {
0243         cpu_relax();
0244         if (time_after(jiffies, timeout)) {
0245             dev_err(&serverworks_private.svrwrks_dev->dev,
0246                 "TLB post flush took more than 3 seconds\n");
0247             break;
0248         }
0249     }
0250 
0251     writel(1, serverworks_private.registers+SVWRKS_DIRFLUSH);
0252     timeout = jiffies + 3*HZ;
0253     while (readl(serverworks_private.registers+SVWRKS_DIRFLUSH) == 1) {
0254         cpu_relax();
0255         if (time_after(jiffies, timeout)) {
0256             dev_err(&serverworks_private.svrwrks_dev->dev,
0257                 "TLB Dir flush took more than 3 seconds\n");
0258             break;
0259         }
0260     }
0261 }
0262 
0263 static int serverworks_configure(void)
0264 {
0265     u32 temp;
0266     u8 enable_reg;
0267     u16 cap_reg;
0268 
0269     /* Get the memory mapped registers */
0270     pci_read_config_dword(agp_bridge->dev, serverworks_private.mm_addr_ofs, &temp);
0271     temp = (temp & PCI_BASE_ADDRESS_MEM_MASK);
0272     serverworks_private.registers = (volatile u8 __iomem *) ioremap(temp, 4096);
0273     if (!serverworks_private.registers) {
0274         dev_err(&agp_bridge->dev->dev, "can't ioremap(%#x)\n", temp);
0275         return -ENOMEM;
0276     }
0277 
0278     writeb(0xA, serverworks_private.registers+SVWRKS_GART_CACHE);
0279     readb(serverworks_private.registers+SVWRKS_GART_CACHE); /* PCI Posting. */
0280 
0281     writel(agp_bridge->gatt_bus_addr, serverworks_private.registers+SVWRKS_GATTBASE);
0282     readl(serverworks_private.registers+SVWRKS_GATTBASE);   /* PCI Posting. */
0283 
0284     cap_reg = readw(serverworks_private.registers+SVWRKS_COMMAND);
0285     cap_reg &= ~0x0007;
0286     cap_reg |= 0x4;
0287     writew(cap_reg, serverworks_private.registers+SVWRKS_COMMAND);
0288     readw(serverworks_private.registers+SVWRKS_COMMAND);
0289 
0290     pci_read_config_byte(serverworks_private.svrwrks_dev,SVWRKS_AGP_ENABLE, &enable_reg);
0291     enable_reg |= 0x1; /* Agp Enable bit */
0292     pci_write_config_byte(serverworks_private.svrwrks_dev,SVWRKS_AGP_ENABLE, enable_reg);
0293     serverworks_tlbflush(NULL);
0294 
0295     agp_bridge->capndx = pci_find_capability(serverworks_private.svrwrks_dev, PCI_CAP_ID_AGP);
0296 
0297     /* Fill in the mode register */
0298     pci_read_config_dword(serverworks_private.svrwrks_dev,
0299                   agp_bridge->capndx+PCI_AGP_STATUS, &agp_bridge->mode);
0300 
0301     pci_read_config_byte(agp_bridge->dev, SVWRKS_CACHING, &enable_reg);
0302     enable_reg &= ~0x3;
0303     pci_write_config_byte(agp_bridge->dev, SVWRKS_CACHING, enable_reg);
0304 
0305     pci_read_config_byte(agp_bridge->dev, SVWRKS_FEATURE, &enable_reg);
0306     enable_reg |= (1<<6);
0307     pci_write_config_byte(agp_bridge->dev,SVWRKS_FEATURE, enable_reg);
0308 
0309     return 0;
0310 }
0311 
0312 static void serverworks_cleanup(void)
0313 {
0314     iounmap((void __iomem *) serverworks_private.registers);
0315 }
0316 
0317 static int serverworks_insert_memory(struct agp_memory *mem,
0318                  off_t pg_start, int type)
0319 {
0320     int i, j, num_entries;
0321     unsigned long __iomem *cur_gatt;
0322     unsigned long addr;
0323 
0324     num_entries = A_SIZE_LVL2(agp_bridge->current_size)->num_entries;
0325 
0326     if (type != 0 || mem->type != 0) {
0327         return -EINVAL;
0328     }
0329     if ((pg_start + mem->page_count) > num_entries) {
0330         return -EINVAL;
0331     }
0332 
0333     j = pg_start;
0334     while (j < (pg_start + mem->page_count)) {
0335         addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
0336         cur_gatt = SVRWRKS_GET_GATT(addr);
0337         if (!PGE_EMPTY(agp_bridge, readl(cur_gatt+GET_GATT_OFF(addr))))
0338             return -EBUSY;
0339         j++;
0340     }
0341 
0342     if (!mem->is_flushed) {
0343         global_cache_flush();
0344         mem->is_flushed = true;
0345     }
0346 
0347     for (i = 0, j = pg_start; i < mem->page_count; i++, j++) {
0348         addr = (j * PAGE_SIZE) + agp_bridge->gart_bus_addr;
0349         cur_gatt = SVRWRKS_GET_GATT(addr);
0350         writel(agp_bridge->driver->mask_memory(agp_bridge,
0351                 page_to_phys(mem->pages[i]), mem->type),
0352                cur_gatt+GET_GATT_OFF(addr));
0353     }
0354     serverworks_tlbflush(mem);
0355     return 0;
0356 }
0357 
0358 static int serverworks_remove_memory(struct agp_memory *mem, off_t pg_start,
0359                  int type)
0360 {
0361     int i;
0362     unsigned long __iomem *cur_gatt;
0363     unsigned long addr;
0364 
0365     if (type != 0 || mem->type != 0) {
0366         return -EINVAL;
0367     }
0368 
0369     global_cache_flush();
0370     serverworks_tlbflush(mem);
0371 
0372     for (i = pg_start; i < (mem->page_count + pg_start); i++) {
0373         addr = (i * PAGE_SIZE) + agp_bridge->gart_bus_addr;
0374         cur_gatt = SVRWRKS_GET_GATT(addr);
0375         writel(agp_bridge->scratch_page, cur_gatt+GET_GATT_OFF(addr));
0376     }
0377 
0378     serverworks_tlbflush(mem);
0379     return 0;
0380 }
0381 
0382 static const struct gatt_mask serverworks_masks[] =
0383 {
0384     {.mask = 1, .type = 0}
0385 };
0386 
0387 static const struct aper_size_info_lvl2 serverworks_sizes[7] =
0388 {
0389     {2048, 524288, 0x80000000},
0390     {1024, 262144, 0xc0000000},
0391     {512, 131072, 0xe0000000},
0392     {256, 65536, 0xf0000000},
0393     {128, 32768, 0xf8000000},
0394     {64, 16384, 0xfc000000},
0395     {32, 8192, 0xfe000000}
0396 };
0397 
0398 static void serverworks_agp_enable(struct agp_bridge_data *bridge, u32 mode)
0399 {
0400     u32 command;
0401 
0402     pci_read_config_dword(serverworks_private.svrwrks_dev,
0403                   bridge->capndx + PCI_AGP_STATUS,
0404                   &command);
0405 
0406     command = agp_collect_device_status(bridge, mode, command);
0407 
0408     command &= ~0x10;   /* disable FW */
0409     command &= ~0x08;
0410 
0411     command |= 0x100;
0412 
0413     pci_write_config_dword(serverworks_private.svrwrks_dev,
0414                    bridge->capndx + PCI_AGP_COMMAND,
0415                    command);
0416 
0417     agp_device_command(command, false);
0418 }
0419 
0420 static const struct agp_bridge_driver sworks_driver = {
0421     .owner          = THIS_MODULE,
0422     .aperture_sizes     = serverworks_sizes,
0423     .size_type      = LVL2_APER_SIZE,
0424     .num_aperture_sizes = 7,
0425     .configure      = serverworks_configure,
0426     .fetch_size     = serverworks_fetch_size,
0427     .cleanup        = serverworks_cleanup,
0428     .tlb_flush      = serverworks_tlbflush,
0429     .mask_memory        = agp_generic_mask_memory,
0430     .masks          = serverworks_masks,
0431     .agp_enable     = serverworks_agp_enable,
0432     .cache_flush        = global_cache_flush,
0433     .create_gatt_table  = serverworks_create_gatt_table,
0434     .free_gatt_table    = serverworks_free_gatt_table,
0435     .insert_memory      = serverworks_insert_memory,
0436     .remove_memory      = serverworks_remove_memory,
0437     .alloc_by_type      = agp_generic_alloc_by_type,
0438     .free_by_type       = agp_generic_free_by_type,
0439     .agp_alloc_page     = agp_generic_alloc_page,
0440     .agp_alloc_pages    = agp_generic_alloc_pages,
0441     .agp_destroy_page   = agp_generic_destroy_page,
0442     .agp_destroy_pages  = agp_generic_destroy_pages,
0443     .agp_type_to_mask_type  = agp_generic_type_to_mask_type,
0444 };
0445 
0446 static int agp_serverworks_probe(struct pci_dev *pdev,
0447                  const struct pci_device_id *ent)
0448 {
0449     struct agp_bridge_data *bridge;
0450     struct pci_dev *bridge_dev;
0451     u32 temp, temp2;
0452     u8 cap_ptr = 0;
0453 
0454     cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP);
0455 
0456     switch (pdev->device) {
0457     case 0x0006:
0458         dev_err(&pdev->dev, "ServerWorks CNB20HE is unsupported due to lack of documentation\n");
0459         return -ENODEV;
0460 
0461     case PCI_DEVICE_ID_SERVERWORKS_HE:
0462     case PCI_DEVICE_ID_SERVERWORKS_LE:
0463     case 0x0007:
0464         break;
0465 
0466     default:
0467         if (cap_ptr)
0468             dev_err(&pdev->dev, "unsupported Serverworks chipset "
0469                 "[%04x/%04x]\n", pdev->vendor, pdev->device);
0470         return -ENODEV;
0471     }
0472 
0473     /* Everything is on func 1 here so we are hardcoding function one */
0474     bridge_dev = pci_get_domain_bus_and_slot(pci_domain_nr(pdev->bus),
0475             (unsigned int)pdev->bus->number,
0476             PCI_DEVFN(0, 1));
0477     if (!bridge_dev) {
0478         dev_info(&pdev->dev, "can't find secondary device\n");
0479         return -ENODEV;
0480     }
0481 
0482     serverworks_private.svrwrks_dev = bridge_dev;
0483     serverworks_private.gart_addr_ofs = 0x10;
0484 
0485     pci_read_config_dword(pdev, SVWRKS_APSIZE, &temp);
0486     if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
0487         pci_read_config_dword(pdev, SVWRKS_APSIZE + 4, &temp2);
0488         if (temp2 != 0) {
0489             dev_info(&pdev->dev, "64 bit aperture address, "
0490                  "but top bits are not zero; disabling AGP\n");
0491             return -ENODEV;
0492         }
0493         serverworks_private.mm_addr_ofs = 0x18;
0494     } else
0495         serverworks_private.mm_addr_ofs = 0x14;
0496 
0497     pci_read_config_dword(pdev, serverworks_private.mm_addr_ofs, &temp);
0498     if (temp & PCI_BASE_ADDRESS_MEM_TYPE_64) {
0499         pci_read_config_dword(pdev,
0500                 serverworks_private.mm_addr_ofs + 4, &temp2);
0501         if (temp2 != 0) {
0502             dev_info(&pdev->dev, "64 bit MMIO address, but top "
0503                  "bits are not zero; disabling AGP\n");
0504             return -ENODEV;
0505         }
0506     }
0507 
0508     bridge = agp_alloc_bridge();
0509     if (!bridge)
0510         return -ENOMEM;
0511 
0512     bridge->driver = &sworks_driver;
0513     bridge->dev_private_data = &serverworks_private;
0514     bridge->dev = pci_dev_get(pdev);
0515 
0516     pci_set_drvdata(pdev, bridge);
0517     return agp_add_bridge(bridge);
0518 }
0519 
0520 static void agp_serverworks_remove(struct pci_dev *pdev)
0521 {
0522     struct agp_bridge_data *bridge = pci_get_drvdata(pdev);
0523 
0524     pci_dev_put(bridge->dev);
0525     agp_remove_bridge(bridge);
0526     agp_put_bridge(bridge);
0527     pci_dev_put(serverworks_private.svrwrks_dev);
0528     serverworks_private.svrwrks_dev = NULL;
0529 }
0530 
0531 static struct pci_device_id agp_serverworks_pci_table[] = {
0532     {
0533     .class      = (PCI_CLASS_BRIDGE_HOST << 8),
0534     .class_mask = ~0,
0535     .vendor     = PCI_VENDOR_ID_SERVERWORKS,
0536     .device     = PCI_ANY_ID,
0537     .subvendor  = PCI_ANY_ID,
0538     .subdevice  = PCI_ANY_ID,
0539     },
0540     { }
0541 };
0542 
0543 MODULE_DEVICE_TABLE(pci, agp_serverworks_pci_table);
0544 
0545 static struct pci_driver agp_serverworks_pci_driver = {
0546     .name       = "agpgart-serverworks",
0547     .id_table   = agp_serverworks_pci_table,
0548     .probe      = agp_serverworks_probe,
0549     .remove     = agp_serverworks_remove,
0550 };
0551 
0552 static int __init agp_serverworks_init(void)
0553 {
0554     if (agp_off)
0555         return -EINVAL;
0556     return pci_register_driver(&agp_serverworks_pci_driver);
0557 }
0558 
0559 static void __exit agp_serverworks_cleanup(void)
0560 {
0561     pci_unregister_driver(&agp_serverworks_pci_driver);
0562 }
0563 
0564 module_init(agp_serverworks_init);
0565 module_exit(agp_serverworks_cleanup);
0566 
0567 MODULE_LICENSE("GPL and additional rights");
0568