diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index ed4825b..24df187 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -40,6 +40,7 @@
#include <linux/irq.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/phy.h>
#include <asm/cacheflush.h>
@@ -51,6 +52,7 @@
#include "fec.h"
#ifdef CONFIG_ARCH_MXC
+#include <linux/fec.h>
#include <mach/hardware.h>
#define FEC_ALIGNMENT 0xf
#else
@@ -110,8 +112,6 @@ static unsigned char fec_mac_default[] = {
#define FEC_FLASHMAC 0
#endif
-#endif /* FEC_LEGACY */
-
/* Forward declarations of some structures to support different PHYs
*/
@@ -130,6 +130,8 @@ typedef struct {
const phy_cmd_t *shutdown;
} phy_info_t;
+#endif /* FEC_LEGACY */
+
/* The number of Tx and Rx buffers. These are allocated from the page
* pool. The code may assume these are power of two, so it it best
* to keep them that size.@@ -213,13 +215,13 @@ struct fec_enet_private {
uint tx_full;
/* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
spinlock_t hw_lock;
+#ifdef FEC_LEGACY
/* hold while accessing the mii_list_t() elements */
spinlock_t mii_lock;
uint phy_id;
uint phy_id_done;
uint phy_status;
- uint phy_speed;
phy_info_t const *phy;
struct work_struct phy_task;
@@ -228,16 +230,25 @@ struct fec_enet_private {
uint phy_addr;
+ int old_link;
+#else
+ struct platform_device *pdev;
+ struct mii_bus *mii_bus;
+ struct phy_device *phy_dev;
+ int mii_timeout;
+#endif
+ uint phy_speed;
int index;
int opened;
int link;
- int old_link;
int full_duplex;
};
static int fec_enet_open(struct net_device *dev);
static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+#ifdef FEC_LEGACY
static void fec_enet_mii(struct net_device *dev);
+#endif
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);@@ -248,6 +259,11 @@ static void fec_stop(struct net_device *dev);
static void fec_set_mac_address(struct net_device *dev);
+/* Transmitter timeout.
+*/
+#define TX_TIMEOUT (2*HZ)
+
+#ifdef FEC_LEGACY
/* MII processing. We keep this as simple as possible. Requests are
* placed on the list (if there is room). When the request is finished
* by the MII, an optional function may be called.
@@ -274,10 +290,6 @@ static int mii_queue(struct net_device *dev, int request,
(VAL & 0xffff))
#define mk_mii_end 0
-/* Transmitter timeout.
-*/
-#define TX_TIMEOUT (2*HZ)
-
/* Register definitions for the PHY.
*/
@@ -310,6 +322,18 @@ static int mii_queue(struct net_device *dev, int request,
#define PHY_STAT_100HDX 0x4000 /* 100 Mbit half duplex selected */
#define PHY_STAT_100FDX 0x8000 /* 100 Mbit full duplex selected */
+#else
+/* FEC MMFR bits definition */
+#define FEC_MMFR_ST (1 << 30)
+#define FEC_MMFR_OP_READ (2 << 28)
+#define FEC_MMFR_OP_WRITE (1 << 28)
+#define FEC_MMFR_PA(v) ((v & 0x1f) << 23)
+#define FEC_MMFR_RA(v) ((v & 0x1f) << 18)
+#define FEC_MMFR_TA (2 << 16)
+#define FEC_MMFR_DATA(v) (v & 0xffff)
+
+#define FEC_MII_TRIES 10000
+#endif
static int
fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -490,10 +514,12 @@ fec_enet_interrupt(int irq, void * dev_id)
fec_enet_tx(dev);
}
+#ifdef FEC_LEGACY
if (int_events & FEC_ENET_MII) {
ret = IRQ_HANDLED;
fec_enet_mii(dev);
}
+#endif
} while (int_events);
@@ -711,6 +737,7 @@ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
}
+#ifdef FEC_LEGACY
/* called from interrupt context */
static void
fec_enet_mii(struct net_device *dev)@@ -1238,6 +1265,7 @@ static phy_info_t const * const phy_info[] = {
NULL
};
+#endif /* FEC_LEGACY */
/* ------------------------------------------------------------------------- */
#ifdef HAVE_mii_link_interrupt
static irqreturn_t@@ -1726,6 +1754,7 @@ static void __inline__ fec_phy_ack_intr(void)
/* ------------------------------------------------------------------------- */
+#ifdef FEC_LEGACY
static void mii_display_status(struct net_device *dev)
{
struct fec_enet_private *fep = netdev_priv(dev);@@ -1927,9 +1956,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
printk("FEC: No PHY device found.\n");
/* Disable external MII interface */
fecp->fec_mii_speed = fep->phy_speed = 0;
-#ifdef FREC_LEGACY
fec_disable_phy_intr();
-#endif
}
}
@@ -1954,6 +1981,289 @@ mii_link_interrupt(int irq, void * dev_id)
return IRQ_HANDLED;
}
#endif
+#else
+static void fec_enet_handle_link_change(struct net_device *dev)
+{
+ struct fec_enet_private *fep = netdev_priv(dev);
+ struct phy_device *phy_dev = fep->phy_dev;
+ unsigned long flags;
+
+ int status_change = 0;
+
+ spin_lock_irqsave(&fep->hw_lock, flags);
+
+ /* Prevent a state halted on mii error */
+ if (fep->mii_timeout && phy_dev->state == PHY_HALTED) {
+ printk(KERN_INFO "%s: mii resume\n", dev->name);
+ phy_dev->state = PHY_RESUMING;
+ goto spin_unlock;
+ }
+
+ if (phy_dev->link) {
+ if (fep->full_duplex != phy_dev->duplex) {
+ fec_restart(dev, phy_dev->duplex);
+ status_change = 1;
+ }
+ }
+
+ if (phy_dev->link != fep->link) {
+ fep->link = phy_dev->link;
+ if (phy_dev->link)
+ fec_restart(dev, phy_dev->duplex);
+ else
+ fec_stop(dev);
+ status_change = 1;
+ }
+spin_unlock:
+ spin_unlock_irqrestore(&fep->hw_lock, flags);
+
+ if (status_change) {
+ if (phy_dev->link)
+ printk(KERN_INFO "%s: link up (%d/%s)\n",
+ dev->name, phy_dev->speed,
+ DUPLEX_FULL == phy_dev->duplex ? "Full"
+ : "Half");
+ else
+ printk(KERN_INFO "%s: link down\n", dev->name);