Hi, A long time ago I was working on an AGPGART driver for my PPC machine, but couldn't get it working due to missing datasheet, etc. Now I started working on it again, as Radeon KMS works well on my machine so far and I also rediscovered an old binary-only AGPGART driver for which objdump revealed some interesting information.
Well, the current driver code is basically a copy of the UniNorth AGPGART driver. The driver initializes fine, as the excerpt below shows: calling agp_init+0x0/0x54 @ 1 Linux agpgart interface v0.103 initcall agp_init+0x0/0x54 returned 0 after 2749 usecs calling agp_articias_init+0x0/0x58 @ 1 agpgart-articias 0000:00:00.0: MAI Logic Articia S chipset agpgart-articias 0000:00:00.0: configuring for size idx: 1 agpgart-articias 0000:00:00.0: AGP aperture is 4M @ 0xc0000000 initcall agp_articias_init+0x0/0x58 returned 0 after 19494 usecs calling drm_core_init+0x0/0x158 @ 1 [drm] Initialized drm 1.1.0 20060810 initcall drm_core_init+0x0/0x158 returned 0 after 4526 usecs calling ttm_init+0x0/0x8c @ 1 initcall ttm_init+0x0/0x8c returned 0 after 1170 usecs calling radeon_init+0x0/0x100 @ 1 [drm] radeon defaulting to kernel modesetting. [drm] radeon kernel modesetting enabled. [drm] radeon: Initializing kernel modesetting. [drm] register mmio base: 0x88000000 [drm] register mmio size: 65536 [drm] GPU reset succeed (RBBM_STATUS=0x00000140) [drm] Generation 2 PCI interface, using max accessible memory [drm] AGP mode requested: 1 agpgart-articias 0000:00:00.0: AGP 1.0 bridge agpgart-articias 0000:00:00.0: putting AGP V2 device into 1x mode radeon 0000:01:00.0: putting AGP V2 device into 1x mode [drm] radeon: VRAM 128M [drm] radeon: VRAM from 0x00000000 to 0x07FFFFFF [drm] radeon: GTT 4M [drm] radeon: GTT from 0xC0000000 to 0xC03FFFFF [drm] radeon: irq initialized. [drm] Detected VRAM RAM=128M, BAR=128M [drm] RAM width 128bits DDR [TTM] Zone kernel: Available graphics memory: 377416 kiB. [TTM] Zone highmem: Available graphics memory: 770632 kiB. [drm] radeon: 128M of VRAM memory ready [drm] radeon: 4M of GTT memory ready. [drm] radeon: cp idle (0x02000603) [drm] Loading R200 Microcode platform radeon_cp.0: firmware: using built-in firmware radeon/R200_cp.bin agpgart-articias 0000:00:00.0: TLB flush! [drm] radeon: ring at 0x00000000C0000000 [drm] ring test succeeded in 0 usecs agpgart-articias 0000:00:00.0: TLB flush! agpgart-articias 0000:00:00.0: TLB flush! [drm] radeon: ib pool ready. [drm] ib test succeeded in 0 usecs [drm] DFP table revision: 3 [drm] Radeon Display Connectors [drm] Connector 0: [drm] VGA [drm] DDC: 0x60 0x60 0x60 0x60 0x60 0x60 0x60 0x60 [drm] Encoders: [drm] CRT1: INTERNAL_DAC1 [drm] Connector 1: [drm] DVI-I [drm] DDC: 0x64 0x64 0x64 0x64 0x64 0x64 0x64 0x64 [drm] Encoders: [drm] CRT2: INTERNAL_DAC2 [drm] DFP1: INTERNAL_TMDS1 [drm] fb mappable at 0x80040000 [drm] vram apper at 0x80000000 [drm] size 7680000 [drm] fb depth is 24 [drm] pitch is 6400 [drm] TMDS-12: set mode 1600x1200 24 Console: switching to colour frame buffer device 200x75 fb0: radeondrmfb frame buffer device registered panic notifier [drm] Initialized radeon 2.0.0 20080528 for 0000:01:00.0 on minor 0 initcall radeon_init+0x0/0x100 returned 0 after 635215 usecs Judging from what the log says, I would expect that the radeon driver can make use of the AGP aperture (as the the ring and ib test succeed - is this assumption correct?). Next I booted the kernel with radeon.test=1 and this test fails immediately with a message like this: [drm:radeon_test_moves] *ERROR* Incorrect GTT->VRAM copy 0: Got 0xf14a88f0, expected 0xf14a6680 (GTT map 0xf14a6000-0xf15a6000) A different aperture size doesn't make any difference. However the test works in PCIGART mode. Now I wonder what the problem could be, as I don't have a clue about the radeon/DRM code. Can somebody explain me, how the test works and what the error message means for the AGPGART driver? Thanks! best regards, Gerhard PS: Please put me on CC:. articias-agp.c: /* * Articia S AGPGART routines. */ #include <linux/module.h> #include <linux/pci.h> #include <linux/init.h> #include <linux/pagemap.h> #include <linux/vmalloc.h> #include <linux/agp_backend.h> #include "agp.h" #define ARTICIAS_GARTCTRL 0x58 /* bit 6 -> GART enable */ #define ARTICIAS_APSIZE 0x59 /* bit 2:0 -> aperture size */ #define ARTICIAS_TLBCTRL 0xe0 /* bit 5 -> TLB flush */ #define ARTICIAS_GATTBASE 0x58 /* 31:12 GATT base address */ static int articias_fetch_size(void) { int i; u8 temp; struct aper_size_info_8 *values; values = A_SIZE_8(agp_bridge->driver->aperture_sizes); pci_read_config_byte(agp_bridge->dev, ARTICIAS_APSIZE, &temp); temp &= 0x07; for (i = 0; i < agp_bridge->driver->num_aperture_sizes; i++) { if (temp == values[i].size_value) { agp_bridge->previous_size = agp_bridge->current_size = (void *) (values + i); agp_bridge->aperture_size_idx = i; return values[i].size; } } dev_err(&agp_bridge->dev->dev, "unknown aperture size from AGP bridge (0x%x)\n", temp); return 0; } static void articias_tlbflush(struct agp_memory *mem) { /* Reverse engineered from binary-only driver. */ /* Does this really work? Register seems to be read-only? */ pci_write_config_byte(agp_bridge->dev, ARTICIAS_TLBCTRL, 0x20); pci_write_config_byte(agp_bridge->dev, ARTICIAS_TLBCTRL, 0); dev_info(&agp_bridge->dev->dev, "TLB flush!\n"); } static void articias_cleanup(void) { u8 temp; struct aper_size_info_8 *previous_size; /* Disable GART transfer control. */ pci_read_config_byte(agp_bridge->dev, ARTICIAS_GARTCTRL, &temp); pci_write_config_byte(agp_bridge->dev, ARTICIAS_GARTCTRL, temp & ~0x40); /* Write back previous aperture size. */ previous_size = A_SIZE_8(agp_bridge->previous_size); pci_write_config_byte(agp_bridge->dev, ARTICIAS_APSIZE, previous_size->size_value); } static int articias_configure(void) { u32 temp; struct aper_size_info_8 *current_size; current_size = A_SIZE_8(agp_bridge->current_size); dev_info(&agp_bridge->dev->dev, "configuring for size idx: %d\n", current_size->size_value); /* Setup aperture size and GATT base address. */ pci_read_config_dword(agp_bridge->dev, ARTICIAS_GATTBASE, &temp); temp = (temp & 0x000000ff) | ((u32)current_size->size_value)<<8 | (agp_bridge->gatt_bus_addr & 0xfffff000); pci_write_config_dword(agp_bridge->dev, ARTICIAS_GATTBASE, temp); /* Aperture address to map too. */ pci_read_config_dword(agp_bridge->dev, AGP_APBASE, &temp); agp_bridge->gart_bus_addr = (temp & PCI_BASE_ADDRESS_MEM_MASK); /* Enable GART transfer control. */ pci_read_config_dword(agp_bridge->dev, ARTICIAS_GARTCTRL, &temp); pci_write_config_dword(agp_bridge->dev, ARTICIAS_GARTCTRL, temp | 0x40); return 0; } static void articias_agp_enable(struct agp_bridge_data *bridge, u32 requested_mode) { u32 bridge_agpstat; dev_info(&agp_bridge->dev->dev, "AGP %d.%d bridge\n", agp_bridge->major_version, agp_bridge->minor_version); pci_read_config_dword(agp_bridge->dev, agp_bridge->capndx + PCI_AGP_STATUS, &bridge_agpstat); /* AGP 4X status bit is lying. */ bridge_agpstat &= ~AGPSTAT2_4X; bridge_agpstat = agp_collect_device_status(agp_bridge, requested_mode, bridge_agpstat); bridge_agpstat |= AGPSTAT_AGP_ENABLE; agp_device_command(bridge_agpstat, false); } static int articias_insert_memory(struct agp_memory *mem, off_t pg_start, int type) { int i, num_entries, mask_type; void *temp; u32 *gp; if (type != mem->type) return -EINVAL; mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); if (mask_type != 0) { /* We know nothing of memory types */ return -EINVAL; } if (mem->page_count == 0) return 0; temp = agp_bridge->current_size; num_entries = A_SIZE_8(temp)->num_entries; if ((pg_start + mem->page_count) > num_entries) return -EINVAL; gp = (u32 *)&agp_bridge->gatt_table[pg_start]; for (i = 0; i < mem->page_count; ++i) { if (gp[i]) { dev_info(&agp_bridge->dev->dev, "articias_insert_memory: entry 0x%x occupied (%x)\n", i, gp[i]); return -EBUSY; } } for (i = 0; i < mem->page_count; i++) { gp[i] = cpu_to_le32(page_to_phys(mem->pages[i]) & 0xfffff000UL); flush_dcache_range((unsigned long)__va(page_to_phys(mem->pages[i])), (unsigned long)__va(page_to_phys(mem->pages[i]))+0x1000); } mb(); articias_tlbflush(mem); return 0; } int articias_remove_memory(struct agp_memory *mem, off_t pg_start, int type) { size_t i; u32 *gp; int mask_type; if (type != mem->type) return -EINVAL; mask_type = agp_bridge->driver->agp_type_to_mask_type(agp_bridge, type); if (mask_type != 0) { /* We know nothing of memory types */ return -EINVAL; } if (mem->page_count == 0) return 0; gp = (u32 *)&agp_bridge->gatt_table[pg_start]; for (i = 0; i < mem->page_count; ++i) gp[i] = 0; mb(); articias_tlbflush(mem); return 0; } static int articias_create_gatt_table(struct agp_bridge_data *bridge) { char *table; char *table_end; int size; int page_order; int num_entries; int i; void *temp; struct page *page; struct page **pages; /* We can't handle 2 level gatt's */ if (bridge->driver->size_type == LVL2_APER_SIZE) return -EINVAL; table = NULL; i = bridge->aperture_size_idx; temp = bridge->current_size; size = page_order = num_entries = 0; do { size = A_SIZE_8(temp)->size; page_order = A_SIZE_8(temp)->page_order; num_entries = A_SIZE_8(temp)->num_entries; table = (char *) __get_free_pages(GFP_KERNEL, page_order); if (table == NULL) { i++; bridge->current_size = A_IDX8(bridge); } else { bridge->aperture_size_idx = i; } } while (!table && (i < bridge->driver->num_aperture_sizes)); if (table == NULL) return -ENOMEM; pages = kmalloc((1 << page_order) * sizeof(struct page*), GFP_KERNEL); if (pages == NULL) goto enomem; table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); for (page = virt_to_page(table), i = 0; page <= virt_to_page(table_end); page++, i++) { SetPageReserved(page); pages[i] = page; } bridge->gatt_table_real = (u32 *)table; /* Need to clear out any dirty data still sitting in caches. */ flush_dcache_range((unsigned long)table, (unsigned long)(table_end + PAGE_SIZE)); bridge->gatt_table = vmap(pages, (1 << page_order), 0, PAGE_KERNEL_NCG); if (bridge->gatt_table == NULL) goto enomem; bridge->gatt_bus_addr = virt_to_phys(table); for (i = 0; i < num_entries; i++) bridge->gatt_table[i] = 0; return 0; enomem: kfree(pages); if (table) free_pages((unsigned long)table, page_order); return -ENOMEM; } static int articias_free_gatt_table(struct agp_bridge_data *bridge) { int page_order; char *table, *table_end; void *temp; struct page *page; temp = bridge->current_size; page_order = A_SIZE_8(temp)->page_order; /* * Do not worry about freeing memory, because if this is called, * then all agp memory is deallocated and removed from the table. */ vunmap(bridge->gatt_table); table = (char *)bridge->gatt_table_real; table_end = table + ((PAGE_SIZE * (1 << page_order)) - 1); for (page = virt_to_page(table); page <= virt_to_page(table_end); page++) ClearPageReserved(page); free_pages((unsigned long)bridge->gatt_table_real, page_order); return 0; } void articias_null_cache_flush(void) { mb(); } static const struct aper_size_info_8 articias_sizes[] = { /* size, num_entries, page_order, size_value */ {256, 65536, 6, 7}, {128, 32768, 5, 6}, {64, 16384, 4, 5}, {32, 8192, 3, 4}, {16, 4096, 2, 3}, {8, 2048, 1, 2}, {4, 1024, 1, 1} }; const struct agp_bridge_driver articias_agp_driver = { .owner = THIS_MODULE, .aperture_sizes = (void *)articias_sizes, .size_type = U8_APER_SIZE, .num_aperture_sizes = ARRAY_SIZE(articias_sizes), .configure = articias_configure, .fetch_size = articias_fetch_size, .cleanup = articias_cleanup, .tlb_flush = articias_tlbflush, .mask_memory = agp_generic_mask_memory, .masks = NULL, .cache_flush = articias_null_cache_flush, .agp_enable = articias_agp_enable, /* .agp_enable = agp_generic_enable, */ .create_gatt_table = articias_create_gatt_table, .free_gatt_table = articias_free_gatt_table, .insert_memory = articias_insert_memory, .remove_memory = articias_remove_memory, .alloc_by_type = agp_generic_alloc_by_type, .free_by_type = agp_generic_free_by_type, .agp_alloc_page = agp_generic_alloc_page, .agp_alloc_pages = agp_generic_alloc_pages, .agp_destroy_page = agp_generic_destroy_page, .agp_destroy_pages = agp_generic_destroy_pages, .agp_type_to_mask_type = agp_generic_type_to_mask_type, .cant_use_aperture = true, }; static struct agp_device_ids articias_agp_device_ids[] __devinitdata = { { .device_id = PCI_DEVICE_ID_MAI_ARTICIAS, .chipset_name = "Articia S", }, { } }; static int __devinit agp_articias_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct agp_device_ids *devs = articias_agp_device_ids; struct agp_bridge_data *bridge; u8 cap_ptr; int j; cap_ptr = pci_find_capability(pdev, PCI_CAP_ID_AGP); if (cap_ptr == 0) return -ENODEV; /* Probe for known chipsets. */ for (j = 0; devs[j].chipset_name != NULL; ++j) { if (pdev->device == devs[j].device_id) { dev_info(&pdev->dev, "MAI Logic %s chipset\n", devs[j].chipset_name); goto found; } } dev_err(&pdev->dev, "unsupported MAI Logic chipset [%04x/%04x]\n", pdev->vendor, pdev->device); return -ENODEV; found: bridge = agp_alloc_bridge(); if (!bridge) return -ENOMEM; bridge->dev = pdev; bridge->capndx = cap_ptr; bridge->driver = &articias_agp_driver; /* AGP 2X isn't reliable and the AGP 4X status bit is wrong. */ // bridge->flags = AGP_ERRATA_1X; /* Get bridge revision. */ get_agp_version(bridge); /* Fill in the mode register. */ pci_read_config_dword(pdev, bridge->capndx + PCI_AGP_STATUS, &bridge->mode); pci_set_drvdata(pdev, bridge); return agp_add_bridge(bridge); } static void __devexit agp_articias_remove(struct pci_dev *pdev) { struct agp_bridge_data *bridge = pci_get_drvdata(pdev); agp_remove_bridge(bridge); agp_put_bridge(bridge); } static struct pci_device_id agp_articias_pci_table[] = { { .class = (PCI_CLASS_BRIDGE_HOST << 8), .class_mask = ~0, .vendor = PCI_VENDOR_ID_MAI, .device = PCI_DEVICE_ID_MAI_ARTICIAS, .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, { } }; MODULE_DEVICE_TABLE(pci, agp_articias_pci_table); static struct pci_driver agp_articias_pci_driver = { .name = "agpgart-articias", .id_table = agp_articias_pci_table, .probe = agp_articias_probe, .remove = agp_articias_remove, }; static int __init agp_articias_init(void) { if (agp_off) return -EINVAL; return pci_register_driver(&agp_articias_pci_driver); } static void __exit agp_articias_cleanup(void) { pci_unregister_driver(&agp_articias_pci_driver); } module_init(agp_articias_init); module_exit(agp_articias_cleanup); MODULE_AUTHOR("Gerhard Pircher <gerhard_pirc...@gmx.net"); MODULE_LICENSE("GPL"); -- Jetzt kostenlos herunterladen: Internet Explorer 8 und Mozilla Firefox 3.5 - sicherer, schneller und einfacher! http://portal.gmx.net/de/go/atbrowser ------------------------------------------------------------------------------ Return on Information: Google Enterprise Search pays you back Get the facts. http://p.sf.net/sfu/google-dev2dev -- _______________________________________________ Dri-devel mailing list Dri-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/dri-devel