aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/fec_mpc52xx.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/fec_mpc52xx.c')
-rw-r--r--drivers/net/fec_mpc52xx.c120
1 files changed, 87 insertions, 33 deletions
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c
index e5e6352556fa..5f9c42e7a7f1 100644
--- a/drivers/net/fec_mpc52xx.c
+++ b/drivers/net/fec_mpc52xx.c
@@ -43,6 +43,29 @@
43 43
44#define DRIVER_NAME "mpc52xx-fec" 44#define DRIVER_NAME "mpc52xx-fec"
45 45
46#define FEC5200_PHYADDR_NONE (-1)
47#define FEC5200_PHYADDR_7WIRE (-2)
48
49/* Private driver data structure */
50struct mpc52xx_fec_priv {
51 int duplex;
52 int speed;
53 int r_irq;
54 int t_irq;
55 struct mpc52xx_fec __iomem *fec;
56 struct bcom_task *rx_dmatsk;
57 struct bcom_task *tx_dmatsk;
58 spinlock_t lock;
59 int msg_enable;
60
61 /* MDIO link details */
62 int phy_addr;
63 unsigned int phy_speed;
64 struct phy_device *phydev;
65 enum phy_state link;
66};
67
68
46static irqreturn_t mpc52xx_fec_interrupt(int, void *); 69static irqreturn_t mpc52xx_fec_interrupt(int, void *);
47static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *); 70static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *);
48static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *); 71static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *);
@@ -223,7 +246,7 @@ static int mpc52xx_fec_phy_start(struct net_device *dev)
223 struct mpc52xx_fec_priv *priv = netdev_priv(dev); 246 struct mpc52xx_fec_priv *priv = netdev_priv(dev);
224 int err; 247 int err;
225 248
226 if (!priv->has_phy) 249 if (priv->phy_addr < 0)
227 return 0; 250 return 0;
228 251
229 err = mpc52xx_fec_init_phy(dev); 252 err = mpc52xx_fec_init_phy(dev);
@@ -243,7 +266,7 @@ static void mpc52xx_fec_phy_stop(struct net_device *dev)
243{ 266{
244 struct mpc52xx_fec_priv *priv = netdev_priv(dev); 267 struct mpc52xx_fec_priv *priv = netdev_priv(dev);
245 268
246 if (!priv->has_phy) 269 if (!priv->phydev)
247 return; 270 return;
248 271
249 phy_disconnect(priv->phydev); 272 phy_disconnect(priv->phydev);
@@ -255,7 +278,7 @@ static void mpc52xx_fec_phy_stop(struct net_device *dev)
255static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv, 278static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv,
256 struct mii_ioctl_data *mii_data, int cmd) 279 struct mii_ioctl_data *mii_data, int cmd)
257{ 280{
258 if (!priv->has_phy) 281 if (!priv->phydev)
259 return -ENOTSUPP; 282 return -ENOTSUPP;
260 283
261 return phy_mii_ioctl(priv->phydev, mii_data, cmd); 284 return phy_mii_ioctl(priv->phydev, mii_data, cmd);
@@ -265,7 +288,7 @@ static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv)
265{ 288{
266 struct mpc52xx_fec __iomem *fec = priv->fec; 289 struct mpc52xx_fec __iomem *fec = priv->fec;
267 290
268 if (!priv->has_phy) 291 if (priv->phydev)
269 return; 292 return;
270 293
271 out_be32(&fec->mii_speed, priv->phy_speed); 294 out_be32(&fec->mii_speed, priv->phy_speed);
@@ -491,20 +514,23 @@ static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id)
491 514
492 out_be32(&fec->ievent, ievent); /* clear pending events */ 515 out_be32(&fec->ievent, ievent); /* clear pending events */
493 516
494 if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) { 517 /* on fifo error, soft-reset fec */
495 if (ievent & ~FEC_IEVENT_TFINT) 518 if (ievent & (FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) {
496 dev_dbg(&dev->dev, "ievent: %08x\n", ievent); 519
520 if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR))
521 dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n");
522 if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
523 dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
524
525 mpc52xx_fec_reset(dev);
526
527 netif_wake_queue(dev);
497 return IRQ_HANDLED; 528 return IRQ_HANDLED;
498 } 529 }
499 530
500 if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR)) 531 if (ievent & ~FEC_IEVENT_TFINT)
501 dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n"); 532 dev_dbg(&dev->dev, "ievent: %08x\n", ievent);
502 if (net_ratelimit() && (ievent & FEC_IEVENT_XFIFO_ERROR))
503 dev_warn(&dev->dev, "FEC_IEVENT_XFIFO_ERROR\n");
504
505 mpc52xx_fec_reset(dev);
506 533
507 netif_wake_queue(dev);
508 return IRQ_HANDLED; 534 return IRQ_HANDLED;
509} 535}
510 536
@@ -701,7 +727,7 @@ static void mpc52xx_fec_start(struct net_device *dev)
701 rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */ 727 rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */
702 rcntrl |= FEC_RCNTRL_FCE; 728 rcntrl |= FEC_RCNTRL_FCE;
703 729
704 if (priv->has_phy) 730 if (priv->phy_addr != FEC5200_PHYADDR_7WIRE)
705 rcntrl |= FEC_RCNTRL_MII_MODE; 731 rcntrl |= FEC_RCNTRL_MII_MODE;
706 732
707 if (priv->duplex == DUPLEX_FULL) 733 if (priv->duplex == DUPLEX_FULL)
@@ -861,7 +887,10 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
861 struct net_device *ndev; 887 struct net_device *ndev;
862 struct mpc52xx_fec_priv *priv = NULL; 888 struct mpc52xx_fec_priv *priv = NULL;
863 struct resource mem; 889 struct resource mem;
864 const phandle *ph; 890 struct device_node *phy_node;
891 const phandle *phy_handle;
892 const u32 *prop;
893 int prop_size;
865 894
866 phys_addr_t rx_fifo; 895 phys_addr_t rx_fifo;
867 phys_addr_t tx_fifo; 896 phys_addr_t tx_fifo;
@@ -945,26 +974,37 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
945 mpc52xx_fec_get_paddr(ndev, ndev->dev_addr); 974 mpc52xx_fec_get_paddr(ndev, ndev->dev_addr);
946 975
947 priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT); 976 priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT);
948 priv->duplex = DUPLEX_FULL;
949 977
950 /* is the phy present in device tree? */ 978 /*
951 ph = of_get_property(op->node, "phy-handle", NULL); 979 * Link mode configuration
952 if (ph) { 980 */
953 const unsigned int *prop;
954 struct device_node *phy_dn;
955 priv->has_phy = 1;
956
957 phy_dn = of_find_node_by_phandle(*ph);
958 prop = of_get_property(phy_dn, "reg", NULL);
959 priv->phy_addr = *prop;
960 981
961 of_node_put(phy_dn); 982 /* Start with safe defaults for link connection */
983 priv->phy_addr = FEC5200_PHYADDR_NONE;
984 priv->speed = 100;
985 priv->duplex = DUPLEX_HALF;
986 priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1;
987
988 /* the 7-wire property means don't use MII mode */
989 if (of_find_property(op->node, "fsl,7-wire-mode", NULL))
990 priv->phy_addr = FEC5200_PHYADDR_7WIRE;
991
992 /* The current speed preconfigures the speed of the MII link */
993 prop = of_get_property(op->node, "current-speed", &prop_size);
994 if (prop && (prop_size >= sizeof(u32) * 2)) {
995 priv->speed = prop[0];
996 priv->duplex = prop[1] ? DUPLEX_FULL : DUPLEX_HALF;
997 }
962 998
963 /* Phy speed */ 999 /* If there is a phy handle, setup link to that phy */
964 priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; 1000 phy_handle = of_get_property(op->node, "phy-handle", &prop_size);
965 } else { 1001 if (phy_handle && (prop_size >= sizeof(phandle))) {
966 dev_info(&ndev->dev, "can't find \"phy-handle\" in device" 1002 phy_node = of_find_node_by_phandle(*phy_handle);
967 " tree, using 7-wire mode\n"); 1003 prop = of_get_property(phy_node, "reg", &prop_size);
1004 if (prop && (prop_size >= sizeof(u32)))
1005 if ((*prop >= 0) && (*prop < PHY_MAX_ADDR))
1006 priv->phy_addr = *prop;
1007 of_node_put(phy_node);
968 } 1008 }
969 1009
970 /* Hardware init */ 1010 /* Hardware init */
@@ -979,6 +1019,20 @@ mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match)
979 if (rv < 0) 1019 if (rv < 0)
980 goto probe_error; 1020 goto probe_error;
981 1021
1022 /* Now report the link setup */
1023 switch (priv->phy_addr) {
1024 case FEC5200_PHYADDR_NONE:
1025 dev_info(&ndev->dev, "Fixed speed MII link: %i%cD\n",
1026 priv->speed, priv->duplex ? 'F' : 'H');
1027 break;
1028 case FEC5200_PHYADDR_7WIRE:
1029 dev_info(&ndev->dev, "using 7-wire PHY mode\n");
1030 break;
1031 default:
1032 dev_info(&ndev->dev, "Using PHY at MDIO address %i\n",
1033 priv->phy_addr);
1034 }
1035
982 /* We're done ! */ 1036 /* We're done ! */
983 dev_set_drvdata(&op->dev, ndev); 1037 dev_set_drvdata(&op->dev, ndev);
984 1038