X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fnet%2Ffec.c;h=6764281b4531b713c291d0c3e3ce158be8d28ed6;hb=a2f44b27303a5353859d77a3e96a1d3f33f56ab7;hp=2c7008491378fef4cf71050582e6f88fb9f3e3c7;hpb=433e2af4175021d339b067f6e7ee0a4e4c4f7e2d;p=linux-2.6.git diff --git a/drivers/net/fec.c b/drivers/net/fec.c index 2c7008491..6764281b4 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -8,7 +8,7 @@ * describes connections using the internal parallel port I/O, which * is basically all of Port D. * - * Right now, I am very watseful with the buffers. I allocate memory + * Right now, I am very wasteful with the buffers. I allocate memory * pages and then divide them into 2K frame buffers. This way I know I * have buffers large enough to hold one frame within one buffer descriptor. * Once I get this working, I will use 64 or 128 byte CPM buffers, which @@ -18,11 +18,13 @@ * Much better multiple PHY support by Magnus Damm. * Copyright (c) 2000 Ericsson Radio Systems AB. * - * Support for FEC controller of ColdFire/5270/5271/5272/5274/5275/5280/5282. - * Copyrught (c) 2001-2004 Greg Ungerer (gerg@snapgear.com) + * Support for FEC controller of ColdFire processors. + * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com) + * + * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) + * Copyright (c) 2004-2006 Macq Electronique SA. */ -#include #include #include #include @@ -46,7 +48,9 @@ #include #include -#if defined(CONFIG_M527x) || defined(CONFIG_M5272) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \ + defined(CONFIG_M5272) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) || defined(CONFIG_M532x) #include #include #include "fec.h" @@ -71,8 +75,12 @@ static unsigned int fec_hw[] = { #elif defined(CONFIG_M527x) (MCF_MBAR + 0x1000), (MCF_MBAR + 0x1800), -#elif defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M528x) (MCF_MBAR + 0x1000), +#elif defined(CONFIG_M520x) + (MCF_MBAR+0x30000), +#elif defined(CONFIG_M532x) + (MCF_MBAR+0xfc030000), #else &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec), #endif @@ -94,12 +102,14 @@ static unsigned char fec_mac_default[] = { #define FEC_FLASHMAC 0xffe04000 #elif defined(CONFIG_CANCam) #define FEC_FLASHMAC 0xf0020000 +#elif defined (CONFIG_M5272C3) +#define FEC_FLASHMAC (0xffe04000 + 4) +#elif defined(CONFIG_MOD5272) +#define FEC_FLASHMAC 0xffc0406b #else #define FEC_FLASHMAC 0 #endif -unsigned char *fec_flashmac = (unsigned char *) FEC_FLASHMAC; - /* Forward declarations of some structures to support different PHYs */ @@ -133,6 +143,10 @@ typedef struct { #define TX_RING_SIZE 16 /* Must be power of two */ #define TX_RING_MOD_MASK 15 /* for this to work */ +#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) +#error "FEC: descriptor ring size constants too large" +#endif + /* Interrupt events/masks. */ #define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ @@ -154,11 +168,12 @@ typedef struct { /* - * The 5270/5271/5280/5282 RX control register also contains maximum frame + * The 5270/5271/5280/5282/532x RX control register also contains maximum frame * size bits. Other FEC hardware does not, so we need to take that into * account when setting it. */ -#if defined(CONFIG_M527x) || defined(CONFIG_M528x) +#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ + defined(CONFIG_M520x) || defined(CONFIG_M532x) #define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) #else #define OPT_FRAME_SIZE 0 @@ -196,7 +211,7 @@ struct fec_enet_private { uint phy_id_done; uint phy_status; uint phy_speed; - phy_info_t *phy; + phy_info_t const *phy; struct work_struct phy_task; uint sequence_done; @@ -209,13 +224,12 @@ struct fec_enet_private { int link; int old_link; int full_duplex; - unsigned char mac_addr[ETH_ALEN]; }; static int fec_enet_open(struct net_device *dev); static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev); static void fec_enet_mii(struct net_device *dev); -static irqreturn_t fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs); +static irqreturn_t fec_enet_interrupt(int irq, void * dev_id); static void fec_enet_tx(struct net_device *dev); static void fec_enet_rx(struct net_device *dev); static int fec_enet_close(struct net_device *dev); @@ -237,12 +251,12 @@ typedef struct mii_list { } mii_list_t; #define NMII 20 -mii_list_t mii_cmds[NMII]; -mii_list_t *mii_free; -mii_list_t *mii_head; -mii_list_t *mii_tail; +static mii_list_t mii_cmds[NMII]; +static mii_list_t *mii_free; +static mii_list_t *mii_head; +static mii_list_t *mii_tail; -static int mii_queue(struct net_device *dev, int request, +static int mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *)); /* Make MII read/write commands for the FEC. @@ -263,7 +277,7 @@ static int mii_queue(struct net_device *dev, int request, #define MII_REG_SR 1 /* Status Register */ #define MII_REG_PHYIR1 2 /* PHY Identification Register 1 */ #define MII_REG_PHYIR2 3 /* PHY Identification Register 2 */ -#define MII_REG_ANAR 4 /* A-N Advertisement Register */ +#define MII_REG_ANAR 4 /* A-N Advertisement Register */ #define MII_REG_ANLPAR 5 /* A-N Link Partner Ability Register */ #define MII_REG_ANER 6 /* A-N Expansion Register */ #define MII_REG_ANNPTR 7 /* A-N Next Page Transmit Register */ @@ -275,18 +289,18 @@ static int mii_queue(struct net_device *dev, int request, #define PHY_CONF_LOOP 0x0002 /* 1 loopback mode enabled */ #define PHY_CONF_SPMASK 0x00f0 /* mask for speed */ #define PHY_CONF_10HDX 0x0010 /* 10 Mbit half duplex supported */ -#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ +#define PHY_CONF_10FDX 0x0020 /* 10 Mbit full duplex supported */ #define PHY_CONF_100HDX 0x0040 /* 100 Mbit half duplex supported */ -#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ +#define PHY_CONF_100FDX 0x0080 /* 100 Mbit full duplex supported */ #define PHY_STAT_LINK 0x0100 /* 1 up - 0 down */ #define PHY_STAT_FAULT 0x0200 /* 1 remote fault */ #define PHY_STAT_ANC 0x0400 /* 1 auto-negotiation complete */ #define PHY_STAT_SPMASK 0xf000 /* mask for speed */ #define PHY_STAT_10HDX 0x1000 /* 10 Mbit half duplex selected */ -#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ +#define PHY_STAT_10FDX 0x2000 /* 10 Mbit full duplex selected */ #define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */ -#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ +#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */ static int @@ -295,6 +309,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) struct fec_enet_private *fep; volatile fec_t *fecp; volatile cbd_t *bdp; + unsigned short status; fep = netdev_priv(dev); fecp = (volatile fec_t*)dev->base_addr; @@ -307,8 +322,9 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Fill in a Tx ring entry */ bdp = fep->cur_tx; + status = bdp->cbd_sc; #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. * This should not happen, since dev->tbusy should be set. */ @@ -319,7 +335,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Clear all of the status flags. */ - bdp->cbd_sc &= ~BD_ENET_TX_STATS; + status &= ~BD_ENET_TX_STATS; /* Set buffer length and buffer pointer. */ @@ -344,7 +360,7 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) fep->stats.tx_bytes += skb->len; fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; - + /* Push the data cache so the CPM does not get stale memory * data. */ @@ -353,21 +369,22 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev) spin_lock_irq(&fep->lock); - /* Send it on its way. Tell FEC its ready, interrupt when done, - * its the last BD of the frame, and to put the CRC on the end. + /* Send it on its way. Tell FEC it's ready, interrupt when done, + * 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); + bdp->cbd_sc = status; dev->trans_start = jiffies; /* 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 (bdp->cbd_sc & BD_ENET_TX_WRAP) { + if (status & BD_ENET_TX_WRAP) { bdp = fep->tx_bd_base; } else { bdp++; @@ -405,7 +422,7 @@ fec_timeout(struct net_device *dev) bdp = fep->tx_bd_base; printk(" tx: %u buffers\n", TX_RING_SIZE); for (i = 0 ; i < TX_RING_SIZE; i++) { - printk(" %08x: %04x %04x %08x\n", + printk(" %08x: %04x %04x %08x\n", (uint) bdp, bdp->cbd_sc, bdp->cbd_datlen, @@ -425,7 +442,7 @@ fec_timeout(struct net_device *dev) } } #endif - fec_restart(dev, 0); + fec_restart(dev, fep->full_duplex); netif_wake_queue(dev); } @@ -433,7 +450,7 @@ fec_timeout(struct net_device *dev) * This is called from the MPC core interrupt. */ static irqreturn_t -fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) +fec_enet_interrupt(int irq, void * dev_id) { struct net_device *dev = dev_id; volatile fec_t *fecp; @@ -467,7 +484,7 @@ fec_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs) handled = 1; fec_enet_mii(dev); } - + } return IRQ_RETVAL(handled); } @@ -478,58 +495,59 @@ fec_enet_tx(struct net_device *dev) { struct fec_enet_private *fep; volatile cbd_t *bdp; + unsigned short status; struct sk_buff *skb; fep = netdev_priv(dev); spin_lock(&fep->lock); 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; skb = fep->tx_skbuff[fep->skb_dirty]; /* 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_CSL)) { 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++; - if (bdp->cbd_sc & BD_ENET_TX_LC) /* Late collision */ + if (status & BD_ENET_TX_LC) /* Late collision */ 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++; - if (bdp->cbd_sc & BD_ENET_TX_UN) /* Underrun */ + if (status & BD_ENET_TX_UN) /* Underrun */ 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++; } else { fep->stats.tx_packets++; } #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"); #endif /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ - if (bdp->cbd_sc & BD_ENET_TX_DEF) + if (status & BD_ENET_TX_DEF) fep->stats.collisions++; - + /* Free the sk buffer associated with this last transmit. */ dev_kfree_skb_any(skb); fep->tx_skbuff[fep->skb_dirty] = NULL; fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; - + /* 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; else bdp++; - + /* Since we have freed up a buffer, the ring is no longer * full. */ @@ -555,10 +573,15 @@ fec_enet_rx(struct net_device *dev) struct fec_enet_private *fep; volatile fec_t *fecp; volatile cbd_t *bdp; + unsigned short status; struct sk_buff *skb; ushort pkt_len; __u8 *data; +#ifdef CONFIG_M532x + flush_cache_all(); +#endif + fep = netdev_priv(dev); fecp = (volatile fec_t*)dev->base_addr; @@ -567,13 +590,13 @@ fec_enet_rx(struct net_device *dev) */ bdp = fep->cur_rx; -while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { +while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { #ifndef final_version /* Since we have allocated space to hold a complete frame, * 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"); #endif @@ -581,26 +604,26 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { goto rx_processing_done; /* 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)) { - fep->stats.rx_errors++; - if (bdp->cbd_sc & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { + fep->stats.rx_errors++; + if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { /* Frame too long or too short. */ 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++; - if (bdp->cbd_sc & BD_ENET_RX_CR) /* CRC Error */ - fep->stats.rx_crc_errors++; - if (bdp->cbd_sc & BD_ENET_RX_OV) /* FIFO overrun */ + if (status & BD_ENET_RX_CR) /* CRC Error */ 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. * 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. */ - if (bdp->cbd_sc & BD_ENET_RX_CL) { + if (status & BD_ENET_RX_CL) { fep->stats.rx_errors++; fep->stats.rx_frame_errors++; goto rx_processing_done; @@ -626,9 +649,7 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { } else { skb->dev = dev; skb_put(skb,pkt_len-4); /* Make room */ - eth_copy_and_sum(skb, - (unsigned char *)__va(bdp->cbd_bufaddr), - pkt_len-4, 0); + eth_copy_and_sum(skb, data, pkt_len-4, 0); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); } @@ -636,27 +657,28 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { /* Clear the status flags for this buffer. */ - bdp->cbd_sc &= ~BD_ENET_RX_STATS; + status &= ~BD_ENET_RX_STATS; /* 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. */ - if (bdp->cbd_sc & BD_ENET_RX_WRAP) + if (status & BD_ENET_RX_WRAP) bdp = fep->rx_bd_base; else bdp++; - + #if 1 /* Doing this here will keep the FEC running while we process * incoming frames. On a heavily loaded network, we should be * able to keep up at the expense of system resources. */ - fecp->fec_r_des_active = 0x01000000; + fecp->fec_r_des_active = 0; #endif - } /* while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) */ + } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */ fep->cur_rx = (cbd_t *)bdp; #if 0 @@ -667,11 +689,12 @@ while (!(bdp->cbd_sc & BD_ENET_RX_EMPTY)) { * our way back to the interrupt return only to come right back * here. */ - fecp->fec_r_des_active = 0x01000000; + fecp->fec_r_des_active = 0; #endif } +/* called from interrupt context */ static void fec_enet_mii(struct net_device *dev) { @@ -683,10 +706,12 @@ fec_enet_mii(struct net_device *dev) fep = netdev_priv(dev); ep = fep->hwp; mii_reg = ep->fec_mii_data; - + + spin_lock(&fep->lock); + if ((mip = mii_head) == NULL) { printk("MII and no head!\n"); - return; + goto unlock; } if (mip->mii_func != NULL) @@ -698,6 +723,9 @@ fec_enet_mii(struct net_device *dev) if ((mip = mii_head) != NULL) ep->fec_mii_data = mip->mii_regval; + +unlock: + spin_unlock(&fep->lock); } static int @@ -715,8 +743,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi retval = 0; - save_flags(flags); - cli(); + spin_lock_irqsave(&fep->lock,flags); if ((mip = mii_free) != NULL) { mii_free = mip->mii_next; @@ -736,7 +763,7 @@ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_devi retval = 1; } - restore_flags(flags); + spin_unlock_irqrestore(&fep->lock,flags); return(retval); } @@ -757,45 +784,52 @@ static void mii_parse_sr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); + status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC); if (mii_reg & 0x0004) - *s |= PHY_STAT_LINK; + status |= PHY_STAT_LINK; if (mii_reg & 0x0010) - *s |= PHY_STAT_FAULT; + status |= PHY_STAT_FAULT; if (mii_reg & 0x0020) - *s |= PHY_STAT_ANC; + status |= PHY_STAT_ANC; + + *s = status; } static void mii_parse_cr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_CONF_ANE | PHY_CONF_LOOP); + status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP); if (mii_reg & 0x1000) - *s |= PHY_CONF_ANE; + status |= PHY_CONF_ANE; if (mii_reg & 0x4000) - *s |= PHY_CONF_LOOP; + status |= PHY_CONF_LOOP; + *s = status; } static void mii_parse_anar(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_CONF_SPMASK); + status = *s & ~(PHY_CONF_SPMASK); if (mii_reg & 0x0020) - *s |= PHY_CONF_10HDX; + status |= PHY_CONF_10HDX; if (mii_reg & 0x0040) - *s |= PHY_CONF_10FDX; + status |= PHY_CONF_10FDX; if (mii_reg & 0x0080) - *s |= PHY_CONF_100HDX; + status |= PHY_CONF_100HDX; if (mii_reg & 0x00100) - *s |= PHY_CONF_100FDX; + status |= PHY_CONF_100FDX; + *s = status; } /* ------------------------------------------------------------------------- */ @@ -811,37 +845,34 @@ static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK); - + status = *s & ~(PHY_STAT_SPMASK); if (mii_reg & 0x0800) { if (mii_reg & 0x1000) - *s |= PHY_STAT_100FDX; + status |= PHY_STAT_100FDX; else - *s |= PHY_STAT_100HDX; + status |= PHY_STAT_100HDX; } else { if (mii_reg & 0x1000) - *s |= PHY_STAT_10FDX; + status |= PHY_STAT_10FDX; else - *s |= PHY_STAT_10HDX; + status |= PHY_STAT_10HDX; } + *s = status; } -static phy_info_t phy_info_lxt970 = { - 0x07810000, - "LXT970", - - (const phy_cmd_t []) { /* config */ +static phy_cmd_t const phy_cmd_lxt970_config[] = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt970_startup[] = { /* enable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0002), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_lxt970_ack_int[] = { /* read SR and ISR to acknowledge */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT970_ISR), NULL }, @@ -849,13 +880,20 @@ static phy_info_t phy_info_lxt970 = { /* find out the current status */ { mk_mii_read(MII_LXT970_CSR), mii_parse_lxt970_csr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt970_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_LXT970_IER, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_lxt970 = { + .id = 0x07810000, + .name = "LXT970", + .config = phy_cmd_lxt970_config, + .startup = phy_cmd_lxt970_startup, + .ack_int = phy_cmd_lxt970_ack_int, + .shutdown = phy_cmd_lxt970_shutdown }; - + /* ------------------------------------------------------------------------- */ /* The Level one LXT971 is used on some of my custom boards */ @@ -868,7 +906,7 @@ static phy_info_t phy_info_lxt970 = { #define MII_LXT971_LCR 20 /* LED Control Register */ #define MII_LXT971_TCR 30 /* Transmit Control Register */ -/* +/* * I had some nice ideas of running the MDIO faster... * The 971 should support 8MHz and I tried it, but things acted really * weird, so 2.5 MHz ought to be enough for anyone... @@ -878,66 +916,72 @@ static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); + status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); if (mii_reg & 0x0400) { fep->link = 1; - *s |= PHY_STAT_LINK; + status |= PHY_STAT_LINK; } else { fep->link = 0; } if (mii_reg & 0x0080) - *s |= PHY_STAT_ANC; + status |= PHY_STAT_ANC; if (mii_reg & 0x4000) { if (mii_reg & 0x0200) - *s |= PHY_STAT_100FDX; + status |= PHY_STAT_100FDX; else - *s |= PHY_STAT_100HDX; + status |= PHY_STAT_100HDX; } else { if (mii_reg & 0x0200) - *s |= PHY_STAT_10FDX; + status |= PHY_STAT_10FDX; else - *s |= PHY_STAT_10HDX; + status |= PHY_STAT_10HDX; } if (mii_reg & 0x0008) - *s |= PHY_STAT_FAULT; + status |= PHY_STAT_FAULT; + + *s = status; } -static phy_info_t phy_info_lxt971 = { - 0x0001378e, - "LXT971", - - (const phy_cmd_t []) { /* config */ - /* limit to 10MBit because my protorype board +static phy_cmd_t const phy_cmd_lxt971_config[] = { + /* limit to 10MBit because my prototype board * doesn't work with 100. */ { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt971_startup[] = { /* enable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x00f2), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_write(MII_LXT971_LCR, 0xd422), NULL }, /* LED config */ /* Somehow does the 971 tell me that the link is down * the first read after power-up. * read here to get a valid value in ack_int */ - { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_lxt971_ack_int[] = { + /* acknowledge the int before reading status ! */ + { mk_mii_read(MII_LXT971_ISR), NULL }, /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_LXT971_SR2), mii_parse_lxt971_sr2 }, - /* we only need to read ISR to acknowledge */ - { mk_mii_read(MII_LXT971_ISR), NULL }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_lxt971_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_LXT971_IER, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_lxt971 = { + .id = 0x0001378e, + .name = "LXT971", + .config = phy_cmd_lxt971_config, + .startup = phy_cmd_lxt971_startup, + .ack_int = phy_cmd_lxt971_ack_int, + .shutdown = phy_cmd_lxt971_shutdown }; /* ------------------------------------------------------------------------- */ @@ -956,23 +1000,22 @@ static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK); + status = *s & ~(PHY_STAT_SPMASK); switch((mii_reg >> 2) & 7) { - case 1: *s |= PHY_STAT_10HDX; break; - case 2: *s |= PHY_STAT_100HDX; break; - case 5: *s |= PHY_STAT_10FDX; break; - case 6: *s |= PHY_STAT_100FDX; break; - } + case 1: status |= PHY_STAT_10HDX; break; + case 2: status |= PHY_STAT_100HDX; break; + case 5: status |= PHY_STAT_10FDX; break; + case 6: status |= PHY_STAT_100FDX; break; +} + + *s = status; } -static phy_info_t phy_info_qs6612 = { - 0x00181440, - "QS6612", - - (const phy_cmd_t []) { /* config */ - /* The PHY powers up isolated on the RPX, +static phy_cmd_t const phy_cmd_qs6612_config[] = { + /* The PHY powers up isolated on the RPX, * so send a command to allow operation. */ { mk_mii_write(MII_QS6612_PCR, 0x0dc0), NULL }, @@ -981,13 +1024,13 @@ static phy_info_t phy_info_qs6612 = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_qs6612_startup[] = { /* enable interrupts */ { mk_mii_write(MII_QS6612_IMR, 0x003a), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_qs6612_ack_int[] = { /* we need to read ISR, SR and ANER to acknowledge */ { mk_mii_read(MII_QS6612_ISR), NULL }, { mk_mii_read(MII_REG_SR), mii_parse_sr }, @@ -996,11 +1039,18 @@ static phy_info_t phy_info_qs6612 = { /* read pcr to get info */ { mk_mii_read(MII_QS6612_PCR), mii_parse_qs6612_pcr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_qs6612_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_QS6612_IMR, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_qs6612 = { + .id = 0x00181440, + .name = "QS6612", + .config = phy_cmd_qs6612_config, + .startup = phy_cmd_qs6612_startup, + .ack_int = phy_cmd_qs6612_ack_int, + .shutdown = phy_cmd_qs6612_shutdown }; /* ------------------------------------------------------------------------- */ @@ -1020,49 +1070,54 @@ static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); + uint status; - *s &= ~(PHY_STAT_SPMASK | PHY_STAT_ANC); + status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC); if (mii_reg & 0x0080) - *s |= PHY_STAT_ANC; + status |= PHY_STAT_ANC; if (mii_reg & 0x0400) - *s |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); + status |= ((mii_reg & 0x0800) ? PHY_STAT_100FDX : PHY_STAT_100HDX); else - *s |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); + status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX); + + *s = status; } -static phy_info_t phy_info_am79c874 = { - 0x00022561, - "AM79C874", - - (const phy_cmd_t []) { /* config */ - /* limit to 10MBit because my protorype board - * doesn't work with 100. */ +static phy_cmd_t const phy_cmd_am79c874_config[] = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup - enable interrupts */ + }; +static phy_cmd_t const phy_cmd_am79c874_startup[] = { /* enable interrupts */ { mk_mii_write(MII_AM79C874_ICSR, 0xff00), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ - { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_am79c874_ack_int[] = { /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_read(MII_AM79C874_DR), mii_parse_am79c874_dr }, /* we only need to read ISR to acknowledge */ { mk_mii_read(MII_AM79C874_ICSR), NULL }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* shutdown - disable interrupts */ + }; +static phy_cmd_t const phy_cmd_am79c874_shutdown[] = { /* disable interrupts */ { mk_mii_write(MII_AM79C874_ICSR, 0x0000), NULL }, { mk_mii_end, } - }, + }; +static phy_info_t const phy_info_am79c874 = { + .id = 0x00022561, + .name = "AM79C874", + .config = phy_cmd_am79c874_config, + .startup = phy_cmd_am79c874_startup, + .ack_int = phy_cmd_am79c874_ack_int, + .shutdown = phy_cmd_am79c874_shutdown }; + /* ------------------------------------------------------------------------- */ /* Kendin KS8721BL phy */ @@ -1072,53 +1127,117 @@ static phy_info_t phy_info_am79c874 = { #define MII_KS8721BL_ICSR 22 #define MII_KS8721BL_PHYCR 31 -static phy_info_t phy_info_ks8721bl = { - 0x00022161, - "KS8721BL", - - (const phy_cmd_t []) { /* config */ +static phy_cmd_t const phy_cmd_ks8721bl_config[] = { { mk_mii_read(MII_REG_CR), mii_parse_cr }, { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* startup */ + }; +static phy_cmd_t const phy_cmd_ks8721bl_startup[] = { /* enable interrupts */ { mk_mii_write(MII_KS8721BL_ICSR, 0xff00), NULL }, { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ - { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_read(MII_REG_SR), mii_parse_sr }, { mk_mii_end, } - }, - (const phy_cmd_t []) { /* ack_int */ + }; +static phy_cmd_t const phy_cmd_ks8721bl_ack_int[] = { /* find out the current status */ { mk_mii_read(MII_REG_SR), mii_parse_sr }, /* we only need to read ISR to acknowledge */ { mk_mii_read(MII_KS8721BL_ICSR), NULL }, { mk_mii_end, } + }; +static phy_cmd_t const phy_cmd_ks8721bl_shutdown[] = { /* disable interrupts */ + { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL }, + { mk_mii_end, } + }; +static phy_info_t const phy_info_ks8721bl = { + .id = 0x00022161, + .name = "KS8721BL", + .config = phy_cmd_ks8721bl_config, + .startup = phy_cmd_ks8721bl_startup, + .ack_int = phy_cmd_ks8721bl_ack_int, + .shutdown = phy_cmd_ks8721bl_shutdown +}; + +/* ------------------------------------------------------------------------- */ +/* register definitions for the DP83848 */ + +#define MII_DP8384X_PHYSTST 16 /* PHY Status Register */ + +static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) +{ + struct fec_enet_private *fep = dev->priv; + volatile uint *s = &(fep->phy_status); + + *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); + + /* Link up */ + if (mii_reg & 0x0001) { + fep->link = 1; + *s |= PHY_STAT_LINK; + } else + fep->link = 0; + /* Status of link */ + if (mii_reg & 0x0010) /* Autonegotioation complete */ + *s |= PHY_STAT_ANC; + if (mii_reg & 0x0002) { /* 10MBps? */ + if (mii_reg & 0x0004) /* Full Duplex? */ + *s |= PHY_STAT_10FDX; + else + *s |= PHY_STAT_10HDX; + } else { /* 100 Mbps? */ + if (mii_reg & 0x0004) /* Full Duplex? */ + *s |= PHY_STAT_100FDX; + else + *s |= PHY_STAT_100HDX; + } + if (mii_reg & 0x0008) + *s |= PHY_STAT_FAULT; +} + +static phy_info_t phy_info_dp83848= { + 0x020005c9, + "DP83848", + + (const phy_cmd_t []) { /* config */ + { mk_mii_read(MII_REG_CR), mii_parse_cr }, + { mk_mii_read(MII_REG_ANAR), mii_parse_anar }, + { mk_mii_read(MII_DP8384X_PHYSTST), mii_parse_dp8384x_sr2 }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* startup - enable interrupts */ + { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */ + { mk_mii_read(MII_REG_SR), mii_parse_sr }, + { mk_mii_end, } + }, + (const phy_cmd_t []) { /* ack_int - never happens, no interrupt */ + { mk_mii_end, } }, (const phy_cmd_t []) { /* shutdown */ - { mk_mii_write(MII_KS8721BL_ICSR, 0x0000), NULL }, { mk_mii_end, } }, }; /* ------------------------------------------------------------------------- */ -static phy_info_t *phy_info[] = { +static phy_info_t const * const phy_info[] = { &phy_info_lxt970, &phy_info_lxt971, &phy_info_qs6612, &phy_info_am79c874, &phy_info_ks8721bl, + &phy_info_dp83848, NULL }; /* ------------------------------------------------------------------------- */ - +#if !defined(CONFIG_M532x) #ifdef CONFIG_RPXCLASSIC static void mii_link_interrupt(void *dev_id); #else static irqreturn_t -mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs); +mii_link_interrupt(int irq, void * dev_id); +#endif #endif #if defined(CONFIG_M5272) @@ -1129,16 +1248,23 @@ mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs); static void __inline__ fec_request_intrs(struct net_device *dev) { volatile unsigned long *icrp; + static const struct idesc { + char *name; + unsigned short irq; + irq_handler_t handler; + } *idp, id[] = { + { "fec(RX)", 86, fec_enet_interrupt }, + { "fec(TX)", 87, fec_enet_interrupt }, + { "fec(OTHER)", 88, fec_enet_interrupt }, + { "fec(MII)", 66, mii_link_interrupt }, + { NULL }, + }; /* Setup interrupt handlers. */ - if (request_irq(86, fec_enet_interrupt, 0, "fec(RX)", dev) != 0) - printk("FEC: Could not allocate FEC(RC) IRQ(86)!\n"); - if (request_irq(87, fec_enet_interrupt, 0, "fec(TX)", dev) != 0) - printk("FEC: Could not allocate FEC(RC) IRQ(87)!\n"); - if (request_irq(88, fec_enet_interrupt, 0, "fec(OTHER)", dev) != 0) - printk("FEC: Could not allocate FEC(OTHER) IRQ(88)!\n"); - if (request_irq(66, mii_link_interrupt, 0, "fec(MII)", dev) != 0) - printk("FEC: Could not allocate MII IRQ(66)!\n"); + for (idp = id; idp->name; idp++) { + if (request_irq(idp->irq, idp->handler, 0, idp->name, dev) != 0) + printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq); + } /* Unmask interrupt at ColdFire 5272 SIM */ icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3); @@ -1169,17 +1295,16 @@ static void __inline__ fec_get_mac(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile fec_t *fecp; - unsigned char *iap, tmpaddr[6]; - int i; + unsigned char *iap, tmpaddr[ETH_ALEN]; fecp = fep->hwp; - if (fec_flashmac) { + if (FEC_FLASHMAC) { /* * Get MAC address from FLASH. * If it is all 1's or 0's, use the default. */ - iap = fec_flashmac; + iap = (unsigned char *)FEC_FLASHMAC; if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) iap = fec_mac_default; @@ -1192,14 +1317,11 @@ static void __inline__ fec_get_mac(struct net_device *dev) iap = &tmpaddr[0]; } - for (i=0; idev_addr[i] = fep->mac_addr[i] = *iap++; + memcpy(dev->dev_addr, iap, ETH_ALEN); /* Adjust MAC if using default MAC address */ - if (iap == fec_mac_default) { - dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] = - iap[ETH_ALEN-1] + fep->index; - } + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; } static void __inline__ fec_enable_phy_intr(void) @@ -1234,60 +1356,56 @@ static void __inline__ fec_uncache(unsigned long addr) /* ------------------------------------------------------------------------- */ -#elif defined(CONFIG_M527x) || defined(CONFIG_M528x) +#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) /* - * Code specific to Coldfire 5270/5271/5274/5275 and 5280/5282 setups. + * Code specific to Coldfire 5230/5231/5232/5234/5235, + * the 5270/5271/5274/5275 and 5280/5282 setups. */ static void __inline__ fec_request_intrs(struct net_device *dev) { struct fec_enet_private *fep; int b; + static const struct idesc { + char *name; + unsigned short irq; + } *idp, id[] = { + { "fec(TXF)", 23 }, + { "fec(TXB)", 24 }, + { "fec(TXFIFO)", 25 }, + { "fec(TXCR)", 26 }, + { "fec(RXF)", 27 }, + { "fec(RXB)", 28 }, + { "fec(MII)", 29 }, + { "fec(LC)", 30 }, + { "fec(HBERR)", 31 }, + { "fec(GRA)", 32 }, + { "fec(EBERR)", 33 }, + { "fec(BABT)", 34 }, + { "fec(BABR)", 35 }, + { NULL }, + }; fep = netdev_priv(dev); b = (fep->index) ? 128 : 64; /* Setup interrupt handlers. */ - if (request_irq(b+23, fec_enet_interrupt, 0, "fec(TXF)", dev) != 0) - printk("FEC: Could not allocate FEC(TXF) IRQ(%d+23)!\n", b); - if (request_irq(b+24, fec_enet_interrupt, 0, "fec(TXB)", dev) != 0) - printk("FEC: Could not allocate FEC(TXB) IRQ(%d+24)!\n", b); - if (request_irq(b+25, fec_enet_interrupt, 0, "fec(TXFIFO)", dev) != 0) - printk("FEC: Could not allocate FEC(TXFIFO) IRQ(%d+25)!\n", b); - if (request_irq(b+26, fec_enet_interrupt, 0, "fec(TXCR)", dev) != 0) - printk("FEC: Could not allocate FEC(TXCR) IRQ(%d+26)!\n", b); - - if (request_irq(b+27, fec_enet_interrupt, 0, "fec(RXF)", dev) != 0) - printk("FEC: Could not allocate FEC(RXF) IRQ(%d+27)!\n", b); - if (request_irq(b+28, fec_enet_interrupt, 0, "fec(RXB)", dev) != 0) - printk("FEC: Could not allocate FEC(RXB) IRQ(%d+28)!\n", b); - - if (request_irq(b+29, fec_enet_interrupt, 0, "fec(MII)", dev) != 0) - printk("FEC: Could not allocate FEC(MII) IRQ(%d+29)!\n", b); - if (request_irq(b+30, fec_enet_interrupt, 0, "fec(LC)", dev) != 0) - printk("FEC: Could not allocate FEC(LC) IRQ(%d+30)!\n", b); - if (request_irq(b+31, fec_enet_interrupt, 0, "fec(HBERR)", dev) != 0) - printk("FEC: Could not allocate FEC(HBERR) IRQ(%d+31)!\n", b); - if (request_irq(b+32, fec_enet_interrupt, 0, "fec(GRA)", dev) != 0) - printk("FEC: Could not allocate FEC(GRA) IRQ(%d+32)!\n", b); - if (request_irq(b+33, fec_enet_interrupt, 0, "fec(EBERR)", dev) != 0) - printk("FEC: Could not allocate FEC(EBERR) IRQ(%d+33)!\n", b); - if (request_irq(b+34, fec_enet_interrupt, 0, "fec(BABT)", dev) != 0) - printk("FEC: Could not allocate FEC(BABT) IRQ(%d+34)!\n", b); - if (request_irq(b+35, fec_enet_interrupt, 0, "fec(BABR)", dev) != 0) - printk("FEC: Could not allocate FEC(BABR) IRQ(%d+35)!\n", b); + for (idp = id; idp->name; idp++) { + if (request_irq(b+idp->irq, fec_enet_interrupt, 0, idp->name, dev) != 0) + printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); + } /* Unmask interrupts at ColdFire 5280/5282 interrupt controller */ { volatile unsigned char *icrp; volatile unsigned long *imrp; - int i; + int i, ilip; b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0; icrp = (volatile unsigned char *) (MCF_IPSBAR + b + MCFINTC_ICR0); - for (i = 23; (i < 36); i++) - icrp[i] = 0x23; + for (i = 23, ilip = 0x28; (i < 36); i++) + icrp[i] = ilip--; imrp = (volatile unsigned long *) (MCF_IPSBAR + b + MCFINTC_IMRH); @@ -1300,11 +1418,13 @@ static void __inline__ fec_request_intrs(struct net_device *dev) #if defined(CONFIG_M528x) /* Set up gpio outputs for MII lines */ { - volatile unsigned short *gpio_paspar; - - gpio_paspar = (volatile unsigned short *) (MCF_IPSBAR + - 0x100056); - *gpio_paspar = 0x0f00; + volatile u16 *gpio_paspar; + volatile u8 *gpio_pehlpar; + + gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056); + gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058); + *gpio_paspar |= 0x0f00; + *gpio_pehlpar = 0xc0; } #endif } @@ -1331,17 +1451,16 @@ static void __inline__ fec_get_mac(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); volatile fec_t *fecp; - unsigned char *iap, tmpaddr[6]; - int i; + unsigned char *iap, tmpaddr[ETH_ALEN]; fecp = fep->hwp; - if (fec_flashmac) { + if (FEC_FLASHMAC) { /* * Get MAC address from FLASH. * If it is all 1's or 0's, use the default. */ - iap = fec_flashmac; + iap = FEC_FLASHMAC; if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) iap = fec_mac_default; @@ -1354,14 +1473,11 @@ static void __inline__ fec_get_mac(struct net_device *dev) iap = &tmpaddr[0]; } - for (i=0; idev_addr[i] = fep->mac_addr[i] = *iap++; + memcpy(dev->dev_addr, iap, ETH_ALEN); /* Adjust MAC if using default MAC address */ - if (iap == fec_mac_default) { - dev->dev_addr[ETH_ALEN-1] = fep->mac_addr[ETH_ALEN-1] = - iap[ETH_ALEN-1] + fep->index; - } + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; } static void __inline__ fec_enable_phy_intr(void) @@ -1389,10 +1505,291 @@ static void __inline__ fec_uncache(unsigned long addr) /* ------------------------------------------------------------------------- */ +#elif defined(CONFIG_M520x) + +/* + * Code specific to Coldfire 520x + */ +static void __inline__ fec_request_intrs(struct net_device *dev) +{ + struct fec_enet_private *fep; + int b; + static const struct idesc { + char *name; + unsigned short irq; + } *idp, id[] = { + { "fec(TXF)", 23 }, + { "fec(TXB)", 24 }, + { "fec(TXFIFO)", 25 }, + { "fec(TXCR)", 26 }, + { "fec(RXF)", 27 }, + { "fec(RXB)", 28 }, + { "fec(MII)", 29 }, + { "fec(LC)", 30 }, + { "fec(HBERR)", 31 }, + { "fec(GRA)", 32 }, + { "fec(EBERR)", 33 }, + { "fec(BABT)", 34 }, + { "fec(BABR)", 35 }, + { NULL }, + }; + + fep = netdev_priv(dev); + b = 64 + 13; + + /* Setup interrupt handlers. */ + for (idp = id; idp->name; idp++) { + if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0) + printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq); + } + + /* Unmask interrupts at ColdFire interrupt controller */ + { + volatile unsigned char *icrp; + volatile unsigned long *imrp; + + icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 + + MCFINTC_ICR0); + for (b = 36; (b < 49); b++) + icrp[b] = 0x04; + imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + + MCFINTC_IMRH); + *imrp &= ~0x0001FFF0; + } + *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FEC) |= 0xf0; + *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C) |= 0x0f; +} + +static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) +{ + volatile fec_t *fecp; + + fecp = fep->hwp; + fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; + fecp->fec_x_cntrl = 0x00; + + /* + * Set MII speed to 2.5 MHz + * See 5282 manual section 17.5.4.7: MSCR + */ + fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2; + fecp->fec_mii_speed = fep->phy_speed; + + fec_restart(dev, 0); +} + +static void __inline__ fec_get_mac(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + volatile fec_t *fecp; + unsigned char *iap, tmpaddr[ETH_ALEN]; + + fecp = fep->hwp; + + if (FEC_FLASHMAC) { + /* + * Get MAC address from FLASH. + * If it is all 1's or 0's, use the default. + */ + iap = FEC_FLASHMAC; + if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && + (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) + iap = fec_mac_default; + if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && + (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = fec_mac_default; + } else { + *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; + *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + + memcpy(dev->dev_addr, iap, ETH_ALEN); + + /* Adjust MAC if using default MAC address */ + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; +} + +static void __inline__ fec_enable_phy_intr(void) +{ +} + +static void __inline__ fec_disable_phy_intr(void) +{ +} + +static void __inline__ fec_phy_ack_intr(void) +{ +} + +static void __inline__ fec_localhw_setup(void) +{ +} + +static void __inline__ fec_uncache(unsigned long addr) +{ +} + +/* ------------------------------------------------------------------------- */ + +#elif defined(CONFIG_M532x) +/* + * Code specific for M532x + */ +static void __inline__ fec_request_intrs(struct net_device *dev) +{ + struct fec_enet_private *fep; + int b; + static const struct idesc { + char *name; + unsigned short irq; + } *idp, id[] = { + { "fec(TXF)", 36 }, + { "fec(TXB)", 37 }, + { "fec(TXFIFO)", 38 }, + { "fec(TXCR)", 39 }, + { "fec(RXF)", 40 }, + { "fec(RXB)", 41 }, + { "fec(MII)", 42 }, + { "fec(LC)", 43 }, + { "fec(HBERR)", 44 }, + { "fec(GRA)", 45 }, + { "fec(EBERR)", 46 }, + { "fec(BABT)", 47 }, + { "fec(BABR)", 48 }, + { NULL }, + }; + + fep = netdev_priv(dev); + b = (fep->index) ? 128 : 64; + + /* Setup interrupt handlers. */ + for (idp = id; idp->name; idp++) { + if (request_irq(b+idp->irq,fec_enet_interrupt,0,idp->name,dev)!=0) + printk("FEC: Could not allocate %s IRQ(%d)!\n", + idp->name, b+idp->irq); + } + + /* Unmask interrupts */ + MCF_INTC0_ICR36 = 0x2; + MCF_INTC0_ICR37 = 0x2; + MCF_INTC0_ICR38 = 0x2; + MCF_INTC0_ICR39 = 0x2; + MCF_INTC0_ICR40 = 0x2; + MCF_INTC0_ICR41 = 0x2; + MCF_INTC0_ICR42 = 0x2; + MCF_INTC0_ICR43 = 0x2; + MCF_INTC0_ICR44 = 0x2; + MCF_INTC0_ICR45 = 0x2; + MCF_INTC0_ICR46 = 0x2; + MCF_INTC0_ICR47 = 0x2; + MCF_INTC0_ICR48 = 0x2; + + MCF_INTC0_IMRH &= ~( + MCF_INTC_IMRH_INT_MASK36 | + MCF_INTC_IMRH_INT_MASK37 | + MCF_INTC_IMRH_INT_MASK38 | + MCF_INTC_IMRH_INT_MASK39 | + MCF_INTC_IMRH_INT_MASK40 | + MCF_INTC_IMRH_INT_MASK41 | + MCF_INTC_IMRH_INT_MASK42 | + MCF_INTC_IMRH_INT_MASK43 | + MCF_INTC_IMRH_INT_MASK44 | + MCF_INTC_IMRH_INT_MASK45 | + MCF_INTC_IMRH_INT_MASK46 | + MCF_INTC_IMRH_INT_MASK47 | + MCF_INTC_IMRH_INT_MASK48 ); + + /* Set up gpio outputs for MII lines */ + MCF_GPIO_PAR_FECI2C |= (0 | + MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC | + MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO); + MCF_GPIO_PAR_FEC = (0 | + MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC | + MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC); +} + +static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) +{ + volatile fec_t *fecp; + + fecp = fep->hwp; + fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04; + fecp->fec_x_cntrl = 0x00; + + /* + * Set MII speed to 2.5 MHz + */ + fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2; + fecp->fec_mii_speed = fep->phy_speed; + + fec_restart(dev, 0); +} + +static void __inline__ fec_get_mac(struct net_device *dev) +{ + struct fec_enet_private *fep = netdev_priv(dev); + volatile fec_t *fecp; + unsigned char *iap, tmpaddr[ETH_ALEN]; + + fecp = fep->hwp; + + if (FEC_FLASHMAC) { + /* + * Get MAC address from FLASH. + * If it is all 1's or 0's, use the default. + */ + iap = FEC_FLASHMAC; + if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) && + (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0)) + iap = fec_mac_default; + if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) && + (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff)) + iap = fec_mac_default; + } else { + *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low; + *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16); + iap = &tmpaddr[0]; + } + + memcpy(dev->dev_addr, iap, ETH_ALEN); + + /* Adjust MAC if using default MAC address */ + if (iap == fec_mac_default) + dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index; +} + +static void __inline__ fec_enable_phy_intr(void) +{ +} + +static void __inline__ fec_disable_phy_intr(void) +{ +} + +static void __inline__ fec_phy_ack_intr(void) +{ +} + +static void __inline__ fec_localhw_setup(void) +{ +} + +/* + * Do not need to make region uncached on 532x. + */ +static void __inline__ fec_uncache(unsigned long addr) +{ +} + +/* ------------------------------------------------------------------------- */ + + #else /* - * Code sepcific to the MPC860T setup. + * Code specific to the MPC860T setup. */ static void __inline__ fec_request_intrs(struct net_device *dev) { @@ -1424,13 +1821,10 @@ static void __inline__ fec_request_intrs(struct net_device *dev) static void __inline__ fec_get_mac(struct net_device *dev) { - struct fec_enet_private *fep = netdev_priv(dev); - unsigned char *iap, tmpaddr[6]; bd_t *bd; - int i; - iap = bd->bi_enetaddr; bd = (bd_t *)__res; + memcpy(dev->dev_addr, bd->bi_enetaddr, ETH_ALEN); #ifdef CONFIG_RPXCLASSIC /* The Embedded Planet boards have only one MAC address in @@ -1439,14 +1833,8 @@ static void __inline__ fec_get_mac(struct net_device *dev) * the address bits above something that would have (up to * now) been allocated. */ - for (i=0; i<6; i++) - tmpaddr[i] = *iap++; - tmpaddr[3] |= 0x80; - iap = tmpaddr; + dev->dev_adrd[3] |= 0x80; #endif - - for (i=0; i<6; i++) - dev->dev_addr[i] = fep->mac_addr[i] = *iap++; } static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep) @@ -1468,10 +1856,10 @@ static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_priva immap->im_ioport.iop_pddir = 0x1c58; /* Pre rev. D */ else immap->im_ioport.iop_pddir = 0x1fff; /* Rev. D and later */ - + /* Set MII speed to 2.5 MHz */ - fecp->fec_mii_speed = fep->phy_speed = + fecp->fec_mii_speed = fep->phy_speed = ((bd->bi_busfreq * 1000000) / 2500000) & 0x7e; } @@ -1481,7 +1869,7 @@ static void __inline__ fec_enable_phy_intr(void) fecp = fep->hwp; - /* Enable MII command finished interrupt + /* Enable MII command finished interrupt */ fecp->fec_ivec = (FEC_INTERRUPT/2) << 29; } @@ -1556,7 +1944,7 @@ static void mii_display_status(struct net_device *dev) static void mii_display_config(struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); - volatile uint *s = &(fep->phy_status); + uint status = fep->phy_status; /* ** When we get here, phy_task is already removed from @@ -1565,25 +1953,25 @@ static void mii_display_config(struct net_device *dev) fep->mii_phy_task_queued = 0; printk("%s: config: auto-negotiation ", dev->name); - if (*s & PHY_CONF_ANE) + if (status & PHY_CONF_ANE) printk("on"); else printk("off"); - if (*s & PHY_CONF_100FDX) + if (status & PHY_CONF_100FDX) printk(", 100FDX"); - if (*s & PHY_CONF_100HDX) + if (status & PHY_CONF_100HDX) printk(", 100HDX"); - if (*s & PHY_CONF_10FDX) + if (status & PHY_CONF_10FDX) printk(", 10FDX"); - if (*s & PHY_CONF_10HDX) + if (status & PHY_CONF_10HDX) printk(", 10HDX"); - if (!(*s & PHY_CONF_SPMASK)) + if (!(status & PHY_CONF_SPMASK)) printk(", No speed/duplex selected?"); - if (*s & PHY_CONF_LOOP) + if (status & PHY_CONF_LOOP) printk(", loopback enabled"); - + printk(".\n"); fep->sequence_done = 1; @@ -1605,7 +1993,7 @@ static void mii_relink(struct net_device *dev) if (fep->link) { duplex = 0; - if (fep->phy_status + if (fep->phy_status & (PHY_STAT_100FDX | PHY_STAT_10FDX)) duplex = 1; fec_restart(dev, duplex); @@ -1639,7 +2027,7 @@ static void mii_queue_relink(uint mii_reg, struct net_device *dev) schedule_work(&fep->phy_task); } -/* mii_queue_config is called in user context from fec_enet_open */ +/* mii_queue_config is called in interrupt context from fec_enet_mii */ static void mii_queue_config(uint mii_reg, struct net_device *dev) { struct fec_enet_private *fep = netdev_priv(dev); @@ -1652,14 +2040,14 @@ static void mii_queue_config(uint mii_reg, struct net_device *dev) schedule_work(&fep->phy_task); } - - -phy_cmd_t phy_cmd_relink[] = { { mk_mii_read(MII_REG_CR), mii_queue_relink }, - { mk_mii_end, } }; -phy_cmd_t phy_cmd_config[] = { { mk_mii_read(MII_REG_CR), mii_queue_config }, - { mk_mii_end, } }; - - +phy_cmd_t const phy_cmd_relink[] = { + { mk_mii_read(MII_REG_CR), mii_queue_relink }, + { mk_mii_end, } + }; +phy_cmd_t const phy_cmd_config[] = { + { mk_mii_read(MII_REG_CR), mii_queue_config }, + { mk_mii_end, } + }; /* Read remainder of PHY ID. */ @@ -1682,7 +2070,7 @@ mii_discover_phy3(uint mii_reg, struct net_device *dev) printk(" -- %s\n", phy_info[i]->name); else printk(" -- unknown PHY!\n"); - + fep->phy = phy_info[i]; fep->phy_id_done = 1; } @@ -1702,7 +2090,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev) if (fep->phy_addr < 32) { if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) { - + /* Got first part of ID, now get remainder. */ fep->phy_id = phytype << 16; @@ -1729,7 +2117,7 @@ static void mii_link_interrupt(void *dev_id) #else static irqreturn_t -mii_link_interrupt(int irq, void * dev_id, struct pt_regs * regs) +mii_link_interrupt(int irq, void * dev_id) #endif { struct net_device *dev = dev_id; @@ -1765,9 +2153,12 @@ fec_enet_open(struct net_device *dev) mii_do_cmd(dev, fep->phy->config); mii_do_cmd(dev, phy_cmd_config); /* display configuration */ - /* FIXME: use netif_carrier_{on,off} ; this polls - * until link is up which is wrong... could be - * 30 seconds or more we are trapped in here. -jgarzik + /* Poll until the PHY tells us its configuration + * (not link state). + * Request is initiated by mii_do_cmd above, but answer + * comes by interrupt. + * This should take about 25 usec per register at 2.5 MHz, + * and we read approximately 5 registers. */ while(!fep->sequence_done) schedule(); @@ -1836,8 +2227,6 @@ static void set_multicast_list(struct net_device *dev) ep = fep->hwp; if (dev->flags&IFF_PROMISC) { - /* Log any net taps. */ - printk("%s: Promiscuous mode enabled.\n", dev->name); ep->fec_r_cntrl |= 0x0008; } else { @@ -1854,7 +2243,7 @@ static void set_multicast_list(struct net_device *dev) */ ep->fec_hash_table_high = 0; ep->fec_hash_table_low = 0; - + dmi = dev->mc_list; for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) @@ -1863,7 +2252,7 @@ static void set_multicast_list(struct net_device *dev) */ if (!(dmi->dmi_addr[0] & 1)) continue; - + /* calculate crc32 value of mac address */ crc = 0xffffffff; @@ -1882,7 +2271,7 @@ static void set_multicast_list(struct net_device *dev) which point to specific bit in he hash registers */ hash = (crc >> (32 - HASH_BITS)) & 0x3f; - + if (hash > 31) ep->fec_hash_table_high |= 1 << (hash - 32); else @@ -1897,17 +2286,15 @@ static void set_multicast_list(struct net_device *dev) static void fec_set_mac_address(struct net_device *dev) { - struct fec_enet_private *fep; volatile fec_t *fecp; - fep = netdev_priv(dev); - fecp = fep->hwp; + fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp; /* Set station address. */ - fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) | - (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24); - fecp->fec_addr_high = (fep->mac_addr[5] << 16) | - (fep->mac_addr[4] << 24); + fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) | + (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24); + fecp->fec_addr_high = (dev->dev_addr[5] << 16) | + (dev->dev_addr[4] << 24); } @@ -1930,6 +2317,14 @@ int __init fec_enet_init(struct net_device *dev) if (index >= FEC_MAX_PORTS) return -ENXIO; + /* Allocate memory for buffer descriptors. + */ + mem_addr = __get_free_page(GFP_KERNEL); + if (mem_addr == 0) { + printk("FEC: allocate descriptor memory failed?\n"); + return -ENOMEM; + } + /* Create an Ethernet device instance. */ fecp = (volatile fec_t *) fec_hw[index]; @@ -1942,16 +2337,6 @@ int __init fec_enet_init(struct net_device *dev) fecp->fec_ecntrl = 1; udelay(10); - /* Clear and enable interrupts */ - fecp->fec_ievent = 0xffc0; - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | - FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); - fecp->fec_hash_table_high = 0; - fecp->fec_hash_table_low = 0; - fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; - fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0x01000000; - /* Set the Ethernet address. If using multiple Enets on the 8xx, * this needs some work to get unique addresses. * @@ -1960,14 +2345,6 @@ int __init fec_enet_init(struct net_device *dev) */ fec_get_mac(dev); - /* Allocate memory for buffer descriptors. - */ - if (((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t)) > PAGE_SIZE) { - printk("FEC init error. Need more space.\n"); - printk("FEC initialization failed.\n"); - return 1; - } - mem_addr = __get_free_page(GFP_KERNEL); cbd_base = (cbd_t *)mem_addr; /* XXX: missing check for allocation failure */ @@ -2045,6 +2422,12 @@ int __init fec_enet_init(struct net_device *dev) */ fec_request_intrs(dev); + fecp->fec_hash_table_high = 0; + fecp->fec_hash_table_low = 0; + fecp->fec_r_buff_size = PKT_MAXBLR_SIZE; + fecp->fec_ecntrl = 2; + fecp->fec_r_des_active = 0; + dev->base_addr = (unsigned long)fecp; /* The FEC Ethernet specific entries in the device structure. */ @@ -2063,10 +2446,10 @@ int __init fec_enet_init(struct net_device *dev) /* setup MII interface */ fec_set_mii(dev, fep); - printk("%s: FEC ENET Version 0.2, ", dev->name); - for (i=0; i<5; i++) - printk("%02x:", dev->dev_addr[i]); - printk("%02x\n", dev->dev_addr[5]); + /* Clear and enable interrupts */ + fecp->fec_ievent = 0xffc00000; + fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); /* Queue up command to detect the PHY and initialize the * remainder of the interface. @@ -2099,25 +2482,14 @@ fec_restart(struct net_device *dev, int duplex) fecp->fec_ecntrl = 1; udelay(10); - /* Enable interrupts we wish to service. - */ - fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | - FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); - /* Clear any outstanding interrupt. */ - fecp->fec_ievent = 0xffc0; + fecp->fec_ievent = 0xffc00000; fec_enable_phy_intr(); /* Set station address. */ - fecp->fec_addr_low = fep->mac_addr[3] | (fep->mac_addr[2] << 8) | - (fep->mac_addr[1] << 16) | (fep->mac_addr[0] << 24); - fecp->fec_addr_high = (fep->mac_addr[5] << 16) | - (fep->mac_addr[4] << 24); - - for (i=0; idev_addr[i] = fep->mac_addr[i]; + fec_set_mac_address(dev); /* Reset all multicast. */ @@ -2201,7 +2573,12 @@ fec_restart(struct net_device *dev, int duplex) /* And last, enable the transmit and receive processing. */ fecp->fec_ecntrl = 2; - fecp->fec_r_des_active = 0x01000000; + fecp->fec_r_des_active = 0; + + /* Enable interrupts we wish to service. + */ + fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_TXB | + FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII); } static void @@ -2213,9 +2590,16 @@ fec_stop(struct net_device *dev) fep = netdev_priv(dev); fecp = fep->hwp; - fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ - - while(!(fecp->fec_ievent & 0x10000000)); + /* + ** We cannot expect a graceful transmit stop without link !!! + */ + if (fep->link) + { + fecp->fec_x_cntrl = 0x01; /* Graceful transmit stop */ + udelay(10); + if (!(fecp->fec_ievent & FEC_ENET_GRA)) + printk("fec_stop : Graceful transmit stop did not complete !\n"); + } /* Whack a reset. We should wait for this. */ @@ -2234,7 +2618,9 @@ fec_stop(struct net_device *dev) static int __init fec_enet_module_init(void) { struct net_device *dev; - int i, err; + int i, j, err; + + printk("FEC ENET Version 0.2\n"); for (i = 0; (i < FEC_MAX_PORTS); i++) { dev = alloc_etherdev(sizeof(struct fec_enet_private)); @@ -2250,6 +2636,11 @@ static int __init fec_enet_module_init(void) free_netdev(dev); return -EIO; } + + printk("%s: ethernet ", dev->name); + for (j = 0; (j < 5); j++) + printk("%02x:", dev->dev_addr[j]); + printk("%02x\n", dev->dev_addr[5]); } return 0; }