📄 e100_main.c
字号:
#ifdef E100_IDIAG_PRO_SUPPORT case IDIAG_PRO_BASE_SIOC: diag_status = e100_run_idiag(dev, diag_data); switch (diag_status) { case IDIAG_PRO_STAT_OK: case IDIAG_PRO_STAT_TEST_FAILED: return 0; case IDIAG_PRO_STAT_NOT_SUPPORTED: return -EINVAL; case IDIAG_PRO_STAT_INVALID_STATE: return -EBUSY; default: /* should not happen */ return -EINVAL; }#endif /* E100_IDIAG_PRO_SUPPORT */#ifdef SIOCETHTOOL case SIOCETHTOOL: return e100_do_ethtool_ioctl(dev, ifr); break;#endif /*SIOCETHTOOL */#ifdef SIOCGMIIPHY case SIOCGMIIPHY: /* Get address of MII PHY in use. */ case SIOCGMIIREG: /* Read MII PHY register. */ case SIOCSMIIREG: /* Write to MII PHY register. */ return e100_mii_ioctl(dev, ifr, cmd); break;#endif /* SIOCGMIIPHY */ default: return -EOPNOTSUPP; } return 0;}/** * e100init - initialize the adapter * @bdp: atapter's private data struct * * This routine is called when this driver is loaded. This is the initialization * routine which allocates memory, configures the adapter and determines the * system resources. * * Returns: * true: if successful * false: otherwise */static unsigned char __devinite100_init(struct e100_private *bdp){ e100_sw_init(bdp); if (!e100_selftest(bdp, NULL, NULL)) { printk(KERN_ERR "e100: selftest failed\n"); return false; } /* read the MAC address from the eprom */ e100_rd_eaddr(bdp); /* read NIC's part number */ e100_rd_pwa_no(bdp); if (!e100_hw_init(bdp, PORT_SOFTWARE_RESET)) { printk(KERN_ERR "e100: hw init failed\n"); return false; } e100_dis_intr(bdp); return true;}/** * e100_sw_init - initialize software structs * @bdp: atapter's private data struct * * This routine initializes all software structures. Sets up the * circular structures for the RFD's & TCB's. Allocates the per board * structure for storing adapter information. The CSR is also memory * mapped in this routine. * * Returns : * true: if S/W was successfully initialized * false: otherwise */static unsigned char __devinite100_sw_init(struct e100_private *bdp){#ifdef IANS bd_ans_drv_InitANS(bdp, bdp->iANSdata);#endif bdp->next_cu_cmd = START_WAIT; // init the next cu state /* * Set the value for # of good xmits per underrun. the value assigned * here is an intelligent suggested default. Nothing magical about it. */ bdp->tx_per_underrun = DEFAULT_TX_PER_UNDERRUN; /* get the default transmit threshold value */ bdp->tx_thld = TX_THRSHLD; /* get the EPROM size */ bdp->eeprom_size = e100_eeprom_size(bdp); /* Initialize our spinlocks */ spin_lock_init(&(bdp->bd_lock)); spin_lock_init(&(bdp->bd_non_tx_lock)); spin_lock_init(&(bdp->config_lock)); spin_lock_init(&(bdp->mdi_access_lock)); bdp->isolate_lock = RW_LOCK_UNLOCKED; bdp->driver_isolated = false; return 1;}/** * e100_hw_init - initialized tthe hardware * @bdp: atapter's private data struct * @reset_cmd: s/w reset or selective reset * * This routine performs a reset on the adapter, and configures the adapter. * This includes configuring the 82557 LAN controller, validating and setting * the node address, detecting and configuring the Phy chip on the adapter, * and initializing all of the on chip counters. * * Returns: * true - If the adapter was initialized * false - If the adapter failed initialization */unsigned char __devinite100_hw_init(struct e100_private *bdp, u32 reset_cmd){ if (!e100_phy_init(bdp)) return false; /* Issue a software reset to the e100 */ e100_sw_reset(bdp, reset_cmd); /* Load the CU BASE (set to 0, because we use linear mode) */ if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) return false; if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) return false; /* Load interrupt microcode */ if (e100_load_microcode(bdp)) { bdp->flags |= DF_UCODE_LOADED; } e100_config_init(bdp); if (!e100_config(bdp)) { return false; } if (!e100_setup_iaaddr(bdp, bdp->device->dev_addr)) return false; /* Clear the internal counters */ if (!e100_clr_cntrs(bdp)) return false; /* Change for 82558 enhancement */ /* If 82558/9 and if the user has enabled flow control, set up the * Flow Control Reg. in the CSR */ if ((bdp->flags & IS_BACHELOR) && (bdp->params.b_params & PRM_FC)) { writeb(DFLT_FC_THLD, &bdp->scb->scb_ext.d101_scb.scb_fc_thld); writeb(DFLT_FC_CMD, &bdp->scb->scb_ext.d101_scb.scb_fc_xon_xoff); } return true;}/** * e100_setup_tcb_pool - setup TCB circular list * @head: Pointer to head of the allocated TCBs * @qlen: Number of elements in the queue * @bdp: atapter's private data struct * * This routine arranges the contigiously allocated TCB's in a circular list. * Also does the one time initialization of the TCBs. */static voide100_setup_tcb_pool(tcb_t *head, unsigned int qlen, struct e100_private *bdp){ int ele_no; tcb_t *pcurr_tcb; /* point to current tcb */ u32 next_phys; /* the next phys addr */ u16 txcommand = CB_S_BIT | CB_TX_SF_BIT; if (bdp->flags & USE_IPCB) { txcommand |= CB_IPCB_TRANSMIT | CB_CID_DEFAULT; } else if (bdp->flags & IS_BACHELOR) { txcommand |= CB_TRANSMIT | CB_CID_DEFAULT; } else { txcommand |= CB_TRANSMIT; } for (ele_no = 0, next_phys = bdp->tcb_phys, pcurr_tcb = head; ele_no < qlen; ele_no++, pcurr_tcb++) { /* set the phys addr for this TCB, next_phys has not incr. yet */ pcurr_tcb->tcb_phys = next_phys; next_phys += sizeof (tcb_t); /* set the link to next tcb */ if (ele_no == (qlen - 1)) pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(bdp->tcb_phys); else pcurr_tcb->tcb_hdr.cb_lnk_ptr = cpu_to_le32(next_phys); pcurr_tcb->tcb_hdr.cb_status = 0; pcurr_tcb->tcb_hdr.cb_cmd = cpu_to_le16(txcommand); pcurr_tcb->tcb_cnt = 0; pcurr_tcb->tcb_thrshld = bdp->tx_thld; if (ele_no < 2) { pcurr_tcb->tcb_hdr.cb_status = cpu_to_le16(CB_STATUS_COMPLETE); } pcurr_tcb->tcb_tbd_num = 1; if (bdp->flags & IS_BACHELOR) { pcurr_tcb->tcb_tbd_ptr = __constant_cpu_to_le32(0xFFFFFFFF); } else { pcurr_tcb->tcb_tbd_ptr = cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); }#ifdef MAX_SKB_FRAGS if (bdp->flags & IS_BACHELOR) { pcurr_tcb->tcb_tbd_expand_ptr = cpu_to_le32(pcurr_tcb->tcb_phys + 0x20); } else { pcurr_tcb->tcb_tbd_expand_ptr = cpu_to_le32(pcurr_tcb->tcb_phys + 0x10); } pcurr_tcb->tcb_tbd_dflt_ptr = pcurr_tcb->tcb_tbd_ptr;#endif if (bdp->flags & USE_IPCB) { pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[1]); pcurr_tcb->tcbu.ipcb.ip_activation_high = IPCB_IP_ACTIVATION_DEFAULT; pcurr_tcb->tcbu.ipcb.vlan = 0; } else { pcurr_tcb->tbd_ptr = &(pcurr_tcb->tcbu.tbd_array[0]); } pcurr_tcb->tcb_skb = NULL; } wmb();}/***************************************************************************//***************************************************************************//* Memory Management Routines *//***************************************************************************//** * e100_alloc_space - allocate private driver data * @bdp: atapter's private data struct * * This routine allocates memory for the driver. Memory allocated is for the * selftest and statistics structures. * * Returns: * 0: if the operation was successful * %-ENOMEM: if memory allocation failed */unsigned char __devinite100_alloc_space(struct e100_private *bdp){ unsigned long off;#ifdef IANS if (!(bdp->iANSdata = kmalloc(sizeof (iANSsupport_t), GFP_ATOMIC))) goto err; memset((void *) bdp->iANSdata, 0, sizeof (iANSsupport_t));#endif /* allocate all the dma-able structures in one call: * selftest results, adapter stats, and non-tx cb commands */ if (!(bdp->dma_able = pci_alloc_consistent(bdp->pdev, sizeof (bd_dma_able_t), &(bdp->dma_able_phys)))) { goto err; } /* now assign the various pointers into the struct we've just allocated */ off = offsetof(bd_dma_able_t, selftest); bdp->selftest = (self_test_t *) (bdp->dma_able + off); bdp->selftest_phys = bdp->dma_able_phys + off; off = offsetof(bd_dma_able_t, stats_counters); bdp->stats_counters = (max_counters_t *) (bdp->dma_able + off); bdp->stat_cnt_phys = bdp->dma_able_phys + off; return 0;err:#ifdef IANS kfree(bdp->iANSdata);#endif printk(KERN_ERR "e100: Failed to allocate memory\n"); return -ENOMEM;}/** * e100_alloc_tcb_pool - allocate TCB circular list * @bdp: atapter's private data struct * * This routine allocates memory for the circular list of transmit descriptors. * * Returns: * 0: if allocation has failed. * 1: Otherwise. */inte100_alloc_tcb_pool(struct e100_private *bdp){ int stcb = sizeof (tcb_t) * bdp->params.TxDescriptors; /* allocate space for the TCBs */ if (!(bdp->tcb_pool.data = pci_alloc_consistent(bdp->pdev, stcb, &bdp->tcb_phys))) return 0; memset(bdp->tcb_pool.data, 0x00, stcb); return 1;}voide100_free_tcb_pool(struct e100_private *bdp){ pci_free_consistent(bdp->pdev, sizeof (tcb_t) * bdp->params.TxDescriptors, bdp->tcb_pool.data, bdp->tcb_phys); bdp->tcb_phys = 0;}static voide100_dealloc_space(struct e100_private *bdp){#ifdef IANS kfree(bdp->iANSdata);#endif if (bdp->dma_able) { pci_free_consistent(bdp->pdev, sizeof (bd_dma_able_t), bdp->dma_able, bdp->dma_able_phys); } bdp->selftest_phys = 0; bdp->stat_cnt_phys = 0; bdp->dma_able_phys = 0; bdp->dma_able = 0;}static voide100_free_rfd_pool(struct e100_private *bdp){ struct rx_list_elem *rx_struct; while (!list_empty(&(bdp->active_rx_list))) { rx_struct = list_entry(bdp->active_rx_list.next, struct rx_list_elem, list_elem); list_del(&(rx_struct->list_elem)); pci_unmap_single(bdp->pdev, rx_struct->dma_addr, sizeof (rfd_t), PCI_DMA_TODEVICE); dev_kfree_skb(rx_struct->skb); kfree(rx_struct); } while (!list_empty(&(bdp->rx_struct_pool))) { rx_struct = list_entry(bdp->rx_struct_pool.next, struct rx_list_elem, list_elem); list_del(&(rx_struct->list_elem)); kfree(rx_struct); }}/** * e100_alloc_rfd_pool - allocate RFDs * @bdp: atapter's private data struct * * Allocates initial pool of skb which holds both rfd and data, * and return a pointer to the head of the list */static inte100_alloc_rfd_pool(struct e100_private *bdp){ struct rx_list_elem *rx_struct; int i; INIT_LIST_HEAD(&(bdp->active_rx_list)); INIT_LIST_HEAD(&(bdp->rx_struct_pool)); bdp->skb_req = bdp->params.RxDescriptors; for (i = 0; i < bdp->skb_req; i++) { rx_struct = kmalloc(sizeof (struct rx_list_elem), GFP_ATOMIC); list_add(&(rx_struct->list_elem), &(bdp->rx_struct_pool)); } e100_alloc_skbs(bdp); return !list_empty(&(bdp->active_rx_list));}voide100_clear_pools(struct e100_private *bdp){ bdp->last_tcb = NULL; e100_free_rfd_pool(bdp); e100_free_tcb_pool(bdp);}/*****************************************************************************//*****************************************************************************//* Run Time Functions *//*****************************************************************************//** * e100_watchdog * @dev: adapter's net_device struct * * This routine runs every 2 seconds and updates our statitics and link state, * and refreshs txthld value. */voide100_watchdog(struct net_device *dev){ struct e100_private *bdp = dev->priv; read_lock(&(bdp->isolate_lock)); if (bdp->driver_isolated) { goto exit; }#ifdef IANS if (!(bdp->flags & DF_OPENED)) { goto exit; }#else if (!netif_running(dev)) { goto exit; }#endif e100_get_mdix_status(bdp); /* check if link state has changed */ if (e100_phy_check(bdp)) { if (netif_carrier_ok(dev)) { printk(KERN_ERR "e100: %s NIC Link is Up %d Mbps %s duplex\n", bdp->device->name, bdp->cur_line_speed, (bdp->cur_dplx_mode == HALF_DUPLEX) ? "Half" : "Full"); e100_config_fc(bdp); e100_config(bdp); bdp->cable_status = "Cable OK"; } else { printk(KERN_ERR "e100: %s NIC Link is Down\n", bdp->device->name); if (bdp->rev_id < D102_REV_ID) bdp->cable_status = "Not supported"; else { /* Initiate hwi, ie, cable diagnostic */ bdp->saved_open_circut = 0xffff;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -