summaryrefslogtreecommitdiffstats
path: root/arch/ppc/8xx_io/enet.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/8xx_io/enet.c')
-rw-r--r--arch/ppc/8xx_io/enet.c175
1 files changed, 133 insertions, 42 deletions
diff --git a/arch/ppc/8xx_io/enet.c b/arch/ppc/8xx_io/enet.c
index 126b724be..1c71f473f 100644
--- a/arch/ppc/8xx_io/enet.c
+++ b/arch/ppc/8xx_io/enet.c
@@ -1,5 +1,4 @@
/*
- * $Id: enet.c,v 1.8 1998/11/15 19:58:07 cort Exp $
* Ethernet driver for Motorola MPC8xx.
* Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
*
@@ -22,6 +21,7 @@
* small packets.
*
*/
+#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
@@ -39,7 +39,7 @@
#include <asm/8xx_immap.h>
#include <asm/pgtable.h>
-#include <asm/mbx.h>
+#include <asm/fads.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
#include "commproc.h"
@@ -49,7 +49,7 @@
*
* The MPC8xx CPM performs the Ethernet processing on SCC1. It can use
* an aribtrary number of buffers on byte boundaries, but must have at
- * least two receive buffers to prevent constand overrun conditions.
+ * least two receive buffers to prevent constant overrun conditions.
*
* The buffer descriptors are allocated from the CPM dual port memory
* with the data buffers allocated from host memory, just like all other
@@ -94,6 +94,17 @@
* Port C, 15 - SCC1 Ethernet Tx Enable
* Port C, 11 - SCC1 Ethernet Collision
* Port C, 10 - SCC1 Ethernet Rx Enable
+ *
+ * The RPX-Lite (that I had :-), was the MPC850SAR. It has a control
+ * register to enable Ethernet functions in the 68160, and the Ethernet
+ * was controlled by SCC2. So, the pin I/O was like this:
+ * Port A, 13 - SCC2 Ethernet Rx
+ * Port A, 12 - SCC2 Ethernet Tx
+ * Port A, 6 (CLK2) - Ethernet Tx Clk
+ * Port A, 4 (CLK4) - Ethernet Rx Clk
+ * Port B, 18 (RTS2) - Ethernet Tx Enable
+ * Port C, 8 (CD2) - Ethernet Rx Enable
+ * Port C, 9 (CTS2) - SCC Ethernet Collision
*/
/* The number of Tx and Rx buffers. These are allocated from the page
@@ -149,10 +160,26 @@ static int cpm_enet_close(struct device *dev);
static struct net_device_stats *cpm_enet_get_stats(struct device *dev);
static void set_multicast_list(struct device *dev);
-/* GET THIS FROM THE VPD!!!!
+/* Get this from various configuration locations (depends on board).
*/
/*static ushort my_enet_addr[] = { 0x0800, 0x3e26, 0x1559 };*/
+/* Right now, only the boards with an 860 use SCC1 for the Ethernet.
+ * All others use SCC2. We may need to make this board specific someday.
+ */
+#ifndef CONFIG_MPC860
+/*static ushort my_enet_addr[] = { 0x2700, 0x00ec, 0x1000 };*/
+#define CPM_CR_ENET CPM_CR_CH_SCC2
+#define PROFF_ENET PROFF_SCC2
+#define SCC_ENET 1 /* Index, not number! */
+#define CPMVEC_ENET CPMVEC_SCC2
+#else
+#define CPM_CR_ENET CPM_CR_CH_SCC1
+#define PROFF_ENET PROFF_SCC1
+#define SCC_ENET 0
+#define CPMVEC_ENET CPMVEC_SCC1
+#endif
+
static int
cpm_enet_open(struct device *dev)
{
@@ -178,7 +205,7 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev)
/* Transmitter timeout, serious problems. */
if (dev->tbusy) {
int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 20)
+ if (tickssofar < 200)
return 1;
printk("%s: transmit timed out.\n", dev->name);
cep->stats.tx_errors++;
@@ -186,17 +213,17 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev)
{
int i;
cbd_t *bdp;
- printk(" Ring data dump: cur_tx %x%s cur_rx %x.\n",
+ 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++)
+ 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++)
+ for (i = 0 ; i < RX_RING_SIZE; i++, bdp++)
printk("%04x %04x %08x\n",
bdp->cbd_sc,
bdp->cbd_datlen,
@@ -263,7 +290,7 @@ cpm_enet_start_xmit(struct sk_buff *skb, struct device *dev)
/* 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(skb->data, skb->data + skb->len);
/* 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.
@@ -300,7 +327,7 @@ static void
cpm_enet_interrupt(void *dev_id)
{
struct device *dev = dev_id;
- struct cpm_enet_private *cep;
+ volatile struct cpm_enet_private *cep;
volatile cbd_t *bdp;
ushort int_events;
int must_restart;
@@ -314,6 +341,7 @@ cpm_enet_interrupt(void *dev_id)
/* Get the interrupt events that caused us to be here.
*/
int_events = cep->sccp->scc_scce;
+ cep->sccp->scc_scce = int_events;
must_restart = 0;
/* Handle receive event in its own function.
@@ -329,6 +357,7 @@ cpm_enet_interrupt(void *dev_id)
* I don't know if "normally" implies TXB is set when the buffer
* descriptor is closed.....trial and error :-).
*/
+#if 0
if (int_events & SCCE_ENET_TXE) {
/* Transmission errors.
@@ -359,16 +388,46 @@ cpm_enet_interrupt(void *dev_id)
(BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN))
must_restart = 1;
}
+#endif
/* Transmit OK, or non-fatal error. Update the buffer descriptors.
*/
if (int_events & (SCCE_ENET_TXE | SCCE_ENET_TXB)) {
+#if 1
+ bdp = cep->dirty_tx;
+ while ((bdp->cbd_sc&BD_ENET_TX_READY)==0) {
+ if ((bdp==cep->cur_tx) && (cep->tx_full == 0))
+ break;
+
+ if (bdp->cbd_sc & BD_ENET_TX_HB) /* No heartbeat */
+ cep->stats.tx_heartbeat_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */
+ cep->stats.tx_window_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_RL) /* Retrans limit */
+ cep->stats.tx_aborted_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */
+ cep->stats.tx_fifo_errors++;
+ if (bdp->cbd_sc & BD_ENET_TX_CSL) /* Carrier lost */
+ cep->stats.tx_carrier_errors++;
+
+
+ /* No heartbeat or Lost carrier are not really bad errors.
+ * The others require a restart transmit command.
+ */
+ if (bdp->cbd_sc &
+ (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) {
+ must_restart = 1;
+ cep->stats.tx_errors++;
+ }
+
cep->stats.tx_packets++;
+#else
bdp = cep->dirty_tx;
-#ifndef final_version
+#if 1
if (bdp->cbd_sc & BD_ENET_TX_READY)
printk("HEY! Enet xmit interrupt and TX_READY.\n");
#endif
+#endif
/* Deferred means some collisions occurred during transmit,
* but we eventually sent the packet OK.
*/
@@ -406,9 +465,9 @@ cpm_enet_interrupt(void *dev_id)
}
cep->dirty_tx = (cbd_t *)bdp;
- }
+ }
- if (must_restart) {
+ if (must_restart) {
volatile cpm8xx_t *cp;
/* Some transmit errors cause the transmitter to shut
@@ -419,8 +478,9 @@ cpm_enet_interrupt(void *dev_id)
*/
cp = cpmp;
cp->cp_cpcr =
- mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_RESTART_TX) | CPM_CR_FLG;
+ mk_cr_cmd(CPM_CR_ENET, CPM_CR_RESTART_TX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
+ }
}
/* Check for receive busy, i.e. packets coming but no place to
@@ -432,11 +492,6 @@ cpm_enet_interrupt(void *dev_id)
printk("CPM ENET: BSY can't happen.\n");
}
- /* Write the SCC event register with the events we have handled
- * to clear them. Maybe we should do this sooner?
- */
- cep->sccp->scc_scce = int_events;
-
dev->interrupt = 0;
return;
@@ -576,7 +631,7 @@ static void set_multicast_list(struct device *dev)
int i, j;
cep = (struct cpm_enet_private *)dev->priv;
- /* Get pointer to SCC1 area in parameter RAM.
+ /* Get pointer to SCC area in parameter RAM.
*/
ep = (scc_enet_t *)dev->base_addr;
@@ -627,7 +682,7 @@ static void set_multicast_list(struct device *dev)
/* Ask CPM to run CRC and set bit in
* filter mask.
*/
- cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_SET_GADDR) | CPM_CR_FLG;
+ cpmp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_SET_GADDR) | CPM_CR_FLG;
/* this delay is necessary here -- Cort */
udelay(10);
while (cpmp->cp_cpcr & CPM_CR_FLG);
@@ -636,13 +691,15 @@ static void set_multicast_list(struct device *dev)
}
}
-/* Initialize the CPM Ethernet on SCC1. If EPPC-Bug loaded us, or performed
+/* Initialize the CPM Ethernet on SCC. If EPPC-Bug loaded us, or performed
* some other network I/O, a whole bunch of this has already been set up.
* It is no big deal if we do it again, we just have to disable the
* transmit and receive to make sure we don't catch the CPM with some
* inconsistent control information.
*/
-__initfunc(int cpm_enet_init(void))
+/* until this gets cleared up -- Cort */
+int __init cpm_enet_init() { m8xx_enet_init(); }
+int __init m8xx_enet_init(void)
{
struct device *dev;
struct cpm_enet_private *cep;
@@ -650,6 +707,7 @@ __initfunc(int cpm_enet_init(void))
unsigned char *eap;
unsigned long mem_addr;
pte_t *pte;
+ bd_t *bd;
volatile cbd_t *bdp;
volatile cpm8xx_t *cp;
volatile scc_t *sccp;
@@ -660,6 +718,8 @@ __initfunc(int cpm_enet_init(void))
immap = (immap_t *)IMAP_ADDR; /* and to internal registers */
+ bd = (bd_t *)res;
+
/* Allocate some private information.
*/
cep = (struct cpm_enet_private *)kmalloc(sizeof(*cep), GFP_KERNEL);
@@ -670,13 +730,13 @@ __initfunc(int cpm_enet_init(void))
*/
dev = init_etherdev(0, 0);
- /* Get pointer to SCC1 area in parameter RAM.
+ /* Get pointer to SCC area in parameter RAM.
*/
- ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_SCC1]);
+ ep = (scc_enet_t *)(&cp->cp_dparam[PROFF_ENET]);
/* And another to the SCC register area.
*/
- sccp = (volatile scc_t *)(&cp->cp_scc[0]);
+ sccp = (volatile scc_t *)(&cp->cp_scc[SCC_ENET]);
cep->sccp = (scc_t *)sccp; /* Keep the pointer handy */
/* Disable receive and transmit in case EPPC-Bug started it.
@@ -686,6 +746,9 @@ __initfunc(int cpm_enet_init(void))
/* Cookbook style from the MPC860 manual.....
* Not all of this is necessary if EPPC-Bug has initialized
* the network.
+ * So far we are lucky, all board configurations use the same
+ * pins, or at least the same I/O Port for these functions.....
+ * It can't last though......
*/
/* Configure port A pins for Txd and Rxd.
@@ -706,7 +769,7 @@ __initfunc(int cpm_enet_init(void))
immap->im_ioport.iop_padir &= ~(PA_ENET_TCLK | PA_ENET_RCLK);
/* Configure Serial Interface clock routing.
- * First, clear all SCC1 bits to zero, then set the ones we want.
+ * First, clear all SCC bits to zero, then set the ones we want.
*/
cp->cp_sicr &= ~SICR_ENET_MASK;
cp->cp_sicr |= SICR_ENET_CLKRT;
@@ -731,13 +794,13 @@ __initfunc(int cpm_enet_init(void))
cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;
cep->cur_rx = cep->rx_bd_base;
- /* Issue init Rx BD command for SCC1.
+ /* Issue init Rx BD command for SCC.
* Manual says to perform an Init Rx parameters here. We have
* to perform both Rx and Tx because the SCC may have been
* already running.
* In addition, we have to do it later because we don't yet have
* all of the BD control/status set properly.
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_RX) | CPM_CR_FLG;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_RX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
*/
@@ -781,20 +844,17 @@ __initfunc(int cpm_enet_init(void))
ep->sen_iaddr3 = 0;
ep->sen_iaddr4 = 0;
- /* Set Ethernet station address. This must come from the
- * Vital Product Data (VPD) EEPROM.....as soon as I get the
- * I2C interface working.....
+ /* Set Ethernet station address.
*
- * Since we performed a diskless boot, the Ethernet controller
+ * If we performed a MBX diskless boot, the Ethernet controller
* has been initialized and we copy the address out into our
* own structure.
*/
-#ifdef notdef
- ep->sen_paddrh = my_enet_addr[0];
- ep->sen_paddrm = my_enet_addr[1];
- ep->sen_paddrl = my_enet_addr[2];
-#else
eap = (unsigned char *)&(ep->sen_paddrh);
+#ifndef CONFIG_MBX
+ for (i=5; i>=0; i--)
+ *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i];
+#else
for (i=5; i>=0; i--)
dev->dev_addr[i] = *eap++;
#endif
@@ -854,7 +914,7 @@ __initfunc(int cpm_enet_init(void))
* than the manual describes because we have just now finished
* the BD initialization.
*/
- cp->cp_cpcr = mk_cr_cmd(CPM_CR_CH_SCC1, CPM_CR_INIT_TRX) | CPM_CR_FLG;
+ cp->cp_cpcr = mk_cr_cmd(CPM_CR_ENET, CPM_CR_INIT_TRX) | CPM_CR_FLG;
while (cp->cp_cpcr & CPM_CR_FLG);
cep->skb_cur = cep->skb_dirty = 0;
@@ -869,7 +929,7 @@ __initfunc(int cpm_enet_init(void))
/* Install our interrupt handler.
*/
- cpm_install_handler(CPMVEC_SCC1, cpm_enet_interrupt, dev);
+ cpm_install_handler(CPMVEC_ENET, cpm_enet_interrupt, dev);
/* Set GSMR_H to enable all normal operating modes.
* Set GSMR_L to enable Ethernet to MC68160.
@@ -884,12 +944,42 @@ __initfunc(int cpm_enet_init(void))
/* Set processing mode. Use Ethernet CRC, catch broadcast, and
* start frame search 22 bit times after RENA.
*/
- sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_BRO | SCC_PMSR_NIB22);
+ sccp->scc_pmsr = (SCC_PMSR_ENCRC | SCC_PMSR_NIB22);
/* It is now OK to enable the Ethernet transmitter.
- */
+ * Unfortunately, there are board implementation differences here.
+ */
+#ifdef CONFIG_MBX
immap->im_ioport.iop_pcpar |= PC_ENET_TENA;
immap->im_ioport.iop_pcdir &= ~PC_ENET_TENA;
+#endif
+
+#if defined(CONFIG_RPXLITE) || defined(CONFIG_RPXCLASSIC)
+ cp->cp_pbpar |= PB_ENET_TENA;
+ cp->cp_pbdir |= PB_ENET_TENA;
+
+ /* And while we are here, set the configuration to enable ethernet.
+ */
+ *((volatile uint *)RPX_CSR_ADDR) &= ~BCSR0_ETHLPBK;
+ *((volatile uint *)RPX_CSR_ADDR) |=
+ (BCSR0_ETHEN | BCSR0_COLTESTDIS | BCSR0_FULLDPLXDIS);
+#endif
+
+#ifdef CONFIG_BSEIP
+ cp->cp_pbpar |= PB_ENET_TENA;
+ cp->cp_pbdir |= PB_ENET_TENA;
+
+ /* BSE uses port B and C for PHY control.
+ */
+ cp->cp_pbpar &= ~(PB_BSE_POWERUP | PB_BSE_FDXDIS);
+ cp->cp_pbdir |= (PB_BSE_POWERUP | PB_BSE_FDXDIS);
+ cp->cp_pbdat |= (PB_BSE_POWERUP | PB_BSE_FDXDIS);
+
+ immap->im_ioport.iop_pcpar &= ~PC_BSE_LOOPBACK;
+ immap->im_ioport.iop_pcdir |= PC_BSE_LOOPBACK;
+ immap->im_ioport.iop_pcso &= ~PC_BSE_LOOPBACK;
+ immap->im_ioport.iop_pcdat &= ~PC_BSE_LOOPBACK;
+#endif
dev->base_addr = (unsigned long)ep;
dev->priv = cep;
@@ -913,3 +1003,4 @@ __initfunc(int cpm_enet_init(void))
return 0;
}
+