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

📄 ioc3.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * SGI IOC3 master driver and IRQ demuxer * * Copyright (c) 2005 Stanislaw Skowronek <skylark@linux-mips.org> * Heavily based on similar work by: *   Brent Casavant <bcasavan@sgi.com> - IOC4 master driver *   Pat Gefre <pfg@sgi.com> - IOC3 serial port IRQ demuxer */#include <linux/errno.h>#include <linux/module.h>#include <linux/pci.h>#include <linux/dma-mapping.h>#include <linux/interrupt.h>#include <linux/spinlock.h>#include <linux/delay.h>#include <linux/ioc3.h>#include <linux/rwsem.h>#define IOC3_PCI_SIZE 0x100000static LIST_HEAD(ioc3_devices);static int ioc3_counter;static DECLARE_RWSEM(ioc3_devices_rwsem);static struct ioc3_submodule *ioc3_submodules[IOC3_MAX_SUBMODULES];static struct ioc3_submodule *ioc3_ethernet;static DEFINE_RWLOCK(ioc3_submodules_lock);/* NIC probing code */#define GPCR_MLAN_EN    0x00200000      /* enable MCR to pin 8 */static inline unsigned mcr_pack(unsigned pulse, unsigned sample){	return (pulse << 10) | (sample << 2);}static int nic_wait(struct ioc3_driver_data *idd){	unsigned mcr;        do {                mcr = readl(&idd->vma->mcr);        } while (!(mcr & 2));        return mcr & 1;}static int nic_reset(struct ioc3_driver_data *idd){        int presence;	unsigned long flags;	local_irq_save(flags);	writel(mcr_pack(500, 65), &idd->vma->mcr);	presence = nic_wait(idd);	local_irq_restore(flags);	udelay(500);        return presence;}static int nic_read_bit(struct ioc3_driver_data *idd){	int result;	unsigned long flags;	local_irq_save(flags);	writel(mcr_pack(6, 13), &idd->vma->mcr);	result = nic_wait(idd);	local_irq_restore(flags);	udelay(500);	return result;}static void nic_write_bit(struct ioc3_driver_data *idd, int bit){	if (bit)		writel(mcr_pack(6, 110), &idd->vma->mcr);	else		writel(mcr_pack(80, 30), &idd->vma->mcr);	nic_wait(idd);}static unsigned nic_read_byte(struct ioc3_driver_data *idd){	unsigned result = 0;	int i;	for (i = 0; i < 8; i++)		result = (result >> 1) | (nic_read_bit(idd) << 7);	return result;}static void nic_write_byte(struct ioc3_driver_data *idd, int byte){	int i, bit;	for (i = 8; i; i--) {		bit = byte & 1;		byte >>= 1;		nic_write_bit(idd, bit);	}}static unsigned longnic_find(struct ioc3_driver_data *idd, int *last, unsigned long addr){	int a, b, index, disc;	nic_reset(idd);	/* Search ROM.  */	nic_write_byte(idd, 0xF0);	/* Algorithm from ``Book of iButton Standards''.  */	for (index = 0, disc = 0; index < 64; index++) {		a = nic_read_bit(idd);		b = nic_read_bit(idd);		if (a && b) {			printk(KERN_WARNING "IOC3 NIC search failed.\n");			*last = 0;			return 0;		}		if (!a && !b) {			if (index == *last) {				addr |= 1UL << index;			} else if (index > *last) {				addr &= ~(1UL << index);				disc = index;			} else if ((addr & (1UL << index)) == 0)				disc = index;			nic_write_bit(idd, (addr>>index)&1);			continue;		} else {			if (a)				addr |= 1UL << index;			else				addr &= ~(1UL << index);			nic_write_bit(idd, a);			continue;		}	}	*last = disc;	return addr;}static void nic_addr(struct ioc3_driver_data *idd, unsigned long addr){	int index;	nic_reset(idd);	nic_write_byte(idd, 0xF0);	for (index = 0; index < 64; index++) {		nic_read_bit(idd);		nic_read_bit(idd);		nic_write_bit(idd, (addr>>index)&1);	}}static void crc16_byte(unsigned int *crc, unsigned char db){	int i;	for(i=0;i<8;i++) {		*crc <<= 1;		if((db^(*crc>>16)) & 1)			*crc ^= 0x8005;		db >>= 1;	}	*crc &= 0xFFFF;}static unsigned int crc16_area(unsigned char *dbs, int size, unsigned int crc){	while(size--)		crc16_byte(&crc, *(dbs++));	return crc;}static void crc8_byte(unsigned int *crc, unsigned char db){	int i,f;	for(i=0;i<8;i++) {		f = (*crc ^ db) & 1;		*crc >>= 1;		db >>= 1;		if(f)			*crc ^= 0x8c;	}	*crc &= 0xff;}static unsigned int crc8_addr(unsigned long addr){	int i;	unsigned int crc = 0x00;	for(i=0;i<8;i++)		crc8_byte(&crc, addr>>(i<<3));	return crc;}static voidread_redir_page(struct ioc3_driver_data *idd, unsigned long addr, int page,			unsigned char *redir, unsigned char *data){	int loops = 16, i;	while(redir[page] != 0xFF) {		page = redir[page]^0xFF;		loops--;		if(loops<0) {			printk(KERN_ERR "IOC3: NIC circular redirection\n");			return;		}	}	loops = 3;	while(loops>0) {		nic_addr(idd, addr);		nic_write_byte(idd, 0xF0);		nic_write_byte(idd, (page << 5) & 0xE0);		nic_write_byte(idd, (page >> 3) & 0x1F);		for(i=0;i<0x20;i++)			data[i] = nic_read_byte(idd);		if(crc16_area(data, 0x20, 0x0000) == 0x800d)			return;		loops--;	}	printk(KERN_ERR "IOC3: CRC error in data page\n");	for(i=0;i<0x20;i++)		data[i] = 0x00;}static voidread_redir_map(struct ioc3_driver_data *idd, unsigned long addr,					 unsigned char *redir){	int i,j,loops = 3,crc_ok;	unsigned int crc;	while(loops>0) {		crc_ok = 1;		nic_addr(idd, addr);		nic_write_byte(idd, 0xAA);		nic_write_byte(idd, 0x00);		nic_write_byte(idd, 0x01);		for(i=0;i<64;i+=8) {			for(j=0;j<8;j++)				redir[i+j] = nic_read_byte(idd);			crc = crc16_area(redir+i, 8, (i==0)?0x8707:0x0000);			crc16_byte(&crc, nic_read_byte(idd));			crc16_byte(&crc, nic_read_byte(idd));			if(crc != 0x800d)				crc_ok = 0;		}		if(crc_ok)			return;		loops--;	}	printk(KERN_ERR "IOC3: CRC error in redirection page\n");	for(i=0;i<64;i++)		redir[i] = 0xFF;}static void read_nic(struct ioc3_driver_data *idd, unsigned long addr){	unsigned char redir[64];	unsigned char data[64],part[32];	int i,j;	/* read redirections */	read_redir_map(idd, addr, redir);	/* read data pages */	read_redir_page(idd, addr, 0, redir, data);	read_redir_page(idd, addr, 1, redir, data+32);	/* assemble the part # */	j=0;	for(i=0;i<19;i++)		if(data[i+11] != ' ')			part[j++] = data[i+11];	for(i=0;i<6;i++)		if(data[i+32] != ' ')			part[j++] = data[i+32];	part[j] = 0;	/* skip Octane power supplies */	if(!strncmp(part, "060-0035-", 9))		return;	if(!strncmp(part, "060-0038-", 9))		return;	strcpy(idd->nic_part, part);	/* assemble the serial # */	j=0;	for(i=0;i<10;i++)		if(data[i+1] != ' ')			idd->nic_serial[j++] = data[i+1];	idd->nic_serial[j] = 0;}static void read_mac(struct ioc3_driver_data *idd, unsigned long addr){	int i, loops = 3;	unsigned char data[13];	while(loops>0) {		nic_addr(idd, addr);		nic_write_byte(idd, 0xF0);		nic_write_byte(idd, 0x00);		nic_write_byte(idd, 0x00);		nic_read_byte(idd);		for(i=0;i<13;i++)			data[i] = nic_read_byte(idd);		if(crc16_area(data, 13, 0x0000) == 0x800d) {			for(i=10;i>4;i--)				idd->nic_mac[10-i] = data[i];			return;		}		loops--;	}	printk(KERN_ERR "IOC3: CRC error in MAC address\n");	for(i=0;i<6;i++)		idd->nic_mac[i] = 0x00;}static void probe_nic(struct ioc3_driver_data *idd){        int save = 0, loops = 3;        unsigned long first, addr;        writel(GPCR_MLAN_EN, &idd->vma->gpcr_s);        while(loops>0) {                idd->nic_part[0] = 0;                idd->nic_serial[0] = 0;                addr = first = nic_find(idd, &save, 0);                if(!first)                        return;                while(1) {                        if(crc8_addr(addr))                                break;                        else {                                switch(addr & 0xFF) {                                case 0x0B:                                        read_nic(idd, addr);                                        break;                                case 0x09:                                case 0x89:                                case 0x91:                                        read_mac(idd, addr);                                        break;                                }                        }                        addr = nic_find(idd, &save, addr);                        if(addr == first)                                return;                }                loops--;        }        printk(KERN_ERR "IOC3: CRC error in NIC address\n");}/* Interrupts */static void write_ireg(struct ioc3_driver_data *idd, uint32_t val, int which){	unsigned long flags;	spin_lock_irqsave(&idd->ir_lock, flags);	switch (which) {	case IOC3_W_IES:		writel(val, &idd->vma->sio_ies);		break;	case IOC3_W_IEC:		writel(val, &idd->vma->sio_iec);		break;	}	spin_unlock_irqrestore(&idd->ir_lock, flags);}static inline uint32_t get_pending_intrs(struct ioc3_driver_data *idd){	unsigned long flag;	uint32_t intrs = 0;	spin_lock_irqsave(&idd->ir_lock, flag);	intrs = readl(&idd->vma->sio_ir);	intrs &= readl(&idd->vma->sio_ies);	spin_unlock_irqrestore(&idd->ir_lock, flag);	return intrs;}static irqreturn_t ioc3_intr_io(int irq, void *arg){	unsigned long flags;	struct ioc3_driver_data *idd = arg;	int handled = 1, id;	unsigned int pending;	read_lock_irqsave(&ioc3_submodules_lock, flags);	if(idd->dual_irq && readb(&idd->vma->eisr)) {		/* send Ethernet IRQ to the driver */		if(ioc3_ethernet && idd->active[ioc3_ethernet->id] &&						ioc3_ethernet->intr) {			handled = handled && !ioc3_ethernet->intr(ioc3_ethernet,							idd, 0);		}	}	pending = get_pending_intrs(idd);	/* look at the IO IRQs */	for(id=0;id<IOC3_MAX_SUBMODULES;id++) {		if(idd->active[id] && ioc3_submodules[id]				&& (pending & ioc3_submodules[id]->irq_mask)

⌨️ 快捷键说明

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