ixgb_main.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 2,146 行 · 第 1/4 页

C
2,146
字号
		atomic_inc(&adapter->irq_sem);		IXGB_WRITE_REG(hw, IMC, ~0);		__netif_rx_schedule(netdev);	}#else	for (i = 0; i < IXGB_MAX_INTR; i++)		if (!ixgb_clean_rx_irq(adapter) & !ixgb_clean_tx_irq(adapter))			break;	/* if RAIDC:EN == 1 and ICR:RXDMT0 == 1, we need to	 * set IMS:RXDMT0 to 1 to restart the RBD timer (POLL)	 */	if ((icr & IXGB_INT_RXDMT0) && adapter->raidc) {		/* ready the timer by writing the clear reg */		IXGB_WRITE_REG(hw, IMC, IXGB_INT_RXDMT0);		/* now restart it, h/w will decide if its necessary */		IXGB_WRITE_REG(hw, IMS, IXGB_INT_RXDMT0);	}#endif	return IRQ_HANDLED;}#ifdef CONFIG_IXGB_NAPI/** * ixgb_clean - NAPI Rx polling callback * @adapter: board private structure **/static int ixgb_clean(struct net_device *netdev, int *budget){	struct ixgb_adapter *adapter = netdev->priv;	int work_to_do = min(*budget, netdev->quota);	int work_done = 0;	ixgb_clean_tx_irq(adapter);	ixgb_clean_rx_irq(adapter, &work_done, work_to_do);	*budget -= work_done;	netdev->quota -= work_done;	if (work_done < work_to_do || !netif_running(netdev)) {		netif_rx_complete(netdev);		/* RAIDC will be automatically restarted by irq_enable */		ixgb_irq_enable(adapter);	}	return (work_done >= work_to_do);}#endif/** * ixgb_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure **/static boolean_t ixgb_clean_tx_irq(struct ixgb_adapter *adapter){	struct ixgb_desc_ring *tx_ring = &adapter->tx_ring;	struct net_device *netdev = adapter->netdev;	struct pci_dev *pdev = adapter->pdev;	struct ixgb_tx_desc *tx_desc, *eop_desc;	struct ixgb_buffer *buffer_info;	unsigned int i, eop;	boolean_t cleaned = FALSE;	i = tx_ring->next_to_clean;	eop = tx_ring->buffer_info[i].next_to_watch;	eop_desc = IXGB_TX_DESC(*tx_ring, eop);	while (eop_desc->status & cpu_to_le32(IXGB_TX_DESC_STATUS_DD)) {		for (cleaned = FALSE; !cleaned;) {			tx_desc = IXGB_TX_DESC(*tx_ring, i);			buffer_info = &tx_ring->buffer_info[i];			if (tx_desc->popts			    & (IXGB_TX_DESC_POPTS_TXSM |			       IXGB_TX_DESC_POPTS_IXSM))				adapter->hw_csum_tx_good++;			if (buffer_info->dma) {				pci_unmap_page(pdev,					       buffer_info->dma,					       buffer_info->length,					       PCI_DMA_TODEVICE);				buffer_info->dma = 0;			}			if (buffer_info->skb) {				dev_kfree_skb_any(buffer_info->skb);				buffer_info->skb = NULL;			}			*(uint32_t *) & (tx_desc->status) = 0;			cleaned = (i == eop);			if (++i == tx_ring->count)				i = 0;		}		eop = tx_ring->buffer_info[i].next_to_watch;		eop_desc = IXGB_TX_DESC(*tx_ring, eop);	}	tx_ring->next_to_clean = i;	spin_lock(&adapter->tx_lock);	if (cleaned && netif_queue_stopped(netdev) && netif_carrier_ok(netdev)	    && (IXGB_DESC_UNUSED(tx_ring) > IXGB_TX_QUEUE_WAKE)) {		netif_wake_queue(netdev);	}	spin_unlock(&adapter->tx_lock);	return cleaned;}/** * ixgb_clean_rx_irq - Send received data up the network stack, * @adapter: board private structure **/static boolean_t#ifdef CONFIG_IXGB_NAPIixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do)#elseixgb_clean_rx_irq(struct ixgb_adapter *adapter)#endif{	struct ixgb_desc_ring *rx_ring = &adapter->rx_ring;	struct net_device *netdev = adapter->netdev;	struct pci_dev *pdev = adapter->pdev;	struct ixgb_rx_desc *rx_desc, *next_rxd;	struct ixgb_buffer *buffer_info, *next_buffer, *next2_buffer;	struct sk_buff *skb, *next_skb;	uint32_t length;	unsigned int i, j;	boolean_t cleaned = FALSE;	i = rx_ring->next_to_clean;	rx_desc = IXGB_RX_DESC(*rx_ring, i);	buffer_info = &rx_ring->buffer_info[i];	while (rx_desc->status & IXGB_RX_DESC_STATUS_DD) {		skb = buffer_info->skb;		prefetch(skb->data);		if (++i == rx_ring->count)			i = 0;		next_rxd = IXGB_RX_DESC(*rx_ring, i);		prefetch(next_rxd);		if ((j = i + 1) == rx_ring->count)			j = 0;		next2_buffer = &rx_ring->buffer_info[j];		prefetch(next2_buffer);		next_buffer = &rx_ring->buffer_info[i];		next_skb = next_buffer->skb;		prefetch(next_skb);#ifdef CONFIG_IXGB_NAPI		if (*work_done >= work_to_do)			break;		(*work_done)++;#endif		cleaned = TRUE;		pci_unmap_single(pdev,				 buffer_info->dma,				 buffer_info->length, PCI_DMA_FROMDEVICE);		length = le16_to_cpu(rx_desc->length);		if (unlikely(!(rx_desc->status & IXGB_RX_DESC_STATUS_EOP))) {			/* All receives must fit into a single buffer */			IXGB_DBG("Receive packet consumed multiple buffers "				 "length<%x>\n", length);			dev_kfree_skb_irq(skb);			rx_desc->status = 0;			buffer_info->skb = NULL;			rx_desc = next_rxd;			buffer_info = next_buffer;			continue;		}		if (unlikely(rx_desc->errors			     & (IXGB_RX_DESC_ERRORS_CE | IXGB_RX_DESC_ERRORS_SE				| IXGB_RX_DESC_ERRORS_P |				IXGB_RX_DESC_ERRORS_RXE))) {			dev_kfree_skb_irq(skb);			rx_desc->status = 0;			buffer_info->skb = NULL;			rx_desc = next_rxd;			buffer_info = next_buffer;			continue;		}		/* Good Receive */		skb_put(skb, length);		/* Receive Checksum Offload */		ixgb_rx_checksum(adapter, rx_desc, skb);		skb->protocol = eth_type_trans(skb, netdev);#ifdef CONFIG_IXGB_NAPI		if (adapter->vlgrp		    && (rx_desc->status & IXGB_RX_DESC_STATUS_VP)) {			vlan_hwaccel_receive_skb(skb, adapter->vlgrp,						 le16_to_cpu(rx_desc->							     special &							     IXGB_RX_DESC_SPECIAL_VLAN_MASK));		} else {			netif_receive_skb(skb);		}#else				/* CONFIG_IXGB_NAPI */		if (adapter->vlgrp		    && (rx_desc->status & IXGB_RX_DESC_STATUS_VP)) {			vlan_hwaccel_rx(skb, adapter->vlgrp,					le16_to_cpu(rx_desc->						    special &						    IXGB_RX_DESC_SPECIAL_VLAN_MASK));		} else {			netif_rx(skb);		}#endif				/* CONFIG_IXGB_NAPI */		netdev->last_rx = jiffies;		rx_desc->status = 0;		buffer_info->skb = NULL;		rx_desc = next_rxd;		buffer_info = next_buffer;	}	rx_ring->next_to_clean = i;	ixgb_alloc_rx_buffers(adapter);	return cleaned;}/** * ixgb_alloc_rx_buffers - Replace used receive buffers * @adapter: address of board private structure **/static void ixgb_alloc_rx_buffers(struct ixgb_adapter *adapter){	struct ixgb_desc_ring *rx_ring = &adapter->rx_ring;	struct net_device *netdev = adapter->netdev;	struct pci_dev *pdev = adapter->pdev;	struct ixgb_rx_desc *rx_desc;	struct ixgb_buffer *buffer_info;	struct sk_buff *skb;	unsigned int i;	int num_group_tail_writes;	long cleancount;	i = rx_ring->next_to_use;	buffer_info = &rx_ring->buffer_info[i];	cleancount = IXGB_DESC_UNUSED(rx_ring);	/* lessen this to 4 if we're	 * in the midst of raidc and rbd is occuring	 * because we don't want to delay returning buffers when low	 */	num_group_tail_writes = adapter->raidc ? 4 : IXGB_RX_BUFFER_WRITE;	/* leave one descriptor unused */	while (--cleancount > 0) {		rx_desc = IXGB_RX_DESC(*rx_ring, i);		skb = dev_alloc_skb(adapter->rx_buffer_len + NET_IP_ALIGN);		if (unlikely(!skb)) {			/* Better luck next round */			break;		}		/* Make buffer alignment 2 beyond a 16 byte boundary		 * this will result in a 16 byte aligned IP header after		 * the 14 byte MAC header is removed		 */		skb_reserve(skb, NET_IP_ALIGN);		skb->dev = netdev;		buffer_info->skb = skb;		buffer_info->length = adapter->rx_buffer_len;		buffer_info->dma =		    pci_map_single(pdev,				   skb->data,				   adapter->rx_buffer_len, PCI_DMA_FROMDEVICE);		rx_desc->buff_addr = cpu_to_le64(buffer_info->dma);		if ((i & ~(num_group_tail_writes - 1)) == i) {			/* Force memory writes to complete before letting h/w			 * know there are new descriptors to fetch.  (Only			 * applicable for weak-ordered memory model archs,			 * such as IA-64). */			wmb();			IXGB_WRITE_REG(&adapter->hw, RDT, i);		}		if (++i == rx_ring->count)			i = 0;		buffer_info = &rx_ring->buffer_info[i];	}	rx_ring->next_to_use = i;}/** * ixgb_ioctl - perform a command - e.g: ethtool:get_driver_info. * @param netdev network interface device structure * @param ifr data to be used/filled in by the ioctl command * @param cmd ioctl command to execute **/static int ixgb_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd){	switch (cmd) {	case SIOCETHTOOL:		return ixgb_ethtool_ioctl(netdev, ifr);	default:		return -EOPNOTSUPP;	}	return 0;}/** * ixgb_rx_checksum - Receive Checksum Offload for 82597. * @adapter: board private structure * @rx_desc: receive descriptor * @sk_buff: socket buffer with received data **/static inline voidixgb_rx_checksum(struct ixgb_adapter *adapter,		 struct ixgb_rx_desc *rx_desc, struct sk_buff *skb){	/* Ignore Checksum bit is set OR 	 * TCP Checksum has not been calculated 	 */	if ((rx_desc->status & IXGB_RX_DESC_STATUS_IXSM) ||	    (!(rx_desc->status & IXGB_RX_DESC_STATUS_TCPCS))) {		skb->ip_summed = CHECKSUM_NONE;		return;	}	/* At this point we know the hardware did the TCP checksum */	/* now look at the TCP checksum error bit */	if (rx_desc->errors & IXGB_RX_DESC_ERRORS_TCPE) {		/* let the stack verify checksum errors */		skb->ip_summed = CHECKSUM_NONE;		adapter->hw_csum_rx_error++;	} else {		/* TCP checksum is good */		skb->ip_summed = CHECKSUM_UNNECESSARY;		adapter->hw_csum_rx_good++;	}}/** * ixgb_vlan_rx_register - enables or disables vlan tagging/stripping. *  * @param netdev network interface device structure * @param grp indicates to enable or disable tagging/stripping **/static voidixgb_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp){	struct ixgb_adapter *adapter = netdev->priv;	uint32_t ctrl, rctl;	ixgb_irq_disable(adapter);	adapter->vlgrp = grp;	if (grp) {		/* enable VLAN tag insert/strip */		ctrl = IXGB_READ_REG(&adapter->hw, CTRL0);		ctrl |= IXGB_CTRL0_VME;		IXGB_WRITE_REG(&adapter->hw, CTRL0, ctrl);		/* enable VLAN receive filtering */		rctl = IXGB_READ_REG(&adapter->hw, RCTL);		rctl |= IXGB_RCTL_VFE;		rctl &= ~IXGB_RCTL_CFIEN;		IXGB_WRITE_REG(&adapter->hw, RCTL, rctl);	} else {		/* disable VLAN tag insert/strip */		ctrl = IXGB_READ_REG(&adapter->hw, CTRL0);		ctrl &= ~IXGB_CTRL0_VME;		IXGB_WRITE_REG(&adapter->hw, CTRL0, ctrl);		/* disable VLAN filtering */		rctl = IXGB_READ_REG(&adapter->hw, RCTL);		rctl &= ~IXGB_RCTL_VFE;		IXGB_WRITE_REG(&adapter->hw, RCTL, rctl);	}	ixgb_irq_enable(adapter);}static void ixgb_vlan_rx_add_vid(struct net_device *netdev, uint16_t vid){	struct ixgb_adapter *adapter = netdev->priv;	uint32_t vfta, index;	/* add VID to filter table */	index = (vid >> 5) & 0x7F;	vfta = IXGB_READ_REG_ARRAY(&adapter->hw, VFTA, index);	vfta |= (1 << (vid & 0x1F));	ixgb_write_vfta(&adapter->hw, index, vfta);}static void ixgb_vlan_rx_kill_vid(struct net_device *netdev, uint16_t vid){	struct ixgb_adapter *adapter = netdev->priv;	uint32_t vfta, index;	ixgb_irq_disable(adapter);	if (adapter->vlgrp)		adapter->vlgrp->vlan_devices[vid] = NULL;	ixgb_irq_enable(adapter);	/* remove VID from filter table */	index = (vid >> 5) & 0x7F;	vfta = IXGB_READ_REG_ARRAY(&adapter->hw, VFTA, index);	vfta &= ~(1 << (vid & 0x1F));	ixgb_write_vfta(&adapter->hw, index, vfta);}static void ixgb_restore_vlan(struct ixgb_adapter *adapter){	ixgb_vlan_rx_register(adapter->netdev, adapter->vlgrp);	if (adapter->vlgrp) {		uint16_t vid;		for (vid = 0; vid < VLAN_GROUP_ARRAY_LEN; vid++) {			if (!adapter->vlgrp->vlan_devices[vid])				continue;			ixgb_vlan_rx_add_vid(adapter->netdev, vid);		}	}}/** * ixgb_notify_reboot - handles OS notification of reboot event. * @param nb notifier block, unused * @param event Event being passed to driver to act upon * @param p A pointer to our net device **/static intixgb_notify_reboot(struct notifier_block *nb, unsigned long event, void *p){	struct pci_dev *pdev = NULL;	switch (event) {	case SYS_DOWN:	case SYS_HALT:	case SYS_POWER_OFF:		while ((pdev = pci_find_device(PCI_ANY_ID, PCI_ANY_ID, pdev))) {			if (pci_dev_driver(pdev) == &ixgb_driver)				ixgb_suspend(pdev, 3);		}	}	return NOTIFY_DONE;}/** * ixgb_suspend - driver suspend function called from notify. * @param pdev pci driver structure used for passing to * @param state power state to enter  **/static int ixgb_suspend(struct pci_dev *pdev, uint32_t state){	struct net_device *netdev = pci_get_drvdata(pdev);	struct ixgb_adapter *adapter = netdev->priv;	netif_device_detach(netdev);	if (netif_running(netdev))		ixgb_down(adapter, TRUE);	pci_save_state(pdev, adapter->pci_state);	state = (state > 0) ? 3 : 0;	pci_set_power_state(pdev, state);	msec_delay(200);	return 0;}#ifdef CONFIG_NET_POLL_CONTROLLER/* * Polling 'interrupt' - used by things like netconsole to send skbs * without having to re-enable interrupts. It's not called while * the interrupt routine is executing. */static void ixgb_netpoll(struct net_device *dev){	struct ixgb_adapter *adapter = dev->priv;	disable_irq(adapter->pdev->irq);	ixgb_intr(adapter->pdev->irq, dev, NULL);	enable_irq(adapter->pdev->irq);}#endif/* ixgb_main.c */

⌨️ 快捷键说明

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