cpmac.c

来自「linux 内核源代码」· C语言 代码 · 共 1,197 行 · 第 1/3 页

C
1,197
字号
			       "%s: low on skbs, dropping packet\n",			       priv->dev->name);		priv->dev->stats.rx_dropped++;	}	desc->buflen = CPMAC_SKB_SIZE;	desc->dataflags = CPMAC_OWN;	return result;}static int cpmac_poll(struct napi_struct *napi, int budget){	struct sk_buff *skb;	struct cpmac_desc *desc;	int received = 0;	struct cpmac_priv *priv = container_of(napi, struct cpmac_priv, napi);	spin_lock(&priv->rx_lock);	if (unlikely(!priv->rx_head)) {		if (netif_msg_rx_err(priv) && net_ratelimit())			printk(KERN_WARNING "%s: rx: polling, but no queue\n",			       priv->dev->name);		netif_rx_complete(priv->dev, napi);		return 0;	}	desc = priv->rx_head;	while (((desc->dataflags & CPMAC_OWN) == 0) && (received < budget)) {		skb = cpmac_rx_one(priv, desc);		if (likely(skb)) {			netif_receive_skb(skb);			received++;		}		desc = desc->next;	}	priv->rx_head = desc;	spin_unlock(&priv->rx_lock);	if (unlikely(netif_msg_rx_status(priv)))		printk(KERN_DEBUG "%s: poll processed %d packets\n",		       priv->dev->name, received);	if (desc->dataflags & CPMAC_OWN) {		netif_rx_complete(priv->dev, napi);		cpmac_write(priv->regs, CPMAC_RX_PTR(0), (u32)desc->mapping);		cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);		return 0;	}	return 1;}static int cpmac_start_xmit(struct sk_buff *skb, struct net_device *dev){	int queue, len;	struct cpmac_desc *desc;	struct cpmac_priv *priv = netdev_priv(dev);	if (unlikely(skb_padto(skb, ETH_ZLEN)))		return NETDEV_TX_OK;	len = max(skb->len, ETH_ZLEN);	queue = skb_get_queue_mapping(skb);#ifdef CONFIG_NETDEVICES_MULTIQUEUE	netif_stop_subqueue(dev, queue);#else	netif_stop_queue(dev);#endif	desc = &priv->desc_ring[queue];	if (unlikely(desc->dataflags & CPMAC_OWN)) {		if (netif_msg_tx_err(priv) && net_ratelimit())			printk(KERN_WARNING "%s: tx dma ring full\n",			       dev->name);		return NETDEV_TX_BUSY;	}	spin_lock(&priv->lock);	dev->trans_start = jiffies;	spin_unlock(&priv->lock);	desc->dataflags = CPMAC_SOP | CPMAC_EOP | CPMAC_OWN;	desc->skb = skb;	desc->data_mapping = dma_map_single(&dev->dev, skb->data, len,					    DMA_TO_DEVICE);	desc->hw_data = (u32)desc->data_mapping;	desc->datalen = len;	desc->buflen = len;	if (unlikely(netif_msg_tx_queued(priv)))		printk(KERN_DEBUG "%s: sending 0x%p, len=%d\n", dev->name, skb,		       skb->len);	if (unlikely(netif_msg_hw(priv)))		cpmac_dump_desc(dev, desc);	if (unlikely(netif_msg_pktdata(priv)))		cpmac_dump_skb(dev, skb);	cpmac_write(priv->regs, CPMAC_TX_PTR(queue), (u32)desc->mapping);	return NETDEV_TX_OK;}static void cpmac_end_xmit(struct net_device *dev, int queue){	struct cpmac_desc *desc;	struct cpmac_priv *priv = netdev_priv(dev);	desc = &priv->desc_ring[queue];	cpmac_write(priv->regs, CPMAC_TX_ACK(queue), (u32)desc->mapping);	if (likely(desc->skb)) {		spin_lock(&priv->lock);		dev->stats.tx_packets++;		dev->stats.tx_bytes += desc->skb->len;		spin_unlock(&priv->lock);		dma_unmap_single(&dev->dev, desc->data_mapping, desc->skb->len,				 DMA_TO_DEVICE);		if (unlikely(netif_msg_tx_done(priv)))			printk(KERN_DEBUG "%s: sent 0x%p, len=%d\n", dev->name,			       desc->skb, desc->skb->len);		dev_kfree_skb_irq(desc->skb);		desc->skb = NULL;#ifdef CONFIG_NETDEVICES_MULTIQUEUE		if (netif_subqueue_stopped(dev, queue))			netif_wake_subqueue(dev, queue);#else		if (netif_queue_stopped(dev))			netif_wake_queue(dev);#endif	} else {		if (netif_msg_tx_err(priv) && net_ratelimit())			printk(KERN_WARNING			       "%s: end_xmit: spurious interrupt\n", dev->name);#ifdef CONFIG_NETDEVICES_MULTIQUEUE		if (netif_subqueue_stopped(dev, queue))			netif_wake_subqueue(dev, queue);#else		if (netif_queue_stopped(dev))			netif_wake_queue(dev);#endif	}}static void cpmac_hw_stop(struct net_device *dev){	int i;	struct cpmac_priv *priv = netdev_priv(dev);	struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data;	ar7_device_reset(pdata->reset_bit);	cpmac_write(priv->regs, CPMAC_RX_CONTROL,		    cpmac_read(priv->regs, CPMAC_RX_CONTROL) & ~1);	cpmac_write(priv->regs, CPMAC_TX_CONTROL,		    cpmac_read(priv->regs, CPMAC_TX_CONTROL) & ~1);	for (i = 0; i < 8; i++) {		cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);		cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0);	}	cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff);	cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff);	cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff);	cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff);	cpmac_write(priv->regs, CPMAC_MAC_CONTROL,		    cpmac_read(priv->regs, CPMAC_MAC_CONTROL) & ~MAC_MII);}static void cpmac_hw_start(struct net_device *dev){	int i;	struct cpmac_priv *priv = netdev_priv(dev);	struct plat_cpmac_data *pdata = priv->pdev->dev.platform_data;	ar7_device_reset(pdata->reset_bit);	for (i = 0; i < 8; i++) {		cpmac_write(priv->regs, CPMAC_TX_PTR(i), 0);		cpmac_write(priv->regs, CPMAC_RX_PTR(i), 0);	}	cpmac_write(priv->regs, CPMAC_RX_PTR(0), priv->rx_head->mapping);	cpmac_write(priv->regs, CPMAC_MBP, MBP_RXSHORT | MBP_RXBCAST |		    MBP_RXMCAST);	cpmac_write(priv->regs, CPMAC_BUFFER_OFFSET, 0);	for (i = 0; i < 8; i++)		cpmac_write(priv->regs, CPMAC_MAC_ADDR_LO(i), dev->dev_addr[5]);	cpmac_write(priv->regs, CPMAC_MAC_ADDR_MID, dev->dev_addr[4]);	cpmac_write(priv->regs, CPMAC_MAC_ADDR_HI, dev->dev_addr[0] |		    (dev->dev_addr[1] << 8) | (dev->dev_addr[2] << 16) |		    (dev->dev_addr[3] << 24));	cpmac_write(priv->regs, CPMAC_MAX_LENGTH, CPMAC_SKB_SIZE);	cpmac_write(priv->regs, CPMAC_UNICAST_CLEAR, 0xff);	cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 0xff);	cpmac_write(priv->regs, CPMAC_TX_INT_CLEAR, 0xff);	cpmac_write(priv->regs, CPMAC_MAC_INT_CLEAR, 0xff);	cpmac_write(priv->regs, CPMAC_UNICAST_ENABLE, 1);	cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1);	cpmac_write(priv->regs, CPMAC_TX_INT_ENABLE, 0xff);	cpmac_write(priv->regs, CPMAC_MAC_INT_ENABLE, 3);	cpmac_write(priv->regs, CPMAC_RX_CONTROL,		    cpmac_read(priv->regs, CPMAC_RX_CONTROL) | 1);	cpmac_write(priv->regs, CPMAC_TX_CONTROL,		    cpmac_read(priv->regs, CPMAC_TX_CONTROL) | 1);	cpmac_write(priv->regs, CPMAC_MAC_CONTROL,		    cpmac_read(priv->regs, CPMAC_MAC_CONTROL) | MAC_MII |		    MAC_FDX);}static void cpmac_clear_rx(struct net_device *dev){	struct cpmac_priv *priv = netdev_priv(dev);	struct cpmac_desc *desc;	int i;	if (unlikely(!priv->rx_head))		return;	desc = priv->rx_head;	for (i = 0; i < priv->ring_size; i++) {		if ((desc->dataflags & CPMAC_OWN) == 0) {			if (netif_msg_rx_err(priv) && net_ratelimit())				printk(KERN_WARNING "%s: packet dropped\n",				       dev->name);			if (unlikely(netif_msg_hw(priv)))				cpmac_dump_desc(dev, desc);			desc->dataflags = CPMAC_OWN;			dev->stats.rx_dropped++;		}		desc = desc->next;	}}static void cpmac_clear_tx(struct net_device *dev){	struct cpmac_priv *priv = netdev_priv(dev);	int i;	if (unlikely(!priv->desc_ring))		return;	for (i = 0; i < CPMAC_QUEUES; i++) {		priv->desc_ring[i].dataflags = 0;		if (priv->desc_ring[i].skb) {			dev_kfree_skb_any(priv->desc_ring[i].skb);			if (netif_subqueue_stopped(dev, i))			    netif_wake_subqueue(dev, i);		}	}}static void cpmac_hw_error(struct work_struct *work){	struct cpmac_priv *priv =		container_of(work, struct cpmac_priv, reset_work);	spin_lock(&priv->rx_lock);	cpmac_clear_rx(priv->dev);	spin_unlock(&priv->rx_lock);	cpmac_clear_tx(priv->dev);	cpmac_hw_start(priv->dev);	napi_enable(&priv->napi);	netif_start_queue(priv->dev);}static irqreturn_t cpmac_irq(int irq, void *dev_id){	struct net_device *dev = dev_id;	struct cpmac_priv *priv;	int queue;	u32 status;	if (!dev)		return IRQ_NONE;	priv = netdev_priv(dev);	status = cpmac_read(priv->regs, CPMAC_MAC_INT_VECTOR);	if (unlikely(netif_msg_intr(priv)))		printk(KERN_DEBUG "%s: interrupt status: 0x%08x\n", dev->name,		       status);	if (status & MAC_INT_TX)		cpmac_end_xmit(dev, (status & 7));	if (status & MAC_INT_RX) {		queue = (status >> 8) & 7;		if (netif_rx_schedule_prep(dev, &priv->napi)) {			cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue);			__netif_rx_schedule(dev, &priv->napi);		}	}	cpmac_write(priv->regs, CPMAC_MAC_EOI_VECTOR, 0);	if (unlikely(status & (MAC_INT_HOST | MAC_INT_STATUS))) {		if (netif_msg_drv(priv) && net_ratelimit())			printk(KERN_ERR "%s: hw error, resetting...\n",			       dev->name);		netif_stop_queue(dev);		napi_disable(&priv->napi);		cpmac_hw_stop(dev);		schedule_work(&priv->reset_work);		if (unlikely(netif_msg_hw(priv)))			cpmac_dump_regs(dev);	}	return IRQ_HANDLED;}static void cpmac_tx_timeout(struct net_device *dev){	struct cpmac_priv *priv = netdev_priv(dev);	int i;	spin_lock(&priv->lock);	dev->stats.tx_errors++;	spin_unlock(&priv->lock);	if (netif_msg_tx_err(priv) && net_ratelimit())		printk(KERN_WARNING "%s: transmit timeout\n", dev->name);	/* 	 * FIXME: waking up random queue is not the best thing to	 * do... on the other hand why we got here at all?	 */#ifdef CONFIG_NETDEVICES_MULTIQUEUE	for (i = 0; i < CPMAC_QUEUES; i++)		if (priv->desc_ring[i].skb) {			priv->desc_ring[i].dataflags = 0;			dev_kfree_skb_any(priv->desc_ring[i].skb);			netif_wake_subqueue(dev, i);			break;		}#else	priv->desc_ring[0].dataflags = 0;	if (priv->desc_ring[0].skb)		dev_kfree_skb_any(priv->desc_ring[0].skb);	netif_wake_queue(dev);#endif}static int cpmac_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){	struct cpmac_priv *priv = netdev_priv(dev);	if (!(netif_running(dev)))		return -EINVAL;	if (!priv->phy)		return -EINVAL;	if ((cmd == SIOCGMIIPHY) || (cmd == SIOCGMIIREG) ||	    (cmd == SIOCSMIIREG))		return phy_mii_ioctl(priv->phy, if_mii(ifr), cmd);	return -EOPNOTSUPP;}static int cpmac_get_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct cpmac_priv *priv = netdev_priv(dev);	if (priv->phy)		return phy_ethtool_gset(priv->phy, cmd);	return -EINVAL;}static int cpmac_set_settings(struct net_device *dev, struct ethtool_cmd *cmd){	struct cpmac_priv *priv = netdev_priv(dev);	if (!capable(CAP_NET_ADMIN))		return -EPERM;	if (priv->phy)		return phy_ethtool_sset(priv->phy, cmd);	return -EINVAL;}static void cpmac_get_ringparam(struct net_device *dev, struct ethtool_ringparam* ring){	struct cpmac_priv *priv = netdev_priv(dev);	ring->rx_max_pending = 1024;	ring->rx_mini_max_pending = 1;	ring->rx_jumbo_max_pending = 1;	ring->tx_max_pending = 1;	ring->rx_pending = priv->ring_size;	ring->rx_mini_pending = 1;	ring->rx_jumbo_pending = 1;	ring->tx_pending = 1;}static int cpmac_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ring){	struct cpmac_priv *priv = netdev_priv(dev);	if (netif_running(dev))		return -EBUSY;	priv->ring_size = ring->rx_pending;	return 0;}static void cpmac_get_drvinfo(struct net_device *dev,			      struct ethtool_drvinfo *info){	strcpy(info->driver, "cpmac");

⌨️ 快捷键说明

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