📄 rtl_e100.c
字号:
/******************************************************************************* Copyright(c) 1999 - 2003 Intel Corporation. All rights reserved. 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. 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. The full GNU General Public License is included in this distribution in file called LICENSE. Contact Information: Linux NICS <linux.nics@intel.com> Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497*******************************************************************************//*********************************************************************** ** 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. ** ***********************************************************************//* Change Log * * 2.2.21 02/11/03 * o Removed marketing brand strings. Instead, Using generic string * "Intel(R) PRO/100 Network Connection" for all adapters. * o Implemented ethtool -S option * o Strip /proc/net/PRO_LAN_Adapters files for kernel driver * o Bug fix: Read wrong byte in EEPROM when offset is odd number * o Bug fix: PHY loopback test fails on ICH devices * o Bug fix: System panic on e100_close when repeating Hot Remove and * Add in a team * o Bug fix: Linux Bonding driver claims adapter's link loss because of * not updating last_rx field * o Bug fix: e100 does not check validity of MAC address * o New feature: added ICH5 support * * 2.1.27 11/20/02 * o Bug fix: Device command timeout due to SMBus processing during init * o Bug fix: Not setting/clearing I (Interrupt) bit in tcb correctly * o Bug fix: Not using EEPROM WoL setting as default in ethtool * o Bug fix: Not able to set autoneg on using ethtool when interface down * o Bug fix: Not able to change speed/duplex using ethtool/mii * when interface up * o Bug fix: Ethtool shows autoneg on when forced to 100/Full * o Bug fix: Compiler error when CONFIG_PROC_FS not defined * o Bug fix: 2.5.44 e100 doesn't load with preemptive kernel enabled * (sleep while holding spinlock) * o Bug fix: 2.1.24-k1 doesn't display complete statistics * o Bug fix: System panic due to NULL watchdog timer dereference during * ifconfig down, rmmod and insmod * * 2.1.24 10/7/02 **********************************************************************Changelog: June 29,2004: The file is changed by, Deyu Liu,to port the e100 adapter to RTLinux-GPLComputer Science Department, The Florida State University,USA<bullleo2003@yahoo.com>CHANGELOG: November 25, 2004 Sergio P閞ez Alca駃z(serpeal@upvnet.upv.es): o Bug fix: the use of the function schedule_timeout(HZ / 50 + 1) can cause an exception in the RTLinux context. It should only be used in the Linux context. It's been replaced with usleep(). o Bug fix: the use of the function set_current_state() is only needed in the Linux driver. Using it in the RTLinux context may cause Linux to be hanged.CHANGELOG: December 1, 2004 Sergio P閞ez Alca駃z(serpeal@upvnet.upv.es): o Driver modified to provide the O_NOBLOCK access mode (non-blocking access). o Driver modified to support the zero copy technique or not, depending on the options set in the reddopts.h. o Driver modified to support the FAKE architecture described in the reddoopts.h***********************************************************************/ #include <linux/config.h>#include <net/checksum.h>#include <linux/tcp.h>#include <linux/udp.h>#include "drivers/rtl_e100main_drv.h"#include "drivers/rtl_e100_ucode.h"#include "drivers/rtl_e100_config.h"#include "drivers/rtl_e100_phy.h"MODULE_AUTHOR("Intel Corporation, <linux.nics@intel.com>");MODULE_DESCRIPTION("Intel(R) PRO/100 Network Driver");MODULE_LICENSE("GPL");static int rt_e100_interrupted = 0, rt_e100_writting = 0;extern void e100_force_speed_duplex_to_phy(void);static void e100_get_speed_duplex_caps(void);#define E100_EEPROM_MAGIC 0x1234extern void e100_config_wol(void);/* Global Data structures and variables */char e100_copyright[] __devinitdata = "Copyright (c) 2003 Intel Corporation";char e100_driver_version[]="2.2.21-k1";const char *e100_full_driver_name = "Intel(R) PRO/100 Network Driver";char e100_short_driver_name[] = "e100";static int e100nics = 0;#ifdef CONFIG_PM/*struct notifier_block e100_notifier_reboot = { .notifier_call = e100_notify_reboot, .next = NULL, .priority = 0 };*/#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 int e100_open(struct pci_dev *);static int e100_found1(struct pci_dev *pcid);static inline void e100_tx_skb_free(tcb_t *tcb);static inline struct rx_list_elem *e100_get_rx_struct(void);static unsigned char e100_init(void);void e100_isolate_driver(void);static unsigned int e100intr(unsigned int, struct pt_regs *);static void rt_e100_print_brd_conf(void);static int e100_pci_setup(struct pci_dev *);static u8 e100_sw_init(void);static void e100_tco_workaround(void);static unsigned char e100_alloc_space(void);static void e100_dealloc_space(void);static int e100_alloc_tcb_pool(void);static void e100_setup_tcb_pool(tcb_t *, unsigned int);static void e100_free_tcb_pool(void);static int e100_alloc_rfd_pool(void);static void e100_free_rfd_pool(void);static void e100_rd_eaddr(void);static void e100_rd_pwa_no(void);extern u16 e100_eeprom_read( u16);extern void e100_eeprom_write_block( u16, u16 *, u16);extern u16 e100_eeprom_size(void);u16 e100_eeprom_calculate_chksum(void);static unsigned char e100_clr_cntrs(void);static unsigned char e100_load_microcode(void);static unsigned char e100_hw_init(void);static unsigned char e100_setup_iaaddr( u8 *);static void e100_start_ru(void);static void e100_check_options(int board);static void e100_set_int_option(int *, int, int, int, int, char *);static void e100_set_bool_option(int, u32, int, char *);unsigned char e100_wait_exec_cmplx( u32, u8, u8);void e100_exec_cmplx( u32, u8);static inline tcb_t *e100_prepare_xmit_buff(const char *buffer, size_t size);/***************************************************************************************//* This function is called in the cleanup_module function, and it must do other stuff *//* not done in the cleanup_module function in order to "close" the driver. In some *//* implementations this function could be empty. *//***************************************************************************************/static void other_stuff_closing(void){}/***************************************************************************************//* This function is used to send a packet. It writes into the internal buffers of the *//* card. *//***************************************************************************************/static int rt_eth_send_packet(const char *buffer, size_t size){ rt_e100_writting = 1; e100_prepare_xmit_buff(buffer,size); private_data.cur_tx++; rt_e100_writting = 0; return size;}/***************************************************************************************//* This function does internal initialisations of the card. It writes into internal *//* registers and checks the card capabilities. *//***************************************************************************************/int start_up_device(struct pci_dev *dev){ int rc=0; rc=e100_found1(dev);return rc;}/** * e100_get_rx_struct - retrieve cell to hold skb buff from the pool * @private_data: 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 rx_list_elem *rx_struct = NULL; if (!list_empty(&(private_data.rx_struct_pool))) { rx_struct = list_entry(private_data.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 * @private_data: 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(void){ unsigned char *new_skb; u32 skb_size = sizeof (rfd_t); struct rx_list_elem *rx_struct; new_skb = (unsigned char *) rtl_malloc(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. modified skb_reserve(new_skb, 2);*/ if ((rx_struct = e100_get_rx_struct()) == NULL) goto err; rx_struct->skb = new_skb; rx_struct->dma_addr = pci_map_single(private_data.pdev, new_skb, sizeof (rfd_t),PCI_DMA_FROMDEVICE); if (!rx_struct->dma_addr) goto err; /* reserve the header*/ rx_struct->skb += private_data.rfd_size; return rx_struct; } else { return NULL; }err: return NULL;}/** * e100_add_skb_to_end - add an skb to the end of our rfd list * @private_data: 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 rx_list_elem *rx_struct){ rfd_t *rfdn; /* The new rfd */ rfd_t *rfd; /* The old rfd */ struct rx_list_elem *rx_struct_last; rfdn = RFD_POINTER(rx_struct->skb, private_data); rfdn->rfd_header.cb_status = 0; /*indicate the last RFD*/ 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); /*for the last RFD, wrap around*/ if (private_data.skb_req==1) put_unaligned(cpu_to_le32(((struct rx_list_elem *)(private_data.active_rx_list.next))->dma_addr), ((u32 *) (&(rfdn->rfd_header.cb_lnk_ptr)))); pci_dma_sync_single(private_data.pdev, rx_struct->dma_addr, private_data.rfd_size, PCI_DMA_TODEVICE); if (!list_empty(&(private_data.active_rx_list))) { rx_struct_last = list_entry(private_data.active_rx_list.prev, struct rx_list_elem, list_elem); rfd = RFD_POINTER(rx_struct_last->skb, private_data); pci_dma_sync_single(private_data.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(private_data.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(private_data.pdev, rx_struct_last->dma_addr, 4, PCI_DMA_TODEVICE); } list_add_tail(&(rx_struct->list_elem), &(private_data.active_rx_list));}static inline voide100_alloc_skbs(void){ for (; private_data.skb_req > 0; private_data.skb_req--) { struct rx_list_elem *rx_struct; if ((rx_struct = e100_alloc_skb()) == NULL) return; e100_add_skb_to_end( rx_struct); }}void e100_tx_srv(void);u32 e100_rx_srv(void);void e100_clear_pools(void);static void e100_clear_structs(struct pci_dev *);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_exec_cmd - issue a comand * @private_data: 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(u8 cmd_low){ writeb(cmd_low, &(private_data.scb->scb_cmd_low)); readw(&(private_data.scb->scb_status)); }/** * e100_wait_scb - wait for SCB to clear * @private_data: 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(){ int i; /* loop on the scb for a few times */ for (i = 0; i < 100; i++) { if (!readb(&private_data.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(&private_data.scb->scb_cmd_low)) return true; cpu_relax(); udelay(1); } return false;}/** * e100_wait_exec_simple - issue a command * @private_data: 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 after waiting for * the previous command to finish. * * Returns: * true if the command was issued to the chip successfully * false if the command was not issued to the chip */inline unsigned chare100_wait_exec_simple(u8 scb_cmd_low){ /*wait one scb command to be ACKed*/ if (!e100_wait_scb()) { rtl_printf(KERN_DEBUG "e100: e100_wait_exec_simple: failed\n");#ifdef E100_CU_DEBUG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -