M7350v1_en_gpl

This commit is contained in:
T
2024-09-09 08:52:07 +00:00
commit f9cc65cfda
65988 changed files with 26357421 additions and 0 deletions

View File

@ -0,0 +1,7 @@
#
# Makefile for Linux arch/m68k/sun3 source directory
#
obj-y := sun3ints.o sun3dvma.o idprom.o
obj-$(CONFIG_SUN3) += config.o mmu_emu.o leds.o dvma.o intersil.o

View File

@ -0,0 +1,171 @@
/*
* linux/arch/m68k/sun3/config.c
*
* Copyright (C) 1996,1997 Pekka Pietik{inen
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/seq_file.h>
#include <linux/tty.h>
#include <linux/console.h>
#include <linux/init.h>
#include <linux/bootmem.h>
#include <asm/oplib.h>
#include <asm/setup.h>
#include <asm/contregs.h>
#include <asm/movs.h>
#include <asm/pgtable.h>
#include <asm/pgalloc.h>
#include <asm/sun3-head.h>
#include <asm/sun3mmu.h>
#include <asm/rtc.h>
#include <asm/machdep.h>
#include <asm/idprom.h>
#include <asm/intersil.h>
#include <asm/irq.h>
#include <asm/sections.h>
#include <asm/segment.h>
#include <asm/sun3ints.h>
char sun3_reserved_pmeg[SUN3_PMEGS_NUM];
extern unsigned long sun3_gettimeoffset(void);
static void sun3_sched_init(irq_handler_t handler);
extern void sun3_get_model (char* model);
extern int sun3_hwclk(int set, struct rtc_time *t);
volatile char* clock_va;
extern unsigned long availmem;
unsigned long num_pages;
static void sun3_get_hardware_list(struct seq_file *m)
{
seq_printf(m, "PROM Revision:\t%s\n", romvec->pv_monid);
}
void __init sun3_init(void)
{
unsigned char enable_register;
int i;
m68k_machtype= MACH_SUN3;
m68k_cputype = CPU_68020;
m68k_fputype = FPU_68881; /* mc68881 actually */
m68k_mmutype = MMU_SUN3;
clock_va = (char *) 0xfe06000; /* dark */
sun3_intreg = (unsigned char *) 0xfe0a000; /* magic */
sun3_disable_interrupts();
prom_init((void *)LINUX_OPPROM_BEGVM);
GET_CONTROL_BYTE(AC_SENABLE,enable_register);
enable_register |= 0x50; /* Enable FPU */
SET_CONTROL_BYTE(AC_SENABLE,enable_register);
GET_CONTROL_BYTE(AC_SENABLE,enable_register);
/* This code looks suspicious, because it doesn't subtract
memory belonging to the kernel from the available space */
memset(sun3_reserved_pmeg, 0, sizeof(sun3_reserved_pmeg));
/* Reserve important PMEGS */
/* FIXME: These should be probed instead of hardcoded */
for (i=0; i<8; i++) /* Kernel PMEGs */
sun3_reserved_pmeg[i] = 1;
sun3_reserved_pmeg[247] = 1; /* ROM mapping */
sun3_reserved_pmeg[248] = 1; /* AMD Ethernet */
sun3_reserved_pmeg[251] = 1; /* VB area */
sun3_reserved_pmeg[254] = 1; /* main I/O */
sun3_reserved_pmeg[249] = 1;
sun3_reserved_pmeg[252] = 1;
sun3_reserved_pmeg[253] = 1;
set_fs(KERNEL_DS);
}
/* Without this, Bad Things happen when something calls arch_reset. */
static void sun3_reboot (void)
{
prom_reboot ("vmlinux");
}
static void sun3_halt (void)
{
prom_halt ();
}
/* sun3 bootmem allocation */
static void __init sun3_bootmem_alloc(unsigned long memory_start,
unsigned long memory_end)
{
unsigned long start_page;
/* align start/end to page boundaries */
memory_start = ((memory_start + (PAGE_SIZE-1)) & PAGE_MASK);
memory_end = memory_end & PAGE_MASK;
start_page = __pa(memory_start) >> PAGE_SHIFT;
num_pages = __pa(memory_end) >> PAGE_SHIFT;
high_memory = (void *)memory_end;
availmem = memory_start;
m68k_setup_node(0);
availmem += init_bootmem_node(NODE_DATA(0), start_page, 0, num_pages);
availmem = (availmem + (PAGE_SIZE-1)) & PAGE_MASK;
free_bootmem(__pa(availmem), memory_end - (availmem));
}
void __init config_sun3(void)
{
unsigned long memory_start, memory_end;
printk("ARCH: SUN3\n");
idprom_init();
/* Subtract kernel memory from available memory */
mach_sched_init = sun3_sched_init;
mach_init_IRQ = sun3_init_IRQ;
mach_reset = sun3_reboot;
mach_gettimeoffset = sun3_gettimeoffset;
mach_get_model = sun3_get_model;
mach_hwclk = sun3_hwclk;
mach_halt = sun3_halt;
mach_get_hardware_list = sun3_get_hardware_list;
memory_start = ((((unsigned long)_end) + 0x2000) & ~0x1fff);
// PROM seems to want the last couple of physical pages. --m
memory_end = *(romvec->pv_sun3mem) + PAGE_OFFSET - 2*PAGE_SIZE;
m68k_num_memory=1;
m68k_memory[0].size=*(romvec->pv_sun3mem);
sun3_bootmem_alloc(memory_start, memory_end);
}
static void __init sun3_sched_init(irq_handler_t timer_routine)
{
sun3_disable_interrupts();
intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_DISABLE|INTERSIL_24H_MODE);
intersil_clock->int_reg=INTERSIL_HZ_100_MASK;
intersil_clear();
sun3_enable_irq(5);
intersil_clock->cmd_reg=(INTERSIL_RUN|INTERSIL_INT_ENABLE|INTERSIL_24H_MODE);
sun3_enable_interrupts();
intersil_clear();
}

View File

@ -0,0 +1,71 @@
/*
* linux/arch/m68k/sun3/dvma.c
*
* Written by Sam Creasey
*
* Sun3 IOMMU routines used for dvma accesses.
*
*/
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/bootmem.h>
#include <linux/list.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/sun3mmu.h>
#include <asm/dvma.h>
static unsigned long ptelist[120];
static unsigned long dvma_page(unsigned long kaddr, unsigned long vaddr)
{
unsigned long pte;
unsigned long j;
pte_t ptep;
j = *(volatile unsigned long *)kaddr;
*(volatile unsigned long *)kaddr = j;
ptep = pfn_pte(virt_to_pfn(kaddr), PAGE_KERNEL);
pte = pte_val(ptep);
// printk("dvma_remap: addr %lx -> %lx pte %08lx len %x\n",
// kaddr, vaddr, pte, len);
if(ptelist[(vaddr & 0xff000) >> PAGE_SHIFT] != pte) {
sun3_put_pte(vaddr, pte);
ptelist[(vaddr & 0xff000) >> PAGE_SHIFT] = pte;
}
return (vaddr + (kaddr & ~PAGE_MASK));
}
int dvma_map_iommu(unsigned long kaddr, unsigned long baddr,
int len)
{
unsigned long end;
unsigned long vaddr;
vaddr = dvma_btov(baddr);
end = vaddr + len;
while(vaddr < end) {
dvma_page(kaddr, vaddr);
kaddr += PAGE_SIZE;
vaddr += PAGE_SIZE;
}
return 0;
}
void sun3_dvma_init(void)
{
memset(ptelist, 0, sizeof(ptelist));
}

View File

@ -0,0 +1,132 @@
/*
* idprom.c: Routines to load the idprom into kernel addresses and
* interpret the data contained within.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Sun3/3x models added by David Monro (davidm@psrg.cs.usyd.edu.au)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/string.h>
#include <asm/oplib.h>
#include <asm/idprom.h>
#include <asm/machines.h> /* Fun with Sun released architectures. */
struct idprom *idprom;
EXPORT_SYMBOL(idprom);
static struct idprom idprom_buffer;
/* Here is the master table of Sun machines which use some implementation
* of the Sparc CPU and have a meaningful IDPROM machtype value that we
* know about. See asm-sparc/machines.h for empirical constants.
*/
static struct Sun_Machine_Models Sun_Machines[NUM_SUN_MACHINES] = {
/* First, Sun3's */
{ .name = "Sun 3/160 Series", .id_machtype = (SM_SUN3 | SM_3_160) },
{ .name = "Sun 3/50", .id_machtype = (SM_SUN3 | SM_3_50) },
{ .name = "Sun 3/260 Series", .id_machtype = (SM_SUN3 | SM_3_260) },
{ .name = "Sun 3/110 Series", .id_machtype = (SM_SUN3 | SM_3_110) },
{ .name = "Sun 3/60", .id_machtype = (SM_SUN3 | SM_3_60) },
{ .name = "Sun 3/E", .id_machtype = (SM_SUN3 | SM_3_E) },
/* Now, Sun3x's */
{ .name = "Sun 3/460 Series", .id_machtype = (SM_SUN3X | SM_3_460) },
{ .name = "Sun 3/80", .id_machtype = (SM_SUN3X | SM_3_80) },
/* Then, Sun4's */
// { .name = "Sun 4/100 Series", .id_machtype = (SM_SUN4 | SM_4_110) },
// { .name = "Sun 4/200 Series", .id_machtype = (SM_SUN4 | SM_4_260) },
// { .name = "Sun 4/300 Series", .id_machtype = (SM_SUN4 | SM_4_330) },
// { .name = "Sun 4/400 Series", .id_machtype = (SM_SUN4 | SM_4_470) },
/* And now, Sun4c's */
// { .name = "Sun4c SparcStation 1", .id_machtype = (SM_SUN4C | SM_4C_SS1) },
// { .name = "Sun4c SparcStation IPC", .id_machtype = (SM_SUN4C | SM_4C_IPC) },
// { .name = "Sun4c SparcStation 1+", .id_machtype = (SM_SUN4C | SM_4C_SS1PLUS) },
// { .name = "Sun4c SparcStation SLC", .id_machtype = (SM_SUN4C | SM_4C_SLC) },
// { .name = "Sun4c SparcStation 2", .id_machtype = (SM_SUN4C | SM_4C_SS2) },
// { .name = "Sun4c SparcStation ELC", .id_machtype = (SM_SUN4C | SM_4C_ELC) },
// { .name = "Sun4c SparcStation IPX", .id_machtype = (SM_SUN4C | SM_4C_IPX) },
/* Finally, early Sun4m's */
// { .name = "Sun4m SparcSystem600", .id_machtype = (SM_SUN4M | SM_4M_SS60) },
// { .name = "Sun4m SparcStation10/20", .id_machtype = (SM_SUN4M | SM_4M_SS50) },
// { .name = "Sun4m SparcStation5", .id_machtype = (SM_SUN4M | SM_4M_SS40) },
/* One entry for the OBP arch's which are sun4d, sun4e, and newer sun4m's */
// { .name = "Sun4M OBP based system", .id_machtype = (SM_SUN4M_OBP | 0x0) }
};
static void __init display_system_type(unsigned char machtype)
{
register int i;
for (i = 0; i < NUM_SUN_MACHINES; i++) {
if(Sun_Machines[i].id_machtype == machtype) {
if (machtype != (SM_SUN4M_OBP | 0x00))
printk("TYPE: %s\n", Sun_Machines[i].name);
else {
#if 0
prom_getproperty(prom_root_node, "banner-name",
sysname, sizeof(sysname));
printk("TYPE: %s\n", sysname);
#endif
}
return;
}
}
prom_printf("IDPROM: Bogus id_machtype value, 0x%x\n", machtype);
prom_halt();
}
void sun3_get_model(unsigned char* model)
{
register int i;
for (i = 0; i < NUM_SUN_MACHINES; i++) {
if(Sun_Machines[i].id_machtype == idprom->id_machtype) {
strcpy(model, Sun_Machines[i].name);
return;
}
}
}
/* Calculate the IDPROM checksum (xor of the data bytes). */
static unsigned char __init calc_idprom_cksum(struct idprom *idprom)
{
unsigned char cksum, i, *ptr = (unsigned char *)idprom;
for (i = cksum = 0; i <= 0x0E; i++)
cksum ^= *ptr++;
return cksum;
}
/* Create a local IDPROM copy, verify integrity, and display information. */
void __init idprom_init(void)
{
prom_get_idprom((char *) &idprom_buffer, sizeof(idprom_buffer));
idprom = &idprom_buffer;
if (idprom->id_format != 0x01) {
prom_printf("IDPROM: Unknown format type!\n");
prom_halt();
}
if (idprom->id_cksum != calc_idprom_cksum(idprom)) {
prom_printf("IDPROM: Checksum failure (nvram=%x, calc=%x)!\n",
idprom->id_cksum, calc_idprom_cksum(idprom));
prom_halt();
}
display_system_type(idprom->id_machtype);
printk("Ethernet address: %x:%x:%x:%x:%x:%x\n",
idprom->id_ethaddr[0], idprom->id_ethaddr[1],
idprom->id_ethaddr[2], idprom->id_ethaddr[3],
idprom->id_ethaddr[4], idprom->id_ethaddr[5]);
}

View File

@ -0,0 +1,74 @@
/*
* arch/m68k/sun3/intersil.c
*
* basic routines for accessing the intersil clock within the sun3 machines
*
* started 11/12/1999 Sam Creasey
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/kernel.h>
#include <linux/rtc.h>
#include <asm/errno.h>
#include <asm/rtc.h>
#include <asm/intersil.h>
/* bits to set for start/run of the intersil */
#define STOP_VAL (INTERSIL_STOP | INTERSIL_INT_ENABLE | INTERSIL_24H_MODE)
#define START_VAL (INTERSIL_RUN | INTERSIL_INT_ENABLE | INTERSIL_24H_MODE)
/* does this need to be implemented? */
unsigned long sun3_gettimeoffset(void)
{
return 1;
}
/* get/set hwclock */
int sun3_hwclk(int set, struct rtc_time *t)
{
volatile struct intersil_dt *todintersil;
unsigned long flags;
todintersil = (struct intersil_dt *) &intersil_clock->counter;
local_irq_save(flags);
intersil_clock->cmd_reg = STOP_VAL;
/* set or read the clock */
if(set) {
todintersil->csec = 0;
todintersil->hour = t->tm_hour;
todintersil->minute = t->tm_min;
todintersil->second = t->tm_sec;
todintersil->month = t->tm_mon;
todintersil->day = t->tm_mday;
todintersil->year = t->tm_year - 68;
todintersil->weekday = t->tm_wday;
} else {
/* read clock */
t->tm_sec = todintersil->csec;
t->tm_hour = todintersil->hour;
t->tm_min = todintersil->minute;
t->tm_sec = todintersil->second;
t->tm_mon = todintersil->month;
t->tm_mday = todintersil->day;
t->tm_year = todintersil->year + 68;
t->tm_wday = todintersil->weekday;
}
intersil_clock->cmd_reg = START_VAL;
local_irq_restore(flags);
return 0;
}

View File

@ -0,0 +1,13 @@
#include <asm/contregs.h>
#include <asm/sun3mmu.h>
#include <asm/io.h>
void sun3_leds(unsigned char byte)
{
unsigned char dfc;
GET_DFC(dfc);
SET_DFC(FC_CONTROL);
SET_CONTROL_BYTE(AC_LEDS, byte);
SET_DFC(dfc);
}

View File

@ -0,0 +1,425 @@
/*
** Tablewalk MMU emulator
**
** by Toshiyasu Morita
**
** Started 1/16/98 @ 2:22 am
*/
#include <linux/mman.h>
#include <linux/mm.h>
#include <linux/kernel.h>
#include <linux/ptrace.h>
#include <linux/delay.h>
#include <linux/bootmem.h>
#include <linux/bitops.h>
#include <linux/module.h>
#include <asm/setup.h>
#include <asm/traps.h>
#include <asm/uaccess.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/sun3mmu.h>
#include <asm/segment.h>
#include <asm/oplib.h>
#include <asm/mmu_context.h>
#include <asm/dvma.h>
#undef DEBUG_MMU_EMU
#define DEBUG_PROM_MAPS
/*
** Defines
*/
#define CONTEXTS_NUM 8
#define SEGMAPS_PER_CONTEXT_NUM 2048
#define PAGES_PER_SEGMENT 16
#define PMEGS_NUM 256
#define PMEG_MASK 0xFF
/*
** Globals
*/
unsigned long m68k_vmalloc_end;
EXPORT_SYMBOL(m68k_vmalloc_end);
unsigned long pmeg_vaddr[PMEGS_NUM];
unsigned char pmeg_alloc[PMEGS_NUM];
unsigned char pmeg_ctx[PMEGS_NUM];
/* pointers to the mm structs for each task in each
context. 0xffffffff is a marker for kernel context */
static struct mm_struct *ctx_alloc[CONTEXTS_NUM] = {
[0] = (struct mm_struct *)0xffffffff
};
/* has this context been mmdrop'd? */
static unsigned char ctx_avail = CONTEXTS_NUM-1;
/* array of pages to be marked off for the rom when we do mem_init later */
/* 256 pages lets the rom take up to 2mb of physical ram.. I really
hope it never wants mote than that. */
unsigned long rom_pages[256];
/* Print a PTE value in symbolic form. For debugging. */
void print_pte (pte_t pte)
{
#if 0
/* Verbose version. */
unsigned long val = pte_val (pte);
printk (" pte=%lx [addr=%lx",
val, (val & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT);
if (val & SUN3_PAGE_VALID) printk (" valid");
if (val & SUN3_PAGE_WRITEABLE) printk (" write");
if (val & SUN3_PAGE_SYSTEM) printk (" sys");
if (val & SUN3_PAGE_NOCACHE) printk (" nocache");
if (val & SUN3_PAGE_ACCESSED) printk (" accessed");
if (val & SUN3_PAGE_MODIFIED) printk (" modified");
switch (val & SUN3_PAGE_TYPE_MASK) {
case SUN3_PAGE_TYPE_MEMORY: printk (" memory"); break;
case SUN3_PAGE_TYPE_IO: printk (" io"); break;
case SUN3_PAGE_TYPE_VME16: printk (" vme16"); break;
case SUN3_PAGE_TYPE_VME32: printk (" vme32"); break;
}
printk ("]\n");
#else
/* Terse version. More likely to fit on a line. */
unsigned long val = pte_val (pte);
char flags[7], *type;
flags[0] = (val & SUN3_PAGE_VALID) ? 'v' : '-';
flags[1] = (val & SUN3_PAGE_WRITEABLE) ? 'w' : '-';
flags[2] = (val & SUN3_PAGE_SYSTEM) ? 's' : '-';
flags[3] = (val & SUN3_PAGE_NOCACHE) ? 'x' : '-';
flags[4] = (val & SUN3_PAGE_ACCESSED) ? 'a' : '-';
flags[5] = (val & SUN3_PAGE_MODIFIED) ? 'm' : '-';
flags[6] = '\0';
switch (val & SUN3_PAGE_TYPE_MASK) {
case SUN3_PAGE_TYPE_MEMORY: type = "memory"; break;
case SUN3_PAGE_TYPE_IO: type = "io" ; break;
case SUN3_PAGE_TYPE_VME16: type = "vme16" ; break;
case SUN3_PAGE_TYPE_VME32: type = "vme32" ; break;
default: type = "unknown?"; break;
}
printk (" pte=%08lx [%07lx %s %s]\n",
val, (val & SUN3_PAGE_PGNUM_MASK) << PAGE_SHIFT, flags, type);
#endif
}
/* Print the PTE value for a given virtual address. For debugging. */
void print_pte_vaddr (unsigned long vaddr)
{
printk (" vaddr=%lx [%02lx]", vaddr, sun3_get_segmap (vaddr));
print_pte (__pte (sun3_get_pte (vaddr)));
}
/*
* Initialise the MMU emulator.
*/
void mmu_emu_init(unsigned long bootmem_end)
{
unsigned long seg, num;
int i,j;
memset(rom_pages, 0, sizeof(rom_pages));
memset(pmeg_vaddr, 0, sizeof(pmeg_vaddr));
memset(pmeg_alloc, 0, sizeof(pmeg_alloc));
memset(pmeg_ctx, 0, sizeof(pmeg_ctx));
/* pmeg align the end of bootmem, adding another pmeg,
* later bootmem allocations will likely need it */
bootmem_end = (bootmem_end + (2 * SUN3_PMEG_SIZE)) & ~SUN3_PMEG_MASK;
/* mark all of the pmegs used thus far as reserved */
for (i=0; i < __pa(bootmem_end) / SUN3_PMEG_SIZE ; ++i)
pmeg_alloc[i] = 2;
/* I'm thinking that most of the top pmeg's are going to be
used for something, and we probably shouldn't risk it */
for(num = 0xf0; num <= 0xff; num++)
pmeg_alloc[num] = 2;
/* liberate all existing mappings in the rest of kernel space */
for(seg = bootmem_end; seg < 0x0f800000; seg += SUN3_PMEG_SIZE) {
i = sun3_get_segmap(seg);
if(!pmeg_alloc[i]) {
#ifdef DEBUG_MMU_EMU
printk("freed: ");
print_pte_vaddr (seg);
#endif
sun3_put_segmap(seg, SUN3_INVALID_PMEG);
}
}
j = 0;
for (num=0, seg=0x0F800000; seg<0x10000000; seg+=16*PAGE_SIZE) {
if (sun3_get_segmap (seg) != SUN3_INVALID_PMEG) {
#ifdef DEBUG_PROM_MAPS
for(i = 0; i < 16; i++) {
printk ("mapped:");
print_pte_vaddr (seg + (i*PAGE_SIZE));
break;
}
#endif
// the lowest mapping here is the end of our
// vmalloc region
if (!m68k_vmalloc_end)
m68k_vmalloc_end = seg;
// mark the segmap alloc'd, and reserve any
// of the first 0xbff pages the hardware is
// already using... does any sun3 support > 24mb?
pmeg_alloc[sun3_get_segmap(seg)] = 2;
}
}
dvma_init();
/* blank everything below the kernel, and we've got the base
mapping to start all the contexts off with... */
for(seg = 0; seg < PAGE_OFFSET; seg += SUN3_PMEG_SIZE)
sun3_put_segmap(seg, SUN3_INVALID_PMEG);
set_fs(MAKE_MM_SEG(3));
for(seg = 0; seg < 0x10000000; seg += SUN3_PMEG_SIZE) {
i = sun3_get_segmap(seg);
for(j = 1; j < CONTEXTS_NUM; j++)
(*(romvec->pv_setctxt))(j, (void *)seg, i);
}
set_fs(KERNEL_DS);
}
/* erase the mappings for a dead context. Uses the pg_dir for hints
as the pmeg tables proved somewhat unreliable, and unmapping all of
TASK_SIZE was much slower and no more stable. */
/* todo: find a better way to keep track of the pmegs used by a
context for when they're cleared */
void clear_context(unsigned long context)
{
unsigned char oldctx;
unsigned long i;
if(context) {
if(!ctx_alloc[context])
panic("clear_context: context not allocated\n");
ctx_alloc[context]->context = SUN3_INVALID_CONTEXT;
ctx_alloc[context] = (struct mm_struct *)0;
ctx_avail++;
}
oldctx = sun3_get_context();
sun3_put_context(context);
for(i = 0; i < SUN3_INVALID_PMEG; i++) {
if((pmeg_ctx[i] == context) && (pmeg_alloc[i] == 1)) {
sun3_put_segmap(pmeg_vaddr[i], SUN3_INVALID_PMEG);
pmeg_ctx[i] = 0;
pmeg_alloc[i] = 0;
pmeg_vaddr[i] = 0;
}
}
sun3_put_context(oldctx);
}
/* gets an empty context. if full, kills the next context listed to
die first */
/* This context invalidation scheme is, well, totally arbitrary, I'm
sure it could be much more intelligent... but it gets the job done
for now without much overhead in making it's decision. */
/* todo: come up with optimized scheme for flushing contexts */
unsigned long get_free_context(struct mm_struct *mm)
{
unsigned long new = 1;
static unsigned char next_to_die = 1;
if(!ctx_avail) {
/* kill someone to get our context */
new = next_to_die;
clear_context(new);
next_to_die = (next_to_die + 1) & 0x7;
if(!next_to_die)
next_to_die++;
} else {
while(new < CONTEXTS_NUM) {
if(ctx_alloc[new])
new++;
else
break;
}
// check to make sure one was really free...
if(new == CONTEXTS_NUM)
panic("get_free_context: failed to find free context");
}
ctx_alloc[new] = mm;
ctx_avail--;
return new;
}
/*
* Dynamically select a `spare' PMEG and use it to map virtual `vaddr' in
* `context'. Maintain internal PMEG management structures. This doesn't
* actually map the physical address, but does clear the old mappings.
*/
//todo: better allocation scheme? but is extra complexity worthwhile?
//todo: only clear old entries if necessary? how to tell?
inline void mmu_emu_map_pmeg (int context, int vaddr)
{
static unsigned char curr_pmeg = 128;
int i;
/* Round address to PMEG boundary. */
vaddr &= ~SUN3_PMEG_MASK;
/* Find a spare one. */
while (pmeg_alloc[curr_pmeg] == 2)
++curr_pmeg;
#ifdef DEBUG_MMU_EMU
printk("mmu_emu_map_pmeg: pmeg %x to context %d vaddr %x\n",
curr_pmeg, context, vaddr);
#endif
/* Invalidate old mapping for the pmeg, if any */
if (pmeg_alloc[curr_pmeg] == 1) {
sun3_put_context(pmeg_ctx[curr_pmeg]);
sun3_put_segmap (pmeg_vaddr[curr_pmeg], SUN3_INVALID_PMEG);
sun3_put_context(context);
}
/* Update PMEG management structures. */
// don't take pmeg's away from the kernel...
if(vaddr >= PAGE_OFFSET) {
/* map kernel pmegs into all contexts */
unsigned char i;
for(i = 0; i < CONTEXTS_NUM; i++) {
sun3_put_context(i);
sun3_put_segmap (vaddr, curr_pmeg);
}
sun3_put_context(context);
pmeg_alloc[curr_pmeg] = 2;
pmeg_ctx[curr_pmeg] = 0;
}
else {
pmeg_alloc[curr_pmeg] = 1;
pmeg_ctx[curr_pmeg] = context;
sun3_put_segmap (vaddr, curr_pmeg);
}
pmeg_vaddr[curr_pmeg] = vaddr;
/* Set hardware mapping and clear the old PTE entries. */
for (i=0; i<SUN3_PMEG_SIZE; i+=SUN3_PTE_SIZE)
sun3_put_pte (vaddr + i, SUN3_PAGE_SYSTEM);
/* Consider a different one next time. */
++curr_pmeg;
}
/*
* Handle a pagefault at virtual address `vaddr'; check if there should be a
* page there (specifically, whether the software pagetables indicate that
* there is). This is necessary due to the limited size of the second-level
* Sun3 hardware pagetables (256 groups of 16 pages). If there should be a
* mapping present, we select a `spare' PMEG and use it to create a mapping.
* `read_flag' is nonzero for a read fault; zero for a write. Returns nonzero
* if we successfully handled the fault.
*/
//todo: should we bump minor pagefault counter? if so, here or in caller?
//todo: possibly inline this into bus_error030 in <asm/buserror.h> ?
// kernel_fault is set when a kernel page couldn't be demand mapped,
// and forces another try using the kernel page table. basically a
// hack so that vmalloc would work correctly.
int mmu_emu_handle_fault (unsigned long vaddr, int read_flag, int kernel_fault)
{
unsigned long segment, offset;
unsigned char context;
pte_t *pte;
pgd_t * crp;
if(current->mm == NULL) {
crp = swapper_pg_dir;
context = 0;
} else {
context = current->mm->context;
if(kernel_fault)
crp = swapper_pg_dir;
else
crp = current->mm->pgd;
}
#ifdef DEBUG_MMU_EMU
printk ("mmu_emu_handle_fault: vaddr=%lx type=%s crp=%p\n",
vaddr, read_flag ? "read" : "write", crp);
#endif
segment = (vaddr >> SUN3_PMEG_SIZE_BITS) & 0x7FF;
offset = (vaddr >> SUN3_PTE_SIZE_BITS) & 0xF;
#ifdef DEBUG_MMU_EMU
printk ("mmu_emu_handle_fault: segment=%lx offset=%lx\n", segment, offset);
#endif
pte = (pte_t *) pgd_val (*(crp + segment));
//todo: next line should check for valid pmd properly.
if (!pte) {
// printk ("mmu_emu_handle_fault: invalid pmd\n");
return 0;
}
pte = (pte_t *) __va ((unsigned long)(pte + offset));
/* Make sure this is a valid page */
if (!(pte_val (*pte) & SUN3_PAGE_VALID))
return 0;
/* Make sure there's a pmeg allocated for the page */
if (sun3_get_segmap (vaddr&~SUN3_PMEG_MASK) == SUN3_INVALID_PMEG)
mmu_emu_map_pmeg (context, vaddr);
/* Write the pte value to hardware MMU */
sun3_put_pte (vaddr&PAGE_MASK, pte_val (*pte));
/* Update software copy of the pte value */
// I'm not sure this is necessary. If this is required, we ought to simply
// copy this out when we reuse the PMEG or at some other convenient time.
// Doing it here is fairly meaningless, anyway, as we only know about the
// first access to a given page. --m
if (!read_flag) {
if (pte_val (*pte) & SUN3_PAGE_WRITEABLE)
pte_val (*pte) |= (SUN3_PAGE_ACCESSED
| SUN3_PAGE_MODIFIED);
else
return 0; /* Write-protect error. */
} else
pte_val (*pte) |= SUN3_PAGE_ACCESSED;
#ifdef DEBUG_MMU_EMU
printk ("seg:%d crp:%p ->", get_fs().seg, crp);
print_pte_vaddr (vaddr);
printk ("\n");
#endif
return 1;
}

View File

@ -0,0 +1,6 @@
# Makefile for the Sun Boot PROM interface library under
# Linux.
#
obj-y := init.o console.o printf.o misc.o
#bootstr.o init.o misc.o segment.o console.o printf.o

View File

@ -0,0 +1,169 @@
/*
* console.c: Routines that deal with sending and receiving IO
* to/from the current console device using the PROM.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <linux/string.h>
/* Non blocking get character from console input device, returns -1
* if no input was taken. This can be used for polling.
*/
int
prom_nbgetchar(void)
{
int i = -1;
unsigned long flags;
local_irq_save(flags);
i = (*(romvec->pv_nbgetchar))();
local_irq_restore(flags);
return i; /* Ugh, we could spin forever on unsupported proms ;( */
}
/* Non blocking put character to console device, returns -1 if
* unsuccessful.
*/
int
prom_nbputchar(char c)
{
unsigned long flags;
int i = -1;
local_irq_save(flags);
i = (*(romvec->pv_nbputchar))(c);
local_irq_restore(flags);
return i; /* Ugh, we could spin forever on unsupported proms ;( */
}
/* Blocking version of get character routine above. */
char
prom_getchar(void)
{
int character;
while((character = prom_nbgetchar()) == -1) ;
return (char) character;
}
/* Blocking version of put character routine above. */
void
prom_putchar(char c)
{
while(prom_nbputchar(c) == -1) ;
return;
}
/* Query for input device type */
#if 0
enum prom_input_device
prom_query_input_device()
{
unsigned long flags;
int st_p;
char propb[64];
char *p;
switch(prom_vers) {
case PROM_V0:
case PROM_V2:
default:
switch(*romvec->pv_stdin) {
case PROMDEV_KBD: return PROMDEV_IKBD;
case PROMDEV_TTYA: return PROMDEV_ITTYA;
case PROMDEV_TTYB: return PROMDEV_ITTYB;
default:
return PROMDEV_I_UNK;
};
case PROM_V3:
case PROM_P1275:
local_irq_save(flags);
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdin);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
"r" (&current_set[smp_processor_id()]) :
"memory");
local_irq_restore(flags);
if(prom_node_has_property(st_p, "keyboard"))
return PROMDEV_IKBD;
prom_getproperty(st_p, "device_type", propb, sizeof(propb));
if(strncmp(propb, "serial", sizeof("serial")))
return PROMDEV_I_UNK;
prom_getproperty(prom_root_node, "stdin-path", propb, sizeof(propb));
p = propb;
while(*p) p++; p -= 2;
if(p[0] == ':') {
if(p[1] == 'a')
return PROMDEV_ITTYA;
else if(p[1] == 'b')
return PROMDEV_ITTYB;
}
return PROMDEV_I_UNK;
};
}
#endif
/* Query for output device type */
#if 0
enum prom_output_device
prom_query_output_device()
{
unsigned long flags;
int st_p;
char propb[64];
char *p;
int propl;
switch(prom_vers) {
case PROM_V0:
switch(*romvec->pv_stdin) {
case PROMDEV_SCREEN: return PROMDEV_OSCREEN;
case PROMDEV_TTYA: return PROMDEV_OTTYA;
case PROMDEV_TTYB: return PROMDEV_OTTYB;
};
break;
case PROM_V2:
case PROM_V3:
case PROM_P1275:
local_irq_save(flags);
st_p = (*romvec->pv_v2devops.v2_inst2pkg)(*romvec->pv_v2bootargs.fd_stdout);
__asm__ __volatile__("ld [%0], %%g6\n\t" : :
"r" (&current_set[smp_processor_id()]) :
"memory");
local_irq_restore(flags);
propl = prom_getproperty(st_p, "device_type", propb, sizeof(propb));
if (propl >= 0 && propl == sizeof("display") &&
strncmp("display", propb, sizeof("display")) == 0)
{
return PROMDEV_OSCREEN;
}
if(prom_vers == PROM_V3) {
if(strncmp("serial", propb, sizeof("serial")))
return PROMDEV_O_UNK;
prom_getproperty(prom_root_node, "stdout-path", propb, sizeof(propb));
p = propb;
while(*p) p++; p -= 2;
if(p[0]==':') {
if(p[1] == 'a')
return PROMDEV_OTTYA;
else if(p[1] == 'b')
return PROMDEV_OTTYB;
}
return PROMDEV_O_UNK;
} else {
/* This works on SS-2 (an early OpenFirmware) still. */
switch(*romvec->pv_stdin) {
case PROMDEV_TTYA: return PROMDEV_OTTYA;
case PROMDEV_TTYB: return PROMDEV_OTTYB;
};
}
break;
};
return PROMDEV_O_UNK;
}
#endif

View File

@ -0,0 +1,79 @@
/*
* init.c: Initialize internal variables used by the PROM
* library functions.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
struct linux_romvec *romvec;
enum prom_major_version prom_vers;
unsigned int prom_rev, prom_prev;
/* The root node of the prom device tree. */
int prom_root_node;
/* Pointer to the device tree operations structure. */
struct linux_nodeops *prom_nodeops;
/* You must call prom_init() before you attempt to use any of the
* routines in the prom library. It returns 0 on success, 1 on
* failure. It gets passed the pointer to the PROM vector.
*/
extern void prom_meminit(void);
extern void prom_ranges_init(void);
void __init prom_init(struct linux_romvec *rp)
{
romvec = rp;
#ifndef CONFIG_SUN3
switch(romvec->pv_romvers) {
case 0:
prom_vers = PROM_V0;
break;
case 2:
prom_vers = PROM_V2;
break;
case 3:
prom_vers = PROM_V3;
break;
case 4:
prom_vers = PROM_P1275;
prom_printf("PROMLIB: Sun IEEE Prom not supported yet\n");
prom_halt();
break;
default:
prom_printf("PROMLIB: Bad PROM version %d\n",
romvec->pv_romvers);
prom_halt();
break;
};
prom_rev = romvec->pv_plugin_revision;
prom_prev = romvec->pv_printrev;
prom_nodeops = romvec->pv_nodeops;
prom_root_node = prom_getsibling(0);
if((prom_root_node == 0) || (prom_root_node == -1))
prom_halt();
if((((unsigned long) prom_nodeops) == 0) ||
(((unsigned long) prom_nodeops) == -1))
prom_halt();
prom_meminit();
prom_ranges_init();
#endif
// printk("PROMLIB: Sun Boot Prom Version %d Revision %d\n",
// romvec->pv_romvers, prom_rev);
/* Initialization successful. */
return;
}

View File

@ -0,0 +1,94 @@
/*
* misc.c: Miscellaneous prom functions that don't belong
* anywhere else.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <asm/sun3-head.h>
#include <asm/idprom.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#include <asm/movs.h>
/* Reset and reboot the machine with the command 'bcommand'. */
void
prom_reboot(char *bcommand)
{
unsigned long flags;
local_irq_save(flags);
(*(romvec->pv_reboot))(bcommand);
local_irq_restore(flags);
}
/* Drop into the prom, with the chance to continue with the 'go'
* prom command.
*/
void
prom_cmdline(void)
{
}
/* Drop into the prom, but completely terminate the program.
* No chance of continuing.
*/
void
prom_halt(void)
{
unsigned long flags;
again:
local_irq_save(flags);
(*(romvec->pv_halt))();
local_irq_restore(flags);
goto again; /* PROM is out to get me -DaveM */
}
typedef void (*sfunc_t)(void);
/* Get the idprom and stuff it into buffer 'idbuf'. Returns the
* format type. 'num_bytes' is the number of bytes that your idbuf
* has space for. Returns 0xff on error.
*/
unsigned char
prom_get_idprom(char *idbuf, int num_bytes)
{
int i, oldsfc;
GET_SFC(oldsfc);
SET_SFC(FC_CONTROL);
for(i=0;i<num_bytes; i++)
{
/* There is a problem with the GET_CONTROL_BYTE
macro; defining the extra variable
gets around it.
*/
int c;
GET_CONTROL_BYTE(SUN3_IDPROM_BASE + i, c);
idbuf[i] = c;
}
SET_SFC(oldsfc);
return idbuf[0];
}
/* Get the major prom version number. */
int
prom_version(void)
{
return romvec->pv_romvers;
}
/* Get the prom plugin-revision. */
int
prom_getrev(void)
{
return prom_rev;
}
/* Get the prom firmware print revision. */
int
prom_getprev(void)
{
return prom_prev;
}

View File

@ -0,0 +1,55 @@
/*
* printf.c: Internal prom library printf facility.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
/* This routine is internal to the prom library, no one else should know
* about or use it! It's simple and smelly anyway....
*/
#include <linux/kernel.h>
#include <asm/openprom.h>
#include <asm/oplib.h>
#ifdef CONFIG_KGDB
extern int kgdb_initialized;
#endif
static char ppbuf[1024];
void
prom_printf(char *fmt, ...)
{
va_list args;
char ch, *bptr;
int i;
va_start(args, fmt);
#ifdef CONFIG_KGDB
ppbuf[0] = 'O';
i = vsprintf(ppbuf + 1, fmt, args) + 1;
#else
i = vsprintf(ppbuf, fmt, args);
#endif
bptr = ppbuf;
#ifdef CONFIG_KGDB
if (kgdb_initialized) {
printk("kgdb_initialized = %d\n", kgdb_initialized);
putpacket(bptr, 1);
} else
#else
while((ch = *(bptr++)) != 0) {
if(ch == '\n')
prom_putchar('\r');
prom_putchar(ch);
}
#endif
va_end(args);
return;
}

View File

@ -0,0 +1,381 @@
/*
* linux/arch/m68k/sun3/sun3dvma.c
*
* Copyright (C) 2000 Sam Creasey
*
* Contains common routines for sun3/sun3x DVMA management.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/gfp.h>
#include <linux/mm.h>
#include <linux/list.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/dvma.h>
#undef DVMA_DEBUG
#ifdef CONFIG_SUN3X
extern void dvma_unmap_iommu(unsigned long baddr, int len);
#else
static inline void dvma_unmap_iommu(unsigned long a, int b)
{
}
#endif
#ifdef CONFIG_SUN3
extern void sun3_dvma_init(void);
#endif
static unsigned long iommu_use[IOMMU_TOTAL_ENTRIES];
#define dvma_index(baddr) ((baddr - DVMA_START) >> DVMA_PAGE_SHIFT)
#define dvma_entry_use(baddr) (iommu_use[dvma_index(baddr)])
struct hole {
unsigned long start;
unsigned long end;
unsigned long size;
struct list_head list;
};
static struct list_head hole_list;
static struct list_head hole_cache;
static struct hole initholes[64];
#ifdef DVMA_DEBUG
static unsigned long dvma_allocs;
static unsigned long dvma_frees;
static unsigned long long dvma_alloc_bytes;
static unsigned long long dvma_free_bytes;
static void print_use(void)
{
int i;
int j = 0;
printk("dvma entry usage:\n");
for(i = 0; i < IOMMU_TOTAL_ENTRIES; i++) {
if(!iommu_use[i])
continue;
j++;
printk("dvma entry: %08lx len %08lx\n",
( i << DVMA_PAGE_SHIFT) + DVMA_START,
iommu_use[i]);
}
printk("%d entries in use total\n", j);
printk("allocation/free calls: %lu/%lu\n", dvma_allocs, dvma_frees);
printk("allocation/free bytes: %Lx/%Lx\n", dvma_alloc_bytes,
dvma_free_bytes);
}
static void print_holes(struct list_head *holes)
{
struct list_head *cur;
struct hole *hole;
printk("listing dvma holes\n");
list_for_each(cur, holes) {
hole = list_entry(cur, struct hole, list);
if((hole->start == 0) && (hole->end == 0) && (hole->size == 0))
continue;
printk("hole: start %08lx end %08lx size %08lx\n", hole->start, hole->end, hole->size);
}
printk("end of hole listing...\n");
}
#endif /* DVMA_DEBUG */
static inline int refill(void)
{
struct hole *hole;
struct hole *prev = NULL;
struct list_head *cur;
int ret = 0;
list_for_each(cur, &hole_list) {
hole = list_entry(cur, struct hole, list);
if(!prev) {
prev = hole;
continue;
}
if(hole->end == prev->start) {
hole->size += prev->size;
hole->end = prev->end;
list_move(&(prev->list), &hole_cache);
ret++;
}
}
return ret;
}
static inline struct hole *rmcache(void)
{
struct hole *ret;
if(list_empty(&hole_cache)) {
if(!refill()) {
printk("out of dvma hole cache!\n");
BUG();
}
}
ret = list_entry(hole_cache.next, struct hole, list);
list_del(&(ret->list));
return ret;
}
static inline unsigned long get_baddr(int len, unsigned long align)
{
struct list_head *cur;
struct hole *hole;
if(list_empty(&hole_list)) {
#ifdef DVMA_DEBUG
printk("out of dvma holes! (printing hole cache)\n");
print_holes(&hole_cache);
print_use();
#endif
BUG();
}
list_for_each(cur, &hole_list) {
unsigned long newlen;
hole = list_entry(cur, struct hole, list);
if(align > DVMA_PAGE_SIZE)
newlen = len + ((hole->end - len) & (align-1));
else
newlen = len;
if(hole->size > newlen) {
hole->end -= newlen;
hole->size -= newlen;
dvma_entry_use(hole->end) = newlen;
#ifdef DVMA_DEBUG
dvma_allocs++;
dvma_alloc_bytes += newlen;
#endif
return hole->end;
} else if(hole->size == newlen) {
list_move(&(hole->list), &hole_cache);
dvma_entry_use(hole->start) = newlen;
#ifdef DVMA_DEBUG
dvma_allocs++;
dvma_alloc_bytes += newlen;
#endif
return hole->start;
}
}
printk("unable to find dvma hole!\n");
BUG();
return 0;
}
static inline int free_baddr(unsigned long baddr)
{
unsigned long len;
struct hole *hole;
struct list_head *cur;
unsigned long orig_baddr;
orig_baddr = baddr;
len = dvma_entry_use(baddr);
dvma_entry_use(baddr) = 0;
baddr &= DVMA_PAGE_MASK;
dvma_unmap_iommu(baddr, len);
#ifdef DVMA_DEBUG
dvma_frees++;
dvma_free_bytes += len;
#endif
list_for_each(cur, &hole_list) {
hole = list_entry(cur, struct hole, list);
if(hole->end == baddr) {
hole->end += len;
hole->size += len;
return 0;
} else if(hole->start == (baddr + len)) {
hole->start = baddr;
hole->size += len;
return 0;
}
}
hole = rmcache();
hole->start = baddr;
hole->end = baddr + len;
hole->size = len;
// list_add_tail(&(hole->list), cur);
list_add(&(hole->list), cur);
return 0;
}
void dvma_init(void)
{
struct hole *hole;
int i;
INIT_LIST_HEAD(&hole_list);
INIT_LIST_HEAD(&hole_cache);
/* prepare the hole cache */
for(i = 0; i < 64; i++)
list_add(&(initholes[i].list), &hole_cache);
hole = rmcache();
hole->start = DVMA_START;
hole->end = DVMA_END;
hole->size = DVMA_SIZE;
list_add(&(hole->list), &hole_list);
memset(iommu_use, 0, sizeof(iommu_use));
dvma_unmap_iommu(DVMA_START, DVMA_SIZE);
#ifdef CONFIG_SUN3
sun3_dvma_init();
#endif
}
inline unsigned long dvma_map_align(unsigned long kaddr, int len, int align)
{
unsigned long baddr;
unsigned long off;
if(!len)
len = 0x800;
if(!kaddr || !len) {
// printk("error: kaddr %lx len %x\n", kaddr, len);
// *(int *)4 = 0;
return 0;
}
#ifdef DEBUG
printk("dvma_map request %08lx bytes from %08lx\n",
len, kaddr);
#endif
off = kaddr & ~DVMA_PAGE_MASK;
kaddr &= PAGE_MASK;
len += off;
len = ((len + (DVMA_PAGE_SIZE-1)) & DVMA_PAGE_MASK);
if(align == 0)
align = DVMA_PAGE_SIZE;
else
align = ((align + (DVMA_PAGE_SIZE-1)) & DVMA_PAGE_MASK);
baddr = get_baddr(len, align);
// printk("using baddr %lx\n", baddr);
if(!dvma_map_iommu(kaddr, baddr, len))
return (baddr + off);
printk("dvma_map failed kaddr %lx baddr %lx len %x\n", kaddr, baddr, len);
BUG();
return 0;
}
EXPORT_SYMBOL(dvma_map_align);
void dvma_unmap(void *baddr)
{
unsigned long addr;
addr = (unsigned long)baddr;
/* check if this is a vme mapping */
if(!(addr & 0x00f00000))
addr |= 0xf00000;
free_baddr(addr);
return;
}
EXPORT_SYMBOL(dvma_unmap);
void *dvma_malloc_align(unsigned long len, unsigned long align)
{
unsigned long kaddr;
unsigned long baddr;
unsigned long vaddr;
if(!len)
return NULL;
#ifdef DEBUG
printk("dvma_malloc request %lx bytes\n", len);
#endif
len = ((len + (DVMA_PAGE_SIZE-1)) & DVMA_PAGE_MASK);
if((kaddr = __get_free_pages(GFP_ATOMIC, get_order(len))) == 0)
return NULL;
if((baddr = (unsigned long)dvma_map_align(kaddr, len, align)) == 0) {
free_pages(kaddr, get_order(len));
return NULL;
}
vaddr = dvma_btov(baddr);
if(dvma_map_cpu(kaddr, vaddr, len) < 0) {
dvma_unmap((void *)baddr);
free_pages(kaddr, get_order(len));
return NULL;
}
#ifdef DEBUG
printk("mapped %08lx bytes %08lx kern -> %08lx bus\n",
len, kaddr, baddr);
#endif
return (void *)vaddr;
}
EXPORT_SYMBOL(dvma_malloc_align);
void dvma_free(void *vaddr)
{
return;
}
EXPORT_SYMBOL(dvma_free);

View File

@ -0,0 +1,120 @@
/*
* linux/arch/m68k/sun3/sun3ints.c -- Sun-3(x) Linux interrupt handling code
*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file COPYING in the main directory of this archive
* for more details.
*/
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/kernel_stat.h>
#include <linux/interrupt.h>
#include <asm/segment.h>
#include <asm/intersil.h>
#include <asm/oplib.h>
#include <asm/sun3ints.h>
#include <asm/irq_regs.h>
#include <linux/seq_file.h>
extern void sun3_leds (unsigned char);
void sun3_disable_interrupts(void)
{
sun3_disable_irq(0);
}
void sun3_enable_interrupts(void)
{
sun3_enable_irq(0);
}
static int led_pattern[8] = {
~(0x80), ~(0x01),
~(0x40), ~(0x02),
~(0x20), ~(0x04),
~(0x10), ~(0x08)
};
volatile unsigned char* sun3_intreg;
void sun3_enable_irq(unsigned int irq)
{
*sun3_intreg |= (1 << irq);
}
void sun3_disable_irq(unsigned int irq)
{
*sun3_intreg &= ~(1 << irq);
}
static irqreturn_t sun3_int7(int irq, void *dev_id)
{
unsigned int cnt;
cnt = kstat_irqs_cpu(irq, 0);
if (!(cnt % 2000))
sun3_leds(led_pattern[cnt % 16000 / 2000]);
return IRQ_HANDLED;
}
static irqreturn_t sun3_int5(int irq, void *dev_id)
{
unsigned int cnt;
#ifdef CONFIG_SUN3
intersil_clear();
#endif
#ifdef CONFIG_SUN3
intersil_clear();
#endif
xtime_update(1);
update_process_times(user_mode(get_irq_regs()));
cnt = kstat_irqs_cpu(irq, 0);
if (!(cnt % 20))
sun3_leds(led_pattern[cnt % 160 / 20]);
return IRQ_HANDLED;
}
static irqreturn_t sun3_vec255(int irq, void *dev_id)
{
// intersil_clear();
return IRQ_HANDLED;
}
static void sun3_irq_enable(struct irq_data *data)
{
sun3_enable_irq(data->irq);
};
static void sun3_irq_disable(struct irq_data *data)
{
sun3_disable_irq(data->irq);
};
static struct irq_chip sun3_irq_chip = {
.name = "sun3",
.irq_startup = m68k_irq_startup,
.irq_shutdown = m68k_irq_shutdown,
.irq_enable = sun3_irq_enable,
.irq_disable = sun3_irq_disable,
.irq_mask = sun3_irq_disable,
.irq_unmask = sun3_irq_enable,
};
void __init sun3_init_IRQ(void)
{
*sun3_intreg = 1;
m68k_setup_irq_controller(&sun3_irq_chip, handle_level_irq, IRQ_AUTO_1,
7);
m68k_setup_user_interrupt(VEC_USER, 128);
if (request_irq(IRQ_AUTO_5, sun3_int5, 0, "int5", NULL))
pr_err("Couldn't register %s interrupt\n", "int5");
if (request_irq(IRQ_AUTO_7, sun3_int7, 0, "int7", NULL))
pr_err("Couldn't register %s interrupt\n", "int7");
if (request_irq(IRQ_USER+127, sun3_vec255, 0, "vec255", NULL))
pr_err("Couldn't register %s interrupt\n", "vec255");
}