⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 e100.c

📁 网卡的驱动程序源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		cb->prev = (i == 0) ? nic->cbs + count - 1 : cb - 1;		cb->dma_addr = nic->cbs_dma_addr + i * sizeof(struct cb);		cb->link = cpu_to_le32(nic->cbs_dma_addr +			((i+1) % count) * sizeof(struct cb));		cb->skb = NULL;	}	nic->cb_to_use = nic->cb_to_send = nic->cb_to_clean = nic->cbs;	nic->cbs_avail = count;	return 0;}static inline void e100_start_receiver(struct nic *nic, struct rx *rx){	if(!nic->rxs) return;	if(RU_SUSPENDED != nic->ru_running) return;	/* handle init time starts */	if(!rx) rx = nic->rxs;	/* (Re)start RU if suspended or idle and RFA is non-NULL */	if(rx->skb) {		e100_exec_cmd(nic, ruc_start, rx->dma_addr);		nic->ru_running = RU_RUNNING;	}}#define RFD_BUF_LEN (sizeof(struct rfd) + VLAN_ETH_FRAME_LEN)static int e100_rx_alloc_skb(struct nic *nic, struct rx *rx){	if(!(rx->skb = dev_alloc_skb(RFD_BUF_LEN + NET_IP_ALIGN)))		return -ENOMEM;	/* Align, init, and map the RFD. */	rx->skb->dev = nic->netdev;	skb_reserve(rx->skb, NET_IP_ALIGN);	memcpy(rx->skb->data, &nic->blank_rfd, sizeof(struct rfd));	rx->dma_addr = pci_map_single(nic->pdev, rx->skb->data,		RFD_BUF_LEN, PCI_DMA_BIDIRECTIONAL);	if(pci_dma_mapping_error(rx->dma_addr)) {		dev_kfree_skb_any(rx->skb);		rx->skb = NULL;		rx->dma_addr = 0;		return -ENOMEM;	}	/* Link the RFD to end of RFA by linking previous RFD to	 * this one, and clearing EL bit of previous.  */	if(rx->prev->skb) {		struct rfd *prev_rfd = (struct rfd *)rx->prev->skb->data;		put_unaligned(cpu_to_le32(rx->dma_addr),			(u32 *)&prev_rfd->link);		wmb();		prev_rfd->command &= ~cpu_to_le16(cb_el);		pci_dma_sync_single_for_device(nic->pdev, rx->prev->dma_addr,			sizeof(struct rfd), PCI_DMA_TODEVICE);	}	return 0;}static int e100_rx_indicate(struct nic *nic, struct rx *rx,	unsigned int *work_done, unsigned int work_to_do){	struct sk_buff *skb = rx->skb;	struct rfd *rfd = (struct rfd *)skb->data;	u16 rfd_status, actual_size;	if(unlikely(work_done && *work_done >= work_to_do))		return -EAGAIN;	/* Need to sync before taking a peek at cb_complete bit */	pci_dma_sync_single_for_cpu(nic->pdev, rx->dma_addr,		sizeof(struct rfd), PCI_DMA_FROMDEVICE);	rfd_status = le16_to_cpu(rfd->status);	DPRINTK(RX_STATUS, DEBUG, "status=0x%04X\n", rfd_status);	/* If data isn't ready, nothing to indicate */	if(unlikely(!(rfd_status & cb_complete)))		return -ENODATA;	/* Get actual data size */	actual_size = le16_to_cpu(rfd->actual_size) & 0x3FFF;	if(unlikely(actual_size > RFD_BUF_LEN - sizeof(struct rfd)))		actual_size = RFD_BUF_LEN - sizeof(struct rfd);	/* Get data */	pci_unmap_single(nic->pdev, rx->dma_addr,		RFD_BUF_LEN, PCI_DMA_FROMDEVICE);	/* this allows for a fast restart without re-enabling interrupts */	if(le16_to_cpu(rfd->command) & cb_el)		nic->ru_running = RU_SUSPENDED;	/* Pull off the RFD and put the actual data (minus eth hdr) */	skb_reserve(skb, sizeof(struct rfd));	skb_put(skb, actual_size);	skb->protocol = eth_type_trans(skb, nic->netdev);	if(unlikely(!(rfd_status & cb_ok))) {		/* Don't indicate if hardware indicates errors */		dev_kfree_skb_any(skb);	} else if(actual_size > ETH_DATA_LEN + VLAN_ETH_HLEN) {		/* Don't indicate oversized frames */		nic->rx_over_length_errors++;		dev_kfree_skb_any(skb);	} else {		nic->net_stats.rx_packets++;		nic->net_stats.rx_bytes += actual_size;		nic->netdev->last_rx = jiffies;#ifdef CONFIG_E100_NAPI		netif_receive_skb(skb);#else		netif_rx(skb);#endif		if(work_done)			(*work_done)++;	}	rx->skb = NULL;	return 0;}static void e100_rx_clean(struct nic *nic, unsigned int *work_done,	unsigned int work_to_do){	struct rx *rx;	int restart_required = 0;	struct rx *rx_to_start = NULL;	/* are we already rnr? then pay attention!!! this ensures that	 * the state machine progression never allows a start with a	 * partially cleaned list, avoiding a race between hardware	 * and rx_to_clean when in NAPI mode */	if(RU_SUSPENDED == nic->ru_running)		restart_required = 1;	/* Indicate newly arrived packets */	for(rx = nic->rx_to_clean; rx->skb; rx = nic->rx_to_clean = rx->next) {		int err = e100_rx_indicate(nic, rx, work_done, work_to_do);		if(-EAGAIN == err) {			/* hit quota so have more work to do, restart once			 * cleanup is complete */			restart_required = 0;			break;		} else if(-ENODATA == err)			break; /* No more to clean */	}	/* save our starting point as the place we'll restart the receiver */	if(restart_required)		rx_to_start = nic->rx_to_clean;	/* Alloc new skbs to refill list */	for(rx = nic->rx_to_use; !rx->skb; rx = nic->rx_to_use = rx->next) {		if(unlikely(e100_rx_alloc_skb(nic, rx)))			break; /* Better luck next time (see watchdog) */	}	if(restart_required) {		// ack the rnr?		writeb(stat_ack_rnr, &nic->csr->scb.stat_ack);		e100_start_receiver(nic, rx_to_start);		if(work_done)			(*work_done)++;	}}static void e100_rx_clean_list(struct nic *nic){	struct rx *rx;	unsigned int i, count = nic->params.rfds.count;	nic->ru_running = RU_UNINITIALIZED;	if(nic->rxs) {		for(rx = nic->rxs, i = 0; i < count; rx++, i++) {			if(rx->skb) {				pci_unmap_single(nic->pdev, rx->dma_addr,					RFD_BUF_LEN, PCI_DMA_FROMDEVICE);				dev_kfree_skb(rx->skb);			}		}		kfree(nic->rxs);		nic->rxs = NULL;	}	nic->rx_to_use = nic->rx_to_clean = NULL;}static int e100_rx_alloc_list(struct nic *nic){	struct rx *rx;	unsigned int i, count = nic->params.rfds.count;	nic->rx_to_use = nic->rx_to_clean = NULL;	nic->ru_running = RU_UNINITIALIZED;	if(!(nic->rxs = kmalloc(sizeof(struct rx) * count, GFP_ATOMIC)))		return -ENOMEM;	memset(nic->rxs, 0, sizeof(struct rx) * count);	for(rx = nic->rxs, i = 0; i < count; rx++, i++) {		rx->next = (i + 1 < count) ? rx + 1 : nic->rxs;		rx->prev = (i == 0) ? nic->rxs + count - 1 : rx - 1;		if(e100_rx_alloc_skb(nic, rx)) {			e100_rx_clean_list(nic);			return -ENOMEM;		}	}	nic->rx_to_use = nic->rx_to_clean = nic->rxs;	nic->ru_running = RU_SUSPENDED;	return 0;}static irqreturn_t e100_intr(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *netdev = dev_id;	struct nic *nic = netdev_priv(netdev);	u8 stat_ack = readb(&nic->csr->scb.stat_ack);	DPRINTK(INTR, DEBUG, "stat_ack = 0x%02X\n", stat_ack);	if(stat_ack == stat_ack_not_ours ||	/* Not our interrupt */	   stat_ack == stat_ack_not_present)	/* Hardware is ejected */		return IRQ_NONE;	/* Ack interrupt(s) */	writeb(stat_ack, &nic->csr->scb.stat_ack);	/* We hit Receive No Resource (RNR); restart RU after cleaning */	if(stat_ack & stat_ack_rnr)		nic->ru_running = RU_SUSPENDED;#ifdef CONFIG_E100_NAPI	if(likely(netif_rx_schedule_prep(netdev))) {		e100_disable_irq(nic);		__netif_rx_schedule(netdev);	}#else	e100_rx_clean(nic, NULL, 0);	e100_tx_clean(nic);#endif	return IRQ_HANDLED;}#ifdef CONFIG_E100_NAPIstatic int e100_poll(struct net_device *netdev, int *budget){	struct nic *nic = netdev_priv(netdev);	unsigned int work_to_do = min(netdev->quota, *budget);	unsigned int work_done = 0;	int tx_cleaned;	e100_rx_clean(nic, &work_done, work_to_do);	tx_cleaned = e100_tx_clean(nic);	/* If no Rx and Tx cleanup work was done, exit polling mode. */	if((!tx_cleaned && (work_done == 0)) || !netif_running(netdev)) {		netif_rx_complete(netdev);		e100_enable_irq(nic);		return 0;	}	*budget -= work_done;	netdev->quota -= work_done;	return 1;}#endif#ifdef CONFIG_NET_POLL_CONTROLLERstatic void e100_netpoll(struct net_device *netdev){	struct nic *nic = netdev_priv(netdev);	e100_disable_irq(nic);	e100_intr(nic->pdev->irq, netdev, NULL);	e100_tx_clean(nic);	e100_enable_irq(nic);}#endifstatic struct net_device_stats *e100_get_stats(struct net_device *netdev){	struct nic *nic = netdev_priv(netdev);	return &nic->net_stats;}static int e100_set_mac_address(struct net_device *netdev, void *p){	struct nic *nic = netdev_priv(netdev);	struct sockaddr *addr = p;	if (!is_valid_ether_addr(addr->sa_data))		return -EADDRNOTAVAIL;	memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);	e100_exec_cb(nic, NULL, e100_setup_iaaddr);	return 0;}static int e100_change_mtu(struct net_device *netdev, int new_mtu){	if(new_mtu < ETH_ZLEN || new_mtu > ETH_DATA_LEN)		return -EINVAL;	netdev->mtu = new_mtu;	return 0;}#ifdef CONFIG_PMstatic int e100_asf(struct nic *nic){	/* ASF can be enabled from eeprom */	return((nic->pdev->device >= 0x1050) && (nic->pdev->device <= 0x1057) &&	   (nic->eeprom[eeprom_config_asf] & eeprom_asf) &&	   !(nic->eeprom[eeprom_config_asf] & eeprom_gcl) &&	   ((nic->eeprom[eeprom_smbus_addr] & 0xFF) != 0xFE));}#endifstatic int e100_up(struct nic *nic){	int err;	if((err = e100_rx_alloc_list(nic)))		return err;	if((err = e100_alloc_cbs(nic)))		goto err_rx_clean_list;	if((err = e100_hw_init(nic)))		goto err_clean_cbs;	e100_set_multicast_list(nic->netdev);	e100_start_receiver(nic, NULL);	mod_timer(&nic->watchdog, jiffies);	if((err = request_irq(nic->pdev->irq, e100_intr, SA_SHIRQ,		nic->netdev->name, nic->netdev)))		goto err_no_irq;	netif_wake_queue(nic->netdev);#ifdef CONFIG_E100_NAPI	netif_poll_enable(nic->netdev);	/* enable ints _after_ enabling poll, preventing a race between	 * disable ints+schedule */#endif	e100_enable_irq(nic);	return 0;err_no_irq:	del_timer_sync(&nic->watchdog);err_clean_cbs:	e100_clean_cbs(nic);err_rx_clean_list:	e100_rx_clean_list(nic);	return err;}static void e100_down(struct nic *nic){#ifdef CONFIG_E100_NAPI	/* wait here for poll to complete */	netif_poll_disable(nic->netdev);#endif	netif_stop_queue(nic->netdev);	e100_hw_reset(nic);	free_irq(nic->pdev->irq, nic->netdev);	del_timer_sync(&nic->watchdog);	netif_carrier_off(nic->netdev);	e100_clean_cbs(nic);	e100_rx_clean_list(nic);}static void e100_tx_timeout(struct net_device *netdev){	struct nic *nic = netdev_priv(netdev);	/* Reset outside of interrupt context, to avoid request_irq	 * in interrupt context */	schedule_work(&nic->tx_timeout_task);}static void e100_tx_timeout_task(struct net_device *netdev){	struct nic *nic = netdev_priv(netdev);	DPRINTK(TX_ERR, DEBUG, "scb.status=0x%02X\n",		readb(&nic->csr->scb.status));	e100_down(netdev_priv(netdev));	e100_up(netdev_priv(netdev));}static int e100_loopback_test(struct nic *nic, enum loopback loopback_mode){	int err;	struct sk_buff *skb;	/* Use driver resources to perform internal MAC or PHY	 * loopback test.  A single packet is prepared and transmitted	 * in loopback mode, and the test passes if the received	 * packet compares byte-for-byte to the transmitted packet. */	if((err = e100_rx_alloc_list(nic)))		return err;	if((err = e100_alloc_cbs(nic)))		goto err_clean_rx;	/* ICH PHY loopback is broken so do MAC loopback instead */	if(nic->flags & ich && loopback_mode == lb_phy)		loopback_mode = lb_mac;	nic->loopback = loopback_mode;	if((err = e100_hw_init(nic)))		goto err_loopback_none;	if(loopback_mode == lb_phy)		mdio_write(nic->netdev, nic->mii.phy_id, MII_BMCR,			BMCR_LOOPBACK);	e100_start_receiver(nic, NULL);	if(!(skb = dev_alloc_skb(ETH_DATA_LEN))) {		err = -ENOMEM;		goto err_loopback_none;	}	skb_put(skb, ETH_DATA_LEN);	memset(skb->data, 0xFF, ETH_DATA_LEN);	e100_xmit_frame(skb, nic->netdev);	msleep(10)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -