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

📄 voyager_cat.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* -*- mode: c; c-basic-offset: 8 -*- *//* Copyright (C) 1999,2001 * * Author: J.E.J.Bottomley@HansenPartnership.com * * linux/arch/i386/kernel/voyager_cat.c * * This file contains all the logic for manipulating the CAT bus * in a level 5 machine. * * The CAT bus is a serial configuration and test bus.  Its primary * uses are to probe the initial configuration of the system and to * diagnose error conditions when a system interrupt occurs.  The low * level interface is fairly primitive, so most of this file consists * of bit shift manipulations to send and receive packets on the * serial bus */#include <linux/types.h>#include <linux/completion.h>#include <linux/sched.h>#include <asm/voyager.h>#include <asm/vic.h>#include <linux/ioport.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/delay.h>#include <asm/io.h>#ifdef VOYAGER_CAT_DEBUG#define CDEBUG(x)	printk x#else#define CDEBUG(x)#endif/* the CAT command port */#define CAT_CMD		(sspb + 0xe)/* the CAT data port */#define CAT_DATA	(sspb + 0xd)/* the internal cat functions */static void cat_pack(__u8 *msg, __u16 start_bit, __u8 *data, 		     __u16 num_bits);static void cat_unpack(__u8 *msg, __u16 start_bit, __u8 *data,		       __u16 num_bits);static void cat_build_header(__u8 *header, const __u16 len, 			     const __u16 smallest_reg_bits,			     const __u16 longest_reg_bits);static int cat_sendinst(voyager_module_t *modp, voyager_asic_t *asicp,			__u8 reg, __u8 op);static int cat_getdata(voyager_module_t *modp, voyager_asic_t *asicp,		       __u8 reg, __u8 *value);static int cat_shiftout(__u8 *data, __u16 data_bytes, __u16 header_bytes,			__u8 pad_bits);static int cat_write(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,		     __u8 value);static int cat_read(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg,		    __u8 *value);static int cat_subread(voyager_module_t *modp, voyager_asic_t *asicp,		       __u16 offset, __u16 len, void *buf);static int cat_senddata(voyager_module_t *modp, voyager_asic_t *asicp,			__u8 reg, __u8 value);static int cat_disconnect(voyager_module_t *modp, voyager_asic_t *asicp);static int cat_connect(voyager_module_t *modp, voyager_asic_t *asicp);static inline const char *cat_module_name(int module_id){	switch(module_id) {	case 0x10:		return "Processor Slot 0";	case 0x11:		return "Processor Slot 1";	case 0x12:		return "Processor Slot 2";	case 0x13:		return "Processor Slot 4";	case 0x14:		return "Memory Slot 0";	case 0x15:		return "Memory Slot 1";	case 0x18:		return "Primary Microchannel";	case 0x19:		return "Secondary Microchannel";	case 0x1a:		return "Power Supply Interface";	case 0x1c:		return "Processor Slot 5";	case 0x1d:		return "Processor Slot 6";	case 0x1e:		return "Processor Slot 7";	case 0x1f:		return "Processor Slot 8";	default:		return "Unknown Module";	}}static int sspb = 0;		/* stores the super port location */int voyager_8slot = 0;		/* set to true if a 51xx monster */voyager_module_t *voyager_cat_list;/* the I/O port assignments for the VIC and QIC */static struct resource vic_res = {	.name	= "Voyager Interrupt Controller",	.start	= 0xFC00,	.end	= 0xFC6F};static struct resource qic_res = {	.name	= "Quad Interrupt Controller",	.start	= 0xFC70,	.end	= 0xFCFF};/* This function is used to pack a data bit stream inside a message. * It writes num_bits of the data buffer in msg starting at start_bit. * Note: This function assumes that any unused bit in the data stream * is set to zero so that the ors will work correctly */static voidcat_pack(__u8 *msg, const __u16 start_bit, __u8 *data, const __u16 num_bits){	/* compute initial shift needed */	const __u16 offset = start_bit % BITS_PER_BYTE;	__u16 len = num_bits / BITS_PER_BYTE;	__u16 byte = start_bit / BITS_PER_BYTE;	__u16 residue = (num_bits % BITS_PER_BYTE) + offset;	int i;	/* adjust if we have more than a byte of residue */	if(residue >= BITS_PER_BYTE) {		residue -= BITS_PER_BYTE;		len++;	}	/* clear out the bits.  We assume here that if len==0 then	 * residue >= offset.  This is always true for the catbus	 * operations */	msg[byte] &= 0xff << (BITS_PER_BYTE - offset); 	msg[byte++] |= data[0] >> offset;	if(len == 0)		return;	for(i = 1; i < len; i++)		msg[byte++] = (data[i-1] << (BITS_PER_BYTE - offset))			| (data[i] >> offset);	if(residue != 0) {		__u8 mask = 0xff >> residue;		__u8 last_byte = data[i-1] << (BITS_PER_BYTE - offset)			| (data[i] >> offset);				last_byte &= ~mask;		msg[byte] &= mask;		msg[byte] |= last_byte;	}	return;}/* unpack the data again (same arguments as cat_pack()). data buffer * must be zero populated. * * Function: given a message string move to start_bit and copy num_bits into * data (starting at bit 0 in data). */static voidcat_unpack(__u8 *msg, const __u16 start_bit, __u8 *data, const __u16 num_bits){	/* compute initial shift needed */	const __u16 offset = start_bit % BITS_PER_BYTE;	__u16 len = num_bits / BITS_PER_BYTE;	const __u8 last_bits = num_bits % BITS_PER_BYTE;	__u16 byte = start_bit / BITS_PER_BYTE;	int i;	if(last_bits != 0)		len++;	/* special case: want < 8 bits from msg and we can get it from	 * a single byte of the msg */	if(len == 0 && BITS_PER_BYTE - offset >= num_bits) {		data[0] = msg[byte] << offset;		data[0] &= 0xff >> (BITS_PER_BYTE - num_bits);		return;	}	for(i = 0; i < len; i++) {		/* this annoying if has to be done just in case a read of		 * msg one beyond the array causes a panic */		if(offset != 0) {			data[i] = msg[byte++] << offset;			data[i] |= msg[byte] >> (BITS_PER_BYTE - offset);		}		else {			data[i] = msg[byte++];		}	}	/* do we need to truncate the final byte */	if(last_bits != 0) {		data[i-1] &= 0xff << (BITS_PER_BYTE - last_bits);	}	return;}static voidcat_build_header(__u8 *header, const __u16 len, const __u16 smallest_reg_bits,		 const __u16 longest_reg_bits){	int i;	__u16 start_bit = (smallest_reg_bits - 1) % BITS_PER_BYTE;	__u8 *last_byte = &header[len - 1];	if(start_bit == 0)		start_bit = 1;	/* must have at least one bit in the hdr */		for(i=0; i < len; i++)		header[i] = 0;	for(i = start_bit; i > 0; i--)		*last_byte = ((*last_byte) << 1) + 1;}static intcat_sendinst(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg, __u8 op){	__u8 parity, inst, inst_buf[4] = { 0 };	__u8 iseq[VOYAGER_MAX_SCAN_PATH], hseq[VOYAGER_MAX_REG_SIZE];	__u16 ibytes, hbytes, padbits;	int i;		/* 	 * Parity is the parity of the register number + 1 (READ_REGISTER	 * and WRITE_REGISTER always add '1' to the number of bits == 1)	 */	parity = (__u8)(1 + (reg & 0x01) +	         ((__u8)(reg & 0x02) >> 1) +	         ((__u8)(reg & 0x04) >> 2) +	         ((__u8)(reg & 0x08) >> 3)) % 2;	inst = ((parity << 7) | (reg << 2) | op);	outb(VOYAGER_CAT_IRCYC, CAT_CMD);	if(!modp->scan_path_connected) {		if(asicp->asic_id != VOYAGER_CAT_ID) {			printk("**WARNING***: cat_sendinst has disconnected scan path not to CAT asic\n");			return 1;		}		outb(VOYAGER_CAT_HEADER, CAT_DATA);		outb(inst, CAT_DATA);		if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {			CDEBUG(("VOYAGER CAT: cat_sendinst failed to get CAT_HEADER\n"));			return 1;		}		return 0;	}	ibytes = modp->inst_bits / BITS_PER_BYTE;	if((padbits = modp->inst_bits % BITS_PER_BYTE) != 0) {		padbits = BITS_PER_BYTE - padbits;		ibytes++;	}	hbytes = modp->largest_reg / BITS_PER_BYTE;	if(modp->largest_reg % BITS_PER_BYTE)		hbytes++;	CDEBUG(("cat_sendinst: ibytes=%d, hbytes=%d\n", ibytes, hbytes));	/* initialise the instruction sequence to 0xff */	for(i=0; i < ibytes + hbytes; i++)		iseq[i] = 0xff;	cat_build_header(hseq, hbytes, modp->smallest_reg, modp->largest_reg);	cat_pack(iseq, modp->inst_bits, hseq, hbytes * BITS_PER_BYTE);	inst_buf[0] = inst;	inst_buf[1] = 0xFF >> (modp->largest_reg % BITS_PER_BYTE);	cat_pack(iseq, asicp->bit_location, inst_buf, asicp->ireg_length);#ifdef VOYAGER_CAT_DEBUG	printk("ins = 0x%x, iseq: ", inst);	for(i=0; i< ibytes + hbytes; i++)		printk("0x%x ", iseq[i]);	printk("\n");#endif	if(cat_shiftout(iseq, ibytes, hbytes, padbits)) {		CDEBUG(("VOYAGER CAT: cat_sendinst: cat_shiftout failed\n"));		return 1;	}	CDEBUG(("CAT SHIFTOUT DONE\n"));	return 0;}static intcat_getdata(voyager_module_t *modp, voyager_asic_t *asicp, __u8 reg, 	    __u8 *value){	if(!modp->scan_path_connected) {		if(asicp->asic_id != VOYAGER_CAT_ID) {			CDEBUG(("VOYAGER CAT: ERROR: cat_getdata to CAT asic with scan path connected\n"));			return 1;		}		if(reg > VOYAGER_SUBADDRHI) 			outb(VOYAGER_CAT_RUN, CAT_CMD);		outb(VOYAGER_CAT_DRCYC, CAT_CMD);		outb(VOYAGER_CAT_HEADER, CAT_DATA);		*value = inb(CAT_DATA);		outb(0xAA, CAT_DATA);		if(inb(CAT_DATA) != VOYAGER_CAT_HEADER) {			CDEBUG(("cat_getdata: failed to get VOYAGER_CAT_HEADER\n"));			return 1;		}		return 0;	}	else {		__u16 sbits = modp->num_asics -1 + asicp->ireg_length;		__u16 sbytes = sbits / BITS_PER_BYTE;		__u16 tbytes;		__u8 string[VOYAGER_MAX_SCAN_PATH], trailer[VOYAGER_MAX_REG_SIZE];		__u8 padbits;		int i;				outb(VOYAGER_CAT_DRCYC, CAT_CMD);		if((padbits = sbits % BITS_PER_BYTE) != 0) {			padbits = BITS_PER_BYTE - padbits;			sbytes++;		}		tbytes = asicp->ireg_length / BITS_PER_BYTE;		if(asicp->ireg_length % BITS_PER_BYTE)			tbytes++;		CDEBUG(("cat_getdata: tbytes = %d, sbytes = %d, padbits = %d\n",			tbytes,	sbytes, padbits));		cat_build_header(trailer, tbytes, 1, asicp->ireg_length);				for(i = tbytes - 1; i >= 0; i--) {			outb(trailer[i], CAT_DATA);			string[sbytes + i] = inb(CAT_DATA);		}		for(i = sbytes - 1; i >= 0; i--) {			outb(0xaa, CAT_DATA);			string[i] = inb(CAT_DATA);		}		*value = 0;		cat_unpack(string, padbits + (tbytes * BITS_PER_BYTE) + asicp->asic_location, value, asicp->ireg_length);#ifdef VOYAGER_CAT_DEBUG		printk("value=0x%x, string: ", *value);		for(i=0; i< tbytes+sbytes; i++)			printk("0x%x ", string[i]);		printk("\n");#endif				/* sanity check the rest of the return */		for(i=0; i < tbytes; i++) {			__u8 input = 0;			cat_unpack(string, padbits + (i * BITS_PER_BYTE), &input, BITS_PER_BYTE);			if(trailer[i] != input) {				CDEBUG(("cat_getdata: failed to sanity check rest of ret(%d) 0x%x != 0x%x\n", i, input, trailer[i]));				return 1;			}		}		CDEBUG(("cat_getdata DONE\n"));		return 0;	}}static intcat_shiftout(__u8 *data, __u16 data_bytes, __u16 header_bytes, __u8 pad_bits){	int i;		for(i = data_bytes + header_bytes - 1; i >= header_bytes; i--)		outb(data[i], CAT_DATA);	for(i = header_bytes - 1; i >= 0; i--) {		__u8 header = 0;		__u8 input;		outb(data[i], CAT_DATA);		input = inb(CAT_DATA);		CDEBUG(("cat_shiftout: returned 0x%x\n", input));		cat_unpack(data, ((data_bytes + i) * BITS_PER_BYTE) - pad_bits,			   &header, BITS_PER_BYTE);		if(input != header) {			CDEBUG(("VOYAGER CAT: cat_shiftout failed to return header 0x%x != 0x%x\n", input, header));			return 1;		}	}	return 0;}static intcat_senddata(voyager_module_t *modp, voyager_asic_t *asicp, 	     __u8 reg, __u8 value){	outb(VOYAGER_CAT_DRCYC, CAT_CMD);	if(!modp->scan_path_connected) {		if(asicp->asic_id != VOYAGER_CAT_ID) {			CDEBUG(("VOYAGER CAT: ERROR: scan path disconnected when asic != CAT\n"));

⌨️ 快捷键说明

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