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; }
/* Read MII register 'addr' from core 'regs' */ static int read_mii(int phyaddr, int regaddr, volatile greth_regs * regs) { while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { } GRETH_REGSAVE(®s->mdio, ((phyaddr & 0x1F) << 11) | ((regaddr & 0x1F) << 6) | 2); while (GRETH_REGLOAD(®s->mdio) & GRETH_MII_BUSY) { } if (!(GRETH_REGLOAD(®s->mdio) & GRETH_MII_NVALID)) { return (GRETH_REGLOAD(®s->mdio) >> 16) & 0xFFFF; } else { return -1;
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; }
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; }
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; }
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; }