?? s2io.c
字號:
/************************************************************************ * s2io.c: A Linux PCI-X Ethernet driver for S2IO 10GbE Server NIC * Copyright(c) 2002-2005 S2IO Technologies * This software may be used and distributed according to the terms of * the GNU General Public License (GPL), incorporated herein by reference. * Drivers based on or derived from this code fall under the GPL and must * retain the authorship, copyright and license notice. This file is not * a complete program and may only be used when the entire operating * system is licensed under the GPL. * See the file COPYING in this distribution for more information. * * Credits: * Jeff Garzik : For pointing out the improper error condition * check in the s2io_xmit routine and also some * issues in the Tx watch dog function. Also for * patiently answering all those innumerable * questions regaring the 2.6 porting issues. * Stephen Hemminger : Providing proper 2.6 porting mechanism for some * macros available only in 2.6 Kernel. * Francois Romieu : For pointing out all code part that were * deprecated and also styling related comments. * Grant Grundler : For helping me get rid of some Architecture * dependent code. * Christopher Hellwig : Some more 2.6 specific issues in the driver. * * The module loadable parameters that are supported by the driver and a brief * explaination of all the variables. * ring_num : This can be used to program the number of receive rings used * in the driver. * frame_len: This is an array of size 8. Using this we can set the maximum * size of the received frame that can be steered into the corrsponding * receive ring. * ring_len: This defines the number of descriptors each ring can have. This * is also an array of size 8. * fifo_num: This defines the number of Tx FIFOs thats used int the driver. * fifo_len: This too is an array of 8. Each element defines the number of * Tx descriptors that can be associated with each corresponding FIFO. * latency_timer: This input is programmed into the Latency timer register * in PCI Configuration space. ************************************************************************/#include<linux/config.h>#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/etherdevice.h>#include<linux/skbuff.h>#include<linux/init.h>#include<linux/delay.h>#include<linux/stddef.h>#include<linux/ioctl.h>#include<linux/timex.h>#include<linux/sched.h>#include<linux/ethtool.h>#include<asm/system.h>#include<asm/uaccess.h>#include<linux/version.h>#include<asm/io.h>#include<linux/workqueue.h>/* local include */#include "s2io.h"#include "s2io-regs.h"/* S2io Driver name & version. */static char s2io_driver_name[] = "s2io";static char s2io_driver_version[] = "Version 1.0";#define LINK_IS_UP(val64) (!(val64 & (ADAPTER_STATUS_RMAC_REMOTE_FAULT | \ ADAPTER_STATUS_RMAC_LOCAL_FAULT)))#define TASKLET_IN_USE test_and_set_bit(0, \ (unsigned long *)(&sp->tasklet_status))#define PANIC 1#define LOW 2static inline int rx_buffer_level(nic_t * sp, int rxb_size, int ring){ int level = 0; if ((sp->pkt_cnt[ring] - rxb_size) > 128) { level = LOW; if (rxb_size < sp->pkt_cnt[ring] / 8) level = PANIC; } return level;}/* Ethtool related variables and Macros. */static char s2io_gstrings[][ETH_GSTRING_LEN] = { "Register test\t(offline)", "Eeprom test\t(offline)", "Link test\t(online)", "RLDRAM test\t(offline)", "BIST Test\t(offline)"};static char ethtool_stats_keys[][ETH_GSTRING_LEN] = { "tmac_frms", "tmac_data_octets", "tmac_drop_frms", "tmac_mcst_frms", "tmac_bcst_frms", "tmac_pause_ctrl_frms", "tmac_any_err_frms", "tmac_vld_ip_octets", "tmac_vld_ip", "tmac_drop_ip", "tmac_icmp", "tmac_rst_tcp", "tmac_tcp", "tmac_udp", "rmac_vld_frms", "rmac_data_octets", "rmac_fcs_err_frms", "rmac_drop_frms", "rmac_vld_mcst_frms", "rmac_vld_bcst_frms", "rmac_in_rng_len_err_frms", "rmac_long_frms", "rmac_pause_ctrl_frms", "rmac_discarded_frms", "rmac_usized_frms", "rmac_osized_frms", "rmac_frag_frms", "rmac_jabber_frms", "rmac_ip", "rmac_ip_octets", "rmac_hdr_err_ip", "rmac_drop_ip", "rmac_icmp", "rmac_tcp", "rmac_udp", "rmac_err_drp_udp", "rmac_pause_cnt", "rmac_accepted_ip", "rmac_err_tcp",};#define S2IO_STAT_LEN sizeof(ethtool_stats_keys)/ ETH_GSTRING_LEN#define S2IO_STAT_STRINGS_LEN S2IO_STAT_LEN * ETH_GSTRING_LEN#define S2IO_TEST_LEN sizeof(s2io_gstrings) / ETH_GSTRING_LEN#define S2IO_STRINGS_LEN S2IO_TEST_LEN * ETH_GSTRING_LEN/* Constants to be programmed into the Xena's registers to configure * the XAUI. */#define SWITCH_SIGN 0xA5A5A5A5A5A5A5A5ULL#define END_SIGN 0x0static u64 default_mdio_cfg[] = { /* Reset PMA PLL */ 0xC001010000000000ULL, 0xC0010100000000E0ULL, 0xC0010100008000E4ULL, /* Remove Reset from PMA PLL */ 0xC001010000000000ULL, 0xC0010100000000E0ULL, 0xC0010100000000E4ULL, END_SIGN};static u64 default_dtx_cfg[] = { 0x8000051500000000ULL, 0x80000515000000E0ULL, 0x80000515D93500E4ULL, 0x8001051500000000ULL, 0x80010515000000E0ULL, 0x80010515001E00E4ULL, 0x8002051500000000ULL, 0x80020515000000E0ULL, 0x80020515F21000E4ULL, /* Set PADLOOPBACKN */ 0x8002051500000000ULL, 0x80020515000000E0ULL, 0x80020515B20000E4ULL, 0x8003051500000000ULL, 0x80030515000000E0ULL, 0x80030515B20000E4ULL, 0x8004051500000000ULL, 0x80040515000000E0ULL, 0x80040515B20000E4ULL, 0x8005051500000000ULL, 0x80050515000000E0ULL, 0x80050515B20000E4ULL, SWITCH_SIGN, /* Remove PADLOOPBACKN */ 0x8002051500000000ULL, 0x80020515000000E0ULL, 0x80020515F20000E4ULL, 0x8003051500000000ULL, 0x80030515000000E0ULL, 0x80030515F20000E4ULL, 0x8004051500000000ULL, 0x80040515000000E0ULL, 0x80040515F20000E4ULL, 0x8005051500000000ULL, 0x80050515000000E0ULL, 0x80050515F20000E4ULL, END_SIGN};/* Constants for Fixing the MacAddress problem seen mostly on * Alpha machines. */static u64 fix_mac[] = { 0x0060000000000000ULL, 0x0060600000000000ULL, 0x0040600000000000ULL, 0x0000600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0060600000000000ULL, 0x0020600000000000ULL, 0x0000600000000000ULL, 0x0040600000000000ULL, 0x0060600000000000ULL, END_SIGN};/* Module Loadable parameters. */static u32 ring_num;static u32 frame_len[MAX_RX_RINGS];static u32 ring_len[MAX_RX_RINGS];static u32 fifo_num;static u32 fifo_len[MAX_TX_FIFOS];static u32 rx_prio;static u32 tx_prio;static u8 latency_timer = 0;/* * S2IO device table. * This table lists all the devices that this driver supports. */static struct pci_device_id s2io_tbl[] __devinitdata = { {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_WIN, PCI_ANY_ID, PCI_ANY_ID}, {PCI_VENDOR_ID_S2IO, PCI_DEVICE_ID_S2IO_UNI, PCI_ANY_ID, PCI_ANY_ID}, {0,}};MODULE_DEVICE_TABLE(pci, s2io_tbl);static struct pci_driver s2io_driver = { .name = "S2IO", .id_table = s2io_tbl, .probe = s2io_init_nic, .remove = __devexit_p(s2io_rem_nic),};/* * Input Arguments: * Device private variable. * Return Value: * SUCCESS on success and an appropriate -ve value on failure. * Description: * The function allocates the all memory areas shared * between the NIC and the driver. This includes Tx descriptors, * Rx descriptors and the statistics block. */static int initSharedMem(struct s2io_nic *nic){ u32 size; void *tmp_v_addr, *tmp_v_addr_next; dma_addr_t tmp_p_addr, tmp_p_addr_next; RxD_block_t *pre_rxd_blk = NULL; int i, j, blk_cnt; struct net_device *dev = nic->dev; mac_info_t *mac_control; struct config_param *config; mac_control = &nic->mac_control; config = &nic->config; /* Allocation and initialization of TXDLs in FIOFs */ size = 0; for (i = 0; i < config->TxFIFONum; i++) { size += config->TxCfg[i].FifoLen; } if (size > MAX_AVAILABLE_TXDS) { DBG_PRINT(ERR_DBG, "%s: Total number of Tx FIFOs ", dev->name); DBG_PRINT(ERR_DBG, "exceeds the maximum value "); DBG_PRINT(ERR_DBG, "that can be used\n"); return FAILURE; } size *= (sizeof(TxD_t) * config->MaxTxDs); mac_control->txd_list_mem = pci_alloc_consistent (nic->pdev, size, &mac_control->txd_list_mem_phy); if (!mac_control->txd_list_mem) { return -ENOMEM; } mac_control->txd_list_mem_sz = size; tmp_v_addr = mac_control->txd_list_mem; tmp_p_addr = mac_control->txd_list_mem_phy; memset(tmp_v_addr, 0, size); DBG_PRINT(INIT_DBG, "%s:List Mem PHY: 0x%llx\n", dev->name, (unsigned long long) tmp_p_addr); for (i = 0; i < config->TxFIFONum; i++) { mac_control->txdl_start_phy[i] = tmp_p_addr; mac_control->txdl_start[i] = (TxD_t *) tmp_v_addr; mac_control->tx_curr_put_info[i].offset = 0; mac_control->tx_curr_put_info[i].fifo_len = config->TxCfg[i].FifoLen - 1; mac_control->tx_curr_get_info[i].offset = 0; mac_control->tx_curr_get_info[i].fifo_len = config->TxCfg[i].FifoLen - 1; tmp_p_addr += (config->TxCfg[i].FifoLen * (sizeof(TxD_t)) * config->MaxTxDs); tmp_v_addr += (config->TxCfg[i].FifoLen * (sizeof(TxD_t)) * config->MaxTxDs); } /* Allocation and initialization of RXDs in Rings */ size = 0; for (i = 0; i < config->RxRingNum; i++) { if (config->RxCfg[i].NumRxd % (MAX_RXDS_PER_BLOCK + 1)) { DBG_PRINT(ERR_DBG, "%s: RxD count of ", dev->name); DBG_PRINT(ERR_DBG, "Ring%d is not a multiple of ", i); DBG_PRINT(ERR_DBG, "RxDs per Block"); return FAILURE; } size += config->RxCfg[i].NumRxd; nic->block_count[i] = config->RxCfg[i].NumRxd / (MAX_RXDS_PER_BLOCK + 1); nic->pkt_cnt[i] = config->RxCfg[i].NumRxd - nic->block_count[i]; } size = (size * (sizeof(RxD_t))); mac_control->rxd_ring_mem_sz = size; for (i = 0; i < config->RxRingNum; i++) { mac_control->rx_curr_get_info[i].block_index = 0; mac_control->rx_curr_get_info[i].offset = 0; mac_control->rx_curr_get_info[i].ring_len = config->RxCfg[i].NumRxd - 1; mac_control->rx_curr_put_info[i].block_index = 0; mac_control->rx_curr_put_info[i].offset = 0; mac_control->rx_curr_put_info[i].ring_len = config->RxCfg[i].NumRxd - 1; blk_cnt = config->RxCfg[i].NumRxd / (MAX_RXDS_PER_BLOCK + 1); /* Allocating all the Rx blocks */ for (j = 0; j < blk_cnt; j++) { size = (MAX_RXDS_PER_BLOCK + 1) * (sizeof(RxD_t)); tmp_v_addr = pci_alloc_consistent(nic->pdev, size, &tmp_p_addr); if (tmp_v_addr == NULL) { /* In case of failure, freeSharedMem() * is called, which should free any * memory that was alloced till the * failure happened. */ nic->rx_blocks[i][j].block_virt_addr = tmp_v_addr; return -ENOMEM; } memset(tmp_v_addr, 0, size); nic->rx_blocks[i][j].block_virt_addr = tmp_v_addr; nic->rx_blocks[i][j].block_dma_addr = tmp_p_addr; } /* Interlinking all Rx Blocks */ for (j = 0; j < blk_cnt; j++) { tmp_v_addr = nic->rx_blocks[i][j].block_virt_addr; tmp_v_addr_next = nic->rx_blocks[i][(j + 1) % blk_cnt].block_virt_addr; tmp_p_addr = nic->rx_blocks[i][j].block_dma_addr; tmp_p_addr_next = nic->rx_blocks[i][(j + 1) % blk_cnt].block_dma_addr; pre_rxd_blk = (RxD_block_t *) tmp_v_addr; pre_rxd_blk->reserved_1 = END_OF_BLOCK; /* last RxD * marker. */ pre_rxd_blk->reserved_2_pNext_RxD_block = (unsigned long) tmp_v_addr_next; pre_rxd_blk->pNext_RxD_Blk_physical = (u64) tmp_p_addr_next; } } /* Allocation and initialization of Statistics block */ size = sizeof(StatInfo_t); mac_control->stats_mem = pci_alloc_consistent (nic->pdev, size, &mac_control->stats_mem_phy); if (!mac_control->stats_mem) { /* In case of failure, freeSharedMem() is called, which * should free any memory that was alloced till the * failure happened. */ return -ENOMEM; } mac_control->stats_mem_sz = size; tmp_v_addr = mac_control->stats_mem; mac_control->StatsInfo = (StatInfo_t *) tmp_v_addr; memset(tmp_v_addr, 0, size); DBG_PRINT(INIT_DBG, "%s:Ring Mem PHY: 0x%llx\n", dev->name, (unsigned long long) tmp_p_addr); return SUCCESS;}/* * Input Arguments: * Device peivate variable. * Return Value: * NONE * Description: * This function is to free all memory locations allocated by * the initSharedMem() function and return it to the kernel. */static void freeSharedMem(struct s2io_nic *nic){ int i, j, blk_cnt, size; void *tmp_v_addr; dma_addr_t tmp_p_addr; mac_info_t *mac_control; struct config_param *config; if (!nic) return; mac_control = &nic->mac_control; config = &nic->config; if (mac_control->txd_list_mem) { pci_free_consistent(nic->pdev, mac_control->txd_list_mem_sz, mac_control->txd_list_mem, mac_control->txd_list_mem_phy); } size = (MAX_RXDS_PER_BLOCK + 1) * (sizeof(RxD_t)); for (i = 0; i < config->RxRingNum; i++) { blk_cnt = nic->block_count[i]; for (j = 0; j < blk_cnt; j++) { tmp_v_addr = nic->rx_blocks[i][j].block_virt_addr; tmp_p_addr = nic->rx_blocks[i][j].block_dma_addr; if (tmp_v_addr == NULL) break; pci_free_consistent(nic->pdev, size,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -