|
@@ -528,3 +528,202 @@ titan_ioremap(unsigned long addr, unsigned long size)
|
|
PAGE_SIZE, 0)) {
|
|
PAGE_SIZE, 0)) {
|
|
printk("FAILED to remap_area_pages...\n");
|
|
printk("FAILED to remap_area_pages...\n");
|
|
vfree(area->addr);
|
|
vfree(area->addr);
|
|
|
|
+ return NULL;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ flush_tlb_all();
|
|
|
|
+
|
|
|
|
+ vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
|
|
|
|
+ return (void __iomem *) vaddr;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Assume a legacy (read: VGA) address, and return appropriately. */
|
|
|
|
+ return (void __iomem *)(addr + TITAN_MEM_BIAS);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+void
|
|
|
|
+titan_iounmap(volatile void __iomem *xaddr)
|
|
|
|
+{
|
|
|
|
+ unsigned long addr = (unsigned long) xaddr;
|
|
|
|
+ if (addr >= VMALLOC_START)
|
|
|
|
+ vfree((void *)(PAGE_MASK & addr));
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+int
|
|
|
|
+titan_is_mmio(const volatile void __iomem *xaddr)
|
|
|
|
+{
|
|
|
|
+ unsigned long addr = (unsigned long) xaddr;
|
|
|
|
+
|
|
|
|
+ if (addr >= VMALLOC_START)
|
|
|
|
+ return 1;
|
|
|
|
+ else
|
|
|
|
+ return (addr & 0x100000000UL) == 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#ifndef CONFIG_ALPHA_GENERIC
|
|
|
|
+EXPORT_SYMBOL(titan_ioportmap);
|
|
|
|
+EXPORT_SYMBOL(titan_ioremap);
|
|
|
|
+EXPORT_SYMBOL(titan_iounmap);
|
|
|
|
+EXPORT_SYMBOL(titan_is_mmio);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * AGP GART Support.
|
|
|
|
+ */
|
|
|
|
+#include <linux/agp_backend.h>
|
|
|
|
+#include <asm/agp_backend.h>
|
|
|
|
+#include <linux/slab.h>
|
|
|
|
+#include <linux/delay.h>
|
|
|
|
+
|
|
|
|
+struct titan_agp_aperture {
|
|
|
|
+ struct pci_iommu_arena *arena;
|
|
|
|
+ long pg_start;
|
|
|
|
+ long pg_count;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+titan_agp_setup(alpha_agp_info *agp)
|
|
|
|
+{
|
|
|
|
+ struct titan_agp_aperture *aper;
|
|
|
|
+
|
|
|
|
+ if (!alpha_agpgart_size)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ aper = kmalloc(sizeof(struct titan_agp_aperture), GFP_KERNEL);
|
|
|
|
+ if (aper == NULL)
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+
|
|
|
|
+ aper->arena = agp->hose->sg_pci;
|
|
|
|
+ aper->pg_count = alpha_agpgart_size / PAGE_SIZE;
|
|
|
|
+ aper->pg_start = iommu_reserve(aper->arena, aper->pg_count,
|
|
|
|
+ aper->pg_count - 1);
|
|
|
|
+ if (aper->pg_start < 0) {
|
|
|
|
+ printk(KERN_ERR "Failed to reserve AGP memory\n");
|
|
|
|
+ kfree(aper);
|
|
|
|
+ return -ENOMEM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ agp->aperture.bus_base =
|
|
|
|
+ aper->arena->dma_base + aper->pg_start * PAGE_SIZE;
|
|
|
|
+ agp->aperture.size = aper->pg_count * PAGE_SIZE;
|
|
|
|
+ agp->aperture.sysdata = aper;
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void
|
|
|
|
+titan_agp_cleanup(alpha_agp_info *agp)
|
|
|
|
+{
|
|
|
|
+ struct titan_agp_aperture *aper = agp->aperture.sysdata;
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
+ status = iommu_release(aper->arena, aper->pg_start, aper->pg_count);
|
|
|
|
+ if (status == -EBUSY) {
|
|
|
|
+ printk(KERN_WARNING
|
|
|
|
+ "Attempted to release bound AGP memory - unbinding\n");
|
|
|
|
+ iommu_unbind(aper->arena, aper->pg_start, aper->pg_count);
|
|
|
|
+ status = iommu_release(aper->arena, aper->pg_start,
|
|
|
|
+ aper->pg_count);
|
|
|
|
+ }
|
|
|
|
+ if (status < 0)
|
|
|
|
+ printk(KERN_ERR "Failed to release AGP memory\n");
|
|
|
|
+
|
|
|
|
+ kfree(aper);
|
|
|
|
+ kfree(agp);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+titan_agp_configure(alpha_agp_info *agp)
|
|
|
|
+{
|
|
|
|
+ union TPAchipPCTL pctl;
|
|
|
|
+ titan_pachip_port *port = agp->private;
|
|
|
|
+ pctl.pctl_q_whole = port->pctl.csr;
|
|
|
|
+
|
|
|
|
+ /* Side-Band Addressing? */
|
|
|
|
+ pctl.pctl_r_bits.apctl_v_agp_sba_en = agp->mode.bits.sba;
|
|
|
|
+
|
|
|
|
+ /* AGP Rate? */
|
|
|
|
+ pctl.pctl_r_bits.apctl_v_agp_rate = 0; /* 1x */
|
|
|
|
+ if (agp->mode.bits.rate & 2)
|
|
|
|
+ pctl.pctl_r_bits.apctl_v_agp_rate = 1; /* 2x */
|
|
|
|
+#if 0
|
|
|
|
+ if (agp->mode.bits.rate & 4)
|
|
|
|
+ pctl.pctl_r_bits.apctl_v_agp_rate = 2; /* 4x */
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+ /* RQ Depth? */
|
|
|
|
+ pctl.pctl_r_bits.apctl_v_agp_hp_rd = 2;
|
|
|
|
+ pctl.pctl_r_bits.apctl_v_agp_lp_rd = 7;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * AGP Enable.
|
|
|
|
+ */
|
|
|
|
+ pctl.pctl_r_bits.apctl_v_agp_en = agp->mode.bits.enable;
|
|
|
|
+
|
|
|
|
+ /* Tell the user. */
|
|
|
|
+ printk("Enabling AGP: %dX%s\n",
|
|
|
|
+ 1 << pctl.pctl_r_bits.apctl_v_agp_rate,
|
|
|
|
+ pctl.pctl_r_bits.apctl_v_agp_sba_en ? " - SBA" : "");
|
|
|
|
+
|
|
|
|
+ /* Write it. */
|
|
|
|
+ port->pctl.csr = pctl.pctl_q_whole;
|
|
|
|
+
|
|
|
|
+ /* And wait at least 5000 66MHz cycles (per Titan spec). */
|
|
|
|
+ udelay(100);
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+titan_agp_bind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
|
|
|
|
+{
|
|
|
|
+ struct titan_agp_aperture *aper = agp->aperture.sysdata;
|
|
|
|
+ return iommu_bind(aper->arena, aper->pg_start + pg_start,
|
|
|
|
+ mem->page_count, mem->pages);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+titan_agp_unbind_memory(alpha_agp_info *agp, off_t pg_start, struct agp_memory *mem)
|
|
|
|
+{
|
|
|
|
+ struct titan_agp_aperture *aper = agp->aperture.sysdata;
|
|
|
|
+ return iommu_unbind(aper->arena, aper->pg_start + pg_start,
|
|
|
|
+ mem->page_count);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static unsigned long
|
|
|
|
+titan_agp_translate(alpha_agp_info *agp, dma_addr_t addr)
|
|
|
|
+{
|
|
|
|
+ struct titan_agp_aperture *aper = agp->aperture.sysdata;
|
|
|
|
+ unsigned long baddr = addr - aper->arena->dma_base;
|
|
|
|
+ unsigned long pte;
|
|
|
|
+
|
|
|
|
+ if (addr < agp->aperture.bus_base ||
|
|
|
|
+ addr >= agp->aperture.bus_base + agp->aperture.size) {
|
|
|
|
+ printk("%s: addr out of range\n", __func__);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pte = aper->arena->ptes[baddr >> PAGE_SHIFT];
|
|
|
|
+ if (!(pte & 1)) {
|
|
|
|
+ printk("%s: pte not valid\n", __func__);
|
|
|
|
+ return -EINVAL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return (pte >> 1) << PAGE_SHIFT;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+struct alpha_agp_ops titan_agp_ops =
|
|
|
|
+{
|
|
|
|
+ .setup = titan_agp_setup,
|
|
|
|
+ .cleanup = titan_agp_cleanup,
|
|
|
|
+ .configure = titan_agp_configure,
|
|
|
|
+ .bind = titan_agp_bind_memory,
|
|
|
|
+ .unbind = titan_agp_unbind_memory,
|
|
|
|
+ .translate = titan_agp_translate
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+alpha_agp_info *
|
|
|
|
+titan_agp_info(void)
|
|
|
|
+{
|
|
|
|
+ alpha_agp_info *agp;
|