/************************************************************************ * s2io.c: A Linux PCI-X Ethernet driver for Neterion 10GbE Server NIC * Copyright(c) 2002-2010 Exar Corp. * * 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 * explanation of all the variables. * * rx_ring_num : This can be used to program the number of receive rings used * in the driver. * rx_ring_sz: This defines the number of receive blocks each ring can have. * This is also an array of size 8. * rx_ring_mode: This defines the operation mode of all 8 rings. The valid * values are 1, 2. * tx_fifo_num: This defines the number of Tx FIFOs thats used int the driver. * tx_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. * intr_type: This defines the type of interrupt. The values can be 0(INTA), * 2(MSI_X). Default value is '2(MSI_X)' * lro_max_pkts: This parameter defines maximum number of packets can be * aggregated as a single large packet * napi: This parameter used to enable/disable NAPI (polling Rx) * Possible values '1' for enable and '0' for disable. Default is '1' * vlan_tag_strip: This can be used to enable or disable vlan stripping. * Possible values '1' for enable , '0' for disable. * Default is '2' - which means disable in promisc mode * and enable in non-promiscuous mode. * multiq: This parameter used to enable/disable MULTIQUEUE support. * Possible values '1' for enable and '0' for disable. Default is '0'
************************************************************************/
/* Module Loadable parameters. */
S2IO_PARM_INT(tx_fifo_num, FIFO_DEFAULT_NUM);
S2IO_PARM_INT(rx_ring_num, 1);
S2IO_PARM_INT(multiq, 0);
S2IO_PARM_INT(rx_ring_mode, 1);
S2IO_PARM_INT(use_continuous_tx_intrs, 1);
S2IO_PARM_INT(rmac_pause_time, 0x100);
S2IO_PARM_INT(mc_pause_threshold_q0q3, 187);
S2IO_PARM_INT(mc_pause_threshold_q4q7, 187);
S2IO_PARM_INT(shared_splits, 0);
S2IO_PARM_INT(tmac_util_period, 5);
S2IO_PARM_INT(rmac_util_period, 5);
S2IO_PARM_INT(l3l4hdr_size, 128); /* 0 is no steering, 1 is Priority steering, 2 is Default steering */
S2IO_PARM_INT(tx_steering_type, TX_DEFAULT_STEERING); /* Frequency of Rx desc syncs expressed as power of 2 */
S2IO_PARM_INT(rxsync_frequency, 3); /* Interrupt type. Values can be 0(INTA), 2(MSI_X) */
S2IO_PARM_INT(intr_type, 2); /* Large receive offload feature */
/* Max pkts to be aggregated by LRO at one time. If not specified, * aggregation happens until we hit max IP pkt size(64K)
*/
S2IO_PARM_INT(lro_max_pkts, 0xFFFF);
S2IO_PARM_INT(indicate_max_pkts, 0);
/* A simplifier macro used both by init and free shared_mem Fns(). */ #define TXD_MEM_PAGE_CNT(len, per_each) DIV_ROUND_UP(len, per_each)
/* netqueue manipulation helper functions */ staticinlinevoid s2io_stop_all_tx_queue(struct s2io_nic *sp)
{ if (!sp->config.multiq) { int i;
for (i = 0; i < sp->config.tx_fifo_num; i++)
sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_STOP;
}
netif_tx_stop_all_queues(sp->dev);
}
staticinlinevoid s2io_stop_tx_queue(struct s2io_nic *sp, int fifo_no)
{ if (!sp->config.multiq)
sp->mac_control.fifos[fifo_no].queue_state =
FIFO_QUEUE_STOP;
netif_tx_stop_all_queues(sp->dev);
}
staticinlinevoid s2io_start_all_tx_queue(struct s2io_nic *sp)
{ if (!sp->config.multiq) { int i;
for (i = 0; i < sp->config.tx_fifo_num; i++)
sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
}
netif_tx_start_all_queues(sp->dev);
}
staticinlinevoid s2io_wake_all_tx_queue(struct s2io_nic *sp)
{ if (!sp->config.multiq) { int i;
for (i = 0; i < sp->config.tx_fifo_num; i++)
sp->mac_control.fifos[i].queue_state = FIFO_QUEUE_START;
}
netif_tx_wake_all_queues(sp->dev);
}
staticinlinevoid s2io_wake_tx_queue( struct fifo_info *fifo, int cnt, u8 multiq)
{
if (multiq) { if (cnt && __netif_subqueue_stopped(fifo->dev, fifo->fifo_no))
netif_wake_subqueue(fifo->dev, fifo->fifo_no);
} elseif (cnt && (fifo->queue_state == FIFO_QUEUE_STOP)) { if (netif_queue_stopped(fifo->dev)) {
fifo->queue_state = FIFO_QUEUE_START;
netif_wake_queue(fifo->dev);
}
}
}
/** * init_shared_mem - Allocation and Initialization of Memory * @nic: Device private variable. * Description: The function allocates all the memory areas shared * between the NIC and the driver. This includes Tx descriptors, * Rx descriptors and the statistics block.
*/
/* Allocation and initialization of TXDLs in FIFOs */
size = 0; for (i = 0; i < config->tx_fifo_num; i++) { struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];
size += tx_cfg->fifo_len;
} if (size > MAX_AVAILABLE_TXDS) {
DBG_PRINT(ERR_DBG, "Too many TxDs requested: %d, max supported: %d\n",
size, MAX_AVAILABLE_TXDS); return -EINVAL;
}
size = 0; for (i = 0; i < config->tx_fifo_num; i++) { struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];
size = tx_cfg->fifo_len; /* * Legal values are from 2 to 8192
*/ if (size < 2) {
DBG_PRINT(ERR_DBG, "Fifo %d: Invalid length (%d) - " "Valid lengths are 2 through 8192\n",
i, size); return -EINVAL;
}
}
blk_cnt = rx_cfg->num_rxd / (rxd_count[nic->rxd_mode] + 1); /* Allocating all the Rx blocks */ for (j = 0; j < blk_cnt; j++) { struct rx_block_info *rx_blocks; int l;
rx_blocks = &ring->rx_blocks[j];
size = SIZE_OF_BLOCK; /* size is always page size */
tmp_v_addr = dma_alloc_coherent(&nic->pdev->dev, size,
&tmp_p_addr, GFP_KERNEL); if (tmp_v_addr == NULL) { /* * In case of failure, free_shared_mem() * is called, which should free any * memory that was alloced till the * failure happened.
*/
rx_blocks->block_virt_addr = tmp_v_addr; return -ENOMEM;
}
mem_allocated += size;
/* Allocation and initialization of Statistics block */
size = sizeof(struct stat_block);
mac_control->stats_mem =
dma_alloc_coherent(&nic->pdev->dev, size,
&mac_control->stats_mem_phy, GFP_KERNEL);
if (!mac_control->stats_mem) { /* * In case of failure, free_shared_mem() is called, which * should free any memory that was alloced till the * failure happened.
*/ return -ENOMEM;
}
mem_allocated += size;
mac_control->stats_mem_sz = size;
/** * free_shared_mem - Free the allocated Memory * @nic: Device private variable. * Description: This function is to free all memory locations allocated by * the init_shared_mem() function and return it to the kernel.
*/
staticvoid free_shared_mem(struct s2io_nic *nic)
{ int i, j, blk_cnt, size; void *tmp_v_addr;
dma_addr_t tmp_p_addr; int lst_size, lst_per_page; struct net_device *dev; int page_num = 0; struct config_param *config; struct mac_info *mac_control; struct stat_block *stats; struct swStat *swstats;
if (s2io_on_nec_bridge(nic->pdev)) {
DBG_PRINT(ERR_DBG, "%s: Device is on PCI-E bus\n",
nic->dev->name); return mode;
}
switch (mode) { case PCI_MODE_PCI_33:
pcimode = "33MHz PCI bus"; break; case PCI_MODE_PCI_66:
pcimode = "66MHz PCI bus"; break; case PCI_MODE_PCIX_M1_66:
pcimode = "66MHz PCIX(M1) bus"; break; case PCI_MODE_PCIX_M1_100:
pcimode = "100MHz PCIX(M1) bus"; break; case PCI_MODE_PCIX_M1_133:
pcimode = "133MHz PCIX(M1) bus"; break; case PCI_MODE_PCIX_M2_66:
pcimode = "133MHz PCIX(M2) bus"; break; case PCI_MODE_PCIX_M2_100:
pcimode = "200MHz PCIX(M2) bus"; break; case PCI_MODE_PCIX_M2_133:
pcimode = "266MHz PCIX(M2) bus"; break; default:
pcimode = "unsupported bus!";
mode = -1;
}
DBG_PRINT(ERR_DBG, "%s: Device is on %d bit %s\n",
nic->dev->name, val64 & PCI_MODE_32_BITS ? 32 : 64, pcimode);
return mode;
}
/** * init_tti - Initialization transmit traffic interrupt scheme * @nic: device private variable * @link: link status (UP/DOWN) used to enable/disable continuous * transmit interrupts * @may_sleep: parameter indicates if sleeping when waiting for * command complete * Description: The function configures transmit traffic interrupts * Return Value: SUCCESS on success and * '-1' on failure
*/
for (i = 0; i < config->tx_fifo_num; i++) { /* * TTI Initialization. Default Tx timer gets us about * 250 interrupts per sec. Continuous interrupts are enabled * by default.
*/ if (nic->device_type == XFRAME_II_DEVICE) { int count = (nic->config.bus_speed * 125)/2;
val64 = TTI_DATA1_MEM_TX_TIMER_VAL(count);
} else
val64 = TTI_DATA1_MEM_TX_TIMER_VAL(0x2078);
val64 |= TTI_DATA1_MEM_TX_URNG_A(0xA) |
TTI_DATA1_MEM_TX_URNG_B(0x10) |
TTI_DATA1_MEM_TX_URNG_C(0x30) |
TTI_DATA1_MEM_TX_TIMER_AC_EN; if (i == 0) if (use_continuous_tx_intrs && (link == LINK_UP))
val64 |= TTI_DATA1_MEM_TX_TIMER_CI_EN;
writeq(val64, &bar0->tti_data1_mem);
if (wait_for_cmd_complete(&bar0->tti_command_mem,
TTI_CMD_MEM_STROBE_NEW_CMD,
S2IO_BIT_RESET, may_sleep) != SUCCESS) return FAILURE;
}
return SUCCESS;
}
/** * init_nic - Initialization of hardware * @nic: device private variable * Description: The function sequentially configures every block * of the H/W from their reset values. * Return Value: SUCCESS on success and * '-1' on failure (endian settings incorrect).
*/
/* to set the swapper controle on the card */ if (s2io_set_swapper(nic)) {
DBG_PRINT(ERR_DBG, "ERROR: Setting Swapper failed\n"); return -EIO;
}
/* * Herc requires EOI to be removed from reset before XGXS, so..
*/ if (nic->device_type & XFRAME_II_DEVICE) {
val64 = 0xA500000000ULL;
writeq(val64, &bar0->sw_reset);
msleep(500);
val64 = readq(&bar0->sw_reset);
}
/* Remove XGXS from reset state */
val64 = 0;
writeq(val64, &bar0->sw_reset);
msleep(500);
val64 = readq(&bar0->sw_reset);
/* Ensure that it's safe to access registers by checking * RIC_RUNNING bit is reset. Check is valid only for XframeII.
*/ if (nic->device_type == XFRAME_II_DEVICE) { for (i = 0; i < 50; i++) {
val64 = readq(&bar0->adapter_status); if (!(val64 & ADAPTER_STATUS_RIC_RUNNING)) break;
msleep(10);
} if (i == 50) return -ENODEV;
}
/* Filling the Rx round robin registers as per the * number of Rings and steering based on QoS with * equal priority.
*/ switch (config->rx_ring_num) { case 1:
val64 = 0x0;
writeq(val64, &bar0->rx_w_round_robin_0);
writeq(val64, &bar0->rx_w_round_robin_1);
writeq(val64, &bar0->rx_w_round_robin_2);
writeq(val64, &bar0->rx_w_round_robin_3);
writeq(val64, &bar0->rx_w_round_robin_4);
/* UDP Fix */
val64 = 0; for (i = 0; i < 8; i++)
writeq(val64, &bar0->rts_frm_len_n[i]);
/* Set the default rts frame length for the rings configured */
val64 = MAC_RTS_FRM_LEN_SET(dev->mtu+22); for (i = 0 ; i < config->rx_ring_num ; i++)
writeq(val64, &bar0->rts_frm_len_n[i]);
/* Set the frame length for the configured rings * desired by the user
*/ for (i = 0; i < config->rx_ring_num; i++) { /* If rts_frm_len[i] == 0 then it is assumed that user not * specified frame length steering. * If the user provides the frame length then program * the rts_frm_len register for those values or else * leave it as it is.
*/ if (rts_frm_len[i] != 0) {
writeq(MAC_RTS_FRM_LEN_SET(rts_frm_len[i]),
&bar0->rts_frm_len_n[i]);
}
}
/* Disable differentiated services steering logic */ for (i = 0; i < 64; i++) { if (rts_ds_steer(nic, i, 0) == FAILURE) {
DBG_PRINT(ERR_DBG, "%s: rts_ds_steer failed on codepoint %d\n",
dev->name, i); return -ENODEV;
}
}
/* Program statistics memory */
writeq(mac_control->stats_mem_phy, &bar0->stat_addr);
/* * Initializing the sampling rate for the device to calculate the * bandwidth utilization.
*/
val64 = MAC_TX_LINK_UTIL_VAL(tmac_util_period) |
MAC_RX_LINK_UTIL_VAL(rmac_util_period);
writeq(val64, &bar0->mac_link_util);
/* * Initializing the Transmit and Receive Traffic Interrupt * Scheme.
*/
for (i = 0; i < config->rx_ring_num; i++) {
val64 = RTI_CMD_MEM_WE |
RTI_CMD_MEM_STROBE_NEW_CMD |
RTI_CMD_MEM_OFFSET(i);
writeq(val64, &bar0->rti_command_mem);
/* * Once the operation completes, the Strobe bit of the * command register will be reset. We poll for this * particular condition. We wait for a maximum of 500ms * for the operation to complete, if it's not complete * by then we return error.
*/
time = 0; while (true) {
val64 = readq(&bar0->rti_command_mem); if (!(val64 & RTI_CMD_MEM_STROBE_NEW_CMD)) break;
/* * Initializing proper values as Pause threshold into all * the 8 Queues on Rx side.
*/
writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q0q3);
writeq(0xffbbffbbffbbffbbULL, &bar0->mc_pause_thresh_q4q7);
/* * Set the time value to be inserted in the pause frame * generated by xena.
*/
val64 = readq(&bar0->rmac_pause_cfg);
val64 &= ~(RMAC_PAUSE_HG_PTIME(0xffff));
val64 |= RMAC_PAUSE_HG_PTIME(nic->mac_control.rmac_pause_time);
writeq(val64, &bar0->rmac_pause_cfg);
/* * Set the Threshold Limit for Generating the pause frame * If the amount of data in any Queue exceeds ratio of * (mac_control.mc_pause_threshold_q0q3 or q4q7)/256 * pause frame is generated
*/
val64 = 0; for (i = 0; i < 4; i++) {
val64 |= (((u64)0xFF00 |
nic->mac_control.mc_pause_threshold_q0q3)
<< (i * 2 * 8));
}
writeq(val64, &bar0->mc_pause_thresh_q0q3);
val64 = 0; for (i = 0; i < 4; i++) {
val64 |= (((u64)0xFF00 |
nic->mac_control.mc_pause_threshold_q4q7)
<< (i * 2 * 8));
}
writeq(val64, &bar0->mc_pause_thresh_q4q7);
/* * TxDMA will stop Read request if the number of read split has * exceeded the limit pointed by shared_splits
*/
val64 = readq(&bar0->pic_control);
val64 |= PIC_CNTL_SHARED_SPLITS(shared_splits);
writeq(val64, &bar0->pic_control);
/* * Programming the Herc to split every write transaction * that does not start on an ADB to reduce disconnects.
*/ if (nic->device_type == XFRAME_II_DEVICE) {
val64 = FAULT_BEHAVIOUR | EXT_REQ_EN |
MISC_LINK_STABILITY_PRD(3);
writeq(val64, &bar0->misc_control);
val64 = readq(&bar0->pic_control2);
val64 &= ~(s2BIT(13)|s2BIT(14)|s2BIT(15));
writeq(val64, &bar0->pic_control2);
} if (strstr(nic->product_name, "CX4")) {
val64 = TMAC_AVG_IPG(0x17);
writeq(val64, &bar0->tmac_avg_ipg);
}
/* Remove this line when alarm interrupts are enabled */
nic->general_int_mask = 0;
}
/** * en_dis_able_nic_intrs - Enable or Disable the interrupts * @nic: device private variable, * @mask: A mask indicating which Intr block must be modified and, * @flag: A flag indicating whether to enable or disable the Intrs. * Description: This function will either disable or enable the interrupts * depending on the flag argument. The mask argument can be used to * enable/disable any Intr block. * Return Value: NONE.
*/
/** * verify_pcc_quiescent- Checks for PCC quiescent state * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @flag: boolean controlling function path * Return: 1 If PCC is quiescence * 0 If PCC is not quiescence
*/ staticint verify_pcc_quiescent(struct s2io_nic *sp, int flag)
{ int ret = 0, herc; struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = readq(&bar0->adapter_status);
herc = (sp->device_type == XFRAME_II_DEVICE);
if (flag == false) { if ((!herc && (sp->pdev->revision >= 4)) || herc) { if (!(val64 & ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
} else { if (!(val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
ret = 1;
}
} else { if ((!herc && (sp->pdev->revision >= 4)) || herc) { if (((val64 & ADAPTER_STATUS_RMAC_PCC_IDLE) ==
ADAPTER_STATUS_RMAC_PCC_IDLE))
ret = 1;
} else { if (((val64 & ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE) ==
ADAPTER_STATUS_RMAC_PCC_FOUR_IDLE))
ret = 1;
}
}
return ret;
} /** * verify_xena_quiescence - Checks whether the H/W is ready * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * Description: Returns whether the H/W is ready to go or not. Depending * on whether adapter enable bit was written or not the comparison * differs and the calling function passes the input argument flag to * indicate this. * Return: 1 If xena is quiescence * 0 If Xena is not quiescence
*/
if (!(val64 & ADAPTER_STATUS_TDMA_READY)) {
DBG_PRINT(ERR_DBG, "TDMA is not ready!\n"); return 0;
} if (!(val64 & ADAPTER_STATUS_RDMA_READY)) {
DBG_PRINT(ERR_DBG, "RDMA is not ready!\n"); return 0;
} if (!(val64 & ADAPTER_STATUS_PFC_READY)) {
DBG_PRINT(ERR_DBG, "PFC is not ready!\n"); return 0;
} if (!(val64 & ADAPTER_STATUS_TMAC_BUF_EMPTY)) {
DBG_PRINT(ERR_DBG, "TMAC BUF is not empty!\n"); return 0;
} if (!(val64 & ADAPTER_STATUS_PIC_QUIESCENT)) {
DBG_PRINT(ERR_DBG, "PIC is not QUIESCENT!\n"); return 0;
} if (!(val64 & ADAPTER_STATUS_MC_DRAM_READY)) {
DBG_PRINT(ERR_DBG, "MC_DRAM is not ready!\n"); return 0;
} if (!(val64 & ADAPTER_STATUS_MC_QUEUES_READY)) {
DBG_PRINT(ERR_DBG, "MC_QUEUES is not ready!\n"); return 0;
} if (!(val64 & ADAPTER_STATUS_M_PLL_LOCK)) {
DBG_PRINT(ERR_DBG, "M_PLL is not locked!\n"); return 0;
}
/* * In PCI 33 mode, the P_PLL is not used, and therefore, * the P_PLL_LOCK bit in the adapter_status register will * not be asserted.
*/ if (!(val64 & ADAPTER_STATUS_P_PLL_LOCK) &&
sp->device_type == XFRAME_II_DEVICE &&
mode != PCI_MODE_PCI_33) {
DBG_PRINT(ERR_DBG, "P_PLL is not locked!\n"); return 0;
} if (!((val64 & ADAPTER_STATUS_RC_PRC_QUIESCENT) ==
ADAPTER_STATUS_RC_PRC_QUIESCENT)) {
DBG_PRINT(ERR_DBG, "RC_PRC is not QUIESCENT!\n"); return 0;
} return 1;
}
/** * fix_mac_address - Fix for Mac addr problem on Alpha platforms * @sp: Pointer to device specifc structure * Description : * New procedure to clear mac address reading problems on Alpha platforms *
*/
staticvoid fix_mac_address(struct s2io_nic *sp)
{ struct XENA_dev_config __iomem *bar0 = sp->bar0; int i = 0;
/** * start_nic - Turns the device on * @nic : device private variable. * Description: * This function actually turns the device on. Before this function is * called,all Registers are configured from their reset states * and shared memory is allocated but the NIC is still quiescent. On * calling this function, the device interrupts are cleared and the NIC is * literally switched on by writing into the adapter control register. * Return Value: * SUCCESS on success and -1 on failure.
*/
/* * Enabling MC-RLDRAM. After enabling the device, we timeout * for around 100ms, which is approximately the time required * for the device to be ready for operation.
*/
val64 = readq(&bar0->mc_rldram_mrs);
val64 |= MC_RLDRAM_QUEUE_SIZE_ENABLE | MC_RLDRAM_MRS_ENABLE;
SPECIAL_REG_WRITE(val64, &bar0->mc_rldram_mrs, UF);
val64 = readq(&bar0->mc_rldram_mrs);
/* * Verify if the device is ready to be enabled, if so enable * it.
*/
val64 = readq(&bar0->adapter_status); if (!verify_xena_quiescence(nic)) {
DBG_PRINT(ERR_DBG, "%s: device is not ready, " "Adapter status reads: 0x%llx\n",
dev->name, (unsignedlonglong)val64); return FAILURE;
}
/* * With some switches, link might be already up at this point. * Because of this weird behavior, when we enable laser, * we may not get link. We need to handle this. We cannot * figure out which switch is misbehaving. So we are forced to * make a global change.
*/
if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { /* * Dont see link state interrupts initially on some switches, * so directly scheduling the link state task here.
*/
schedule_work(&nic->set_link_task);
} /* SXE-002: Initialize link and activity LED */
subid = nic->pdev->subsystem_device; if (((subid & 0xFF) >= 0x07) &&
(nic->device_type == XFRAME_I_DEVICE)) {
val64 = readq(&bar0->gpio_control);
val64 |= 0x0000800000000000ULL;
writeq(val64, &bar0->gpio_control);
val64 = 0x0411040400000000ULL;
writeq(val64, (void __iomem *)bar0 + 0x2700);
}
return SUCCESS;
} /** * s2io_txdl_getskb - Get the skb from txdl, unmap and return skb * @fifo_data: fifo data pointer * @txdlp: descriptor * @get_off: unused
*/ staticstruct sk_buff *s2io_txdl_getskb(struct fifo_info *fifo_data, struct TxD *txdlp, int get_off)
{ struct s2io_nic *nic = fifo_data->nic; struct sk_buff *skb; struct TxD *txds;
u16 j, frg_cnt;
/** * stop_nic - To stop the nic * @nic : device private variable. * Description: * This function does exactly the opposite of what the start_nic() * function does. This function is called to stop the device. * Return Value: * void.
*/
/* Clearing Adapter_En bit of ADAPTER_CONTROL Register */
val64 = readq(&bar0->adapter_control);
val64 &= ~(ADAPTER_CNTL_EN);
writeq(val64, &bar0->adapter_control);
}
/** * fill_rx_buffers - Allocates the Rx side skbs * @nic : device private variable. * @ring: per ring structure * @from_card_up: If this is true, we will map the buffer to get * the dma address for buf0 and buf1 to give it to the card. * Else we will sync the already mapped buffer to give it to the card. * Description: * The function allocates Rx side skbs and puts the physical * address of these buffers into the RxD buffer pointers, so that the NIC * can DMA the received frame into these locations. * The NIC supports 3 receive modes, viz * 1. single buffer, * 2. three buffer and * 3. Five buffer modes. * Each mode defines how many fragments the received frame will be split * up into by the NIC. The frame is split into L3 header, L4 Header, * L4 payload in three buffer mode and in 5 buffer mode, L4 payload itself * is split into 3 fragments. As of now only single buffer mode is * supported. * Return Value: * SUCCESS on success or an appropriate -ve value on failure.
*/ staticint fill_rx_buffers(struct s2io_nic *nic, struct ring_info *ring, int from_card_up)
{ struct sk_buff *skb; struct RxD_t *rxdp; int off, size, block_no, block_no1;
u32 alloc_tab = 0;
u32 alloc_cnt;
u64 tmp; struct buffAdd *ba; struct RxD_t *first_rxdp = NULL;
u64 Buffer0_ptr = 0, Buffer1_ptr = 0; struct RxD1 *rxdp1; struct RxD3 *rxdp3; struct swStat *swstats = &ring->nic->mac_control.stats_info->sw_stat;
end: /* Transfer ownership of first descriptor to adapter just before * exiting. Before that, use memory barrier so that ownership * and other fields are seen by adapter correctly.
*/ if (first_rxdp) {
dma_wmb();
first_rxdp->Control_1 |= RXD_OWN_XENA;
}
staticint s2io_chk_rx_buffers(struct s2io_nic *nic, struct ring_info *ring)
{ if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s: Out of memory in Rx Intr!!\n",
ring->dev->name);
} return 0;
}
/** * s2io_poll_msix - Rx interrupt handler for NAPI support * @napi : pointer to the napi structure. * @budget : The number of packets that were budgeted to be processed * during one pass through the 'Poll" function. * Description: * Comes into picture only if NAPI support has been incorporated. It does * the same thing that rx_intr_handler does, but not in a interrupt context * also It will process only a given number of packets. * Return value: * 0 on success and 1 if there are No Rx packets to be processed.
*/
for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i];
ring_pkts_processed = rx_intr_handler(ring, budget);
s2io_chk_rx_buffers(nic, ring);
pkts_processed += ring_pkts_processed;
budget -= ring_pkts_processed; if (budget <= 0) break;
} if (pkts_processed < budget_org) {
napi_complete_done(napi, pkts_processed); /* Re enable the Rx interrupts for the ring */
writeq(0, &bar0->rx_traffic_mask);
readl(&bar0->rx_traffic_mask);
} return pkts_processed;
}
#ifdef CONFIG_NET_POLL_CONTROLLER /** * s2io_netpoll - netpoll event handler entry point * @dev : pointer to the device structure. * Description: * This function will be called by upper layer to check for events on the * interface in situations where interrupts are disabled. It is used for * specific in-kernel networking tasks, such as remote consoles and kernel * debugging over the network (example netdump in RedHat).
*/ staticvoid s2io_netpoll(struct net_device *dev)
{ struct s2io_nic *nic = netdev_priv(dev); constint irq = nic->pdev->irq; struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64 = 0xFFFFFFFFFFFFFFFFULL; int i; struct config_param *config = &nic->config; struct mac_info *mac_control = &nic->mac_control;
/* we need to free up the transmitted skbufs or else netpoll will * run out of skbs and will fail and eventually netpoll application such * as netdump will fail.
*/ for (i = 0; i < config->tx_fifo_num; i++)
tx_intr_handler(&mac_control->fifos[i]);
/* check for received packet and indicate up to network */ for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i];
rx_intr_handler(ring, 0);
}
for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i];
if (fill_rx_buffers(nic, ring, 0) == -ENOMEM) {
DBG_PRINT(INFO_DBG, "%s: Out of memory in Rx Netpoll!!\n",
dev->name); break;
}
}
enable_irq(irq);
} #endif
/** * rx_intr_handler - Rx interrupt handler * @ring_data: per ring structure. * @budget: budget for napi processing. * Description: * If the interrupt is because of a received frame or if the * receive ring contains fresh as yet un-processed frames,this function is * called. It picks out the RxD at which place the last Rx processing had * stopped and sends the skb to the OSM's Rx handler and then increments * the offset. * Return Value: * No. of napi packets processed.
*/ staticint rx_intr_handler(struct ring_info *ring_data, int budget)
{ int get_block, put_block; struct rx_curr_get_info get_info, put_info; struct RxD_t *rxdp; struct sk_buff *skb; int pkt_cnt = 0, napi_pkts = 0; int i; struct RxD1 *rxdp1; struct RxD3 *rxdp3;
while (RXD_IS_UP2DT(rxdp)) { /* * If your are next to put index then it's * FIFO full condition
*/ if ((get_block == put_block) &&
(get_info.offset + 1) == put_info.offset) {
DBG_PRINT(INTR_DBG, "%s: Ring Full\n",
ring_data->dev->name); break;
}
skb = (struct sk_buff *)((unsignedlong)rxdp->Host_Control); if (skb == NULL) {
DBG_PRINT(ERR_DBG, "%s: NULL skb in Rx Intr\n",
ring_data->dev->name); return 0;
} if (ring_data->rxd_mode == RXD_MODE_1) {
rxdp1 = (struct RxD1 *)rxdp;
dma_unmap_single(&ring_data->pdev->dev,
(dma_addr_t)rxdp1->Buffer0_ptr,
ring_data->mtu +
HEADER_ETHERNET_II_802_3_SIZE +
HEADER_802_2_SIZE +
HEADER_SNAP_SIZE,
DMA_FROM_DEVICE);
} elseif (ring_data->rxd_mode == RXD_MODE_3B) {
rxdp3 = (struct RxD3 *)rxdp;
dma_sync_single_for_cpu(&ring_data->pdev->dev,
(dma_addr_t)rxdp3->Buffer0_ptr,
BUF0_LEN, DMA_FROM_DEVICE);
dma_unmap_single(&ring_data->pdev->dev,
(dma_addr_t)rxdp3->Buffer2_ptr,
ring_data->mtu + 4, DMA_FROM_DEVICE);
}
prefetch(skb->data);
rx_osm_handler(ring_data, rxdp);
get_info.offset++;
ring_data->rx_curr_get_info.offset = get_info.offset;
rxdp = ring_data->rx_blocks[get_block].
rxds[get_info.offset].virt_addr; if (get_info.offset == rxd_count[ring_data->rxd_mode]) {
get_info.offset = 0;
ring_data->rx_curr_get_info.offset = get_info.offset;
get_block++; if (get_block == ring_data->block_count)
get_block = 0;
ring_data->rx_curr_get_info.block_index = get_block;
rxdp = ring_data->rx_blocks[get_block].block_virt_addr;
}
if (ring_data->nic->config.napi) {
budget--;
napi_pkts++; if (!budget) break;
}
pkt_cnt++; if ((indicate_max_pkts) && (pkt_cnt > indicate_max_pkts)) break;
} if (ring_data->lro) { /* Clear all LRO sessions before exiting */ for (i = 0; i < MAX_LRO_SESSIONS; i++) { struct lro *lro = &ring_data->lro0_n[i]; if (lro->in_use) {
update_L3L4_header(ring_data->nic, lro);
queue_rx_frame(lro->parent, lro->vlan_tag);
clear_lro_session(lro);
}
}
} return napi_pkts;
}
/** * tx_intr_handler - Transmit interrupt handler * @fifo_data : fifo data pointer * Description: * If an interrupt was raised to indicate DMA complete of the * Tx packet, this function is called. It identifies the last TxD * whose buffer was freed and frees all skbs whose data have already * DMA'ed into the NICs internal memory. * Return Value: * NONE
*/
/** * s2io_mdio_write - Function to write in to MDIO registers * @mmd_type : MMD type value (PMA/PMD/WIS/PCS/PHYXS) * @addr : address value * @value : data value * @dev : pointer to net_device structure * Description: * This function is used to write values to the MDIO registers * NONE
*/ staticvoid s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev)
{
u64 val64; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0;
/* Read the value from regs */
rval64 = readq(&bar0->mdio_control);
rval64 = rval64 & 0xFFFF0000;
rval64 = rval64 >> 16; return rval64;
}
/** * s2io_chk_xpak_counter - Function to check the status of the xpak counters * @counter : counter value to be updated * @regs_stat : registers status * @index : index * @flag : flag to indicate the status * @type : counter type * Description: * This function is to check the status of the xpak counters value * NONE
*/
staticvoid s2io_chk_xpak_counter(u64 *counter, u64 * regs_stat, u32 index,
u16 flag, u16 type)
{
u64 mask = 0x3;
u64 val64; int i; for (i = 0; i < index; i++)
mask = mask << 0x2;
if (flag > 0) {
*counter = *counter + 1;
val64 = *regs_stat & mask;
val64 = val64 >> (index * 0x2);
val64 = val64 + 1; if (val64 == 3) { switch (type) { case 1:
DBG_PRINT(ERR_DBG, "Take Xframe NIC out of service.\n");
DBG_PRINT(ERR_DBG, "Excessive temperatures may result in premature transceiver failure.\n"); break; case 2:
DBG_PRINT(ERR_DBG, "Take Xframe NIC out of service.\n");
DBG_PRINT(ERR_DBG, "Excessive bias currents may indicate imminent laser diode failure.\n"); break; case 3:
DBG_PRINT(ERR_DBG, "Take Xframe NIC out of service.\n");
DBG_PRINT(ERR_DBG, "Excessive laser output power may saturate far-end receiver.\n"); break; default:
DBG_PRINT(ERR_DBG, "Incorrect XPAK Alarm type\n");
}
val64 = 0x0;
}
val64 = val64 << (index * 0x2);
*regs_stat = (*regs_stat & (~mask)) | (val64);
} else {
*regs_stat = *regs_stat & (~mask);
}
}
/** * s2io_updt_xpak_counter - Function to update the xpak counters * @dev : pointer to net_device struct * Description: * This function is to upate the status of the xpak counters value * NONE
*/ staticvoid s2io_updt_xpak_counter(struct net_device *dev)
{
u16 flag = 0x0;
u16 type = 0x0;
u16 val16 = 0x0;
u64 val64 = 0x0;
u64 addr = 0x0;
/* Check the communication with the MDIO slave */
addr = MDIO_CTRL1;
val64 = 0x0;
val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev); if ((val64 == 0xFFFF) || (val64 == 0x0000)) {
DBG_PRINT(ERR_DBG, "ERR: MDIO slave access failed - Returned %llx\n",
(unsignedlonglong)val64); return;
}
/* Check for the expected value of control reg 1 */ if (val64 != MDIO_CTRL1_SPEED10G) {
DBG_PRINT(ERR_DBG, "Incorrect value at PMA address 0x0000 - " "Returned: %llx- Expected: 0x%x\n",
(unsignedlonglong)val64, MDIO_CTRL1_SPEED10G); return;
}
/* Loading the DOM register to MDIO register */
addr = 0xA100;
s2io_mdio_write(MDIO_MMD_PMAPMD, addr, val16, dev);
val64 = s2io_mdio_read(MDIO_MMD_PMAPMD, addr, dev);
if (CHECKBIT(val64, 0x7))
xstats->warn_transceiver_temp_high++;
if (CHECKBIT(val64, 0x6))
xstats->warn_transceiver_temp_low++;
if (CHECKBIT(val64, 0x3))
xstats->warn_laser_bias_current_high++;
if (CHECKBIT(val64, 0x2))
xstats->warn_laser_bias_current_low++;
if (CHECKBIT(val64, 0x1))
xstats->warn_laser_output_power_high++;
if (CHECKBIT(val64, 0x0))
xstats->warn_laser_output_power_low++;
}
/** * wait_for_cmd_complete - waits for a command to complete. * @addr: address * @busy_bit: bit to check for busy * @bit_state: state to check * @may_sleep: parameter indicates if sleeping when waiting for * command complete * Description: Function that waits for a command to Write into RMAC * ADDR DATA registers to be completed and returns either success or * error depending on whether the command was complete or not. * Return value: * SUCCESS on success and FAILURE on failure.
*/
staticint wait_for_cmd_complete(void __iomem *addr, u64 busy_bit, int bit_state, bool may_sleep)
{ int ret = FAILURE, cnt = 0, delay = 1;
u64 val64;
if ((bit_state != S2IO_BIT_RESET) && (bit_state != S2IO_BIT_SET)) return FAILURE;
do {
val64 = readq(addr); if (bit_state == S2IO_BIT_RESET) { if (!(val64 & busy_bit)) {
ret = SUCCESS; break;
}
} else { if (val64 & busy_bit) {
ret = SUCCESS; break;
}
}
if (!may_sleep)
mdelay(delay); else
msleep(delay);
if (++cnt >= 10)
delay = 50;
} while (cnt < 20); return ret;
} /** * check_pci_device_id - Checks if the device id is supported * @id : device id * Description: Function to check if the pci device id is supported by driver. * Return value: Actual device id if supported else PCI_ANY_ID
*/ static u16 check_pci_device_id(u16 id)
{ switch (id) { case PCI_DEVICE_ID_HERC_WIN: case PCI_DEVICE_ID_HERC_UNI: return XFRAME_II_DEVICE; case PCI_DEVICE_ID_S2IO_UNI: case PCI_DEVICE_ID_S2IO_WIN: return XFRAME_I_DEVICE; default: return PCI_ANY_ID;
}
}
/** * s2io_reset - Resets the card. * @sp : private member of the device structure. * Description: Function to Reset the card. This function then also * restores the previously saved PCI configuration space registers as * the card reset also resets the configuration space. * Return value: * void.
*/
/* Back up the PCI-X CMD reg, dont want to lose MMRBC, OST settings */
pci_read_config_word(sp->pdev, PCIX_COMMAND_REGISTER, &(pci_cmd));
val64 = SW_RESET_ALL;
writeq(val64, &bar0->sw_reset); if (strstr(sp->product_name, "CX4"))
msleep(750);
msleep(250); for (i = 0; i < S2IO_MAX_PCI_CONFIG_SPACE_REINIT; i++) {
/* Restore the PCI state saved during initialization. */
pci_restore_state(sp->pdev);
pci_save_state(sp->pdev);
pci_read_config_word(sp->pdev, 0x2, &val16); if (check_pci_device_id(val16) != (u16)PCI_ANY_ID) break;
msleep(200);
}
if (check_pci_device_id(val16) == (u16)PCI_ANY_ID)
DBG_PRINT(ERR_DBG, "%s SW_Reset failed!\n", __func__);
/* SXE-002: Configure link and activity LED to turn it off */
subid = sp->pdev->subsystem_device; if (((subid & 0xFF) >= 0x07) &&
(sp->device_type == XFRAME_I_DEVICE)) {
val64 = readq(&bar0->gpio_control);
val64 |= 0x0000800000000000ULL;
writeq(val64, &bar0->gpio_control);
val64 = 0x0411040400000000ULL;
writeq(val64, (void __iomem *)bar0 + 0x2700);
}
/* * Clear spurious ECC interrupts that would have occurred on * XFRAME II cards after reset.
*/ if (sp->device_type == XFRAME_II_DEVICE) {
val64 = readq(&bar0->pcc_err_reg);
writeq(val64, &bar0->pcc_err_reg);
}
sp->device_enabled_once = false;
}
/** * s2io_set_swapper - to set the swapper controle on the card * @sp : private member of the device structure, * pointer to the s2io_nic structure. * Description: Function to set the swapper control on the card * correctly depending on the 'endianness' of the system. * Return value: * SUCCESS on success and FAILURE on failure.
*/
while (i < 4) {
writeq((value[i] | valr), &bar0->swapper_ctrl);
writeq(valt, &bar0->xmsi_address);
val64 = readq(&bar0->xmsi_address); if (val64 == valt) break;
i++;
} if (i == 4) { unsignedlonglong x = val64;
DBG_PRINT(ERR_DBG, "Write failed, Xmsi_addr reads:0x%llx\n", x); return FAILURE;
}
}
val64 = readq(&bar0->swapper_ctrl);
val64 &= 0xFFFF000000000000ULL;
#ifdef __BIG_ENDIAN /* * The device by default set to a big endian format, so a * big endian driver need not set anything.
*/
val64 |= (SWAPPER_CTRL_TXP_FE |
SWAPPER_CTRL_TXP_SE |
SWAPPER_CTRL_TXD_R_FE |
SWAPPER_CTRL_TXD_W_FE |
SWAPPER_CTRL_TXF_R_FE |
SWAPPER_CTRL_RXD_R_FE |
SWAPPER_CTRL_RXD_W_FE |
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
SWAPPER_CTRL_STATS_FE |
SWAPPER_CTRL_STATS_SE); if (sp->config.intr_type == INTA)
val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl); #else /* * Initially we enable all bits to make it accessible by the * driver, then we selectively enable only those bits that * we want to set.
*/
val64 |= (SWAPPER_CTRL_TXP_FE |
SWAPPER_CTRL_TXP_SE |
SWAPPER_CTRL_TXD_R_FE |
SWAPPER_CTRL_TXD_R_SE |
SWAPPER_CTRL_TXD_W_FE |
SWAPPER_CTRL_TXD_W_SE |
SWAPPER_CTRL_TXF_R_FE |
SWAPPER_CTRL_RXD_R_FE |
SWAPPER_CTRL_RXD_R_SE |
SWAPPER_CTRL_RXD_W_FE |
SWAPPER_CTRL_RXD_W_SE |
SWAPPER_CTRL_RXF_W_FE |
SWAPPER_CTRL_XMSI_FE |
SWAPPER_CTRL_STATS_FE |
SWAPPER_CTRL_STATS_SE); if (sp->config.intr_type == INTA)
val64 |= SWAPPER_CTRL_XMSI_SE;
writeq(val64, &bar0->swapper_ctrl); #endif
val64 = readq(&bar0->swapper_ctrl);
/* * Verifying if endian settings are accurate by reading a * feedback register.
*/
val64 = readq(&bar0->pif_rd_swapper_fb); if (val64 != 0x0123456789ABCDEFULL) { /* Endian settings are incorrect, calls for another dekko. */
DBG_PRINT(ERR_DBG, "%s: Endian settings are wrong, feedback read %llx\n",
dev->name, (unsignedlonglong)val64); return FAILURE;
}
return SUCCESS;
}
staticint wait_for_msix_trans(struct s2io_nic *nic, int i)
{ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64; int ret = 0, cnt = 0;
do {
val64 = readq(&bar0->xmsi_access); if (!(val64 & s2BIT(15))) break;
mdelay(1);
cnt++;
} while (cnt < 5); if (cnt == 5) {
DBG_PRINT(ERR_DBG, "XMSI # %d Access failed\n", i);
ret = 1;
}
return ret;
}
staticvoid restore_xmsi_data(struct s2io_nic *nic)
{ struct XENA_dev_config __iomem *bar0 = nic->bar0;
u64 val64; int i, msix_index;
ret = pci_enable_msix_range(nic->pdev, nic->entries,
nic->num_entries, nic->num_entries); /* We fail init if error or we get less vectors than min required */ if (ret < 0) {
DBG_PRINT(ERR_DBG, "Enabling MSI-X failed\n");
kfree(nic->entries);
swstats->mem_freed += nic->num_entries * sizeof(struct msix_entry);
kfree(nic->s2io_entries);
swstats->mem_freed += nic->num_entries * sizeof(struct s2io_msix_entry);
nic->entries = NULL;
nic->s2io_entries = NULL; return -ENOMEM;
}
/* * To enable MSI-X, MSI also needs to be enabled, due to a bug * in the herc NIC. (Temp change, needs to be removed later)
*/
pci_read_config_word(nic->pdev, 0x42, &msi_control);
msi_control |= 0x1; /* Enable MSI */
pci_write_config_word(nic->pdev, 0x42, msi_control);
return 0;
}
/* Handle software interrupt used during MSI(X) test */ static irqreturn_t s2io_test_intr(int irq, void *dev_id)
{ struct s2io_nic *sp = dev_id;
sp->msi_detected = 1;
wake_up(&sp->msi_wait);
return IRQ_HANDLED;
}
/* Test interrupt path by forcing a software IRQ */ staticint s2io_test_msi(struct s2io_nic *sp)
{ struct pci_dev *pdev = sp->pdev; struct XENA_dev_config __iomem *bar0 = sp->bar0; int err;
u64 val64, saved64;
if (!sp->msi_detected) { /* MSI(X) test failed, go back to INTx mode */
DBG_PRINT(ERR_DBG, "%s: PCI %s: No interrupt was generated " "using MSI(X) during test\n",
sp->dev->name, pci_name(pdev));
err = -EOPNOTSUPP;
}
free_irq(sp->entries[1].vector, sp);
writeq(saved64, &bar0->scheduled_int_ctrl);
return err;
}
staticvoid remove_msix_isr(struct s2io_nic *sp)
{ int i;
u16 msi_control;
for (i = 0; i < sp->num_entries; i++) { if (sp->s2io_entries[i].in_use == MSIX_REGISTERED_SUCCESS) { int vector = sp->entries[i].vector; void *arg = sp->s2io_entries[i].arg;
free_irq(vector, arg);
}
}
/* ********************************************************* * * Functions defined below concern the OS part of the driver *
* ********************************************************* */
/** * s2io_open - open entry point of the driver * @dev : pointer to the device structure. * Description: * This function is the open entry point of the driver. It mainly calls a * function to allocate Rx buffers and inserts them into the buffer * descriptors and then enables the Rx part of the NIC. * Return value: * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure.
*/
/** * s2io_close -close entry point of the driver * @dev : device pointer. * Description: * This is the stop entry point of the driver. It needs to undo exactly * whatever was done by the open entry point,thus it's usually referred to * as the close function.Among other things this function mainly stops the * Rx side of the NIC and frees all the Rx buffers in the Rx rings. * Return value: * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure.
*/
/* Return if the device is already closed * * Can happen when s2io_card_up failed in change_mtu *
*/ if (!is_s2io_card_up(sp)) return 0;
s2io_stop_all_tx_queue(sp); /* delete all populated mac entries */ for (offset = 1; offset < config->max_mc_addr; offset++) {
tmp64 = do_s2io_read_unicast_mc(sp, offset); if (tmp64 != S2IO_DISABLE_MAC_ENTRY)
do_s2io_delete_unicast_mc(sp, tmp64);
}
s2io_card_down(sp);
return 0;
}
/** * s2io_xmit - Tx entry point of te driver * @skb : the socket buffer containing the Tx data. * @dev : device pointer. * Description : * This function is the Tx entry point of the driver. S2IO NIC supports * certain protocol assist features on Tx side, namely CSO, S/G, LSO. * NOTE: when device can't queue the pkt,just the trans_start variable will * not be upadted. * Return value: * 0 on success & 1 on failure.
*/
if (unlikely(!is_s2io_card_up(sp))) return IRQ_NONE;
reason = readq(&bar0->general_int_status); if (unlikely(reason == S2IO_MINUS_ONE)) /* Nothing much can be done. Get out */ return IRQ_HANDLED;
if (reason & (GEN_INTR_TXPIC | GEN_INTR_TXTRAFFIC)) {
writeq(S2IO_MINUS_ONE, &bar0->general_int_mask);
if (reason & GEN_INTR_TXPIC)
s2io_txpic_intr_handle(sp);
if (reason & GEN_INTR_TXTRAFFIC)
writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
for (i = 0; i < config->tx_fifo_num; i++)
tx_intr_handler(&fifos[i]);
writeq(sp->general_int_mask, &bar0->general_int_mask);
readl(&bar0->general_int_status); return IRQ_HANDLED;
} /* The interrupt was not raised by us */ return IRQ_NONE;
}
/** * do_s2io_chk_alarm_bit - Check for alarm and incrment the counter * @value: alarm bits * @addr: address value * @cnt: counter variable * Description: Check for alarm and increment the counter * Return Value: * 1 - if alarm bit set * 0 - if alarm bit is not set
*/ staticint do_s2io_chk_alarm_bit(u64 value, void __iomem *addr, unsignedlonglong *cnt)
{
u64 val64;
val64 = readq(addr); if (val64 & value) {
writeq(val64, addr);
(*cnt)++; return 1;
} return 0;
}
/** * s2io_handle_errors - Xframe error indication handler * @dev_id: opaque handle to dev * Description: Handle alarms such as loss of link, single or * double ECC errors, critical and serious errors. * Return Value: * NONE
*/ staticvoid s2io_handle_errors(void *dev_id)
{ struct net_device *dev = (struct net_device *)dev_id; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 temp64 = 0, val64 = 0; int i = 0;
/* Handling the XPAK counters update */ if (stats->xpak_timer_count < 72000) { /* waiting for an hour */
stats->xpak_timer_count++;
} else {
s2io_updt_xpak_counter(dev); /* reset the count to zero */
stats->xpak_timer_count = 0;
}
/* Handling link status change error Intr */ if (s2io_link_fault_indication(sp) == MAC_RMAC_ERR_TIMER) {
val64 = readq(&bar0->mac_rmac_err_reg);
writeq(val64, &bar0->mac_rmac_err_reg); if (val64 & RMAC_LINK_STATE_CHANGE_INT)
schedule_work(&sp->set_link_task);
}
/* In case of a serious error, the device will be Reset. */ if (do_s2io_chk_alarm_bit(SERR_SOURCE_ANY, &bar0->serr_source,
&sw_stat->serious_err_cnt)) goto reset;
/* Check for data parity error */ if (do_s2io_chk_alarm_bit(GPIO_INT_REG_DP_ERR_INT, &bar0->gpio_int_reg,
&sw_stat->parity_err_cnt)) goto reset;
/* Check for ring full counter */ if (sp->device_type == XFRAME_II_DEVICE) {
val64 = readq(&bar0->ring_bump_counter1); for (i = 0; i < 4; i++) {
temp64 = (val64 & vBIT(0xFFFF, (i*16), 16));
temp64 >>= 64 - ((i+1)*16);
sw_stat->ring_full_cnt[i] += temp64;
}
val64 = readq(&bar0->ring_bump_counter2); for (i = 0; i < 4; i++) {
temp64 = (val64 & vBIT(0xFFFF, (i*16), 16));
temp64 >>= 64 - ((i+1)*16);
sw_stat->ring_full_cnt[i+4] += temp64;
}
}
val64 = readq(&bar0->txdma_int_status); /*check for pfc_err*/ if (val64 & TXDMA_PFC_INT) { if (do_s2io_chk_alarm_bit(PFC_ECC_DB_ERR | PFC_SM_ERR_ALARM |
PFC_MISC_0_ERR | PFC_MISC_1_ERR |
PFC_PCIX_ERR,
&bar0->pfc_err_reg,
&sw_stat->pfc_err_cnt)) goto reset;
do_s2io_chk_alarm_bit(PFC_ECC_SG_ERR,
&bar0->pfc_err_reg,
&sw_stat->pfc_err_cnt);
}
/*check for tda_err*/ if (val64 & TXDMA_TDA_INT) { if (do_s2io_chk_alarm_bit(TDA_Fn_ECC_DB_ERR |
TDA_SM0_ERR_ALARM |
TDA_SM1_ERR_ALARM,
&bar0->tda_err_reg,
&sw_stat->tda_err_cnt)) goto reset;
do_s2io_chk_alarm_bit(TDA_Fn_ECC_SG_ERR | TDA_PCIX_ERR,
&bar0->tda_err_reg,
&sw_stat->tda_err_cnt);
} /*check for pcc_err*/ if (val64 & TXDMA_PCC_INT) { if (do_s2io_chk_alarm_bit(PCC_SM_ERR_ALARM | PCC_WR_ERR_ALARM |
PCC_N_SERR | PCC_6_COF_OV_ERR |
PCC_7_COF_OV_ERR | PCC_6_LSO_OV_ERR |
PCC_7_LSO_OV_ERR | PCC_FB_ECC_DB_ERR |
PCC_TXB_ECC_DB_ERR,
&bar0->pcc_err_reg,
&sw_stat->pcc_err_cnt)) goto reset;
do_s2io_chk_alarm_bit(PCC_FB_ECC_SG_ERR | PCC_TXB_ECC_SG_ERR,
&bar0->pcc_err_reg,
&sw_stat->pcc_err_cnt);
}
/*check for tti_err*/ if (val64 & TXDMA_TTI_INT) { if (do_s2io_chk_alarm_bit(TTI_SM_ERR_ALARM,
&bar0->tti_err_reg,
&sw_stat->tti_err_cnt)) goto reset;
do_s2io_chk_alarm_bit(TTI_ECC_SG_ERR | TTI_ECC_DB_ERR,
&bar0->tti_err_reg,
&sw_stat->tti_err_cnt);
}
/*check for lso_err*/ if (val64 & TXDMA_LSO_INT) { if (do_s2io_chk_alarm_bit(LSO6_ABORT | LSO7_ABORT |
LSO6_SM_ERR_ALARM | LSO7_SM_ERR_ALARM,
&bar0->lso_err_reg,
&sw_stat->lso_err_cnt)) goto reset;
do_s2io_chk_alarm_bit(LSO6_SEND_OFLOW | LSO7_SEND_OFLOW,
&bar0->lso_err_reg,
&sw_stat->lso_err_cnt);
}
/*check for tpa_err*/ if (val64 & TXDMA_TPA_INT) { if (do_s2io_chk_alarm_bit(TPA_SM_ERR_ALARM,
&bar0->tpa_err_reg,
&sw_stat->tpa_err_cnt)) goto reset;
do_s2io_chk_alarm_bit(TPA_TX_FRM_DROP,
&bar0->tpa_err_reg,
&sw_stat->tpa_err_cnt);
}
/*check for sm_err*/ if (val64 & TXDMA_SM_INT) { if (do_s2io_chk_alarm_bit(SM_SM_ERR_ALARM,
&bar0->sm_err_reg,
&sw_stat->sm_err_cnt)) goto reset;
}
/** * s2io_isr - ISR handler of the device . * @irq: the irq of the device. * @dev_id: a void pointer to the dev structure of the NIC. * Description: This function is the ISR handler of the device. It * identifies the reason for the interrupt and calls the relevant * service routines. As a contongency measure, this ISR allocates the * recv buffers, if their numbers are below the panic value which is * presently set to 25% of the original number of rcv buffers allocated. * Return value: * IRQ_HANDLED: will be returned if IRQ was handled by this routine * IRQ_NONE: will be returned if interrupt is not from our device
*/ static irqreturn_t s2io_isr(int irq, void *dev_id)
{ struct net_device *dev = (struct net_device *)dev_id; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; int i;
u64 reason = 0; struct mac_info *mac_control; struct config_param *config;
/* Pretend we handled any irq's from a disconnected card */ if (pci_channel_offline(sp->pdev)) return IRQ_NONE;
/* * Identify the cause for interrupt and call the appropriate * interrupt handler. Causes for the interrupt could be; * 1. Rx of packet. * 2. Tx complete. * 3. Link down.
*/
reason = readq(&bar0->general_int_status);
if (unlikely(reason == S2IO_MINUS_ONE)) return IRQ_HANDLED; /* Nothing much can be done. Get out */
if (config->napi) { if (reason & GEN_INTR_RXTRAFFIC) {
napi_schedule(&sp->napi);
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask);
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
readl(&bar0->rx_traffic_int);
}
} else { /* * rx_traffic_int reg is an R1 register, writing all 1's * will ensure that the actual interrupt causing bit * gets cleared and hence a read can be avoided.
*/ if (reason & GEN_INTR_RXTRAFFIC)
writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int);
for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i];
rx_intr_handler(ring, 0);
}
}
/* * tx_traffic_int reg is an R1 register, writing all 1's * will ensure that the actual interrupt causing bit gets * cleared and hence a read can be avoided.
*/ if (reason & GEN_INTR_TXTRAFFIC)
writeq(S2IO_MINUS_ONE, &bar0->tx_traffic_int);
for (i = 0; i < config->tx_fifo_num; i++)
tx_intr_handler(&mac_control->fifos[i]);
if (reason & GEN_INTR_TXPIC)
s2io_txpic_intr_handle(sp);
/* * Reallocate the buffers from the interrupt handler itself.
*/ if (!config->napi) { for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i];
if (is_s2io_card_up(sp)) { /* Apprx 30us on a 133 MHz bus */
val64 = SET_UPDT_CLICKS(10) |
STAT_CFG_ONE_SHOT_EN | STAT_CFG_STAT_EN;
writeq(val64, &bar0->stat_cfg); do {
udelay(100);
val64 = readq(&bar0->stat_cfg); if (!(val64 & s2BIT(0))) break;
cnt++; if (cnt == 5) break; /* Updt failed */
} while (1);
}
}
/** * s2io_get_stats - Updates the device statistics structure. * @dev : pointer to the device structure. * Description: * This function updates the device statistics structure in the s2io_nic * structure and returns a pointer to the same. * Return value: * pointer to the updated net_device_stats structure.
*/ staticstruct net_device_stats *s2io_get_stats(struct net_device *dev)
{ struct s2io_nic *sp = netdev_priv(dev); struct mac_info *mac_control = &sp->mac_control; struct stat_block *stats = mac_control->stats_info;
u64 delta;
/* Configure Stats for immediate updt */
s2io_updt_stats(sp);
/* A device reset will cause the on-adapter statistics to be zero'ed. * This can be done while running by changing the MTU. To prevent the * system from having the stats zero'ed, the driver keeps a copy of the * last update to the system (which is also zero'ed on reset). This * enables the driver to accurately know the delta between the last * update and the current update.
*/
delta = ((u64) le32_to_cpu(stats->rmac_vld_frms_oflow) << 32 |
le32_to_cpu(stats->rmac_vld_frms)) - sp->stats.rx_packets;
sp->stats.rx_packets += delta;
dev->stats.rx_packets += delta;
/* The adapter MAC interprets pause frames as multicast packets, but * does not pass them up. This erroneously increases the multicast * packet count and needs to be deducted when the multicast frame count * is queried.
*/
delta = (u64) le32_to_cpu(stats->rmac_vld_mcst_frms_oflow) << 32 |
le32_to_cpu(stats->rmac_vld_mcst_frms);
delta -= le64_to_cpu(stats->rmac_pause_ctrl_frms);
delta -= sp->stats.multicast;
sp->stats.multicast += delta;
dev->stats.multicast += delta;
/** * s2io_set_multicast - entry point for multicast address enable/disable. * @dev : pointer to the device structure * @may_sleep: parameter indicates if sleeping when waiting for command * complete * Description: * This function is a driver entry point which gets called by the kernel * whenever multicast addresses must be enabled/disabled. This also gets * called to set/reset promiscuous mode. Depending on the deivce flag, we * determine, if multicast address must be enabled or if promiscuous mode * is to be disabled etc. * Return value: * void.
*/ staticvoid s2io_set_multicast(struct net_device *dev, bool may_sleep)
{ int i, j, prev_cnt; struct netdev_hw_addr *ha; struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = 0, multi_mac = 0x010203040506ULL, mask =
0xfeffffffffffULL;
u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, mac_addr = 0; void __iomem *add; struct config_param *config = &sp->config;
if ((dev->flags & IFF_PROMISC) && (!sp->promisc_flg)) { /* Put the NIC into promiscuous mode */
add = &bar0->mac_cfg;
val64 = readq(&bar0->mac_cfg);
val64 |= MAC_CFG_RMAC_PROM_ENABLE;
/* Clear out the previous list of Mc in the H/W. */ for (i = 0; i < prev_cnt; i++) {
writeq(RMAC_ADDR_DATA0_MEM_ADDR(dis_addr),
&bar0->rmac_addr_data0_mem);
writeq(RMAC_ADDR_DATA1_MEM_MASK(0ULL),
&bar0->rmac_addr_data1_mem);
val64 = RMAC_ADDR_CMD_MEM_WE |
RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
RMAC_ADDR_CMD_MEM_OFFSET
(config->mc_start_offset + i);
writeq(val64, &bar0->rmac_addr_cmd_mem);
/* check if the multicast mac already preset in CAM */ for (i = config->mc_start_offset; i < config->max_mc_addr; i++) {
u64 tmp64;
tmp64 = do_s2io_read_unicast_mc(sp, i); if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */ break;
if (tmp64 == mac_addr) return SUCCESS;
} if (i == config->max_mc_addr) {
DBG_PRINT(ERR_DBG, "CAM full no space left for multicast MAC\n"); return FAILURE;
} /* Update the internal structure with this new mac address */
do_s2io_copy_mac_addr(sp, i, mac_addr);
return do_s2io_add_mac(sp, mac_addr, i);
}
/* add MAC address to CAM */ staticint do_s2io_add_mac(struct s2io_nic *sp, u64 addr, int off)
{
u64 val64; struct XENA_dev_config __iomem *bar0 = sp->bar0;
/* Wait till command completes */ if (wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
S2IO_BIT_RESET, true)) {
DBG_PRINT(INFO_DBG, "do_s2io_add_mac failed\n"); return FAILURE;
} return SUCCESS;
} /* deletes a specified unicast/multicast mac entry from CAM */ staticint do_s2io_delete_unicast_mc(struct s2io_nic *sp, u64 addr)
{ int offset;
u64 dis_addr = S2IO_DISABLE_MAC_ENTRY, tmp64; struct config_param *config = &sp->config;
for (offset = 1;
offset < config->max_mc_addr; offset++) {
tmp64 = do_s2io_read_unicast_mc(sp, offset); if (tmp64 == addr) { /* disable the entry by writing 0xffffffffffffULL */ if (do_s2io_add_mac(sp, dis_addr, offset) == FAILURE) return FAILURE; /* store the new mac list from CAM */
do_s2io_store_unicast_mc(sp); return SUCCESS;
}
}
DBG_PRINT(ERR_DBG, "MAC address 0x%llx not found in CAM\n",
(unsignedlonglong)addr); return FAILURE;
}
/* read mac entries from CAM */ static u64 do_s2io_read_unicast_mc(struct s2io_nic *sp, int offset)
{
u64 tmp64, val64; struct XENA_dev_config __iomem *bar0 = sp->bar0;
if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL;
eth_hw_addr_set(dev, addr->sa_data);
/* store the MAC address in CAM */ return do_s2io_prog_unicast(dev, dev->dev_addr);
} /** * do_s2io_prog_unicast - Programs the Xframe mac address * @dev : pointer to the device structure. * @addr: a uchar pointer to the new mac address which is to be set. * Description : This procedure will program the Xframe to receive * frames with new Mac Address * Return value: SUCCESS on success and an appropriate (-)ve integer * as defined in errno.h file on failure.
*/
/* * Set the new MAC address as the new unicast filter and reflect this * change on the device address registered with the OS. It will be * at offset 0.
*/
mac_addr = ether_addr_to_u64(addr);
perm_addr = ether_addr_to_u64(sp->def_mac_addr[0].mac_addr);
/* check if the dev_addr is different than perm_addr */ if (mac_addr == perm_addr) return SUCCESS;
/* check if the mac already preset in CAM */ for (i = 1; i < config->max_mac_addr; i++) {
tmp64 = do_s2io_read_unicast_mc(sp, i); if (tmp64 == S2IO_DISABLE_MAC_ENTRY) /* CAM entry is empty */ break;
if (tmp64 == mac_addr) {
DBG_PRINT(INFO_DBG, "MAC addr:0x%llx already present in CAM\n",
(unsignedlonglong)mac_addr); return SUCCESS;
}
} if (i == config->max_mac_addr) {
DBG_PRINT(ERR_DBG, "CAM full no space left for Unicast MAC\n"); return FAILURE;
} /* Update the internal structure with this new mac address */
do_s2io_copy_mac_addr(sp, i, mac_addr);
return do_s2io_add_mac(sp, mac_addr, i);
}
/** * s2io_ethtool_set_link_ksettings - Sets different link parameters. * @dev : pointer to netdev * @cmd: pointer to the structure with parameters given by ethtool to set * link information. * Description: * The function sets different link parameters provided by the user onto * the NIC. * Return value: * 0 on success.
*/
/** * s2io_ethtool_get_link_ksettings - Return link specific information. * @dev: pointer to netdev * @cmd : pointer to the structure with parameters given by ethtool * to return link information. * Description: * Returns link specific information like speed, duplex etc.. to ethtool. * Return value : * return 0 on success.
*/
/** * s2io_ethtool_gdrvinfo - Returns driver specific information. * @dev: pointer to netdev * @info : pointer to the structure with parameters given by ethtool to * return driver information. * Description: * Returns driver specefic information like name, version etc.. to ethtool. * Return value: * void
*/
/** * s2io_ethtool_gregs - dumps the entire space of Xfame into the buffer. * @dev: pointer to netdev * @regs : pointer to the structure with parameters given by ethtool for * dumping the registers. * @space: The input argument into which all the registers are dumped. * Description: * Dumps the entire register space of xFrame NIC into the user given * buffer area. * Return value : * void .
*/
/** * s2io_ethtool_set_led - To physically identify the nic on the system. * @dev : network device * @state: led setting * * Description: Used to physically identify the NIC on the system. * The Link LED will blink for a time specified by the user for * identification. * NOTE: The Link has to be Up to be able to blink the LED. Hence * identification is possible only if it's link is up.
*/
/** * s2io_ethtool_setpause_data - set/reset pause frame generation. * @dev: pointer to netdev * @ep : pointer to the structure with pause parameters given by ethtool. * Description: * It can be used to set or reset Pause frame generation or reception * support of the NIC. * Return value: * int, returns 0 on Success
*/
#define S2IO_DEV_ID 5 /** * read_eeprom - reads 4 bytes of data from user given offset. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @off : offset at which the data must be written * @data : Its an output parameter where the data read at the given * offset is stored. * Description: * Will read 4 bytes of data from the user given offset and return the * read data. * NOTE: Will allow to read only part of the EEPROM visible through the * I2C bus. * Return value: * -1 on failure and 0 on success.
*/ staticint read_eeprom(struct s2io_nic *sp, int off, u64 *data)
{ int ret = -1;
u32 exit_cnt = 0;
u64 val64; struct XENA_dev_config __iomem *bar0 = sp->bar0;
/** * write_eeprom - actually writes the relevant part of the data value. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @off : offset at which the data must be written * @data : The data that is to be written * @cnt : Number of bytes of the data that are actually to be written into * the Eeprom. (max of 3) * Description: * Actually writes the relevant part of the data value into the Eeprom * through the I2C bus. * Return value: * 0 on success, -1 on failure.
*/
staticint write_eeprom(struct s2io_nic *sp, int off, u64 data, int cnt)
{ int exit_cnt = 0, ret = -1;
u64 val64; struct XENA_dev_config __iomem *bar0 = sp->bar0;
/** * s2io_ethtool_geeprom - reads the value stored in the Eeprom. * @dev: pointer to netdev * @eeprom : pointer to the user level structure provided by ethtool, * containing all relevant information. * @data_buf : user defined value to be written into Eeprom. * Description: Reads the values stored in the Eeprom at given offset * for a given length. Stores these values int the input argument data * buffer 'data_buf' and returns these to the caller (ethtool.) * Return value: * int 0 on success
*/
for (i = 0; i < eeprom->len; i += 4) { if (read_eeprom(sp, (eeprom->offset + i), &data)) {
DBG_PRINT(ERR_DBG, "Read of EEPROM failed\n"); return -EFAULT;
}
valid = INV(data);
memcpy((data_buf + i), &valid, 4);
} return 0;
}
/** * s2io_ethtool_seeprom - tries to write the user provided value in Eeprom * @dev: pointer to netdev * @eeprom : pointer to the user level structure provided by ethtool, * containing all relevant information. * @data_buf : user defined value to be written into Eeprom. * Description: * Tries to write the user provided value in the Eeprom, at the offset * given by the user. * Return value: * 0 on success, -EFAULT on failure.
*/
if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) {
DBG_PRINT(ERR_DBG, "ETHTOOL_WRITE_EEPROM Err: " "Magic value is wrong, it is 0x%x should be 0x%x\n",
(sp->pdev->vendor | (sp->pdev->device << 16)),
eeprom->magic); return -EFAULT;
}
while (len) {
data = (u32)data_buf[cnt] & 0x000000FF; if (data)
valid = (u32)(data << 24); else
valid = data;
if (write_eeprom(sp, (eeprom->offset + cnt), valid, 0)) {
DBG_PRINT(ERR_DBG, "ETHTOOL_WRITE_EEPROM Err: " "Cannot write into the specified offset\n"); return -EFAULT;
}
cnt++;
len--;
}
return 0;
}
/** * s2io_register_test - reads and writes into all clock domains. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @data : variable that returns the result of each of the test conducted b * by the driver. * Description: * Read and write into all clock domains. The NIC has 3 clock domains, * see that registers in all the three regions are accessible. * Return value: * 0 on success.
*/
/** * s2io_eeprom_test - to verify that EEprom in the xena can be programmed. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @data:variable that returns the result of each of the test conducted by * the driver. * Description: * Verify that EEPROM in the xena can be programmed using I2C_CONTROL * register. * Return value: * 0 on success.
*/
/* Test Write Error at offset 0 */ /* Note that SPI interface allows write access to all areas * of EEPROM. Hence doing all negative testing only for Xframe I.
*/ if (sp->device_type == XFRAME_I_DEVICE) if (!write_eeprom(sp, 0, 0, 3))
fail = 1;
/* Save current values at offsets 0x4F0 and 0x7F0 */ if (!read_eeprom(sp, 0x4F0, &org_4F0))
saved_4F0 = 1; if (!read_eeprom(sp, 0x7F0, &org_7F0))
saved_7F0 = 1;
/* Test Write at offset 4f0 */ if (write_eeprom(sp, 0x4F0, 0x012345, 3))
fail = 1; if (read_eeprom(sp, 0x4F0, &ret_data))
fail = 1;
if (ret_data != 0x012345) {
DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x4F0. " "Data written %llx Data read %llx\n",
dev->name, (unsignedlonglong)0x12345,
(unsignedlonglong)ret_data);
fail = 1;
}
/* Reset the EEPROM data go FFFF */
write_eeprom(sp, 0x4F0, 0xFFFFFF, 3);
/* Test Write Request Error at offset 0x7c */ if (sp->device_type == XFRAME_I_DEVICE) if (!write_eeprom(sp, 0x07C, 0, 3))
fail = 1;
/* Test Write Request at offset 0x7f0 */ if (write_eeprom(sp, 0x7F0, 0x012345, 3))
fail = 1; if (read_eeprom(sp, 0x7F0, &ret_data))
fail = 1;
if (ret_data != 0x012345) {
DBG_PRINT(ERR_DBG, "%s: eeprom test error at offset 0x7F0. " "Data written %llx Data read %llx\n",
dev->name, (unsignedlonglong)0x12345,
(unsignedlonglong)ret_data);
fail = 1;
}
/* Reset the EEPROM data go FFFF */
write_eeprom(sp, 0x7F0, 0xFFFFFF, 3);
if (sp->device_type == XFRAME_I_DEVICE) { /* Test Write Error at offset 0x80 */ if (!write_eeprom(sp, 0x080, 0, 3))
fail = 1;
/* Test Write Error at offset 0xfc */ if (!write_eeprom(sp, 0x0FC, 0, 3))
fail = 1;
/* Test Write Error at offset 0x100 */ if (!write_eeprom(sp, 0x100, 0, 3))
fail = 1;
/* Test Write Error at offset 4ec */ if (!write_eeprom(sp, 0x4EC, 0, 3))
fail = 1;
}
/* Restore values at offsets 0x4F0 and 0x7F0 */ if (saved_4F0)
write_eeprom(sp, 0x4F0, org_4F0, 3); if (saved_7F0)
write_eeprom(sp, 0x7F0, org_7F0, 3);
*data = fail; return fail;
}
/** * s2io_bist_test - invokes the MemBist test of the card . * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @data:variable that returns the result of each of the test conducted by * the driver. * Description: * This invokes the MemBist test of the card. We give around * 2 secs time for the Test to complete. If it's still not complete * within this peiod, we consider that the test failed. * Return value: * 0 on success and -1 on failure.
*/
staticint s2io_bist_test(struct s2io_nic *sp, uint64_t *data)
{
u8 bist = 0; int cnt = 0, ret = -1;
while (cnt < 20) {
pci_read_config_byte(sp->pdev, PCI_BIST, &bist); if (!(bist & PCI_BIST_START)) {
*data = (bist & PCI_BIST_CODE_MASK);
ret = 0; break;
}
msleep(100);
cnt++;
}
return ret;
}
/** * s2io_link_test - verifies the link state of the nic * @sp: private member of the device structure, which is a pointer to the * s2io_nic structure. * @data: variable that returns the result of each of the test conducted by * the driver. * Description: * The function verifies the link state of the NIC and updates the input * argument 'data' appropriately. * Return value: * 0 on success.
*/
/** * s2io_rldram_test - offline test for access to the RldRam chip on the NIC * @sp: private member of the device structure, which is a pointer to the * s2io_nic structure. * @data: variable that returns the result of each of the test * conducted by the driver. * Description: * This is one of the offline test that tests the read and write * access to the RldRam chip on the NIC. * Return value: * 0 on success.
*/
for (cnt = 0; cnt < 5; cnt++) {
val64 = readq(&bar0->mc_rldram_test_ctrl); if (val64 & MC_RLDRAM_TEST_DONE) break;
msleep(500);
}
if (cnt == 5) break;
val64 = readq(&bar0->mc_rldram_test_ctrl); if (!(val64 & MC_RLDRAM_TEST_PASS))
test_fail = 1;
iteration++;
}
*data = test_fail;
/* Bring the adapter out of test mode */
SPECIAL_REG_WRITE(0, &bar0->mc_rldram_test_ctrl, LF);
return test_fail;
}
/** * s2io_ethtool_test - conducts 6 tsets to determine the health of card. * @dev: pointer to netdev * @ethtest : pointer to a ethtool command specific structure that will be * returned to the user. * @data : variable that returns the result of each of the test * conducted by the driver. * Description: * This function conducts 6 tests ( 4 offline and 2 online) to determine * the health of the card. * Return value: * void
*/
/** * s2io_ioctl - Entry point for the Ioctl * @dev : Device pointer. * @rq : An IOCTL specefic structure, that can contain a pointer to * a proprietary structure used to pass information to the driver. * @cmd : This is used to distinguish between the different commands that * can be passed to the IOCTL functions. * Description: * Currently there are no special functionality supported in IOCTL, hence * function always return EOPNOTSUPPORTED
*/
/** * s2io_change_mtu - entry point to change MTU size for the device. * @dev : device pointer. * @new_mtu : the new MTU size for the device. * Description: A driver entry point to change MTU size for the device. * Before changing the MTU the device must be stopped. * Return value: * 0 on success and an appropriate (-)ve integer as defined in errno.h * file on failure.
*/
staticint s2io_change_mtu(struct net_device *dev, int new_mtu)
{ struct s2io_nic *sp = netdev_priv(dev); int ret = 0;
WRITE_ONCE(dev->mtu, new_mtu); if (netif_running(dev)) {
s2io_stop_all_tx_queue(sp);
s2io_card_down(sp);
ret = s2io_card_up(sp); if (ret) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n",
__func__); return ret;
}
s2io_wake_all_tx_queue(sp);
} else { /* Device is down */ struct XENA_dev_config __iomem *bar0 = sp->bar0;
u64 val64 = new_mtu;
/** * s2io_set_link - Set the LInk status * @work: work struct containing a pointer to device private structure * Description: Sets the link status for the adapter
*/
if (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(nic->state))) { /* The card is being reset, no point doing anything */ goto out_unlock;
}
subid = nic->pdev->subsystem_device; if (s2io_link_fault_indication(nic) == MAC_RMAC_ERR_TIMER) { /* * Allow a small delay for the NICs self initiated * cleanup to complete.
*/
msleep(100);
}
for (j = 0; j < blk_cnt; j++) { for (k = 0; k < rxd_count[sp->rxd_mode]; k++) {
rxdp = ring->rx_blocks[j].rxds[k].virt_addr; if (sp->rxd_mode == RXD_MODE_3B)
ba = &ring->ba[j][k]; if (set_rxd_buffer_pointer(sp, rxdp, ba, &skb,
&temp0_64,
&temp1_64,
&temp2_64,
size) == -ENOMEM) { return 0;
}
set_rxd_buffer_size(sp, rxdp, size);
dma_wmb(); /* flip the Ownership bit to Hardware */
rxdp->Control_1 |= RXD_OWN_XENA;
}
}
} return 0;
}
staticint s2io_add_isr(struct s2io_nic *sp)
{ int ret = 0; struct net_device *dev = sp->dev; int err = 0;
if (sp->config.intr_type == MSI_X)
ret = s2io_enable_msi_x(sp); if (ret) {
DBG_PRINT(ERR_DBG, "%s: Defaulting to INTA\n", dev->name);
sp->config.intr_type = INTA;
}
/* * Store the values of the MSIX table in * the struct s2io_nic structure
*/
store_xmsi_data(sp);
/* After proper initialization of H/W, register ISR */ if (sp->config.intr_type == MSI_X) { int i, msix_rx_cnt = 0;
for (i = 0; i < sp->num_entries; i++) { if (sp->s2io_entries[i].in_use == MSIX_FLG) { if (sp->s2io_entries[i].type ==
MSIX_RING_TYPE) {
snprintf(sp->desc[i], sizeof(sp->desc[i]), "%s:MSI-X-%d-RX",
dev->name, i);
err = request_irq(sp->entries[i].vector,
s2io_msix_ring_handle,
0,
sp->desc[i],
sp->s2io_entries[i].arg);
} elseif (sp->s2io_entries[i].type ==
MSIX_ALARM_TYPE) {
snprintf(sp->desc[i], sizeof(sp->desc[i]), "%s:MSI-X-%d-TX",
dev->name, i);
err = request_irq(sp->entries[i].vector,
s2io_msix_fifo_handle,
0,
sp->desc[i],
sp->s2io_entries[i].arg);
} /* if either data or addr is zero print it. */ if (!(sp->msix_info[i].addr &&
sp->msix_info[i].data)) {
DBG_PRINT(ERR_DBG, "%s @Addr:0x%llx Data:0x%llx\n",
sp->desc[i],
(unsignedlonglong)
sp->msix_info[i].addr,
(unsignedlonglong)
ntohl(sp->msix_info[i].data));
} else
msix_rx_cnt++; if (err) {
remove_msix_isr(sp);
timer_delete_sync(&sp->alarm_timer); /* If s2io_set_link task is executing, wait till it completes. */ while (test_and_set_bit(__S2IO_STATE_LINK_TASK, &(sp->state)))
msleep(50);
clear_bit(__S2IO_STATE_CARD_UP, &sp->state);
/* Disable napi */ if (sp->config.napi) { int off = 0; if (config->intr_type == MSI_X) { for (; off < sp->config.rx_ring_num; off++)
napi_disable(&sp->mac_control.rings[off].napi);
} else
napi_disable(&sp->napi);
}
/* disable Tx and Rx traffic on the NIC */ if (do_io)
stop_nic(sp);
s2io_rem_isr(sp);
/* stop the tx queue, indicate link down */
s2io_link(sp, LINK_DOWN);
/* Check if the device is Quiescent and then Reset the NIC */ while (do_io) { /* As per the HW requirement we need to replenish the * receive buffer to avoid the ring bump. Since there is * no intention of processing the Rx frame at this pointwe are * just setting the ownership bit of rxd in Each Rx * ring to HW and set the appropriate buffer size * based on the ring mode
*/
rxd_owner_bit_reset(sp);
val64 = readq(&bar0->adapter_status); if (verify_xena_quiescence(sp)) { if (verify_pcc_quiescent(sp, sp->device_enabled_once)) break;
}
msleep(50);
cnt++; if (cnt == 10) {
DBG_PRINT(ERR_DBG, "Device not Quiescent - " "adapter status reads 0x%llx\n",
(unsignedlonglong)val64); break;
}
} if (do_io)
s2io_reset(sp);
staticint s2io_card_up(struct s2io_nic *sp)
{ int i, ret = 0; struct config_param *config; struct mac_info *mac_control; struct net_device *dev = sp->dev;
u16 interruptible;
/* Initialize the H/W I/O registers */
ret = init_nic(sp); if (ret != 0) {
DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n",
dev->name); if (ret != -EIO)
s2io_reset(sp); return ret;
}
/* * Initializing the Rx buffers. For now we are considering only 1 * Rx ring and initializing buffers into 30 Rx blocks
*/
config = &sp->config;
mac_control = &sp->mac_control;
for (i = 0; i < config->rx_ring_num; i++) { struct ring_info *ring = &mac_control->rings[i];
ring->mtu = dev->mtu;
ring->lro = !!(dev->features & NETIF_F_LRO);
ret = fill_rx_buffers(sp, ring, 1); if (ret) {
DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n",
dev->name);
ret = -ENOMEM; goto err_fill_buff;
}
DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i,
ring->rx_bufs_left);
}
/* Initialise napi */ if (config->napi) { if (config->intr_type == MSI_X) { for (i = 0; i < sp->config.rx_ring_num; i++)
napi_enable(&sp->mac_control.rings[i].napi);
} else {
napi_enable(&sp->napi);
}
}
/* Maintain the state prior to the open */ if (sp->promisc_flg)
sp->promisc_flg = 0; if (sp->m_cast_flg) {
sp->m_cast_flg = 0;
sp->all_multi_pos = 0;
}
/* Setting its receive mode */
s2io_set_multicast(dev, true);
if (dev->features & NETIF_F_LRO) { /* Initialize max aggregatable pkts per session based on MTU */
sp->lro_max_aggr_per_sess = ((1<<16) - 1) / dev->mtu; /* Check if we can use (if specified) user provided value */ if (lro_max_pkts < sp->lro_max_aggr_per_sess)
sp->lro_max_aggr_per_sess = lro_max_pkts;
}
/* Enable Rx Traffic and interrupts on the NIC */ if (start_nic(sp)) {
DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name);
ret = -ENODEV; goto err_out;
}
/* Add interrupt service routine */ if (s2io_add_isr(sp) != 0) { if (sp->config.intr_type == MSI_X)
s2io_rem_isr(sp);
ret = -ENODEV; goto err_out;
}
err_out: if (config->napi) { if (config->intr_type == MSI_X) { for (i = 0; i < sp->config.rx_ring_num; i++)
napi_disable(&sp->mac_control.rings[i].napi);
} else {
napi_disable(&sp->napi);
}
}
err_fill_buff:
s2io_reset(sp);
free_rx_buffers(sp); return ret;
}
/** * s2io_restart_nic - Resets the NIC. * @work : work struct containing a pointer to the device private structure * Description: * This function is scheduled to be run by the s2io_tx_watchdog * function after 0.5 secs to reset the NIC. The idea is to reduce * the run time of the watch dog routine which is run holding a * spin lock.
*/
s2io_card_down(sp); if (s2io_card_up(sp)) {
DBG_PRINT(ERR_DBG, "%s: Device bring up failed\n", dev->name);
}
s2io_wake_all_tx_queue(sp);
DBG_PRINT(ERR_DBG, "%s: was reset by Tx watchdog timer\n", dev->name);
out_unlock:
rtnl_unlock();
}
/** * s2io_tx_watchdog - Watchdog for transmit side. * @dev : Pointer to net device structure * @txqueue: index of the hanging queue * Description: * This function is triggered if the Tx Queue is stopped * for a pre-defined amount of time when the Interface is still up. * If the Interface is jammed in such a situation, the hardware is * reset (by s2io_close) and restarted again (by s2io_open) to * overcome any problem that might have been caused in the hardware. * Return value: * void
*/
if (netif_carrier_ok(dev)) {
swstats->watchdog_timer_cnt++;
schedule_work(&sp->rst_timer_task);
swstats->soft_reset_cnt++;
}
}
/** * rx_osm_handler - To perform some OS related operations on SKB. * @ring_data : the ring from which this RxD was extracted. * @rxdp: descriptor * Description: * This function is called by the Rx interrupt serivce routine to perform * some OS related operations on the SKB before passing it to the upper * layers. It mainly checks if the checksum is OK, if so adds it to the * SKBs cksum variable, increments the Rx packet count and passes the SKB * to the upper layer. If the checksum is wrong, it increments the Rx * packet error count, frees the SKB and returns error. * Return value: * SUCCESS on success and -1 on failure.
*/ staticint rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp)
{ struct s2io_nic *sp = ring_data->nic; struct net_device *dev = ring_data->dev; struct sk_buff *skb = (struct sk_buff *)
((unsignedlong)rxdp->Host_Control); int ring_no = ring_data->ring_no;
u16 l3_csum, l4_csum; unsignedlonglong err = rxdp->Control_1 & RXD_T_CODE; struct lro *lro;
u8 err_mask; struct swStat *swstats = &sp->mac_control.stats_info->sw_stat;
skb->dev = dev;
if (err) { /* Check for parity error */ if (err & 0x1)
swstats->parity_err_cnt++;
case 15:
swstats->rx_unkn_err_cnt++; break;
} /* * Drop the packet if bad transfer code. Exception being * 0x5, which could be due to unsupported IPv6 extension header. * In this case, we let stack handle the packet. * Note that in this case, since checksum will be incorrect, * stack will validate the same.
*/ if (err_mask != 0x5) {
DBG_PRINT(ERR_DBG, "%s: Rx error Value: 0x%x\n",
dev->name, err_mask);
dev->stats.rx_crc_errors++;
swstats->mem_freed
+= skb->truesize;
dev_kfree_skb(skb);
ring_data->rx_bufs_left -= 1;
rxdp->Host_Control = 0; return 0;
}
}
rxdp->Host_Control = 0; if (sp->rxd_mode == RXD_MODE_1) { int len = RXD_GET_BUFFER0_SIZE_1(rxdp->Control_2);
skb_put(skb, len);
} elseif (sp->rxd_mode == RXD_MODE_3B) { int get_block = ring_data->rx_curr_get_info.block_index; int get_off = ring_data->rx_curr_get_info.offset; int buf0_len = RXD_GET_BUFFER0_SIZE_3(rxdp->Control_2); int buf2_len = RXD_GET_BUFFER2_SIZE_3(rxdp->Control_2);
if ((rxdp->Control_1 & TCP_OR_UDP_FRAME) &&
((!ring_data->lro) ||
(!(rxdp->Control_1 & RXD_FRAME_IP_FRAG))) &&
(dev->features & NETIF_F_RXCSUM)) {
l3_csum = RXD_GET_L3_CKSUM(rxdp->Control_1);
l4_csum = RXD_GET_L4_CKSUM(rxdp->Control_1); if ((l3_csum == L3_CKSUM_OK) && (l4_csum == L4_CKSUM_OK)) { /* * NIC verifies if the Checksum of the received * frame is Ok or not and accordingly returns * a flag in the RxD.
*/
skb->ip_summed = CHECKSUM_UNNECESSARY; if (ring_data->lro) {
u32 tcp_len = 0;
u8 *tcp; int ret = 0;
ret = s2io_club_tcp_session(ring_data,
skb->data, &tcp,
&tcp_len, &lro,
rxdp, sp); switch (ret) { case 3: /* Begin anew */
lro->parent = skb; goto aggregate; case 1: /* Aggregate */
lro_append_pkt(sp, lro, skb, tcp_len); goto aggregate; case 4: /* Flush session */
lro_append_pkt(sp, lro, skb, tcp_len);
queue_rx_frame(lro->parent,
lro->vlan_tag);
clear_lro_session(lro);
swstats->flush_max_pkts++; goto aggregate; case 2: /* Flush both */
lro->parent->data_len = lro->frags_len;
swstats->sending_both++;
queue_rx_frame(lro->parent,
lro->vlan_tag);
clear_lro_session(lro); goto send_up; case 0: /* sessions exceeded */ case -1: /* non-TCP or not L2 aggregatable */ case 5: /* * First pkt in session not * L3/L4 aggregatable
*/ break; default:
DBG_PRINT(ERR_DBG, "%s: Samadhana!!\n",
__func__);
BUG();
}
}
} else { /* * Packet with erroneous checksum, let the * upper layers deal with it.
*/
skb_checksum_none_assert(skb);
}
} else
skb_checksum_none_assert(skb);
/** * s2io_link - stops/starts the Tx queue. * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * @link : inidicates whether link is UP/DOWN. * Description: * This function stops/starts the Tx queue depending on whether the link * status of the NIC is down or up. This is called by the Alarm * interrupt handler whenever a link change interrupt comes up. * Return value: * void.
*/
if (link != sp->last_link_state) {
init_tti(sp, link, false); if (link == LINK_DOWN) {
DBG_PRINT(ERR_DBG, "%s: Link down\n", dev->name);
s2io_stop_all_tx_queue(sp);
netif_carrier_off(dev); if (swstats->link_up_cnt)
swstats->link_up_time =
jiffies - sp->start_time;
swstats->link_down_cnt++;
} else {
DBG_PRINT(ERR_DBG, "%s: Link Up\n", dev->name); if (swstats->link_down_cnt)
swstats->link_down_time =
jiffies - sp->start_time;
swstats->link_up_cnt++;
netif_carrier_on(dev);
s2io_wake_all_tx_queue(sp);
}
}
sp->last_link_state = link;
sp->start_time = jiffies;
}
/** * s2io_init_pci -Initialization of PCI and PCI-X configuration registers . * @sp : private member of the device structure, which is a pointer to the * s2io_nic structure. * Description: * This function initializes a few of the PCI and PCI-X configuration registers * with recommended values. * Return value: * void
*/
if (rx_ring_num > MAX_RX_RINGS) {
DBG_PRINT(ERR_DBG, "Requested number of rx rings not supported\n");
DBG_PRINT(ERR_DBG, "Default to %d rx rings\n",
MAX_RX_RINGS);
rx_ring_num = MAX_RX_RINGS;
}
if ((*dev_intr_type == MSI_X) &&
((pdev->device != PCI_DEVICE_ID_HERC_WIN) &&
(pdev->device != PCI_DEVICE_ID_HERC_UNI))) {
DBG_PRINT(ERR_DBG, "Xframe I does not support MSI_X. " "Defaulting to INTA\n");
*dev_intr_type = INTA;
}
if ((rx_ring_mode != 1) && (rx_ring_mode != 2)) {
DBG_PRINT(ERR_DBG, "Requested ring mode not supported\n");
DBG_PRINT(ERR_DBG, "Defaulting to 1-buffer mode\n");
rx_ring_mode = 1;
}
for (i = 0; i < MAX_RX_RINGS; i++) if (rx_ring_sz[i] > MAX_RX_BLOCKS_PER_RING) {
DBG_PRINT(ERR_DBG, "Requested rx ring size not " "supported\nDefaulting to %d\n",
MAX_RX_BLOCKS_PER_RING);
rx_ring_sz[i] = MAX_RX_BLOCKS_PER_RING;
}
return SUCCESS;
}
/** * rts_ds_steer - Receive traffic steering based on IPv4 or IPv6 TOS or Traffic class respectively. * @nic: device private variable * @ds_codepoint: data * @ring: ring index * Description: The function configures the receive steering to * desired receive ring. * Return Value: SUCCESS on success and * '-1' on failure (endian settings incorrect).
*/ staticint rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring)
{ struct XENA_dev_config __iomem *bar0 = nic->bar0; register u64 val64 = 0;
/** * s2io_init_nic - Initialization of the adapter . * @pdev : structure containing the PCI related information of the device. * @pre: List of PCI devices supported by the driver listed in s2io_tbl. * Description: * The function initializes an adapter identified by the pci_dec structure. * All OS related initialization including memory and device structure and * initlaization of the device private variable is done. Also the swapper * control register is initialized to enable read and write into the I/O * registers of the device. * Return value: * returns 0 on success and negative on failure.
*/
/* Initialize some PCI/PCI-X fields of the NIC. */
s2io_init_pci(sp);
/* * Setting the device configuration parameters. * Most of these parameters can be specified by the user during * module insertion as they are module loadable parameters. If * these parameters are not specified during load time, they * are initialized with default values.
*/
config = &sp->config;
mac_control = &sp->mac_control;
/* mapping the QoS priority to the configured fifos */ for (i = 0; i < MAX_TX_FIFOS; i++)
config->fifo_mapping[i] = fifo_map[config->tx_fifo_num - 1][i];
/* map the hashing selector table to the configured fifos */ for (i = 0; i < config->tx_fifo_num; i++)
sp->fifo_selector[i] = fifo_selector[i];
config->tx_intr_type = TXD_INT_TYPE_UTILZ; for (i = 0; i < config->tx_fifo_num; i++) { struct tx_fifo_config *tx_cfg = &config->tx_cfg[i];
tx_cfg->f_no_snoop = (NO_SNOOP_TXD | NO_SNOOP_TXD_BUFFER); if (tx_cfg->fifo_len < 65) {
config->tx_intr_type = TXD_INT_TYPE_PER_LIST; break;
}
} /* + 2 because one Txd for skb->data and one Txd for UFO */
config->max_txds = MAX_SKB_FRAGS + 2;
/* Rx side parameters. */
config->rx_ring_num = rx_ring_num; for (i = 0; i < config->rx_ring_num; i++) { struct rx_ring_config *rx_cfg = &config->rx_cfg[i]; struct ring_info *ring = &mac_control->rings[i];
/* Setting Mac Control parameters */
mac_control->rmac_pause_time = rmac_pause_time;
mac_control->mc_pause_threshold_q0q3 = mc_pause_threshold_q0q3;
mac_control->mc_pause_threshold_q4q7 = mc_pause_threshold_q4q7;
/* initialize the shared memory used by the NIC and the host */ if (init_shared_mem(sp)) {
DBG_PRINT(ERR_DBG, "%s: Memory allocation failed\n", dev->name);
ret = -ENOMEM; goto mem_alloc_failed;
}
/* Initializing the BAR1 address as the start of the FIFO pointer. */ for (j = 0; j < MAX_TX_FIFOS; j++) {
mac_control->tx_FIFO_start[j] = sp->bar1 + (j * 0x00020000);
}
/* Setting swapper control on the NIC, for proper reset operation */ if (s2io_set_swapper(sp)) {
DBG_PRINT(ERR_DBG, "%s: swapper settings are wrong\n",
dev->name);
ret = -EAGAIN; goto set_swap_failed;
}
/* Verify if the Herc works on the slot its placed into */ if (sp->device_type & XFRAME_II_DEVICE) {
mode = s2io_verify_pci_mode(sp); if (mode < 0) {
DBG_PRINT(ERR_DBG, "%s: Unsupported PCI bus mode\n",
__func__);
ret = -EBADSLT; goto set_swap_failed;
}
}
if (sp->config.intr_type == MSI_X) {
sp->num_entries = config->rx_ring_num + 1;
ret = s2io_enable_msi_x(sp);
if (!ret) {
ret = s2io_test_msi(sp); /* rollback MSI-X, will re-enable during add_isr() */
remove_msix_isr(sp);
} if (ret) {
DBG_PRINT(ERR_DBG, "MSI-X requested but failed to enable\n");
sp->config.intr_type = INTA;
}
}
if (config->intr_type == MSI_X) { for (i = 0; i < config->rx_ring_num ; i++) { struct ring_info *ring = &mac_control->rings[i];
/* Not needed for Herc */ if (sp->device_type & XFRAME_I_DEVICE) { /* * Fix for all "FFs" MAC address problems observed on * Alpha platforms
*/
fix_mac_address(sp);
s2io_reset(sp);
}
/* * MAC address initialization. * For now only one mac address will be read and used.
*/
bar0 = sp->bar0;
val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD |
RMAC_ADDR_CMD_MEM_OFFSET(0 + S2IO_MAC_ADDR_START_OFFSET);
writeq(val64, &bar0->rmac_addr_cmd_mem);
wait_for_cmd_complete(&bar0->rmac_addr_cmd_mem,
RMAC_ADDR_CMD_MEM_STROBE_CMD_EXECUTING,
S2IO_BIT_RESET, true);
tmp64 = readq(&bar0->rmac_addr_data0_mem);
mac_down = (u32)tmp64;
mac_up = (u32) (tmp64 >> 32);
/* store mac addresses from CAM to s2io_nic structure */
do_s2io_store_unicast_mc(sp);
/* Configure MSIX vector for number of rings configured plus one */ if ((sp->device_type == XFRAME_II_DEVICE) &&
(config->intr_type == MSI_X))
sp->num_entries = config->rx_ring_num + 1;
/* Store the values of the MSIX table in the s2io_nic structure */
store_xmsi_data(sp); /* reset Nic and bring it to known state */
s2io_reset(sp);
/* * Initialize link state flags * and the card state parameter
*/
sp->state = 0;
/* Initialize spinlocks */ for (i = 0; i < sp->config.tx_fifo_num; i++) { struct fifo_info *fifo = &mac_control->fifos[i];
spin_lock_init(&fifo->tx_lock);
}
/* * SXE-002: Configure link and activity LED to init state * on driver load.
*/
subid = sp->pdev->subsystem_device; if ((subid & 0xFF) >= 0x07) {
val64 = readq(&bar0->gpio_control);
val64 |= 0x0000800000000000ULL;
writeq(val64, &bar0->gpio_control);
val64 = 0x0411040400000000ULL;
writeq(val64, (void __iomem *)bar0 + 0x2700);
val64 = readq(&bar0->gpio_control);
}
switch (sp->config.napi) { case 0:
DBG_PRINT(ERR_DBG, "%s: NAPI disabled\n", dev->name); break; case 1:
DBG_PRINT(ERR_DBG, "%s: NAPI enabled\n", dev->name); break;
}
DBG_PRINT(ERR_DBG, "%s: Using %d Tx fifo(s)\n", dev->name,
sp->config.tx_fifo_num);
DBG_PRINT(ERR_DBG, "%s: Using %d Rx ring(s)\n", dev->name,
sp->config.rx_ring_num);
switch (sp->config.intr_type) { case INTA:
DBG_PRINT(ERR_DBG, "%s: Interrupt type INTA\n", dev->name); break; case MSI_X:
DBG_PRINT(ERR_DBG, "%s: Interrupt type MSI-X\n", dev->name); break;
} if (sp->config.multiq) { for (i = 0; i < sp->config.tx_fifo_num; i++) { struct fifo_info *fifo = &mac_control->fifos[i];
fifo->multiq = config->multiq;
}
DBG_PRINT(ERR_DBG, "%s: Multiqueue support enabled\n",
dev->name);
} else
DBG_PRINT(ERR_DBG, "%s: Multiqueue support disabled\n",
dev->name);
switch (sp->config.tx_steering_type) { case NO_STEERING:
DBG_PRINT(ERR_DBG, "%s: No steering enabled for transmit\n",
dev->name); break; case TX_PRIORITY_STEERING:
DBG_PRINT(ERR_DBG, "%s: Priority steering enabled for transmit\n",
dev->name); break; case TX_DEFAULT_STEERING:
DBG_PRINT(ERR_DBG, "%s: Default steering enabled for transmit\n",
dev->name);
}
DBG_PRINT(ERR_DBG, "%s: Large receive offload enabled\n",
dev->name); /* Initialize device name */
snprintf(sp->name, sizeof(sp->name), "%s Neterion %s", dev->name,
sp->product_name);
if (vlan_tag_strip)
sp->vlan_strip_flag = 1; else
sp->vlan_strip_flag = 0;
/* * Make Link state as off at this point, when the Link change * interrupt comes the state will be automatically changed to * the right state.
*/
netif_carrier_off(dev);
/** * s2io_rem_nic - Free the PCI device * @pdev: structure containing the PCI related information of the device. * Description: This function is called by the Pci subsystem to release a * PCI device and free up all resource held up by the device. This could * be in response to a Hot plug event or when the driver is to be removed * from memory.
*/
if (!(rxdp->Control_1 & RXD_FRAME_PROTO_TCP)) {
DBG_PRINT(INIT_DBG, "%s: Non-TCP frames not supported for LRO\n",
__func__); return -1;
}
/* Checking for DIX type or DIX type with VLAN */ if ((l2_type == 0) || (l2_type == 4)) {
ip_off = HEADER_ETHERNET_II_802_3_SIZE; /* * If vlan stripping is disabled and the frame is VLAN tagged, * shift the offset by the VLAN header size bytes.
*/ if ((!sp->vlan_strip_flag) &&
(rxdp->Control_1 & RXD_FRAME_VLAN_TAG))
ip_off += HEADER_VLAN_SIZE;
} else { /* LLC, SNAP etc are considered non-mergeable */ return -1;
}
/* Update tsecr field if this session has timestamps enabled */ if (lro->saw_ts) {
__be32 *ptr = (__be32 *)(tcp + 1);
*(ptr+2) = lro->cur_tsecr;
}
/* Update counters required for calculation of * average no. of packets aggregated.
*/
swstats->sum_avg_pkts_aggregated += lro->sg_num;
swstats->num_aggregations++;
}
DBG_PRINT(INFO_DBG, "%s: Been here...\n", __func__);
if (!tcp_pyld_len) { /* Runt frame or a pure ack */ return -1;
}
if (ip->ihl != 5) /* IP has options */ return -1;
/* If we see CE codepoint in IP header, packet is not mergeable */ if (INET_ECN_is_ce(ipv4_get_dsfield(ip))) return -1;
/* If we see ECE or CWR flags in TCP header, packet is not mergeable */ if (tcp->urg || tcp->psh || tcp->rst ||
tcp->syn || tcp->fin ||
tcp->ece || tcp->cwr || !tcp->ack) { /* * Currently recognize only the ack control word and * any other control field being set would result in * flushing the LRO session
*/ return -1;
}
/* * Allow only one TCP timestamp option. Don't aggregate if * any other options are detected.
*/ if (tcp->doff != 5 && tcp->doff != 8) return -1;
if (tcp->doff == 8) {
ptr = (u8 *)(tcp + 1); while (*ptr == TCPOPT_NOP)
ptr++; if (*ptr != TCPOPT_TIMESTAMP || *(ptr+1) != TCPOLEN_TIMESTAMP) return -1;
/* Ensure timestamp value increases monotonically */ if (l_lro) if (l_lro->cur_tsval > ntohl(*((__be32 *)(ptr+2)))) return -1;
/* timestamp echo reply should be non-zero */ if (*((__be32 *)(ptr+6)) == 0) return -1;
}
vlan_tag = RXD_GET_VLAN_TAG(rxdp->Control_2);
tcph = (struct tcphdr *)*tcp;
*tcp_len = get_l4_pyld_length(ip, tcph); for (i = 0; i < MAX_LRO_SESSIONS; i++) { struct lro *l_lro = &ring_data->lro0_n[i]; if (l_lro->in_use) { if (check_for_socket_match(l_lro, ip, tcph)) continue; /* Sock pair matched */
*lro = l_lro;
if ((*lro)->tcp_next_seq != ntohl(tcph->seq)) {
DBG_PRINT(INFO_DBG, "%s: Out of sequence. " "expected 0x%x, actual 0x%x\n",
__func__,
(*lro)->tcp_next_seq,
ntohl(tcph->seq));
swstats->outof_sequence_pkts++;
ret = 2; break;
}
if (!verify_l3_l4_lro_capable(l_lro, ip, tcph,
*tcp_len))
ret = 1; /* Aggregate */ else
ret = 2; /* Flush both */ break;
}
}
if (ret == 0) { /* Before searching for available LRO objects, * check if the pkt is L3/L4 aggregatable. If not * don't create new LRO session. Just send this * packet up.
*/ if (verify_l3_l4_lro_capable(NULL, ip, tcph, *tcp_len)) return 5;
for (i = 0; i < MAX_LRO_SESSIONS; i++) { struct lro *l_lro = &ring_data->lro0_n[i]; if (!(l_lro->in_use)) {
*lro = l_lro;
ret = 3; /* Begin anew */ break;
}
}
}
if (ret == 0) { /* sessions exceeded */
DBG_PRINT(INFO_DBG, "%s: All LRO sessions already in use\n",
__func__);
*lro = NULL; return ret;
}
switch (ret) { case 3:
initiate_new_session(*lro, buffer, ip, tcph, *tcp_len,
vlan_tag); break; case 2:
update_L3L4_header(sp, *lro); break; case 1:
aggregate_new_rx(*lro, ip, tcph, *tcp_len); if ((*lro)->sg_num == sp->lro_max_aggr_per_sess) {
update_L3L4_header(sp, *lro);
ret = 4; /* Flush the LRO */
} break; default:
DBG_PRINT(ERR_DBG, "%s: Don't know, can't say!!\n", __func__); break;
}
/** * s2io_io_error_detected - called when PCI error is detected * @pdev: Pointer to PCI device * @state: The current pci connection state * * This function is called after a PCI bus error affecting * this device has been detected.
*/ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{ struct net_device *netdev = pci_get_drvdata(pdev); struct s2io_nic *sp = netdev_priv(netdev);
netif_device_detach(netdev);
if (state == pci_channel_io_perm_failure) return PCI_ERS_RESULT_DISCONNECT;
if (netif_running(netdev)) { /* Bring down the card, while avoiding PCI I/O */
do_s2io_card_down(sp, 0);
}
pci_disable_device(pdev);
return PCI_ERS_RESULT_NEED_RESET;
}
/** * s2io_io_slot_reset - called after the pci bus has been reset. * @pdev: Pointer to PCI device * * Restart the card from scratch, as if from a cold-boot. * At this point, the card has experienced a hard reset, * followed by fixups by BIOS, and has its config space * set up identically to what it was at cold boot.
*/ static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev)
{ struct net_device *netdev = pci_get_drvdata(pdev); struct s2io_nic *sp = netdev_priv(netdev);
if (pci_enable_device(pdev)) {
pr_err("Cannot re-enable PCI device after reset.\n"); return PCI_ERS_RESULT_DISCONNECT;
}
pci_set_master(pdev);
s2io_reset(sp);
return PCI_ERS_RESULT_RECOVERED;
}
/** * s2io_io_resume - called when traffic can start flowing again. * @pdev: Pointer to PCI device * * This callback is called when the error recovery driver tells * us that its OK to resume normal operation.
*/ staticvoid s2io_io_resume(struct pci_dev *pdev)
{ struct net_device *netdev = pci_get_drvdata(pdev); struct s2io_nic *sp = netdev_priv(netdev);
if (netif_running(netdev)) { if (s2io_card_up(sp)) {
pr_err("Can't bring device back up after reset.\n"); return;
}
if (do_s2io_prog_unicast(netdev, netdev->dev_addr) == FAILURE) {
s2io_card_down(sp);
pr_err("Can't restore mac addr after reset.\n"); return;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.