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);
|