linux/arch/sparc/mm/io-unit.c
<<
>>
Prefs
   1/*
   2 * io-unit.c:  IO-UNIT specific routines for memory management.
   3 *
   4 * Copyright (C) 1997,1998 Jakub Jelinek    (jj@sunsite.mff.cuni.cz)
   5 */
   6 
   7#include <linux/kernel.h>
   8#include <linux/init.h>
   9#include <linux/slab.h>
  10#include <linux/spinlock.h>
  11#include <linux/mm.h>
  12#include <linux/highmem.h>      /* pte_offset_map => kmap_atomic */
  13#include <linux/bitops.h>
  14#include <linux/scatterlist.h>
  15
  16#include <asm/pgalloc.h>
  17#include <asm/pgtable.h>
  18#include <asm/sbus.h>
  19#include <asm/io.h>
  20#include <asm/io-unit.h>
  21#include <asm/mxcc.h>
  22#include <asm/cacheflush.h>
  23#include <asm/tlbflush.h>
  24#include <asm/dma.h>
  25#include <asm/oplib.h>
  26
  27/* #define IOUNIT_DEBUG */
  28#ifdef IOUNIT_DEBUG
  29#define IOD(x) printk(x)
  30#else
  31#define IOD(x) do { } while (0)
  32#endif
  33
  34#define IOPERM        (IOUPTE_CACHE | IOUPTE_WRITE | IOUPTE_VALID)
  35#define MKIOPTE(phys) __iopte((((phys)>>4) & IOUPTE_PAGE) | IOPERM)
  36
  37void __init
  38iounit_init(int sbi_node, int io_node, struct sbus_bus *sbus)
  39{
  40        iopte_t *xpt, *xptend;
  41        struct iounit_struct *iounit;
  42        struct linux_prom_registers iommu_promregs[PROMREG_MAX];
  43        struct resource r;
  44
  45        iounit = kzalloc(sizeof(struct iounit_struct), GFP_ATOMIC);
  46        if (!iounit) {
  47                prom_printf("SUN4D: Cannot alloc iounit, halting.\n");
  48                prom_halt();
  49        }
  50
  51        iounit->limit[0] = IOUNIT_BMAP1_START;
  52        iounit->limit[1] = IOUNIT_BMAP2_START;
  53        iounit->limit[2] = IOUNIT_BMAPM_START;
  54        iounit->limit[3] = IOUNIT_BMAPM_END;
  55        iounit->rotor[1] = IOUNIT_BMAP2_START;
  56        iounit->rotor[2] = IOUNIT_BMAPM_START;
  57
  58        xpt = NULL;
  59        if(prom_getproperty(sbi_node, "reg", (void *) iommu_promregs,
  60                            sizeof(iommu_promregs)) != -1) {
  61                prom_apply_generic_ranges(io_node, 0, iommu_promregs, 3);
  62                memset(&r, 0, sizeof(r));
  63                r.flags = iommu_promregs[2].which_io;
  64                r.start = iommu_promregs[2].phys_addr;
  65                xpt = (iopte_t *) sbus_ioremap(&r, 0, PAGE_SIZE * 16, "XPT");
  66        }
  67        if(!xpt) panic("Cannot map External Page Table.");
  68        
  69        sbus->ofdev.dev.archdata.iommu = iounit;
  70        iounit->page_table = xpt;
  71        spin_lock_init(&iounit->lock);
  72        
  73        for (xptend = iounit->page_table + (16 * PAGE_SIZE) / sizeof(iopte_t);
  74             xpt < xptend;)
  75                iopte_val(*xpt++) = 0;
  76}
  77
  78/* One has to hold iounit->lock to call this */
  79static unsigned long iounit_get_area(struct iounit_struct *iounit, unsigned long vaddr, int size)
  80{
  81        int i, j, k, npages;
  82        unsigned long rotor, scan, limit;
  83        iopte_t iopte;
  84
  85        npages = ((vaddr & ~PAGE_MASK) + size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
  86
  87        /* A tiny bit of magic ingredience :) */
  88        switch (npages) {
  89        case 1: i = 0x0231; break;
  90        case 2: i = 0x0132; break;
  91        default: i = 0x0213; break;
  92        }
  93        
  94        IOD(("iounit_get_area(%08lx,%d[%d])=", vaddr, size, npages));
  95        
  96next:   j = (i & 15);
  97        rotor = iounit->rotor[j - 1];
  98        limit = iounit->limit[j];
  99        scan = rotor;
 100nexti:  scan = find_next_zero_bit(iounit->bmap, limit, scan);
 101        if (scan + npages > limit) {
 102                if (limit != rotor) {
 103                        limit = rotor;
 104                        scan = iounit->limit[j - 1];
 105                        goto nexti;
 106                }
 107                i >>= 4;
 108                if (!(i & 15))
 109                        panic("iounit_get_area: Couldn't find free iopte slots for (%08lx,%d)\n", vaddr, size);
 110                goto next;
 111        }
 112        for (k = 1, scan++; k < npages; k++)
 113                if (test_bit(scan++, iounit->bmap))
 114                        goto nexti;
 115        iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
 116        scan -= npages;
 117        iopte = MKIOPTE(__pa(vaddr & PAGE_MASK));
 118        vaddr = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT) + (vaddr & ~PAGE_MASK);
 119        for (k = 0; k < npages; k++, iopte = __iopte(iopte_val(iopte) + 0x100), scan++) {
 120                set_bit(scan, iounit->bmap);
 121                iounit->page_table[scan] = iopte;
 122        }
 123        IOD(("%08lx\n", vaddr));
 124        return vaddr;
 125}
 126
 127static __u32 iounit_get_scsi_one(char *vaddr, unsigned long len, struct sbus_bus *sbus)
 128{
 129        unsigned long ret, flags;
 130        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 131        
 132        spin_lock_irqsave(&iounit->lock, flags);
 133        ret = iounit_get_area(iounit, (unsigned long)vaddr, len);
 134        spin_unlock_irqrestore(&iounit->lock, flags);
 135        return ret;
 136}
 137
 138static void iounit_get_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
 139{
 140        unsigned long flags;
 141        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 142
 143        /* FIXME: Cache some resolved pages - often several sg entries are to the same page */
 144        spin_lock_irqsave(&iounit->lock, flags);
 145        while (sz != 0) {
 146                --sz;
 147                sg->dvma_address = iounit_get_area(iounit, (unsigned long) sg_virt(sg), sg->length);
 148                sg->dvma_length = sg->length;
 149                sg = sg_next(sg);
 150        }
 151        spin_unlock_irqrestore(&iounit->lock, flags);
 152}
 153
 154static void iounit_release_scsi_one(__u32 vaddr, unsigned long len, struct sbus_bus *sbus)
 155{
 156        unsigned long flags;
 157        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 158        
 159        spin_lock_irqsave(&iounit->lock, flags);
 160        len = ((vaddr & ~PAGE_MASK) + len + (PAGE_SIZE-1)) >> PAGE_SHIFT;
 161        vaddr = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
 162        IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
 163        for (len += vaddr; vaddr < len; vaddr++)
 164                clear_bit(vaddr, iounit->bmap);
 165        spin_unlock_irqrestore(&iounit->lock, flags);
 166}
 167
 168static void iounit_release_scsi_sgl(struct scatterlist *sg, int sz, struct sbus_bus *sbus)
 169{
 170        unsigned long flags;
 171        unsigned long vaddr, len;
 172        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 173
 174        spin_lock_irqsave(&iounit->lock, flags);
 175        while (sz != 0) {
 176                --sz;
 177                len = ((sg->dvma_address & ~PAGE_MASK) + sg->length + (PAGE_SIZE-1)) >> PAGE_SHIFT;
 178                vaddr = (sg->dvma_address - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
 179                IOD(("iounit_release %08lx-%08lx\n", (long)vaddr, (long)len+vaddr));
 180                for (len += vaddr; vaddr < len; vaddr++)
 181                        clear_bit(vaddr, iounit->bmap);
 182                sg = sg_next(sg);
 183        }
 184        spin_unlock_irqrestore(&iounit->lock, flags);
 185}
 186
 187#ifdef CONFIG_SBUS
 188static int iounit_map_dma_area(dma_addr_t *pba, unsigned long va, __u32 addr, int len)
 189{
 190        unsigned long page, end;
 191        pgprot_t dvma_prot;
 192        iopte_t *iopte;
 193        struct sbus_bus *sbus;
 194
 195        *pba = addr;
 196
 197        dvma_prot = __pgprot(SRMMU_CACHE | SRMMU_ET_PTE | SRMMU_PRIV);
 198        end = PAGE_ALIGN((addr + len));
 199        while(addr < end) {
 200                page = va;
 201                {
 202                        pgd_t *pgdp;
 203                        pmd_t *pmdp;
 204                        pte_t *ptep;
 205                        long i;
 206
 207                        pgdp = pgd_offset(&init_mm, addr);
 208                        pmdp = pmd_offset(pgdp, addr);
 209                        ptep = pte_offset_map(pmdp, addr);
 210
 211                        set_pte(ptep, mk_pte(virt_to_page(page), dvma_prot));
 212                        
 213                        i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
 214
 215                        for_each_sbus(sbus) {
 216                                struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 217
 218                                iopte = (iopte_t *)(iounit->page_table + i);
 219                                *iopte = MKIOPTE(__pa(page));
 220                        }
 221                }
 222                addr += PAGE_SIZE;
 223                va += PAGE_SIZE;
 224        }
 225        flush_cache_all();
 226        flush_tlb_all();
 227
 228        return 0;
 229}
 230
 231static void iounit_unmap_dma_area(unsigned long addr, int len)
 232{
 233        /* XXX Somebody please fill this in */
 234}
 235
 236/* XXX We do not pass sbus device here, bad. */
 237static struct page *iounit_translate_dvma(unsigned long addr)
 238{
 239        struct sbus_bus *sbus = sbus_root;      /* They are all the same */
 240        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 241        int i;
 242        iopte_t *iopte;
 243
 244        i = ((addr - IOUNIT_DMA_BASE) >> PAGE_SHIFT);
 245        iopte = (iopte_t *)(iounit->page_table + i);
 246        return pfn_to_page(iopte_val(*iopte) >> (PAGE_SHIFT-4)); /* XXX sun4d guru, help */
 247}
 248#endif
 249
 250static char *iounit_lockarea(char *vaddr, unsigned long len)
 251{
 252/* FIXME: Write this */
 253        return vaddr;
 254}
 255
 256static void iounit_unlockarea(char *vaddr, unsigned long len)
 257{
 258/* FIXME: Write this */
 259}
 260
 261void __init ld_mmu_iounit(void)
 262{
 263        BTFIXUPSET_CALL(mmu_lockarea, iounit_lockarea, BTFIXUPCALL_RETO0);
 264        BTFIXUPSET_CALL(mmu_unlockarea, iounit_unlockarea, BTFIXUPCALL_NOP);
 265
 266        BTFIXUPSET_CALL(mmu_get_scsi_one, iounit_get_scsi_one, BTFIXUPCALL_NORM);
 267        BTFIXUPSET_CALL(mmu_get_scsi_sgl, iounit_get_scsi_sgl, BTFIXUPCALL_NORM);
 268        BTFIXUPSET_CALL(mmu_release_scsi_one, iounit_release_scsi_one, BTFIXUPCALL_NORM);
 269        BTFIXUPSET_CALL(mmu_release_scsi_sgl, iounit_release_scsi_sgl, BTFIXUPCALL_NORM);
 270
 271#ifdef CONFIG_SBUS
 272        BTFIXUPSET_CALL(mmu_map_dma_area, iounit_map_dma_area, BTFIXUPCALL_NORM);
 273        BTFIXUPSET_CALL(mmu_unmap_dma_area, iounit_unmap_dma_area, BTFIXUPCALL_NORM);
 274        BTFIXUPSET_CALL(mmu_translate_dvma, iounit_translate_dvma, BTFIXUPCALL_NORM);
 275#endif
 276}
 277
 278__u32 iounit_map_dma_init(struct sbus_bus *sbus, int size)
 279{
 280        int i, j, k, npages;
 281        unsigned long rotor, scan, limit;
 282        unsigned long flags;
 283        __u32 ret;
 284        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 285
 286        npages = (size + (PAGE_SIZE-1)) >> PAGE_SHIFT;
 287        i = 0x0213;
 288        spin_lock_irqsave(&iounit->lock, flags);
 289next:   j = (i & 15);
 290        rotor = iounit->rotor[j - 1];
 291        limit = iounit->limit[j];
 292        scan = rotor;
 293nexti:  scan = find_next_zero_bit(iounit->bmap, limit, scan);
 294        if (scan + npages > limit) {
 295                if (limit != rotor) {
 296                        limit = rotor;
 297                        scan = iounit->limit[j - 1];
 298                        goto nexti;
 299                }
 300                i >>= 4;
 301                if (!(i & 15))
 302                        panic("iounit_map_dma_init: Couldn't find free iopte slots for %d bytes\n", size);
 303                goto next;
 304        }
 305        for (k = 1, scan++; k < npages; k++)
 306                if (test_bit(scan++, iounit->bmap))
 307                        goto nexti;
 308        iounit->rotor[j - 1] = (scan < limit) ? scan : iounit->limit[j - 1];
 309        scan -= npages;
 310        ret = IOUNIT_DMA_BASE + (scan << PAGE_SHIFT);
 311        for (k = 0; k < npages; k++, scan++)
 312                set_bit(scan, iounit->bmap);
 313        spin_unlock_irqrestore(&iounit->lock, flags);
 314        return ret;
 315}
 316
 317__u32 iounit_map_dma_page(__u32 vaddr, void *addr, struct sbus_bus *sbus)
 318{
 319        int scan = (vaddr - IOUNIT_DMA_BASE) >> PAGE_SHIFT;
 320        struct iounit_struct *iounit = sbus->ofdev.dev.archdata.iommu;
 321        
 322        iounit->page_table[scan] = MKIOPTE(__pa(((unsigned long)addr) & PAGE_MASK));
 323        return vaddr + (((unsigned long)addr) & ~PAGE_MASK);
 324}
 325