patch-2.3.99-pre7 linux/arch/ppc/8xx_io/enet.c
Next file: linux/arch/ppc/8xx_io/uart.c
Previous file: linux/arch/ppc/8260_io/uart.c
Back to the patch index
Back to the overall index
- Lines: 383
- Date:
Tue May 2 13:05:39 2000
- Orig file:
v2.3.99-pre6/linux/arch/ppc/8xx_io/enet.c
- Orig date:
Tue Apr 11 15:09:13 2000
diff -u --recursive --new-file v2.3.99-pre6/linux/arch/ppc/8xx_io/enet.c linux/arch/ppc/8xx_io/enet.c
@@ -37,6 +37,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/spinlock.h>
#include <asm/8xx_immap.h>
#include <asm/pgtable.h>
@@ -108,6 +109,10 @@
* Port C, 9 (CTS2) - SCC Ethernet Collision
*/
+/* The transmitter timeout
+ */
+#define TX_TIMEOUT (2*HZ)
+
/* The number of Tx and Rx buffers. These are allocated from the page
* pool. The code may assume these are power of two, so it is best
* to keep them that size.
@@ -135,7 +140,7 @@
* empty and completely full conditions. The empty/ready indicator in
* the buffer descriptor determines the actual condition.
*/
-struct cpm_enet_private {
+struct scc_enet_private {
/* The saved address of a sent-in-place packet/buffer, for skfree(). */
struct sk_buff* tx_skbuff[TX_RING_SIZE];
ushort skb_cur;
@@ -150,17 +155,15 @@
scc_t *sccp;
struct net_device_stats stats;
uint tx_full;
- uint tx_busy;
- unsigned long lock;
- int interrupt;
+ spinlock_t lock;
};
-static int cpm_enet_open(struct net_device *dev);
-static int cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static int cpm_enet_rx(struct net_device *dev);
-static void cpm_enet_interrupt(void *dev_id);
-static int cpm_enet_close(struct net_device *dev);
-static struct net_device_stats *cpm_enet_get_stats(struct net_device *dev);
+static int scc_enet_open(struct net_device *dev);
+static int scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int scc_enet_rx(struct net_device *dev);
+static void scc_enet_interrupt(void *dev_id);
+static int scc_enet_close(struct net_device *dev);
+static struct net_device_stats *scc_enet_get_stats(struct net_device *dev);
static void set_multicast_list(struct net_device *dev);
/* Get this from various configuration locations (depends on board).
@@ -185,7 +188,7 @@
#endif
static int
-cpm_enet_open(struct net_device *dev)
+scc_enet_open(struct net_device *dev)
{
/* I should reset the ring buffers here, but I don't yet know
@@ -197,60 +200,10 @@
}
static int
-cpm_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+scc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv;
+ struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv;
volatile cbd_t *bdp;
- unsigned long flags;
-
- /* Transmitter timeout, serious problems. */
- if (cep->tx_busy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 200)
- return 1;
- printk("%s: transmit timed out.\n", dev->name);
- cep->stats.tx_errors++;
-#ifndef final_version
- {
- int i;
- cbd_t *bdp;
- printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n",
- cep->cur_tx, cep->tx_full ? " (full)" : "",
- cep->cur_rx);
- bdp = cep->tx_bd_base;
- for (i = 0 ; i < TX_RING_SIZE; i++, bdp++)
- printk("%04x %04x %08x\n",
- bdp->cbd_sc,
- bdp->cbd_datlen,
- bdp->cbd_bufaddr);
- bdp = cep->rx_bd_base;
- for (i = 0 ; i < RX_RING_SIZE; i++, bdp++)
- printk("%04x %04x %08x\n",
- bdp->cbd_sc,
- bdp->cbd_datlen,
- bdp->cbd_bufaddr);
- }
-#endif
-
- cep->tx_busy=0;
- dev->trans_start = jiffies;
-
- return 0;
- }
-
- /* Block a timer-based transmit from overlapping. This could better be
- * done with atomic_swap(1, cep->tx_busy), but set_bit() works as well.
- */
- if (test_and_set_bit(0, (void*)&cep->tx_busy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
-
- if (test_and_set_bit(0, (void*)&cep->lock) != 0) {
- printk("%s: tx queue lock!.\n", dev->name);
- /* don't clear cep->tx_busy flag. */
- return 1;
- }
/* Fill in a Tx ring entry */
bdp = cep->cur_tx;
@@ -261,7 +214,6 @@
* This should not happen, since cep->tx_busy should be set.
*/
printk("%s: tx queue full!.\n", dev->name);
- cep->lock = 0;
return 1;
}
#endif
@@ -292,7 +244,10 @@
/* Push the data cache so the CPM does not get stale memory
* data.
*/
- flush_dcache_range(skb->data, skb->data + skb->len);
+ flush_dcache_range((unsigned long)(skb->data),
+ (unsigned long)(skb->data + skb->len));
+
+ spin_lock_irq(&cep->lock);
/* Send it on its way. Tell CPM its ready, interrupt when done,
* its the last BD of the frame, and to put the CRC on the end.
@@ -308,37 +263,61 @@
else
bdp++;
- save_flags(flags);
- cli();
- cep->lock = 0;
if (bdp->cbd_sc & BD_ENET_TX_READY)
- cep->tx_full = 1;
- else
- cep->tx_busy=0;
- restore_flags(flags);
+ netif_stop_queue(dev);
cep->cur_tx = (cbd_t *)bdp;
+ spin_unlock_irq(&cep->lock);
+
return 0;
}
+static void
+scc_enet_timeout(struct net_device *dev)
+{
+ struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv;
+
+ printk("%s: transmit timed out.\n", dev->name);
+ cep->stats.tx_errors++;
+#ifndef final_version
+ {
+ int i;
+ cbd_t *bdp;
+ printk(" Ring data dump: cur_tx %p%s cur_rx %p.\n",
+ cep->cur_tx, cep->tx_full ? " (full)" : "",
+ cep->cur_rx);
+ bdp = cep->tx_bd_base;
+ for (i = 0 ; i < TX_RING_SIZE; i++, bdp++)
+ printk("%04x %04x %08x\n",
+ bdp->cbd_sc,
+ bdp->cbd_datlen,
+ bdp->cbd_bufaddr);
+ bdp = cep->rx_bd_base;
+ for (i = 0 ; i < RX_RING_SIZE; i++, bdp++)
+ printk("%04x %04x %08x\n",
+ bdp->cbd_sc,
+ bdp->cbd_datlen,
+ bdp->cbd_bufaddr);
+ }
+#endif
+ if (!cep->tx_full)
+ netif_wake_queue(dev);
+}
+
/* The interrupt handler.
* This is called from the CPM handler, not the MPC core interrupt.
*/
static void
-cpm_enet_interrupt(void *dev_id)
+scc_enet_interrupt(void *dev_id)
{
struct net_device *dev = dev_id;
- volatile struct cpm_enet_private *cep;
+ volatile struct scc_enet_private *cep;
volatile cbd_t *bdp;
ushort int_events;
int must_restart;
- cep = (struct cpm_enet_private *)dev->priv;
- if (cep->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
- cep->interrupt = 1;
+ cep = (struct scc_enet_private *)dev->priv;
/* Get the interrupt events that caused us to be here.
*/
@@ -349,7 +328,7 @@
/* Handle receive event in its own function.
*/
if (int_events & SCCE_ENET_RXF)
- cpm_enet_rx(dev_id);
+ scc_enet_rx(dev_id);
/* Check for a transmit error. The manual is a little unclear
* about this, so the debug code until I get it figured out. It
@@ -363,6 +342,7 @@
/* Transmit OK, or non-fatal error. Update the buffer descriptors.
*/
if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) {
+ spin_lock(&cep->lock);
bdp = cep->dirty_tx;
while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {
if ((bdp==cep->cur_tx) && (cep->tx_full == 0))
@@ -421,10 +401,9 @@
/* Since we have freed up a buffer, the ring is no longer
* full.
*/
- if (cep->tx_full && cep->tx_busy) {
- cep->tx_full = 0;
- cep->tx_busy = 0;
- netif_wake_queue(dev);
+ if (cep->tx_full) {
+ if (netif_queue_stopped(dev))
+ netif_wake_queue(dev);
}
cep->dirty_tx = (cbd_t *)bdp;
@@ -444,6 +423,7 @@
mk_cr_cmd(CPM_CR_ENET, CPM_CR_RESTART_TX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
}
+ spin_unlock(&cep->lock);
}
/* Check for receive busy, i.e. packets coming but no place to
@@ -455,8 +435,6 @@
printk("CPM ENET: BSY can't happen.\n");
}
- cep->interrupt = 0;
-
return;
}
@@ -466,14 +444,14 @@
* effectively tossing the packet.
*/
static int
-cpm_enet_rx(struct net_device *dev)
+scc_enet_rx(struct net_device *dev)
{
- struct cpm_enet_private *cep;
+ struct scc_enet_private *cep;
volatile cbd_t *bdp;
struct sk_buff *skb;
ushort pkt_len;
- cep = (struct cpm_enet_private *)dev->priv;
+ cep = (struct scc_enet_private *)dev->priv;
/* First, grab all of the stats for the incoming packet.
* These get messed up if we get called due to a busy condition.
@@ -560,7 +538,7 @@
}
static int
-cpm_enet_close(struct net_device *dev)
+scc_enet_close(struct net_device *dev)
{
/* Don't know what to do yet.
*/
@@ -569,9 +547,9 @@
return 0;
}
-static struct net_device_stats *cpm_enet_get_stats(struct net_device *dev)
+static struct net_device_stats *scc_enet_get_stats(struct net_device *dev)
{
- struct cpm_enet_private *cep = (struct cpm_enet_private *)dev->priv;
+ struct scc_enet_private *cep = (struct scc_enet_private *)dev->priv;
return &cep->stats;
}
@@ -588,12 +566,12 @@
static void set_multicast_list(struct net_device *dev)
{
- struct cpm_enet_private *cep;
+ struct scc_enet_private *cep;
struct dev_mc_list *dmi;
u_char *mcptr, *tdptr;
volatile scc_enet_t *ep;
int i, j;
- cep = (struct cpm_enet_private *)dev->priv;
+ cep = (struct scc_enet_private *)dev->priv;
/* Get pointer to SCC area in parameter RAM.
*/
@@ -661,10 +639,10 @@
* transmit and receive to make sure we don't catch the CPM with some
* inconsistent control information.
*/
-int __init cpm_enet_init(void)
+int __init scc_enet_init(void)
{
struct net_device *dev;
- struct cpm_enet_private *cep;
+ struct scc_enet_private *cep;
int i, j;
unsigned char *eap;
unsigned long mem_addr;
@@ -684,9 +662,10 @@
/* Allocate some private information.
*/
- cep = (struct cpm_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
+ cep = (struct scc_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
/*memset(cep, 0, sizeof(*cep));*/
__clear_user(cep,sizeof(*cep));
+ spin_lock_init(&cep->lock);
/* Create an Ethernet device instance.
*/
@@ -858,7 +837,7 @@
*/
pte = find_pte(&init_mm, mem_addr);
pte_val(*pte) |= _PAGE_NO_CACHE;
- flush_tlb_page(current->mm->mmap, mem_addr);
+ flush_tlb_page(init_mm.mmap, mem_addr);
/* Initialize the BD for every fragment in the page.
*/
@@ -894,7 +873,7 @@
/* Install our interrupt handler.
*/
- cpm_install_handler(CPMVEC_ENET, cpm_enet_interrupt, dev);
+ cpm_install_handler(CPMVEC_ENET, scc_enet_interrupt, dev);
/* Set GSMR_H to enable all normal operating modes.
* Set GSMR_L to enable Ethernet to MC68160.
@@ -953,10 +932,12 @@
#endif
/* The CPM Ethernet specific entries in the device structure. */
- dev->open = cpm_enet_open;
- dev->hard_start_xmit = cpm_enet_start_xmit;
- dev->stop = cpm_enet_close;
- dev->get_stats = cpm_enet_get_stats;
+ dev->open = scc_enet_open;
+ dev->hard_start_xmit = scc_enet_start_xmit;
+ dev->tx_timeout = scc_enet_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ dev->stop = scc_enet_close;
+ dev->get_stats = scc_enet_get_stats;
dev->set_multicast_list = set_multicast_list;
/* And last, enable the transmit and receive processing.
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)