Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 231241
b: refs/heads/master
c: 0f73f2c
h: refs/heads/master
i:
  231239: fefa931
v: v3
  • Loading branch information
Daniel Hellstrom authored and David S. Miller committed Jan 14, 2011
1 parent 5b1aa45 commit ccfe5ae
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 68 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 1ca23434dd0001bd2bfff31b8251436b34aa9066
refs/heads/master: 0f73f2c5a3ebb957ee66718c903c17ed71a4fc2e
159 changes: 92 additions & 67 deletions trunk/drivers/net/greth.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/*
* Aeroflex Gaisler GRETH 10/100/1G Ethernet MAC.
*
* 2005-2009 (c) Aeroflex Gaisler AB
* 2005-2010 (c) Aeroflex Gaisler AB
*
* This driver supports GRETH 10/100 and GRETH 10/100/1G Ethernet MACs
* available in the GRLIB VHDL IP core library.
Expand Down Expand Up @@ -392,12 +392,20 @@ 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;
u32 status, dma_addr, ctrl;
unsigned long flags;

bdp = greth->tx_bd_base + greth->tx_next;
/* 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;
}

Expand All @@ -410,13 +418,14 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
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 | (skb->len & GRETH_BD_LEN);
status = GRETH_BD_EN | GRETH_BD_IE | (skb->len & GRETH_BD_LEN);

/* Wrap around descriptor ring */
if (greth->tx_next == GRETH_TXBD_NUM_MASK) {
Expand All @@ -426,22 +435,11 @@ greth_start_xmit(struct sk_buff *skb, struct net_device *dev)
greth->tx_next = NEXT_TX(greth->tx_next);
greth->tx_free--;

/* No more descriptors */
if (unlikely(greth->tx_free == 0)) {

/* Free transmitted descriptors */
greth_clean_tx(dev);

/* If nothing was cleaned, stop queue & wait for irq */
if (unlikely(greth->tx_free == 0)) {
status |= GRETH_BD_IE;
netif_stop_queue(dev);
}
}

/* 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);
Expand All @@ -454,13 +452,23 @@ 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;
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;
}
Expand Down Expand Up @@ -513,14 +521,8 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
/* More fragments left */
if (i < nr_frags - 1)
status |= GRETH_TXBD_MORE;

/* ... last fragment, check if out of descriptors */
else if (greth->tx_free - nr_frags - 1 < (MAX_SKB_FRAGS + 1)) {

/* Enable interrupts and stop queue */
status |= GRETH_BD_IE;
netif_stop_queue(dev);
}
else
status |= GRETH_BD_IE; /* enable IRQ on last fragment */

greth_write_bd(&bdp->stat, status);

Expand Down Expand Up @@ -548,7 +550,9 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)

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;

Expand All @@ -570,12 +574,11 @@ greth_start_xmit_gbit(struct sk_buff *skb, struct net_device *dev)
return err;
}


static irqreturn_t greth_interrupt(int irq, void *dev_id)
{
struct net_device *dev = dev_id;
struct greth_private *greth;
u32 status;
u32 status, ctrl;
irqreturn_t retval = IRQ_NONE;

greth = netdev_priv(dev);
Expand All @@ -585,14 +588,15 @@ static irqreturn_t greth_interrupt(int irq, void *dev_id)
/* 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_RE | GRETH_INT_RX |
GRETH_INT_TE | GRETH_INT_TX)) {
/* 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);

/* Clear interrupt status */
GRETH_REGSAVE(greth->regs->status,
status & (GRETH_INT_RE | GRETH_INT_RX |
GRETH_INT_TE | GRETH_INT_TX));
/* 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() */
Expand All @@ -616,6 +620,8 @@ static void greth_clean_tx(struct net_device *dev)

while (1) {
bdp = greth->tx_bd_base + greth->tx_last;
GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
mb();
stat = greth_read_bd(&bdp->stat);

if (unlikely(stat & GRETH_BD_EN))
Expand Down Expand Up @@ -676,7 +682,10 @@ static void greth_clean_tx_gbit(struct net_device *dev)

/* We only clean fully completed SKBs */
bdp_last_frag = greth->tx_bd_base + SKIP_TX(greth->tx_last, nr_frags);
stat = bdp_last_frag->stat;

GRETH_REGSAVE(greth->regs->status, GRETH_INT_TE | GRETH_INT_TX);
mb();
stat = greth_read_bd(&bdp_last_frag->stat);

if (stat & GRETH_BD_EN)
break;
Expand Down Expand Up @@ -708,21 +717,9 @@ static void greth_clean_tx_gbit(struct net_device *dev)
greth->tx_free += nr_frags+1;
dev_kfree_skb(skb);
}
if (greth->tx_free > (MAX_SKB_FRAGS + 1)) {
netif_wake_queue(dev);
}
}

static int greth_pending_packets(struct greth_private *greth)
{
struct greth_bd *bdp;
u32 status;
bdp = greth->rx_bd_base + greth->rx_cur;
status = greth_read_bd(&bdp->stat);
if (status & GRETH_BD_EN)
return 0;
else
return 1;
if (netif_queue_stopped(dev) && (greth->tx_free > (MAX_SKB_FRAGS+1)))
netif_wake_queue(dev);
}

static int greth_rx(struct net_device *dev, int limit)
Expand All @@ -733,20 +730,24 @@ static int greth_rx(struct net_device *dev, int limit)
int pkt_len;
int bad, count;
u32 status, dma_addr;
unsigned long flags;

greth = netdev_priv(dev);

for (count = 0; count < limit; ++count) {

bdp = greth->rx_bd_base + greth->rx_cur;
GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
mb();
status = greth_read_bd(&bdp->stat);
dma_addr = greth_read_bd(&bdp->addr);
bad = 0;

if (unlikely(status & GRETH_BD_EN)) {
break;
}

dma_addr = greth_read_bd(&bdp->addr);
bad = 0;

/* Check status for errors. */
if (unlikely(status & GRETH_RXBD_STATUS)) {
if (status & GRETH_RXBD_ERR_FT) {
Expand Down Expand Up @@ -808,7 +809,9 @@ static int greth_rx(struct net_device *dev, int limit)

dma_sync_single_for_device(greth->dev, dma_addr, MAX_FRAME_SIZE, DMA_FROM_DEVICE);

spin_lock_irqsave(&greth->devlock, flags); /* save from XMIT */
greth_enable_rx(greth);
spin_unlock_irqrestore(&greth->devlock, flags);

greth->rx_cur = NEXT_RX(greth->rx_cur);
}
Expand Down Expand Up @@ -842,13 +845,16 @@ static int greth_rx_gbit(struct net_device *dev, int limit)
int pkt_len;
int bad, count = 0;
u32 status, dma_addr;
unsigned long flags;

greth = netdev_priv(dev);

for (count = 0; count < limit; ++count) {

bdp = greth->rx_bd_base + greth->rx_cur;
skb = greth->rx_skbuff[greth->rx_cur];
GRETH_REGSAVE(greth->regs->status, GRETH_INT_RE | GRETH_INT_RX);
mb();
status = greth_read_bd(&bdp->stat);
bad = 0;

Expand Down Expand Up @@ -936,7 +942,9 @@ static int greth_rx_gbit(struct net_device *dev, int limit)

wmb();
greth_write_bd(&bdp->stat, status);
spin_lock_irqsave(&greth->devlock, flags);
greth_enable_rx(greth);
spin_unlock_irqrestore(&greth->devlock, flags);
greth->rx_cur = NEXT_RX(greth->rx_cur);
}

Expand All @@ -948,15 +956,18 @@ 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);

if (greth->gbit_mac) {
greth_clean_tx_gbit(greth->netdev);
} else {
greth_clean_tx(greth->netdev);
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);
}

restart_poll:
if (greth->gbit_mac) {
work_done += greth_rx_gbit(greth->netdev, budget - work_done);
} else {
Expand All @@ -965,15 +976,29 @@ static int greth_poll(struct napi_struct *napi, int budget)

if (work_done < budget) {

napi_complete(napi);
spin_lock_irqsave(&greth->devlock, flags);

if (greth_pending_packets(greth)) {
napi_reschedule(napi);
goto restart_poll;
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);
}
}

greth_enable_irqs(greth);
return work_done;
}

Expand Down Expand Up @@ -1168,11 +1193,11 @@ static const struct ethtool_ops greth_ethtool_ops = {
};

static struct net_device_ops greth_netdev_ops = {
.ndo_open = greth_open,
.ndo_stop = greth_close,
.ndo_start_xmit = greth_start_xmit,
.ndo_set_mac_address = greth_set_mac_add,
.ndo_validate_addr = eth_validate_addr,
.ndo_open = greth_open,
.ndo_stop = greth_close,
.ndo_start_xmit = greth_start_xmit,
.ndo_set_mac_address = greth_set_mac_add,
.ndo_validate_addr = eth_validate_addr,
};

static inline int wait_for_mdio(struct greth_private *greth)
Expand Down

0 comments on commit ccfe5ae

Please sign in to comment.