?? s2io.c
字號:
/* Updating the statistics block */ nic->stats.tx_packets++; nic->stats.tx_bytes += skb->len;#if DEBUG_ON nic->txpkt_bytes += skb->len; cnt++;#endif dev_kfree_skb_irq(skb); offset_info.offset++; offset_info.offset %= offset_info.fifo_len + 1; txdlp = mac_control->txdl_start[i] + (config->MaxTxDs * offset_info.offset); mac_control->tx_curr_get_info[i].offset = offset_info.offset; }#if DEBUG_ON DBG_PRINT(INTR_DBG, "%s: freed %d Tx Pkts\n", dev->name, cnt);#endif } spin_lock(&nic->tx_lock); if (netif_queue_stopped(dev)) netif_wake_queue(dev); spin_unlock(&nic->tx_lock);}/* * Input Arguments: * device private variable * Return Value: * NONE * Description: * If the interrupt was neither because of Rx packet or Tx * complete, this function is called. If the interrupt was to indicate a loss * of link, the OSM link status handler is invoked for any other alarm * interrupt the block that raised the interrupt is displayed and a H/W reset * is issued. */static void alarmIntrHandler(struct s2io_nic *nic){ struct net_device *dev = (struct net_device *) nic->dev; XENA_dev_config_t *bar0 = (XENA_dev_config_t *) nic->bar0; register u64 val64 = 0, err_reg = 0; /* Handling link status change error Intr */ err_reg = readq(&bar0->mac_rmac_err_reg); if (err_reg & RMAC_LINK_STATE_CHANGE_INT) { schedule_work(&nic->set_link_task); } /* Handling SERR errors by stopping device Xmit queue and forcing * a H/W reset. */ val64 = readq(&bar0->serr_source); if (val64 & SERR_SOURCE_ANY) { DBG_PRINT(ERR_DBG, "%s: Device indicates ", dev->name); DBG_PRINT(ERR_DBG, "serious error!!\n"); netif_stop_queue(dev); }/* Other type of interrupts are not being handled now, TODO*/}/* * Input Argument: * sp - private member of the device structure, which is a pointer to the * s2io_nic structure. * Return value: * SUCCESS on success and FAILURE on failure. * 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. */int waitForCmdComplete(nic_t * sp){ XENA_dev_config_t *bar0 = (XENA_dev_config_t *) sp->bar0; int ret = FAILURE, cnt = 0; u64 val64; while (TRUE) { val64 = RMAC_ADDR_CMD_MEM_RD | RMAC_ADDR_CMD_MEM_STROBE_NEW_CMD | RMAC_ADDR_CMD_MEM_OFFSET(0); writeq(val64, &bar0->rmac_addr_cmd_mem); val64 = readq(&bar0->rmac_addr_cmd_mem); if (!val64) { ret = SUCCESS; break; } set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 20); if (cnt++ > 10) break; } return ret;}/* * Input Argument: * sp - private member of the device structure, which is a pointer to the * s2io_nic structure. * Return value: * void. * 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 * Configration space. */void s2io_reset(nic_t * sp){ XENA_dev_config_t *bar0 = (XENA_dev_config_t *) sp->bar0; u64 val64; u16 subid; val64 = SW_RESET_ALL; writeq(val64, &bar0->sw_reset); /* At this stage, if the PCI write is indeed completed, the * card is reset and so is the PCI Config space of the device. * So a read cannot be issued at this stage on any of the * registers to ensure the write into "sw_reset" register * has gone through. * Question: Is there any system call that will explicitly force * all the write commands still pending on the bus to be pushed * through? * As of now I'am just giving a 250ms delay and hoping that the * PCI write to sw_reset register is done by this time. */ set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 4); /* Restore the PCI state saved during initializarion. */ pci_restore_state(sp->pdev, sp->config_space); s2io_init_pci(sp); set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 4); /* SXE-002: Configure link and activity LED to turn it off */ 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 *) ((u8 *) bar0 + 0x2700)); } sp->device_enabled_once = FALSE;}/* * Input Argument: * sp - private member of the device structure, which is a pointer to the * s2io_nic structure. * Return value: * SUCCESS on success and FAILURE on failure. * Description: * Function to set the swapper control on the card correctly depending on the * 'endianness' of the system. */int s2io_set_swapper(nic_t * sp){ struct net_device *dev = sp->dev; XENA_dev_config_t *bar0 = (XENA_dev_config_t *) sp->bar0; u64 val64;/* Set proper endian settings and verify the same by reading the PIF * Feed-back register. */#ifdef __BIG_ENDIAN/* The device by default set to a big endian format, so a big endian * driver need not set anything. */ writeq(0xffffffffffffffffULL, &bar0->swapper_ctrl); val64 = (SWAPPER_CTRL_PIF_R_FE | SWAPPER_CTRL_PIF_R_SE | SWAPPER_CTRL_PIF_W_FE | SWAPPER_CTRL_PIF_W_SE | 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_XMSI_SE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_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. */ writeq(0xffffffffffffffffULL, &bar0->swapper_ctrl); val64 = (SWAPPER_CTRL_PIF_R_FE | SWAPPER_CTRL_PIF_R_SE | SWAPPER_CTRL_PIF_W_FE | SWAPPER_CTRL_PIF_W_SE | 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_XMSI_SE | SWAPPER_CTRL_STATS_FE | SWAPPER_CTRL_STATS_SE); writeq(val64, &bar0->swapper_ctrl);#endif/* 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, ", dev->name); DBG_PRINT(ERR_DBG, "feedback read %llx\n", (unsigned long long) val64); return FAILURE; } return SUCCESS;}/* ********************************************************* * * Functions defined below concern the OS part of the driver * * ********************************************************* *//* * Input Argument: * dev - pointer to the device structure. * Return value: * '0' on success and an appropriate (-)ve integer as defined in errno.h * file on failure. * 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. */int s2io_open(struct net_device *dev){ nic_t *sp = dev->priv; int i, ret = 0, err = 0; mac_info_t *mac_control; struct config_param *config;/* Make sure you have link off by default every time Nic is initialized*/ netif_carrier_off(dev); sp->last_link_state = LINK_DOWN;/* Initialize the H/W I/O registers */ if (initNic(sp) != 0) { DBG_PRINT(ERR_DBG, "%s: H/W initialization failed\n", dev->name); return -ENODEV; }/* After proper initialization of H/W, register ISR */ err = request_irq((int) sp->irq, s2io_isr, SA_SHIRQ, sp->name, dev); if (err) { s2io_reset(sp); DBG_PRINT(ERR_DBG, "%s: ISR registration failed\n", dev->name); return err; } if (s2io_set_mac_addr(dev, dev->dev_addr) == FAILURE) { DBG_PRINT(ERR_DBG, "Set Mac Address Failed\n"); s2io_reset(sp); return -ENODEV; }/* Setting its receive mode */ s2io_set_multicast(dev);/* Initializing the Rx buffers. For now we are considering only 1 Rx ring * and initializing buffers into 1016 RxDs or 8 Rx blocks */ mac_control = &sp->mac_control; config = &sp->config; for (i = 0; i < config->RxRingNum; i++) { if ((ret = fill_rx_buffers(sp, i))) { DBG_PRINT(ERR_DBG, "%s: Out of memory in Open\n", dev->name); s2io_reset(sp); free_irq(dev->irq, dev); freeRxBuffers(sp); return -ENOMEM; } DBG_PRINT(INFO_DBG, "Buf in ring:%d is %d:\n", i, atomic_read(&sp->rx_bufs_left[i])); }/* Enable tasklet for the device */ tasklet_init(&sp->task, s2io_tasklet, (unsigned long) dev);/* Enable Rx Traffic and interrupts on the NIC */ if (startNic(sp)) { DBG_PRINT(ERR_DBG, "%s: Starting NIC failed\n", dev->name); tasklet_kill(&sp->task); s2io_reset(sp); free_irq(dev->irq, dev); freeRxBuffers(sp); return -ENODEV; } sp->device_close_flag = FALSE; /* Device is up and running. */ netif_start_queue(dev); return 0;}/* * Input Argument/s: * dev - device pointer. * Return value: * '0' on success and an appropriate (-)ve integer as defined in errno.h * file on failure. * 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. */int s2io_close(struct net_device *dev){ nic_t *sp = dev->priv; XENA_dev_config_t *bar0 = (XENA_dev_config_t *) sp->bar0; register u64 val64 = 0; u16 cnt = 0; spin_lock(&sp->isr_lock); netif_stop_queue(dev);/* disable Tx and Rx traffic on the NIC */ stopNic(sp); spin_unlock(&sp->isr_lock);/* If the device tasklet is running, wait till its done before killing it */ while (atomic_read(&(sp->tasklet_status))) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 10); } tasklet_kill(&sp->task);/* Check if the device is Quiescent and then Reset the NIC */ do { val64 = readq(&bar0->adapter_status); if (verify_xena_quiescence(val64, sp->device_enabled_once)) { break; } set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(HZ / 20); cnt++; if (cnt == 10) { DBG_PRINT(ERR_DBG, "s2io_close:Device not Quiescent "); DBG_PRINT(ERR_DBG, "adaper status reads 0x%llx\n", (unsigned long long) val64); break; } } while (1); s2io_reset(sp);/* Free the Registered IRQ */ free_irq(dev->irq, dev);/* Free all Tx Buffers waiting for transmission */ freeTxBuffers(sp);/* Free all Rx buffers allocated by host */ freeRxBuffers(sp); sp->device_close_flag = TRUE; /* Device is shut down. */ return 0;}/* * Input Argument/s: * skb - the socket buffer containing the Tx data. * dev - device pointer. * Return value: * '0' on success & 1 on failure. * NOTE: when device cant queue the pkt, just the trans_start variable will * not be upadted. * 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. */int s2io_xmit(struct sk_buff *skb, struct net_device *dev){ nic_t *sp = dev->priv; u16 off, txd_len, frg_cnt, frg_len, i, queue, off1, queue_len; register u64 val64; TxD_t *txdp; TxFIFO_element_t *tx_fifo; unsigned long flags;#ifdef NETIF_F_TSO int mss;#endif mac_info_t *mac_control; struct config_param *config; mac_control = &sp->mac_control; config = &sp->config; DBG_PRINT(TX_DBG, "%s: In S2IO Tx routine\n", dev->name); spin_lock_irqsave(&sp->tx_lock, flags); queue = 0; /* Multi FIFO Tx is disabled for now. */ if (!queue && tx_prio) { u8 x = (skb->data)[5]; queue = x % config->TxFIFONum; } off = (u16) mac_control->tx_curr_put_info[queue].offset; off1 = (u16) mac_control->tx_curr_get_info[queue].offset; txd_len = mac_control->txdl_len; txdp = mac_control->txdl_start[queue] + (config->MaxTxDs * off); queue_len = mac_control->tx_curr_put_info[queue].fifo_len + 1; /* Avoid "put" pointer going beyond "get" pointer */ if (txdp->Host_Control || (((off + 1) % queue_len) == off1)) { DBG_PRINT(ERR_DBG, "Error in xmit, No free TXDs.\n"); netif_stop_queue(dev); dev_kfree_skb(skb); spin_unlock_irqres
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -