vserver 1.9.3
[linux-2.6.git] / arch / ppc / 8260_io / fcc_enet.c
index 226214c..41ca124 100644 (file)
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 
-#include <asm/immap_8260.h>
+#include <asm/immap_cpm2.h>
 #include <asm/pgtable.h>
 #include <asm/mpc8260.h>
 #include <asm/irq.h>
 #include <asm/bitops.h>
 #include <asm/uaccess.h>
-#include <asm/cpm_8260.h>
+#include <asm/cpm2.h>
 
 /* The transmitter timeout
  */
@@ -158,12 +158,24 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
 #define PA1_DIRA0      (PA1_RXDAT | PA1_CRS | PA1_COL | PA1_RXER | PA1_RXDV)
 #define PA1_DIRA1      (PA1_TXDAT | PA1_TXEN | PA1_TXER)
 
-/* CLK12 is receive, CLK11 is transmit.  These are board specific.
-*/
+#ifdef CONFIG_SBC82xx
+/* rx is clk9, tx is clk10 */
+#define PC_F1RXCLK     ((uint)0x00000100)
+#define PC_F1TXCLK     ((uint)0x00000200)
+#define CMX1_CLK_ROUTE ((uint)0x25000000)
+#define CMX1_CLK_MASK  ((uint)0xff000000)
+#elif defined(CONFIG_ADS8272)
+#define PC_F1RXCLK     ((uint)0x00000400)
+#define PC_F1TXCLK     ((uint)0x00000200)
+#define CMX1_CLK_ROUTE ((uint)0x36000000)
+#define CMX1_CLK_MASK  ((uint)0xff000000)
+#else /* other boards */
+/* CLK12 is receive, CLK11 is transmit.  These are board specific. */
 #define PC_F1RXCLK     ((uint)0x00000800)
 #define PC_F1TXCLK     ((uint)0x00000400)
 #define CMX1_CLK_ROUTE ((uint)0x3e000000)
 #define CMX1_CLK_MASK  ((uint)0xff000000)
+#endif
 
 /* I/O Pin assignment for FCC2.  I don't yet know the best way to do this,
  * but there is little variation among the choices.
@@ -184,10 +196,17 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
 
 /* CLK13 is receive, CLK14 is transmit.  These are board dependent.
 */
+#ifdef CONFIG_ADS8272
+#define PC_F2RXCLK     ((uint)0x00004000)
+#define PC_F2TXCLK     ((uint)0x00008000)
+#define CMX2_CLK_ROUTE ((uint)0x00370000)
+#define CMX2_CLK_MASK  ((uint)0x00ff0000)
+#else
 #define PC_F2RXCLK     ((uint)0x00001000)
 #define PC_F2TXCLK     ((uint)0x00002000)
 #define CMX2_CLK_ROUTE ((uint)0x00250000)
 #define CMX2_CLK_MASK  ((uint)0x00ff0000)
+#endif
 
 /* I/O Pin assignment for FCC3.  I don't yet know the best way to do this,
  * but there is little variation among the choices.
@@ -219,6 +238,9 @@ static int fcc_enet_set_mac_address(struct net_device *dev, void *addr);
 /* TQM8260 has MDIO and MDCK on PC30 and PC31 respectively */
 #define PC_MDIO                ((uint)0x00000002)
 #define PC_MDCK                ((uint)0x00000001)
+#elif defined(CONFIG_ADS8272)
+#define PC_MDIO                ((uint)0x00002000)
+#define PC_MDCK                ((uint)0x00001000)
 #else
 #define PC_MDIO                ((uint)0x00000004)
 #define PC_MDCK                ((uint)0x00000020)
@@ -246,7 +268,7 @@ static fcc_info_t fcc_ports[] = {
 #ifdef CONFIG_FCC1_ENET
        { 0, CPM_CR_FCC1_SBLOCK, CPM_CR_FCC1_PAGE, PROFF_FCC1, SIU_INT_FCC1,
                (PC_F1RXCLK | PC_F1TXCLK), CMX1_CLK_ROUTE, CMX1_CLK_MASK,
-# if defined(CONFIG_TQM8260)
+# if defined(CONFIG_TQM8260) || defined(CONFIG_ADS8272)
                PC_MDIO, PC_MDCK },
 # else
                0x00000004, 0x00000100 },
@@ -255,7 +277,7 @@ static fcc_info_t fcc_ports[] = {
 #ifdef CONFIG_FCC2_ENET
        { 1, CPM_CR_FCC2_SBLOCK, CPM_CR_FCC2_PAGE, PROFF_FCC2, SIU_INT_FCC2,
                (PC_F2RXCLK | PC_F2TXCLK), CMX2_CLK_ROUTE, CMX2_CLK_MASK,
-# if defined(CONFIG_TQM8260)
+# if defined(CONFIG_TQM8260) || defined(CONFIG_ADS8272)
                PC_MDIO, PC_MDCK },
 # elif defined(CONFIG_EST8260) || defined(CONFIG_ADS8260)
                0x00400000, 0x00200000 },
@@ -266,7 +288,7 @@ static fcc_info_t fcc_ports[] = {
 #ifdef CONFIG_FCC3_ENET
        { 2, CPM_CR_FCC3_SBLOCK, CPM_CR_FCC3_PAGE, PROFF_FCC3, SIU_INT_FCC3,
                (PC_F3RXCLK | PC_F3TXCLK), CMX3_CLK_ROUTE, CMX3_CLK_MASK,
-# if defined(CONFIG_TQM8260)
+# if defined(CONFIG_TQM8260) || defined(CONFIG_ADS8272)
                PC_MDIO, PC_MDCK },
 # else
                0x00000001, 0x00000040 },
@@ -288,6 +310,8 @@ struct fcc_enet_private {
        ushort  skb_cur;
        ushort  skb_dirty;
 
+       atomic_t n_pkts;  /* Number of packets in tx ring */
+
        /* CPM dual port RAM relative addresses.
        */
        cbd_t   *rx_bd_base;            /* Address of Rx and Tx buffers. */
@@ -320,12 +344,12 @@ struct fcc_enet_private {
 };
 
 static void init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,
-       volatile immap_t *immap);
+       volatile cpm2_map_t *immap);
 static void init_fcc_startup(fcc_info_t *fip, struct net_device *dev);
-static void init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io,
-       volatile immap_t *immap);
+static void init_fcc_ioports(fcc_info_t *fip, volatile iop_cpm2_t *io,
+       volatile cpm2_map_t *immap);
 static void init_fcc_param(fcc_info_t *fip, struct net_device *dev,
-       volatile immap_t *immap);
+       volatile cpm2_map_t *immap);
 
 #ifdef CONFIG_USE_MDIO
 static int     mii_queue(struct net_device *dev, int request, void (*func)(uint, struct net_device *));
@@ -347,6 +371,7 @@ fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct fcc_enet_private *cep = (struct fcc_enet_private *)dev->priv;
        volatile cbd_t  *bdp;
+       int idx;
 
        if (!cep->link) {
                /* Link is down or autonegotiation is in progress. */
@@ -379,13 +404,24 @@ fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        bdp->cbd_datlen = skb->len;
        bdp->cbd_bufaddr = __pa(skb->data);
 
+       spin_lock_irq(&cep->lock);
+
        /* Save skb pointer. */
-       cep->tx_skbuff[cep->skb_cur] = skb;
+       idx = cep->skb_cur & TX_RING_MOD_MASK;
+       if (cep->tx_skbuff[idx]) {
+               /* This should never happen (any more).
+                  Leave the sanity check in for now... */
+               printk(KERN_ERR "EEP. cep->tx_skbuff[%d] is %p not NULL in %s\n", 
+                      idx, cep->tx_skbuff[idx], __func__);
+               printk(KERN_ERR "Expect to lose %d bytes of sock space", 
+                      cep->tx_skbuff[idx]->truesize);
+       }
+       cep->tx_skbuff[idx] = skb;
 
        cep->stats.tx_bytes += skb->len;
-       cep->skb_cur = (cep->skb_cur+1) & TX_RING_MOD_MASK;
+       cep->skb_cur++;
 
-       spin_lock_irq(&cep->lock);
+       atomic_inc(&cep->n_pkts);
 
        /* 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.
@@ -404,9 +440,13 @@ fcc_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        else
                bdp++;
 
-       if (bdp->cbd_sc & BD_ENET_TX_READY) {
-               netif_stop_queue(dev);
+
+       /* If the tx_ring is full, stop the queue */
+       if (atomic_read(&cep->n_pkts) >= (TX_RING_SIZE-1)) {
+         if (!netif_queue_stopped(dev)) {
+               netif_stop_queue(dev);    
                cep->tx_full = 1;
+         }
        }
 
        cep->cur_tx = (cbd_t *)bdp;
@@ -460,6 +500,7 @@ fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
        volatile cbd_t  *bdp;
        ushort  int_events;
        int     must_restart;
+       int idx;
 
        cep = (struct fcc_enet_private *)dev->priv;
 
@@ -522,8 +563,12 @@ fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
                        cep->stats.collisions++;
 
                /* Free the sk buffer associated with this last transmit. */
-               dev_kfree_skb_irq(cep->tx_skbuff[cep->skb_dirty]);
-               cep->skb_dirty = (cep->skb_dirty + 1) & TX_RING_MOD_MASK;
+               idx = cep->skb_dirty & TX_RING_MOD_MASK;
+               dev_kfree_skb_irq(cep->tx_skbuff[idx]);
+               cep->tx_skbuff[idx] = NULL;
+               cep->skb_dirty++;
+
+               atomic_dec(&cep->n_pkts);
 
                /* Update pointer to next buffer descriptor to be transmitted. */
                if (bdp->cbd_sc & BD_ENET_TX_WRAP)
@@ -554,7 +599,7 @@ fcc_enet_interrupt(int irq, void * dev_id, struct pt_regs * regs)
            }
 
            if (must_restart) {
-               volatile cpm8260_t *cp;
+               volatile cpm_cpm2_t *cp;
 
                /* Some transmit errors cause the transmitter to shut
                 * down.  We now issue a restart transmit.  Since the
@@ -1020,6 +1065,75 @@ static phy_info_t phy_info_qs6612 = {
 #endif /* CONFIG_FEC_QS6612 */
 
 
+/* ------------------------------------------------------------------------- */
+/* The Davicom DM9131 is used on the HYMOD board                            */
+
+#ifdef CONFIG_FCC_DM9131
+
+/* register definitions */
+
+#define MII_DM9131_ACR         16      /* Aux. Config Register         */
+#define MII_DM9131_ACSR                17      /* Aux. Config/Status Register  */
+#define MII_DM9131_10TCSR      18      /* 10BaseT Config/Status Reg.   */
+#define MII_DM9131_INTR                21      /* Interrupt Register           */
+#define MII_DM9131_RECR                22      /* Receive Error Counter Reg.   */
+#define MII_DM9131_DISCR       23      /* Disconnect Counter Register  */
+
+static void mii_parse_dm9131_acsr(uint mii_reg, struct net_device *dev)
+{
+       volatile struct fcc_enet_private *fep = dev->priv;
+       uint s = fep->phy_status;
+
+       s &= ~(PHY_STAT_SPMASK);
+
+       switch ((mii_reg >> 12) & 0xf) {
+       case 1: s |= PHY_STAT_10HDX;  break;
+       case 2: s |= PHY_STAT_10FDX;  break;
+       case 4: s |= PHY_STAT_100HDX; break;
+       case 8: s |= PHY_STAT_100FDX; break;
+       }
+
+       fep->phy_status = s;
+}
+
+static phy_info_t phy_info_dm9131 = {
+       0x00181b80,
+       "DM9131",
+
+       (const phy_cmd_t []) {  /* config */
+               /* parse cr and anar to get some info */
+               { 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 */
+               { mk_mii_write(MII_DM9131_INTR, 0x0002), NULL },
+               { mk_mii_write(MII_REG_CR, 0x1200), NULL }, /* autonegotiate */
+               { mk_mii_end, }
+       },
+       (const phy_cmd_t []) { /* ack_int */
+
+               /* we need to read INTR, SR and ANER to acknowledge */
+
+               { mk_mii_read(MII_DM9131_INTR), NULL },
+               { mk_mii_read(MII_REG_SR), mii_parse_sr },
+               { mk_mii_read(MII_REG_ANER), NULL },
+
+               /* read acsr to get info */
+
+               { mk_mii_read(MII_DM9131_ACSR), mii_parse_dm9131_acsr },
+               { mk_mii_end, }
+       },
+       (const phy_cmd_t []) {  /* shutdown - disable interrupts */
+               { mk_mii_write(MII_DM9131_INTR, 0x0f00), NULL },
+               { mk_mii_end, }
+       },
+};
+
+
+#endif /* CONFIG_FEC_DM9131 */
+
+
 static phy_info_t *phy_info[] = {
 
 #ifdef CONFIG_FCC_LXT970
@@ -1032,7 +1146,11 @@ static phy_info_t *phy_info[] = {
 
 #ifdef CONFIG_FCC_QS6612
        &phy_info_qs6612,
-#endif /* CONFIG_FEC_LXT971 */
+#endif /* CONFIG_FEC_QS6612 */
+
+#ifdef CONFIG_FCC_DM9131
+       &phy_info_dm9131,
+#endif /* CONFIG_FEC_DM9131 */
 
        NULL
 };
@@ -1329,10 +1447,10 @@ static int __init fec_enet_init(void)
        struct fcc_enet_private *cep;
        fcc_info_t      *fip;
        int     i, np, err;
-       volatile        immap_t         *immap;
-       volatile        iop8260_t       *io;
+       volatile        cpm2_map_t              *immap;
+       volatile        iop_cpm2_t      *io;
 
-       immap = (immap_t *)IMAP_ADDR;   /* and to internal registers */
+       immap = (cpm2_map_t *)CPM_MAP_ADDR;     /* and to internal registers */
        io = &immap->im_ioport;
 
        np = sizeof(fcc_ports) / sizeof(fcc_info_t);
@@ -1399,7 +1517,7 @@ module_init(fec_enet_init);
 */
 static void __init
 init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,
-                                               volatile immap_t *immap)
+                                               volatile cpm2_map_t *immap)
 {
        volatile        fcc_enet_t      *ep;
        volatile        fcc_t           *fccp;
@@ -1422,8 +1540,8 @@ init_fcc_shutdown(fcc_info_t *fip, struct fcc_enet_private *cep,
 /* Initialize the I/O pins for the FCC Ethernet.
 */
 static void __init
-init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io,
-                                               volatile immap_t *immap)
+init_fcc_ioports(fcc_info_t *fip, volatile iop_cpm2_t *io,
+                                               volatile cpm2_map_t *immap)
 {
 
        /* FCC1 pins are on port A/C.  FCC2/3 are port B/C.
@@ -1481,7 +1599,7 @@ init_fcc_ioports(fcc_info_t *fip, volatile iop8260_t *io,
 
 static void __init
 init_fcc_param(fcc_info_t *fip, struct net_device *dev,
-                                               volatile immap_t *immap)
+                                               volatile cpm2_map_t *immap)
 {
        unsigned char   *eap;
        unsigned long   mem_addr;
@@ -1490,7 +1608,7 @@ init_fcc_param(fcc_info_t *fip, struct net_device *dev,
        struct          fcc_enet_private *cep;
        volatile        fcc_enet_t      *ep;
        volatile        cbd_t           *bdp;
-       volatile        cpm8260_t       *cp;
+       volatile        cpm_cpm2_t      *cp;
 
        cep = (struct fcc_enet_private *)(dev->priv);
        ep = cep->ep;
@@ -1503,28 +1621,15 @@ init_fcc_param(fcc_info_t *fip, struct net_device *dev,
         */
        memset((char *)ep, 0, sizeof(fcc_enet_t));
 
-       /* Allocate space for the buffer descriptors in the DP ram.
-        * These are relative offsets in the DP ram address space.
+       /* Allocate space for the buffer descriptors from regular memory.
         * Initialize base addresses for the buffer descriptors.
         */
-#if 0
-       /* I really want to do this, but for some reason it doesn't
-        * work with the data cache enabled, so I allocate from the
-        * main memory instead.
-        */
-       i = m8260_cpm_dpalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
-       ep->fen_genfcc.fcc_rbase = (uint)&immap->im_dprambase[i];
-       cep->rx_bd_base = (cbd_t *)&immap->im_dprambase[i];
-
-       i = m8260_cpm_dpalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
-       ep->fen_genfcc.fcc_tbase = (uint)&immap->im_dprambase[i];
-       cep->tx_bd_base = (cbd_t *)&immap->im_dprambase[i];
-#else
-       cep->rx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * RX_RING_SIZE, 8);
+       cep->rx_bd_base = (cbd_t *)kmalloc(sizeof(cbd_t) * RX_RING_SIZE,
+                       GFP_KERNEL | GFP_DMA);
        ep->fen_genfcc.fcc_rbase = __pa(cep->rx_bd_base);
-       cep->tx_bd_base = (cbd_t *)m8260_cpm_hostalloc(sizeof(cbd_t) * TX_RING_SIZE, 8);
+       cep->tx_bd_base = (cbd_t *)kmalloc(sizeof(cbd_t) * TX_RING_SIZE,
+                       GFP_KERNEL | GFP_DMA);
        ep->fen_genfcc.fcc_tbase = __pa(cep->tx_bd_base);
-#endif
 
        cep->dirty_tx = cep->cur_tx = cep->tx_bd_base;
        cep->cur_rx = cep->rx_bd_base;
@@ -1594,11 +1699,21 @@ init_fcc_param(fcc_info_t *fip, struct net_device *dev,
         */
        eap = (unsigned char *)&(ep->fen_paddrh);
        for (i=5; i>=0; i--) {
+#ifdef CONFIG_SBC82xx
+               if (i == 5) {
+                       /* bd->bi_enetaddr holds the SCC0 address; the FCC
+                          devices count up from there */
+                       dev->dev_addr[i] = bd->bi_enetaddr[i] & ~3;
+                       dev->dev_addr[i] += 1 + fip->fc_fccnum;
+                       *eap++ = dev->dev_addr[i];
+               }
+#else
                if (i == 3) {
                        dev->dev_addr[i] = bd->bi_enetaddr[i];
                        dev->dev_addr[i] |= (1 << (7 - fip->fc_fccnum));
                        *eap++ = dev->dev_addr[i];
                }
+#endif
                else {
                        *eap++ = dev->dev_addr[i] = bd->bi_enetaddr[i];
                }
@@ -1683,6 +1798,7 @@ init_fcc_param(fcc_info_t *fip, struct net_device *dev,
        while (cp->cp_cpcr & CPM_CR_FLG);
 
        cep->skb_cur = cep->skb_dirty = 0;
+       atomic_set(&cep->n_pkts, 0);
 }
 
 /* Let 'er rip.
@@ -1730,11 +1846,11 @@ init_fcc_startup(fcc_info_t *fip, struct net_device *dev)
         */
        fccp->fcc_fpsmr = FCC_PSMR_ENCRC;
 
-#ifdef CONFIG_ADS8260
+#ifdef CONFIG_PQ2ADS
        /* Enable the PHY.
        */
-       ads_csr_addr[1] |= BCSR1_FETH_RST;      /* Remove reset */
-       ads_csr_addr[1] &= ~BCSR1_FETHIEN;      /* Enable */
+        *(volatile uint *)(BCSR_ADDR + 4) &= ~BCSR1_FETHIEN;
+        *(volatile uint *)(BCSR_ADDR + 4) |=  BCSR1_FETH_RST;
 #endif
 
 #if defined(CONFIG_USE_MDIO) || defined(CONFIG_TQM8260)
@@ -1774,10 +1890,10 @@ mii_send_receive(fcc_info_t *fip, uint cmd)
 {
        uint            retval;
        int             read_op, i, off;
-       volatile        immap_t         *immap;
-       volatile        iop8260_t       *io;
+       volatile        cpm2_map_t              *immap;
+       volatile        iop_cpm2_t      *io;
 
-       immap = (immap_t *)IMAP_ADDR;
+       immap = (cpm2_map_t *)CPM_MAP_ADDR;
        io = &immap->im_ioport;
 
        io->iop_pdirc |= (fip->fc_mdio | fip->fc_mdck);
@@ -1870,9 +1986,9 @@ fcc_restart(struct net_device *dev, int duplex)
        fccp = fcp->fccp;
 
        if (duplex)
-               fccp->fcc_fpsmr |= FCC_PSMR_FDE;
+               fccp->fcc_fpsmr |= FCC_PSMR_FDE | FCC_PSMR_LPB;
        else
-               fccp->fcc_fpsmr &= ~FCC_PSMR_FDE;
+               fccp->fcc_fpsmr &= ~(FCC_PSMR_FDE | FCC_PSMR_LPB);
 
        /* Enable transmit/receive */
        fccp->fcc_gfmr |= FCC_GFMR_ENR | FCC_GFMR_ENT;