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

📄 spider_net.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
 * packets, including updating the queue tail pointer. */static voidspider_net_cleanup_tx_ring(struct spider_net_card *card){	if ((spider_net_release_tx_chain(card, 0) != 0) &&	    (card->netdev->flags & IFF_UP)) {		spider_net_kick_tx_dma(card);		netif_wake_queue(card->netdev);	}}/** * spider_net_do_ioctl - called for device ioctls * @netdev: interface device structure * @ifr: request parameter structure for ioctl * @cmd: command code for ioctl * * returns 0 on success, <0 on failure. Currently, we have no special ioctls. * -EOPNOTSUPP is returned, if an unknown ioctl was requested */static intspider_net_do_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd){	switch (cmd) {	default:		return -EOPNOTSUPP;	}}/** * spider_net_pass_skb_up - takes an skb from a descriptor and passes it on * @descr: descriptor to process * @card: card structure * * Fills out skb structure and passes the data to the stack. * The descriptor state is not changed. */static voidspider_net_pass_skb_up(struct spider_net_descr *descr,		       struct spider_net_card *card){	struct spider_net_hw_descr *hwdescr = descr->hwdescr;	struct sk_buff *skb = descr->skb;	struct net_device *netdev = card->netdev;	u32 data_status = hwdescr->data_status;	u32 data_error = hwdescr->data_error;	skb_put(skb, hwdescr->valid_size);	/* the card seems to add 2 bytes of junk in front	 * of the ethernet frame */#define SPIDER_MISALIGN		2	skb_pull(skb, SPIDER_MISALIGN);	skb->protocol = eth_type_trans(skb, netdev);	/* checksum offload */	if (card->options.rx_csum) {		if ( ( (data_status & SPIDER_NET_DATA_STATUS_CKSUM_MASK) ==		       SPIDER_NET_DATA_STATUS_CKSUM_MASK) &&		     !(data_error & SPIDER_NET_DATA_ERR_CKSUM_MASK))			skb->ip_summed = CHECKSUM_UNNECESSARY;		else			skb->ip_summed = CHECKSUM_NONE;	} else		skb->ip_summed = CHECKSUM_NONE;	if (data_status & SPIDER_NET_VLAN_PACKET) {		/* further enhancements: HW-accel VLAN		 * vlan_hwaccel_receive_skb		 */	}	/* update netdevice statistics */	netdev->stats.rx_packets++;	netdev->stats.rx_bytes += skb->len;	/* pass skb up to stack */	netif_receive_skb(skb);}static void show_rx_chain(struct spider_net_card *card){	struct spider_net_descr_chain *chain = &card->rx_chain;	struct spider_net_descr *start= chain->tail;	struct spider_net_descr *descr= start;	struct spider_net_hw_descr *hwd = start->hwdescr;	struct device *dev = &card->netdev->dev;	u32 curr_desc, next_desc;	int status;	int tot = 0;	int cnt = 0;	int off = start - chain->ring;	int cstat = hwd->dmac_cmd_status;	dev_info(dev, "Total number of descrs=%d\n",		chain->num_desc);	dev_info(dev, "Chain tail located at descr=%d, status=0x%x\n",		off, cstat);	curr_desc = spider_net_read_reg(card, SPIDER_NET_GDACTDPA);	next_desc = spider_net_read_reg(card, SPIDER_NET_GDACNEXTDA);	status = cstat;	do	{		hwd = descr->hwdescr;		off = descr - chain->ring;		status = hwd->dmac_cmd_status;		if (descr == chain->head)			dev_info(dev, "Chain head is at %d, head status=0x%x\n",			         off, status);		if (curr_desc == descr->bus_addr)			dev_info(dev, "HW curr desc (GDACTDPA) is at %d, status=0x%x\n",			         off, status);		if (next_desc == descr->bus_addr)			dev_info(dev, "HW next desc (GDACNEXTDA) is at %d, status=0x%x\n",			         off, status);		if (hwd->next_descr_addr == 0)			dev_info(dev, "chain is cut at %d\n", off);		if (cstat != status) {			int from = (chain->num_desc + off - cnt) % chain->num_desc;			int to = (chain->num_desc + off - 1) % chain->num_desc;			dev_info(dev, "Have %d (from %d to %d) descrs "			         "with stat=0x%08x\n", cnt, from, to, cstat);			cstat = status;			cnt = 0;		}		cnt ++;		tot ++;		descr = descr->next;	} while (descr != start);	dev_info(dev, "Last %d descrs with stat=0x%08x "	         "for a total of %d descrs\n", cnt, cstat, tot);#ifdef DEBUG	/* Now dump the whole ring */	descr = start;	do	{		struct spider_net_hw_descr *hwd = descr->hwdescr;		status = spider_net_get_descr_status(hwd);		cnt = descr - chain->ring;		dev_info(dev, "Descr %d stat=0x%08x skb=%p\n",		         cnt, status, descr->skb);		dev_info(dev, "bus addr=%08x buf addr=%08x sz=%d\n",		         descr->bus_addr, hwd->buf_addr, hwd->buf_size);		dev_info(dev, "next=%08x result sz=%d valid sz=%d\n",		         hwd->next_descr_addr, hwd->result_size,		         hwd->valid_size);		dev_info(dev, "dmac=%08x data stat=%08x data err=%08x\n",		         hwd->dmac_cmd_status, hwd->data_status,		         hwd->data_error);		dev_info(dev, "\n");		descr = descr->next;	} while (descr != start);#endif}/** * spider_net_resync_head_ptr - Advance head ptr past empty descrs * * If the driver fails to keep up and empty the queue, then the * hardware wil run out of room to put incoming packets. This * will cause the hardware to skip descrs that are full (instead * of halting/retrying). Thus, once the driver runs, it wil need * to "catch up" to where the hardware chain pointer is at. */static void spider_net_resync_head_ptr(struct spider_net_card *card){	unsigned long flags;	struct spider_net_descr_chain *chain = &card->rx_chain;	struct spider_net_descr *descr;	int i, status;	/* Advance head pointer past any empty descrs */	descr = chain->head;	status = spider_net_get_descr_status(descr->hwdescr);	if (status == SPIDER_NET_DESCR_NOT_IN_USE)		return;	spin_lock_irqsave(&chain->lock, flags);	descr = chain->head;	status = spider_net_get_descr_status(descr->hwdescr);	for (i=0; i<chain->num_desc; i++) {		if (status != SPIDER_NET_DESCR_CARDOWNED) break;		descr = descr->next;		status = spider_net_get_descr_status(descr->hwdescr);	}	chain->head = descr;	spin_unlock_irqrestore(&chain->lock, flags);}static int spider_net_resync_tail_ptr(struct spider_net_card *card){	struct spider_net_descr_chain *chain = &card->rx_chain;	struct spider_net_descr *descr;	int i, status;	/* Advance tail pointer past any empty and reaped descrs */	descr = chain->tail;	status = spider_net_get_descr_status(descr->hwdescr);	for (i=0; i<chain->num_desc; i++) {		if ((status != SPIDER_NET_DESCR_CARDOWNED) &&		    (status != SPIDER_NET_DESCR_NOT_IN_USE)) break;		descr = descr->next;		status = spider_net_get_descr_status(descr->hwdescr);	}	chain->tail = descr;	if ((i == chain->num_desc) || (i == 0))		return 1;	return 0;}/** * spider_net_decode_one_descr - processes an RX descriptor * @card: card structure * * Returns 1 if a packet has been sent to the stack, otherwise 0. * * Processes an RX descriptor by iommu-unmapping the data buffer * and passing the packet up to the stack. This function is called * in softirq context, e.g. either bottom half from interrupt or * NAPI polling context. */static intspider_net_decode_one_descr(struct spider_net_card *card){	struct net_device *dev = card->netdev;	struct spider_net_descr_chain *chain = &card->rx_chain;	struct spider_net_descr *descr = chain->tail;	struct spider_net_hw_descr *hwdescr = descr->hwdescr;	u32 hw_buf_addr;	int status;	status = spider_net_get_descr_status(hwdescr);	/* Nothing in the descriptor, or ring must be empty */	if ((status == SPIDER_NET_DESCR_CARDOWNED) ||	    (status == SPIDER_NET_DESCR_NOT_IN_USE))		return 0;	/* descriptor definitively used -- move on tail */	chain->tail = descr->next;	/* unmap descriptor */	hw_buf_addr = hwdescr->buf_addr;	hwdescr->buf_addr = 0xffffffff;	pci_unmap_single(card->pdev, hw_buf_addr,			SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE);	if ( (status == SPIDER_NET_DESCR_RESPONSE_ERROR) ||	     (status == SPIDER_NET_DESCR_PROTECTION_ERROR) ||	     (status == SPIDER_NET_DESCR_FORCE_END) ) {		if (netif_msg_rx_err(card))			dev_err(&dev->dev,			       "dropping RX descriptor with state %d\n", status);		dev->stats.rx_dropped++;		goto bad_desc;	}	if ( (status != SPIDER_NET_DESCR_COMPLETE) &&	     (status != SPIDER_NET_DESCR_FRAME_END) ) {		if (netif_msg_rx_err(card))			dev_err(&card->netdev->dev,			       "RX descriptor with unknown state %d\n", status);		card->spider_stats.rx_desc_unk_state++;		goto bad_desc;	}	/* The cases we'll throw away the packet immediately */	if (hwdescr->data_error & SPIDER_NET_DESTROY_RX_FLAGS) {		if (netif_msg_rx_err(card))			dev_err(&card->netdev->dev,			       "error in received descriptor found, "			       "data_status=x%08x, data_error=x%08x\n",			       hwdescr->data_status, hwdescr->data_error);		goto bad_desc;	}	if (hwdescr->dmac_cmd_status & SPIDER_NET_DESCR_BAD_STATUS) {		dev_err(&card->netdev->dev, "bad status, cmd_status=x%08x\n",			       hwdescr->dmac_cmd_status);		pr_err("buf_addr=x%08x\n", hw_buf_addr);		pr_err("buf_size=x%08x\n", hwdescr->buf_size);		pr_err("next_descr_addr=x%08x\n", hwdescr->next_descr_addr);		pr_err("result_size=x%08x\n", hwdescr->result_size);		pr_err("valid_size=x%08x\n", hwdescr->valid_size);		pr_err("data_status=x%08x\n", hwdescr->data_status);		pr_err("data_error=x%08x\n", hwdescr->data_error);		pr_err("which=%ld\n", descr - card->rx_chain.ring);		card->spider_stats.rx_desc_error++;		goto bad_desc;	}	/* Ok, we've got a packet in descr */	spider_net_pass_skb_up(descr, card);	descr->skb = NULL;	hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;	return 1;bad_desc:	if (netif_msg_rx_err(card))		show_rx_chain(card);	dev_kfree_skb_irq(descr->skb);	descr->skb = NULL;	hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE;	return 0;}/** * spider_net_poll - NAPI poll function called by the stack to return packets * @netdev: interface device structure * @budget: number of packets we can pass to the stack at most * * returns 0 if no more packets available to the driver/stack. Returns 1, * if the quota is exceeded, but the driver has still packets. * * spider_net_poll returns all packets from the rx descriptors to the stack * (using netif_receive_skb). If all/enough packets are up, the driver * reenables interrupts and returns 0. If not, 1 is returned. */static int spider_net_poll(struct napi_struct *napi, int budget){	struct spider_net_card *card = container_of(napi, struct spider_net_card, napi);	struct net_device *netdev = card->netdev;	int packets_done = 0;	while (packets_done < budget) {		if (!spider_net_decode_one_descr(card))			break;		packets_done++;	}	if ((packets_done == 0) && (card->num_rx_ints != 0)) {		if (!spider_net_resync_tail_ptr(card))			packets_done = budget;		spider_net_resync_head_ptr(card);	}	card->num_rx_ints = 0;	spider_net_refill_rx_chain(card);	spider_net_enable_rxdmac(card);	spider_net_cleanup_tx_ring(card);	/* if all packets are in the stack, enable interrupts and return 0 */	/* if not, return 1 */	if (packets_done < budget) {		netif_rx_complete(netdev, napi);		spider_net_rx_irq_on(card);		card->ignore_rx_ramfull = 0;	}	return packets_done;}/** * spider_net_change_mtu - changes the MTU of an interface * @netdev: interface device structure * @new_mtu: new MTU value * * returns 0 on success, <0 on failure */static intspider_net_change_mtu(struct net_device *netdev, int new_mtu){	/* no need to re-alloc skbs or so -- the max mtu is about 2.3k	 * and mtu is outbound only anyway */	if ( (new_mtu < SPIDER_NET_MIN_MTU ) ||		(new_mtu > SPIDER_NET_MAX_MTU) )		return -EINVAL;	netdev->mtu = new_mtu;	return 0;}/** * spider_net_set_mac - sets the MAC of an interface * @netdev: interface device structure * @ptr: pointer to new MAC address * * Returns 0 on success, <0 on failure. Currently, we don't support this * and will always return EOPNOTSUPP. */static intspider_net_set_mac(struct net_device *netdev, void *p){	struct spider_net_card *card = netdev_priv(netdev);	u32 macl, macu, regvalue;	struct sockaddr *addr = p;	if (!is_valid_ether_addr(addr->sa_data))		return -EADDRNOTAVAIL;	/* switch off GMACTPE and GMACRPE */	regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);	regvalue &= ~((1 << 5) | (1 << 6));	spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);	/* write mac */	macu = (addr->sa_data[0]<<24) + (addr->sa_data[1]<<16) +		(addr->sa_data[2]<<8) + (addr->sa_data[3]);	macl = (addr->sa_data[4]<<8) + (addr->sa_data[5]);	spider_net_write_reg(card, SPIDER_NET_GMACUNIMACU, macu);	spider_net_write_reg(card, SPIDER_NET_GMACUNIMACL, macl);	/* switch GMACTPE and GMACRPE back on */	regvalue = spider_net_read_reg(card, SPIDER_NET_GMACOPEMD);	regvalue |= ((1 << 5) | (1 << 6));	spider_net_write_reg(card, SPIDER_NET_GMACOPEMD, regvalue);	spider_net_set_promisc(card);	/* look up, whether we have been successful */	if (spider_net_get_mac_address(netdev))		return -EADDRNOTAVAIL;	if (memcmp(netdev->dev_addr,addr->sa_data,netdev->addr_len))		return -EADDRNOTAVAIL;	return 0;}/** * spider_net_link_reset * @netdev: net device structure * * This is called when the PHY_LINK signal is asserted. For the blade this is * not connected so we should never get here. * */static voidspider_net_link_reset(struct net_device *netdev){	struct spider_net_card *card = netdev_priv(netdev);	del_timer_sync(&card->aneg_timer);	/* clear interrupt, block further interrupts */	spider_net_write_reg(card, SPIDER_NET_GMACST,			     spider_net_read_reg(card, SPIDER_NET_GMACST));	spider_net_write_reg(card, SPIDER_NET_GMACINTEN, 0);	/* reset phy and setup aneg */	spider_net_setup_aneg(card);	mod_timer(&card->aneg_timer, jiffies + SPIDER_NET_ANEG_TIMER);}/** * spider_net_handle_error_irq - handles errors raised by an interrupt * @card: card structure * @status_reg: interrupt status register 0 (GHIINT0STS)

⌨️ 快捷键说明

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