diff options
| -rw-r--r-- | drivers/net/Kconfig | 24 | ||||
| -rw-r--r-- | drivers/net/Makefile | 4 | ||||
| -rw-r--r-- | drivers/net/fec_mpc52xx.c | 1112 | ||||
| -rw-r--r-- | drivers/net/fec_mpc52xx.h | 313 | ||||
| -rw-r--r-- | drivers/net/fec_mpc52xx_phy.c | 198 |
5 files changed, 1651 insertions, 0 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 72d3447fb99b..867cb7345b5f 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
| @@ -1881,6 +1881,30 @@ config FEC2 | |||
| 1881 | Say Y here if you want to use the second built-in 10/100 Fast | 1881 | Say Y here if you want to use the second built-in 10/100 Fast |
| 1882 | ethernet controller on some Motorola ColdFire processors. | 1882 | ethernet controller on some Motorola ColdFire processors. |
| 1883 | 1883 | ||
| 1884 | config FEC_MPC52xx | ||
| 1885 | tristate "MPC52xx FEC driver" | ||
| 1886 | depends on PPC_MPC52xx | ||
| 1887 | select PPC_BESTCOMM | ||
| 1888 | select PPC_BESTCOMM_FEC | ||
| 1889 | select CRC32 | ||
| 1890 | select PHYLIB | ||
| 1891 | ---help--- | ||
| 1892 | This option enables support for the MPC5200's on-chip | ||
| 1893 | Fast Ethernet Controller | ||
| 1894 | If compiled as module, it will be called 'fec_mpc52xx.ko'. | ||
| 1895 | |||
| 1896 | config FEC_MPC52xx_MDIO | ||
| 1897 | bool "MPC52xx FEC MDIO bus driver" | ||
| 1898 | depends on FEC_MPC52xx | ||
| 1899 | default y | ||
| 1900 | ---help--- | ||
| 1901 | The MPC5200's FEC can connect to the Ethernet either with | ||
| 1902 | an external MII PHY chip or 10 Mbps 7-wire interface | ||
| 1903 | (Motorola? industry standard). | ||
| 1904 | If your board uses an external PHY connected to FEC, enable this. | ||
| 1905 | If not sure, enable. | ||
| 1906 | If compiled as module, it will be called 'fec_mpc52xx_phy.ko'. | ||
| 1907 | |||
| 1884 | config NE_H8300 | 1908 | config NE_H8300 |
| 1885 | tristate "NE2000 compatible support for H8/300" | 1909 | tristate "NE2000 compatible support for H8/300" |
| 1886 | depends on H8300 | 1910 | depends on H8300 |
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 593262065c9b..0e5fde4a1b2c 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
| @@ -96,6 +96,10 @@ obj-$(CONFIG_SHAPER) += shaper.o | |||
| 96 | obj-$(CONFIG_HP100) += hp100.o | 96 | obj-$(CONFIG_HP100) += hp100.o |
| 97 | obj-$(CONFIG_SMC9194) += smc9194.o | 97 | obj-$(CONFIG_SMC9194) += smc9194.o |
| 98 | obj-$(CONFIG_FEC) += fec.o | 98 | obj-$(CONFIG_FEC) += fec.o |
| 99 | obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx.o | ||
| 100 | ifeq ($(CONFIG_FEC_MPC52xx_MDIO),y) | ||
| 101 | obj-$(CONFIG_FEC_MPC52xx) += fec_mpc52xx_phy.o | ||
| 102 | endif | ||
| 99 | obj-$(CONFIG_68360_ENET) += 68360enet.o | 103 | obj-$(CONFIG_68360_ENET) += 68360enet.o |
| 100 | obj-$(CONFIG_WD80x3) += wd.o 8390.o | 104 | obj-$(CONFIG_WD80x3) += wd.o 8390.o |
| 101 | obj-$(CONFIG_EL2) += 3c503.o 8390.o | 105 | obj-$(CONFIG_EL2) += 3c503.o 8390.o |
diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c new file mode 100644 index 000000000000..fc1cf0b742b0 --- /dev/null +++ b/drivers/net/fec_mpc52xx.c | |||
| @@ -0,0 +1,1112 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the MPC5200 Fast Ethernet Controller | ||
| 3 | * | ||
| 4 | * Originally written by Dale Farnsworth <dfarnsworth@mvista.com> and | ||
| 5 | * now maintained by Sylvain Munaut <tnt@246tNt.com> | ||
| 6 | * | ||
| 7 | * Copyright (C) 2007 Domen Puncer, Telargo, Inc. | ||
| 8 | * Copyright (C) 2007 Sylvain Munaut <tnt@246tNt.com> | ||
| 9 | * Copyright (C) 2003-2004 MontaVista, Software, Inc. | ||
| 10 | * | ||
| 11 | * This file is licensed under the terms of the GNU General Public License | ||
| 12 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 13 | * kind, whether express or implied. | ||
| 14 | * | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/module.h> | ||
| 18 | |||
| 19 | #include <linux/kernel.h> | ||
| 20 | #include <linux/types.h> | ||
| 21 | #include <linux/spinlock.h> | ||
| 22 | #include <linux/errno.h> | ||
| 23 | #include <linux/init.h> | ||
| 24 | #include <linux/crc32.h> | ||
| 25 | #include <linux/hardirq.h> | ||
| 26 | #include <linux/delay.h> | ||
| 27 | #include <linux/of_device.h> | ||
| 28 | #include <linux/of_platform.h> | ||
| 29 | |||
| 30 | #include <linux/netdevice.h> | ||
| 31 | #include <linux/etherdevice.h> | ||
| 32 | #include <linux/ethtool.h> | ||
| 33 | #include <linux/skbuff.h> | ||
| 34 | |||
| 35 | #include <asm/io.h> | ||
| 36 | #include <asm/delay.h> | ||
| 37 | #include <asm/mpc52xx.h> | ||
| 38 | |||
| 39 | #include <sysdev/bestcomm/bestcomm.h> | ||
| 40 | #include <sysdev/bestcomm/fec.h> | ||
| 41 | |||
| 42 | #include "fec_mpc52xx.h" | ||
| 43 | |||
| 44 | #define DRIVER_NAME "mpc52xx-fec" | ||
| 45 | |||
| 46 | static irqreturn_t mpc52xx_fec_interrupt(int, void *); | ||
| 47 | static irqreturn_t mpc52xx_fec_rx_interrupt(int, void *); | ||
| 48 | static irqreturn_t mpc52xx_fec_tx_interrupt(int, void *); | ||
| 49 | static void mpc52xx_fec_stop(struct net_device *dev); | ||
| 50 | static void mpc52xx_fec_start(struct net_device *dev); | ||
| 51 | static void mpc52xx_fec_reset(struct net_device *dev); | ||
| 52 | |||
| 53 | static u8 mpc52xx_fec_mac_addr[6]; | ||
| 54 | module_param_array_named(mac, mpc52xx_fec_mac_addr, byte, NULL, 0); | ||
| 55 | MODULE_PARM_DESC(mac, "six hex digits, ie. 0x1,0x2,0xc0,0x01,0xba,0xbe"); | ||
| 56 | |||
| 57 | #define MPC52xx_MESSAGES_DEFAULT ( NETIF_MSG_DRV | NETIF_MSG_PROBE | \ | ||
| 58 | NETIF_MSG_LINK | NETIF_MSG_IFDOWN | NETIF_MSG_IFDOWN ) | ||
| 59 | static int debug = -1; /* the above default */ | ||
| 60 | module_param(debug, int, 0); | ||
| 61 | MODULE_PARM_DESC(debug, "debugging messages level"); | ||
| 62 | |||
| 63 | static void mpc52xx_fec_tx_timeout(struct net_device *dev) | ||
| 64 | { | ||
| 65 | dev_warn(&dev->dev, "transmit timed out\n"); | ||
| 66 | |||
| 67 | mpc52xx_fec_reset(dev); | ||
| 68 | |||
| 69 | dev->stats.tx_errors++; | ||
| 70 | |||
| 71 | netif_wake_queue(dev); | ||
| 72 | } | ||
| 73 | |||
| 74 | static void mpc52xx_fec_set_paddr(struct net_device *dev, u8 *mac) | ||
| 75 | { | ||
| 76 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 77 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 78 | |||
| 79 | out_be32(&fec->paddr1, *(u32 *)(&mac[0])); | ||
| 80 | out_be32(&fec->paddr2, (*(u16 *)(&mac[4]) << 16) | FEC_PADDR2_TYPE); | ||
| 81 | } | ||
| 82 | |||
| 83 | static void mpc52xx_fec_get_paddr(struct net_device *dev, u8 *mac) | ||
| 84 | { | ||
| 85 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 86 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 87 | |||
| 88 | *(u32 *)(&mac[0]) = in_be32(&fec->paddr1); | ||
| 89 | *(u16 *)(&mac[4]) = in_be32(&fec->paddr2) >> 16; | ||
| 90 | } | ||
| 91 | |||
| 92 | static int mpc52xx_fec_set_mac_address(struct net_device *dev, void *addr) | ||
| 93 | { | ||
| 94 | struct sockaddr *sock = addr; | ||
| 95 | |||
| 96 | memcpy(dev->dev_addr, sock->sa_data, dev->addr_len); | ||
| 97 | |||
| 98 | mpc52xx_fec_set_paddr(dev, sock->sa_data); | ||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | |||
| 102 | static void mpc52xx_fec_free_rx_buffers(struct net_device *dev, struct bcom_task *s) | ||
| 103 | { | ||
| 104 | while (!bcom_queue_empty(s)) { | ||
| 105 | struct bcom_fec_bd *bd; | ||
| 106 | struct sk_buff *skb; | ||
| 107 | |||
| 108 | skb = bcom_retrieve_buffer(s, NULL, (struct bcom_bd **)&bd); | ||
| 109 | dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_FROM_DEVICE); | ||
| 110 | kfree_skb(skb); | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | static int mpc52xx_fec_alloc_rx_buffers(struct net_device *dev, struct bcom_task *rxtsk) | ||
| 115 | { | ||
| 116 | while (!bcom_queue_full(rxtsk)) { | ||
| 117 | struct sk_buff *skb; | ||
| 118 | struct bcom_fec_bd *bd; | ||
| 119 | |||
| 120 | skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE); | ||
| 121 | if (skb == NULL) | ||
| 122 | return -EAGAIN; | ||
| 123 | |||
| 124 | /* zero out the initial receive buffers to aid debugging */ | ||
| 125 | memset(skb->data, 0, FEC_RX_BUFFER_SIZE); | ||
| 126 | |||
| 127 | bd = (struct bcom_fec_bd *)bcom_prepare_next_buffer(rxtsk); | ||
| 128 | |||
| 129 | bd->status = FEC_RX_BUFFER_SIZE; | ||
| 130 | bd->skb_pa = dma_map_single(&dev->dev, skb->data, | ||
| 131 | FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); | ||
| 132 | |||
| 133 | bcom_submit_next_buffer(rxtsk, skb); | ||
| 134 | } | ||
| 135 | |||
| 136 | return 0; | ||
| 137 | } | ||
| 138 | |||
| 139 | /* based on generic_adjust_link from fs_enet-main.c */ | ||
| 140 | static void mpc52xx_fec_adjust_link(struct net_device *dev) | ||
| 141 | { | ||
| 142 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 143 | struct phy_device *phydev = priv->phydev; | ||
| 144 | int new_state = 0; | ||
| 145 | |||
| 146 | if (phydev->link != PHY_DOWN) { | ||
| 147 | if (phydev->duplex != priv->duplex) { | ||
| 148 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 149 | u32 rcntrl; | ||
| 150 | u32 tcntrl; | ||
| 151 | |||
| 152 | new_state = 1; | ||
| 153 | priv->duplex = phydev->duplex; | ||
| 154 | |||
| 155 | rcntrl = in_be32(&fec->r_cntrl); | ||
| 156 | tcntrl = in_be32(&fec->x_cntrl); | ||
| 157 | |||
| 158 | rcntrl &= ~FEC_RCNTRL_DRT; | ||
| 159 | tcntrl &= ~FEC_TCNTRL_FDEN; | ||
| 160 | if (phydev->duplex == DUPLEX_FULL) | ||
| 161 | tcntrl |= FEC_TCNTRL_FDEN; /* FD enable */ | ||
| 162 | else | ||
| 163 | rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */ | ||
| 164 | |||
| 165 | out_be32(&fec->r_cntrl, rcntrl); | ||
| 166 | out_be32(&fec->x_cntrl, tcntrl); | ||
| 167 | } | ||
| 168 | |||
| 169 | if (phydev->speed != priv->speed) { | ||
| 170 | new_state = 1; | ||
| 171 | priv->speed = phydev->speed; | ||
| 172 | } | ||
| 173 | |||
| 174 | if (priv->link == PHY_DOWN) { | ||
| 175 | new_state = 1; | ||
| 176 | priv->link = phydev->link; | ||
| 177 | netif_schedule(dev); | ||
| 178 | netif_carrier_on(dev); | ||
| 179 | netif_start_queue(dev); | ||
| 180 | } | ||
| 181 | |||
| 182 | } else if (priv->link) { | ||
| 183 | new_state = 1; | ||
| 184 | priv->link = PHY_DOWN; | ||
| 185 | priv->speed = 0; | ||
| 186 | priv->duplex = -1; | ||
| 187 | netif_stop_queue(dev); | ||
| 188 | netif_carrier_off(dev); | ||
| 189 | } | ||
| 190 | |||
| 191 | if (new_state && netif_msg_link(priv)) | ||
| 192 | phy_print_status(phydev); | ||
| 193 | } | ||
| 194 | |||
| 195 | static int mpc52xx_fec_init_phy(struct net_device *dev) | ||
| 196 | { | ||
| 197 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 198 | struct phy_device *phydev; | ||
| 199 | char phy_id[BUS_ID_SIZE]; | ||
| 200 | |||
| 201 | snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, | ||
| 202 | (unsigned int)dev->base_addr, priv->phy_addr); | ||
| 203 | |||
| 204 | priv->link = PHY_DOWN; | ||
| 205 | priv->speed = 0; | ||
| 206 | priv->duplex = -1; | ||
| 207 | |||
| 208 | phydev = phy_connect(dev, phy_id, &mpc52xx_fec_adjust_link, 0, PHY_INTERFACE_MODE_MII); | ||
| 209 | if (IS_ERR(phydev)) { | ||
| 210 | dev_err(&dev->dev, "phy_connect failed\n"); | ||
| 211 | return PTR_ERR(phydev); | ||
| 212 | } | ||
| 213 | dev_info(&dev->dev, "attached phy %i to driver %s\n", | ||
| 214 | phydev->addr, phydev->drv->name); | ||
| 215 | |||
| 216 | priv->phydev = phydev; | ||
| 217 | |||
| 218 | return 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | static int mpc52xx_fec_phy_start(struct net_device *dev) | ||
| 222 | { | ||
| 223 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 224 | int err; | ||
| 225 | |||
| 226 | if (!priv->has_phy) | ||
| 227 | return 0; | ||
| 228 | |||
| 229 | err = mpc52xx_fec_init_phy(dev); | ||
| 230 | if (err) { | ||
| 231 | dev_err(&dev->dev, "mpc52xx_fec_init_phy failed\n"); | ||
| 232 | return err; | ||
| 233 | } | ||
| 234 | |||
| 235 | /* reset phy - this also wakes it from PDOWN */ | ||
| 236 | phy_write(priv->phydev, MII_BMCR, BMCR_RESET); | ||
| 237 | phy_start(priv->phydev); | ||
| 238 | |||
| 239 | return 0; | ||
| 240 | } | ||
| 241 | |||
| 242 | static void mpc52xx_fec_phy_stop(struct net_device *dev) | ||
| 243 | { | ||
| 244 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 245 | |||
| 246 | if (!priv->has_phy) | ||
| 247 | return; | ||
| 248 | |||
| 249 | phy_disconnect(priv->phydev); | ||
| 250 | /* power down phy */ | ||
| 251 | phy_stop(priv->phydev); | ||
| 252 | phy_write(priv->phydev, MII_BMCR, BMCR_PDOWN); | ||
| 253 | } | ||
| 254 | |||
| 255 | static int mpc52xx_fec_phy_mii_ioctl(struct mpc52xx_fec_priv *priv, | ||
| 256 | struct mii_ioctl_data *mii_data, int cmd) | ||
| 257 | { | ||
| 258 | if (!priv->has_phy) | ||
| 259 | return -ENOTSUPP; | ||
| 260 | |||
| 261 | return phy_mii_ioctl(priv->phydev, mii_data, cmd); | ||
| 262 | } | ||
| 263 | |||
| 264 | static void mpc52xx_fec_phy_hw_init(struct mpc52xx_fec_priv *priv) | ||
| 265 | { | ||
| 266 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 267 | |||
| 268 | if (!priv->has_phy) | ||
| 269 | return; | ||
| 270 | |||
| 271 | out_be32(&fec->mii_speed, priv->phy_speed); | ||
| 272 | } | ||
| 273 | |||
| 274 | static int mpc52xx_fec_open(struct net_device *dev) | ||
| 275 | { | ||
| 276 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 277 | int err = -EBUSY; | ||
| 278 | |||
| 279 | if (request_irq(dev->irq, &mpc52xx_fec_interrupt, IRQF_SHARED, | ||
| 280 | DRIVER_NAME "_ctrl", dev)) { | ||
| 281 | dev_err(&dev->dev, "ctrl interrupt request failed\n"); | ||
| 282 | goto out; | ||
| 283 | } | ||
| 284 | if (request_irq(priv->r_irq, &mpc52xx_fec_rx_interrupt, 0, | ||
| 285 | DRIVER_NAME "_rx", dev)) { | ||
| 286 | dev_err(&dev->dev, "rx interrupt request failed\n"); | ||
| 287 | goto free_ctrl_irq; | ||
| 288 | } | ||
| 289 | if (request_irq(priv->t_irq, &mpc52xx_fec_tx_interrupt, 0, | ||
| 290 | DRIVER_NAME "_tx", dev)) { | ||
| 291 | dev_err(&dev->dev, "tx interrupt request failed\n"); | ||
| 292 | goto free_2irqs; | ||
| 293 | } | ||
| 294 | |||
| 295 | bcom_fec_rx_reset(priv->rx_dmatsk); | ||
| 296 | bcom_fec_tx_reset(priv->tx_dmatsk); | ||
| 297 | |||
| 298 | err = mpc52xx_fec_alloc_rx_buffers(dev, priv->rx_dmatsk); | ||
| 299 | if (err) { | ||
| 300 | dev_err(&dev->dev, "mpc52xx_fec_alloc_rx_buffers failed\n"); | ||
| 301 | goto free_irqs; | ||
| 302 | } | ||
| 303 | |||
| 304 | err = mpc52xx_fec_phy_start(dev); | ||
| 305 | if (err) | ||
| 306 | goto free_skbs; | ||
| 307 | |||
| 308 | bcom_enable(priv->rx_dmatsk); | ||
| 309 | bcom_enable(priv->tx_dmatsk); | ||
| 310 | |||
| 311 | mpc52xx_fec_start(dev); | ||
| 312 | |||
| 313 | netif_start_queue(dev); | ||
| 314 | |||
| 315 | return 0; | ||
| 316 | |||
| 317 | free_skbs: | ||
| 318 | mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk); | ||
| 319 | |||
| 320 | free_irqs: | ||
| 321 | free_irq(priv->t_irq, dev); | ||
| 322 | free_2irqs: | ||
| 323 | free_irq(priv->r_irq, dev); | ||
| 324 | free_ctrl_irq: | ||
| 325 | free_irq(dev->irq, dev); | ||
| 326 | out: | ||
| 327 | |||
| 328 | return err; | ||
| 329 | } | ||
| 330 | |||
| 331 | static int mpc52xx_fec_close(struct net_device *dev) | ||
| 332 | { | ||
| 333 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 334 | |||
| 335 | netif_stop_queue(dev); | ||
| 336 | |||
| 337 | mpc52xx_fec_stop(dev); | ||
| 338 | |||
| 339 | mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk); | ||
| 340 | |||
| 341 | free_irq(dev->irq, dev); | ||
| 342 | free_irq(priv->r_irq, dev); | ||
| 343 | free_irq(priv->t_irq, dev); | ||
| 344 | |||
| 345 | mpc52xx_fec_phy_stop(dev); | ||
| 346 | |||
| 347 | return 0; | ||
| 348 | } | ||
| 349 | |||
| 350 | /* This will only be invoked if your driver is _not_ in XOFF state. | ||
| 351 | * What this means is that you need not check it, and that this | ||
| 352 | * invariant will hold if you make sure that the netif_*_queue() | ||
| 353 | * calls are done at the proper times. | ||
| 354 | */ | ||
| 355 | static int mpc52xx_fec_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) | ||
| 356 | { | ||
| 357 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 358 | struct bcom_fec_bd *bd; | ||
| 359 | |||
| 360 | if (bcom_queue_full(priv->tx_dmatsk)) { | ||
| 361 | if (net_ratelimit()) | ||
| 362 | dev_err(&dev->dev, "transmit queue overrun\n"); | ||
| 363 | return 1; | ||
| 364 | } | ||
| 365 | |||
| 366 | spin_lock_irq(&priv->lock); | ||
| 367 | dev->trans_start = jiffies; | ||
| 368 | |||
| 369 | bd = (struct bcom_fec_bd *) | ||
| 370 | bcom_prepare_next_buffer(priv->tx_dmatsk); | ||
| 371 | |||
| 372 | bd->status = skb->len | BCOM_FEC_TX_BD_TFD | BCOM_FEC_TX_BD_TC; | ||
| 373 | bd->skb_pa = dma_map_single(&dev->dev, skb->data, skb->len, DMA_TO_DEVICE); | ||
| 374 | |||
| 375 | bcom_submit_next_buffer(priv->tx_dmatsk, skb); | ||
| 376 | |||
| 377 | if (bcom_queue_full(priv->tx_dmatsk)) { | ||
| 378 | netif_stop_queue(dev); | ||
| 379 | } | ||
| 380 | |||
| 381 | spin_unlock_irq(&priv->lock); | ||
| 382 | |||
| 383 | return 0; | ||
| 384 | } | ||
| 385 | |||
| 386 | /* This handles BestComm transmit task interrupts | ||
| 387 | */ | ||
| 388 | static irqreturn_t mpc52xx_fec_tx_interrupt(int irq, void *dev_id) | ||
| 389 | { | ||
| 390 | struct net_device *dev = dev_id; | ||
| 391 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 392 | |||
| 393 | spin_lock(&priv->lock); | ||
| 394 | |||
| 395 | while (bcom_buffer_done(priv->tx_dmatsk)) { | ||
| 396 | struct sk_buff *skb; | ||
| 397 | struct bcom_fec_bd *bd; | ||
| 398 | skb = bcom_retrieve_buffer(priv->tx_dmatsk, NULL, | ||
| 399 | (struct bcom_bd **)&bd); | ||
| 400 | dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_TO_DEVICE); | ||
| 401 | |||
| 402 | dev_kfree_skb_irq(skb); | ||
| 403 | } | ||
| 404 | |||
| 405 | netif_wake_queue(dev); | ||
| 406 | |||
| 407 | spin_unlock(&priv->lock); | ||
| 408 | |||
| 409 | return IRQ_HANDLED; | ||
| 410 | } | ||
| 411 | |||
| 412 | static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) | ||
| 413 | { | ||
| 414 | struct net_device *dev = dev_id; | ||
| 415 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 416 | |||
| 417 | while (bcom_buffer_done(priv->rx_dmatsk)) { | ||
| 418 | struct sk_buff *skb; | ||
| 419 | struct sk_buff *rskb; | ||
| 420 | struct bcom_fec_bd *bd; | ||
| 421 | u32 status; | ||
| 422 | |||
| 423 | rskb = bcom_retrieve_buffer(priv->rx_dmatsk, &status, | ||
| 424 | (struct bcom_bd **)&bd); | ||
| 425 | dma_unmap_single(&dev->dev, bd->skb_pa, skb->len, DMA_FROM_DEVICE); | ||
| 426 | |||
| 427 | /* Test for errors in received frame */ | ||
| 428 | if (status & BCOM_FEC_RX_BD_ERRORS) { | ||
| 429 | /* Drop packet and reuse the buffer */ | ||
| 430 | bd = (struct bcom_fec_bd *) | ||
| 431 | bcom_prepare_next_buffer(priv->rx_dmatsk); | ||
| 432 | |||
| 433 | bd->status = FEC_RX_BUFFER_SIZE; | ||
| 434 | bd->skb_pa = dma_map_single(&dev->dev, rskb->data, | ||
| 435 | FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); | ||
| 436 | |||
| 437 | bcom_submit_next_buffer(priv->rx_dmatsk, rskb); | ||
| 438 | |||
| 439 | dev->stats.rx_dropped++; | ||
| 440 | |||
| 441 | continue; | ||
| 442 | } | ||
| 443 | |||
| 444 | /* skbs are allocated on open, so now we allocate a new one, | ||
| 445 | * and remove the old (with the packet) */ | ||
| 446 | skb = dev_alloc_skb(FEC_RX_BUFFER_SIZE); | ||
| 447 | if (skb) { | ||
| 448 | /* Process the received skb */ | ||
| 449 | int length = status & BCOM_FEC_RX_BD_LEN_MASK; | ||
| 450 | |||
| 451 | skb_put(rskb, length - 4); /* length without CRC32 */ | ||
| 452 | |||
| 453 | rskb->dev = dev; | ||
| 454 | rskb->protocol = eth_type_trans(rskb, dev); | ||
| 455 | |||
| 456 | netif_rx(rskb); | ||
| 457 | dev->last_rx = jiffies; | ||
| 458 | } else { | ||
| 459 | /* Can't get a new one : reuse the same & drop pkt */ | ||
| 460 | dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n"); | ||
| 461 | dev->stats.rx_dropped++; | ||
| 462 | |||
| 463 | skb = rskb; | ||
| 464 | } | ||
| 465 | |||
| 466 | bd = (struct bcom_fec_bd *) | ||
| 467 | bcom_prepare_next_buffer(priv->rx_dmatsk); | ||
| 468 | |||
| 469 | bd->status = FEC_RX_BUFFER_SIZE; | ||
| 470 | bd->skb_pa = dma_map_single(&dev->dev, rskb->data, | ||
| 471 | FEC_RX_BUFFER_SIZE, DMA_FROM_DEVICE); | ||
| 472 | |||
| 473 | bcom_submit_next_buffer(priv->rx_dmatsk, skb); | ||
| 474 | } | ||
| 475 | |||
| 476 | return IRQ_HANDLED; | ||
| 477 | } | ||
| 478 | |||
| 479 | static irqreturn_t mpc52xx_fec_interrupt(int irq, void *dev_id) | ||
| 480 | { | ||
| 481 | struct net_device *dev = dev_id; | ||
| 482 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 483 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 484 | u32 ievent; | ||
| 485 | |||
| 486 | ievent = in_be32(&fec->ievent); | ||
| 487 | |||
| 488 | ievent &= ~FEC_IEVENT_MII; /* mii is handled separately */ | ||
| 489 | if (!ievent) | ||
| 490 | return IRQ_NONE; | ||
| 491 | |||
| 492 | out_be32(&fec->ievent, ievent); /* clear pending events */ | ||
| 493 | |||
| 494 | if (ievent & ~(FEC_IEVENT_RFIFO_ERROR | FEC_IEVENT_XFIFO_ERROR)) { | ||
| 495 | if (ievent & ~FEC_IEVENT_TFINT) | ||
| 496 | dev_dbg(&dev->dev, "ievent: %08x\n", ievent); | ||
| 497 | return IRQ_HANDLED; | ||
| 498 | } | ||
| 499 | |||
| 500 | if (net_ratelimit() && (ievent & FEC_IEVENT_RFIFO_ERROR)) | ||
| 501 | dev_warn(&dev->dev, "FEC_IEVENT_RFIFO_ERROR\n"); | ||
| 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 | |||
| 507 | netif_wake_queue(dev); | ||
| 508 | return IRQ_HANDLED; | ||
| 509 | } | ||
| 510 | |||
| 511 | /* | ||
| 512 | * Get the current statistics. | ||
| 513 | * This may be called with the card open or closed. | ||
| 514 | */ | ||
| 515 | static struct net_device_stats *mpc52xx_fec_get_stats(struct net_device *dev) | ||
| 516 | { | ||
| 517 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 518 | struct net_device_stats *stats = &dev->stats; | ||
| 519 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 520 | |||
| 521 | stats->rx_bytes = in_be32(&fec->rmon_r_octets); | ||
| 522 | stats->rx_packets = in_be32(&fec->rmon_r_packets); | ||
| 523 | stats->rx_errors = in_be32(&fec->rmon_r_crc_align) + | ||
| 524 | in_be32(&fec->rmon_r_undersize) + | ||
| 525 | in_be32(&fec->rmon_r_oversize) + | ||
| 526 | in_be32(&fec->rmon_r_frag) + | ||
| 527 | in_be32(&fec->rmon_r_jab); | ||
| 528 | |||
| 529 | stats->tx_bytes = in_be32(&fec->rmon_t_octets); | ||
| 530 | stats->tx_packets = in_be32(&fec->rmon_t_packets); | ||
| 531 | stats->tx_errors = in_be32(&fec->rmon_t_crc_align) + | ||
| 532 | in_be32(&fec->rmon_t_undersize) + | ||
| 533 | in_be32(&fec->rmon_t_oversize) + | ||
| 534 | in_be32(&fec->rmon_t_frag) + | ||
| 535 | in_be32(&fec->rmon_t_jab); | ||
| 536 | |||
| 537 | stats->multicast = in_be32(&fec->rmon_r_mc_pkt); | ||
| 538 | stats->collisions = in_be32(&fec->rmon_t_col); | ||
| 539 | |||
| 540 | /* detailed rx_errors: */ | ||
| 541 | stats->rx_length_errors = in_be32(&fec->rmon_r_undersize) | ||
| 542 | + in_be32(&fec->rmon_r_oversize) | ||
| 543 | + in_be32(&fec->rmon_r_frag) | ||
| 544 | + in_be32(&fec->rmon_r_jab); | ||
| 545 | stats->rx_over_errors = in_be32(&fec->r_macerr); | ||
| 546 | stats->rx_crc_errors = in_be32(&fec->ieee_r_crc); | ||
| 547 | stats->rx_frame_errors = in_be32(&fec->ieee_r_align); | ||
| 548 | stats->rx_fifo_errors = in_be32(&fec->rmon_r_drop); | ||
| 549 | stats->rx_missed_errors = in_be32(&fec->rmon_r_drop); | ||
| 550 | |||
| 551 | /* detailed tx_errors: */ | ||
| 552 | stats->tx_aborted_errors = 0; | ||
| 553 | stats->tx_carrier_errors = in_be32(&fec->ieee_t_cserr); | ||
| 554 | stats->tx_fifo_errors = in_be32(&fec->rmon_t_drop); | ||
| 555 | stats->tx_heartbeat_errors = in_be32(&fec->ieee_t_sqe); | ||
| 556 | stats->tx_window_errors = in_be32(&fec->ieee_t_lcol); | ||
| 557 | |||
| 558 | return stats; | ||
| 559 | } | ||
| 560 | |||
| 561 | /* | ||
| 562 | * Read MIB counters in order to reset them, | ||
| 563 | * then zero all the stats fields in memory | ||
| 564 | */ | ||
| 565 | static void mpc52xx_fec_reset_stats(struct net_device *dev) | ||
| 566 | { | ||
| 567 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 568 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 569 | |||
| 570 | out_be32(&fec->mib_control, FEC_MIB_DISABLE); | ||
| 571 | memset_io(&fec->rmon_t_drop, 0, (__force u32)&fec->reserved10 - | ||
| 572 | (__force u32)&fec->rmon_t_drop); | ||
| 573 | out_be32(&fec->mib_control, 0); | ||
| 574 | |||
| 575 | memset(&dev->stats, 0, sizeof(dev->stats)); | ||
| 576 | } | ||
| 577 | |||
| 578 | /* | ||
| 579 | * Set or clear the multicast filter for this adaptor. | ||
| 580 | */ | ||
| 581 | static void mpc52xx_fec_set_multicast_list(struct net_device *dev) | ||
| 582 | { | ||
| 583 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 584 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 585 | u32 rx_control; | ||
| 586 | |||
| 587 | rx_control = in_be32(&fec->r_cntrl); | ||
| 588 | |||
| 589 | if (dev->flags & IFF_PROMISC) { | ||
| 590 | rx_control |= FEC_RCNTRL_PROM; | ||
| 591 | out_be32(&fec->r_cntrl, rx_control); | ||
| 592 | } else { | ||
| 593 | rx_control &= ~FEC_RCNTRL_PROM; | ||
| 594 | out_be32(&fec->r_cntrl, rx_control); | ||
| 595 | |||
| 596 | if (dev->flags & IFF_ALLMULTI) { | ||
| 597 | out_be32(&fec->gaddr1, 0xffffffff); | ||
| 598 | out_be32(&fec->gaddr2, 0xffffffff); | ||
| 599 | } else { | ||
| 600 | u32 crc; | ||
| 601 | int i; | ||
| 602 | struct dev_mc_list *dmi; | ||
| 603 | u32 gaddr1 = 0x00000000; | ||
| 604 | u32 gaddr2 = 0x00000000; | ||
| 605 | |||
| 606 | dmi = dev->mc_list; | ||
| 607 | for (i=0; i<dev->mc_count; i++) { | ||
| 608 | crc = ether_crc_le(6, dmi->dmi_addr) >> 26; | ||
| 609 | if (crc >= 32) | ||
| 610 | gaddr1 |= 1 << (crc-32); | ||
| 611 | else | ||
| 612 | gaddr2 |= 1 << crc; | ||
| 613 | dmi = dmi->next; | ||
| 614 | } | ||
| 615 | out_be32(&fec->gaddr1, gaddr1); | ||
| 616 | out_be32(&fec->gaddr2, gaddr2); | ||
| 617 | } | ||
| 618 | } | ||
| 619 | } | ||
| 620 | |||
| 621 | /** | ||
| 622 | * mpc52xx_fec_hw_init | ||
| 623 | * @dev: network device | ||
| 624 | * | ||
| 625 | * Setup various hardware setting, only needed once on start | ||
| 626 | */ | ||
| 627 | static void mpc52xx_fec_hw_init(struct net_device *dev) | ||
| 628 | { | ||
| 629 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 630 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 631 | int i; | ||
| 632 | |||
| 633 | /* Whack a reset. We should wait for this. */ | ||
| 634 | out_be32(&fec->ecntrl, FEC_ECNTRL_RESET); | ||
| 635 | for (i = 0; i < FEC_RESET_DELAY; ++i) { | ||
| 636 | if ((in_be32(&fec->ecntrl) & FEC_ECNTRL_RESET) == 0) | ||
| 637 | break; | ||
| 638 | udelay(1); | ||
| 639 | } | ||
| 640 | if (i == FEC_RESET_DELAY) | ||
| 641 | dev_err(&dev->dev, "FEC Reset timeout!\n"); | ||
| 642 | |||
| 643 | /* set pause to 0x20 frames */ | ||
| 644 | out_be32(&fec->op_pause, FEC_OP_PAUSE_OPCODE | 0x20); | ||
| 645 | |||
| 646 | /* high service request will be deasserted when there's < 7 bytes in fifo | ||
| 647 | * low service request will be deasserted when there's < 4*7 bytes in fifo | ||
| 648 | */ | ||
| 649 | out_be32(&fec->rfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7); | ||
| 650 | out_be32(&fec->tfifo_cntrl, FEC_FIFO_CNTRL_FRAME | FEC_FIFO_CNTRL_LTG_7); | ||
| 651 | |||
| 652 | /* alarm when <= x bytes in FIFO */ | ||
| 653 | out_be32(&fec->rfifo_alarm, 0x0000030c); | ||
| 654 | out_be32(&fec->tfifo_alarm, 0x00000100); | ||
| 655 | |||
| 656 | /* begin transmittion when 256 bytes are in FIFO (or EOF or FIFO full) */ | ||
| 657 | out_be32(&fec->x_wmrk, FEC_FIFO_WMRK_256B); | ||
| 658 | |||
| 659 | /* enable crc generation */ | ||
| 660 | out_be32(&fec->xmit_fsm, FEC_XMIT_FSM_APPEND_CRC | FEC_XMIT_FSM_ENABLE_CRC); | ||
| 661 | out_be32(&fec->iaddr1, 0x00000000); /* No individual filter */ | ||
| 662 | out_be32(&fec->iaddr2, 0x00000000); /* No individual filter */ | ||
| 663 | |||
| 664 | /* set phy speed. | ||
| 665 | * this can't be done in phy driver, since it needs to be called | ||
| 666 | * before fec stuff (even on resume) */ | ||
| 667 | mpc52xx_fec_phy_hw_init(priv); | ||
| 668 | } | ||
| 669 | |||
| 670 | /** | ||
| 671 | * mpc52xx_fec_start | ||
| 672 | * @dev: network device | ||
| 673 | * | ||
| 674 | * This function is called to start or restart the FEC during a link | ||
| 675 | * change. This happens on fifo errors or when switching between half | ||
| 676 | * and full duplex. | ||
| 677 | */ | ||
| 678 | static void mpc52xx_fec_start(struct net_device *dev) | ||
| 679 | { | ||
| 680 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 681 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 682 | u32 rcntrl; | ||
| 683 | u32 tcntrl; | ||
| 684 | u32 tmp; | ||
| 685 | |||
| 686 | /* clear sticky error bits */ | ||
| 687 | tmp = FEC_FIFO_STATUS_ERR | FEC_FIFO_STATUS_UF | FEC_FIFO_STATUS_OF; | ||
| 688 | out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status) & tmp); | ||
| 689 | out_be32(&fec->tfifo_status, in_be32(&fec->tfifo_status) & tmp); | ||
| 690 | |||
| 691 | /* FIFOs will reset on mpc52xx_fec_enable */ | ||
| 692 | out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_ENABLE_IS_RESET); | ||
| 693 | |||
| 694 | /* Set station address. */ | ||
| 695 | mpc52xx_fec_set_paddr(dev, dev->dev_addr); | ||
| 696 | |||
| 697 | mpc52xx_fec_set_multicast_list(dev); | ||
| 698 | |||
| 699 | /* set max frame len, enable flow control, select mii mode */ | ||
| 700 | rcntrl = FEC_RX_BUFFER_SIZE << 16; /* max frame length */ | ||
| 701 | rcntrl |= FEC_RCNTRL_FCE; | ||
| 702 | |||
| 703 | if (priv->has_phy) | ||
| 704 | rcntrl |= FEC_RCNTRL_MII_MODE; | ||
| 705 | |||
| 706 | if (priv->duplex == DUPLEX_FULL) | ||
| 707 | tcntrl = FEC_TCNTRL_FDEN; /* FD enable */ | ||
| 708 | else { | ||
| 709 | rcntrl |= FEC_RCNTRL_DRT; /* disable Rx on Tx (HD) */ | ||
| 710 | tcntrl = 0; | ||
| 711 | } | ||
| 712 | out_be32(&fec->r_cntrl, rcntrl); | ||
| 713 | out_be32(&fec->x_cntrl, tcntrl); | ||
| 714 | |||
| 715 | /* Clear any outstanding interrupt. */ | ||
| 716 | out_be32(&fec->ievent, 0xffffffff); | ||
| 717 | |||
| 718 | /* Enable interrupts we wish to service. */ | ||
| 719 | out_be32(&fec->imask, FEC_IMASK_ENABLE); | ||
| 720 | |||
| 721 | /* And last, enable the transmit and receive processing. */ | ||
| 722 | out_be32(&fec->ecntrl, FEC_ECNTRL_ETHER_EN); | ||
| 723 | out_be32(&fec->r_des_active, 0x01000000); | ||
| 724 | } | ||
| 725 | |||
| 726 | /** | ||
| 727 | * mpc52xx_fec_stop | ||
| 728 | * @dev: network device | ||
| 729 | * | ||
| 730 | * stop all activity on fec and empty dma buffers | ||
| 731 | */ | ||
| 732 | static void mpc52xx_fec_stop(struct net_device *dev) | ||
| 733 | { | ||
| 734 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 735 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 736 | unsigned long timeout; | ||
| 737 | |||
| 738 | /* disable all interrupts */ | ||
| 739 | out_be32(&fec->imask, 0); | ||
| 740 | |||
| 741 | /* Disable the rx task. */ | ||
| 742 | bcom_disable(priv->rx_dmatsk); | ||
| 743 | |||
| 744 | /* Wait for tx queue to drain, but only if we're in process context */ | ||
| 745 | if (!in_interrupt()) { | ||
| 746 | timeout = jiffies + msecs_to_jiffies(2000); | ||
| 747 | while (time_before(jiffies, timeout) && | ||
| 748 | !bcom_queue_empty(priv->tx_dmatsk)) | ||
| 749 | msleep(100); | ||
| 750 | |||
| 751 | if (time_after_eq(jiffies, timeout)) | ||
| 752 | dev_err(&dev->dev, "queues didn't drain\n"); | ||
| 753 | #if 1 | ||
| 754 | if (time_after_eq(jiffies, timeout)) { | ||
| 755 | dev_err(&dev->dev, " tx: index: %i, outdex: %i\n", | ||
| 756 | priv->tx_dmatsk->index, | ||
| 757 | priv->tx_dmatsk->outdex); | ||
| 758 | dev_err(&dev->dev, " rx: index: %i, outdex: %i\n", | ||
| 759 | priv->rx_dmatsk->index, | ||
| 760 | priv->rx_dmatsk->outdex); | ||
| 761 | } | ||
| 762 | #endif | ||
| 763 | } | ||
| 764 | |||
| 765 | bcom_disable(priv->tx_dmatsk); | ||
| 766 | |||
| 767 | /* Stop FEC */ | ||
| 768 | out_be32(&fec->ecntrl, in_be32(&fec->ecntrl) & ~FEC_ECNTRL_ETHER_EN); | ||
| 769 | |||
| 770 | return; | ||
| 771 | } | ||
| 772 | |||
| 773 | /* reset fec and bestcomm tasks */ | ||
| 774 | static void mpc52xx_fec_reset(struct net_device *dev) | ||
| 775 | { | ||
| 776 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 777 | struct mpc52xx_fec __iomem *fec = priv->fec; | ||
| 778 | |||
| 779 | mpc52xx_fec_stop(dev); | ||
| 780 | |||
| 781 | out_be32(&fec->rfifo_status, in_be32(&fec->rfifo_status)); | ||
| 782 | out_be32(&fec->reset_cntrl, FEC_RESET_CNTRL_RESET_FIFO); | ||
| 783 | |||
| 784 | mpc52xx_fec_free_rx_buffers(dev, priv->rx_dmatsk); | ||
| 785 | |||
| 786 | mpc52xx_fec_hw_init(dev); | ||
| 787 | |||
| 788 | phy_stop(priv->phydev); | ||
| 789 | phy_write(priv->phydev, MII_BMCR, BMCR_RESET); | ||
| 790 | phy_start(priv->phydev); | ||
| 791 | |||
| 792 | bcom_fec_rx_reset(priv->rx_dmatsk); | ||
| 793 | bcom_fec_tx_reset(priv->tx_dmatsk); | ||
| 794 | |||
| 795 | mpc52xx_fec_alloc_rx_buffers(dev, priv->rx_dmatsk); | ||
| 796 | |||
| 797 | bcom_enable(priv->rx_dmatsk); | ||
| 798 | bcom_enable(priv->tx_dmatsk); | ||
| 799 | |||
| 800 | mpc52xx_fec_start(dev); | ||
| 801 | } | ||
| 802 | |||
| 803 | |||
| 804 | /* ethtool interface */ | ||
| 805 | static void mpc52xx_fec_get_drvinfo(struct net_device *dev, | ||
| 806 | struct ethtool_drvinfo *info) | ||
| 807 | { | ||
| 808 | strcpy(info->driver, DRIVER_NAME); | ||
| 809 | } | ||
| 810 | |||
| 811 | static int mpc52xx_fec_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
| 812 | { | ||
| 813 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 814 | return phy_ethtool_gset(priv->phydev, cmd); | ||
| 815 | } | ||
| 816 | |||
| 817 | static int mpc52xx_fec_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
| 818 | { | ||
| 819 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 820 | return phy_ethtool_sset(priv->phydev, cmd); | ||
| 821 | } | ||
| 822 | |||
| 823 | static u32 mpc52xx_fec_get_msglevel(struct net_device *dev) | ||
| 824 | { | ||
| 825 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 826 | return priv->msg_enable; | ||
| 827 | } | ||
| 828 | |||
| 829 | static void mpc52xx_fec_set_msglevel(struct net_device *dev, u32 level) | ||
| 830 | { | ||
| 831 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 832 | priv->msg_enable = level; | ||
| 833 | } | ||
| 834 | |||
| 835 | static const struct ethtool_ops mpc52xx_fec_ethtool_ops = { | ||
| 836 | .get_drvinfo = mpc52xx_fec_get_drvinfo, | ||
| 837 | .get_settings = mpc52xx_fec_get_settings, | ||
| 838 | .set_settings = mpc52xx_fec_set_settings, | ||
| 839 | .get_link = ethtool_op_get_link, | ||
| 840 | .get_msglevel = mpc52xx_fec_get_msglevel, | ||
| 841 | .set_msglevel = mpc52xx_fec_set_msglevel, | ||
| 842 | }; | ||
| 843 | |||
| 844 | |||
| 845 | static int mpc52xx_fec_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) | ||
| 846 | { | ||
| 847 | struct mpc52xx_fec_priv *priv = netdev_priv(dev); | ||
| 848 | |||
| 849 | return mpc52xx_fec_phy_mii_ioctl(priv, if_mii(rq), cmd); | ||
| 850 | } | ||
| 851 | |||
| 852 | /* ======================================================================== */ | ||
| 853 | /* OF Driver */ | ||
| 854 | /* ======================================================================== */ | ||
| 855 | |||
| 856 | static int __devinit | ||
| 857 | mpc52xx_fec_probe(struct of_device *op, const struct of_device_id *match) | ||
| 858 | { | ||
| 859 | int rv; | ||
| 860 | struct net_device *ndev; | ||
| 861 | struct mpc52xx_fec_priv *priv = NULL; | ||
| 862 | struct resource mem; | ||
| 863 | const phandle *ph; | ||
| 864 | |||
| 865 | phys_addr_t rx_fifo; | ||
| 866 | phys_addr_t tx_fifo; | ||
| 867 | |||
| 868 | /* Get the ether ndev & it's private zone */ | ||
| 869 | ndev = alloc_etherdev(sizeof(struct mpc52xx_fec_priv)); | ||
| 870 | if (!ndev) | ||
| 871 | return -ENOMEM; | ||
| 872 | |||
| 873 | priv = netdev_priv(ndev); | ||
| 874 | |||
| 875 | /* Reserve FEC control zone */ | ||
| 876 | rv = of_address_to_resource(op->node, 0, &mem); | ||
| 877 | if (rv) { | ||
| 878 | printk(KERN_ERR DRIVER_NAME ": " | ||
| 879 | "Error while parsing device node resource\n" ); | ||
| 880 | return rv; | ||
| 881 | } | ||
| 882 | if ((mem.end - mem.start + 1) != sizeof(struct mpc52xx_fec)) { | ||
| 883 | printk(KERN_ERR DRIVER_NAME | ||
| 884 | " - invalid resource size (%lx != %x), check mpc52xx_devices.c\n", | ||
| 885 | (unsigned long)(mem.end - mem.start + 1), sizeof(struct mpc52xx_fec)); | ||
| 886 | return -EINVAL; | ||
| 887 | } | ||
| 888 | |||
| 889 | if (!request_mem_region(mem.start, sizeof(struct mpc52xx_fec), DRIVER_NAME)) | ||
| 890 | return -EBUSY; | ||
| 891 | |||
| 892 | /* Init ether ndev with what we have */ | ||
| 893 | ndev->open = mpc52xx_fec_open; | ||
| 894 | ndev->stop = mpc52xx_fec_close; | ||
| 895 | ndev->hard_start_xmit = mpc52xx_fec_hard_start_xmit; | ||
| 896 | ndev->do_ioctl = mpc52xx_fec_ioctl; | ||
| 897 | ndev->ethtool_ops = &mpc52xx_fec_ethtool_ops; | ||
| 898 | ndev->get_stats = mpc52xx_fec_get_stats; | ||
| 899 | ndev->set_mac_address = mpc52xx_fec_set_mac_address; | ||
| 900 | ndev->set_multicast_list = mpc52xx_fec_set_multicast_list; | ||
| 901 | ndev->tx_timeout = mpc52xx_fec_tx_timeout; | ||
| 902 | ndev->watchdog_timeo = FEC_WATCHDOG_TIMEOUT; | ||
| 903 | ndev->base_addr = mem.start; | ||
| 904 | |||
| 905 | priv->t_irq = priv->r_irq = ndev->irq = NO_IRQ; /* IRQ are free for now */ | ||
| 906 | |||
| 907 | spin_lock_init(&priv->lock); | ||
| 908 | |||
| 909 | /* ioremap the zones */ | ||
| 910 | priv->fec = ioremap(mem.start, sizeof(struct mpc52xx_fec)); | ||
| 911 | |||
| 912 | if (!priv->fec) { | ||
| 913 | rv = -ENOMEM; | ||
| 914 | goto probe_error; | ||
| 915 | } | ||
| 916 | |||
| 917 | /* Bestcomm init */ | ||
| 918 | rx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, rfifo_data); | ||
| 919 | tx_fifo = ndev->base_addr + offsetof(struct mpc52xx_fec, tfifo_data); | ||
| 920 | |||
| 921 | priv->rx_dmatsk = bcom_fec_rx_init(FEC_RX_NUM_BD, rx_fifo, FEC_RX_BUFFER_SIZE); | ||
| 922 | priv->tx_dmatsk = bcom_fec_tx_init(FEC_TX_NUM_BD, tx_fifo); | ||
| 923 | |||
| 924 | if (!priv->rx_dmatsk || !priv->tx_dmatsk) { | ||
| 925 | printk(KERN_ERR DRIVER_NAME ": Can not init SDMA tasks\n" ); | ||
| 926 | rv = -ENOMEM; | ||
| 927 | goto probe_error; | ||
| 928 | } | ||
| 929 | |||
| 930 | /* Get the IRQ we need one by one */ | ||
| 931 | /* Control */ | ||
| 932 | ndev->irq = irq_of_parse_and_map(op->node, 0); | ||
| 933 | |||
| 934 | /* RX */ | ||
| 935 | priv->r_irq = bcom_get_task_irq(priv->rx_dmatsk); | ||
| 936 | |||
| 937 | /* TX */ | ||
| 938 | priv->t_irq = bcom_get_task_irq(priv->tx_dmatsk); | ||
| 939 | |||
| 940 | /* MAC address init */ | ||
| 941 | if (!is_zero_ether_addr(mpc52xx_fec_mac_addr)) | ||
| 942 | memcpy(ndev->dev_addr, mpc52xx_fec_mac_addr, 6); | ||
| 943 | else | ||
| 944 | mpc52xx_fec_get_paddr(ndev, ndev->dev_addr); | ||
| 945 | |||
| 946 | priv->msg_enable = netif_msg_init(debug, MPC52xx_MESSAGES_DEFAULT); | ||
| 947 | priv->duplex = DUPLEX_FULL; | ||
| 948 | |||
| 949 | /* is the phy present in device tree? */ | ||
| 950 | ph = of_get_property(op->node, "phy-handle", NULL); | ||
| 951 | if (ph) { | ||
| 952 | const unsigned int *prop; | ||
| 953 | struct device_node *phy_dn; | ||
| 954 | priv->has_phy = 1; | ||
| 955 | |||
| 956 | phy_dn = of_find_node_by_phandle(*ph); | ||
| 957 | prop = of_get_property(phy_dn, "reg", NULL); | ||
| 958 | priv->phy_addr = *prop; | ||
| 959 | |||
| 960 | of_node_put(phy_dn); | ||
| 961 | |||
| 962 | /* Phy speed */ | ||
| 963 | priv->phy_speed = ((mpc52xx_find_ipb_freq(op->node) >> 20) / 5) << 1; | ||
| 964 | } else { | ||
| 965 | dev_info(&ndev->dev, "can't find \"phy-handle\" in device" | ||
| 966 | " tree, using 7-wire mode\n"); | ||
| 967 | } | ||
| 968 | |||
| 969 | /* Hardware init */ | ||
| 970 | mpc52xx_fec_hw_init(ndev); | ||
| 971 | |||
| 972 | mpc52xx_fec_reset_stats(ndev); | ||
| 973 | |||
| 974 | /* Register the new network device */ | ||
| 975 | rv = register_netdev(ndev); | ||
| 976 | if (rv < 0) | ||
| 977 | goto probe_error; | ||
| 978 | |||
| 979 | /* We're done ! */ | ||
| 980 | dev_set_drvdata(&op->dev, ndev); | ||
| 981 | |||
| 982 | return 0; | ||
| 983 | |||
| 984 | |||
| 985 | /* Error handling - free everything that might be allocated */ | ||
| 986 | probe_error: | ||
| 987 | |||
| 988 | irq_dispose_mapping(ndev->irq); | ||
| 989 | |||
| 990 | if (priv->rx_dmatsk) | ||
| 991 | bcom_fec_rx_release(priv->rx_dmatsk); | ||
| 992 | if (priv->tx_dmatsk) | ||
| 993 | bcom_fec_tx_release(priv->tx_dmatsk); | ||
| 994 | |||
| 995 | if (priv->fec) | ||
| 996 | iounmap(priv->fec); | ||
| 997 | |||
| 998 | release_mem_region(mem.start, sizeof(struct mpc52xx_fec)); | ||
| 999 | |||
| 1000 | free_netdev(ndev); | ||
| 1001 | |||
| 1002 | return rv; | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | static int | ||
| 1006 | mpc52xx_fec_remove(struct of_device *op) | ||
| 1007 | { | ||
| 1008 | struct net_device *ndev; | ||
| 1009 | struct mpc52xx_fec_priv *priv; | ||
| 1010 | |||
| 1011 | ndev = dev_get_drvdata(&op->dev); | ||
| 1012 | priv = netdev_priv(ndev); | ||
| 1013 | |||
| 1014 | unregister_netdev(ndev); | ||
| 1015 | |||
| 1016 | irq_dispose_mapping(ndev->irq); | ||
| 1017 | |||
| 1018 | bcom_fec_rx_release(priv->rx_dmatsk); | ||
| 1019 | bcom_fec_tx_release(priv->tx_dmatsk); | ||
| 1020 | |||
| 1021 | iounmap(priv->fec); | ||
| 1022 | |||
| 1023 | release_mem_region(ndev->base_addr, sizeof(struct mpc52xx_fec)); | ||
| 1024 | |||
| 1025 | free_netdev(ndev); | ||
| 1026 | |||
| 1027 | dev_set_drvdata(&op->dev, NULL); | ||
| 1028 | return 0; | ||
| 1029 | } | ||
| 1030 | |||
| 1031 | #ifdef CONFIG_PM | ||
| 1032 | static int mpc52xx_fec_of_suspend(struct of_device *op, pm_message_t state) | ||
| 1033 | { | ||
| 1034 | struct net_device *dev = dev_get_drvdata(&op->dev); | ||
| 1035 | |||
| 1036 | if (netif_running(dev)) | ||
| 1037 | mpc52xx_fec_close(dev); | ||
| 1038 | |||
| 1039 | return 0; | ||
| 1040 | } | ||
| 1041 | |||
| 1042 | static int mpc52xx_fec_of_resume(struct of_device *op) | ||
| 1043 | { | ||
| 1044 | struct net_device *dev = dev_get_drvdata(&op->dev); | ||
| 1045 | |||
| 1046 | mpc52xx_fec_hw_init(dev); | ||
| 1047 | mpc52xx_fec_reset_stats(dev); | ||
| 1048 | |||
| 1049 | if (netif_running(dev)) | ||
| 1050 | mpc52xx_fec_open(dev); | ||
| 1051 | |||
| 1052 | return 0; | ||
| 1053 | } | ||
| 1054 | #endif | ||
| 1055 | |||
| 1056 | static struct of_device_id mpc52xx_fec_match[] = { | ||
| 1057 | { | ||
| 1058 | .type = "network", | ||
| 1059 | .compatible = "mpc5200-fec", | ||
| 1060 | }, | ||
| 1061 | { } | ||
| 1062 | }; | ||
| 1063 | |||
| 1064 | MODULE_DEVICE_TABLE(of, mpc52xx_fec_match); | ||
| 1065 | |||
| 1066 | static struct of_platform_driver mpc52xx_fec_driver = { | ||
| 1067 | .owner = THIS_MODULE, | ||
| 1068 | .name = DRIVER_NAME, | ||
| 1069 | .match_table = mpc52xx_fec_match, | ||
| 1070 | .probe = mpc52xx_fec_probe, | ||
| 1071 | .remove = mpc52xx_fec_remove, | ||
| 1072 | #ifdef CONFIG_PM | ||
| 1073 | .suspend = mpc52xx_fec_of_suspend, | ||
| 1074 | .resume = mpc52xx_fec_of_resume, | ||
| 1075 | #endif | ||
| 1076 | }; | ||
| 1077 | |||
| 1078 | |||
| 1079 | /* ======================================================================== */ | ||
| 1080 | /* Module */ | ||
| 1081 | /* ======================================================================== */ | ||
| 1082 | |||
| 1083 | static int __init | ||
| 1084 | mpc52xx_fec_init(void) | ||
| 1085 | { | ||
| 1086 | #ifdef CONFIG_FEC_MPC52xx_MDIO | ||
| 1087 | int ret; | ||
| 1088 | ret = of_register_platform_driver(&mpc52xx_fec_mdio_driver); | ||
| 1089 | if (ret) { | ||
| 1090 | printk(KERN_ERR DRIVER_NAME ": failed to register mdio driver\n"); | ||
| 1091 | return ret; | ||
| 1092 | } | ||
| 1093 | #endif | ||
| 1094 | return of_register_platform_driver(&mpc52xx_fec_driver); | ||
| 1095 | } | ||
| 1096 | |||
| 1097 | static void __exit | ||
| 1098 | mpc52xx_fec_exit(void) | ||
| 1099 | { | ||
| 1100 | of_unregister_platform_driver(&mpc52xx_fec_driver); | ||
| 1101 | #ifdef CONFIG_FEC_MPC52xx_MDIO | ||
| 1102 | of_unregister_platform_driver(&mpc52xx_fec_mdio_driver); | ||
| 1103 | #endif | ||
| 1104 | } | ||
| 1105 | |||
| 1106 | |||
| 1107 | module_init(mpc52xx_fec_init); | ||
| 1108 | module_exit(mpc52xx_fec_exit); | ||
| 1109 | |||
| 1110 | MODULE_LICENSE("GPL"); | ||
| 1111 | MODULE_AUTHOR("Dale Farnsworth"); | ||
| 1112 | MODULE_DESCRIPTION("Ethernet driver for the Freescale MPC52xx FEC"); | ||
diff --git a/drivers/net/fec_mpc52xx.h b/drivers/net/fec_mpc52xx.h new file mode 100644 index 000000000000..8b1f75397b9a --- /dev/null +++ b/drivers/net/fec_mpc52xx.h | |||
| @@ -0,0 +1,313 @@ | |||
| 1 | /* | ||
| 2 | * drivers/drivers/net/fec_mpc52xx/fec.h | ||
| 3 | * | ||
| 4 | * Driver for the MPC5200 Fast Ethernet Controller | ||
| 5 | * | ||
| 6 | * Author: Dale Farnsworth <dfarnsworth@mvista.com> | ||
| 7 | * | ||
| 8 | * 2003-2004 (c) MontaVista, Software, Inc. This file is licensed under | ||
| 9 | * the terms of the GNU General Public License version 2. This program | ||
| 10 | * is licensed "as is" without any warranty of any kind, whether express | ||
| 11 | * or implied. | ||
| 12 | */ | ||
| 13 | |||
| 14 | #ifndef __DRIVERS_NET_MPC52XX_FEC_H__ | ||
| 15 | #define __DRIVERS_NET_MPC52XX_FEC_H__ | ||
| 16 | |||
| 17 | #include <linux/phy.h> | ||
| 18 | |||
| 19 | /* Tunable constant */ | ||
| 20 | /* FEC_RX_BUFFER_SIZE includes 4 bytes for CRC32 */ | ||
| 21 | #define FEC_RX_BUFFER_SIZE 1522 /* max receive packet size */ | ||
| 22 | #define FEC_RX_NUM_BD 256 | ||
| 23 | #define FEC_TX_NUM_BD 64 | ||
| 24 | |||
| 25 | #define FEC_RESET_DELAY 50 /* uS */ | ||
| 26 | |||
| 27 | #define FEC_WATCHDOG_TIMEOUT ((400*HZ)/1000) | ||
| 28 | |||
| 29 | struct mpc52xx_fec_priv { | ||
| 30 | int duplex; | ||
| 31 | int r_irq; | ||
| 32 | int t_irq; | ||
| 33 | struct mpc52xx_fec __iomem *fec; | ||
| 34 | struct bcom_task *rx_dmatsk; | ||
| 35 | struct bcom_task *tx_dmatsk; | ||
| 36 | spinlock_t lock; | ||
| 37 | int msg_enable; | ||
| 38 | |||
| 39 | int has_phy; | ||
| 40 | unsigned int phy_speed; | ||
| 41 | unsigned int phy_addr; | ||
| 42 | struct phy_device *phydev; | ||
| 43 | enum phy_state link; | ||
| 44 | int speed; | ||
| 45 | }; | ||
| 46 | |||
| 47 | |||
| 48 | /* ======================================================================== */ | ||
| 49 | /* Hardware register sets & bits */ | ||
| 50 | /* ======================================================================== */ | ||
| 51 | |||
| 52 | struct mpc52xx_fec { | ||
| 53 | u32 fec_id; /* FEC + 0x000 */ | ||
| 54 | u32 ievent; /* FEC + 0x004 */ | ||
| 55 | u32 imask; /* FEC + 0x008 */ | ||
| 56 | |||
| 57 | u32 reserved0[1]; /* FEC + 0x00C */ | ||
| 58 | u32 r_des_active; /* FEC + 0x010 */ | ||
| 59 | u32 x_des_active; /* FEC + 0x014 */ | ||
| 60 | u32 r_des_active_cl; /* FEC + 0x018 */ | ||
| 61 | u32 x_des_active_cl; /* FEC + 0x01C */ | ||
| 62 | u32 ivent_set; /* FEC + 0x020 */ | ||
| 63 | u32 ecntrl; /* FEC + 0x024 */ | ||
| 64 | |||
| 65 | u32 reserved1[6]; /* FEC + 0x028-03C */ | ||
| 66 | u32 mii_data; /* FEC + 0x040 */ | ||
| 67 | u32 mii_speed; /* FEC + 0x044 */ | ||
| 68 | u32 mii_status; /* FEC + 0x048 */ | ||
| 69 | |||
| 70 | u32 reserved2[5]; /* FEC + 0x04C-05C */ | ||
| 71 | u32 mib_data; /* FEC + 0x060 */ | ||
| 72 | u32 mib_control; /* FEC + 0x064 */ | ||
| 73 | |||
| 74 | u32 reserved3[6]; /* FEC + 0x068-7C */ | ||
| 75 | u32 r_activate; /* FEC + 0x080 */ | ||
| 76 | u32 r_cntrl; /* FEC + 0x084 */ | ||
| 77 | u32 r_hash; /* FEC + 0x088 */ | ||
| 78 | u32 r_data; /* FEC + 0x08C */ | ||
| 79 | u32 ar_done; /* FEC + 0x090 */ | ||
| 80 | u32 r_test; /* FEC + 0x094 */ | ||
| 81 | u32 r_mib; /* FEC + 0x098 */ | ||
| 82 | u32 r_da_low; /* FEC + 0x09C */ | ||
| 83 | u32 r_da_high; /* FEC + 0x0A0 */ | ||
| 84 | |||
| 85 | u32 reserved4[7]; /* FEC + 0x0A4-0BC */ | ||
| 86 | u32 x_activate; /* FEC + 0x0C0 */ | ||
| 87 | u32 x_cntrl; /* FEC + 0x0C4 */ | ||
| 88 | u32 backoff; /* FEC + 0x0C8 */ | ||
| 89 | u32 x_data; /* FEC + 0x0CC */ | ||
| 90 | u32 x_status; /* FEC + 0x0D0 */ | ||
| 91 | u32 x_mib; /* FEC + 0x0D4 */ | ||
| 92 | u32 x_test; /* FEC + 0x0D8 */ | ||
| 93 | u32 fdxfc_da1; /* FEC + 0x0DC */ | ||
| 94 | u32 fdxfc_da2; /* FEC + 0x0E0 */ | ||
| 95 | u32 paddr1; /* FEC + 0x0E4 */ | ||
| 96 | u32 paddr2; /* FEC + 0x0E8 */ | ||
| 97 | u32 op_pause; /* FEC + 0x0EC */ | ||
| 98 | |||
| 99 | u32 reserved5[4]; /* FEC + 0x0F0-0FC */ | ||
| 100 | u32 instr_reg; /* FEC + 0x100 */ | ||
| 101 | u32 context_reg; /* FEC + 0x104 */ | ||
| 102 | u32 test_cntrl; /* FEC + 0x108 */ | ||
| 103 | u32 acc_reg; /* FEC + 0x10C */ | ||
| 104 | u32 ones; /* FEC + 0x110 */ | ||
| 105 | u32 zeros; /* FEC + 0x114 */ | ||
| 106 | u32 iaddr1; /* FEC + 0x118 */ | ||
| 107 | u32 iaddr2; /* FEC + 0x11C */ | ||
| 108 | u32 gaddr1; /* FEC + 0x120 */ | ||
| 109 | u32 gaddr2; /* FEC + 0x124 */ | ||
| 110 | u32 random; /* FEC + 0x128 */ | ||
| 111 | u32 rand1; /* FEC + 0x12C */ | ||
| 112 | u32 tmp; /* FEC + 0x130 */ | ||
| 113 | |||
| 114 | u32 reserved6[3]; /* FEC + 0x134-13C */ | ||
| 115 | u32 fifo_id; /* FEC + 0x140 */ | ||
| 116 | u32 x_wmrk; /* FEC + 0x144 */ | ||
| 117 | u32 fcntrl; /* FEC + 0x148 */ | ||
| 118 | u32 r_bound; /* FEC + 0x14C */ | ||
| 119 | u32 r_fstart; /* FEC + 0x150 */ | ||
| 120 | u32 r_count; /* FEC + 0x154 */ | ||
| 121 | u32 r_lag; /* FEC + 0x158 */ | ||
| 122 | u32 r_read; /* FEC + 0x15C */ | ||
| 123 | u32 r_write; /* FEC + 0x160 */ | ||
| 124 | u32 x_count; /* FEC + 0x164 */ | ||
| 125 | u32 x_lag; /* FEC + 0x168 */ | ||
| 126 | u32 x_retry; /* FEC + 0x16C */ | ||
| 127 | u32 x_write; /* FEC + 0x170 */ | ||
| 128 | u32 x_read; /* FEC + 0x174 */ | ||
| 129 | |||
| 130 | u32 reserved7[2]; /* FEC + 0x178-17C */ | ||
| 131 | u32 fm_cntrl; /* FEC + 0x180 */ | ||
| 132 | u32 rfifo_data; /* FEC + 0x184 */ | ||
| 133 | u32 rfifo_status; /* FEC + 0x188 */ | ||
| 134 | u32 rfifo_cntrl; /* FEC + 0x18C */ | ||
| 135 | u32 rfifo_lrf_ptr; /* FEC + 0x190 */ | ||
| 136 | u32 rfifo_lwf_ptr; /* FEC + 0x194 */ | ||
| 137 | u32 rfifo_alarm; /* FEC + 0x198 */ | ||
| 138 | u32 rfifo_rdptr; /* FEC + 0x19C */ | ||
| 139 | u32 rfifo_wrptr; /* FEC + 0x1A0 */ | ||
| 140 | u32 tfifo_data; /* FEC + 0x1A4 */ | ||
| 141 | u32 tfifo_status; /* FEC + 0x1A8 */ | ||
| 142 | u32 tfifo_cntrl; /* FEC + 0x1AC */ | ||
| 143 | u32 tfifo_lrf_ptr; /* FEC + 0x1B0 */ | ||
| 144 | u32 tfifo_lwf_ptr; /* FEC + 0x1B4 */ | ||
| 145 | u32 tfifo_alarm; /* FEC + 0x1B8 */ | ||
| 146 | u32 tfifo_rdptr; /* FEC + 0x1BC */ | ||
| 147 | u32 tfifo_wrptr; /* FEC + 0x1C0 */ | ||
| 148 | |||
| 149 | u32 reset_cntrl; /* FEC + 0x1C4 */ | ||
| 150 | u32 xmit_fsm; /* FEC + 0x1C8 */ | ||
| 151 | |||
| 152 | u32 reserved8[3]; /* FEC + 0x1CC-1D4 */ | ||
| 153 | u32 rdes_data0; /* FEC + 0x1D8 */ | ||
| 154 | u32 rdes_data1; /* FEC + 0x1DC */ | ||
| 155 | u32 r_length; /* FEC + 0x1E0 */ | ||
| 156 | u32 x_length; /* FEC + 0x1E4 */ | ||
| 157 | u32 x_addr; /* FEC + 0x1E8 */ | ||
| 158 | u32 cdes_data; /* FEC + 0x1EC */ | ||
| 159 | u32 status; /* FEC + 0x1F0 */ | ||
| 160 | u32 dma_control; /* FEC + 0x1F4 */ | ||
| 161 | u32 des_cmnd; /* FEC + 0x1F8 */ | ||
| 162 | u32 data; /* FEC + 0x1FC */ | ||
| 163 | |||
| 164 | u32 rmon_t_drop; /* FEC + 0x200 */ | ||
| 165 | u32 rmon_t_packets; /* FEC + 0x204 */ | ||
| 166 | u32 rmon_t_bc_pkt; /* FEC + 0x208 */ | ||
| 167 | u32 rmon_t_mc_pkt; /* FEC + 0x20C */ | ||
| 168 | u32 rmon_t_crc_align; /* FEC + 0x210 */ | ||
| 169 | u32 rmon_t_undersize; /* FEC + 0x214 */ | ||
| 170 | u32 rmon_t_oversize; /* FEC + 0x218 */ | ||
| 171 | u32 rmon_t_frag; /* FEC + 0x21C */ | ||
| 172 | u32 rmon_t_jab; /* FEC + 0x220 */ | ||
| 173 | u32 rmon_t_col; /* FEC + 0x224 */ | ||
| 174 | u32 rmon_t_p64; /* FEC + 0x228 */ | ||
| 175 | u32 rmon_t_p65to127; /* FEC + 0x22C */ | ||
| 176 | u32 rmon_t_p128to255; /* FEC + 0x230 */ | ||
| 177 | u32 rmon_t_p256to511; /* FEC + 0x234 */ | ||
| 178 | u32 rmon_t_p512to1023; /* FEC + 0x238 */ | ||
| 179 | u32 rmon_t_p1024to2047; /* FEC + 0x23C */ | ||
| 180 | u32 rmon_t_p_gte2048; /* FEC + 0x240 */ | ||
| 181 | u32 rmon_t_octets; /* FEC + 0x244 */ | ||
| 182 | u32 ieee_t_drop; /* FEC + 0x248 */ | ||
| 183 | u32 ieee_t_frame_ok; /* FEC + 0x24C */ | ||
| 184 | u32 ieee_t_1col; /* FEC + 0x250 */ | ||
| 185 | u32 ieee_t_mcol; /* FEC + 0x254 */ | ||
| 186 | u32 ieee_t_def; /* FEC + 0x258 */ | ||
| 187 | u32 ieee_t_lcol; /* FEC + 0x25C */ | ||
| 188 | u32 ieee_t_excol; /* FEC + 0x260 */ | ||
| 189 | u32 ieee_t_macerr; /* FEC + 0x264 */ | ||
| 190 | u32 ieee_t_cserr; /* FEC + 0x268 */ | ||
| 191 | u32 ieee_t_sqe; /* FEC + 0x26C */ | ||
| 192 | u32 t_fdxfc; /* FEC + 0x270 */ | ||
| 193 | u32 ieee_t_octets_ok; /* FEC + 0x274 */ | ||
| 194 | |||
| 195 | u32 reserved9[2]; /* FEC + 0x278-27C */ | ||
| 196 | u32 rmon_r_drop; /* FEC + 0x280 */ | ||
| 197 | u32 rmon_r_packets; /* FEC + 0x284 */ | ||
| 198 | u32 rmon_r_bc_pkt; /* FEC + 0x288 */ | ||
| 199 | u32 rmon_r_mc_pkt; /* FEC + 0x28C */ | ||
| 200 | u32 rmon_r_crc_align; /* FEC + 0x290 */ | ||
| 201 | u32 rmon_r_undersize; /* FEC + 0x294 */ | ||
| 202 | u32 rmon_r_oversize; /* FEC + 0x298 */ | ||
| 203 | u32 rmon_r_frag; /* FEC + 0x29C */ | ||
| 204 | u32 rmon_r_jab; /* FEC + 0x2A0 */ | ||
| 205 | |||
| 206 | u32 rmon_r_resvd_0; /* FEC + 0x2A4 */ | ||
| 207 | |||
| 208 | u32 rmon_r_p64; /* FEC + 0x2A8 */ | ||
| 209 | u32 rmon_r_p65to127; /* FEC + 0x2AC */ | ||
| 210 | u32 rmon_r_p128to255; /* FEC + 0x2B0 */ | ||
| 211 | u32 rmon_r_p256to511; /* FEC + 0x2B4 */ | ||
| 212 | u32 rmon_r_p512to1023; /* FEC + 0x2B8 */ | ||
| 213 | u32 rmon_r_p1024to2047; /* FEC + 0x2BC */ | ||
| 214 | u32 rmon_r_p_gte2048; /* FEC + 0x2C0 */ | ||
| 215 | u32 rmon_r_octets; /* FEC + 0x2C4 */ | ||
| 216 | u32 ieee_r_drop; /* FEC + 0x2C8 */ | ||
| 217 | u32 ieee_r_frame_ok; /* FEC + 0x2CC */ | ||
| 218 | u32 ieee_r_crc; /* FEC + 0x2D0 */ | ||
| 219 | u32 ieee_r_align; /* FEC + 0x2D4 */ | ||
| 220 | u32 r_macerr; /* FEC + 0x2D8 */ | ||
| 221 | u32 r_fdxfc; /* FEC + 0x2DC */ | ||
| 222 | u32 ieee_r_octets_ok; /* FEC + 0x2E0 */ | ||
| 223 | |||
| 224 | u32 reserved10[7]; /* FEC + 0x2E4-2FC */ | ||
| 225 | |||
| 226 | u32 reserved11[64]; /* FEC + 0x300-3FF */ | ||
| 227 | }; | ||
| 228 | |||
| 229 | #define FEC_MIB_DISABLE 0x80000000 | ||
| 230 | |||
| 231 | #define FEC_IEVENT_HBERR 0x80000000 | ||
| 232 | #define FEC_IEVENT_BABR 0x40000000 | ||
| 233 | #define FEC_IEVENT_BABT 0x20000000 | ||
| 234 | #define FEC_IEVENT_GRA 0x10000000 | ||
| 235 | #define FEC_IEVENT_TFINT 0x08000000 | ||
| 236 | #define FEC_IEVENT_MII 0x00800000 | ||
| 237 | #define FEC_IEVENT_LATE_COL 0x00200000 | ||
| 238 | #define FEC_IEVENT_COL_RETRY_LIM 0x00100000 | ||
| 239 | #define FEC_IEVENT_XFIFO_UN 0x00080000 | ||
| 240 | #define FEC_IEVENT_XFIFO_ERROR 0x00040000 | ||
| 241 | #define FEC_IEVENT_RFIFO_ERROR 0x00020000 | ||
| 242 | |||
| 243 | #define FEC_IMASK_HBERR 0x80000000 | ||
| 244 | #define FEC_IMASK_BABR 0x40000000 | ||
| 245 | #define FEC_IMASK_BABT 0x20000000 | ||
| 246 | #define FEC_IMASK_GRA 0x10000000 | ||
| 247 | #define FEC_IMASK_MII 0x00800000 | ||
| 248 | #define FEC_IMASK_LATE_COL 0x00200000 | ||
| 249 | #define FEC_IMASK_COL_RETRY_LIM 0x00100000 | ||
| 250 | #define FEC_IMASK_XFIFO_UN 0x00080000 | ||
| 251 | #define FEC_IMASK_XFIFO_ERROR 0x00040000 | ||
| 252 | #define FEC_IMASK_RFIFO_ERROR 0x00020000 | ||
| 253 | |||
| 254 | /* all but MII, which is enabled separately */ | ||
| 255 | #define FEC_IMASK_ENABLE (FEC_IMASK_HBERR | FEC_IMASK_BABR | \ | ||
| 256 | FEC_IMASK_BABT | FEC_IMASK_GRA | FEC_IMASK_LATE_COL | \ | ||
| 257 | FEC_IMASK_COL_RETRY_LIM | FEC_IMASK_XFIFO_UN | \ | ||
| 258 | FEC_IMASK_XFIFO_ERROR | FEC_IMASK_RFIFO_ERROR) | ||
| 259 | |||
| 260 | #define FEC_RCNTRL_MAX_FL_SHIFT 16 | ||
| 261 | #define FEC_RCNTRL_LOOP 0x01 | ||
| 262 | #define FEC_RCNTRL_DRT 0x02 | ||
| 263 | #define FEC_RCNTRL_MII_MODE 0x04 | ||
| 264 | #define FEC_RCNTRL_PROM 0x08 | ||
| 265 | #define FEC_RCNTRL_BC_REJ 0x10 | ||
| 266 | #define FEC_RCNTRL_FCE 0x20 | ||
| 267 | |||
| 268 | #define FEC_TCNTRL_GTS 0x00000001 | ||
| 269 | #define FEC_TCNTRL_HBC 0x00000002 | ||
| 270 | #define FEC_TCNTRL_FDEN 0x00000004 | ||
| 271 | #define FEC_TCNTRL_TFC_PAUSE 0x00000008 | ||
| 272 | #define FEC_TCNTRL_RFC_PAUSE 0x00000010 | ||
| 273 | |||
| 274 | #define FEC_ECNTRL_RESET 0x00000001 | ||
| 275 | #define FEC_ECNTRL_ETHER_EN 0x00000002 | ||
| 276 | |||
| 277 | #define FEC_MII_DATA_ST 0x40000000 /* Start frame */ | ||
| 278 | #define FEC_MII_DATA_OP_RD 0x20000000 /* Perform read */ | ||
| 279 | #define FEC_MII_DATA_OP_WR 0x10000000 /* Perform write */ | ||
| 280 | #define FEC_MII_DATA_PA_MSK 0x0f800000 /* PHY Address mask */ | ||
| 281 | #define FEC_MII_DATA_RA_MSK 0x007c0000 /* PHY Register mask */ | ||
| 282 | #define FEC_MII_DATA_TA 0x00020000 /* Turnaround */ | ||
| 283 | #define FEC_MII_DATA_DATAMSK 0x0000ffff /* PHY data mask */ | ||
| 284 | |||
| 285 | #define FEC_MII_READ_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_RD | FEC_MII_DATA_TA) | ||
| 286 | #define FEC_MII_WRITE_FRAME (FEC_MII_DATA_ST | FEC_MII_DATA_OP_WR | FEC_MII_DATA_TA) | ||
| 287 | |||
| 288 | #define FEC_MII_DATA_RA_SHIFT 0x12 /* MII reg addr bits */ | ||
| 289 | #define FEC_MII_DATA_PA_SHIFT 0x17 /* MII PHY addr bits */ | ||
| 290 | |||
| 291 | #define FEC_PADDR2_TYPE 0x8808 | ||
| 292 | |||
| 293 | #define FEC_OP_PAUSE_OPCODE 0x00010000 | ||
| 294 | |||
| 295 | #define FEC_FIFO_WMRK_256B 0x3 | ||
| 296 | |||
| 297 | #define FEC_FIFO_STATUS_ERR 0x00400000 | ||
| 298 | #define FEC_FIFO_STATUS_UF 0x00200000 | ||
| 299 | #define FEC_FIFO_STATUS_OF 0x00100000 | ||
| 300 | |||
| 301 | #define FEC_FIFO_CNTRL_FRAME 0x08000000 | ||
| 302 | #define FEC_FIFO_CNTRL_LTG_7 0x07000000 | ||
| 303 | |||
| 304 | #define FEC_RESET_CNTRL_RESET_FIFO 0x02000000 | ||
| 305 | #define FEC_RESET_CNTRL_ENABLE_IS_RESET 0x01000000 | ||
| 306 | |||
| 307 | #define FEC_XMIT_FSM_APPEND_CRC 0x02000000 | ||
| 308 | #define FEC_XMIT_FSM_ENABLE_CRC 0x01000000 | ||
| 309 | |||
| 310 | |||
| 311 | extern struct of_platform_driver mpc52xx_fec_mdio_driver; | ||
| 312 | |||
| 313 | #endif /* __DRIVERS_NET_MPC52XX_FEC_H__ */ | ||
diff --git a/drivers/net/fec_mpc52xx_phy.c b/drivers/net/fec_mpc52xx_phy.c new file mode 100644 index 000000000000..ba6e8b218e0a --- /dev/null +++ b/drivers/net/fec_mpc52xx_phy.c | |||
| @@ -0,0 +1,198 @@ | |||
| 1 | /* | ||
| 2 | * Driver for the MPC5200 Fast Ethernet Controller - MDIO bus driver | ||
| 3 | * | ||
| 4 | * Copyright (C) 2007 Domen Puncer, Telargo, Inc. | ||
| 5 | * | ||
| 6 | * This file is licensed under the terms of the GNU General Public License | ||
| 7 | * version 2. This program is licensed "as is" without any warranty of any | ||
| 8 | * kind, whether express or implied. | ||
| 9 | */ | ||
| 10 | |||
| 11 | #include <linux/kernel.h> | ||
| 12 | #include <linux/module.h> | ||
| 13 | #include <linux/netdevice.h> | ||
| 14 | #include <linux/phy.h> | ||
| 15 | #include <linux/of_platform.h> | ||
| 16 | #include <asm/io.h> | ||
| 17 | #include <asm/mpc52xx.h> | ||
| 18 | #include "fec_mpc52xx.h" | ||
| 19 | |||
| 20 | struct mpc52xx_fec_mdio_priv { | ||
| 21 | struct mpc52xx_fec __iomem *regs; | ||
| 22 | }; | ||
| 23 | |||
| 24 | static int mpc52xx_fec_mdio_read(struct mii_bus *bus, int phy_id, int reg) | ||
| 25 | { | ||
| 26 | struct mpc52xx_fec_mdio_priv *priv = bus->priv; | ||
| 27 | struct mpc52xx_fec __iomem *fec; | ||
| 28 | int tries = 100; | ||
| 29 | u32 request = FEC_MII_READ_FRAME; | ||
| 30 | |||
| 31 | fec = priv->regs; | ||
| 32 | out_be32(&fec->ievent, FEC_IEVENT_MII); | ||
| 33 | |||
| 34 | request |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK; | ||
| 35 | request |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK; | ||
| 36 | |||
| 37 | out_be32(&priv->regs->mii_data, request); | ||
| 38 | |||
| 39 | /* wait for it to finish, this takes about 23 us on lite5200b */ | ||
| 40 | while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries) | ||
| 41 | udelay(5); | ||
| 42 | |||
| 43 | if (tries == 0) | ||
| 44 | return -ETIMEDOUT; | ||
| 45 | |||
| 46 | return in_be32(&priv->regs->mii_data) & FEC_MII_DATA_DATAMSK; | ||
| 47 | } | ||
| 48 | |||
| 49 | static int mpc52xx_fec_mdio_write(struct mii_bus *bus, int phy_id, int reg, u16 data) | ||
| 50 | { | ||
| 51 | struct mpc52xx_fec_mdio_priv *priv = bus->priv; | ||
| 52 | struct mpc52xx_fec __iomem *fec; | ||
| 53 | u32 value = data; | ||
| 54 | int tries = 100; | ||
| 55 | |||
| 56 | fec = priv->regs; | ||
| 57 | out_be32(&fec->ievent, FEC_IEVENT_MII); | ||
| 58 | |||
| 59 | value |= FEC_MII_WRITE_FRAME; | ||
| 60 | value |= (phy_id << FEC_MII_DATA_PA_SHIFT) & FEC_MII_DATA_PA_MSK; | ||
| 61 | value |= (reg << FEC_MII_DATA_RA_SHIFT) & FEC_MII_DATA_RA_MSK; | ||
| 62 | |||
| 63 | out_be32(&priv->regs->mii_data, value); | ||
| 64 | |||
| 65 | /* wait for request to finish */ | ||
| 66 | while (!(in_be32(&fec->ievent) & FEC_IEVENT_MII) && --tries) | ||
| 67 | udelay(5); | ||
| 68 | |||
| 69 | if (tries == 0) | ||
| 70 | return -ETIMEDOUT; | ||
| 71 | |||
| 72 | return 0; | ||
| 73 | } | ||
| 74 | |||
| 75 | static int mpc52xx_fec_mdio_probe(struct of_device *of, const struct of_device_id *match) | ||
| 76 | { | ||
| 77 | struct device *dev = &of->dev; | ||
| 78 | struct device_node *np = of->node; | ||
| 79 | struct device_node *child = NULL; | ||
| 80 | struct mii_bus *bus; | ||
| 81 | struct mpc52xx_fec_mdio_priv *priv; | ||
| 82 | struct resource res = {}; | ||
| 83 | int err; | ||
| 84 | int i; | ||
| 85 | |||
| 86 | bus = kzalloc(sizeof(*bus), GFP_KERNEL); | ||
| 87 | if (bus == NULL) | ||
| 88 | return -ENOMEM; | ||
| 89 | priv = kzalloc(sizeof(*priv), GFP_KERNEL); | ||
| 90 | if (priv == NULL) { | ||
| 91 | err = -ENOMEM; | ||
| 92 | goto out_free; | ||
| 93 | } | ||
| 94 | |||
| 95 | bus->name = "mpc52xx MII bus"; | ||
| 96 | bus->read = mpc52xx_fec_mdio_read; | ||
| 97 | bus->write = mpc52xx_fec_mdio_write; | ||
| 98 | |||
| 99 | /* setup irqs */ | ||
| 100 | bus->irq = kmalloc(sizeof(bus->irq[0]) * PHY_MAX_ADDR, GFP_KERNEL); | ||
| 101 | if (bus->irq == NULL) { | ||
| 102 | err = -ENOMEM; | ||
| 103 | goto out_free; | ||
| 104 | } | ||
| 105 | for (i=0; i<PHY_MAX_ADDR; i++) | ||
| 106 | bus->irq[i] = PHY_POLL; | ||
| 107 | |||
| 108 | while ((child = of_get_next_child(np, child)) != NULL) { | ||
| 109 | int irq = irq_of_parse_and_map(child, 0); | ||
| 110 | if (irq != NO_IRQ) { | ||
| 111 | const u32 *id = of_get_property(child, "reg", NULL); | ||
| 112 | bus->irq[*id] = irq; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | /* setup registers */ | ||
| 117 | err = of_address_to_resource(np, 0, &res); | ||
| 118 | if (err) | ||
| 119 | goto out_free; | ||
| 120 | priv->regs = ioremap(res.start, res.end - res.start + 1); | ||
| 121 | if (priv->regs == NULL) { | ||
| 122 | err = -ENOMEM; | ||
| 123 | goto out_free; | ||
| 124 | } | ||
| 125 | |||
| 126 | bus->id = res.start; | ||
| 127 | bus->priv = priv; | ||
| 128 | |||
| 129 | bus->dev = dev; | ||
| 130 | dev_set_drvdata(dev, bus); | ||
| 131 | |||
| 132 | /* set MII speed */ | ||
| 133 | out_be32(&priv->regs->mii_speed, ((mpc52xx_find_ipb_freq(of->node) >> 20) / 5) << 1); | ||
| 134 | |||
| 135 | /* enable MII interrupt */ | ||
| 136 | out_be32(&priv->regs->imask, in_be32(&priv->regs->imask) | FEC_IMASK_MII); | ||
| 137 | |||
| 138 | err = mdiobus_register(bus); | ||
| 139 | if (err) | ||
| 140 | goto out_unmap; | ||
| 141 | |||
| 142 | return 0; | ||
| 143 | |||
| 144 | out_unmap: | ||
| 145 | iounmap(priv->regs); | ||
| 146 | out_free: | ||
| 147 | for (i=0; i<PHY_MAX_ADDR; i++) | ||
| 148 | if (bus->irq[i] != PHY_POLL) | ||
| 149 | irq_dispose_mapping(bus->irq[i]); | ||
| 150 | kfree(bus->irq); | ||
| 151 | kfree(priv); | ||
| 152 | kfree(bus); | ||
| 153 | |||
| 154 | return err; | ||
| 155 | } | ||
| 156 | |||
| 157 | static int mpc52xx_fec_mdio_remove(struct of_device *of) | ||
| 158 | { | ||
| 159 | struct device *dev = &of->dev; | ||
| 160 | struct mii_bus *bus = dev_get_drvdata(dev); | ||
| 161 | struct mpc52xx_fec_mdio_priv *priv = bus->priv; | ||
| 162 | int i; | ||
| 163 | |||
| 164 | mdiobus_unregister(bus); | ||
| 165 | dev_set_drvdata(dev, NULL); | ||
| 166 | |||
| 167 | iounmap(priv->regs); | ||
| 168 | for (i=0; i<PHY_MAX_ADDR; i++) | ||
| 169 | if (bus->irq[i]) | ||
| 170 | irq_dispose_mapping(bus->irq[i]); | ||
| 171 | kfree(priv); | ||
| 172 | kfree(bus->irq); | ||
| 173 | kfree(bus); | ||
| 174 | |||
| 175 | return 0; | ||
| 176 | } | ||
| 177 | |||
| 178 | |||
| 179 | static struct of_device_id mpc52xx_fec_mdio_match[] = { | ||
| 180 | { | ||
| 181 | .type = "mdio", | ||
| 182 | .compatible = "mpc5200b-fec-phy", | ||
| 183 | }, | ||
| 184 | {}, | ||
| 185 | }; | ||
| 186 | |||
| 187 | struct of_platform_driver mpc52xx_fec_mdio_driver = { | ||
| 188 | .name = "mpc5200b-fec-phy", | ||
| 189 | .probe = mpc52xx_fec_mdio_probe, | ||
| 190 | .remove = mpc52xx_fec_mdio_remove, | ||
| 191 | .match_table = mpc52xx_fec_mdio_match, | ||
| 192 | }; | ||
| 193 | |||
| 194 | /* let fec driver call it, since this has to be registered before it */ | ||
| 195 | EXPORT_SYMBOL_GPL(mpc52xx_fec_mdio_driver); | ||
| 196 | |||
| 197 | |||
| 198 | MODULE_LICENSE("Dual BSD/GPL"); | ||
