⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 apus_setup.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/arch/ppc/kernel/apus_setup.c * *  Copyright (C) 1998, 1999  Jesper Skov * *  Basically what is needed to replace functionality found in *  arch/m68k allowing Amiga drivers to work under APUS. *  Bits of code and/or ideas from arch/m68k and arch/ppc files. * * TODO: *  This file needs a *really* good cleanup. Restructure and optimize. *  Make sure it can be compiled for non-APUS configs. Begin to move *  Amiga specific stuff into mach/amiga. */#include <linux/config.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/kd.h>#include <linux/init.h>#include <linux/hdreg.h>#include <linux/blk.h>#include <linux/pci.h>#ifdef CONFIG_APUS#include <asm/logging.h>#endif/* Needs INITSERIAL call in head.S! */#undef APUS_DEBUG#include <linux/ide.h>#define T_CHAR          (0x0000)        /* char:  don't touch  */#define T_SHORT         (0x4000)        /* short: 12 -> 21     */#define T_INT           (0x8000)        /* int:   1234 -> 4321 */#define T_TEXT          (0xc000)        /* text:  12 -> 21     */#define T_MASK_TYPE     (0xc000)#define T_MASK_COUNT    (0x3fff)#define D_CHAR(cnt)     (T_CHAR  | (cnt))#define D_SHORT(cnt)    (T_SHORT | (cnt))#define D_INT(cnt)      (T_INT   | (cnt))#define D_TEXT(cnt)     (T_TEXT  | (cnt))static u_short driveid_types[] = {        D_SHORT(10),    /* config - vendor2 */        D_TEXT(20),     /* serial_no */        D_SHORT(3),     /* buf_type, buf_size - ecc_bytes */        D_TEXT(48),     /* fw_rev - model */        D_CHAR(2),      /* max_multsect - vendor3 */        D_SHORT(1),     /* dword_io */        D_CHAR(2),      /* vendor4 - capability */        D_SHORT(1),     /* reserved50 */        D_CHAR(4),      /* vendor5 - tDMA */        D_SHORT(4),     /* field_valid - cur_sectors */        D_INT(1),       /* cur_capacity */        D_CHAR(2),      /* multsect - multsect_valid */        D_INT(1),       /* lba_capacity */        D_SHORT(194)    /* dma_1word - reservedyy */};#define num_driveid_types       (sizeof(driveid_types)/sizeof(*driveid_types))#include <asm/bootinfo.h>#include <asm/setup.h>#include <asm/amigahw.h>#include <asm/amigaints.h>#include <asm/amigappc.h>#include <asm/pgtable.h>#include <asm/io.h>#include <asm/dma.h>#include <asm/machdep.h>#include <asm/init.h>#include "local_irq.h"unsigned long m68k_machtype __apusdata;char debug_device[6] __apusdata = "";extern void amiga_init_IRQ(void);void (*mach_sched_init) (void (*handler)(int, void *, struct pt_regs *)) __initdata = NULL;/* machine dependent keyboard functions */int (*mach_keyb_init) (void) __initdata = NULL;int (*mach_kbdrate) (struct kbd_repeat *) __apusdata = NULL;void (*mach_kbd_leds) (unsigned int) __apusdata = NULL;/* machine dependent irq functions */void (*mach_init_IRQ) (void) __initdata = NULL;void (*(*mach_default_handler)[]) (int, void *, struct pt_regs *) __apusdata = NULL;void (*mach_get_model) (char *model) __apusdata = NULL;int (*mach_get_hardware_list) (char *buffer) __apusdata = NULL;int (*mach_get_irq_list) (char *) __apusdata = NULL;void (*mach_process_int) (int, struct pt_regs *) __apusdata = NULL;/* machine dependent timer functions */unsigned long (*mach_gettimeoffset) (void) __apusdata;void (*mach_gettod) (int*, int*, int*, int*, int*, int*) __apusdata;int (*mach_hwclk) (int, struct hwclk_time*) __apusdata = NULL;int (*mach_set_clock_mmss) (unsigned long) __apusdata = NULL;void (*mach_reset)( void ) __apusdata;long mach_max_dma_address __apusdata = 0x00ffffff; /* default set to the lower 16MB */#if defined(CONFIG_AMIGA_FLOPPY)void (*mach_floppy_setup) (char *, int *) __initdata = NULL;void (*mach_floppy_eject) (void) __apusdata = NULL;#endif#ifdef CONFIG_HEARTBEATvoid (*mach_heartbeat) (int) __apusdata = NULL;extern void apus_heartbeat (void);#endifextern unsigned long amiga_model;extern unsigned decrementer_count;/* count value for 1e6/HZ microseconds */extern unsigned count_period_num; /* 1 decrementer count equals */extern unsigned count_period_den; /* count_period_num / count_period_den us */int num_memory __apusdata = 0;struct mem_info memory[NUM_MEMINFO] __apusdata;/* memory description *//* FIXME: Duplicate memory data to avoid conflicts with m68k shared code. */int m68k_realnum_memory __apusdata = 0;struct mem_info m68k_memory[NUM_MEMINFO] __apusdata;/* memory description */struct mem_info ramdisk __apusdata;extern void amiga_floppy_setup(char *, int *);extern void config_amiga(void);static int __60nsram __apusdata = 0;/* for cpuinfo */static int __bus_speed __apusdata = 0;static int __speed_test_failed __apusdata = 0;/********************************************** COMPILE PROTECTION *//* Provide some stubs that links to Amiga specific functions.  * This allows CONFIG_APUS to be removed from generic PPC files while * preventing link errors for other PPC targets. */__apusunsigned long apus_get_rtc_time(void){#ifdef CONFIG_APUS	extern unsigned long m68k_get_rtc_time(void);		return m68k_get_rtc_time ();#else	return 0;#endif}__apusint apus_set_rtc_time(unsigned long nowtime){#ifdef CONFIG_APUS	extern int m68k_set_rtc_time(unsigned long nowtime);	return m68k_set_rtc_time (nowtime);#else	return 0;#endif}/* Here some functions we don't support, but which the other ports reference */int pckbd_setkeycode(unsigned int scancode, unsigned int keycode){	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");	return 0; }int pckbd_getkeycode(unsigned int scancode) { 	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");	return 0; }int pckbd_translate(unsigned char scancode, unsigned char *keycode,		    char raw_mode) {	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");	return 0; }char pckbd_unexpected_up(unsigned char keycode){	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");	return 0;}void pckbd_leds(unsigned char leds){	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");}void pckbd_init_hw(void){	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");}unsigned char pckbd_sysrq_xlate[128];struct pci_bus * __init pci_scan_peer_bridge(int bus){	printk("Bogus call to " __FILE__ ":" __FUNCTION__ "\n");	return NULL;}/*********************************************************** SETUP *//* From arch/m68k/kernel/setup.c. */void __init apus_setup_arch(void){#ifdef CONFIG_APUS	extern char cmd_line[];	int i;	char *p, *q;	/* Let m68k-shared code know it should do the Amiga thing. */	m68k_machtype = MACH_AMIGA;	/* Parse the command line for arch-specific options.	 * For the m68k, this is currently only "debug=xxx" to enable printing	 * certain kernel messages to some machine-specific device.  */	for( p = cmd_line; p && *p; ) {	    i = 0;	    if (!strncmp( p, "debug=", 6 )) {		    strncpy( debug_device, p+6, sizeof(debug_device)-1 );		    debug_device[sizeof(debug_device)-1] = 0;		    if ((q = strchr( debug_device, ' ' ))) *q = 0;		    i = 1;	    } else if (!strncmp( p, "60nsram", 7 )) {		    APUS_WRITE (APUS_REG_WAITSTATE, 				REGWAITSTATE_SETRESET				|REGWAITSTATE_PPCR				|REGWAITSTATE_PPCW);		    __60nsram = 1;		    i = 1;	    }	    if (i) {		/* option processed, delete it */		if ((q = strchr( p, ' ' )))		    strcpy( p, q+1 );		else		    *p = 0;	    } else {		if ((p = strchr( p, ' ' ))) ++p;	    }	}	config_amiga();#if 0 /* Enable for logging - also include logging.o in Makefile rule */	{#define LOG_SIZE 4096		void* base;		/* Throw away some memory - the P5 firmare stomps on top		 * of CHIP memory during bootup.		 */		amiga_chip_alloc(0x1000);		base = amiga_chip_alloc(LOG_SIZE+sizeof(klog_data_t));		LOG_INIT(base, base+sizeof(klog_data_t), LOG_SIZE);	}#endif#endif}__apusintapus_get_cpuinfo(char *buffer){#ifdef CONFIG_APUS	extern int __map_without_bats;	extern unsigned long powerup_PCI_present;	int len;	len = sprintf(buffer, "machine\t\t: Amiga\n");	len += sprintf(buffer+len, "bus speed\t: %d%s", __bus_speed,		       (__speed_test_failed) ? " [failed]\n" : "\n");	len += sprintf(buffer+len, "using BATs\t: %s\n",		       (__map_without_bats) ? "No" : "Yes");	len += sprintf(buffer+len, "ram speed\t: %dns\n", 		       (__60nsram) ? 60 : 70);	len += sprintf(buffer+len, "PCI bridge\t: %s\n",		       (powerup_PCI_present) ? "Yes" : "No");	return len;#endif}__apusstatic void get_current_tb(unsigned long long *time){	__asm __volatile ("1:mftbu 4      \n\t"			  "  mftb  5      \n\t"			  "  mftbu 6      \n\t"			  "  cmpw  4,6    \n\t"			  "  bne   1b     \n\t"			  "  stw   4,0(%0)\n\t"			  "  stw   5,4(%0)\n\t"			  : 			  : "r" (time)			  : "r4", "r5", "r6");}__apusvoid apus_calibrate_decr(void){#ifdef CONFIG_APUS	unsigned long freq;	/* This algorithm for determining the bus speed was           contributed by Ralph Schmidt. */	unsigned long long start, stop;	int bus_speed;	int speed_test_failed = 0;	{		unsigned long loop = amiga_eclock / 10;		get_current_tb (&start);		while (loop--) {			unsigned char tmp;			tmp = ciaa.pra;		}		get_current_tb (&stop);	}	bus_speed = (((unsigned long)(stop-start))*10*4) / 1000000;	if (AMI_1200 == amiga_model)		bus_speed /= 2;	if ((bus_speed >= 47) && (bus_speed < 53)) {		bus_speed = 50;		freq = 12500000;	} else if ((bus_speed >= 57) && (bus_speed < 63)) {		bus_speed = 60;		freq = 15000000;	} else if ((bus_speed >= 63) && (bus_speed < 69)) {		bus_speed = 67;		freq = 16666667;	} else {		printk ("APUS: Unable to determine bus speed (%d). "			"Defaulting to 50MHz", bus_speed);		bus_speed = 50;		freq = 12500000;		speed_test_failed = 1;	}	/* Ease diagnostics... */	{		extern int __map_without_bats;		extern unsigned long powerup_PCI_present;		printk ("APUS: BATs=%d, BUS=%dMHz",			(__map_without_bats) ? 0 : 1,			bus_speed);		if (speed_test_failed)			printk ("[FAILED - please report]");		printk (", RAM=%dns, PCI bridge=%d\n",			(__60nsram) ? 60 : 70,			(powerup_PCI_present) ? 1 : 0);		/* print a bit more if asked politely... */		if (!(ciaa.pra & 0x40)){			extern unsigned int bat_addrs[4][3];			int b;			for (b = 0; b < 4; ++b) {				printk ("APUS: BAT%d ", b);				printk ("%08x-%08x -> %08x\n",					bat_addrs[b][0],					bat_addrs[b][1],					bat_addrs[b][2]);			}		}	}        printk("time_init: decrementer frequency = %lu.%.6lu MHz\n",	       freq/1000000, freq%1000000);	tb_ticks_per_jiffy = freq / HZ;	tb_to_us = mulhwu_scale_factor(freq, 1000000);	__bus_speed = bus_speed;	__speed_test_failed = speed_test_failed;#endif}__apusvoid arch_gettod(int *year, int *mon, int *day, int *hour,		 int *min, int *sec){#ifdef CONFIG_APUS	if (mach_gettod)		mach_gettod(year, mon, day, hour, min, sec);	else		*year = *mon = *day = *hour = *min = *sec = 0;#endif}/* for "kbd-reset" cmdline param */__initvoid kbd_reset_setup(char *str, int *ints){}/*********************************************************** FLOPPY */#if defined(CONFIG_AMIGA_FLOPPY)__init void floppy_setup(char *str, int *ints){	if (mach_floppy_setup)		mach_floppy_setup (str, ints);}__apusvoid floppy_eject(void){	if (mach_floppy_eject)		mach_floppy_eject();}#endif/*********************************************************** MEMORY */#define KMAP_MAX 32unsigned long kmap_chunks[KMAP_MAX*3] __apusdata;int kmap_chunk_count __apusdata = 0;/* From pgtable.h */__apusstatic __inline__ pte_t *my_find_pte(struct mm_struct *mm,unsigned long va){	pgd_t *dir = 0;	pmd_t *pmd = 0;	pte_t *pte = 0;	va &= PAGE_MASK;		dir = pgd_offset( mm, va );	if (dir)	{		pmd = pmd_offset(dir, va & PAGE_MASK);		if (pmd && pmd_present(*pmd))		{			pte = pte_offset(pmd, va);		}	}	return pte;}/* Again simulating an m68k/mm/kmap.c function. */__apusvoid kernel_set_cachemode( unsigned long address, unsigned long size,			   unsigned int cmode ){	unsigned long mask, flags;	switch (cmode)	{	case IOMAP_FULL_CACHING:		mask = ~(_PAGE_NO_CACHE | _PAGE_GUARDED);		flags = 0;		break;	case IOMAP_NOCACHE_SER:		mask = ~0;		flags = (_PAGE_NO_CACHE | _PAGE_GUARDED);		break;	default:		panic ("kernel_set_cachemode() doesn't support mode %d\n", 		       cmode);		break;	}		size /= PAGE_SIZE;	address &= PAGE_MASK;	while (size--)	{		pte_t *pte;		pte = my_find_pte(&init_mm, address);		if ( !pte )		{			printk("pte NULL in kernel_set_cachemode()\n");			return;		}                pte_val (*pte) &= mask;                pte_val (*pte) |= flags;                flush_tlb_page(find_vma(&init_mm,address),address);		address += PAGE_SIZE;	}}__apusunsigned long mm_ptov (unsigned long paddr){	unsigned long ret;	if (paddr < 16*1024*1024)		ret = ZTWO_VADDR(paddr);	else {		int i;		for (i = 0; i < kmap_chunk_count;){			unsigned long phys = kmap_chunks[i++];			unsigned long size = kmap_chunks[i++];			unsigned long virt = kmap_chunks[i++];			if (paddr >= phys			    && paddr < (phys + size)){				ret = virt + paddr - phys;				goto exit;			}		}				ret = (unsigned long) __va(paddr);	}exit:#ifdef DEBUGPV	printk ("PTOV(%lx)=%lx\n", paddr, ret);#endif	return ret;}__apusint mm_end_of_chunk (unsigned long addr, int len){	if (memory[0].addr + memory[0].size == addr + len)		return 1;	return 0;}/*********************************************************** CACHE */#define L1_CACHE_BYTES 32#define MAX_CACHE_SIZE 8192__apusvoid cache_push(__u32 addr, int length){	addr = mm_ptov(addr);	if (MAX_CACHE_SIZE < length)		length = MAX_CACHE_SIZE;	while(length > 0){		__asm ("dcbf 0,%0\n\t"		       : : "r" (addr));		addr += L1_CACHE_BYTES;		length -= L1_CACHE_BYTES;	}	/* Also flush trailing block */	__asm ("dcbf 0,%0\n\t"	       "sync \n\t"	       : : "r" (addr));}__apusvoid cache_clear(__u32 addr, int length){	if (MAX_CACHE_SIZE < length)		length = MAX_CACHE_SIZE;	addr = mm_ptov(addr);	__asm ("dcbf 0,%0\n\t"	       "sync \n\t"	       "icbi 0,%0 \n\t"	       "isync \n\t"	       : : "r" (addr));		addr += L1_CACHE_BYTES;	length -= L1_CACHE_BYTES;	while(length > 0){		__asm ("dcbf 0,%0\n\t"		       "sync \n\t"

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -