summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/Kconfig7
-rw-r--r--drivers/net/Makefile1
-rw-r--r--drivers/net/can/Kconfig4
-rw-r--r--drivers/net/can/flexcan/dev.c112
-rw-r--r--drivers/net/can/flexcan/flexcan.h31
-rw-r--r--drivers/net/can/flexcan/mbm.c74
-rw-r--r--drivers/net/enc28j60.c18
-rw-r--r--drivers/net/fec.c62
-rw-r--r--drivers/net/fec_1588.c155
-rw-r--r--drivers/net/fec_1588.h51
-rw-r--r--drivers/net/phy/mdio_bus.c72
-rw-r--r--drivers/net/phy/phy.c4
-rw-r--r--drivers/net/phy/phy_device.c31
-rw-r--r--drivers/net/smsc911x.c5
-rw-r--r--drivers/net/wireless/ath6kl/os/linux/ar6000_android.c2
15 files changed, 482 insertions, 147 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index bd5d0e026b02..28318f4236b1 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -1885,6 +1885,13 @@ config FEC_1588
bool "Enable FEC 1588 timestamping"
depends on FEC
+config FEC_L2SWITCH
+ bool "L2 Switch Ethernet Controller (of ColdFire CPUs)"
+ depends on ARCH_MX28 && !FEC
+ help
+ Say Y here if you want to use the built-in 10/100 Ethernet Switch
+ Controller on some Motorola ColdFire processors.
+
config FEC2
bool "Second FEC ethernet controller (on some ColdFire CPUs)"
depends on FEC
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index f3c89fb1b799..11bb1b5623bf 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -115,6 +115,7 @@ obj-$(CONFIG_HP100) += hp100.o
obj-$(CONFIG_SMC9194) += smc9194.o
obj-$(CONFIG_FEC) += fec.o
obj-$(CONFIG_FEC_1588) += fec_1588.o
+obj-$(CONFIG_FEC_L2SWITCH) += fec_switch.o
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o
ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y)
obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o
diff --git a/drivers/net/can/Kconfig b/drivers/net/can/Kconfig
index a6bf9a7fddd9..481990fd3f2b 100644
--- a/drivers/net/can/Kconfig
+++ b/drivers/net/can/Kconfig
@@ -86,8 +86,8 @@ config CAN_DEBUG_DEVICES
config CAN_FLEXCAN
tristate "Freescale FlexCAN"
- depends on CAN && (ARCH_MX25 || ARCH_MX35 || ARCH_MX28)
- default m
+ depends on CAN && (ARCH_MX25 || ARCH_MX35 || ARCH_MX28 || ARCH_MX53)
+ default y
---help---
This select the support of Freescale CAN(FlexCAN).
This driver can also be built as a module.
diff --git a/drivers/net/can/flexcan/dev.c b/drivers/net/can/flexcan/dev.c
index 389f85d75709..404877c33eab 100644
--- a/drivers/net/can/flexcan/dev.c
+++ b/drivers/net/can/flexcan/dev.c
@@ -35,6 +35,74 @@
#endif
#include "flexcan.h"
+#define DEFAULT_BITRATE 500000
+#define TIME_SEGMENT_MIN 8
+#define TIME_SEGMENT_MAX 25
+#define TIME_SEGMENT_MID ((TIME_SEGMENT_MIN + TIME_SEGMENT_MAX)/2)
+
+struct time_segment {
+ char propseg;
+ char pseg1;
+ char pseg2;
+};
+
+struct time_segment time_segments[] = {
+ { /* total 8 timequanta */
+ 1, 2, 1
+ },
+ { /* total 9 timequanta */
+ 1, 2, 2
+ },
+ { /* total 10 timequanta */
+ 2, 2, 2
+ },
+ { /* total 11 timequanta */
+ 2, 2, 3
+ },
+ { /* total 12 timequanta */
+ 2, 3, 3
+ },
+ { /* total 13 timequanta */
+ 3, 3, 3
+ },
+ { /* total 14 timequanta */
+ 3, 3, 4
+ },
+ { /* total 15 timequanta */
+ 3, 4, 4
+ },
+ { /* total 16 timequanta */
+ 4, 4, 4
+ },
+ { /* total 17 timequanta */
+ 4, 4, 5
+ },
+ { /* total 18 timequanta */
+ 4, 5, 5
+ },
+ { /* total 19 timequanta */
+ 5, 5, 5
+ },
+ { /* total 20 timequanta */
+ 5, 5, 6
+ },
+ { /* total 21 timequanta */
+ 5, 6, 6
+ },
+ { /* total 22 timequanta */
+ 6, 6, 6
+ },
+ { /* total 23 timequanta */
+ 6, 6, 7
+ },
+ { /* total 24 timequanta */
+ 6, 7, 7
+ },
+ { /* total 25 timequanta */
+ 7, 7, 7
+ },
+};
+
enum {
FLEXCAN_ATTR_STATE = 0,
FLEXCAN_ATTR_BITRATE,
@@ -138,6 +206,45 @@ static void flexcan_set_bitrate(struct flexcan_device *flexcan, int bitrate)
* based on the bitrate to get the timing of
* presdiv, pseg1, pseg2, propseg
*/
+ int i, rate, div;
+ bool found = false;
+ struct time_segment *segment;
+ rate = clk_get_rate(flexcan->clk);
+
+ if (!bitrate)
+ bitrate = DEFAULT_BITRATE;
+
+ if (rate % bitrate == 0) {
+ div = rate / bitrate;
+ for (i = TIME_SEGMENT_MID; i <= TIME_SEGMENT_MAX; i++) {
+ if (div % i == 0) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ for (i = TIME_SEGMENT_MID - 1;
+ i >= TIME_SEGMENT_MIN; i--) {
+ if (div % i == 0) {
+ found = true;
+ break;
+ }
+ }
+
+ }
+ }
+
+ if (found) {
+ segment = &time_segments[i - TIME_SEGMENT_MIN];
+ flexcan->br_presdiv = div/i - 1;
+ flexcan->br_propseg = segment->propseg;
+ flexcan->br_pseg1 = segment->pseg1;
+ flexcan->br_pseg2 = segment->pseg2;
+ flexcan->bitrate = bitrate;
+ } else {
+ pr_info("The bitrate %d can't supported with clock \
+ rate of %d \n", bitrate, rate);
+ }
}
static void flexcan_update_bitrate(struct flexcan_device *flexcan)
@@ -201,7 +308,7 @@ static int flexcan_dump_xmit_mb(struct flexcan_device *flexcan, char *buf)
ret +=
sprintf(buf + ret,
"mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
- i, flexcan->hwmb[i].mb_cs.data,
+ i, flexcan->hwmb[i].mb_cs,
flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
flexcan->hwmb[i].mb_data[2]);
return ret;
@@ -214,7 +321,7 @@ static int flexcan_dump_rx_mb(struct flexcan_device *flexcan, char *buf)
ret +=
sprintf(buf + ret,
"mb[%d]::CS:0x%x ID:0x%x DATA[1~2]:0x%02x,0x%02x\n",
- i, flexcan->hwmb[i].mb_cs.data,
+ i, flexcan->hwmb[i].mb_cs,
flexcan->hwmb[i].mb_id, flexcan->hwmb[i].mb_data[1],
flexcan->hwmb[i].mb_data[2]);
return ret;
@@ -575,6 +682,7 @@ struct net_device *flexcan_device_alloc(struct platform_device *pdev,
return NULL;
}
flexcan_device_default(flexcan);
+ flexcan_set_bitrate(flexcan, flexcan->bitrate);
flexcan_update_bitrate(flexcan);
num = ARRAY_SIZE(flexcan_dev_attr);
diff --git a/drivers/net/can/flexcan/flexcan.h b/drivers/net/can/flexcan/flexcan.h
index d19cc1ee0620..51a800bd8e55 100644
--- a/drivers/net/can/flexcan/flexcan.h
+++ b/drivers/net/can/flexcan/flexcan.h
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -32,17 +32,6 @@
#define FLEXCAN_DEVICE_NAME "FlexCAN"
-struct can_mb_cs {
- unsigned int time_stamp:16;
- unsigned int length:4;
- unsigned int rtr:1;
- unsigned int ide:1;
- unsigned int srr:1;
- unsigned int nouse1:1;
- unsigned int code:4;
- unsigned int nouse2:4;
-};
-
#define CAN_MB_RX_INACTIVE 0x0
#define CAN_MB_RX_EMPTY 0x4
#define CAN_MB_RX_FULL 0x2
@@ -55,14 +44,24 @@ struct can_mb_cs {
#define CAN_MB_TX_REMOTE 0xA
struct can_hw_mb {
- union {
- struct can_mb_cs cs;
- unsigned int data;
- } mb_cs;
+ unsigned int mb_cs;
unsigned int mb_id;
unsigned char mb_data[8];
};
+#define MB_CS_CODE_OFFSET 24
+#define MB_CS_CODE_MASK (0xF << MB_CS_CODE_OFFSET)
+#define MB_CS_SRR_OFFSET 22
+#define MB_CS_SRR_MASK (0x1 << MB_CS_SRR_OFFSET)
+#define MB_CS_IDE_OFFSET 21
+#define MB_CS_IDE_MASK (0x1 << MB_CS_IDE_OFFSET)
+#define MB_CS_RTR_OFFSET 20
+#define MB_CS_RTR_MASK (0x1 << MB_CS_RTR_OFFSET)
+#define MB_CS_LENGTH_OFFSET 16
+#define MB_CS_LENGTH_MASK (0xF << MB_CS_LENGTH_OFFSET)
+#define MB_CS_TIMESTAMP_OFFSET 0
+#define MB_CS_TIMESTAMP_MASK (0xFF << MB_CS_TIMESTAMP_OFFSET)
+
#define CAN_HW_REG_MCR 0x00
#define CAN_HW_REG_CTRL 0x04
#define CAN_HW_REG_TIMER 0x08
diff --git a/drivers/net/can/flexcan/mbm.c b/drivers/net/can/flexcan/mbm.c
index b0341ba9128e..c846d97daadb 100644
--- a/drivers/net/can/flexcan/mbm.c
+++ b/drivers/net/can/flexcan/mbm.c
@@ -1,5 +1,5 @@
/*
- * Copyright 2008-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
*/
/*
@@ -55,10 +55,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
hwmb = flexcan->hwmb + index;
if (flexcan->fifo || (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
- if (hwmb->mb_cs.cs.code == CAN_MB_TX_ABORT)
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ if ((hwmb->mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET ==
+ CAN_MB_TX_ABORT) {
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
+ }
- if (hwmb->mb_cs.cs.code & CAN_MB_TX_INACTIVE) {
+ if (hwmb->mb_cs & (CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET)) {
if (netif_queue_stopped(dev))
netif_start_queue(dev);
return;
@@ -68,16 +71,17 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
if (skb) {
frame = (struct can_frame *)skb_put(skb, sizeof(*frame));
memset(frame, 0, sizeof(*frame));
- if (hwmb->mb_cs.cs.ide)
+ if (hwmb->mb_cs & MB_CS_IDE_MASK)
frame->can_id =
(hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
frame->can_id = (hwmb->mb_id >> 18) & CAN_SFF_MASK;
- if (hwmb->mb_cs.cs.rtr)
+ if (hwmb->mb_cs & MB_CS_RTR_MASK)
frame->can_id |= CAN_RTR_FLAG;
- frame->can_dlc = hwmb->mb_cs.cs.length;
+ frame->can_dlc =
+ (hwmb->mb_cs & MB_CS_LENGTH_MASK) >> MB_CS_LENGTH_OFFSET;
if (frame->can_dlc && frame->can_dlc)
flexcan_memcpy(frame->data, hwmb->mb_data,
@@ -85,7 +89,8 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
if (flexcan->fifo
|| (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
}
@@ -101,13 +106,13 @@ static void flexcan_mb_bottom(struct net_device *dev, int index)
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
} else {
- tmp = hwmb->mb_cs.data;
+ tmp = hwmb->mb_cs;
tmp = hwmb->mb_id;
tmp = hwmb->mb_data[0];
if (flexcan->fifo
|| (index >= (flexcan->maxmb - flexcan->xmit_maxmb))) {
-
- hwmb->mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ hwmb->mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb->mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
}
@@ -131,17 +136,19 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1)
frame =
(struct can_frame *)skb_put(skb, sizeof(*frame));
memset(frame, 0, sizeof(*frame));
- if (hwmb->mb_cs.cs.ide)
+ if (hwmb->mb_cs & MB_CS_IDE_MASK)
frame->can_id =
(hwmb->mb_id & CAN_EFF_MASK) | CAN_EFF_FLAG;
else
frame->can_id =
(hwmb->mb_id >> 18) & CAN_SFF_MASK;
- if (hwmb->mb_cs.cs.rtr)
+ if (hwmb->mb_cs & MB_CS_RTR_MASK)
frame->can_id |= CAN_RTR_FLAG;
- frame->can_dlc = hwmb->mb_cs.cs.length;
+ frame->can_dlc =
+ (hwmb->mb_cs & MB_CS_LENGTH_MASK) >>
+ MB_CS_LENGTH_OFFSET;
if (frame->can_dlc && (frame->can_dlc <= 8))
flexcan_memcpy(frame->data, hwmb->mb_data,
@@ -158,7 +165,7 @@ static void flexcan_fifo_isr(struct net_device *dev, unsigned int iflag1)
skb->ip_summed = CHECKSUM_UNNECESSARY;
netif_rx(skb);
} else {
- tmp = hwmb->mb_cs.data;
+ tmp = hwmb->mb_cs;
tmp = hwmb->mb_id;
tmp = hwmb->mb_data[0];
tmp = __raw_readl(flexcan->io_base + CAN_HW_REG_TIMER);
@@ -252,7 +259,8 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame)
struct can_hw_mb *hwmb = flexcan->hwmb;
do {
- if (hwmb[i].mb_cs.cs.code == CAN_MB_TX_INACTIVE)
+ if ((hwmb[i].mb_cs & MB_CS_CODE_MASK) >> MB_CS_CODE_OFFSET ==
+ CAN_MB_TX_INACTIVE)
break;
if ((++i) > flexcan->maxmb) {
if (flexcan->fifo)
@@ -273,22 +281,24 @@ int flexcan_mbm_xmit(struct flexcan_device *flexcan, struct can_frame *frame)
}
if (frame->can_id & CAN_RTR_FLAG)
- hwmb[i].mb_cs.cs.rtr = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_RTR_OFFSET;
else
- hwmb[i].mb_cs.cs.rtr = 0;
+ hwmb[i].mb_cs &= ~MB_CS_RTR_MASK;
if (frame->can_id & CAN_EFF_FLAG) {
- hwmb[i].mb_cs.cs.ide = 1;
- hwmb[i].mb_cs.cs.srr = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET;
+ hwmb[i].mb_cs |= 1 << MB_CS_SRR_OFFSET;
hwmb[i].mb_id = frame->can_id & CAN_EFF_MASK;
} else {
- hwmb[i].mb_cs.cs.ide = 0;
+ hwmb[i].mb_cs &= ~MB_CS_IDE_MASK;
hwmb[i].mb_id = (frame->can_id & CAN_SFF_MASK) << 18;
}
- hwmb[i].mb_cs.cs.length = frame->can_dlc;
+ hwmb[i].mb_cs &= ~MB_CS_LENGTH_MASK;
+ hwmb[i].mb_cs |= frame->can_dlc << MB_CS_LENGTH_OFFSET;
flexcan_memcpy(hwmb[i].mb_data, frame->data, frame->can_dlc);
- hwmb[i].mb_cs.cs.code = CAN_MB_TX_ONCE;
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_TX_ONCE << MB_CS_CODE_OFFSET;
return 0;
}
@@ -325,23 +335,27 @@ void flexcan_mbm_init(struct flexcan_device *flexcan)
id_table[i] = 0;
} else {
for (i = 0; i < rx_mb; i++) {
- hwmb[i].mb_cs.cs.code = CAN_MB_RX_EMPTY;
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_RX_EMPTY << MB_CS_CODE_OFFSET;
/*
* IDE bit can not control by mask registers
* So set message buffer to receive extend
* or standard message.
*/
- if (flexcan->ext_msg && flexcan->std_msg)
- hwmb[i].mb_cs.cs.ide = i & 1;
- else {
+ if (flexcan->ext_msg && flexcan->std_msg) {
+ hwmb[i].mb_cs &= ~MB_CS_IDE_MASK;
+ hwmb[i].mb_cs |= (i & 1) << MB_CS_IDE_OFFSET;
+ } else {
if (flexcan->ext_msg)
- hwmb[i].mb_cs.cs.ide = 1;
+ hwmb[i].mb_cs |= 1 << MB_CS_IDE_OFFSET;
}
}
}
- for (; i <= flexcan->maxmb; i++)
- hwmb[i].mb_cs.cs.code = CAN_MB_TX_INACTIVE;
+ for (; i <= flexcan->maxmb; i++) {
+ hwmb[i].mb_cs &= ~MB_CS_CODE_MASK;
+ hwmb[i].mb_cs |= CAN_MB_TX_INACTIVE << MB_CS_CODE_OFFSET;
+ }
flexcan->xmit_mb = rx_mb;
}
diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c
index 582eb37390ed..8a34f4679fa5 100644
--- a/drivers/net/enc28j60.c
+++ b/drivers/net/enc28j60.c
@@ -30,8 +30,6 @@
#include <linux/delay.h>
#include <linux/spi/spi.h>
-#include <mach/platform.h>
-
#include "enc28j60_hw.h"
#define DRV_NAME "enc28j60"
@@ -53,9 +51,17 @@
#define MAX_TX_RETRYCOUNT 16
#ifdef CONFIG_ARCH_STMP3XXX
+#include <mach/platform.h>
#include <mach/stmp3xxx.h>
#include <mach/regs-ocotp.h>
#endif
+#ifdef CONFIG_ARCH_MXS
+#include <mach/system.h>
+#include <mach/hardware.h>
+#include <mach/regs-ocotp.h>
+#define REGS_OCOTP_BASE IO_ADDRESS(OCOTP_PHYS_ADDR)
+#endif
+
enum {
RXFILTER_NORMAL,
RXFILTER_MULTI,
@@ -104,12 +110,14 @@ static int enc28j60_get_mac(unsigned char *dev_addr, int idx)
return false;
if (!mac[idx]) {
-#ifdef CONFIG_ARCH_STMP3XXX
+#if defined(CONFIG_ARCH_STMP3XXX) || defined(CONFIG_ARCH_MXS)
if (get_evk_board_version() >= 1) {
int mac1 , mac2 , retry = 0;
- stmp3xxx_setl(BM_OCOTP_CTRL_RD_BANK_OPEN, REGS_OCOTP_BASE + HW_OCOTP_CTRL);
- while (__raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL) & BM_OCOTP_CTRL_BUSY) {
+ __raw_writel(BM_OCOTP_CTRL_RD_BANK_OPEN,
+ REGS_OCOTP_BASE + HW_OCOTP_CTRL_SET);
+ while (__raw_readl(REGS_OCOTP_BASE + HW_OCOTP_CTRL) &
+ BM_OCOTP_CTRL_BUSY) {
msleep(10);
retry++;
if (retry > 10)
diff --git a/drivers/net/fec.c b/drivers/net/fec.c
index 46799e092bc1..206be36f0d19 100644
--- a/drivers/net/fec.c
+++ b/drivers/net/fec.c
@@ -296,6 +296,17 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
bufaddr = fep->tx_bounce[index];
}
+ if (fep->ptimer_present) {
+ if (fec_ptp_do_txstamp(skb))
+ estatus = BD_ENET_TX_TS;
+ else
+ estatus = 0;
+#ifdef CONFIG_FEC_1588
+ bdp->cbd_esc = (estatus | BD_ENET_TX_INT);
+ bdp->cbd_bdu = 0;
+#endif
+ }
+
#ifdef CONFIG_ARCH_MXS
swap_buffer(bufaddr, skb->len);
#endif
@@ -318,16 +329,6 @@ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
| BD_ENET_TX_LAST | BD_ENET_TX_TC);
bdp->cbd_sc = status;
- if (fep->ptimer_present) {
- if (fec_ptp_do_txstamp(skb))
- estatus = BD_ENET_TX_TS;
- else
- estatus = 0;
-#ifdef CONFIG_FEC_1588
- bdp->cbd_esc = (estatus | BD_ENET_TX_INT);
- bdp->cbd_bdu = 0;
-#endif
- }
dev->trans_start = jiffies;
/* Trigger transmission start */
@@ -807,7 +808,7 @@ static struct mii_bus *fec_enet_mii_init(struct platform_device *pdev)
{
struct net_device *dev = platform_get_drvdata(pdev);
struct fec_enet_private *fep = netdev_priv(dev);
- struct fec_enet_platform_data *pdata;
+ struct fec_platform_data *pdata;
int err = -ENXIO, i;
fep->mii_timeout = 0;
@@ -836,6 +837,7 @@ static struct mii_bus *fec_enet_mii_init(struct platform_device *pdev)
fep->mii_bus->priv = fep;
fep->mii_bus->parent = &pdev->dev;
pdata = pdev->dev.platform_data;
+ fep->mii_bus->phy_mask = pdata->phy_mask;
fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
if (!fep->mii_bus->irq) {
@@ -1131,17 +1133,18 @@ fec_set_mac_address(struct net_device *dev, void *p)
{
struct fec_enet_private *fep = netdev_priv(dev);
struct sockaddr *addr = p;
+ u32 temp_mac[2];
if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
- writel(dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
- (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24),
- fep->hwp + FEC_ADDR_LOW);
- writel((dev->dev_addr[5] << 16) | (dev->dev_addr[4] << 24),
- fep + FEC_ADDR_HIGH);
+ memcpy(&temp_mac, dev->dev_addr, ETH_ALEN);
+
+ writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW);
+ writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH);
+
return 0;
}
@@ -1277,6 +1280,7 @@ fec_restart(struct net_device *dev, int duplex)
/* Clear any outstanding interrupt. */
writel(0xffc00000, fep->hwp + FEC_IEVENT);
+#if !defined(CONFIG_MACH_CCMX51JS) && !defined(CONFIG_MACH_CCWMX51JS)
/* Reset all multicast. */
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW);
@@ -1284,6 +1288,7 @@ fec_restart(struct net_device *dev, int duplex)
writel(0, fep->hwp + FEC_HASH_TABLE_HIGH);
writel(0, fep->hwp + FEC_HASH_TABLE_LOW);
#endif
+#endif /* !defined(CONFIG_MACH_CCMX51JS) && !defined(CONFIG_MACH_CCWMX51JS) */
#ifndef CONFIG_ARCH_MXS
if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) {
@@ -1407,6 +1412,15 @@ fec_stop(struct net_device *dev)
writel(1, fep->hwp + FEC_ECNTRL);
udelay(10);
+#ifdef CONFIG_ARCH_MXS
+ /* Check MII or RMII */
+ if (fep->phy_interface == PHY_INTERFACE_MODE_RMII)
+ writel(readl(fep->hwp + FEC_R_CNTRL) | 0x100,
+ fep->hwp + FEC_R_CNTRL);
+ else
+ writel(readl(fep->hwp + FEC_R_CNTRL) & ~0x100,
+ fep->hwp + FEC_R_CNTRL);
+#endif
/* Clear outstanding MII command interrupts. */
writel(FEC_ENET_MII, fep->hwp + FEC_IEVENT);
@@ -1482,6 +1496,18 @@ fec_probe(struct platform_device *pdev)
fep->phy_interface = pdata->phy;
if (pdata->init && pdata->init())
goto failed_platform_init;
+
+ /*
+ * The priority for getting MAC address is:
+ * (1) kernel command line fec_mac = xx:xx:xx...
+ * (2) platform data mac field got from fuse etc
+ * (3) bootloader set the FEC mac register
+ */
+
+ if (!is_valid_ether_addr(fec_mac_default) &&
+ pdata->mac && is_valid_ether_addr(pdata->mac))
+ memcpy(fec_mac_default, pdata->mac,
+ sizeof(fec_mac_default));
} else
fep->phy_interface = PHY_INTERFACE_MODE_MII;
@@ -1499,10 +1525,10 @@ fec_probe(struct platform_device *pdev)
fep->mii_bus = fec_mii_bus;
}
- fep->ptp_priv = kmalloc(sizeof(struct fec_ptp_private), GFP_KERNEL);
+ fep->ptp_priv = kzalloc(sizeof(struct fec_ptp_private), GFP_KERNEL);
if (fep->ptp_priv) {
fep->ptp_priv->hwp = fep->hwp;
- ret = fec_ptp_init(fep->ptp_priv);
+ ret = fec_ptp_init(fep->ptp_priv, pdev->id);
if (ret)
printk(KERN_WARNING
"IEEE1588: ptp-timer is unavailable\n");
diff --git a/drivers/net/fec_1588.c b/drivers/net/fec_1588.c
index 5babcc29de78..c4bf278c7f19 100644
--- a/drivers/net/fec_1588.c
+++ b/drivers/net/fec_1588.c
@@ -35,7 +35,7 @@
static DECLARE_WAIT_QUEUE_HEAD(ptp_rx_ts_wait);
#define PTP_GET_RX_TIMEOUT (HZ/10)
-static struct fec_ptp_private *ptp_private;
+static struct fec_ptp_private *ptp_private[2];
/* Alloc the ring resource */
static int fec_ptp_init_circ(struct circ_buf *ptp_buf)
@@ -88,14 +88,15 @@ static int fec_ptp_is_full(struct circ_buf *buf)
}
static int fec_ptp_insert(struct circ_buf *ptp_buf,
- struct fec_ptp_data_t *data)
+ struct fec_ptp_data_t *data,
+ struct fec_ptp_private *priv)
{
struct fec_ptp_data_t *tmp;
if (fec_ptp_is_full(ptp_buf))
return 1;
- spin_lock(&ptp_private->ptp_lock);
+ spin_lock(&priv->ptp_lock);
tmp = (struct fec_ptp_data_t *)(ptp_buf->buf) + ptp_buf->tail;
tmp->key = data->key;
@@ -104,13 +105,15 @@ static int fec_ptp_insert(struct circ_buf *ptp_buf,
ptp_buf->tail = fec_ptp_calc_index(DEFAULT_PTP_RX_BUF_SZ,
ptp_buf->tail, 1);
- spin_unlock(&ptp_private->ptp_lock);
+ spin_unlock(&priv->ptp_lock);
return 0;
}
static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
- int key, struct fec_ptp_data_t *data)
+ int key,
+ struct fec_ptp_data_t *data,
+ struct fec_ptp_private *priv)
{
int i;
int size = DEFAULT_PTP_RX_BUF_SZ;
@@ -129,10 +132,10 @@ static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
i = fec_ptp_calc_index(size, i, 1);
}
- spin_lock_irqsave(&ptp_private->ptp_lock, flags);
+ spin_lock_irqsave(&priv->ptp_lock, flags);
if (i == end) {
ptp_buf->head = end;
- spin_unlock_irqrestore(&ptp_private->ptp_lock, flags);
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
return 1;
}
@@ -140,7 +143,7 @@ static int fec_ptp_find_and_remove(struct circ_buf *ptp_buf,
data->ts_time.nsec = tmp->ts_time.nsec;
ptp_buf->head = fec_ptp_calc_index(size, i, 1);
- spin_unlock_irqrestore(&ptp_private->ptp_lock, flags);
+ spin_unlock_irqrestore(&priv->ptp_lock, flags);
return 0;
}
@@ -154,9 +157,9 @@ int fec_ptp_start(struct fec_ptp_private *priv)
writel(FEC_T_CTRL_RESTART, fpp->hwp + FEC_ATIME_CTRL);
writel(FEC_T_INC_40MHZ << FEC_T_INC_OFFSET, fpp->hwp + FEC_ATIME_INC);
writel(FEC_T_PERIOD_ONE_SEC, fpp->hwp + FEC_ATIME_EVT_PERIOD);
- writel(FEC_T_CTRL_PERIOD_RST, fpp->hwp + FEC_ATIME_CTRL);
/* start counter */
- writel(FEC_T_CTRL_ENABLE, fpp->hwp + FEC_ATIME_CTRL);
+ writel(FEC_T_CTRL_PERIOD_RST | FEC_T_CTRL_ENABLE,
+ fpp->hwp + FEC_ATIME_CTRL);
return 0;
}
@@ -175,12 +178,19 @@ void fec_ptp_stop(struct fec_ptp_private *priv)
static void fec_get_curr_cnt(struct fec_ptp_private *priv,
struct ptp_rtc_time *curr_time)
{
+ u32 tempval;
+
+ writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL);
writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL);
curr_time->rtc_time.nsec = readl(priv->hwp + FEC_ATIME);
curr_time->rtc_time.sec = priv->prtc;
+
writel(FEC_T_CTRL_CAPTURE, priv->hwp + FEC_ATIME_CTRL);
- if (readl(priv->hwp + FEC_ATIME) < curr_time->rtc_time.nsec)
- curr_time->rtc_time.sec++;
+ tempval = readl(priv->hwp + FEC_ATIME);
+ if (tempval < curr_time->rtc_time.nsec) {
+ curr_time->rtc_time.nsec = tempval;
+ curr_time->rtc_time.sec = priv->prtc;
+ }
}
/* Set the 1588 timer counter registers */
@@ -190,12 +200,12 @@ static void fec_set_1588cnt(struct fec_ptp_private *priv,
u32 tempval;
unsigned long flags;
- spin_lock_irqsave(&ptp_private->cnt_lock, flags);
+ spin_lock_irqsave(&priv->cnt_lock, flags);
priv->prtc = fec_time->rtc_time.sec;
tempval = fec_time->rtc_time.nsec;
writel(tempval, priv->hwp + FEC_ATIME);
- spin_unlock_irqrestore(&ptp_private->cnt_lock, flags);
+ spin_unlock_irqrestore(&priv->cnt_lock, flags);
}
/* Set the BD to ptp */
@@ -207,11 +217,11 @@ int fec_ptp_do_txstamp(struct sk_buff *skb)
if (skb->len > 44) {
/* Check if port is 319 for PTP Event, and check for UDP */
iph = ip_hdr(skb);
- if (iph->protocol != FEC_PACKET_TYPE_UDP)
+ if (iph == NULL || iph->protocol != FEC_PACKET_TYPE_UDP)
return 0;
udph = udp_hdr(skb);
- if (udph->source == 319)
+ if (udph != NULL && ntohs(udph->source) == 319)
return 1;
}
@@ -244,24 +254,24 @@ void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
return;
udph = (struct udphdr *)(skb->data + FEC_PTP_UDP_OFFS);
- if (udph->source != 319)
+ if (ntohs(udph->source) != 319)
return;
seq_id = *((u16 *)(skb->data + FEC_PTP_SEQ_ID_OFFS));
control = *((u8 *)(skb->data + FEC_PTP_CTRL_OFFS));
- tmp_rx_time.key = seq_id;
+ tmp_rx_time.key = ntohs(seq_id);
tmp_rx_time.ts_time.sec = fpp->prtc;
tmp_rx_time.ts_time.nsec = bdp->ts;
switch (control) {
case PTP_MSG_SYNC:
- fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time);
+ fec_ptp_insert(&(priv->rx_time_sync), &tmp_rx_time, priv);
break;
case PTP_MSG_DEL_REQ:
- fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time);
+ fec_ptp_insert(&(priv->rx_time_del_req), &tmp_rx_time, priv);
break;
/* clear transportSpecific field*/
@@ -271,11 +281,11 @@ void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
switch (msg_type) {
case PTP_MSG_P_DEL_REQ:
fec_ptp_insert(&(priv->rx_time_pdel_req),
- &tmp_rx_time);
+ &tmp_rx_time, priv);
break;
case PTP_MSG_P_DEL_RESP:
fec_ptp_insert(&(priv->rx_time_pdel_resp),
- &tmp_rx_time);
+ &tmp_rx_time, priv);
break;
default:
break;
@@ -308,20 +318,20 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv,
switch (mode) {
case PTP_MSG_SYNC:
flag = fec_ptp_find_and_remove(&(priv->rx_time_sync),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_DEL_REQ:
flag = fec_ptp_find_and_remove(&(priv->rx_time_del_req),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_P_DEL_REQ:
flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_req),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_P_DEL_RESP:
flag = fec_ptp_find_and_remove(&(priv->rx_time_pdel_resp),
- key, &tmp);
+ key, &tmp, priv);
break;
default:
@@ -341,19 +351,19 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv,
switch (mode) {
case PTP_MSG_SYNC:
flag = fec_ptp_find_and_remove(&(priv->rx_time_sync),
- key, &tmp);
+ key, &tmp, priv);
break;
case PTP_MSG_DEL_REQ:
flag = fec_ptp_find_and_remove(
- &(priv->rx_time_del_req), key, &tmp);
+ &(priv->rx_time_del_req), key, &tmp, priv);
break;
case PTP_MSG_P_DEL_REQ:
flag = fec_ptp_find_and_remove(
- &(priv->rx_time_pdel_req), key, &tmp);
+ &(priv->rx_time_pdel_req), key, &tmp, priv);
break;
case PTP_MSG_P_DEL_RESP:
flag = fec_ptp_find_and_remove(
- &(priv->rx_time_pdel_resp), key, &tmp);
+ &(priv->rx_time_pdel_resp), key, &tmp, priv);
break;
}
@@ -367,6 +377,75 @@ static uint8_t fec_get_rx_time(struct fec_ptp_private *priv,
}
}
+static void fec_handle_ptpdrift(struct ptp_set_comp *comp,
+ struct ptp_time_correct *ptc)
+{
+ u32 ndrift;
+ u32 i;
+ u32 tmp, tmp_ns, tmp_prid;
+ u32 min_ns, min_prid, miss_ns;
+
+ ndrift = comp->drift;
+ if (ndrift == 0) {
+ ptc->corr_inc = 0;
+ ptc->corr_period = 0;
+ return;
+ }
+
+ if (ndrift >= FEC_ATIME_40MHZ) {
+ ptc->corr_inc = (u32)(ndrift / FEC_ATIME_40MHZ);
+ ptc->corr_period = 1;
+ return;
+ }
+
+ min_ns = 1;
+ tmp = FEC_ATIME_40MHZ % ndrift;
+ tmp_prid = (u32)(FEC_ATIME_40MHZ / ndrift);
+ min_prid = tmp_prid;
+ miss_ns = tmp / tmp_prid;
+ for (i = 2; i <= FEC_T_INC_40MHZ; i++) {
+ tmp = (FEC_ATIME_40MHZ * i) % ndrift;
+ tmp_prid = (FEC_ATIME_40MHZ * i) / ndrift;
+ tmp_ns = tmp / tmp_prid;
+ if (tmp_ns <= 10) {
+ min_ns = i;
+ min_prid = tmp_prid;
+ break;
+ }
+ if (tmp_ns < miss_ns) {
+ min_ns = i;
+ min_prid = tmp_prid;
+ miss_ns = tmp_ns;
+ }
+ }
+
+ ptc->corr_inc = min_ns;
+ ptc->corr_period = min_prid;
+}
+
+static void fec_set_drift(struct fec_ptp_private *priv,
+ struct ptp_set_comp *comp)
+{
+ struct ptp_time_correct tc;
+ struct fec_ptp_private *fpp = priv;
+ u32 tmp, corr_ns;
+
+ fec_handle_ptpdrift(comp, &tc);
+ if (tc.corr_inc == 0)
+ return;
+
+ if (comp->o_ops == TRUE)
+ corr_ns = FEC_T_INC_40MHZ + tc.corr_inc;
+ else
+ corr_ns = FEC_T_INC_40MHZ - tc.corr_inc;
+
+ tmp = readl(fpp->hwp + FEC_ATIME_INC) & FEC_T_INC_MASK;
+ tmp |= corr_ns << FEC_T_INC_CORR_OFFSET;
+ writel(tmp, fpp->hwp + FEC_ATIME_INC);
+
+ writel(tc.corr_period, fpp->hwp + FEC_ATIME_CORR);
+}
+
static int ptp_open(struct inode *inode, struct file *file)
{
return 0;
@@ -387,10 +466,12 @@ static int ptp_ioctl(
struct ptp_rtc_time curr_time;
struct ptp_time rx_time, tx_time;
struct ptp_ts_data *p_ts;
+ struct ptp_set_comp *p_comp;
struct fec_ptp_private *priv;
+ unsigned int minor = MINOR(inode->i_rdev);
int retval = 0;
- priv = (struct fec_ptp_private *) ptp_private;
+ priv = (struct fec_ptp_private *) ptp_private[minor];
switch (cmd) {
case PTP_GET_RX_TIMESTAMP:
p_ts = (struct ptp_ts_data *)arg;
@@ -428,10 +509,11 @@ static int ptp_ioctl(
priv->rx_time_pdel_resp.tail = 0;
break;
case PTP_SET_COMPENSATION:
- /* TBD */
+ p_comp = (struct ptp_set_comp *)arg;
+ fec_set_drift(priv, p_comp);
break;
case PTP_GET_ORIG_COMP:
- /* TBD */
+ ((struct ptp_get_comp *)arg)->dw_origcomp = FEC_PTP_ORIG_COMP;
break;
default:
return -EINVAL;
@@ -466,7 +548,7 @@ static void ptp_free(void)
/*
* Resource required for accessing 1588 Timer Registers.
*/
-int fec_ptp_init(struct fec_ptp_private *priv)
+int fec_ptp_init(struct fec_ptp_private *priv, int id)
{
fec_ptp_init_circ(&(priv->rx_time_sync));
fec_ptp_init_circ(&(priv->rx_time_del_req));
@@ -475,8 +557,9 @@ int fec_ptp_init(struct fec_ptp_private *priv)
spin_lock_init(&priv->ptp_lock);
spin_lock_init(&priv->cnt_lock);
- ptp_private = priv;
- init_ptp();
+ ptp_private[id] = priv;
+ if (id == 0)
+ init_ptp();
return 0;
}
EXPORT_SYMBOL(fec_ptp_init);
diff --git a/drivers/net/fec_1588.h b/drivers/net/fec_1588.h
index 55b1a8c995bd..800ff310668f 100644
--- a/drivers/net/fec_1588.h
+++ b/drivers/net/fec_1588.h
@@ -24,6 +24,9 @@
#include <linux/circ_buf.h>
+#define FALSE 0
+#define TRUE 1
+
/* FEC 1588 register bits */
#define FEC_T_CTRL_CAPTURE 0x00000800
#define FEC_T_CTRL_RESTART 0x00000200
@@ -32,8 +35,11 @@
#define FEC_T_INC_MASK 0x0000007f
#define FEC_T_INC_OFFSET 0
+#define FEC_T_INC_CORR_MASK 0x00007f00
+#define FEC_T_INC_CORR_OFFSET 8
-#define FEC_T_INC_40MHZ 20
+#define FEC_T_INC_40MHZ 25
+#define FEC_ATIME_40MHZ 40000000
#define FEC_T_PERIOD_ONE_SEC 0x3B9ACA00
@@ -52,7 +58,7 @@
#define PTP_MSG_ALL_OTHER 0x5
#define PTP_GET_TX_TIMESTAMP 0x1
-#define PTP_GET_RX_TIMESTAMP 0x2
+#define PTP_GET_RX_TIMESTAMP 0x9
#define PTP_SET_RTC_TIME 0x3
#define PTP_SET_COMPENSATION 0x4
#define PTP_GET_CURRENT_TIME 0x5
@@ -64,13 +70,15 @@
#define PTP_GET_RX_TIMESTAMP_PDELAY_RESP 0xD
#define FEC_PTP_DOMAIN_DLFT 0xe0000181
-#define FEC_PTP_IP_OFFS 0xE
-#define FEC_PTP_UDP_OFFS 0x22
-#define FEC_PTP_MSG_TYPE_OFFS 0x2A
-#define FEC_PTP_SEQ_ID_OFFS 0x48
-#define FEC_PTP_CTRL_OFFS 0x4A
+#define FEC_PTP_IP_OFFS 0x0
+#define FEC_PTP_UDP_OFFS 0x14
+#define FEC_PTP_MSG_TYPE_OFFS 0x1C
+#define FEC_PTP_SEQ_ID_OFFS 0x3A
+#define FEC_PTP_CTRL_OFFS 0x3C
#define FEC_PACKET_TYPE_UDP 0x11
+#define FEC_PTP_ORIG_COMP 0x15555555
+
/* PTP standard time representation structure */
struct ptp_time{
u64 sec; /* seconds */
@@ -102,6 +110,31 @@ struct ptp_rtc_time {
struct ptp_time rtc_time;
};
+/* interface for PTP driver command SET_COMPENSATION */
+struct ptp_set_comp {
+ u32 drift;
+ bool o_ops;
+};
+
+/* interface for PTP driver command GET_ORIG_COMP */
+struct ptp_get_comp {
+ /* the initial compensation value */
+ u32 dw_origcomp;
+ /* the minimum compensation value */
+ u32 dw_mincomp;
+ /*the max compensation value*/
+ u32 dw_maxcomp;
+ /*the min drift applying min compensation value in ppm*/
+ u32 dw_mindrift;
+ /*the max drift applying max compensation value in ppm*/
+ u32 dw_maxdrift;
+};
+
+struct ptp_time_correct {
+ u32 corr_period;
+ u32 corr_inc;
+};
+
/* PTP message version */
#define PTP_1588_MSG_VER_1 1
#define PTP_1588_MSG_VER_2 2
@@ -124,7 +157,7 @@ struct fec_ptp_private {
};
#ifdef CONFIG_FEC_1588
-extern int fec_ptp_init(struct fec_ptp_private *priv);
+extern int fec_ptp_init(struct fec_ptp_private *priv, int id);
extern void fec_ptp_cleanup(struct fec_ptp_private *priv);
extern int fec_ptp_start(struct fec_ptp_private *priv);
extern void fec_ptp_stop(struct fec_ptp_private *priv);
@@ -134,7 +167,7 @@ extern void fec_ptp_store_rxstamp(struct fec_ptp_private *priv,
struct sk_buff *skb,
struct bufdesc *bdp);
#else
-static inline int fec_ptp_init(struct fec_ptp_private *priv)
+static inline int fec_ptp_init(struct fec_ptp_private *priv, int id)
{
return 1;
}
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index bd4e8d72dc08..e17b70291bbc 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -264,6 +264,8 @@ static int mdio_bus_match(struct device *dev, struct device_driver *drv)
(phydev->phy_id & phydrv->phy_id_mask));
}
+#ifdef CONFIG_PM
+
static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
{
struct device_driver *drv = phydev->dev.driver;
@@ -295,34 +297,88 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
return true;
}
-/* Suspend and resume. Copied from platform_suspend and
- * platform_resume
- */
-static int mdio_bus_suspend(struct device * dev, pm_message_t state)
+static int mdio_bus_suspend(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
+ /*
+ * We must stop the state machine manually, otherwise it stops out of
+ * control, possibly with the phydev->lock held. Upon resume, netdev
+ * may call phy routines that try to grab the same lock, and that may
+ * lead to a deadlock.
+ */
+ if (phydev->attached_dev)
+ phy_stop_machine(phydev);
+
if (!mdio_bus_phy_may_suspend(phydev))
return 0;
+
return phydrv->suspend(phydev);
}
-static int mdio_bus_resume(struct device * dev)
+static int mdio_bus_resume(struct device *dev)
{
struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
+ int ret;
if (!mdio_bus_phy_may_suspend(phydev))
+ goto no_resume;
+
+ ret = phydrv->resume(phydev);
+ if (ret < 0)
+ return ret;
+
+no_resume:
+ if (phydev->attached_dev)
+ phy_start_machine(phydev, NULL);
+
+ return 0;
+}
+
+static int mdio_bus_restore(struct device *dev)
+{
+ struct phy_device *phydev = to_phy_device(dev);
+ struct net_device *netdev = phydev->attached_dev;
+ int ret;
+
+ if (!netdev)
return 0;
- return phydrv->resume(phydev);
+
+ ret = phy_init_hw(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* The PHY needs to renegotiate. */
+ phydev->link = 0;
+ phydev->state = PHY_UP;
+
+ phy_start_machine(phydev, NULL);
+
+ return 0;
}
+static struct dev_pm_ops mdio_bus_pm_ops = {
+ .suspend = mdio_bus_suspend,
+ .resume = mdio_bus_resume,
+ .freeze = mdio_bus_suspend,
+ .thaw = mdio_bus_resume,
+ .restore = mdio_bus_restore,
+};
+
+#define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops)
+
+#else
+
+#define MDIO_BUS_PM_OPS NULL
+
+#endif /* CONFIG_PM */
+
struct bus_type mdio_bus_type = {
.name = "mdio_bus",
.match = mdio_bus_match,
- .suspend = mdio_bus_suspend,
- .resume = mdio_bus_resume,
+ .pm = MDIO_BUS_PM_OPS,
};
EXPORT_SYMBOL(mdio_bus_type);
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index eda94fcd4065..d2df6382e123 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -413,7 +413,6 @@ EXPORT_SYMBOL(phy_start_aneg);
static void phy_change(struct work_struct *work);
-static void phy_state_machine(struct work_struct *work);
/**
* phy_start_machine - start PHY state machine tracking
@@ -433,7 +432,6 @@ void phy_start_machine(struct phy_device *phydev,
{
phydev->adjust_state = handler;
- INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine);
schedule_delayed_work(&phydev->state_queue, HZ);
}
@@ -764,7 +762,7 @@ EXPORT_SYMBOL(phy_start);
* phy_state_machine - Handle the state machine
* @work: work_struct that describes the work to be done
*/
-static void phy_state_machine(struct work_struct *work)
+void phy_state_machine(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct phy_device *phydev =
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index b10fedd82143..adbc0fded130 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -177,6 +177,7 @@ struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
dev->state = PHY_DOWN;
mutex_init(&dev->lock);
+ INIT_DELAYED_WORK(&dev->state_queue, phy_state_machine);
return dev;
}
@@ -378,6 +379,20 @@ void phy_disconnect(struct phy_device *phydev)
}
EXPORT_SYMBOL(phy_disconnect);
+int phy_init_hw(struct phy_device *phydev)
+{
+ int ret;
+
+ if (!phydev->drv || !phydev->drv->config_init)
+ return 0;
+
+ ret = phy_scan_fixups(phydev);
+ if (ret < 0)
+ return ret;
+
+ return phydev->drv->config_init(phydev);
+}
+
/**
* phy_attach_direct - attach a network device to a given PHY device pointer
* @dev: network device to attach
@@ -425,21 +440,7 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
/* Do initial configuration here, now that
* we have certain key parameters
* (dev_flags and interface) */
- if (phydev->drv->config_init) {
- int err;
-
- err = phy_scan_fixups(phydev);
-
- if (err < 0)
- return err;
-
- err = phydev->drv->config_init(phydev);
-
- if (err < 0)
- return err;
- }
-
- return 0;
+ return phy_init_hw(phydev);
}
EXPORT_SYMBOL(phy_attach_direct);
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index d4c82f5fa555..a13d107a412b 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -789,6 +789,7 @@ static void smsc911x_phy_adjust_link(struct net_device *dev)
}
pdata->last_carrier = carrier;
}
+ udelay(10);
}
static int smsc911x_mii_probe(struct net_device *dev)
@@ -1011,7 +1012,7 @@ static int smsc911x_poll(struct napi_struct *napi, int budget)
struct net_device *dev = pdata->dev;
int npackets = 0;
- while (likely(netif_running(dev)) && (npackets < budget)) {
+ while (npackets < budget) {
unsigned int pktlength;
unsigned int pktwords;
struct sk_buff *skb;
@@ -1584,7 +1585,7 @@ static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id)
if (unlikely(intsts & inten & INT_STS_PHY_INT_)) {
smsc911x_reg_write( pdata, INT_STS , INT_STS_PHY_INT_);
temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, MII_INTSTS);
- SMSC_TRACE("PHY interrupt, sts 0x%04X", (u16)temp);
+ SMSC_TRACE(DRV,"PHY interrupt, sts 0x%04X", (u16)temp);
smsc911x_phy_adjust_link(dev);
serviced = IRQ_HANDLED;
}
diff --git a/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c b/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c
index 1ca77e513493..9d0c3773d4d7 100644
--- a/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c
+++ b/drivers/net/wireless/ath6kl/os/linux/ar6000_android.c
@@ -56,7 +56,7 @@ ATH_DEBUG_INSTANTIATE_MODULE_VAR(android,
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
-char fwpath[256] = "/system/wifi";
+char fwpath[256] = "/lib/firmware/ath6k/AR6102";
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
int buspm = WLAN_PWR_CTRL_CUT_PWR;
int wow2mode = WLAN_PWR_CTRL_CUT_PWR;