aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/ibm_emac
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/net/ibm_emac
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/net/ibm_emac')
-rw-r--r--drivers/net/ibm_emac/Makefile12
-rw-r--r--drivers/net/ibm_emac/ibm_emac.h267
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.c2012
-rw-r--r--drivers/net/ibm_emac/ibm_emac_core.h146
-rw-r--r--drivers/net/ibm_emac/ibm_emac_debug.c224
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.c463
-rw-r--r--drivers/net/ibm_emac/ibm_emac_mal.h131
-rw-r--r--drivers/net/ibm_emac/ibm_emac_phy.c298
-rw-r--r--drivers/net/ibm_emac/ibm_emac_phy.h137
-rw-r--r--drivers/net/ibm_emac/ibm_emac_rgmii.h65
-rw-r--r--drivers/net/ibm_emac/ibm_emac_tah.h48
-rw-r--r--drivers/net/ibm_emac/ibm_emac_zmii.h93
12 files changed, 3896 insertions, 0 deletions
diff --git a/drivers/net/ibm_emac/Makefile b/drivers/net/ibm_emac/Makefile
new file mode 100644
index 00000000000..7f583a333c2
--- /dev/null
+++ b/drivers/net/ibm_emac/Makefile
@@ -0,0 +1,12 @@
+#
+# Makefile for the IBM PPC4xx EMAC controllers
+#
+
+obj-$(CONFIG_IBM_EMAC) += ibm_emac.o
+
+ibm_emac-objs := ibm_emac_mal.o ibm_emac_core.o ibm_emac_phy.o
+
+# Only need this if you want to see additional debug messages
+ifeq ($(CONFIG_IBM_EMAC_ERRMSG), y)
+ibm_emac-objs += ibm_emac_debug.o
+endif
diff --git a/drivers/net/ibm_emac/ibm_emac.h b/drivers/net/ibm_emac/ibm_emac.h
new file mode 100644
index 00000000000..15d5a0e8286
--- /dev/null
+++ b/drivers/net/ibm_emac/ibm_emac.h
@@ -0,0 +1,267 @@
+/*
+ * ibm_emac.h
+ *
+ *
+ * Armin Kuster akuster@mvista.com
+ * June, 2002
+ *
+ * Copyright 2002 MontaVista Softare Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#ifndef _IBM_EMAC_H_
+#define _IBM_EMAC_H_
+/* General defines needed for the driver */
+
+/* Emac */
+typedef struct emac_regs {
+ u32 em0mr0;
+ u32 em0mr1;
+ u32 em0tmr0;
+ u32 em0tmr1;
+ u32 em0rmr;
+ u32 em0isr;
+ u32 em0iser;
+ u32 em0iahr;
+ u32 em0ialr;
+ u32 em0vtpid;
+ u32 em0vtci;
+ u32 em0ptr;
+ u32 em0iaht1;
+ u32 em0iaht2;
+ u32 em0iaht3;
+ u32 em0iaht4;
+ u32 em0gaht1;
+ u32 em0gaht2;
+ u32 em0gaht3;
+ u32 em0gaht4;
+ u32 em0lsah;
+ u32 em0lsal;
+ u32 em0ipgvr;
+ u32 em0stacr;
+ u32 em0trtr;
+ u32 em0rwmr;
+} emac_t;
+
+/* MODE REG 0 */
+#define EMAC_M0_RXI 0x80000000
+#define EMAC_M0_TXI 0x40000000
+#define EMAC_M0_SRST 0x20000000
+#define EMAC_M0_TXE 0x10000000
+#define EMAC_M0_RXE 0x08000000
+#define EMAC_M0_WKE 0x04000000
+
+/* MODE Reg 1 */
+#define EMAC_M1_FDE 0x80000000
+#define EMAC_M1_ILE 0x40000000
+#define EMAC_M1_VLE 0x20000000
+#define EMAC_M1_EIFC 0x10000000
+#define EMAC_M1_APP 0x08000000
+#define EMAC_M1_AEMI 0x02000000
+#define EMAC_M1_IST 0x01000000
+#define EMAC_M1_MF_1000GPCS 0x00c00000 /* Internal GPCS */
+#define EMAC_M1_MF_1000MBPS 0x00800000 /* External GPCS */
+#define EMAC_M1_MF_100MBPS 0x00400000
+#define EMAC_M1_RFS_16K 0x00280000 /* 000 for 512 byte */
+#define EMAC_M1_TR 0x00008000
+#ifdef CONFIG_IBM_EMAC4
+#define EMAC_M1_RFS_8K 0x00200000
+#define EMAC_M1_RFS_4K 0x00180000
+#define EMAC_M1_RFS_2K 0x00100000
+#define EMAC_M1_RFS_1K 0x00080000
+#define EMAC_M1_TX_FIFO_16K 0x00050000 /* 0's for 512 byte */
+#define EMAC_M1_TX_FIFO_8K 0x00040000
+#define EMAC_M1_TX_FIFO_4K 0x00030000
+#define EMAC_M1_TX_FIFO_2K 0x00020000
+#define EMAC_M1_TX_FIFO_1K 0x00010000
+#define EMAC_M1_TX_TR 0x00008000
+#define EMAC_M1_TX_MWSW 0x00001000 /* 0 wait for status */
+#define EMAC_M1_JUMBO_ENABLE 0x00000800 /* Upt to 9Kr status */
+#define EMAC_M1_OPB_CLK_66 0x00000008 /* 66Mhz */
+#define EMAC_M1_OPB_CLK_83 0x00000010 /* 83Mhz */
+#define EMAC_M1_OPB_CLK_100 0x00000018 /* 100Mhz */
+#define EMAC_M1_OPB_CLK_100P 0x00000020 /* 100Mhz+ */
+#else /* CONFIG_IBM_EMAC4 */
+#define EMAC_M1_RFS_4K 0x00300000 /* ~4k for 512 byte */
+#define EMAC_M1_RFS_2K 0x00200000
+#define EMAC_M1_RFS_1K 0x00100000
+#define EMAC_M1_TX_FIFO_2K 0x00080000 /* 0's for 512 byte */
+#define EMAC_M1_TX_FIFO_1K 0x00040000
+#define EMAC_M1_TR0_DEPEND 0x00010000 /* 0'x for single packet */
+#define EMAC_M1_TR1_DEPEND 0x00004000
+#define EMAC_M1_TR1_MULTI 0x00002000
+#define EMAC_M1_JUMBO_ENABLE 0x00001000
+#endif /* CONFIG_IBM_EMAC4 */
+#define EMAC_M1_BASE (EMAC_M1_TX_FIFO_2K | \
+ EMAC_M1_APP | \
+ EMAC_M1_TR | EMAC_M1_VLE)
+
+/* Transmit Mode Register 0 */
+#define EMAC_TMR0_GNP0 0x80000000
+#define EMAC_TMR0_GNP1 0x40000000
+#define EMAC_TMR0_GNPD 0x20000000
+#define EMAC_TMR0_FC 0x10000000
+#define EMAC_TMR0_TFAE_2_32 0x00000001
+#define EMAC_TMR0_TFAE_4_64 0x00000002
+#define EMAC_TMR0_TFAE_8_128 0x00000003
+#define EMAC_TMR0_TFAE_16_256 0x00000004
+#define EMAC_TMR0_TFAE_32_512 0x00000005
+#define EMAC_TMR0_TFAE_64_1024 0x00000006
+#define EMAC_TMR0_TFAE_128_2048 0x00000007
+
+/* Receive Mode Register */
+#define EMAC_RMR_SP 0x80000000
+#define EMAC_RMR_SFCS 0x40000000
+#define EMAC_RMR_ARRP 0x20000000
+#define EMAC_RMR_ARP 0x10000000
+#define EMAC_RMR_AROP 0x08000000
+#define EMAC_RMR_ARPI 0x04000000
+#define EMAC_RMR_PPP 0x02000000
+#define EMAC_RMR_PME 0x01000000
+#define EMAC_RMR_PMME 0x00800000
+#define EMAC_RMR_IAE 0x00400000
+#define EMAC_RMR_MIAE 0x00200000
+#define EMAC_RMR_BAE 0x00100000
+#define EMAC_RMR_MAE 0x00080000
+#define EMAC_RMR_RFAF_2_32 0x00000001
+#define EMAC_RMR_RFAF_4_64 0x00000002
+#define EMAC_RMR_RFAF_8_128 0x00000003
+#define EMAC_RMR_RFAF_16_256 0x00000004
+#define EMAC_RMR_RFAF_32_512 0x00000005
+#define EMAC_RMR_RFAF_64_1024 0x00000006
+#define EMAC_RMR_RFAF_128_2048 0x00000007
+#define EMAC_RMR_BASE (EMAC_RMR_IAE | EMAC_RMR_BAE)
+
+/* Interrupt Status & enable Regs */
+#define EMAC_ISR_OVR 0x02000000
+#define EMAC_ISR_PP 0x01000000
+#define EMAC_ISR_BP 0x00800000
+#define EMAC_ISR_RP 0x00400000
+#define EMAC_ISR_SE 0x00200000
+#define EMAC_ISR_ALE 0x00100000
+#define EMAC_ISR_BFCS 0x00080000
+#define EMAC_ISR_PTLE 0x00040000
+#define EMAC_ISR_ORE 0x00020000
+#define EMAC_ISR_IRE 0x00010000
+#define EMAC_ISR_DBDM 0x00000200
+#define EMAC_ISR_DB0 0x00000100
+#define EMAC_ISR_SE0 0x00000080
+#define EMAC_ISR_TE0 0x00000040
+#define EMAC_ISR_DB1 0x00000020
+#define EMAC_ISR_SE1 0x00000010
+#define EMAC_ISR_TE1 0x00000008
+#define EMAC_ISR_MOS 0x00000002
+#define EMAC_ISR_MOF 0x00000001
+
+/* STA CONTROL REG */
+#define EMAC_STACR_OC 0x00008000
+#define EMAC_STACR_PHYE 0x00004000
+#define EMAC_STACR_WRITE 0x00002000
+#define EMAC_STACR_READ 0x00001000
+#define EMAC_STACR_CLK_83MHZ 0x00000800 /* 0's for 50Mhz */
+#define EMAC_STACR_CLK_66MHZ 0x00000400
+#define EMAC_STACR_CLK_100MHZ 0x00000C00
+
+/* Transmit Request Threshold Register */
+#define EMAC_TRTR_1600 0x18000000 /* 0's for 64 Bytes */
+#define EMAC_TRTR_1024 0x0f000000
+#define EMAC_TRTR_512 0x07000000
+#define EMAC_TRTR_256 0x03000000
+#define EMAC_TRTR_192 0x10000000
+#define EMAC_TRTR_128 0x01000000
+
+#define EMAC_TX_CTRL_GFCS 0x0200
+#define EMAC_TX_CTRL_GP 0x0100
+#define EMAC_TX_CTRL_ISA 0x0080
+#define EMAC_TX_CTRL_RSA 0x0040
+#define EMAC_TX_CTRL_IVT 0x0020
+#define EMAC_TX_CTRL_RVT 0x0010
+#define EMAC_TX_CTRL_TAH_CSUM 0x000e /* TAH only */
+#define EMAC_TX_CTRL_TAH_SEG4 0x000a /* TAH only */
+#define EMAC_TX_CTRL_TAH_SEG3 0x0008 /* TAH only */
+#define EMAC_TX_CTRL_TAH_SEG2 0x0006 /* TAH only */
+#define EMAC_TX_CTRL_TAH_SEG1 0x0004 /* TAH only */
+#define EMAC_TX_CTRL_TAH_SEG0 0x0002 /* TAH only */
+#define EMAC_TX_CTRL_TAH_DIS 0x0000 /* TAH only */
+
+#define EMAC_TX_CTRL_DFLT ( \
+ MAL_TX_CTRL_INTR | EMAC_TX_CTRL_GFCS | EMAC_TX_CTRL_GP )
+
+/* madmal transmit status / Control bits */
+#define EMAC_TX_ST_BFCS 0x0200
+#define EMAC_TX_ST_BPP 0x0100
+#define EMAC_TX_ST_LCS 0x0080
+#define EMAC_TX_ST_ED 0x0040
+#define EMAC_TX_ST_EC 0x0020
+#define EMAC_TX_ST_LC 0x0010
+#define EMAC_TX_ST_MC 0x0008
+#define EMAC_TX_ST_SC 0x0004
+#define EMAC_TX_ST_UR 0x0002
+#define EMAC_TX_ST_SQE 0x0001
+
+/* madmal receive status / Control bits */
+#define EMAC_RX_ST_OE 0x0200
+#define EMAC_RX_ST_PP 0x0100
+#define EMAC_RX_ST_BP 0x0080
+#define EMAC_RX_ST_RP 0x0040
+#define EMAC_RX_ST_SE 0x0020
+#define EMAC_RX_ST_AE 0x0010
+#define EMAC_RX_ST_BFCS 0x0008
+#define EMAC_RX_ST_PTL 0x0004
+#define EMAC_RX_ST_ORE 0x0002
+#define EMAC_RX_ST_IRE 0x0001
+#define EMAC_BAD_RX_PACKET 0x02ff
+#define EMAC_CSUM_VER_ERROR 0x0003
+
+/* identify a bad rx packet dependent on emac features */
+#ifdef CONFIG_IBM_EMAC4
+#define EMAC_IS_BAD_RX_PACKET(desc) \
+ (((desc & (EMAC_BAD_RX_PACKET & ~EMAC_CSUM_VER_ERROR)) || \
+ ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_ORE) || \
+ ((desc & EMAC_CSUM_VER_ERROR) == EMAC_RX_ST_IRE)))
+#else
+#define EMAC_IS_BAD_RX_PACKET(desc) \
+ (desc & EMAC_BAD_RX_PACKET)
+#endif
+
+/* SoC implementation specific EMAC register defaults */
+#if defined(CONFIG_440GP)
+#define EMAC_RWMR_DEFAULT 0x80009000
+#define EMAC_TMR0_DEFAULT 0x00000000
+#define EMAC_TMR1_DEFAULT 0xf8640000
+#elif defined(CONFIG_440GX)
+#define EMAC_RWMR_DEFAULT 0x1000a200
+#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_2_32
+#define EMAC_TMR1_DEFAULT 0xa00f0000
+#elif defined(CONFIG_440SP)
+#define EMAC_RWMR_DEFAULT 0x08002000
+#define EMAC_TMR0_DEFAULT EMAC_TMR0_TFAE_128_2048
+#define EMAC_TMR1_DEFAULT 0xf8200000
+#else
+#define EMAC_RWMR_DEFAULT 0x0f002000
+#define EMAC_TMR0_DEFAULT 0x00000000
+#define EMAC_TMR1_DEFAULT 0x380f0000
+#endif /* CONFIG_440GP */
+
+/* Revision specific EMAC register defaults */
+#ifdef CONFIG_IBM_EMAC4
+#define EMAC_M1_DEFAULT (EMAC_M1_BASE | \
+ EMAC_M1_OPB_CLK_83 | \
+ EMAC_M1_TX_MWSW)
+#define EMAC_RMR_DEFAULT (EMAC_RMR_BASE | \
+ EMAC_RMR_RFAF_128_2048)
+#define EMAC_TMR0_XMIT (EMAC_TMR0_GNP0 | \
+ EMAC_TMR0_DEFAULT)
+#define EMAC_TRTR_DEFAULT EMAC_TRTR_1024
+#else /* !CONFIG_IBM_EMAC4 */
+#define EMAC_M1_DEFAULT EMAC_M1_BASE
+#define EMAC_RMR_DEFAULT EMAC_RMR_BASE
+#define EMAC_TMR0_XMIT EMAC_TMR0_GNP0
+#define EMAC_TRTR_DEFAULT EMAC_TRTR_1600
+#endif /* CONFIG_IBM_EMAC4 */
+
+#endif
diff --git a/drivers/net/ibm_emac/ibm_emac_core.c b/drivers/net/ibm_emac/ibm_emac_core.c
new file mode 100644
index 00000000000..ab44358ddbf
--- /dev/null
+++ b/drivers/net/ibm_emac/ibm_emac_core.c
@@ -0,0 +1,2012 @@
+/*
+ * ibm_emac_core.c
+ *
+ * Ethernet driver for the built in ethernet on the IBM 4xx PowerPC
+ * processors.
+ *
+ * (c) 2003 Benjamin Herrenschmidt <benh@kernel.crashing.org>
+ *
+ * Based on original work by
+ *
+ * Armin Kuster <akuster@mvista.com>
+ * Johnnie Peters <jpeters@mvista.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ * TODO
+ * - Check for races in the "remove" code path
+ * - Add some Power Management to the MAC and the PHY
+ * - Audit remaining of non-rewritten code (--BenH)
+ * - Cleanup message display using msglevel mecanism
+ * - Address all errata
+ * - Audit all register update paths to ensure they
+ * are being written post soft reset if required.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ptrace.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/dma-mapping.h>
+#include <linux/ethtool.h>
+#include <linux/mii.h>
+#include <linux/bitops.h>
+
+#include <asm/processor.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/ocp.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/crc32.h>
+
+#include "ibm_emac_core.h"
+
+//#define MDIO_DEBUG(fmt) printk fmt
+#define MDIO_DEBUG(fmt)
+
+//#define LINK_DEBUG(fmt) printk fmt
+#define LINK_DEBUG(fmt)
+
+//#define PKT_DEBUG(fmt) printk fmt
+#define PKT_DEBUG(fmt)
+
+#define DRV_NAME "emac"
+#define DRV_VERSION "2.0"
+#define DRV_AUTHOR "Benjamin Herrenschmidt <benh@kernel.crashing.org>"
+#define DRV_DESC "IBM EMAC Ethernet driver"
+
+/*
+ * When mdio_idx >= 0, contains a list of emac ocp_devs
+ * that have had their initialization deferred until the
+ * common MDIO controller has been initialized.
+ */
+LIST_HEAD(emac_init_list);
+
+MODULE_AUTHOR(DRV_AUTHOR);
+MODULE_DESCRIPTION(DRV_DESC);
+MODULE_LICENSE("GPL");
+
+static int skb_res = SKB_RES;
+module_param(skb_res, int, 0444);
+MODULE_PARM_DESC(skb_res, "Amount of data to reserve on skb buffs\n"
+ "The 405 handles a misaligned IP header fine but\n"
+ "this can help if you are routing to a tunnel or a\n"
+ "device that needs aligned data. 0..2");
+
+#define RGMII_PRIV(ocpdev) ((struct ibm_ocp_rgmii*)ocp_get_drvdata(ocpdev))
+
+static unsigned int rgmii_enable[] = {
+ RGMII_RTBI,
+ RGMII_RGMII,
+ RGMII_TBI,
+ RGMII_GMII
+};
+
+static unsigned int rgmii_speed_mask[] = {
+ RGMII_MII2_SPDMASK,
+ RGMII_MII3_SPDMASK
+};
+
+static unsigned int rgmii_speed100[] = {
+ RGMII_MII2_100MB,
+ RGMII_MII3_100MB
+};
+
+static unsigned int rgmii_speed1000[] = {
+ RGMII_MII2_1000MB,
+ RGMII_MII3_1000MB
+};
+
+#define ZMII_PRIV(ocpdev) ((struct ibm_ocp_zmii*)ocp_get_drvdata(ocpdev))
+
+static unsigned int zmii_enable[][4] = {
+ {ZMII_SMII0, ZMII_RMII0, ZMII_MII0,
+ ~(ZMII_MDI1 | ZMII_MDI2 | ZMII_MDI3)},
+ {ZMII_SMII1, ZMII_RMII1, ZMII_MII1,
+ ~(ZMII_MDI0 | ZMII_MDI2 | ZMII_MDI3)},
+ {ZMII_SMII2, ZMII_RMII2, ZMII_MII2,
+ ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI3)},
+ {ZMII_SMII3, ZMII_RMII3, ZMII_MII3, ~(ZMII_MDI0 | ZMII_MDI1 | ZMII_MDI2)}
+};
+
+static unsigned int mdi_enable[] = {
+ ZMII_MDI0,
+ ZMII_MDI1,
+ ZMII_MDI2,
+ ZMII_MDI3
+};
+
+static unsigned int zmii_speed = 0x0;
+static unsigned int zmii_speed100[] = {
+ ZMII_MII0_100MB,
+ ZMII_MII1_100MB,
+ ZMII_MII2_100MB,
+ ZMII_MII3_100MB
+};
+
+/* Since multiple EMACs share MDIO lines in various ways, we need
+ * to avoid re-using the same PHY ID in cases where the arch didn't
+ * setup precise phy_map entries
+ */
+static u32 busy_phy_map = 0;
+
+/* If EMACs share a common MDIO device, this points to it */
+static struct net_device *mdio_ndev = NULL;
+
+struct emac_def_dev {
+ struct list_head link;
+ struct ocp_device *ocpdev;
+ struct ibm_ocp_mal *mal;
+};
+
+static struct net_device_stats *emac_stats(struct net_device *dev)
+{
+ struct ocp_enet_private *fep = dev->priv;
+ return &fep->stats;
+};
+
+static int
+emac_init_rgmii(struct ocp_device *rgmii_dev, int input, int phy_mode)
+{
+ struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(rgmii_dev);
+ const char *mode_name[] = { "RTBI", "RGMII", "TBI", "GMII" };
+ int mode = -1;
+
+ if (!rgmii) {
+ rgmii = kmalloc(sizeof(struct ibm_ocp_rgmii), GFP_KERNEL);
+
+ if (rgmii == NULL) {
+ printk(KERN_ERR
+ "rgmii%d: Out of memory allocating RGMII structure!\n",
+ rgmii_dev->def->index);
+ return -ENOMEM;
+ }
+
+ memset(rgmii, 0, sizeof(*rgmii));
+
+ rgmii->base =
+ (struct rgmii_regs *)ioremap(rgmii_dev->def->paddr,
+ sizeof(*rgmii->base));
+ if (rgmii->base == NULL) {
+ printk(KERN_ERR
+ "rgmii%d: Cannot ioremap bridge registers!\n",
+ rgmii_dev->def->index);
+
+ kfree(rgmii);
+ return -ENOMEM;
+ }
+ ocp_set_drvdata(rgmii_dev, rgmii);
+ }
+
+ if (phy_mode) {
+ switch (phy_mode) {
+ case PHY_MODE_GMII:
+ mode = GMII;
+ break;
+ case PHY_MODE_TBI:
+ mode = TBI;
+ break;
+ case PHY_MODE_RTBI:
+ mode = RTBI;
+ break;
+ case PHY_MODE_RGMII:
+ default:
+ mode = RGMII;
+ }
+ rgmii->base->fer &= ~RGMII_FER_MASK(input);
+ rgmii->base->fer |= rgmii_enable[mode] << (4 * input);
+ } else {
+ switch ((rgmii->base->fer & RGMII_FER_MASK(input)) >> (4 *
+ input)) {
+ case RGMII_RTBI:
+ mode = RTBI;
+ break;
+ case RGMII_RGMII:
+ mode = RGMII;
+ break;
+ case RGMII_TBI:
+ mode = TBI;
+ break;
+ case RGMII_GMII:
+ mode = GMII;
+ }
+ }
+
+ /* Set mode to RGMII if nothing valid is detected */
+ if (mode < 0)
+ mode = RGMII;
+
+ printk(KERN_NOTICE "rgmii%d: input %d in %s mode\n",
+ rgmii_dev->def->index, input, mode_name[mode]);
+
+ rgmii->mode[input] = mode;
+ rgmii->users++;
+
+ return 0;
+}
+
+static void
+emac_rgmii_port_speed(struct ocp_device *ocpdev, int input, int speed)
+{
+ struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev);
+ unsigned int rgmii_speed;
+
+ rgmii_speed = in_be32(&rgmii->base->ssr);
+
+ rgmii_speed &= ~rgmii_speed_mask[input];
+
+ if (speed == 1000)
+ rgmii_speed |= rgmii_speed1000[input];
+ else if (speed == 100)
+ rgmii_speed |= rgmii_speed100[input];
+
+ out_be32(&rgmii->base->ssr, rgmii_speed);
+}
+
+static void emac_close_rgmii(struct ocp_device *ocpdev)
+{
+ struct ibm_ocp_rgmii *rgmii = RGMII_PRIV(ocpdev);
+ BUG_ON(!rgmii || rgmii->users == 0);
+
+ if (!--rgmii->users) {
+ ocp_set_drvdata(ocpdev, NULL);
+ iounmap((void *)rgmii->base);
+ kfree(rgmii);
+ }
+}
+
+static int emac_init_zmii(struct ocp_device *zmii_dev, int input, int phy_mode)
+{
+ struct ibm_ocp_zmii *zmii = ZMII_PRIV(zmii_dev);
+ const char *mode_name[] = { "SMII", "RMII", "MII" };
+ int mode = -1;
+
+ if (!zmii) {
+ zmii = kmalloc(sizeof(struct ibm_ocp_zmii), GFP_KERNEL);
+ if (zmii == NULL) {
+ printk(KERN_ERR
+ "zmii%d: Out of memory allocating ZMII structure!\n",
+ zmii_dev->def->index);
+ return -ENOMEM;
+ }
+ memset(zmii, 0, sizeof(*zmii));
+
+ zmii->base =
+ (struct zmii_regs *)ioremap(zmii_dev->def->paddr,
+ sizeof(*zmii->base));
+ if (zmii->base == NULL) {
+ printk(KERN_ERR
+ "zmii%d: Cannot ioremap bridge registers!\n",
+ zmii_dev->def->index);
+
+ kfree(zmii);
+ return -ENOMEM;
+ }
+ ocp_set_drvdata(zmii_dev, zmii);
+ }
+
+ if (phy_mode) {
+ switch (phy_mode) {
+ case PHY_MODE_MII:
+ mode = MII;
+ break;
+ case PHY_MODE_RMII:
+ mode = RMII;
+ break;
+ case PHY_MODE_SMII:
+ default:
+ mode = SMII;
+ }
+ zmii->base->fer &= ~ZMII_FER_MASK(input);
+ zmii->base->fer |= zmii_enable[input][mode];
+ } else {
+ switch ((zmii->base->fer & ZMII_FER_MASK(input)) << (4 * input)) {
+ case ZMII_MII0:
+ mode = MII;
+ break;
+ case ZMII_RMII0:
+ mode = RMII;
+ break;
+ case ZMII_SMII0:
+ mode = SMII;
+ }
+ }
+
+ /* Set mode to SMII if nothing valid is detected */
+ if (mode < 0)
+ mode = SMII;
+
+ printk(KERN_NOTICE "zmii%d: input %d in %s mode\n",
+ zmii_dev->def->index, input, mode_name[mode]);
+
+ zmii->mode[input] = mode;
+ zmii->users++;
+
+ return 0;
+}
+
+static void emac_enable_zmii_port(struct ocp_device *ocpdev, int input)
+{
+ u32 mask;
+ struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev);
+
+ mask = in_be32(&zmii->base->fer);
+ mask &= zmii_enable[input][MDI]; /* turn all non enabled MDI's off */
+ mask |= zmii_enable[input][zmii->mode[input]] | mdi_enable[input];
+ out_be32(&zmii->base->fer, mask);
+}
+
+static void
+emac_zmii_port_speed(struct ocp_device *ocpdev, int input, int speed)
+{
+ struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev);
+
+ if (speed == 100)
+ zmii_speed |= zmii_speed100[input];
+ else
+ zmii_speed &= ~zmii_speed100[input];
+
+ out_be32(&zmii->base->ssr, zmii_speed);
+}
+
+static void emac_close_zmii(struct ocp_device *ocpdev)
+{
+ struct ibm_ocp_zmii *zmii = ZMII_PRIV(ocpdev);
+ BUG_ON(!zmii || zmii->users == 0);
+
+ if (!--zmii->users) {
+ ocp_set_drvdata(ocpdev, NULL);
+ iounmap((void *)zmii->base);
+ kfree(zmii);
+ }
+}
+
+int emac_phy_read(struct net_device *dev, int mii_id, int reg)
+{
+ int count;
+ uint32_t stacr;
+ struct ocp_enet_private *fep = dev->priv;
+ emac_t *emacp = fep->emacp;
+
+ MDIO_DEBUG(("%s: phy_read, id: 0x%x, reg: 0x%x\n", dev->name, mii_id,
+ reg));
+
+ /* Enable proper ZMII port */
+ if (fep->zmii_dev)
+ emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input);
+
+ /* Use the EMAC that has the MDIO port */
+ if (fep->mdio_dev) {
+ dev = fep->mdio_dev;
+ fep = dev->priv;
+ emacp = fep->emacp;
+ }
+
+ count = 0;
+ while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0)
+ && (count++ < MDIO_DELAY))
+ udelay(1);
+ MDIO_DEBUG((" (count was %d)\n", count));
+
+ if ((stacr & EMAC_STACR_OC) == 0) {
+ printk(KERN_WARNING "%s: PHY read timeout #1!\n", dev->name);
+ return -1;
+ }
+
+ /* Clear the speed bits and make a read request to the PHY */
+ stacr = ((EMAC_STACR_READ | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ);
+ stacr |= ((mii_id & 0x1F) << 5);
+
+ out_be32(&emacp->em0stacr, stacr);
+
+ count = 0;
+ while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0)
+ && (count++ < MDIO_DELAY))
+ udelay(1);
+ MDIO_DEBUG((" (count was %d)\n", count));
+
+ if ((stacr & EMAC_STACR_OC) == 0) {
+ printk(KERN_WARNING "%s: PHY read timeout #2!\n", dev->name);
+ return -1;
+ }
+
+ /* Check for a read error */
+ if (stacr & EMAC_STACR_PHYE) {
+ MDIO_DEBUG(("EMAC MDIO PHY error !\n"));
+ return -1;
+ }
+
+ MDIO_DEBUG((" -> 0x%x\n", stacr >> 16));
+
+ return (stacr >> 16);
+}
+
+void emac_phy_write(struct net_device *dev, int mii_id, int reg, int data)
+{
+ int count;
+ uint32_t stacr;
+ struct ocp_enet_private *fep = dev->priv;
+ emac_t *emacp = fep->emacp;
+
+ MDIO_DEBUG(("%s phy_write, id: 0x%x, reg: 0x%x, data: 0x%x\n",
+ dev->name, mii_id, reg, data));
+
+ /* Enable proper ZMII port */
+ if (fep->zmii_dev)
+ emac_enable_zmii_port(fep->zmii_dev, fep->zmii_input);
+
+ /* Use the EMAC that has the MDIO port */
+ if (fep->mdio_dev) {
+ dev = fep->mdio_dev;
+ fep = dev->priv;
+ emacp = fep->emacp;
+ }
+
+ count = 0;
+ while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0)
+ && (count++ < MDIO_DELAY))
+ udelay(1);
+ MDIO_DEBUG((" (count was %d)\n", count));
+
+ if ((stacr & EMAC_STACR_OC) == 0) {
+ printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name);
+ return;
+ }
+
+ /* Clear the speed bits and make a read request to the PHY */
+
+ stacr = ((EMAC_STACR_WRITE | (reg & 0x1f)) & ~EMAC_STACR_CLK_100MHZ);
+ stacr |= ((mii_id & 0x1f) << 5) | ((data & 0xffff) << 16);
+
+ out_be32(&emacp->em0stacr, stacr);
+
+ count = 0;
+ while ((((stacr = in_be32(&emacp->em0stacr)) & EMAC_STACR_OC) == 0)
+ && (count++ < MDIO_DELAY))
+ udelay(1);
+ MDIO_DEBUG((" (count was %d)\n", count));
+
+ if ((stacr & EMAC_STACR_OC) == 0)
+ printk(KERN_WARNING "%s: PHY write timeout #2!\n", dev->name);
+
+ /* Check for a write error */
+ if ((stacr & EMAC_STACR_PHYE) != 0) {
+ MDIO_DEBUG(("EMAC MDIO PHY error !\n"));
+ }
+}
+
+static void emac_txeob_dev(void *param, u32 chanmask)
+{
+ struct net_device *dev = param;
+ struct ocp_enet_private *fep = dev->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fep->lock, flags);
+
+ PKT_DEBUG(("emac_txeob_dev() entry, tx_cnt: %d\n", fep->tx_cnt));
+
+ while (fep->tx_cnt &&
+ !(fep->tx_desc[fep->ack_slot].ctrl & MAL_TX_CTRL_READY)) {
+
+ if (fep->tx_desc[fep->ack_slot].ctrl & MAL_TX_CTRL_LAST) {
+ /* Tell the system the transmit completed. */
+ dma_unmap_single(&fep->ocpdev->dev,
+ fep->tx_desc[fep->ack_slot].data_ptr,
+ fep->tx_desc[fep->ack_slot].data_len,
+ DMA_TO_DEVICE);
+ dev_kfree_skb_irq(fep->tx_skb[fep->ack_slot]);
+
+ if (fep->tx_desc[fep->ack_slot].ctrl &
+ (EMAC_TX_ST_EC | EMAC_TX_ST_MC | EMAC_TX_ST_SC))
+ fep->stats.collisions++;
+ }
+
+ fep->tx_skb[fep->ack_slot] = (struct sk_buff *)NULL;
+ if (++fep->ack_slot == NUM_TX_BUFF)
+ fep->ack_slot = 0;
+
+ fep->tx_cnt--;
+ }
+ if (fep->tx_cnt < NUM_TX_BUFF)
+ netif_wake_queue(dev);
+
+ PKT_DEBUG(("emac_txeob_dev() exit, tx_cnt: %d\n", fep->tx_cnt));
+
+ spin_unlock_irqrestore(&fep->lock, flags);
+}
+
+/*
+ Fill/Re-fill the rx chain with valid ctrl/ptrs.
+ This function will fill from rx_slot up to the parm end.
+ So to completely fill the chain pre-set rx_slot to 0 and
+ pass in an end of 0.
+ */
+static void emac_rx_fill(struct net_device *dev, int end)
+{
+ int i;
+ struct ocp_enet_private *fep = dev->priv;
+
+ i = fep->rx_slot;
+ do {
+ /* We don't want the 16 bytes skb_reserve done by dev_alloc_skb,
+ * it breaks our cache line alignement. However, we still allocate
+ * +16 so that we end up allocating the exact same size as
+ * dev_alloc_skb() would do.
+ * Also, because of the skb_res, the max DMA size we give to EMAC
+ * is slighly wrong, causing it to potentially DMA 2 more bytes
+ * from a broken/oversized packet. These 16 bytes will take care
+ * that we don't walk on somebody else toes with that.
+ */
+ fep->rx_skb[i] =
+ alloc_skb(fep->rx_buffer_size + 16, GFP_ATOMIC);
+
+ if (fep->rx_skb[i] == NULL) {
+ /* Keep rx_slot here, the next time clean/fill is called
+ * we will try again before the MAL wraps back here
+ * If the MAL tries to use this descriptor with
+ * the EMPTY bit off it will cause the
+ * rxde interrupt. That is where we will
+ * try again to allocate an sk_buff.
+ */
+ break;
+
+ }
+
+ if (skb_res)
+ skb_reserve(fep->rx_skb[i], skb_res);
+
+ /* We must NOT dma_map_single the cache line right after the
+ * buffer, so we must crop our sync size to account for the
+ * reserved space
+ */
+ fep->rx_desc[i].data_ptr =
+ (unsigned char *)dma_map_single(&fep->ocpdev->dev,
+ (void *)fep->rx_skb[i]->
+ data,
+ fep->rx_buffer_size -
+ skb_res, DMA_FROM_DEVICE);
+
+ /*
+ * Some 4xx implementations use the previously
+ * reserved bits in data_len to encode the MS
+ * 4-bits of a 36-bit physical address (ERPN)
+ * This must be initialized.
+ */
+ fep->rx_desc[i].data_len = 0;
+ fep->rx_desc[i].ctrl = MAL_RX_CTRL_EMPTY | MAL_RX_CTRL_INTR |
+ (i == (NUM_RX_BUFF - 1) ? MAL_RX_CTRL_WRAP : 0);
+
+ } while ((i = (i + 1) % NUM_RX_BUFF) != end);
+
+ fep->rx_slot = i;
+}
+
+static void
+emac_rx_csum(struct net_device *dev, unsigned short ctrl, struct sk_buff *skb)
+{
+ struct ocp_enet_private *fep = dev->priv;
+
+ /* Exit if interface has no TAH engine */
+ if (!fep->tah_dev) {
+ skb->ip_summed = CHECKSUM_NONE;
+ return;
+ }
+
+ /* Check for TCP/UDP/IP csum error */
+ if (ctrl & EMAC_CSUM_VER_ERROR) {
+ /* Let the stack verify checksum errors */
+ skb->ip_summed = CHECKSUM_NONE;
+/* adapter->hw_csum_err++; */
+ } else {
+ /* Csum is good */
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+/* adapter->hw_csum_good++; */
+ }
+}
+
+static int emac_rx_clean(struct net_device *dev)
+{
+ int i, b, bnum = 0, buf[6];
+ int error, frame_length;
+ struct ocp_enet_private *fep = dev->priv;
+ unsigned short ctrl;
+
+ i = fep->rx_slot;
+
+ PKT_DEBUG(("emac_rx_clean() entry, rx_slot: %d\n", fep->rx_slot));
+
+ do {
+ if (fep->rx_skb[i] == NULL)
+ continue; /*we have already handled the packet but haved failed to alloc */
+ /*
+ since rx_desc is in uncached mem we don't keep reading it directly
+ we pull out a local copy of ctrl and do the checks on the copy.
+ */
+ ctrl = fep->rx_desc[i].ctrl;
+ if (ctrl & MAL_RX_CTRL_EMPTY)
+ break; /*we don't have any more ready packets */
+
+ if (EMAC_IS_BAD_RX_PACKET(ctrl)) {
+ fep->stats.rx_errors++;
+ fep->stats.rx_dropped++;
+
+ if (ctrl & EMAC_RX_ST_OE)
+ fep->stats.rx_fifo_errors++;
+ if (ctrl & EMAC_RX_ST_AE)
+ fep->stats.rx_frame_errors++;
+ if (ctrl & EMAC_RX_ST_BFCS)
+ fep->stats.rx_crc_errors++;
+ if (ctrl & (EMAC_RX_ST_RP | EMAC_RX_ST_PTL |
+ EMAC_RX_ST_ORE | EMAC_RX_ST_IRE))
+ fep->stats.rx_length_errors++;
+ } else {
+ if ((ctrl & (MAL_RX_CTRL_FIRST | MAL_RX_CTRL_LAST)) ==
+ (MAL_RX_CTRL_FIRST | MAL_RX_CTRL_LAST)) {
+ /* Single descriptor packet */
+ emac_rx_csum(dev, ctrl, fep->rx_skb[i]);
+ /* Send the skb up the chain. */
+ frame_length = fep->rx_desc[i].data_len - 4;
+ skb_put(fep->rx_skb[i], frame_length);
+ fep->rx_skb[i]->dev = dev;
+ fep->rx_skb[i]->protocol =
+ eth_type_trans(fep->rx_skb[i], dev);
+ error = netif_rx(fep->rx_skb[i]);
+
+ if ((error == NET_RX_DROP) ||
+ (error == NET_RX_BAD)) {
+ fep->stats.rx_dropped++;
+ } else {
+ fep->stats.rx_packets++;
+ fep->stats.rx_bytes += frame_length;
+ }
+ fep->rx_skb[i] = NULL;
+ } else {
+ /* Multiple descriptor packet */
+ if (ctrl & MAL_RX_CTRL_FIRST) {
+ if (fep->rx_desc[(i + 1) % NUM_RX_BUFF].
+ ctrl & MAL_RX_CTRL_EMPTY)
+ break;
+ bnum = 0;
+ buf[bnum] = i;
+ ++bnum;
+ continue;
+ }
+ if (((ctrl & MAL_RX_CTRL_FIRST) !=
+ MAL_RX_CTRL_FIRST) &&
+ ((ctrl & MAL_RX_CTRL_LAST) !=
+ MAL_RX_CTRL_LAST)) {
+ if (fep->rx_desc[(i + 1) %
+ NUM_RX_BUFF].ctrl &
+ MAL_RX_CTRL_EMPTY) {
+ i = buf[0];
+ break;
+ }
+ buf[bnum] = i;
+ ++bnum;
+ continue;
+ }
+ if (ctrl & MAL_RX_CTRL_LAST) {
+ buf[bnum] = i;
+ ++bnum;
+ skb_put(fep->rx_skb[buf[0]],
+ fep->rx_desc[buf[0]].data_len);
+ for (b = 1; b < bnum; b++) {
+ /*
+ * MAL is braindead, we need
+ * to copy the remainder
+ * of the packet from the
+ * latter descriptor buffers
+ * to the first skb. Then
+ * dispose of the source
+ * skbs.
+ *
+ * Once the stack is fixed
+ * to handle frags on most
+ * protocols we can generate
+ * a fragmented skb with
+ * no copies.
+ */
+ memcpy(fep->rx_skb[buf[0]]->
+ data +
+ fep->rx_skb[buf[0]]->len,
+ fep->rx_skb[buf[b]]->
+ data,
+ fep->rx_desc[buf[b]].
+ data_len);
+ skb_put(fep->rx_skb[buf[0]],
+ fep->rx_desc[buf[b]].
+ data_len);
+ dma_unmap_single(&fep->ocpdev->
+ dev,
+ fep->
+ rx_desc[buf
+ [b]].
+ data_ptr,
+ fep->
+ rx_desc[buf
+ [b]].
+ data_len,
+ DMA_FROM_DEVICE);
+ dev_kfree_skb(fep->
+ rx_skb[buf[b]]);
+ }
+ emac_rx_c