Пример #1
0
static irqreturn_t greth_interrupt(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
	struct greth_private *greth;
	u32 status, ctrl;
	irqreturn_t retval = IRQ_NONE;

	greth = netdev_priv(dev);

	spin_lock(&greth->devlock);

	/* Get the interrupt events that caused us to be here. */
	status = GRETH_REGLOAD(greth->regs->status);

	/* Must see if interrupts are enabled also, INT_TX|INT_RX flags may be
	 * set regardless of whether IRQ is enabled or not. Especially
	 * important when shared IRQ.
	 */
	ctrl = GRETH_REGLOAD(greth->regs->control);

	/* Handle rx and tx interrupts through poll */
	if (((status & (GRETH_INT_RE | GRETH_INT_RX)) && (ctrl & GRETH_RXI)) ||
	    ((status & (GRETH_INT_TE | GRETH_INT_TX)) && (ctrl & GRETH_TXI))) {
		retval = IRQ_HANDLED;

		/* Disable interrupts and schedule poll() */
		greth_disable_irqs(greth);
		napi_schedule(&greth->napi);
	}

	mmiowb();
	spin_unlock(&greth->devlock);

	return retval;
}
Пример #2
0
/* Read MII register 'addr' from core 'regs' */
static int read_mii(int phyaddr, int regaddr, volatile greth_regs * regs)
{
	while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
	}

	GRETH_REGSAVE(&regs->mdio, ((phyaddr & 0x1F) << 11) | ((regaddr & 0x1F) << 6) | 2);

	while (GRETH_REGLOAD(&regs->mdio) & GRETH_MII_BUSY) {
	}

	if (!(GRETH_REGLOAD(&regs->mdio) & GRETH_MII_NVALID)) {
		return (GRETH_REGLOAD(&regs->mdio) >> 16) & 0xFFFF;
	} else {
		return -1;
Пример #3
0
static int greth_poll(struct napi_struct *napi, int budget)
{
	struct greth_private *greth;
	int work_done = 0;
	unsigned long flags;
	u32 mask, ctrl;
	greth = container_of(napi, struct greth_private, napi);

restart_txrx_poll:
	if (netif_queue_stopped(greth->netdev)) {
		if (greth->gbit_mac)
			greth_clean_tx_gbit(greth->netdev);
		else
			greth_clean_tx(greth->netdev);
	}

	if (greth->gbit_mac) {
		work_done += greth_rx_gbit(greth->netdev, budget - work_done);
	} else {
		work_done += greth_rx(greth->netdev, budget - work_done);
	}

	if (work_done < budget) {

		spin_lock_irqsave(&greth->devlock, flags);

		ctrl = GRETH_REGLOAD(greth->regs->control);
		if (netif_queue_stopped(greth->netdev)) {
			GRETH_REGSAVE(greth->regs->control,
					ctrl | GRETH_TXI | GRETH_RXI);
			mask = GRETH_INT_RX | GRETH_INT_RE |
			       GRETH_INT_TX | GRETH_INT_TE;
		} else {
			GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_RXI);
			mask = GRETH_INT_RX | GRETH_INT_RE;
		}

		if (GRETH_REGLOAD(greth->regs->status) & mask) {
			GRETH_REGSAVE(greth->regs->control, ctrl);
			spin_unlock_irqrestore(&greth->devlock, flags);
			goto restart_txrx_poll;
		} else {
			__napi_complete(napi);
			spin_unlock_irqrestore(&greth->devlock, flags);
		}
	}

	return work_done;
}
Пример #4
0
static netdev_tx_t
greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
	struct greth_private *greth = netdev_priv(dev);
	struct greth_bd *bdp;
	int err = NETDEV_TX_OK;
	u32 status, dma_addr, ctrl;
	unsigned long flags;

	/* Clean TX Ring */
	greth_clean_tx(greth->netdev);

	if (unlikely(greth->tx_free <= 0)) {
		spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/
		ctrl = GRETH_REGLOAD(greth->regs->control);
		/* Enable TX IRQ only if not already in poll() routine */
		if (ctrl & GRETH_RXI)
			GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
		netif_stop_queue(dev);
		spin_unlock_irqrestore(&greth->devlock, flags);
		return NETDEV_TX_BUSY;
	}

	if (netif_msg_pktdata(greth))
		greth_print_tx_packet(skb);


	if (unlikely(skb->len > MAX_FRAME_SIZE)) {
		dev->stats.tx_errors++;
		goto out;
	}

	bdp = greth->tx_bd_base + greth->tx_next;
	dma_addr = greth_read_bd(&bdp->addr);

	memcpy((unsigned char *) phys_to_virt(dma_addr), skb->data, skb->len);

	dma_sync_single_for_device(greth->dev, dma_addr, skb->len, DMA_TO_DEVICE);

	status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN);
	greth->tx_bufs_length[greth->tx_next] = skb->len & GRETH_BD_LEN;

	/* Wrap around descriptor ring */
	if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
		status |= GRETH_BD_WR;
	}

	greth->tx_next = NEXT_TX(greth->tx_next);
	greth->tx_free--;

	/* Write descriptor control word and enable transmission */
	greth_write_bd(&bdp->stat, status);
	spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
	greth_enable_tx(greth);
	spin_unlock_irqrestore(&greth->devlock, flags);

out:
	dev_kfree_skb(skb);
	return err;
}
Пример #5
0
static irqreturn_t greth_interrupt(int irq, void *dev_id)
{
	struct net_device *dev = dev_id;
	struct greth_private *greth;
	u32 status;
	irqreturn_t retval = IRQ_NONE;

	greth = netdev_priv(dev);

	spin_lock(&greth->devlock);

	/* Get the interrupt events that caused us to be here. */
	status = GRETH_REGLOAD(greth->regs->status);

	/* Handle rx and tx interrupts through poll */
	if (status & (GRETH_INT_RX | GRETH_INT_TX)) {

		/* Clear interrupt status */
		GRETH_REGORIN(greth->regs->status,
			      status & (GRETH_INT_RX | GRETH_INT_TX));

		retval = IRQ_HANDLED;

		/* Disable interrupts and schedule poll() */
		greth_disable_irqs(greth);
		napi_schedule(&greth->napi);
	}

	mmiowb();
	spin_unlock(&greth->devlock);

	return retval;
}
Пример #6
0
static netdev_tx_t
greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
{
	struct greth_private *greth = netdev_priv(dev);
	struct greth_bd *bdp;
	u32 status = 0, dma_addr, ctrl;
	int curr_tx, nr_frags, i, err = NETDEV_TX_OK;
	unsigned long flags;

	nr_frags = skb_shinfo(skb)->nr_frags;

	/* Clean TX Ring */
	greth_clean_tx_gbit(dev);

	if (greth->tx_free < nr_frags + 1) {
		spin_lock_irqsave(&greth->devlock, flags);/*save from poll/irq*/
		ctrl = GRETH_REGLOAD(greth->regs->control);
		/* Enable TX IRQ only if not already in poll() routine */
		if (ctrl & GRETH_RXI)
			GRETH_REGSAVE(greth->regs->control, ctrl | GRETH_TXI);
		netif_stop_queue(dev);
		spin_unlock_irqrestore(&greth->devlock, flags);
		err = NETDEV_TX_BUSY;
		goto out;
	}

	if (netif_msg_pktdata(greth))
		greth_print_tx_packet(skb);

	if (unlikely(skb->len > MAX_FRAME_SIZE)) {
		dev->stats.tx_errors++;
		goto out;
	}

	/* Save skb pointer. */
	greth->tx_skbuff[greth->tx_next] = skb;

	/* Linear buf */
	if (nr_frags != 0)
		status = GRETH_TXBD_MORE;

	if (skb->ip_summed == CHECKSUM_PARTIAL)
		status |= GRETH_TXBD_CSALL;
	status |= skb_headlen(skb) & GRETH_BD_LEN;
	if (greth->tx_next == GRETH_TXBD_NUM_MASK)
		status |= GRETH_BD_WR;


	bdp = greth->tx_bd_base + greth->tx_next;
	greth_write_bd(&bdp->stat, status);
	dma_addr = dma_map_single(greth->dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);

	if (unlikely(dma_mapping_error(greth->dev, dma_addr)))
		goto map_error;

	greth_write_bd(&bdp->addr, dma_addr);

	curr_tx = NEXT_TX(greth->tx_next);

	/* Frags */
	for (i = 0; i < nr_frags; i++) {
		skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
		greth->tx_skbuff[curr_tx] = NULL;
		bdp = greth->tx_bd_base + curr_tx;

		status = GRETH_BD_EN;
		if (skb->ip_summed == CHECKSUM_PARTIAL)
			status |= GRETH_TXBD_CSALL;
		status |= frag->size & GRETH_BD_LEN;

		/* Wrap around descriptor ring */
		if (curr_tx == GRETH_TXBD_NUM_MASK)
			status |= GRETH_BD_WR;

		/* More fragments left */
		if (i < nr_frags - 1)
			status |= GRETH_TXBD_MORE;
		else
			status |= GRETH_BD_IE; /* enable IRQ on last fragment */

		greth_write_bd(&bdp->stat, status);

		dma_addr = dma_map_page(greth->dev,
					frag->page,
					frag->page_offset,
					frag->size,
					DMA_TO_DEVICE);

		if (unlikely(dma_mapping_error(greth->dev, dma_addr)))
			goto frag_map_error;

		greth_write_bd(&bdp->addr, dma_addr);

		curr_tx = NEXT_TX(curr_tx);
	}

	wmb();

	/* Enable the descriptor chain by enabling the first descriptor */
	bdp = greth->tx_bd_base + greth->tx_next;
	greth_write_bd(&bdp->stat, greth_read_bd(&bdp->stat) | GRETH_BD_EN);
	greth->tx_next = curr_tx;
	greth->tx_free -= nr_frags + 1;

	wmb();

	spin_lock_irqsave(&greth->devlock, flags); /*save from poll/irq*/
	greth_enable_tx(greth);
	spin_unlock_irqrestore(&greth->devlock, flags);

	return NETDEV_TX_OK;

frag_map_error:
	/* Unmap SKB mappings that succeeded and disable descriptor */
	for (i = 0; greth->tx_next + i != curr_tx; i++) {
		bdp = greth->tx_bd_base + greth->tx_next + i;
		dma_unmap_single(greth->dev,
				 greth_read_bd(&bdp->addr),
				 greth_read_bd(&bdp->stat) & GRETH_BD_LEN,
				 DMA_TO_DEVICE);
		greth_write_bd(&bdp->stat, 0);
	}
map_error:
	if (net_ratelimit())
		dev_warn(greth->dev, "Could not create TX DMA mapping\n");
	dev_kfree_skb(skb);
out:
	return err;
}