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

📄 rrunner.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * rrunner.c: Linux driver for the Essential RoadRunner HIPPI board. * * Copyright (C) 1998-2002 by Jes Sorensen, <jes@wildopensource.com>. * * 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. * * Thanks to Jayaram Bhat from ODS/Essential for fixing some of the * stupid bugs in my code. * * Softnet support and various other patches from Val Henson of * ODS/Essential. * * PCI DMA mapping code partly based on work by Francois Romieu. */#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>#define rr_if_busy(dev)     netif_queue_stopped(dev)#define rr_if_running(dev)  netif_running(dev)#include "rrunner.h"#define RUN_AT(x) (jiffies + (x))MODULE_AUTHOR("Jes Sorensen <jes@wildopensource.com>");MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver");MODULE_LICENSE("GPL");static char version[] __devinitdata = "rrunner.c: v0.50 11/11/2002  Jes Sorensen (jes@wildopensource.com)\n";/* * 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 int __devinit rr_init_one(struct pci_dev *pdev,	const struct pci_device_id *ent){	struct net_device *dev;	static int version_disp;	u8 pci_latency;	struct rr_private *rrpriv;	void *tmpptr;	dma_addr_t ring_dma;	int ret = -ENOMEM;	dev = alloc_hippi_dev(sizeof(struct rr_private));	if (!dev)		goto out3;	ret = pci_enable_device(pdev);	if (ret) {		ret = -ENODEV;		goto out2;	}	rrpriv = netdev_priv(dev);	SET_NETDEV_DEV(dev, &pdev->dev);	if (pci_request_regions(pdev, "rrunner")) {		ret = -EIO;		goto out;	}	pci_set_drvdata(pdev, dev);	rrpriv->pci_dev = pdev;	spin_lock_init(&rrpriv->lock);	dev->irq = pdev->irq;	dev->open = &rr_open;	dev->hard_start_xmit = &rr_start_xmit;	dev->stop = &rr_close;	dev->do_ioctl = &rr_ioctl;	dev->base_addr = pci_resource_start(pdev, 0);	/* 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);	}	pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);	if (pci_latency <= 0x58){		pci_latency = 0x58;		pci_write_config_byte(pdev, PCI_LATENCY_TIMER, pci_latency);	}	pci_set_master(pdev);	printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI "	       "at 0x%08lx, irq %i, PCI latency %i\n", dev->name,	       dev->base_addr, dev->irq, pci_latency);	/*	 * Remap the regs into kernel space.	 */	rrpriv->regs = ioremap(dev->base_addr, 0x1000);	if (!rrpriv->regs){		printk(KERN_ERR "%s:  Unable to map I/O register, "			"RoadRunner will be disabled.\n", dev->name);		ret = -EIO;		goto out;	}	tmpptr = pci_alloc_consistent(pdev, TX_TOTAL_SIZE, &ring_dma);	rrpriv->tx_ring = tmpptr;	rrpriv->tx_ring_dma = ring_dma;	if (!tmpptr) {		ret = -ENOMEM;		goto out;	}	tmpptr = pci_alloc_consistent(pdev, RX_TOTAL_SIZE, &ring_dma);	rrpriv->rx_ring = tmpptr;	rrpriv->rx_ring_dma = ring_dma;	if (!tmpptr) {		ret = -ENOMEM;		goto out;	}	tmpptr = pci_alloc_consistent(pdev, EVT_RING_SIZE, &ring_dma);	rrpriv->evt_ring = tmpptr;	rrpriv->evt_ring_dma = ring_dma;	if (!tmpptr) {		ret = -ENOMEM;		goto out;	}	/*	 * Don't access any register before this point!	 */#ifdef __BIG_ENDIAN	writel(readl(&rrpriv->regs->HostCtrl) | NO_SWAP,		&rrpriv->regs->HostCtrl);#endif	/*	 * Need to add a case for little-endian 64-bit hosts here.	 */	rr_init(dev);	dev->base_addr = 0;	ret = register_netdev(dev);	if (ret)		goto out;	return 0; out:	if (rrpriv->rx_ring)		pci_free_consistent(pdev, RX_TOTAL_SIZE, rrpriv->rx_ring,				    rrpriv->rx_ring_dma);	if (rrpriv->tx_ring)		pci_free_consistent(pdev, TX_TOTAL_SIZE, rrpriv->tx_ring,				    rrpriv->tx_ring_dma);	if (rrpriv->regs)		iounmap(rrpriv->regs);	if (pdev) {		pci_release_regions(pdev);		pci_set_drvdata(pdev, NULL);	} out2:	free_netdev(dev); out3:	return ret;}static void __devexit rr_remove_one (struct pci_dev *pdev){	struct net_device *dev = pci_get_drvdata(pdev);	if (dev) {		struct rr_private *rr = netdev_priv(dev);		if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){			printk(KERN_ERR "%s: trying to unload running NIC\n",			       dev->name);			writel(HALT_NIC, &rr->regs->HostCtrl);		}		pci_free_consistent(pdev, EVT_RING_SIZE, rr->evt_ring,				    rr->evt_ring_dma);		pci_free_consistent(pdev, RX_TOTAL_SIZE, rr->rx_ring,				    rr->rx_ring_dma);		pci_free_consistent(pdev, TX_TOTAL_SIZE, rr->tx_ring,				    rr->tx_ring_dma);		unregister_netdev(dev);		iounmap(rr->regs);		free_netdev(dev);		pci_release_regions(pdev);		pci_disable_device(pdev);		pci_set_drvdata(pdev, NULL);	}}/* * 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 __iomem *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 (readl(&regs->HostCtrl) & NIC_HALTED){		printk("issuing command for halted NIC, code 0x%x, "		       "HostCtrl %08x\n", cmd->code, readl(&regs->HostCtrl));		if (readl(&regs->Mode) & FATAL_ERR)			printk("error codes Fail1 %02x, Fail2 %02x\n",			       readl(&regs->Fail1), readl(&regs->Fail2));	}	idx = rrpriv->info->cmd_ctrl.pi;	writel(*(u32*)(cmd), &regs->CmdRing[idx]);	wmb();	idx = (idx - 1) % CMD_RING_ENTRIES;	rrpriv->info->cmd_ctrl.pi = idx;	wmb();	if (readl(&regs->Mode) & FATAL_ERR)		printk("error code %02x\n", readl(&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 net_device *dev){	struct rr_private *rrpriv;	struct rr_regs __iomem *regs;	u32 start_pc;	int i;	rrpriv = netdev_priv(dev);	regs = rrpriv->regs;	rr_load_firmware(dev);	writel(0x01000000, &regs->TX_state);	writel(0xff800000, &regs->RX_state);	writel(0, &regs->AssistState);	writel(CLEAR_INTA, &regs->LocalCtrl);	writel(0x01, &regs->BrkPt);	writel(0, &regs->Timer);	writel(0, &regs->TimerRef);	writel(RESET_DMA, &regs->DmaReadState);	writel(RESET_DMA, &regs->DmaWriteState);	writel(0, &regs->DmaWriteHostHi);	writel(0, &regs->DmaWriteHostLo);	writel(0, &regs->DmaReadHostHi);	writel(0, &regs->DmaReadHostLo);	writel(0, &regs->DmaReadLen);	writel(0, &regs->DmaWriteLen);	writel(0, &regs->DmaWriteLcl);	writel(0, &regs->DmaWriteIPchecksum);	writel(0, &regs->DmaReadLcl);	writel(0, &regs->DmaReadIPchecksum);	writel(0, &regs->PciState);#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN	writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, &regs->Mode);#elif (BITS_PER_LONG == 64)	writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, &regs->Mode);#else	writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, &regs->Mode);#endif#if 0	/*	 * Don't worry, this is just black magic.	 */	writel(0xdf000, &regs->RxBase);	writel(0xdf000, &regs->RxPrd);	writel(0xdf000, &regs->RxCon);	writel(0xce000, &regs->TxBase);	writel(0xce000, &regs->TxPrd);	writel(0xce000, &regs->TxCon);	writel(0, &regs->RxIndPro);	writel(0, &regs->RxIndCon);	writel(0, &regs->RxIndRef);	writel(0, &regs->TxIndPro);	writel(0, &regs->TxIndCon);	writel(0, &regs->TxIndRef);	writel(0xcc000, &regs->pad10[0]);	writel(0, &regs->DrCmndPro);	writel(0, &regs->DrCmndCon);	writel(0, &regs->DwCmndPro);	writel(0, &regs->DwCmndCon);	writel(0, &regs->DwCmndRef);	writel(0, &regs->DrDataPro);	writel(0, &regs->DrDataCon);	writel(0, &regs->DrDataRef);	writel(0, &regs->DwDataPro);	writel(0, &regs->DwDataCon);	writel(0, &regs->DwDataRef);#endif	writel(0xffffffff, &regs->MbEvent);	writel(0, &regs->Event);	writel(0, &regs->TxPi);	writel(0, &regs->IpRxPi);	writel(0, &regs->EvtCon);	writel(0, &regs->EvtPrd);	rrpriv->info->evt_ctrl.pi = 0;	for (i = 0; i < CMD_RING_ENTRIES; i++)		writel(0, &regs->CmdRing[i]);/* * Why 32 ? is this not cache line size dependent? */	writel(RBURST_64|WBURST_64, &regs->PciState);	wmb();	start_pc = rr_read_eeprom_word(rrpriv,			offsetof(struct eeprom, rncd_info.FwStart));#if (DEBUG > 1)	printk("%s: Executing firmware at address 0x%06x\n",	       dev->name, start_pc);#endif	writel(start_pc + 0x800, &regs->Pc);	wmb();	udelay(5);	writel(start_pc, &regs->Pc);	wmb();	return 0;}/* * Read a string from the EEPROM. */static unsigned int rr_read_eeprom(struct rr_private *rrpriv,				unsigned long offset,				unsigned char *buf,				unsigned long length){	struct rr_regs __iomem *regs = rrpriv->regs;	u32 misc, io, host, i;	io = readl(&regs->ExtIo);	writel(0, &regs->ExtIo);	misc = readl(&regs->LocalCtrl);	writel(0, &regs->LocalCtrl);	host = readl(&regs->HostCtrl);	writel(host | HALT_NIC, &regs->HostCtrl);	mb();	for (i = 0; i < length; i++){		writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);		mb();		buf[i] = (readl(&regs->WinData) >> 24) & 0xff;		mb();	}	writel(host, &regs->HostCtrl);	writel(misc, &regs->LocalCtrl);	writel(io, &regs->ExtIo);	mb();	return i;}/* * Shortcut to read one word (4 bytes) out of the EEPROM and convert * it to our CPU byte-order. */static u32 rr_read_eeprom_word(struct rr_private *rrpriv,			    size_t offset){	__be32 word;	if ((rr_read_eeprom(rrpriv, offset,			    (unsigned 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 __iomem *regs = rrpriv->regs;	u32 misc, io, data, i, j, ready, error = 0;	io = readl(&regs->ExtIo);	writel(0, &regs->ExtIo);	misc = readl(&regs->LocalCtrl);	writel(ENABLE_EEPROM_WRITE, &regs->LocalCtrl);	mb();	for (i = 0; i < length; i++){		writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);		mb();		data = buf[i] << 24;		/*		 * Only try to write the data if it is not the same		 * value already.		 */		if ((readl(&regs->WinData) & 0xff000000) != data){			writel(data, &regs->WinData);			ready = 0;			j = 0;			mb();			while(!ready){				udelay(20);				if ((readl(&regs->WinData) & 0xff000000) ==				    data)					ready = 1;				mb();				if (j++ > 5000){					printk("data mismatch: %08x, "					       "WinData %08x\n", data,					       readl(&regs->WinData));					ready = 1;					error = 1;				}			}		}	}	writel(misc, &regs->LocalCtrl);	writel(io, &regs->ExtIo);	mb();	return error;}static int __devinit rr_init(struct net_device *dev){	struct rr_private *rrpriv;	struct rr_regs __iomem *regs;	u32 sram_size, rev;	DECLARE_MAC_BUF(mac);	rrpriv = netdev_priv(dev);	regs = rrpriv->regs;	rev = readl(&regs->FwRev);	rrpriv->fw_rev = rev;	if (rev > 0x00020024)		printk("  Firmware revision: %i.%i.%i\n", (rev >> 16),		       ((rev >> 8) & 0xff), (rev & 0xff));	else if (rev >= 0x00020000) {		printk("  Firmware revision: %i.%i.%i (2.0.37 or "		       "later is recommended)\n", (rev >> 16),		       ((rev >> 8) & 0xff), (rev & 0xff));	}else{		printk("  Firmware revision too old: %i.%i.%i, please "		       "upgrade to 2.0.37 or later.\n",		       (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff));	}#if (DEBUG > 2)	printk("  Maximum receive rings %i\n", readl(&regs->MaxRxRng));#endif	/*	 * Read the hardware address from the eeprom.  The HW address	 * is not really necessary for HIPPI but awfully convenient.	 * The pointer arithmetic to put it in dev_addr is ugly, but	 * Donald Becker does it this way for the GigE version of this	 * card and it's shorter and more portable than any	 * other method I've seen.  -VAL	 */	*(__be16 *)(dev->dev_addr) =	  htons(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA)));	*(__be32 *)(dev->dev_addr+2) =	  htonl(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA[4])));	printk("  MAC: %s\n", print_mac(mac, dev->dev_addr));	sram_size = rr_read_eeprom_word(rrpriv, 8);	printk("  SRAM size 0x%06x\n", sram_size);	return 0;}static int rr_init1(struct net_device *dev){	struct rr_private *rrpriv;	struct rr_regs __iomem *regs;	unsigned long myjif, flags;	struct cmd cmd;	u32 hostctrl;	int ecode = 0;	short i;	rrpriv = netdev_priv(dev);	regs = rrpriv->regs;

⌨️ 快捷键说明

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