diff options
Diffstat (limited to 'drivers/net/fec_mpc52xx.c')
-rw-r--r-- | drivers/net/fec_mpc52xx.c | 120 |
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 */ | ||
50 | struct 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 | |||
46 | static irqreturn_t mpc52xx_fec_interrupt(int, void *); | 69 | static irqreturn_t mpc52xx_fec_interrupt(int, void *); |
47 | static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *); | 70 | static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *); |
48 | static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *); | 71 | static 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) | |||
255 | static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv, | 278 | static 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 | ||