📄 e100_main.c
字号:
0xFFFF, E100_DEFAULT_CPUSAVER_INTERRUPT_DELAY, "CPU saver interrupt delay value"); e100_set_int_option(&(bdp->params.BundleMax), BundleMax[board], 0x1, 0xFFFF, E100_DEFAULT_CPUSAVER_BUNDLE_MAX, "CPU saver bundle max value");#ifdef E100_RX_CONGESTION_CONTROL e100_set_bool_option(bdp, RxCongestionControl[board], PRM_RX_CONG, E100_DEFAULT_RX_CONGESTION_CONTROL, "Rx Congestion Control value"); e100_set_int_option(&(bdp->params.PollingMaxWork), PollingMaxWork[board], 1, E100_MAX_RFD, bdp->params.RxDescriptors, "Polling Max Work value");#endif}/** * e100_set_int_option - check and set an integer option * @option: a pointer to the relevant option field * @val: the value specified * @min: the minimum valid value * @max: the maximum valid value * @default_val: the default value * @name: the name of the option * * This routine does range checking on a command-line option. * If the option's value is '-1' use the specified default. * Otherwise, if the value is invalid, change it to the default. */void __devinite100_set_int_option(int *option, int val, int min, int max, int default_val, char *name){ if (val == -1) { /* no value specified. use default */ *option = default_val; } else if ((val < min) || (val > max)) { printk(KERN_NOTICE "e100: Invalid %s specified (%i). " "Valid range is %i-%i\n", name, val, min, max); printk(KERN_NOTICE "e100: Using default %s of %i\n", name, default_val); *option = default_val; } else { printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); *option = val; }}/** * e100_set_bool_option - check and set a boolean option * @bdp: atapter's private data struct * @val: the value specified * @mask: the mask for the relevant option * @default_val: the default value * @name: the name of the option * * This routine checks a boolean command-line option. * If the option's value is '-1' use the specified default. * Otherwise, if the value is invalid (not 0 or 1), * change it to the default. */void __devinite100_set_bool_option(struct e100_private *bdp, int val, u32 mask, int default_val, char *name){ if (val == -1) { if (default_val) bdp->params.b_params |= mask; } else if ((val != true) && (val != false)) { printk(KERN_NOTICE "e100: Invalid %s specified (%i). " "Valid values are %i/%i\n", name, val, false, true); printk(KERN_NOTICE "e100: Using default %s of %i\n", name, default_val); if (default_val) bdp->params.b_params |= mask; } else { printk(KERN_INFO "e100: Using specified %s of %i\n", name, val); if (val) bdp->params.b_params |= mask; }}#ifdef IANSstatic voide100_tx_notify_stop(struct e100_private *bdp){ if ((ANS_PRIVATE_DATA_FIELD(bdp)->iANS_status == IANS_COMMUNICATION_UP) && (ANS_PRIVATE_DATA_FIELD(bdp)->reporting_mode == IANS_STATUS_REPORTING_ON)) { if (ans_notify) ans_notify(bdp->device, IANS_IND_XMIT_QUEUE_FULL); }}voide100_tx_notify_start(struct e100_private *bdp){ if (bdp->flags & DF_OPENED) { if ((ANS_PRIVATE_DATA_FIELD(bdp)->iANS_status == IANS_COMMUNICATION_UP) && (ANS_PRIVATE_DATA_FIELD(bdp)->reporting_mode == IANS_STATUS_REPORTING_ON)) { if (ans_notify) ans_notify(bdp->device, IANS_IND_XMIT_QUEUE_READY); } netif_wake_queue(bdp->device); }}#endif /* IANS */static inte100_open(struct net_device *dev){ struct e100_private *bdp; int rc = 0; bdp = dev->priv; read_lock(&(bdp->isolate_lock)); if (bdp->driver_isolated) { rc = -EBUSY; goto exit; }#ifdef IANS if (bdp->flags & DF_OPENED) { rc = -EBUSY; goto exit; } bdp->flags |= DF_OPENED;#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) MOD_INC_USE_COUNT; dev->start = 1;#endif /* setup the tcb pool */ if (!e100_alloc_tcb_pool(bdp)) { rc = -ENOMEM; goto err_exit; } bdp->last_tcb = NULL; bdp->tcb_pool.head = 0; bdp->tcb_pool.tail = 1; e100_setup_tcb_pool((tcb_t *) bdp->tcb_pool.data, bdp->params.TxDescriptors, bdp); if (!e100_alloc_rfd_pool(bdp)) { rc = -ENOMEM; goto err_exit; } if (!e100_wait_exec_cmplx(bdp, 0, SCB_CUC_LOAD_BASE)) { rc = -EAGAIN; goto err_exit; } if (!e100_wait_exec_cmplx(bdp, 0, SCB_RUC_LOAD_BASE)) { rc = -EAGAIN; goto err_exit; } mod_timer(&(bdp->watchdog_timer), jiffies + (2 * HZ)); netif_start_queue(dev); e100_start_ru(bdp); if ((rc = request_irq(dev->irq, &e100intr, SA_SHIRQ, dev->name, dev)) != 0) { del_timer_sync(&bdp->watchdog_timer); goto err_exit; }#ifdef E100_RX_CONGESTION_CONTROL if (bdp->params.b_params & PRM_RX_CONG) { DECLARE_TASKLET(polling_tasklet, e100_polling_tasklet, (unsigned long) bdp); bdp->polling_tasklet = polling_tasklet; }#endif bdp->intr_mask = 0; e100_set_intr_mask(bdp); e100_force_config(bdp); goto exit;err_exit: e100_clear_pools(bdp);#ifdef IANS bdp->flags &= ~DF_OPENED;#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) MOD_DEC_USE_COUNT; dev->start = 0;#endifexit: read_unlock(&(bdp->isolate_lock)); return rc;}static inte100_close(struct net_device *dev){ struct e100_private *bdp = dev->priv; bdp->intr_mask = SCB_INT_MASK; e100_isolate_driver(bdp); netif_carrier_off(bdp->device); bdp->cur_line_speed = 0; bdp->cur_dplx_mode = 0;#ifdef IANS bdp->flags &= ~DF_OPENED;#endif free_irq(dev->irq, dev); e100_clear_pools(bdp);#ifdef E100_RX_CONGESTION_CONTROL if (bdp->params.b_params & PRM_RX_CONG) { tasklet_kill(&(bdp->polling_tasklet)); }#endif /* set the isolate flag to false, so e100_open can be called */ bdp->driver_isolated = false;#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) MOD_DEC_USE_COUNT; dev->start = 0;#endif return 0;}static inte100_change_mtu(struct net_device *dev, int new_mtu){ if ((new_mtu < 68) || (new_mtu > (ETH_DATA_LEN + VLAN_SIZE))) return -EINVAL; dev->mtu = new_mtu; return 0;}static inte100_xmit_frame(struct sk_buff *skb, struct net_device *dev){ int rc = 0; int notify_stop = false; struct e100_private *bdp = dev->priv; read_lock(&(bdp->isolate_lock)); if (bdp->driver_isolated) { rc = -EBUSY; goto exit2; } if (!spin_trylock(&bdp->bd_non_tx_lock)) { notify_stop = true; rc = 1; goto exit2; } if (!TCBS_AVAIL(bdp->tcb_pool) || (bdp->non_tx_command_state != E100_NON_TX_IDLE)) { notify_stop = true; rc = 1; goto exit1; }#ifdef E100_IA64_DMA_FIX if ((u64) skb->head >= (PAGE_OFFSET + 0x100000000UL)) skb_linearize(skb, GFP_ATOMIC | GFP_DMA);#endif e100_prepare_xmit_buff(bdp, skb); bdp->drv_stats.net_stats.tx_bytes += skb->len; dev->trans_start = jiffies;exit1: spin_unlock(&bdp->bd_non_tx_lock);exit2: read_unlock(&(bdp->isolate_lock)); if (notify_stop) {#ifdef IANS e100_tx_notify_stop(bdp);#endif netif_stop_queue(dev); } return rc;}/** * e100_get_stats - get driver statistics * @dev: adapter's net_device struct * * This routine is called when the OS wants the adapter's stats returned. * It returns the address of the net_device_stats stucture for the device. * If the statistics are currently being updated, then they might be incorrect * for a short while. However, since this cannot actually cause damage, no * locking is used. */struct net_device_stats *e100_get_stats(struct net_device *dev){ struct e100_private *bdp = dev->priv; bdp->drv_stats.net_stats.tx_errors = bdp->drv_stats.net_stats.tx_carrier_errors + bdp->drv_stats.net_stats.tx_aborted_errors; bdp->drv_stats.net_stats.rx_errors = bdp->drv_stats.net_stats.rx_crc_errors + bdp->drv_stats.net_stats.rx_frame_errors + bdp->drv_stats.net_stats.rx_length_errors + bdp->drv_stats.rcv_cdt_frames; return &(bdp->drv_stats.net_stats);}/** * e100_set_mac - set the MAC address * @dev: adapter's net_device struct * @addr: the new address * * This routine sets the ethernet address of the board * Returns: * 0 - if successful * -1 - otherwise */static inte100_set_mac(struct net_device *dev, void *addr){ struct e100_private *bdp; int rc = -1; struct sockaddr *p_sockaddr = (struct sockaddr *) addr; bdp = dev->priv; read_lock(&(bdp->isolate_lock)); if (bdp->driver_isolated) { goto exit; } if (e100_setup_iaaddr(bdp, (u8 *) (p_sockaddr->sa_data))) { memcpy(&(dev->dev_addr[0]), p_sockaddr->sa_data, ETH_ALEN); rc = 0; }exit: read_unlock(&(bdp->isolate_lock)); return rc;}static voide100_set_multi_exec(struct net_device *dev){ struct e100_private *bdp = dev->priv; mltcst_cb_t *mcast_buff; cb_header_t *cb_hdr; struct dev_mc_list *mc_list; unsigned int i; nxmit_cb_entry_t *cmd = e100_alloc_non_tx_cmd(bdp); if (cmd != NULL) { mcast_buff = &((cmd->non_tx_cmd)->ntcb.multicast); cb_hdr = &((cmd->non_tx_cmd)->ntcb.multicast.mc_cbhdr); } else { return; } /* initialize the multi cast command */ cb_hdr->cb_cmd = __constant_cpu_to_le16(CB_MULTICAST); /* now fill in the rest of the multicast command */ *(u16 *) (&(mcast_buff->mc_count)) = cpu_to_le16(dev->mc_count * 6); for (i = 0, mc_list = dev->mc_list; (i < dev->mc_count) && (i < MAX_MULTICAST_ADDRS); i++, mc_list = mc_list->next) { /* copy into the command */ memcpy(&(mcast_buff->mc_addr[i * ETH_ALEN]), (u8 *) &(mc_list->dmi_addr), ETH_ALEN); } if (!e100_exec_non_cu_cmd(bdp, cmd)) { printk(KERN_WARNING "e100: %s: Multicast setup failed\n", dev->name); }}/** * e100_set_multi - set multicast status * @dev: adapter's net_device struct * * This routine is called to add or remove multicast addresses, and/or to * change the adapter's promiscuous state. */static voide100_set_multi(struct net_device *dev){ struct e100_private *bdp = dev->priv; unsigned char promisc_enbl; unsigned char mulcast_enbl; read_lock(&(bdp->isolate_lock)); if (bdp->driver_isolated) { goto exit; } promisc_enbl = ((dev->flags & IFF_PROMISC) == IFF_PROMISC); mulcast_enbl = ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > MAX_MULTICAST_ADDRS)); e100_config_promisc(bdp, promisc_enbl); e100_config_mulcast_enbl(bdp, mulcast_enbl); /* reconfigure the chip if something has changed in its config space */ e100_config(bdp); if (promisc_enbl || mulcast_enbl) { goto exit; /* no need for Multicast Cmd */ } /* get the multicast CB */ e100_set_multi_exec(dev);exit: read_unlock(&(bdp->isolate_lock));}static inte100_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){#ifdef IANS struct e100_private *bdp = dev->priv; /* get the private data structure from the dev struct */ BOARD_PRIVATE_STRUCT *bps = dev->priv; IANS_BD_PARAM_HEADER *header = (IANS_BD_PARAM_HEADER *) ifr->ifr_data; iANSsupport_t *iANSdata = ANS_PRIVATE_DATA_FIELD(bps); BD_ANS_STATUS status = BD_ANS_FAILURE;#endif#ifdef E100_IDIAG_PRO_SUPPORT enum idiag_pro_stat diag_status; struct idiag_pro_data *diag_data = (struct idiag_pro_data *) ifr->ifr_data;#endif switch (cmd) {#ifdef IANS case IANS_BASE_SIOC: read_lock(&(bdp->isolate_lock)); if (!bdp->driver_isolated) { status = bd_ans_ProcessRequest(bps, iANSdata, header); } read_unlock(&(bdp->isolate_lock)); if (status == BD_ANS_SUCCESS) return 0; /* some problem occured, return error value */ return -EAGAIN;#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -