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

📄 islpci_dev.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  Copyright (C) 2002 Intersil Americas Inc. *  Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org> *  Copyright (C) 2003 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu> * *  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 * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * */#include <linux/module.h>#include <linux/netdevice.h>#include <linux/ethtool.h>#include <linux/pci.h>#include <linux/etherdevice.h>#include <linux/delay.h>#include <linux/if_arp.h>#include <asm/io.h>#include "prismcompat.h"#include "isl_38xx.h"#include "isl_ioctl.h"#include "islpci_dev.h"#include "islpci_mgt.h"#include "islpci_eth.h"#include "oid_mgt.h"#define ISL3877_IMAGE_FILE	"isl3877"#define ISL3886_IMAGE_FILE	"isl3886"#define ISL3890_IMAGE_FILE	"isl3890"static int prism54_bring_down(islpci_private *);static int islpci_alloc_memory(islpci_private *);static struct net_device_stats *islpci_statistics(struct net_device *);/* Temporary dummy MAC address to use until firmware is loaded. * The idea there is that some tools (such as nameif) may query * the MAC address before the netdev is 'open'. By using a valid * OUI prefix, they can process the netdev properly. * Of course, this is not the final/real MAC address. It doesn't * matter, as you are suppose to be able to change it anytime via * ndev->set_mac_address. Jean II */static const unsigned char	dummy_mac[6] = { 0x00, 0x30, 0xB4, 0x00, 0x00, 0x00 };static intisl_upload_firmware(islpci_private *priv){	u32 reg, rc;	void __iomem *device_base = priv->device_base;	/* clear the RAMBoot and the Reset bit */	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);	reg &= ~ISL38XX_CTRL_STAT_RESET;	reg &= ~ISL38XX_CTRL_STAT_RAMBOOT;	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);	wmb();	udelay(ISL38XX_WRITEIO_DELAY);	/* set the Reset bit without reading the register ! */	reg |= ISL38XX_CTRL_STAT_RESET;	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);	wmb();	udelay(ISL38XX_WRITEIO_DELAY);	/* clear the Reset bit */	reg &= ~ISL38XX_CTRL_STAT_RESET;	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);	wmb();	/* wait a while for the device to reboot */	mdelay(50);	{		const struct firmware *fw_entry = NULL;		long fw_len;		const u32 *fw_ptr;		rc = request_firmware(&fw_entry, priv->firmware, PRISM_FW_PDEV);		if (rc) {			printk(KERN_ERR			       "%s: request_firmware() failed for '%s'\n",			       "prism54", priv->firmware);			return rc;		}		/* prepare the Direct Memory Base register */		reg = ISL38XX_DEV_FIRMWARE_ADDRES;		fw_ptr = (u32 *) fw_entry->data;		fw_len = fw_entry->size;		if (fw_len % 4) {			printk(KERN_ERR			       "%s: firmware '%s' size is not multiple of 32bit, aborting!\n",			       "prism54", priv->firmware);			release_firmware(fw_entry);			return -EILSEQ; /* Illegal byte sequence  */;		}		while (fw_len > 0) {			long _fw_len =			    (fw_len >			     ISL38XX_MEMORY_WINDOW_SIZE) ?			    ISL38XX_MEMORY_WINDOW_SIZE : fw_len;			u32 __iomem *dev_fw_ptr = device_base + ISL38XX_DIRECT_MEM_WIN;			/* set the card's base address for writing the data */			isl38xx_w32_flush(device_base, reg,					  ISL38XX_DIR_MEM_BASE_REG);			wmb();	/* be paranoid */			/* increment the write address for next iteration */			reg += _fw_len;			fw_len -= _fw_len;			/* write the data to the Direct Memory Window 32bit-wise */			/* memcpy_toio() doesn't guarantee 32bit writes :-| */			while (_fw_len > 0) {				/* use non-swapping writel() */				__raw_writel(*fw_ptr, dev_fw_ptr);				fw_ptr++, dev_fw_ptr++;				_fw_len -= 4;			}			/* flush PCI posting */			(void) readl(device_base + ISL38XX_PCI_POSTING_FLUSH);			wmb();	/* be paranoid again */			BUG_ON(_fw_len != 0);		}		BUG_ON(fw_len != 0);		/* Firmware version is at offset 40 (also for "newmac") */		printk(KERN_DEBUG "%s: firmware version: %.8s\n",		       priv->ndev->name, fw_entry->data + 40);		release_firmware(fw_entry);	}	/* now reset the device	 * clear the Reset & ClkRun bit, set the RAMBoot bit */	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);	reg &= ~ISL38XX_CTRL_STAT_CLKRUN;	reg &= ~ISL38XX_CTRL_STAT_RESET;	reg |= ISL38XX_CTRL_STAT_RAMBOOT;	isl38xx_w32_flush(device_base, reg, ISL38XX_CTRL_STAT_REG);	wmb();	udelay(ISL38XX_WRITEIO_DELAY);	/* set the reset bit latches the host override and RAMBoot bits	 * into the device for operation when the reset bit is reset */	reg |= ISL38XX_CTRL_STAT_RESET;	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);	/* don't do flush PCI posting here! */	wmb();	udelay(ISL38XX_WRITEIO_DELAY);	/* clear the reset bit should start the whole circus */	reg &= ~ISL38XX_CTRL_STAT_RESET;	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);	/* don't do flush PCI posting here! */	wmb();	udelay(ISL38XX_WRITEIO_DELAY);	return 0;}/******************************************************************************    Device Interrupt Handler******************************************************************************/irqreturn_tislpci_interrupt(int irq, void *config){	u32 reg;	islpci_private *priv = config;	struct net_device *ndev = priv->ndev;	void __iomem *device = priv->device_base;	int powerstate = ISL38XX_PSM_POWERSAVE_STATE;	/* lock the interrupt handler */	spin_lock(&priv->slock);	/* received an interrupt request on a shared IRQ line	 * first check whether the device is in sleep mode */	reg = readl(device + ISL38XX_CTRL_STAT_REG);	if (reg & ISL38XX_CTRL_STAT_SLEEPMODE)		/* device is in sleep mode, IRQ was generated by someone else */	{#if VERBOSE > SHOW_ERROR_MESSAGES		DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n");#endif		spin_unlock(&priv->slock);		return IRQ_NONE;	}	/* check whether there is any source of interrupt on the device */	reg = readl(device + ISL38XX_INT_IDENT_REG);	/* also check the contents of the Interrupt Enable Register, because this	 * will filter out interrupt sources from other devices on the same irq ! */	reg &= readl(device + ISL38XX_INT_EN_REG);	reg &= ISL38XX_INT_SOURCES;	if (reg != 0) {		if (islpci_get_state(priv) != PRV_STATE_SLEEP)			powerstate = ISL38XX_PSM_ACTIVE_STATE;		/* reset the request bits in the Identification register */		isl38xx_w32_flush(device, reg, ISL38XX_INT_ACK_REG);#if VERBOSE > SHOW_ERROR_MESSAGES		DEBUG(SHOW_FUNCTION_CALLS,		      "IRQ: Identification register 0x%p 0x%x \n", device, reg);#endif		/* check for each bit in the register separately */		if (reg & ISL38XX_INT_IDENT_UPDATE) {#if VERBOSE > SHOW_ERROR_MESSAGES			/* Queue has been updated */			DEBUG(SHOW_TRACING, "IRQ: Update flag \n");			DEBUG(SHOW_QUEUE_INDEXES,			      "CB drv Qs: [%i][%i][%i][%i][%i][%i]\n",			      le32_to_cpu(priv->control_block->					  driver_curr_frag[0]),			      le32_to_cpu(priv->control_block->					  driver_curr_frag[1]),			      le32_to_cpu(priv->control_block->					  driver_curr_frag[2]),			      le32_to_cpu(priv->control_block->					  driver_curr_frag[3]),			      le32_to_cpu(priv->control_block->					  driver_curr_frag[4]),			      le32_to_cpu(priv->control_block->					  driver_curr_frag[5])			    );			DEBUG(SHOW_QUEUE_INDEXES,			      "CB dev Qs: [%i][%i][%i][%i][%i][%i]\n",			      le32_to_cpu(priv->control_block->					  device_curr_frag[0]),			      le32_to_cpu(priv->control_block->					  device_curr_frag[1]),			      le32_to_cpu(priv->control_block->					  device_curr_frag[2]),			      le32_to_cpu(priv->control_block->					  device_curr_frag[3]),			      le32_to_cpu(priv->control_block->					  device_curr_frag[4]),			      le32_to_cpu(priv->control_block->					  device_curr_frag[5])			    );#endif			/* cleanup the data low transmit queue */			islpci_eth_cleanup_transmit(priv, priv->control_block);			/* device is in active state, update the			 * powerstate flag if necessary */			powerstate = ISL38XX_PSM_ACTIVE_STATE;			/* check all three queues in priority order			 * call the PIMFOR receive function until the			 * queue is empty */			if (isl38xx_in_queue(priv->control_block,						ISL38XX_CB_RX_MGMTQ) != 0) {#if VERBOSE > SHOW_ERROR_MESSAGES				DEBUG(SHOW_TRACING,				      "Received frame in Management Queue\n");#endif				islpci_mgt_receive(ndev);				islpci_mgt_cleanup_transmit(ndev);				/* Refill slots in receive queue */				islpci_mgmt_rx_fill(ndev);				/* no need to trigger the device, next                                   islpci_mgt_transaction does it */			}			while (isl38xx_in_queue(priv->control_block,						ISL38XX_CB_RX_DATA_LQ) != 0) {#if VERBOSE > SHOW_ERROR_MESSAGES				DEBUG(SHOW_TRACING,				      "Received frame in Data Low Queue \n");#endif				islpci_eth_receive(priv);			}			/* check whether the data transmit queues were full */			if (priv->data_low_tx_full) {				/* check whether the transmit is not full anymore */				if (ISL38XX_CB_TX_QSIZE -				    isl38xx_in_queue(priv->control_block,						     ISL38XX_CB_TX_DATA_LQ) >=				    ISL38XX_MIN_QTHRESHOLD) {					/* nope, the driver is ready for more network frames */					netif_wake_queue(priv->ndev);					/* reset the full flag */					priv->data_low_tx_full = 0;				}			}		}		if (reg & ISL38XX_INT_IDENT_INIT) {			/* Device has been initialized */#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING,			      "IRQ: Init flag, device initialized \n");#endif			wake_up(&priv->reset_done);		}		if (reg & ISL38XX_INT_IDENT_SLEEP) {			/* Device intends to move to powersave state */#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING, "IRQ: Sleep flag \n");#endif			isl38xx_handle_sleep_request(priv->control_block,						     &powerstate,						     priv->device_base);		}		if (reg & ISL38XX_INT_IDENT_WAKEUP) {			/* Device has been woken up to active state */#if VERBOSE > SHOW_ERROR_MESSAGES			DEBUG(SHOW_TRACING, "IRQ: Wakeup flag \n");#endif			isl38xx_handle_wakeup(priv->control_block,					      &powerstate, priv->device_base);		}	} else {#if VERBOSE > SHOW_ERROR_MESSAGES		DEBUG(SHOW_TRACING, "Assuming someone else called the IRQ\n");#endif		spin_unlock(&priv->slock);		return IRQ_NONE;	}	/* sleep -> ready */	if (islpci_get_state(priv) == PRV_STATE_SLEEP	    && powerstate == ISL38XX_PSM_ACTIVE_STATE)		islpci_set_state(priv, PRV_STATE_READY);	/* !sleep -> sleep */	if (islpci_get_state(priv) != PRV_STATE_SLEEP	    && powerstate == ISL38XX_PSM_POWERSAVE_STATE)		islpci_set_state(priv, PRV_STATE_SLEEP);	/* unlock the interrupt handler */	spin_unlock(&priv->slock);	return IRQ_HANDLED;}/******************************************************************************    Network Interface Control & Statistical functions******************************************************************************/static intislpci_open(struct net_device *ndev){	u32 rc;	islpci_private *priv = netdev_priv(ndev);	/* reset data structures, upload firmware and reset device */	rc = islpci_reset(priv,1);	if (rc) {		prism54_bring_down(priv);		return rc; /* Returns informative message */	}	netif_start_queue(ndev);/*      netif_mark_up( ndev ); */	return 0;}static intislpci_close(struct net_device *ndev){	islpci_private *priv = netdev_priv(ndev);	printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name);	netif_stop_queue(ndev);	return prism54_bring_down(priv);}static intprism54_bring_down(islpci_private *priv){	void __iomem *device_base = priv->device_base;	u32 reg;	/* we are going to shutdown the device */	islpci_set_state(priv, PRV_STATE_PREBOOT);	/* disable all device interrupts in case they weren't */	isl38xx_disable_interrupts(priv->device_base);	/* For safety reasons, we may want to ensure that no DMA transfer is	 * currently in progress by emptying the TX and RX queues. */	/* wait until interrupts have finished executing on other CPUs */	synchronize_irq(priv->pdev->irq);	reg = readl(device_base + ISL38XX_CTRL_STAT_REG);	reg &= ~(ISL38XX_CTRL_STAT_RESET | ISL38XX_CTRL_STAT_RAMBOOT);	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);	wmb();	udelay(ISL38XX_WRITEIO_DELAY);	reg |= ISL38XX_CTRL_STAT_RESET;	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);	wmb();	udelay(ISL38XX_WRITEIO_DELAY);	/* clear the Reset bit */	reg &= ~ISL38XX_CTRL_STAT_RESET;	writel(reg, device_base + ISL38XX_CTRL_STAT_REG);	wmb();	/* wait a while for the device to reset */	schedule_timeout_uninterruptible(msecs_to_jiffies(50));	return 0;}static intislpci_upload_fw(islpci_private *priv){	islpci_state_t old_state;	u32 rc;	old_state = islpci_set_state(priv, PRV_STATE_BOOT);	printk(KERN_DEBUG "%s: uploading firmware...\n", priv->ndev->name);	rc = isl_upload_firmware(priv);	if (rc) {		/* error uploading the firmware */		printk(KERN_ERR "%s: could not upload firmware ('%s')\n",		       priv->ndev->name, priv->firmware);		islpci_set_state(priv, old_state);		return rc;	}	printk(KERN_DEBUG "%s: firmware upload complete\n",	       priv->ndev->name);	islpci_set_state(priv, PRV_STATE_POSTBOOT);	return 0;}static intislpci_reset_if(islpci_private *priv){	long remaining;	int result = -ETIME;	int count;

⌨️ 快捷键说明

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