e100_main.c

来自「是关于linux2.5.1的完全源码」· C语言 代码 · 共 2,319 行 · 第 1/5 页

C
2,319
字号
/*******************************************************************************This software program is available to you under a choice of one of two licenses. You may choose to be licensed under either the GNU General Public License 2.0, June 1991, available at http://www.fsf.org/copyleft/gpl.html, or the Intel BSD + Patent License, the text of which follows:Recipient has requested a license and Intel Corporation ("Intel") is willingto grant a license for the software entitled Linux Base Driver for the Intel(R) PRO/100 Family of Adapters (e100) (the "Software") being provided by Intel Corporation. The following definitions apply to this license:"Licensed Patents" means patent claims licensable by Intel Corporation which are necessarily infringed by the use of sale of the Software alone or when combined with the operating system referred to below."Recipient" means the party to whom Intel delivers this Software."Licensee" means Recipient and those third parties that receive a license to any operating system available under the GNU General Public License 2.0 or later.Copyright (c) 1999 - 2002 Intel Corporation.All rights reserved.The license is provided to Recipient and Recipient's Licensees under the following terms.Redistribution and use in source and binary forms of the Software, with or without modification, are permitted provided that the following conditions are met:Redistributions of source code of the Software may retain the above copyright notice, this list of conditions and the following disclaimer.Redistributions in binary form of the Software may reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or materials provided with the distribution.Neither the name of Intel Corporation nor the names of its contributors shall be used to endorse or promote products derived from this Software without specific prior written permission.Intel hereby grants Recipient and Licensees a non-exclusive, worldwide, royalty-free patent license under Licensed Patents to make, use, sell, offer to sell, import and otherwise transfer the Software, if any, in source code and object code form. This license shall include changes to the Software that are error corrections or other minor changes to the Software that do not add functionality or features when the Software is incorporated in any version of an operating system that has been distributed under the GNU General Public License 2.0 or later. This patent license shall apply to the combination of the Software and any operating system licensed under the GNU General Public License 2.0 or later if, at the time Intel provides the Software to Recipient, such addition of the Software to the then publicly available versions of such operating systems available under the GNU General Public License 2.0 or later (whether in gold, beta or alpha form) causes such combination to be covered by the Licensed Patents. The patent license shall not apply to any other combinations which include the Software. NO hardware per se is licensed hereunder.THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MECHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR IT CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; ANY LOSS OF USE; DATA, OR PROFITS; OR BUSINESS INTERUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*******************************************************************************Portions (C) 2002 Red Hat, Inc. under the terms of the GNU GPL v2.*******************************************************************************//***********************************************************************                                                                     ** INTEL CORPORATION                                                   **                                                                     ** This software is supplied under the terms of the license included   ** above.  All use of this driver must be in accordance with the terms ** of that license.                                                    **                                                                     ** Module Name:  e100_main.c                                           **                                                                     ** Abstract:     Functions for the driver entry points like load,      **               unload, open and close. All board specific calls made **               by the network interface section of the driver.       **                                                                     ** Environment:  This file is intended to be specific to the Linux     **               operating system.                                     **                                                                     ***********************************************************************/#undef __NO_VERSION__#include <linux/config.h>#include <net/checksum.h>#include <linux/tcp.h>#include <linux/udp.h>#include "e100.h"#include "e100_ucode.h"#include "e100_config.h"#include "e100_phy.h"#include "e100_vendor.h"#ifndef CONFIG_PROC_FS#undef E100_CONFIG_PROC_FS#endif#ifdef E100_CONFIG_PROC_FSextern int e100_create_proc_subdir(struct e100_private *);extern void e100_remove_proc_subdir(struct e100_private *);#else#define e100_create_proc_subdir(X) 0#define e100_remove_proc_subdir(X) do {} while(0)#endif#ifdef SIOCETHTOOL#define E100_ETHTOOL_IOCTL#endif#ifdef E100_ETHTOOL_IOCTLstatic int e100_do_ethtool_ioctl(struct net_device *, struct ifreq *);static void e100_get_speed_duplex_caps(struct e100_private *);static int e100_ethtool_get_settings(struct net_device *, struct ifreq *);static int e100_ethtool_set_settings(struct net_device *, struct ifreq *);#ifdef ETHTOOL_GDRVINFOstatic int e100_ethtool_get_drvinfo(struct net_device *, struct ifreq *);#endif#ifdef ETHTOOL_GEEPROMstatic int e100_ethtool_eeprom(struct net_device *, struct ifreq *);#define E100_EEPROM_MAGIC 0x1234#endif#ifdef ETHTOOL_GLINKstatic int e100_ethtool_glink(struct net_device *, struct ifreq *);#endif#ifdef ETHTOOL_NWAY_RSTstatic int e100_ethtool_nway_rst(struct net_device *, struct ifreq *);#endif#ifdef ETHTOOL_GWOLstatic int e100_ethtool_wol(struct net_device *, struct ifreq *);static unsigned char e100_setup_filter(struct e100_private *bdp);static void e100_do_wol(struct pci_dev *pcid, struct e100_private *bdp);static u16 e100_get_ip_lbytes(struct net_device *dev);extern void e100_config_wol(struct e100_private *bdp);#endif#ifdef ETHTOOL_TESTextern u32 e100_run_diag(struct net_device *dev, u64 *test_info, u32 flags);static int e100_ethtool_test(struct net_device *, struct ifreq *);#endif#ifdef ETHTOOL_GSTRINGSstatic int e100_ethtool_gstrings(struct net_device *, struct ifreq *);static char *test_strings[] = {	"E100_EEPROM_TEST_FAIL",	"E100_CHIP_TIMEOUT",	"E100_ROM_TEST_FAIL",	"E100_REG_TEST_FAIL",	"E100_MAC_TEST_FAIL",	"E100_LPBK_MAC_FAIL",	"E100_LPBK_PHY_FAIL"};#endif#endif /*E100_ETHTOOL_IOCTL */#ifdef SIOCGMIIPHY#define E100_MII_IOCTL#endif#ifdef E100_MII_IOCTL#include <linux/mii.h>static int e100_mii_ioctl(struct net_device *, struct ifreq *, int);#endif /*E100_MII_IOCTL */static unsigned char e100_delayed_exec_non_cu_cmd(struct e100_private *,						  nxmit_cb_entry_t *);static void e100_free_nontx_list(struct e100_private *);static void e100_non_tx_background(unsigned long);/* Global Data structures and variables */char e100_copyright[] __devinitdata = "Copyright (c) 2002 Intel Corporation";#define E100_VERSION  "2.0.27-pre3"#define E100_FULL_DRIVER_NAME 	"Intel(R) PRO/100 Fast Ethernet Adapter - Loadable driver, ver "const char *e100_version = E100_VERSION;const char *e100_full_driver_name = E100_FULL_DRIVER_NAME E100_VERSION;char *e100_short_driver_name = "e100";static int e100nics = 0;#ifdef CONFIG_PMstatic int e100_save_state(struct pci_dev *pcid, u32 state);static int e100_suspend(struct pci_dev *pcid, u32 state);static int e100_enable_wake(struct pci_dev *pcid, u32 state, int enable);static int e100_resume(struct pci_dev *pcid);#endif/*********************************************************************//*! This is a GCC extension to ANSI C. *  See the item "Labeled Elements in Initializers" in the section *  "Extensions to the C Language Family" of the GCC documentation. *********************************************************************/#define E100_PARAM_INIT { [0 ... E100_MAX_NIC] = -1 }/* All parameters are treated the same, as an integer array of values. * This macro just reduces the need to repeat the same declaration code * over and over (plus this helps to avoid typo bugs). */#define E100_PARAM(X, S)                                        \        static const int X[E100_MAX_NIC + 1] = E100_PARAM_INIT; \        MODULE_PARM(X, "1-" __MODULE_STRING(E100_MAX_NIC) "i"); \        MODULE_PARM_DESC(X, S);/* ====================================================================== */static u8 e100_D101M_checksum(struct e100_private *, struct sk_buff *);static u8 e100_D102_check_checksum(rfd_t *);static int e100_ioctl(struct net_device *, struct ifreq *, int);static int e100_open(struct net_device *);static int e100_close(struct net_device *);static int e100_change_mtu(struct net_device *, int);static int e100_xmit_frame(struct sk_buff *, struct net_device *);static unsigned char e100_init(struct e100_private *);static int e100_set_mac(struct net_device *, void *);struct net_device_stats *e100_get_stats(struct net_device *);static void e100intr(int, void *, struct pt_regs *);static void e100_print_brd_conf(struct e100_private *);static void e100_set_multi(struct net_device *);void e100_set_speed_duplex(struct e100_private *);char *e100_get_brand_msg(struct e100_private *);static u8 e100_pci_setup(struct pci_dev *, struct e100_private *);static u8 e100_sw_init(struct e100_private *);static unsigned char e100_alloc_space(struct e100_private *);static void e100_dealloc_space(struct e100_private *);static int e100_alloc_tcb_pool(struct e100_private *);static void e100_setup_tcb_pool(tcb_t *, unsigned int, struct e100_private *);static void e100_free_tcb_pool(struct e100_private *);static int e100_alloc_rfd_pool(struct e100_private *);static void e100_free_rfd_pool(struct e100_private *);static void e100_rd_eaddr(struct e100_private *);static void e100_rd_pwa_no(struct e100_private *);extern u16 e100_eeprom_read(struct e100_private *, u16);extern void e100_eeprom_write_block(struct e100_private *, u16, u16 *, u16);extern u16 e100_eeprom_size(struct e100_private *);static unsigned char e100_clr_cntrs(struct e100_private *);static unsigned char e100_load_microcode(struct e100_private *);static unsigned char e100_hw_init(struct e100_private *, u32);static unsigned char e100_setup_iaaddr(struct e100_private *, u8 *);static unsigned char e100_update_stats(struct e100_private *bdp);static void e100_start_ru(struct e100_private *);static void e100_dump_stats_cntrs(struct e100_private *);static void e100_check_options(int board, struct e100_private *bdp);static void e100_set_int_option(int *, int, int, int, int, char *);static void e100_set_bool_option(struct e100_private *bdp, int, u32, int,				 char *);unsigned char e100_wait_exec_cmplx(struct e100_private *, u32, u8);void e100_exec_cmplx(struct e100_private *, u32, u8);/** * e100_get_rx_struct - retrieve cell to hold skb buff from the pool * @bdp: atapter's private data struct * * Returns the new cell to hold sk_buff or %NULL. */static inline struct rx_list_elem *e100_get_rx_struct(struct e100_private *bdp){	struct rx_list_elem *rx_struct = NULL;	if (!list_empty(&(bdp->rx_struct_pool))) {		rx_struct = list_entry(bdp->rx_struct_pool.next,				       struct rx_list_elem, list_elem);		list_del(&(rx_struct->list_elem));	}	return rx_struct;}/** * e100_alloc_skb - allocate an skb for the adapter * @bdp: atapter's private data struct * * Allocates skb with enough room for rfd, and data, and reserve non-data space. * Returns the new cell with sk_buff or %NULL. */static inline struct rx_list_elem *e100_alloc_skb(struct e100_private *bdp){	struct sk_buff *new_skb;	u32 skb_size = sizeof (rfd_t);	struct rx_list_elem *rx_struct;	new_skb = (struct sk_buff *) dev_alloc_skb(skb_size);	if (new_skb) {		/* The IP data should be 		   DWORD aligned. since the ethernet header is 14 bytes long, 		   we need to reserve 2 extra bytes so that the TCP/IP headers		   will be DWORD aligned. */		skb_reserve(new_skb, 2);		if ((rx_struct = e100_get_rx_struct(bdp)) == NULL)			goto err;		rx_struct->skb = new_skb;		rx_struct->dma_addr = pci_map_single(bdp->pdev, new_skb->data,						     sizeof (rfd_t),						     PCI_DMA_FROMDEVICE);		if (!rx_struct->dma_addr)			goto err;		skb_reserve(new_skb, bdp->rfd_size);		return rx_struct;	} else {		return NULL;	}err:	dev_kfree_skb_irq(new_skb);	return NULL;}/** * e100_add_skb_to_end - add an skb to the end of our rfd list * @bdp: atapter's private data struct * @rx_struct: rx_list_elem with the new skb * * Adds a newly allocated skb to the end of our rfd list. */inline voide100_add_skb_to_end(struct e100_private *bdp, struct rx_list_elem *rx_struct){	rfd_t *rfdn;		/* The new rfd */	rfd_t *rfd;		/* The old rfd */	struct rx_list_elem *rx_struct_last;	(rx_struct->skb)->dev = bdp->device;	rfdn = RFD_POINTER(rx_struct->skb, bdp);	rfdn->rfd_header.cb_status = 0;	rfdn->rfd_header.cb_cmd = __constant_cpu_to_le16(RFD_EL_BIT);	rfdn->rfd_act_cnt = 0;	rfdn->rfd_sz = __constant_cpu_to_le16(RFD_DATA_SIZE);	pci_dma_sync_single(bdp->pdev, rx_struct->dma_addr, bdp->rfd_size,			    PCI_DMA_TODEVICE);	if (!list_empty(&(bdp->active_rx_list))) {		rx_struct_last = list_entry(bdp->active_rx_list.prev,					    struct rx_list_elem, list_elem);		rfd = RFD_POINTER(rx_struct_last->skb, bdp);		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,				    4, PCI_DMA_FROMDEVICE);		put_unaligned(cpu_to_le32(rx_struct->dma_addr),			      ((u32 *) (&(rfd->rfd_header.cb_lnk_ptr))));		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,				    8, PCI_DMA_TODEVICE);		rfd->rfd_header.cb_cmd &=			__constant_cpu_to_le16((u16) ~RFD_EL_BIT);		pci_dma_sync_single(bdp->pdev, rx_struct_last->dma_addr,				    4, PCI_DMA_TODEVICE);	}	list_add_tail(&(rx_struct->list_elem), &(bdp->active_rx_list));}static inline voide100_alloc_skbs(struct e100_private *bdp){	for (; bdp->skb_req > 0; bdp->skb_req--) {		struct rx_list_elem *rx_struct;		if ((rx_struct = e100_alloc_skb(bdp)) == NULL)			return;		e100_add_skb_to_end(bdp, rx_struct);	}}void e100_tx_srv(struct e100_private *);u32 e100_rx_srv(struct e100_private *, u32, int *);void e100_polling_tasklet(unsigned long);void e100_watchdog(struct net_device *);void e100_refresh_txthld(struct e100_private *);void e100_manage_adaptive_ifs(struct e100_private *);void e100_clear_pools(struct e100_private *);static void e100_clear_structs(struct net_device *);static inline tcb_t *e100_prepare_xmit_buff(struct e100_private *,					    struct sk_buff *);static void e100_set_multi_exec(struct net_device *dev);MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");MODULE_DESCRIPTION(E100_FULL_DRIVER_NAME E100_VERSION);MODULE_LICENSE("Dual BSD/GPL");EXPORT_NO_SYMBOLS;E100_PARAM(TxDescriptors, "Number of transmit descriptors");E100_PARAM(RxDescriptors, "Number of receive descriptors");E100_PARAM(XsumRX, "Disable or enable Receive Checksum offload");E100_PARAM(e100_speed_duplex, "Speed and Duplex settings");E100_PARAM(ucode, "Disable or enable microcode loading");E100_PARAM(ber, "Value for the BER correction algorithm");E100_PARAM(flow_control, "Disable or enable Ethernet PAUSE frames processing");E100_PARAM(IntDelay, "Value for CPU saver's interrupt delay");E100_PARAM(BundleSmallFr, "Disable or enable interrupt bundling of small frames");E100_PARAM(BundleMax, "Maximum number for CPU saver's packet bundling");E100_PARAM(IFS, "Disable or enable the adaptive IFS algorithm");E100_PARAM(RxCongestionControl, "Disable or enable switch to polling mode");E100_PARAM(PollingMaxWork, "Max number of receive packets processed on single "	   "polling call");/** * e100_exec_cmd - issue a comand * @bdp: atapter's private data struct * @scb_cmd_low: the command that is to be issued * * This general routine will issue a command to the e100. */static inline voide100_exec_cmd(struct e100_private *bdp, u8 cmd_low){	writeb(cmd_low, &(bdp->scb->scb_cmd_low));	readw(&(bdp->scb->scb_status));	/* flashes last write, read-safe */}/** * e100_wait_scb - wait for SCB to clear * @bdp: atapter's private data struct * * This routine checks to see if the e100 has accepted a command. * It does so by checking the command field in the SCB, which will * be zeroed by the e100 upon accepting a command.  The loop waits * for up to 1 millisecond for command acceptance. * * Returns: *      true if the SCB cleared within 1 millisecond. *      false if it didn't clear within 1 millisecond */unsigned chare100_wait_scb(struct e100_private *bdp){	int i;	/* loop on the scb for a few times */	for (i = 0; i < 100; i++) {		if (!readb(&bdp->scb->scb_cmd_low))			return true;		cpu_relax();	}	/* it didn't work. do it the slow way using udelay()s */	for (i = 0; i < E100_MAX_SCB_WAIT; i++) {		if (!readb(&bdp->scb->scb_cmd_low))			return true;		cpu_relax();		udelay(1);	}

⌨️ 快捷键说明

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