From: Dave A. <ai...@us...> - 2002-10-25 17:25:33
|
Update of /cvsroot/linux-vax/kernel-2.4/drivers/vax/bus In directory usw-pr-cvs1:/tmp/cvs-serv27297/bus Added Files: Makefile qbus.c Log Message: DA: backport from 2.5 of Kenns qbus/delqa work - delqa/qbus works iprcons is not working.. needed for SIMH emu --- NEW FILE --- # # Makefile for the Linux/VAX bus device drivers. # O_TARGET := vaxbus.o obj-y := obj-m := obj-n := obj-$(CONFIG_QBUS) += qbus.o include $(TOPDIR)/Rules.make --- NEW FILE --- /* Very dumb map register allocator - does linear searches for available registers. Need a better way to do this. My first thought was to use bits 30:0 in invalid map registers to contain forward and backward links to maintain a list of free registers. However, bits 30:20 are reserved (read as zero and should be written as zero), so that only leaves us with 20 bits for links. This would be OK if we allow the allocation granularity to be 8 registers. - KPH */ #include <asm/io.h> #include <linux/sched.h> #include <linux/init.h> #include <linux/slab.h> #include <asm/bus/qbus.h> #define QBUS_DEBUG 0 #define CQBIC_MAPREGPHYS 0x20088000 #define CQBIC_NUMMAPREGS 8192 static unsigned int *cqbic_mapregbase; /* Given a (start, len), how many pagelets does this span? */ static unsigned int num_pagelets(void *start, unsigned int len) { unsigned int start_pagelet; unsigned int end_pagelet; start_pagelet = (unsigned int)start >> PAGELET_SHIFT; end_pagelet = ((unsigned int)start + len - 1) >> PAGELET_SHIFT; return end_pagelet - start_pagelet + 1; } __init static int qbus_init(void) { int i; if (cqbic_mapregbase == NULL) { cqbic_mapregbase = (unsigned int *)ioremap(CQBIC_MAPREGPHYS, CQBIC_NUMMAPREGS * sizeof(unsigned int)); #if QBUS_DEBUG printk("CQBIC map registers mapped at %p\n", cqbic_mapregbase); #endif } for (i=0; i<CQBIC_NUMMAPREGS; i++) { cqbic_mapregbase[i] = 0; } return 0; } static int find_n_free(unsigned int n) { int i; int j; i = 0; while (i < (8192 - n)) { for (j=0; j<n; j++) { if (cqbic_mapregbase[i+j]) { /* This reg in use */ break; } } if (j == n) { /* Found N contiguous free entries at offset I */ return i; } i += j+1; } return -1; } /* Allocate a bunch of map registers sufficient to map 'len' bytes at address 'start'. */ struct vax_dmamap *qbus_alloc_mapregs(void *start, unsigned int len) { struct vax_dmamap *map; map = kmalloc(sizeof(struct vax_dmamap), GFP_KERNEL); if (map != NULL) { int reg; unsigned int pagelets; pagelets = num_pagelets(start, len); reg = find_n_free(pagelets); if (reg != -1) { unsigned int pfn; unsigned int reg_value; int i; pfn = virt_to_phys(start) >> PAGELET_SHIFT; reg_value = (pfn & 0xfffff) | 0x80000000; for (i = reg; i < reg + pagelets; i++, reg_value++) { cqbic_mapregbase[i] = reg_value; } map->reg = reg; map->pagelets = pagelets; map->virtaddr = start; map->busaddr = (reg * PAGELET_SIZE) + ((unsigned int)start & ~PAGELET_MASK); #if QBUS_DEBUG printk("Using map registers 0x%04x to 0x%04x to map virt %p to %p (bus %08x)\n", reg, reg + pagelets - 1, start, (char *)start + len - 1, map->busaddr); #endif } else { kfree(map); map = NULL; } } return map; } void qbus_unmap(struct vax_dmamap *map) { #if QBUS_DEBUG printk("Zapping map registers 0x%04x to 0x%04x\n", map->reg, map->reg + map->pagelets - 1); #endif while (map->pagelets--) { cqbic_mapregbase[map->reg] = 0; map->reg++; } kfree(map); } void qbus_dumpmap(void) { int i; for (i=0; i<CQBIC_NUMMAPREGS; i++) { if (cqbic_mapregbase[i] != 0) { printk("CQBIC map reg %04x = %08x (-> %08x)\n", i, cqbic_mapregbase[i], (cqbic_mapregbase[i] & 0xfffff) << PAGELET_SHIFT); } } } int qbus_vector_to_irq(unsigned int vector) { return (vector / 4) + 128; } int qbus_request_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char * devname, void *dev_id) { return request_irq(irq / 4 + 128, handler, irqflags, devname, dev_id); } __initcall(qbus_init); |