Commit 0e702ab3 authored by Greg Ungerer's avatar Greg Ungerer Committed by Linus Torvalds

[PATCH] m68knommu: FEC driver event/irq fixes

Collection of fixes for the ColdFire FEC ethernet driver:

. reworked event setting so that it occurs after the MII setup.
  roucaries bastien <roucaries.bastien@gmail.com>
. Do not read cbd_sc in memory for each bit we test. Once per buffer is enough.
. Overrun errors must increase `rx_fifo_errors', not `rx_crc_errors'
. No need for a special value to activate rx or tx.  Only write access matters.
. Simplify parameter of eth_copy_and_sum : `data' has already the right value.
. Some spelling fixes.
Signed-off-by: default avatarPhilippe De Muyter <phdm@macqel.be>
Signed-off-by: default avatarGreg Ungerer <gerg@uclinux.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 83901fc1
...@@ -310,6 +310,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -310,6 +310,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
struct fec_enet_private *fep; struct fec_enet_private *fep;
volatile fec_t *fecp; volatile fec_t *fecp;
volatile cbd_t *bdp; volatile cbd_t *bdp;
unsigned short status;
fep = netdev_priv(dev); fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr; fecp = (volatile fec_t*)dev->base_addr;
...@@ -322,8 +323,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -322,8 +323,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Fill in a Tx ring entry */ /* Fill in a Tx ring entry */
bdp = fep->cur_tx; bdp = fep->cur_tx;
status = bdp->cbd_sc;
#ifndef final_version #ifndef final_version
if (bdp->cbd_sc & BD_ENET_TX_READY) { if (status & BD_ENET_TX_READY) {
/* Ooops. All transmit buffers are full. Bail out. /* Ooops. All transmit buffers are full. Bail out.
* This should not happen, since dev->tbusy should be set. * This should not happen, since dev->tbusy should be set.
*/ */
...@@ -334,7 +336,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -334,7 +336,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Clear all of the status flags. /* Clear all of the status flags.
*/ */
bdp->cbd_sc &= ~BD_ENET_TX_STATS; status &= ~BD_ENET_TX_STATS;
/* Set buffer length and buffer pointer. /* Set buffer length and buffer pointer.
*/ */
...@@ -368,21 +370,22 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -368,21 +370,22 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
spin_lock_irq(&fep->lock); spin_lock_irq(&fep->lock);
/* Send it on its way. Tell FEC its ready, interrupt when done, /* Send it on its way. Tell FEC it's ready, interrupt when done,
* its the last BD of the frame, and to put the CRC on the end. * it's the last BD of the frame, and to put the CRC on the end.
*/ */
bdp->cbd_sc |= (BD_ENET_TX_READY | BD_ENET_TX_INTR status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
| BD_ENET_TX_LAST | BD_ENET_TX_TC); | BD_ENET_TX_LAST | BD_ENET_TX_TC);
bdp->cbd_sc = status;
dev->trans_start = jiffies; dev->trans_start = jiffies;
/* Trigger transmission start */ /* Trigger transmission start */
fecp->fec_x_des_active = 0x01000000; fecp->fec_x_des_active = 0;
/* If this was the last BD in the ring, start at the beginning again. /* If this was the last BD in the ring, start at the beginning again.
*/ */
if (bdp->cbd_sc & BD_ENET_TX_WRAP) { if (status & BD_ENET_TX_WRAP) {
bdp = fep->tx_bd_base; bdp = fep->tx_bd_base;
} else { } else {
bdp++; bdp++;
...@@ -493,43 +496,44 @@ fec_enet_tx(struct net_device *dev) ...@@ -493,43 +496,44 @@ fec_enet_tx(struct net_device *dev)
{ {
struct fec_enet_private *fep; struct fec_enet_private *fep;
volatile cbd_t *bdp; volatile cbd_t *bdp;
unsigned short status;
struct sk_buff *skb; struct sk_buff *skb;
fep = netdev_priv(dev); fep = netdev_priv(dev);
spin_lock(&fep->lock); spin_lock(&fep->lock);
bdp = fep->dirty_tx; bdp = fep->dirty_tx;
while ((bdp->cbd_sc&BD_ENET_TX_READY) == 0) { while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
if (bdp == fep->cur_tx && fep->tx_full == 0) break; if (bdp == fep->cur_tx && fep->tx_full == 0) break;
skb = fep->tx_skbuff[fep->skb_dirty]; skb = fep->tx_skbuff[fep->skb_dirty];
/* Check for errors. */ /* Check for errors. */
if (bdp->cbd_sc & (BD_ENET_TX_HB | BD_ENET_TX_LC | if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_RL | BD_ENET_TX_UN |
BD_ENET_TX_CSL)) { BD_ENET_TX_CSL)) {
fep->stats.tx_errors++; fep->stats.tx_errors++;
if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */ if (status & BD_ENET_TX_HB) /* No heartbeat */
fep->stats.tx_heartbeat_errors++; fep->stats.tx_heartbeat_errors++;
if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ if (status & BD_ENET_TX_LC) /* Late collision */
fep->stats.tx_window_errors++; fep->stats.tx_window_errors++;
if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */ if (status & BD_ENET_TX_RL) /* Retrans limit */
fep->stats.tx_aborted_errors++; fep->stats.tx_aborted_errors++;
if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ if (status & BD_ENET_TX_UN) /* Underrun */
fep->stats.tx_fifo_errors++; fep->stats.tx_fifo_errors++;
if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */ if (status & BD_ENET_TX_CSL) /* Carrier lost */
fep->stats.tx_carrier_errors++; fep->stats.tx_carrier_errors++;
} else { } else {
fep->stats.tx_packets++; fep->stats.tx_packets++;
} }
#ifndef final_version #ifndef final_version
if (bdp->cbd_sc & BD_ENET_TX_READY) if (status & BD_ENET_TX_READY)
printk("HEY! Enet xmit interrupt and TX_READY.\n"); printk("HEY! Enet xmit interrupt and TX_READY.\n");
#endif #endif
/* Deferred means some collisions occurred during transmit, /* Deferred means some collisions occurred during transmit,
* but we eventually sent the packet OK. * but we eventually sent the packet OK.
*/ */
if (bdp->cbd_sc & BD_ENET_TX_DEF) if (status & BD_ENET_TX_DEF)
fep->stats.collisions++; fep->stats.collisions++;
/* Free the sk buffer associated with this last transmit. /* Free the sk buffer associated with this last transmit.
...@@ -540,7 +544,7 @@ fec_enet_tx(struct net_device *dev) ...@@ -540,7 +544,7 @@ fec_enet_tx(struct net_device *dev)
/* Update pointer to next buffer descriptor to be transmitted. /* Update pointer to next buffer descriptor to be transmitted.
*/ */
if (bdp->cbd_sc & BD_ENET_TX_WRAP) if (status & BD_ENET_TX_WRAP)
bdp = fep->tx_bd_base; bdp = fep->tx_bd_base;
else else
bdp++; bdp++;
...@@ -570,10 +574,15 @@ fec_enet_rx(struct net_device *dev) ...@@ -570,10 +574,15 @@ fec_enet_rx(struct net_device *dev)
struct fec_enet_private *fep; struct fec_enet_private *fep;
volatile fec_t *fecp; volatile fec_t *fecp;
volatile cbd_t *bdp; volatile cbd_t *bdp;
unsigned short status;
struct sk_buff *skb; struct sk_buff *skb;
ushort pkt_len; ushort pkt_len;
__u8 *data; __u8 *data;
#ifdef CONFIG_M532x
flush_cache_all();
#endif
fep = netdev_priv(dev); fep = netdev_priv(dev);
fecp = (volatile fec_t*)dev->base_addr; fecp = (volatile fec_t*)dev->base_addr;
...@@ -582,13 +591,13 @@ fec_enet_rx(struct net_device *dev) ...@@ -582,13 +591,13 @@ fec_enet_rx(struct net_device *dev)
*/ */
bdp = fep->cur_rx; bdp = fep->cur_rx;
while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
#ifndef final_version #ifndef final_version
/* Since we have allocated space to hold a complete frame, /* Since we have allocated space to hold a complete frame,
* the last indicator should be set. * the last indicator should be set.
*/ */
if ((bdp->cbd_sc & BD_ENET_RX_LAST) == 0) if ((status & BD_ENET_RX_LAST) == 0)
printk("FEC ENET: rcv is not +last\n"); printk("FEC ENET: rcv is not +last\n");
#endif #endif
...@@ -596,26 +605,26 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { ...@@ -596,26 +605,26 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
goto rx_processing_done; goto rx_processing_done;
/* Check for errors. */ /* Check for errors. */
if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
BD_ENET_RX_CR | BD_ENET_RX_OV)) { BD_ENET_RX_CR | BD_ENET_RX_OV)) {
fep->stats.rx_errors++; fep->stats.rx_errors++;
if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
/* Frame too long or too short. */ /* Frame too long or too short. */
fep->stats.rx_length_errors++; fep->stats.rx_length_errors++;
} }
if (bdp->cbd_sc & BD_ENET_RX_NO) /* Frame alignment */ if (status & BD_ENET_RX_NO) /* Frame alignment */
fep->stats.rx_frame_errors++; fep->stats.rx_frame_errors++;
if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ if (status & BD_ENET_RX_CR) /* CRC Error */
fep->stats.rx_crc_errors++;
if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */
fep->stats.rx_crc_errors++; fep->stats.rx_crc_errors++;
if (status & BD_ENET_RX_OV) /* FIFO overrun */
fep->stats.rx_fifo_errors++;
} }
/* Report late collisions as a frame error. /* Report late collisions as a frame error.
* On this error, the BD is closed, but we don't know what we * On this error, the BD is closed, but we don't know what we
* have in the buffer. So, just drop this frame on the floor. * have in the buffer. So, just drop this frame on the floor.
*/ */
if (bdp->cbd_sc & BD_ENET_RX_CL) { if (status & BD_ENET_RX_CL) {
fep->stats.rx_errors++; fep->stats.rx_errors++;
fep->stats.rx_frame_errors++; fep->stats.rx_frame_errors++;
goto rx_processing_done; goto rx_processing_done;
...@@ -641,9 +650,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { ...@@ -641,9 +650,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
} else { } else {
skb->dev = dev; skb->dev = dev;
skb_put(skb,pkt_len-4); /* Make room */ skb_put(skb,pkt_len-4); /* Make room */
eth_copy_and_sum(skb, eth_copy_and_sum(skb, data, pkt_len-4, 0);
(unsigned char *)__va(bdp->cbd_bufaddr),
pkt_len-4, 0);
skb->protocol=eth_type_trans(skb,dev); skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb); netif_rx(skb);
} }
...@@ -651,15 +658,16 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { ...@@ -651,15 +658,16 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
/* Clear the status flags for this buffer. /* Clear the status flags for this buffer.
*/ */
bdp->cbd_sc &= ~BD_ENET_RX_STATS; status &= ~BD_ENET_RX_STATS;
/* Mark the buffer empty. /* Mark the buffer empty.
*/ */
bdp->cbd_sc |= BD_ENET_RX_EMPTY; status |= BD_ENET_RX_EMPTY;
bdp->cbd_sc = status;
/* Update BD pointer to next entry. /* Update BD pointer to next entry.
*/ */
if (bdp->cbd_sc & BD_ENET_RX_WRAP) if (status & BD_ENET_RX_WRAP)
bdp = fep->rx_bd_base; bdp = fep->rx_bd_base;
else else
bdp++; bdp++;
...@@ -669,9 +677,9 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { ...@@ -669,9 +677,9 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
* incoming frames. On a heavily loaded network, we should be * incoming frames. On a heavily loaded network, we should be
* able to keep up at the expense of system resources. * able to keep up at the expense of system resources.
*/ */
fecp->fec_r_des_active = 0x01000000; fecp->fec_r_des_active = 0;
#endif #endif
} /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */ } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */
fep->cur_rx = (cbd_t *)bdp; fep->cur_rx = (cbd_t *)bdp;
#if 0 #if 0
...@@ -682,11 +690,12 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { ...@@ -682,11 +690,12 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) {
* our way back to the interrupt return only to come right back * our way back to the interrupt return only to come right back
* here. * here.
*/ */
fecp->fec_r_des_active = 0x01000000; fecp->fec_r_des_active = 0;
#endif #endif
} }
/* called from interrupt context */
static void static void
fec_enet_mii(struct net_device *dev) fec_enet_mii(struct net_device *dev)
{ {
...@@ -699,9 +708,11 @@ fec_enet_mii(struct net_device *dev) ...@@ -699,9 +708,11 @@ fec_enet_mii(struct net_device *dev)
ep = fep->hwp; ep = fep->hwp;
mii_reg = ep->fec_mii_data; mii_reg = ep->fec_mii_data;
spin_lock(&fep->lock);
if ((mip = mii_head) == NULL) { if ((mip = mii_head) == NULL) {
printk("MII and no head!\n"); printk("MII and no head!\n");
return; goto unlock;
} }
if (mip->mii_func != NULL) if (mip->mii_func != NULL)
...@@ -713,6 +724,9 @@ fec_enet_mii(struct net_device *dev) ...@@ -713,6 +724,9 @@ fec_enet_mii(struct net_device *dev)
if ((mip = mii_head) != NULL) if ((mip = mii_head) != NULL)
ep->fec_mii_data = mip->mii_regval; ep->fec_mii_data = mip->mii_regval;
unlock:
spin_unlock(&fep->lock);
} }
static int static int
...@@ -730,8 +744,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi ...@@ -730,8 +744,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
retval = 0; retval = 0;
save_flags(flags); spin_lock_irqsave(&fep->lock,flags);
cli();
if ((mip = mii_free) != NULL) { if ((mip = mii_free) != NULL) {
mii_free = mip->mii_next; mii_free = mip->mii_next;
...@@ -751,7 +764,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi ...@@ -751,7 +764,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi
retval = 1; retval = 1;
} }
restore_flags(flags); spin_unlock_irqrestore(&fep->lock,flags);
return(retval); return(retval);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment