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

📄 rrunner.c

📁 powerpc内核mpc8241linux系统下net驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * rrunner.c: Linux driver for the Essential RoadRunner HIPPI board. * * Written 1998 by Jes Sorensen, <Jes.Sorensen@cern.ch>. * * Thanks to Essential Communication for providing us with hardware * and very comprehensive documentation without which I would not have * been able to write this driver. A special thank you to John Gibbon * for sorting out the legal issues, with the NDA, allowing the code to * be released under the GPL. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. */#define DEBUG 1#define RX_DMA_SKBUFF 1#define PKT_COPY_THRESHOLD 512#include <linux/module.h>#include <linux/types.h>#include <linux/errno.h>#include <linux/ioport.h>#include <linux/pci.h>#include <linux/kernel.h>#include <linux/netdevice.h>#include <linux/hippidevice.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/mm.h>#include <net/sock.h>#include <asm/system.h>#include <asm/cache.h>#include <asm/byteorder.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/uaccess.h>#include "rrunner.h"/* * Implementation notes: * * The DMA engine only allows for DMA within physical 64KB chunks of * memory. The current approach of the driver (and stack) is to use * linear blocks of memory for the skbuffs. However, as the data block * is always the first part of the skb and skbs are 2^n aligned so we * are guarantted to get the whole block within one 64KB align 64KB * chunk. * * On the long term, relying on being able to allocate 64KB linear * chunks of memory is not feasible and the skb handling code and the * stack will need to know about I/O vectors or something similar. */static const char *version = "rrunner.c: v0.09 12/14/98  Jes Sorensen (Jes.Sorensen@cern.ch)\n";static unsigned int read_eeprom(struct rr_private *rrpriv,				unsigned long offset,				unsigned char *buf,				unsigned long length);static u32 read_eeprom_word(struct rr_private *rrpriv,			    void * offset);static int rr_load_firmware(struct device *dev);/* * These are checked at init time to see if they are at least 256KB * and increased to 256KB if they are not. This is done to avoid ending * up with socket buffers smaller than the MTU size, */extern __u32 sysctl_wmem_max;extern __u32 sysctl_rmem_max;__initfunc(int rr_hippi_probe (struct device *dev)){	static int i = 0;	int boards_found = 0;	int version_disp;	/* was version info already displayed? */	u8 pci_bus;		/* PCI bus number (0-255) */	u8 pci_dev_fun;		/* PCI device and function numbers (0-255) */	u8 pci_latency;	u16 command;		/* PCI Configuration space Command register */	unsigned int tmp;	u8 irq;	struct rr_private *rrpriv;	if (!pci_present())		/* is PCI BIOS even present? */		return -ENODEV;	version_disp = 0;	for (; i < 255; i++)	{		if (pcibios_find_device(PCI_VENDOR_ID_ESSENTIAL,					PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,					i, &pci_bus, &pci_dev_fun) != 0)			break;		pcibios_read_config_word(pci_bus, pci_dev_fun,					 PCI_COMMAND, &command);		/* Enable mastering */		command |= PCI_COMMAND_MASTER;		pcibios_write_config_word(pci_bus, pci_dev_fun,					  PCI_COMMAND, command);		if (!(command & PCI_COMMAND_MEMORY)){			printk("shared mem not enabled - unable to configure RoadRunner\n");			break;		}		/*		 * So we found our HIPPI ... time to tell the system.		 */		dev = init_hippi_dev(dev, sizeof(struct rr_private));		if (dev == NULL)			break;		if (!dev->priv)			dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL);		rrpriv = (struct rr_private *)dev->priv;		/* Read register base address from		   PCI Configuration Space */		pcibios_read_config_dword(pci_bus, pci_dev_fun,					  PCI_BASE_ADDRESS_0, &tmp);		pcibios_read_config_byte(pci_bus, pci_dev_fun,					 PCI_INTERRUPT_LINE, &irq);		dev->irq = irq;		rrpriv->pci_bus = pci_bus;		rrpriv->pci_dev_fun = pci_dev_fun;		sprintf(rrpriv->name, "RoadRunner serial HIPPI");#ifdef __SMP__		spin_lock_init(&rrpriv->lock);#endif		dev->open = &rr_open;		dev->hard_start_xmit = &rr_start_xmit;		dev->stop = &rr_close;		dev->get_stats = &rr_get_stats;		dev->do_ioctl = &rr_ioctl;		/*		 * Dummy value.		 */		dev->base_addr = 42;		/* display version info if adapter is found */		if (!version_disp)		{			/* set display flag to TRUE so that */			/* we only display this string ONCE */			version_disp = 1;			printk(version);		}		printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI at 0x%08x, irq %i\n",		       dev->name, tmp, dev->irq);		pcibios_read_config_byte(pci_bus, pci_dev_fun,					 PCI_LATENCY_TIMER, &pci_latency);#if 0		if (pci_latency <= 48){			printk("  PCI latency counter too low (%i), setting to 48 clocks\n", pci_latency);			pcibios_write_config_byte(pci_bus, pci_dev_fun,						  PCI_LATENCY_TIMER, 48);		}#else		if (pci_latency <= 0x58)			pcibios_write_config_byte(pci_bus, pci_dev_fun,						  PCI_LATENCY_TIMER, 0x58);#endif		/*		 * Remap the regs into kernel space.		 */		rrpriv->regs = (struct rr_regs *)ioremap(tmp, 0x1000);		if (!rrpriv->regs){			printk(KERN_ERR "%s:  Unable to map I/O register, RoadRunner %i will be disabled.\n", dev->name, i);			break;		}		/*		 * Don't access any registes before this point!		 */#ifdef __BIG_ENDIAN		regs->HostCtrl |= NO_SWAP;#endif		/*		 * Need to add a case for little-endian 64-bit hosts here.		 */		rr_init(dev);		boards_found++;		dev->base_addr = 0;		dev = NULL;	}	/*	 * If we're at this point we're going through rr_hippi_probe()	 * for the first time.  Return success (0) if we've initialized	 * 1 or more boards. Otherwise, return failure (-ENODEV).	 */	if (boards_found > 0)		return 0;	else		return -ENODEV;}/* * Commands are considered to be slow, thus there is no reason to * inline this. */static void rr_issue_cmd(struct rr_private *rrpriv, struct cmd *cmd){	struct rr_regs *regs;	u32 idx;	regs = rrpriv->regs;	/*	 * This is temporary - it will go away in the final version.	 * We probably also want to make this function inline.	 */	if (regs->HostCtrl & NIC_HALTED){		printk("issuing command for halted NIC, code 0x%x, HostCtrl %08x\n", cmd->code, regs->HostCtrl);		if (regs->Mode & FATAL_ERR)			printk("error code %02x\n", regs->Fail1);	}	idx = rrpriv->info->cmd_ctrl.pi;	regs->CmdRing[idx] = *(u32*)(cmd);	idx = (idx - 1) % CMD_RING_ENTRIES;	rrpriv->info->cmd_ctrl.pi = idx;	if (regs->Mode & FATAL_ERR)		printk("error code %02x\n", regs->Fail1);}/* * Reset the board in a sensible manner. The NIC is already halted * when we get here and a spin-lock is held. */static int rr_reset(struct device *dev){	struct rr_private *rrpriv;	struct rr_regs *regs;	struct eeprom *hw = NULL;	u32 start_pc;	int i;	rrpriv = (struct rr_private *)dev->priv;	regs = rrpriv->regs;	rr_load_firmware(dev);	regs->TX_state = 0x01000000;	regs->RX_state = 0xff800000;	regs->AssistState = 0;	regs->LocalCtrl = CLEAR_INTA;	regs->BrkPt = 0x01;	regs->Timer = 0;	regs->TimerRef = 0;	regs->DmaReadState = RESET_DMA;	regs->DmaWriteState = RESET_DMA;	regs->DmaWriteHostHi = 0;	regs->DmaWriteHostLo = 0;	regs->DmaReadHostHi = 0;	regs->DmaReadHostLo = 0;	regs->DmaReadLen = 0;	regs->DmaWriteLen = 0;	regs->DmaWriteLcl = 0;	regs->DmaWriteIPchecksum = 0;	regs->DmaReadLcl = 0;	regs->DmaReadIPchecksum = 0;	regs->PciState = 0; /* 0x90 for GE? */	regs->Mode = SWAP_DATA;#if 0	/*	 * Don't worry, this is just black magic.	 */	regs->RxBase = 0xdf000;	regs->RxPrd = 0xdf000;	regs->RxCon = 0xdf000;	regs->TxBase = 0xce000;	regs->TxPrd = 0xce000;	regs->TxCon = 0xce000;	regs->RxIndPro = 0;	regs->RxIndCon = 0;	regs->RxIndRef = 0;	regs->TxIndPro = 0;	regs->TxIndCon = 0;	regs->TxIndRef = 0;	regs->pad10[0] = 0xcc000;	regs->DrCmndPro = 0;	regs->DrCmndCon = 0;	regs->DwCmndPro = 0;	regs->DwCmndCon = 0;	regs->DwCmndRef = 0;	regs->DrDataPro = 0;	regs->DrDataCon = 0;	regs->DrDataRef = 0;	regs->DwDataPro = 0;	regs->DwDataCon = 0;	regs->DwDataRef = 0;#endif	regs->MbEvent = 0xffffffff;	regs->Event = 0;	regs->TxPi = 0;	regs->IpRxPi = 0;	regs->EvtCon = 0;	regs->EvtPrd = 0;	rrpriv->info->evt_ctrl.pi = 0;	for (i = 0; i < CMD_RING_ENTRIES; i++)		regs->CmdRing[i] = 0;	regs->PciState = 0;	start_pc = read_eeprom_word(rrpriv, &hw->rncd_info.FwStart);#if (DEBUG > 1)	printk("%s: Executing firmware at address 0x%06x\n",	       dev->name, start_pc);#endif	regs->Pc = start_pc + 0x800;	udelay(5);	regs->Pc = start_pc;	return 0;}/* * Read a string from the EEPROM. */static unsigned int read_eeprom(struct rr_private *rrpriv,				unsigned long offset,				unsigned char *buf,				unsigned long length){	struct rr_regs *regs = rrpriv->regs;	u32 misc, io, host, i;	io = regs->ExtIo;	regs->ExtIo = 0;	misc = regs->LocalCtrl;	regs->LocalCtrl = 0;	host = regs->HostCtrl;	regs->HostCtrl |= HALT_NIC;	for (i = 0; i < length; i++){		regs->WinBase = (EEPROM_BASE + ((offset+i) << 3));		buf[i] = (regs->WinData >> 24) & 0xff;	}	regs->HostCtrl = host;	regs->LocalCtrl = misc;	regs->ExtIo = io;	return i;}/* * Shortcut to read one word (4 bytes) out of the EEPROM and convert * it to our CPU byte-order. */static u32 read_eeprom_word(struct rr_private *rrpriv,			    void * offset){	u32 word;	if ((read_eeprom(rrpriv, (unsigned long)offset,			 (char *)&word, 4) == 4))		return be32_to_cpu(word);	return 0;}/* * Write a string to the EEPROM. * * This is only called when the firmware is not running. */static unsigned int write_eeprom(struct rr_private *rrpriv,				unsigned long offset,				unsigned char *buf,				unsigned long length){	struct rr_regs *regs = rrpriv->regs;	u32 misc, io, data, i, j, ready, error = 0;	io = regs->ExtIo;	regs->ExtIo = 0;	misc = regs->LocalCtrl;	regs->LocalCtrl = ENABLE_EEPROM_WRITE;	for (i = 0; i < length; i++){		regs->WinBase = (EEPROM_BASE + ((offset+i) << 3));		data = buf[i] << 24;		/*		 * Only try to write the data if it is not the same		 * value already.		 */		if ((regs->WinData & 0xff000000) != data){			regs->WinData = data;			ready = 0;			j = 0;			mb();			while(!ready){				udelay(1000);				if ((regs->WinData & 0xff000000) == data)					ready = 1;				if (j++ > 5000){					printk("data mismatch: %08x, "					       "WinData %08x\n", data,					       regs->WinData);					ready = 1;					error = 1;				}			}		}	}	regs->LocalCtrl = misc;	regs->ExtIo = io;	return error;}__initfunc(static int rr_init(struct device *dev)){

⌨️ 快捷键说明

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