patch-2.4.10 linux/arch/alpha/kernel/core_irongate.c
Next file: linux/arch/alpha/kernel/irq.c
Previous file: linux/arch/alpha/kernel/core_cia.c
Back to the patch index
Back to the overall index
- Lines: 227
- Date:
Thu Sep 13 15:21:32 2001
- Orig file:
v2.4.9/linux/arch/alpha/kernel/core_irongate.c
- Orig date:
Fri Mar 2 11:12:07 2001
diff -u --recursive --new-file v2.4.9/linux/arch/alpha/kernel/core_irongate.c linux/arch/alpha/kernel/core_irongate.c
@@ -30,6 +30,8 @@
#undef DEBUG_IRONGATE /* define to enable verbose Irongate debug */
+#define IRONGATE_DEFAULT_AGP_APER_SIZE (256*1024*1024) /* 256MB */
+
/*
* BIOS32-style PCI interface:
*/
@@ -374,6 +376,14 @@
irongate_register_dump(__FUNCTION__);
/*
+ * HACK: set AGP aperture size to 256MB.
+ * This should really be changed during PCI probe, when the
+ * size of the aperture the AGP card wants is known.
+ */
+ printk("irongate_init_arch: AGPVA was 0x%x\n", IRONGATE0->agpva);
+ IRONGATE0->agpva = (IRONGATE0->agpva & ~0x0000000f) | 0x00000007;
+
+ /*
* Create our single hose.
*/
@@ -396,4 +406,202 @@
hose->sg_isa = hose->sg_pci = NULL;
__direct_map_base = 0;
__direct_map_size = 0xffffffff;
+}
+
+/*
+ * IO map and AGP support
+ */
+#include <linux/vmalloc.h>
+#include <asm/pgalloc.h>
+
+static inline void
+irongate_remap_area_pte(pte_t * pte, unsigned long address, unsigned long size,
+ unsigned long phys_addr, unsigned long flags)
+{
+ unsigned long end;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ if (address >= end)
+ BUG();
+ do {
+ if (!pte_none(*pte)) {
+ printk("irongate_remap_area_pte: page already exists\n");
+ BUG();
+ }
+ set_pte(pte,
+ mk_pte_phys(phys_addr,
+ __pgprot(_PAGE_VALID | _PAGE_ASM |
+ _PAGE_KRE | _PAGE_KWE | flags)));
+ address += PAGE_SIZE;
+ phys_addr += PAGE_SIZE;
+ pte++;
+ } while (address && (address < end));
+}
+
+static inline int
+irongate_remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size,
+ unsigned long phys_addr, unsigned long flags)
+{
+ unsigned long end;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ phys_addr -= address;
+ if (address >= end)
+ BUG();
+ do {
+ pte_t * pte = pte_alloc(&init_mm, pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ irongate_remap_area_pte(pte, address, end - address,
+ address + phys_addr, flags);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address && (address < end));
+ return 0;
+}
+
+static int
+irongate_remap_area_pages(unsigned long address, unsigned long phys_addr,
+ unsigned long size, unsigned long flags)
+{
+ pgd_t * dir;
+ unsigned long end = address + size;
+
+ phys_addr -= address;
+ dir = pgd_offset(&init_mm, address);
+ flush_cache_all();
+ if (address >= end)
+ BUG();
+ do {
+ pmd_t *pmd;
+ pmd = pmd_alloc(&init_mm, dir, address);
+ if (!pmd)
+ return -ENOMEM;
+ if (irongate_remap_area_pmd(pmd, address, end - address,
+ phys_addr + address, flags))
+ return -ENOMEM;
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (address && (address < end));
+ return 0;
+}
+
+#include <linux/agp_backend.h>
+#include <linux/agpgart.h>
+
+#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
+#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr))
+
+#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12)
+#define GET_GATT(addr) (gatt_pages[GET_PAGE_DIR_IDX(addr)])
+
+unsigned long
+irongate_ioremap(unsigned long addr, unsigned long size)
+{
+ struct vm_struct *area;
+ unsigned long vaddr;
+ unsigned long baddr, last;
+ u32 *mmio_regs, *gatt_pages, *cur_gatt, pte;
+ unsigned long gart_bus_addr, gart_aper_size;
+
+ gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
+ PCI_BASE_ADDRESS_MEM_MASK;
+
+ if (!gart_bus_addr) /* FIXME - there must be a better way!!! */
+ return addr + IRONGATE_MEM;
+
+ gart_aper_size = IRONGATE_DEFAULT_AGP_APER_SIZE; /* FIXME */
+
+ /*
+ * Check for within the AGP aperture...
+ */
+ do {
+ /*
+ * Check the AGP area
+ */
+ if (addr >= gart_bus_addr && addr + size - 1 <
+ gart_bus_addr + gart_aper_size)
+ break;
+
+ /*
+ * Not found - assume legacy ioremap
+ */
+ return addr + IRONGATE_MEM;
+ } while(0);
+
+ mmio_regs = (u32 *)(((unsigned long)IRONGATE0->bar1 &
+ PCI_BASE_ADDRESS_MEM_MASK) + IRONGATE_MEM);
+
+ gatt_pages = (u32 *)(phys_to_virt(mmio_regs[1])); /* FIXME */
+
+ /*
+ * Adjust the limits (mappings must be page aligned)
+ */
+ if (addr & ~PAGE_MASK) {
+ printk("AGP ioremap failed... addr not page aligned (0x%lx)\n",
+ addr);
+ return addr + IRONGATE_MEM;
+ }
+ last = addr + size - 1;
+ size = PAGE_ALIGN(last) - addr;
+
+#if 0
+ printk("irongate_ioremap(0x%lx, 0x%lx)\n", addr, size);
+ printk("irongate_ioremap: gart_bus_addr 0x%lx\n", gart_bus_addr);
+ printk("irongate_ioremap: gart_aper_size 0x%lx\n", gart_aper_size);
+ printk("irongate_ioremap: mmio_regs %p\n", mmio_regs);
+ printk("irongate_ioremap: gatt_pages %p\n", gatt_pages);
+
+ for(baddr = addr; baddr <= last; baddr += PAGE_SIZE)
+ {
+ cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
+ pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
+ printk("irongate_ioremap: cur_gatt %p pte 0x%x\n",
+ cur_gatt, pte);
+ }
+#endif
+
+ /*
+ * Map it
+ */
+ area = get_vm_area(size, VM_IOREMAP);
+ if (!area) return (unsigned long)NULL;
+
+ for(baddr = addr, vaddr = (unsigned long)area->addr;
+ baddr <= last;
+ baddr += PAGE_SIZE, vaddr += PAGE_SIZE)
+ {
+ cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
+ pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
+
+ if (irongate_remap_area_pages(VMALLOC_VMADDR(vaddr),
+ pte, PAGE_SIZE, 0)) {
+ printk("AGP ioremap: FAILED to map...\n");
+ vfree(area->addr);
+ return (unsigned long)NULL;
+ }
+ }
+
+ flush_tlb_all();
+
+ vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+#if 0
+ printk("irongate_ioremap(0x%lx, 0x%lx) returning 0x%lx\n",
+ addr, size, vaddr);
+#endif
+ return vaddr;
+}
+
+void
+irongate_iounmap(unsigned long addr)
+{
+ if (((long)addr >> 41) == -2)
+ return; /* kseg map, nothing to do */
+ if (addr) return vfree((void *)(PAGE_MASK & addr));
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)