11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx. 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 1997 Dan Malek (dmalek@jlc.net) 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 57dd6a2aa27a7a8036fbaf60cbce38a64128d1d4dGreg Ungerer * Right now, I am very wasteful with the buffers. I allocate memory 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pages and then divide them into 2K frame buffers. This way I know I 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * have buffers large enough to hold one frame within one buffer descriptor. 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Once I get this working, I will use 64 or 128 byte CPM buffers, which 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will be much more memory efficient and will easily handle lots of 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * small packets. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Much better multiple PHY support by Magnus Damm. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Copyright (c) 2000 Ericsson Radio Systems AB. 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 15562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer * Support for FEC controller of ColdFire processors. 16562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer * Copyright (c) 2001-2005 Greg Ungerer (gerg@snapgear.com) 177dd6a2aa27a7a8036fbaf60cbce38a64128d1d4dGreg Ungerer * 187dd6a2aa27a7a8036fbaf60cbce38a64128d1d4dGreg Ungerer * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be) 19677177c5319f7079c22d04926c23b31166d7d405Philippe De Muyter * Copyright (c) 2004-2006 Macq Electronique SA. 20b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * 21230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * Copyright (C) 2010-2011 Freescale Semiconductor, Inc. 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/string.h> 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ptrace.h> 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/errno.h> 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/ioport.h> 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h> 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/interrupt.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/pci.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/delay.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/skbuff.h> 381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/spinlock.h> 391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/workqueue.h> 401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/bitops.h> 416f501b173f2d69973497599f5358fb4c30922d67Sascha Hauer#include <linux/io.h> 426f501b173f2d69973497599f5358fb4c30922d67Sascha Hauer#include <linux/irq.h> 43196719ecec0c526de273dcb902f0be956a193232Sascha Hauer#include <linux/clk.h> 44ead731837d142b103eab9870105f50bc40b69255Sascha Hauer#include <linux/platform_device.h> 45e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu#include <linux/phy.h> 465eb32bd059379530fc3809a7fcf183feca75f601Baruch Siach#include <linux/fec.h> 47ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#include <linux/of.h> 48ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#include <linux/of_device.h> 49ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#include <linux/of_gpio.h> 50ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#include <linux/of_net.h> 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 52080853afe3da90d3c54a2eea8a9ab6a2f814fb0eGreg Ungerer#include <asm/cacheflush.h> 53196719ecec0c526de273dcb902f0be956a193232Sascha Hauer 54b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo#ifndef CONFIG_ARM 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/coldfire.h> 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/mcfsim.h> 57196719ecec0c526de273dcb902f0be956a193232Sascha Hauer#endif 586f501b173f2d69973497599f5358fb4c30922d67Sascha Hauer 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "fec.h" 601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61085e79ed88351d2f3cbf257ff4fc00394792da18Uwe Kleine-König#if defined(CONFIG_ARM) 62196719ecec0c526de273dcb902f0be956a193232Sascha Hauer#define FEC_ALIGNMENT 0xf 63196719ecec0c526de273dcb902f0be956a193232Sascha Hauer#else 64196719ecec0c526de273dcb902f0be956a193232Sascha Hauer#define FEC_ALIGNMENT 0x3 65196719ecec0c526de273dcb902f0be956a193232Sascha Hauer#endif 66196719ecec0c526de273dcb902f0be956a193232Sascha Hauer 67b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo#define DRIVER_NAME "fec" 68b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 69b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo/* Controller is ENET-MAC */ 70b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo#define FEC_QUIRK_ENET_MAC (1 << 0) 71b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo/* Controller needs driver to swap frame */ 72b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo#define FEC_QUIRK_SWAP_FRAME (1 << 1) 730ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo/* Controller uses gasket */ 740ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo#define FEC_QUIRK_USE_GASKET (1 << 2) 75230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo/* Controller has GBIT support */ 76230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo#define FEC_QUIRK_HAS_GBIT (1 << 3) 77b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 78b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guostatic struct platform_device_id fec_devtype[] = { 79b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo { 800ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo /* keep it for coldfire */ 81b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo .name = DRIVER_NAME, 82b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo .driver_data = 0, 83b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo }, { 840ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo .name = "imx25-fec", 850ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo .driver_data = FEC_QUIRK_USE_GASKET, 860ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo }, { 870ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo .name = "imx27-fec", 880ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo .driver_data = 0, 890ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo }, { 90b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo .name = "imx28-fec", 91b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_SWAP_FRAME, 920ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo }, { 93230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo .name = "imx6q-fec", 94230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo .driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT, 95230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo }, { 960ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo /* sentinel */ 970ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo } 98b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo}; 990ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn GuoMODULE_DEVICE_TABLE(platform, fec_devtype); 100b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 101ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guoenum imx_fec_type { 102a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann IMX25_FEC = 1, /* runs on i.mx25/50/53 */ 103ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo IMX27_FEC, /* runs on i.mx27/35/51 */ 104ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo IMX28_FEC, 105230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo IMX6Q_FEC, 106ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo}; 107ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 108ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guostatic const struct of_device_id fec_dt_ids[] = { 109ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo { .compatible = "fsl,imx25-fec", .data = &fec_devtype[IMX25_FEC], }, 110ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo { .compatible = "fsl,imx27-fec", .data = &fec_devtype[IMX27_FEC], }, 111ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo { .compatible = "fsl,imx28-fec", .data = &fec_devtype[IMX28_FEC], }, 112230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo { .compatible = "fsl,imx6q-fec", .data = &fec_devtype[IMX6Q_FEC], }, 113ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo { /* sentinel */ } 114ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo}; 115ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn GuoMODULE_DEVICE_TABLE(of, fec_dt_ids); 116ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 11749da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guostatic unsigned char macaddr[ETH_ALEN]; 11849da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guomodule_param_array(macaddr, byte, NULL, 0); 11949da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn GuoMODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address"); 1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12149da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo#if defined(CONFIG_M5272) 1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Some hardware gets it MAC address out of local flash memory. 1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * if this is non-zero then assume it is the address to get MAC from. 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if defined(CONFIG_NETtel) 1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_FLASHMAC 0xf0006006 1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES) 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_FLASHMAC 0xf0006000 1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#elif defined(CONFIG_CANCam) 1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_FLASHMAC 0xf0020000 1327dd6a2aa27a7a8036fbaf60cbce38a64128d1d4dGreg Ungerer#elif defined (CONFIG_M5272C3) 1337dd6a2aa27a7a8036fbaf60cbce38a64128d1d4dGreg Ungerer#define FEC_FLASHMAC (0xffe04000 + 4) 1347dd6a2aa27a7a8036fbaf60cbce38a64128d1d4dGreg Ungerer#elif defined(CONFIG_MOD5272) 135a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann#define FEC_FLASHMAC 0xffc0406b 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_FLASHMAC 0 1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 13943be63662db56de3f87cb4a86bfe062a9797be65Greg Ungerer#endif /* CONFIG_M5272 */ 140ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The number of Tx and Rx buffers. These are allocated from the page 1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * pool. The code may assume these are power of two, so it it best 1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * to keep them that size. 1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * We don't need to allocate pages for the transmitter. We just use 1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the skbuffer directly. 1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_RX_PAGES 8 1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_RX_FRSIZE 2048 1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_RX_FRPPG (PAGE_SIZE / FEC_ENET_RX_FRSIZE) 1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RX_RING_SIZE (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES) 1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_TX_FRSIZE 2048 1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_TX_FRPPG (PAGE_SIZE / FEC_ENET_TX_FRSIZE) 1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_SIZE 16 /* Must be power of two */ 1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define TX_RING_MOD_MASK 15 /* for this to work */ 1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 156562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer#if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE) 1576b2652936b9e61df47664a8dde46872a74d7dba2Matt Waddel#error "FEC: descriptor ring size constants too large" 158562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer#endif 159562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer 16022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer/* Interrupt events/masks. */ 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_HBERR ((uint)0x80000000) /* Heartbeat error */ 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_BABR ((uint)0x40000000) /* Babbling receiver */ 1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_BABT ((uint)0x20000000) /* Babbling transmitter */ 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_GRA ((uint)0x10000000) /* Graceful stop complete */ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_TXF ((uint)0x08000000) /* Full frame transmitted */ 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_TXB ((uint)0x04000000) /* A buffer was transmitted */ 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_RXF ((uint)0x02000000) /* Full frame received */ 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */ 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */ 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */ 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1724bee1f9ac066ef0350b961eab9fedc4d0bd0a549Wolfram Sang#define FEC_DEFAULT_IMASK (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII) 1734bee1f9ac066ef0350b961eab9fedc4d0bd0a549Wolfram Sang 1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The FEC stores dest/src/type, data, and checksum for receive packets. 1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_MAXBUF_SIZE 1518 1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_MINBUF_SIZE 64 1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define PKT_MAXBLR_SIZE 1520 1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 180c7c83d1c95b84cf0e71e947613a5d409cf0ebca1Xiao Jiang/* This device has up to three irqs on some platforms */ 181c7c83d1c95b84cf0e71e947613a5d409cf0ebca1Xiao Jiang#define FEC_IRQ_NUM 3 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1846b2652936b9e61df47664a8dde46872a74d7dba2Matt Waddel * The 5270/5271/5280/5282/532x RX control register also contains maximum frame 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * size bits. Other FEC hardware does not, so we need to take that into 1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * account when setting it. 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 188562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \ 189085e79ed88351d2f3cbf257ff4fc00394792da18Uwe Kleine-König defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARM) 1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPT_FRAME_SIZE (PKT_MAXBUF_SIZE << 16) 1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPT_FRAME_SIZE 0 1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* The FEC buffer descriptors track the ring buffers. The rx_bd_base and 1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * tx_bd_base always point to the base of the buffer descriptors. The 1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * cur_rx and cur_tx point to the currently available buffer. 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The dirty_tx tracks the current buffer that is being sent by the 1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * controller. The cur_tx and dirty_tx are equal under both completely 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * empty and completely full conditions. The empty/ready indicator in 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the buffer descriptor determines the actual condition. 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct fec_enet_private { 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Hardware registers of the FEC device */ 205f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer void __iomem *hwp; 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 207cb84d6e7ad10bd679df1787a1fc9624432a73317Greg Ungerer struct net_device *netdev; 208cb84d6e7ad10bd679df1787a1fc9624432a73317Greg Ungerer 209ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct clk *clk; 210ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* The saved address of a sent-in-place packet/buffer, for skfree(). */ 2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char *tx_bounce[TX_RING_SIZE]; 2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff* tx_skbuff[TX_RING_SIZE]; 214f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct sk_buff* rx_skbuff[RX_RING_SIZE]; 2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort skb_cur; 2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort skb_dirty; 2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 21822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* CPM dual port RAM relative addresses */ 2194661e75b9d7bb12bcbe9be8bbf40ebf0845879a9Sascha Hauer dma_addr_t bd_dma; 22022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Address of Rx and Tx buffers */ 2212e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer struct bufdesc *rx_bd_base; 2222e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer struct bufdesc *tx_bd_base; 2232e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer /* The next free ring entry */ 224db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König struct bufdesc *cur_rx, *cur_tx; 22522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* The ring entries to be free()ed */ 2262e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer struct bufdesc *dirty_tx; 2272e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer 2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds uint tx_full; 2293b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */ 2303b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior spinlock_t hw_lock; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 232db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König struct platform_device *pdev; 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 234e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu int opened; 23543af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo int dev_id; 2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 237e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* Phylib and MDIO interface */ 238db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König struct mii_bus *mii_bus; 239db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König struct phy_device *phy_dev; 240db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König int mii_timeout; 241db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König uint phy_speed; 2425eb32bd059379530fc3809a7fcf183feca75f601Baruch Siach phy_interface_t phy_interface; 2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int link; 2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int full_duplex; 24597b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach struct completion mdio_done; 2467f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang int irq[FEC_IRQ_NUM]; 2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 249e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu/* FEC MII MMFR bits definition */ 250e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu#define FEC_MMFR_ST (1 << 30) 251e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu#define FEC_MMFR_OP_READ (2 << 28) 252e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu#define FEC_MMFR_OP_WRITE (1 << 28) 253e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu#define FEC_MMFR_PA(v) ((v & 0x1f) << 23) 254e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu#define FEC_MMFR_RA(v) ((v & 0x1f) << 18) 255e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu#define FEC_MMFR_TA (2 << 16) 256e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu#define FEC_MMFR_DATA(v) (v & 0xffff) 2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 258c3b084c24c8a372026d95497dbb0da22c6eb591cRogerio Pimentel#define FEC_MII_TIMEOUT 30000 /* us */ 2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 26022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer/* Transmitter timeout */ 26122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer#define TX_TIMEOUT (2 * HZ) 2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 263e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmannstatic int mii_cnt; 264e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann 265b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guostatic void *swap_buffer(void *bufaddr, int len) 266b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo{ 267b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo int i; 268b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo unsigned int *buf = bufaddr; 269b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 270b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo for (i = 0; i < (len + 3) / 4; i++, buf++) 271b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo *buf = cpu_to_be32(*buf); 272b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 273b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo return bufaddr; 274b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo} 275b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 276c7621cb3d9a2c42d2fed7e16845611c8c6fd5835Denis Kirjanovstatic netdev_tx_t 277c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_enet_start_xmit(struct sk_buff *skb, struct net_device *ndev) 2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 279c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 280b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo const struct platform_device_id *id_entry = 281b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo platform_get_device_id(fep->pdev); 2822e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer struct bufdesc *bdp; 2839555b31e8c29d2000e1e1f569f6f242ebd596e47Greg Ungerer void *bufaddr; 2840e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer unsigned short status; 2853b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior unsigned long flags; 2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!fep->link) { 2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Link is down or autonegotiation is in progress. */ 2895b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy return NETDEV_TX_BUSY; 2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2923b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior spin_lock_irqsave(&fep->hw_lock, flags); 2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fill in a Tx ring entry */ 2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp = fep->cur_tx; 2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2960e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer status = bdp->cbd_sc; 29722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer 2980e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_READY) { 2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Ooops. All transmit buffers are full. Bail out. 300c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König * This should not happen, since ndev->tbusy should be set. 3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 302c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König printk("%s: tx queue full!.\n", ndev->name); 3033b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior spin_unlock_irqrestore(&fep->hw_lock, flags); 3045b548140225c6bbbbd560551dd1048b2c0ce58bePatrick McHardy return NETDEV_TX_BUSY; 3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 30722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Clear all of the status flags */ 3080e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer status &= ~BD_ENET_TX_STATS; 3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Set buffer length and buffer pointer */ 3119555b31e8c29d2000e1e1f569f6f242ebd596e47Greg Ungerer bufaddr = skb->data; 3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp->cbd_datlen = skb->len; 3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 31522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * On some FEC implementations data must be aligned on 31622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * 4-byte boundaries. Use bounce buffers to copy data 31722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * and get it aligned. Ugh. 3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3199555b31e8c29d2000e1e1f569f6f242ebd596e47Greg Ungerer if (((unsigned long) bufaddr) & FEC_ALIGNMENT) { 3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned int index; 3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds index = bdp - fep->tx_bd_base; 3228a73b0bc86366113e13d079b3de76df6e94a4a5cUwe Kleine-König memcpy(fep->tx_bounce[index], skb->data, skb->len); 3239555b31e8c29d2000e1e1f569f6f242ebd596e47Greg Ungerer bufaddr = fep->tx_bounce[index]; 3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 326b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo /* 327b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * Some design made an incorrect assumption on endian mode of 328b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * the system that it's running on. As the result, driver has to 329b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * swap every frame going to and coming from the controller. 330b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo */ 331b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) 332b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo swap_buffer(bufaddr, skb->len); 333b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 33422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Save skb pointer */ 3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->tx_skbuff[fep->skb_cur] = skb; 3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 337c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_bytes += skb->len; 3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; 3396aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Push the data cache so the CPM does not get stale memory 3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * data. 3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 343d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, 344f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); 3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3460e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer /* Send it on its way. Tell FEC it's ready, interrupt when done, 3470e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer * it's the last BD of the frame, and to put the CRC on the end. 3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 3490e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR 3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds | BD_ENET_TX_LAST | BD_ENET_TX_TC); 3510e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer bdp->cbd_sc = status; 3521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Trigger transmission start */ 354f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer writel(0, fep->hwp + FEC_X_DES_ACTIVE); 3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 35622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* If this was the last BD in the ring, start at the beginning again. */ 35722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_TX_WRAP) 3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp = fep->tx_bd_base; 35922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer else 3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp++; 3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (bdp == fep->dirty_tx) { 3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->tx_full = 1; 364c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König netif_stop_queue(ndev); 3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 3672e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer fep->cur_tx = bdp; 3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 36918a03b9772da749efb8d92bd9893bfe3bd442425Richard Cochran skb_tx_timestamp(skb); 37018a03b9772da749efb8d92bd9893bfe3bd442425Richard Cochran 371a0087a3619e1b137e7dbc91a1b2b5f15c0382412Richard Cochran spin_unlock_irqrestore(&fep->hw_lock, flags); 372a0087a3619e1b137e7dbc91a1b2b5f15c0382412Richard Cochran 3736ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy return NETDEV_TX_OK; 3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 37645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König/* This function is called to start or restart the FEC during a link 37745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * change. This only happens when switching between half and full 37845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * duplex. 37945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König */ 3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 38145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königfec_restart(struct net_device *ndev, int duplex) 3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 383c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 38445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König const struct platform_device_id *id_entry = 38545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König platform_get_device_id(fep->pdev); 38645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König int i; 387cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König u32 temp_mac[2]; 388cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König u32 rcntl = OPT_FRAME_SIZE | 0x04; 389230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo u32 ecntl = 0x2; /* ETHEREN */ 3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Whack a reset. We should wait for this. */ 39245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(1, fep->hwp + FEC_ECNTRL); 39345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König udelay(10); 3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 39545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* 39645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * enet-mac reset will reset mac address registers too, 39745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * so need to reconfigure it. 39845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König */ 39945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { 40045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN); 40145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); 40245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); 40345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Clear any outstanding interrupt. */ 40645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0xffc00000, fep->hwp + FEC_IEVENT); 4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 40845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Reset all multicast. */ 40945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); 41045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); 41145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König#ifndef CONFIG_M5272 41245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); 41345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0, fep->hwp + FEC_HASH_TABLE_LOW); 41445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König#endif 4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Set maximum receive buffer size. */ 41745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); 4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 41945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Set receive and transmit descriptor base. */ 42045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); 42145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, 42245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fep->hwp + FEC_X_DES_START); 42345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 42445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; 42545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fep->cur_rx = fep->rx_bd_base; 42645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 42745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Reset SKB transmit buffers. */ 42845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fep->skb_cur = fep->skb_dirty = 0; 42945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König for (i = 0; i <= TX_RING_MOD_MASK; i++) { 43045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (fep->tx_skbuff[i]) { 43145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König dev_kfree_skb_any(fep->tx_skbuff[i]); 43245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fep->tx_skbuff[i] = NULL; 4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 43445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 43597b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach 43645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Enable MII mode */ 43745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (duplex) { 438cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König /* FD enable */ 43945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0x04, fep->hwp + FEC_X_CNTRL); 44045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } else { 441cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König /* No Rcv on Xmit */ 442cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König rcntl |= 0x02; 44345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0x0, fep->hwp + FEC_X_CNTRL); 44445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 445cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König 44645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fep->full_duplex = duplex; 44745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 44845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Set MII speed */ 44945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 45045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 45145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* 45245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * The phy interface and speed need to get configured 45345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * differently on enet-mac. 45445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König */ 45545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { 456cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König /* Enable flow control and length check */ 457cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König rcntl |= 0x40000000 | 0x00000020; 45845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 459230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo /* RGMII, RMII or MII */ 460230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII) 461230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo rcntl |= (1 << 6); 462230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) 463cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König rcntl |= (1 << 8); 46445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König else 465cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König rcntl &= ~(1 << 8); 46645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 467230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo /* 1G, 100M or 10M */ 468230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo if (fep->phy_dev) { 469230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo if (fep->phy_dev->speed == SPEED_1000) 470230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo ecntl |= (1 << 5); 471230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo else if (fep->phy_dev->speed == SPEED_100) 472230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo rcntl &= ~(1 << 9); 473230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo else 474230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo rcntl |= (1 << 9); 475230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo } 47645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } else { 47745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König#ifdef FEC_MIIGSK_ENR 4780ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) { 4798d82f219c2d476811cd3157a39c7b5c1f045ebc3Eric Benard u32 cfgr; 48045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* disable the gasket and wait */ 48145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0, fep->hwp + FEC_MIIGSK_ENR); 48245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) 48345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König udelay(1); 48445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 48545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* 48645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * configure the gasket: 48745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * RMII, 50 MHz, no loopback, no echo 4880ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo * MII, 25 MHz, no loopback, no echo 48945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König */ 4908d82f219c2d476811cd3157a39c7b5c1f045ebc3Eric Benard cfgr = (fep->phy_interface == PHY_INTERFACE_MODE_RMII) 4918d82f219c2d476811cd3157a39c7b5c1f045ebc3Eric Benard ? BM_MIIGSK_CFGR_RMII : BM_MIIGSK_CFGR_MII; 4928d82f219c2d476811cd3157a39c7b5c1f045ebc3Eric Benard if (fep->phy_dev && fep->phy_dev->speed == SPEED_10) 4938d82f219c2d476811cd3157a39c7b5c1f045ebc3Eric Benard cfgr |= BM_MIIGSK_CFGR_FRCONT_10M; 4948d82f219c2d476811cd3157a39c7b5c1f045ebc3Eric Benard writel(cfgr, fep->hwp + FEC_MIIGSK_CFGR); 49545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 49645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* re-enable the gasket */ 49745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(2, fep->hwp + FEC_MIIGSK_ENR); 49897b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach } 49945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König#endif 50045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 501cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König writel(rcntl, fep->hwp + FEC_R_CNTRL); 5023b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior 503230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { 504230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo /* enable ENET endian swap */ 505230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo ecntl |= (1 << 8); 506230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo /* enable ENET store and forward mode */ 507230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo writel(1 << 8, fep->hwp + FEC_X_WMRK); 508230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo } 509230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo 51045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* And last, enable the transmit and receive processing */ 511230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo writel(ecntl, fep->hwp + FEC_ECNTRL); 51245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0, fep->hwp + FEC_R_DES_ACTIVE); 51345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 51445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Enable interrupts we wish to service */ 51545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 51645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König} 51745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 51845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königstatic void 51945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königfec_stop(struct net_device *ndev) 52045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König{ 52145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 522230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo const struct platform_device_id *id_entry = 523230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo platform_get_device_id(fep->pdev); 52442431dc24de343d62bb8fb885586de7f408919c8Lothar Waßmann u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); 52545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 52645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* We cannot expect a graceful transmit stop without link !!! */ 52745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (fep->link) { 52845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */ 52945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König udelay(10); 53045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA)) 53145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König printk("fec_stop : Graceful transmit stop did not complete !\n"); 53245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 53345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 53445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Whack a reset. We should wait for this. */ 53545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(1, fep->hwp + FEC_ECNTRL); 53645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König udelay(10); 53745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 53845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 539230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo 540230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo /* We have to keep ENET enabled to have MII interrupt stay working */ 54142431dc24de343d62bb8fb885586de7f408919c8Lothar Waßmann if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { 542230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo writel(2, fep->hwp + FEC_ECNTRL); 54342431dc24de343d62bb8fb885586de7f408919c8Lothar Waßmann writel(rmii_mode, fep->hwp + FEC_R_CNTRL); 54442431dc24de343d62bb8fb885586de7f408919c8Lothar Waßmann } 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 54945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königfec_timeout(struct net_device *ndev) 55045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König{ 55145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 55245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 55345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König ndev->stats.tx_errors++; 55445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 55545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fec_restart(ndev, fep->full_duplex); 55645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König netif_wake_queue(ndev); 55745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König} 55845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 55945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königstatic void 560c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_enet_tx(struct net_device *ndev) 5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fec_enet_private *fep; 5632e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer struct bufdesc *bdp; 5640e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer unsigned short status; 5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 567c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fep = netdev_priv(ndev); 56881538e74ca12a71ea37ce72f809ebc65a90b9538Uwe Kleine-König spin_lock(&fep->hw_lock); 5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp = fep->dirty_tx; 5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5710e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { 572f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (bdp == fep->cur_tx && fep->tx_full == 0) 573f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer break; 574f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 575d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, 576d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); 577f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_bufaddr = 0; 5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = fep->tx_skbuff[fep->skb_dirty]; 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check for errors. */ 5810e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | 5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BD_ENET_TX_RL | BD_ENET_TX_UN | 5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BD_ENET_TX_CSL)) { 584c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_errors++; 5850e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_HB) /* No heartbeat */ 586c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_heartbeat_errors++; 5870e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_LC) /* Late collision */ 588c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_window_errors++; 5890e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_RL) /* Retrans limit */ 590c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_aborted_errors++; 5910e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_UN) /* Underrun */ 592c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_fifo_errors++; 5930e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_CSL) /* Carrier lost */ 594c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_carrier_errors++; 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 596c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_packets++; 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5990e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_READY) 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("HEY! Enet xmit interrupt and TX_READY.\n"); 60122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer 6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Deferred means some collisions occurred during transmit, 6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but we eventually sent the packet OK. 6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6050e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_DEF) 606c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.collisions++; 6076aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 60822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Free the sk buffer associated with this last transmit */ 6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->tx_skbuff[fep->skb_dirty] = NULL; 6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; 6126aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 61322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Update pointer to next buffer descriptor to be transmitted */ 6140e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_WRAP) 6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp = fep->tx_bd_base; 6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp++; 6186aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 61922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Since we have freed up a buffer, the ring is no longer full 6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fep->tx_full) { 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->tx_full = 0; 623c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König if (netif_queue_stopped(ndev)) 624c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König netif_wake_queue(ndev); 6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6272e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer fep->dirty_tx = bdp; 62881538e74ca12a71ea37ce72f809ebc65a90b9538Uwe Kleine-König spin_unlock(&fep->hw_lock); 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* During a receive, the cur_rx points to the current incoming buffer. 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When we update through the ring, if the next incoming buffer has 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not been given to the system, we just set the empty indicator, 6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * effectively tossing the packet. 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 638c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_enet_rx(struct net_device *ndev) 6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 640c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 641b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo const struct platform_device_id *id_entry = 642b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo platform_get_device_id(fep->pdev); 6432e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer struct bufdesc *bdp; 6440e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer unsigned short status; 6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort pkt_len; 6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 *data; 6486aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6490e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer#ifdef CONFIG_M532x 6500e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer flush_cache_all(); 6516aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#endif 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65381538e74ca12a71ea37ce72f809ebc65a90b9538Uwe Kleine-König spin_lock(&fep->hw_lock); 6543b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* First, grab all of the stats for the incoming packet. 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These get messed up if we get called due to a busy condition. 6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp = fep->cur_rx; 6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { 6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Since we have allocated space to hold a complete frame, 66322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * the last indicator should be set. 66422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer */ 66522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if ((status & BD_ENET_RX_LAST) == 0) 66622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer printk("FEC ENET: rcv is not +last\n"); 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (!fep->opened) 66922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer goto rx_processing_done; 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 67122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Check for errors. */ 67222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | 6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BD_ENET_RX_CR | BD_ENET_RX_OV)) { 674c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_errors++; 67522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { 67622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Frame too long or too short. */ 677c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_length_errors++; 67822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } 67922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_NO) /* Frame alignment */ 680c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_frame_errors++; 68122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_CR) /* CRC Error */ 682c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_crc_errors++; 68322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_OV) /* FIFO overrun */ 684c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_fifo_errors++; 6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Report late collisions as a frame error. 68822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * On this error, the BD is closed, but we don't know what we 68922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * have in the buffer. So, just drop this frame on the floor. 69022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer */ 69122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_CL) { 692c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_errors++; 693c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_frame_errors++; 69422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer goto rx_processing_done; 69522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } 6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Process the incoming frame. */ 698c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_packets++; 69922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer pkt_len = bdp->cbd_datlen; 700c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_bytes += pkt_len; 70122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer data = (__u8*)__va(bdp->cbd_bufaddr); 7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 703d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, 704d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); 705ccdc4f198193eb4956b8dbc00745270525c4cd6eSascha Hauer 706b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) 707b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo swap_buffer(data, pkt_len); 708b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 70922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* This does 16 byte alignment, exactly what we need. 71022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * The packet length includes FCS, but we don't want to 71122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * include that when passing upstream as it messes up 71222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * bridging applications. 71322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer */ 714b72061a3cb0f1c5aa3f919e2dadb4a1631773e7aFabio Estevam skb = netdev_alloc_skb(ndev, pkt_len - 4 + NET_IP_ALIGN); 7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7168549889c3369f7653bd98861c3d2cf97d810dc37Sascha Hauer if (unlikely(!skb)) { 71722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer printk("%s: Memory squeeze, dropping packet.\n", 718c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->name); 719c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_dropped++; 72022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } else { 7218549889c3369f7653bd98861c3d2cf97d810dc37Sascha Hauer skb_reserve(skb, NET_IP_ALIGN); 72222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer skb_put(skb, pkt_len - 4); /* Make room */ 72322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer skb_copy_to_linear_data(skb, data, pkt_len - 4); 724c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König skb->protocol = eth_type_trans(skb, ndev); 72518a03b9772da749efb8d92bd9893bfe3bd442425Richard Cochran if (!skb_defer_rx_timestamp(skb)) 72618a03b9772da749efb8d92bd9893bfe3bd442425Richard Cochran netif_rx(skb); 72722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } 728f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 729d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data, 730d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); 73122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauerrx_processing_done: 73222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Clear the status flags for this buffer */ 73322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer status &= ~BD_ENET_RX_STATS; 7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Mark the buffer empty */ 73622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer status |= BD_ENET_RX_EMPTY; 73722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer bdp->cbd_sc = status; 7386aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 73922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Update BD pointer to next entry */ 74022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_WRAP) 74122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer bdp = fep->rx_bd_base; 74222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer else 74322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer bdp++; 74422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Doing this here will keep the FEC running while we process 74522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * incoming frames. On a heavily loaded network, we should be 74622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * able to keep up at the expense of system resources. 74722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer */ 74822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer writel(0, fep->hwp + FEC_R_DES_ACTIVE); 74922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } 7502e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer fep->cur_rx = bdp; 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75281538e74ca12a71ea37ce72f809ebc65a90b9538Uwe Kleine-König spin_unlock(&fep->hw_lock); 7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königstatic irqreturn_t 75645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königfec_enet_interrupt(int irq, void *dev_id) 75745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König{ 75845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König struct net_device *ndev = dev_id; 75945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 76045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König uint int_events; 76145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König irqreturn_t ret = IRQ_NONE; 76245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 76345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König do { 76445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König int_events = readl(fep->hwp + FEC_IEVENT); 76545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(int_events, fep->hwp + FEC_IEVENT); 76645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 76745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (int_events & FEC_ENET_RXF) { 76845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König ret = IRQ_HANDLED; 76945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fec_enet_rx(ndev); 77045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 77145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 77245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Transmit OK, or non-fatal error. Update the buffer 77345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * descriptors. FEC handles all errors, we just discover 77445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * them as part of the transmit process. 77545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König */ 77645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (int_events & FEC_ENET_TXF) { 77745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König ret = IRQ_HANDLED; 77845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fec_enet_tx(ndev); 77945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 78045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 78145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (int_events & FEC_ENET_MII) { 78245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König ret = IRQ_HANDLED; 78345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König complete(&fep->mdio_done); 78445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 78545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } while (int_events); 78645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 78745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König return ret; 78845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König} 78945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 79045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 79145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 792e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu/* ------------------------------------------------------------------------- */ 793c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void __inline__ fec_get_mac(struct net_device *ndev) 7941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 795c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 79649da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo struct fec_platform_data *pdata = fep->pdev->dev.platform_data; 797e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu unsigned char *iap, tmpaddr[ETH_ALEN]; 7981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79949da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* 80049da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo * try to get mac address in following order: 80149da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo * 80249da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo * 1) module parameter via kernel command line in form 80349da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo * fec.macaddr=0x00,0x04,0x9f,0x01,0x30,0xe0 80449da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo */ 80549da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo iap = macaddr; 80649da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo 807ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#ifdef CONFIG_OF 808ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo /* 809ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * 2) from device tree data 810ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo */ 811ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (!is_valid_ether_addr(iap)) { 812ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo struct device_node *np = fep->pdev->dev.of_node; 813ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (np) { 814ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo const char *mac = of_get_mac_address(np); 815ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (mac) 816ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo iap = (unsigned char *) mac; 817ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } 818ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } 819ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#endif 820ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 82149da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* 822ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * 3) from flash or fuse (via platform data) 82349da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo */ 82449da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (!is_valid_ether_addr(iap)) { 82549da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo#ifdef CONFIG_M5272 82649da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (FEC_FLASHMAC) 82749da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo iap = (unsigned char *)FEC_FLASHMAC; 82849da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo#else 82949da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (pdata) 830589efdc7f7327bc8ddf597bdaf9de38fcea31744Lothar Waßmann iap = (unsigned char *)&pdata->mac; 83149da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo#endif 83249da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo } 83349da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo 83449da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* 835ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * 4) FEC mac registers set by bootloader 83649da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo */ 83749da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (!is_valid_ether_addr(iap)) { 83849da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo *((unsigned long *) &tmpaddr[0]) = 83949da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo be32_to_cpu(readl(fep->hwp + FEC_ADDR_LOW)); 84049da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo *((unsigned short *) &tmpaddr[4]) = 84149da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo be16_to_cpu(readl(fep->hwp + FEC_ADDR_HIGH) >> 16); 842e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu iap = &tmpaddr[0]; 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 845c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König memcpy(ndev->dev_addr, iap, ETH_ALEN); 8461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84749da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* Adjust MAC if using macaddr */ 84849da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (iap == macaddr) 84943af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->dev_id; 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 852e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu/* ------------------------------------------------------------------------- */ 8531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 854e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu/* 855e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu * Phy section 856e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu */ 857c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void fec_enet_adjust_link(struct net_device *ndev) 8581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 859c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 860e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phy_dev = fep->phy_dev; 861e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu unsigned long flags; 8621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 863e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu int status_change = 0; 8641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 865e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu spin_lock_irqsave(&fep->hw_lock, flags); 8661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 867e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* Prevent a state halted on mii error */ 868e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (fep->mii_timeout && phy_dev->state == PHY_HALTED) { 869e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu phy_dev->state = PHY_RESUMING; 870e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto spin_unlock; 871e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 8721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 873e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* Duplex link change */ 874e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (phy_dev->link) { 875e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (fep->full_duplex != phy_dev->duplex) { 876c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_restart(ndev, phy_dev->duplex); 8776ea0722fb8cdeacc774733c259d33bf45529e91bLothar Waßmann /* prevent unnecessary second fec_restart() below */ 8786ea0722fb8cdeacc774733c259d33bf45529e91bLothar Waßmann fep->link = phy_dev->link; 879e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu status_change = 1; 880e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 881e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 8821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 883e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* Link on or off change */ 884e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (phy_dev->link != fep->link) { 885e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->link = phy_dev->link; 886e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (phy_dev->link) 887c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_restart(ndev, phy_dev->duplex); 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 889c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_stop(ndev); 890e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu status_change = 1; 8911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8926aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 893e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wuspin_unlock: 894e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu spin_unlock_irqrestore(&fep->hw_lock, flags); 8951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 896e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (status_change) 897e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu phy_print_status(phy_dev); 898e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu} 8991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 900e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 902e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct fec_enet_private *fep = bus->priv; 90397b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach unsigned long time_left; 9041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 905e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_timeout = 0; 90697b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach init_completion(&fep->mdio_done); 907e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 908e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* start a read op */ 909e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu writel(FEC_MMFR_ST | FEC_MMFR_OP_READ | 910e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | 911e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu FEC_MMFR_TA, fep->hwp + FEC_MII_DATA); 912e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 913e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* wait for end of transfer */ 91497b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach time_left = wait_for_completion_timeout(&fep->mdio_done, 91597b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach usecs_to_jiffies(FEC_MII_TIMEOUT)); 91697b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach if (time_left == 0) { 91797b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach fep->mii_timeout = 1; 91897b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach printk(KERN_ERR "FEC: MDIO read timeout\n"); 91997b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach return -ETIMEDOUT; 9201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 922e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* return value */ 923e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA)); 9247dd6a2aa27a7a8036fbaf60cbce38a64128d1d4dGreg Ungerer} 9256aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 926e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, 927e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu u16 value) 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 929e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct fec_enet_private *fep = bus->priv; 93097b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach unsigned long time_left; 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 932e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_timeout = 0; 93397b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach init_completion(&fep->mdio_done); 9341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 935862f0982eadcea0e114576c57ea426d3d51a69a6Shawn Guo /* start a write op */ 936862f0982eadcea0e114576c57ea426d3d51a69a6Shawn Guo writel(FEC_MMFR_ST | FEC_MMFR_OP_WRITE | 937e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | 938e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu FEC_MMFR_TA | FEC_MMFR_DATA(value), 939e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->hwp + FEC_MII_DATA); 940e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 941e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* wait for end of transfer */ 94297b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach time_left = wait_for_completion_timeout(&fep->mdio_done, 94397b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach usecs_to_jiffies(FEC_MII_TIMEOUT)); 94497b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach if (time_left == 0) { 94597b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach fep->mii_timeout = 1; 94697b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach printk(KERN_ERR "FEC: MDIO write timeout\n"); 94797b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach return -ETIMEDOUT; 948e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 950e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return 0; 951e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu} 9521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 953e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic int fec_enet_mdio_reset(struct mii_bus *bus) 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 955e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return 0; 9561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 958c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_mii_probe(struct net_device *ndev) 959562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer{ 960c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 961230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo const struct platform_device_id *id_entry = 962230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo platform_get_device_id(fep->pdev); 963e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phy_dev = NULL; 9646fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer char mdio_bus_id[MII_BUS_ID_SIZE]; 9656fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer char phy_name[MII_BUS_ID_SIZE + 3]; 9666fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer int phy_id; 96743af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo int dev_id = fep->dev_id; 968562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer 969418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu fep->phy_dev = NULL; 970418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu 9716fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer /* check for attached phy */ 9726fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) { 9736fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if ((fep->mii_bus->phy_mask & (1 << phy_id))) 9746fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer continue; 9756fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if (fep->mii_bus->phy_map[phy_id] == NULL) 9766fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer continue; 9776fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if (fep->mii_bus->phy_map[phy_id]->phy_id == 0) 9786fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer continue; 979b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo if (dev_id--) 980b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo continue; 9816fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer strncpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE); 9826fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer break; 983e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 9841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9856fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if (phy_id >= PHY_MAX_ADDR) { 986a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann printk(KERN_INFO 987a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann "%s: no PHY, assuming direct connection to switch\n", 988a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann ndev->name); 989ea51ade9398f3c94f63a25f512445ee7cbbbf284Florian Fainelli strncpy(mdio_bus_id, "fixed-0", MII_BUS_ID_SIZE); 9906fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer phy_id = 0; 9916fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer } 9926fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer 993a7ed07d51c8abdb407be454c6cb6cfad613759d9Richard Zhao snprintf(phy_name, sizeof(phy_name), PHY_ID_FMT, mdio_bus_id, phy_id); 994c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0, 995230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo fep->phy_interface); 9966fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if (IS_ERR(phy_dev)) { 997c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name); 9986fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer return PTR_ERR(phy_dev); 999e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 10001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1001e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* mask with MAC supported features */ 1002230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) 1003230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo phy_dev->supported &= PHY_GBIT_FEATURES; 1004230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo else 1005230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo phy_dev->supported &= PHY_BASIC_FEATURES; 1006230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo 1007e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu phy_dev->advertising = phy_dev->supported; 10081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1009e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->phy_dev = phy_dev; 1010e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->link = 0; 1011e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->full_duplex = 0; 10121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1013a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann printk(KERN_INFO 1014a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann "%s: Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", 1015a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann ndev->name, 1016418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev), 1017418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu fep->phy_dev->irq); 1018418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu 1019e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return 0; 10201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1022e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic int fec_enet_mii_init(struct platform_device *pdev) 1023562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer{ 1024b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo static struct mii_bus *fec0_mii_bus; 1025c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct net_device *ndev = platform_get_drvdata(pdev); 1026c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1027b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo const struct platform_device_id *id_entry = 1028b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo platform_get_device_id(fep->pdev); 1029e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu int err = -ENXIO, i; 10306b2652936b9e61df47664a8dde46872a74d7dba2Matt Waddel 1031b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo /* 1032b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * The dual fec interfaces are not equivalent with enet-mac. 1033b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * Here are the differences: 1034b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * 1035b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * - fec0 supports MII & RMII modes while fec1 only supports RMII 1036b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * - fec0 acts as the 1588 time master while fec1 is slave 1037b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * - external phys can only be configured by fec0 1038b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * 1039b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * That is to say fec1 can not work independently. It only works 1040b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * when fec0 is working. The reason behind this design is that the 1041b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * second interface is added primarily for Switch mode. 1042b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * 1043b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * Because of the last point above, both phys are attached on fec0 1044b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * mdio interface in board design, and need to be configured by 1045b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * fec0 mii_bus. 1046b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo */ 104743af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) { 1048b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo /* fec1 uses fec0 mii_bus */ 1049e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann if (mii_cnt && fec0_mii_bus) { 1050e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann fep->mii_bus = fec0_mii_bus; 1051e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann mii_cnt++; 1052e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann return 0; 1053e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann } 1054e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann return -ENOENT; 1055b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo } 1056b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 1057e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_timeout = 0; 10581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1059e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* 1060e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed) 1061230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * 1062230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while 1063230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28 1064230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * Reference Manual has an error on this, and gets fixed on i.MX6Q 1065230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * document. 1066e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu */ 1067230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000); 1068230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) 1069230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo fep->phy_speed--; 1070230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo fep->phy_speed <<= 1; 1071e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 10721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1073e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus = mdiobus_alloc(); 1074e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (fep->mii_bus == NULL) { 1075e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu err = -ENOMEM; 1076e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto err_out; 10771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1079e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->name = "fec_enet_mii_bus"; 1080e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->read = fec_enet_mdio_read; 1081e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->write = fec_enet_mdio_write; 1082e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->reset = fec_enet_mdio_reset; 1083391420f7b829e73b26a543e39c40a83f7de6467cFlorian Fainelli snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x", 1084391420f7b829e73b26a543e39c40a83f7de6467cFlorian Fainelli pdev->name, fep->dev_id + 1); 1085e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->priv = fep; 1086e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->parent = &pdev->dev; 1087e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 1088e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 1089e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (!fep->mii_bus->irq) { 1090e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu err = -ENOMEM; 1091e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto err_out_free_mdiobus; 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1094e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu for (i = 0; i < PHY_MAX_ADDR; i++) 1095e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->irq[i] = PHY_POLL; 10961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1097e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (mdiobus_register(fep->mii_bus)) 1098e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto err_out_free_mdio_irq; 10991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1100e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann mii_cnt++; 1101e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann 1102b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo /* save fec0 mii_bus */ 1103b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) 1104b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo fec0_mii_bus = fep->mii_bus; 1105b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 1106e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return 0; 11071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1108e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wuerr_out_free_mdio_irq: 1109e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu kfree(fep->mii_bus->irq); 1110e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wuerr_out_free_mdiobus: 1111e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu mdiobus_free(fep->mii_bus); 1112e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wuerr_out: 1113e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return err; 11141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1116e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic void fec_enet_mii_remove(struct fec_enet_private *fep) 11171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1118e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann if (--mii_cnt == 0) { 1119e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann mdiobus_unregister(fep->mii_bus); 1120e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann kfree(fep->mii_bus->irq); 1121e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann mdiobus_free(fep->mii_bus); 1122e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann } 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1125c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_get_settings(struct net_device *ndev, 1126e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct ethtool_cmd *cmd) 11271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1128c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1129e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phydev = fep->phy_dev; 11301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1131e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (!phydev) 1132e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return -ENODEV; 11331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1134e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return phy_ethtool_gset(phydev, cmd); 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1137c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_set_settings(struct net_device *ndev, 1138e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct ethtool_cmd *cmd) 11391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1140c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1141e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phydev = fep->phy_dev; 11421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1143e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (!phydev) 1144e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return -ENODEV; 11451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1146e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return phy_ethtool_sset(phydev, cmd); 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1149c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void fec_enet_get_drvinfo(struct net_device *ndev, 1150e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct ethtool_drvinfo *info) 11511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1152c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 11536aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1154e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu strcpy(info->driver, fep->pdev->dev.driver->name); 1155e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu strcpy(info->version, "Revision: 1.0"); 1156c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König strcpy(info->bus_info, dev_name(&ndev->dev)); 11571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 11599b07be4b2a78166bc54c8eedf18da8a8aafacfabstephen hemmingerstatic const struct ethtool_ops fec_enet_ethtool_ops = { 1160e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu .get_settings = fec_enet_get_settings, 1161e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu .set_settings = fec_enet_set_settings, 1162e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu .get_drvinfo = fec_enet_get_drvinfo, 1163e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu .get_link = ethtool_op_get_link, 1164e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu}; 11651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1166c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) 11671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1168c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1169e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phydev = fep->phy_dev; 11701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1171c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König if (!netif_running(ndev)) 1172e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return -EINVAL; 11731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1174e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (!phydev) 1175e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return -ENODEV; 1176e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 117728b041139e344ecd0f144d6205b004ae354cfa1eRichard Cochran return phy_mii_ioctl(phydev, rq, cmd); 11781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1180c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void fec_enet_free_buffers(struct net_device *ndev) 1181f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer{ 1182c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1183f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer int i; 1184f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct sk_buff *skb; 1185f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct bufdesc *bdp; 1186f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1187f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp = fep->rx_bd_base; 1188f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer for (i = 0; i < RX_RING_SIZE; i++) { 1189f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer skb = fep->rx_skbuff[i]; 1190f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1191f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (bdp->cbd_bufaddr) 1192d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, 1193f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); 1194f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (skb) 1195f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer dev_kfree_skb(skb); 1196f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp++; 1197f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer } 1198f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1199f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp = fep->tx_bd_base; 1200f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer for (i = 0; i < TX_RING_SIZE; i++) 1201f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer kfree(fep->tx_bounce[i]); 1202f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer} 1203f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1204c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_alloc_buffers(struct net_device *ndev) 1205f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer{ 1206c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1207f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer int i; 1208f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct sk_buff *skb; 1209f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct bufdesc *bdp; 1210f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1211f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp = fep->rx_bd_base; 1212f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer for (i = 0; i < RX_RING_SIZE; i++) { 1213b72061a3cb0f1c5aa3f919e2dadb4a1631773e7aFabio Estevam skb = netdev_alloc_skb(ndev, FEC_ENET_RX_FRSIZE); 1214f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (!skb) { 1215c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_enet_free_buffers(ndev); 1216f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer return -ENOMEM; 1217f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer } 1218f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer fep->rx_skbuff[i] = skb; 1219f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1220d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, 1221f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); 1222f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_sc = BD_ENET_RX_EMPTY; 1223f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp++; 1224f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer } 1225f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1226f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer /* Set the last buffer to wrap. */ 1227f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp--; 1228f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_sc |= BD_SC_WRAP; 1229f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1230f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp = fep->tx_bd_base; 1231f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer for (i = 0; i < TX_RING_SIZE; i++) { 1232f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); 1233f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1234f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_sc = 0; 1235f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_bufaddr = 0; 1236f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp++; 1237f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer } 1238f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1239f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer /* Set the last buffer to wrap. */ 1240f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp--; 1241f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_sc |= BD_SC_WRAP; 1242f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1243f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer return 0; 1244f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer} 1245f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 12461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 1247c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_enet_open(struct net_device *ndev) 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1249c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1250f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer int ret; 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* I should reset the ring buffers here, but I don't yet know 12531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a simple way to do that. 12541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1256c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ret = fec_enet_alloc_buffers(ndev); 1257f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (ret) 1258f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer return ret; 1259f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1260418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu /* Probe and connect to PHY when open the interface */ 1261c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ret = fec_enet_mii_probe(ndev); 1262418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu if (ret) { 1263c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_enet_free_buffers(ndev); 1264418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu return ret; 1265418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu } 1266e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu phy_start(fep->phy_dev); 1267c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König netif_start_queue(ndev); 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->opened = 1; 126922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer return 0; 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 1273c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_enet_close(struct net_device *ndev) 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1275c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 12761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 127722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Don't know what to do yet. */ 12781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->opened = 0; 1279c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König netif_stop_queue(ndev); 1280c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_stop(ndev); 12811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1282e497ba825b60727f02d8bc21869f445c5aad34e2Uwe Kleine-König if (fep->phy_dev) { 1283e497ba825b60727f02d8bc21869f445c5aad34e2Uwe Kleine-König phy_stop(fep->phy_dev); 1284418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu phy_disconnect(fep->phy_dev); 1285e497ba825b60727f02d8bc21869f445c5aad34e2Uwe Kleine-König } 1286418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu 1287db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König fec_enet_free_buffers(ndev); 1288f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor. 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Skeleton taken from sunlance driver. 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The CPM Ethernet implementation allows Multicast as well as individual 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MAC address filtering. Some of the drivers check to make sure it is 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a group multicast address, and discard those that are not. I guess I 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will do the same for now, but just remove the test if you want 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * individual filtering as well (do the upper net layers want or support 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this kind of feature?). 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 13011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HASH_BITS 6 /* #bits in hash */ 13031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CRC32_POLY 0xEDB88320 13041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1305c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void set_multicast_list(struct net_device *ndev) 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1307c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 130822bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 130948e2f183cb1709600012265a2e723f45a350d5feJiri Pirko unsigned int i, bit, data, crc, tmp; 13101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char hash; 13111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1312c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König if (ndev->flags & IFF_PROMISC) { 1313f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer tmp = readl(fep->hwp + FEC_R_CNTRL); 1314f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer tmp |= 0x8; 1315f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer writel(tmp, fep->hwp + FEC_R_CNTRL); 13164e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer return; 13174e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer } 13181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13194e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp = readl(fep->hwp + FEC_R_CNTRL); 13204e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp &= ~0x8; 13214e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(tmp, fep->hwp + FEC_R_CNTRL); 13224e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 1323c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König if (ndev->flags & IFF_ALLMULTI) { 13244e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer /* Catch all multicast addresses, so set the 13254e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer * filter to all 1's 13264e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer */ 13274e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); 13284e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW); 13294e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 13304e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer return; 13314e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer } 13324e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 13334e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer /* Clear filter and add the addresses in hash register 13344e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer */ 13354e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); 13364e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); 13374e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 1338c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König netdev_for_each_mc_addr(ha, ndev) { 13394e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer /* calculate crc32 value of mac address */ 13404e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer crc = 0xffffffff; 13414e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 1342c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König for (i = 0; i < ndev->addr_len; i++) { 134322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko data = ha->addr[i]; 13444e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer for (bit = 0; bit < 8; bit++, data >>= 1) { 13454e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer crc = (crc >> 1) ^ 13464e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer (((crc ^ data) & 1) ? CRC32_POLY : 0); 13471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13494e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 13504e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer /* only upper 6 bits (HASH_BITS) are used 13514e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer * which point to specific bit in he hash registers 13524e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer */ 13534e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer hash = (crc >> (32 - HASH_BITS)) & 0x3f; 13544e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 13554e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer if (hash > 31) { 13564e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH); 13574e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp |= 1 << (hash - 32); 13584e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); 13594e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer } else { 13604e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW); 13614e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp |= 1 << hash; 13624e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW); 13634e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer } 13641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 136722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer/* Set a MAC change in hardware. */ 1368009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauerstatic int 1369c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_set_mac_address(struct net_device *ndev, void *p) 13701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1371c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1372009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer struct sockaddr *addr = p; 1373009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer 1374009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer if (!is_valid_ether_addr(addr->sa_data)) 1375009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer return -EADDRNOTAVAIL; 1376009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer 1377c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); 13781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1379c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) | 1380c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König (ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24), 1381f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer fep->hwp + FEC_ADDR_LOW); 1382c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König writel((ndev->dev_addr[5] << 16) | (ndev->dev_addr[4] << 24), 13837cff0943a1104479fc9fc2d6ced24c02ba81e73eMattias Walström fep->hwp + FEC_ADDR_HIGH); 1384009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer return 0; 13851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13877f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang#ifdef CONFIG_NET_POLL_CONTROLLER 13887f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang/* 13897f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * fec_poll_controller: FEC Poll controller function 13907f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * @dev: The FEC network adapter 13917f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * 13927f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * Polled functionality used by netconsole and others in non interrupt mode 13937f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * 13947f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang */ 13957f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiangvoid fec_poll_controller(struct net_device *dev) 13967f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang{ 13977f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang int i; 13987f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang struct fec_enet_private *fep = netdev_priv(dev); 13997f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang 14007f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang for (i = 0; i < FEC_IRQ_NUM; i++) { 14017f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang if (fep->irq[i] > 0) { 14027f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang disable_irq(fep->irq[i]); 14037f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang fec_enet_interrupt(fep->irq[i], dev); 14047f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang enable_irq(fep->irq[i]); 14057f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang } 14067f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang } 14077f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang} 14087f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang#endif 14097f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang 1410009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauerstatic const struct net_device_ops fec_netdev_ops = { 1411009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_open = fec_enet_open, 1412009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_stop = fec_enet_close, 1413009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_start_xmit = fec_enet_start_xmit, 1414afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = set_multicast_list, 1415635ecaa70e862f85f652581305fe0074810893beBen Hutchings .ndo_change_mtu = eth_change_mtu, 1416009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_validate_addr = eth_validate_addr, 1417009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_tx_timeout = fec_timeout, 1418009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_set_mac_address = fec_set_mac_address, 1419db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König .ndo_do_ioctl = fec_enet_ioctl, 14207f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang#ifdef CONFIG_NET_POLL_CONTROLLER 14217f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang .ndo_poll_controller = fec_poll_controller, 14227f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang#endif 1423009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer}; 1424009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer 14251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX: We need to clean up on failure exits here. 1427ead731837d142b103eab9870105f50bc40b69255Sascha Hauer * 14281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1429c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_init(struct net_device *ndev) 14301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1431c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1432f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct bufdesc *cbd_base; 1433633e7533cec78b99d806248e832fc83e689d2453Rob Herring struct bufdesc *bdp; 1434f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer int i; 14351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14368d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer /* Allocate memory for buffer descriptors. */ 14378d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, 14388d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer GFP_KERNEL); 14398d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer if (!cbd_base) { 1440562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer printk("FEC: allocate descriptor memory failed?\n"); 1441562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer return -ENOMEM; 1442562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer } 1443562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer 14443b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior spin_lock_init(&fep->hw_lock); 14453b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior 1446c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fep->netdev = ndev; 14471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 144849da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* Get the Ethernet address */ 1449c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_get_mac(ndev); 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14518d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer /* Set receive and transmit descriptor base. */ 14521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->rx_bd_base = cbd_base; 14531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->tx_bd_base = cbd_base + RX_RING_SIZE; 14541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* The FEC Ethernet specific entries in the device structure */ 1456c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->watchdog_timeo = TX_TIMEOUT; 1457c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->netdev_ops = &fec_netdev_ops; 1458c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->ethtool_ops = &fec_enet_ethtool_ops; 1459633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1460633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Initialize the receive buffer descriptors. */ 1461633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp = fep->rx_bd_base; 1462633e7533cec78b99d806248e832fc83e689d2453Rob Herring for (i = 0; i < RX_RING_SIZE; i++) { 1463633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1464633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Initialize the BD for every fragment in the page. */ 1465633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_sc = 0; 1466633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp++; 1467633e7533cec78b99d806248e832fc83e689d2453Rob Herring } 1468633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1469633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Set the last buffer to wrap */ 1470633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp--; 1471633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_sc |= BD_SC_WRAP; 1472633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1473633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* ...and the same for transmit */ 1474633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp = fep->tx_bd_base; 1475633e7533cec78b99d806248e832fc83e689d2453Rob Herring for (i = 0; i < TX_RING_SIZE; i++) { 1476633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1477633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Initialize the BD for every fragment in the page. */ 1478633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_sc = 0; 1479633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_bufaddr = 0; 1480633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp++; 1481633e7533cec78b99d806248e832fc83e689d2453Rob Herring } 1482633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1483633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Set the last buffer to wrap */ 1484633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp--; 1485633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_sc |= BD_SC_WRAP; 1486633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1487c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_restart(ndev, 0); 14881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1492ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#ifdef CONFIG_OF 1493ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guostatic int __devinit fec_get_phy_mode_dt(struct platform_device *pdev) 1494ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo{ 1495ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo struct device_node *np = pdev->dev.of_node; 1496ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1497ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (np) 1498ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo return of_get_phy_mode(np); 1499ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1500ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo return -ENODEV; 1501ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo} 1502ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1503a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guostatic void __devinit fec_reset_phy(struct platform_device *pdev) 1504ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo{ 1505ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo int err, phy_reset; 1506ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo struct device_node *np = pdev->dev.of_node; 1507ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1508ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (!np) 1509a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guo return; 1510ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1511ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); 1512ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo err = gpio_request_one(phy_reset, GPIOF_OUT_INIT_LOW, "phy-reset"); 1513ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (err) { 1514a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guo pr_debug("FEC: failed to get gpio phy-reset: %d\n", err); 1515a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guo return; 1516ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } 1517ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo msleep(1); 1518ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo gpio_set_value(phy_reset, 1); 1519ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo} 1520ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#else /* CONFIG_OF */ 1521ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guostatic inline int fec_get_phy_mode_dt(struct platform_device *pdev) 1522ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo{ 1523ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo return -ENODEV; 1524ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo} 1525ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1526a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guostatic inline void fec_reset_phy(struct platform_device *pdev) 1527ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo{ 1528ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo /* 1529ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * In case of platform probe, the reset has been done 1530ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * by machine code. 1531ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo */ 1532ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo} 1533ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#endif /* CONFIG_OF */ 1534ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1535ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic int __devinit 1536ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfec_probe(struct platform_device *pdev) 1537ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 1538ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct fec_enet_private *fep; 15395eb32bd059379530fc3809a7fcf183feca75f601Baruch Siach struct fec_platform_data *pdata; 1540ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct net_device *ndev; 1541ead731837d142b103eab9870105f50bc40b69255Sascha Hauer int i, irq, ret = 0; 1542ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct resource *r; 1543ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo const struct of_device_id *of_id; 154443af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo static int dev_id; 1545ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1546ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo of_id = of_match_device(fec_dt_ids, &pdev->dev); 1547ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (of_id) 1548ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo pdev->id_entry = of_id->data; 1549ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1550ead731837d142b103eab9870105f50bc40b69255Sascha Hauer r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1551ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (!r) 1552ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return -ENXIO; 1553ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1554ead731837d142b103eab9870105f50bc40b69255Sascha Hauer r = request_mem_region(r->start, resource_size(r), pdev->name); 1555ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (!r) 1556ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return -EBUSY; 1557ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1558ead731837d142b103eab9870105f50bc40b69255Sascha Hauer /* Init network device */ 1559ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ndev = alloc_etherdev(sizeof(struct fec_enet_private)); 156028e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König if (!ndev) { 156128e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König ret = -ENOMEM; 156228e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König goto failed_alloc_etherdev; 156328e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König } 1564ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1565ead731837d142b103eab9870105f50bc40b69255Sascha Hauer SET_NETDEV_DEV(ndev, &pdev->dev); 1566ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1567ead731837d142b103eab9870105f50bc40b69255Sascha Hauer /* setup board info structure */ 1568ead731837d142b103eab9870105f50bc40b69255Sascha Hauer fep = netdev_priv(ndev); 1569ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 157024e531b401752995493fa36ee8d8f10c45038e75Uwe Kleine-König fep->hwp = ioremap(r->start, resource_size(r)); 1571e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->pdev = pdev; 157243af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo fep->dev_id = dev_id++; 1573ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 157424e531b401752995493fa36ee8d8f10c45038e75Uwe Kleine-König if (!fep->hwp) { 1575ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ret = -ENOMEM; 1576ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_ioremap; 1577ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1578ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1579ead731837d142b103eab9870105f50bc40b69255Sascha Hauer platform_set_drvdata(pdev, ndev); 1580ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1581ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo ret = fec_get_phy_mode_dt(pdev); 1582ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (ret < 0) { 1583ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo pdata = pdev->dev.platform_data; 1584ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (pdata) 1585ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo fep->phy_interface = pdata->phy; 1586ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo else 1587ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo fep->phy_interface = PHY_INTERFACE_MODE_MII; 1588ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } else { 1589ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo fep->phy_interface = ret; 1590ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } 1591ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1592ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo fec_reset_phy(pdev); 15935eb32bd059379530fc3809a7fcf183feca75f601Baruch Siach 1594c7c83d1c95b84cf0e71e947613a5d409cf0ebca1Xiao Jiang for (i = 0; i < FEC_IRQ_NUM; i++) { 1595ead731837d142b103eab9870105f50bc40b69255Sascha Hauer irq = platform_get_irq(pdev, i); 159686f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann if (irq < 0) { 159786f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann if (i) 159886f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann break; 159986f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann ret = irq; 160086f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann goto failed_irq; 160186f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann } 1602ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); 1603ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (ret) { 1604b2b09ad63cc09448e49f6a4addae6e078c0e5e36Uwe Kleine-König while (--i >= 0) { 1605ead731837d142b103eab9870105f50bc40b69255Sascha Hauer irq = platform_get_irq(pdev, i); 1606ead731837d142b103eab9870105f50bc40b69255Sascha Hauer free_irq(irq, ndev); 1607ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1608ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_irq; 1609ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1610ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1611ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 16125b1436c1f94e591e240845edee835658ce98985eLothar Waßmann fep->clk = clk_get(&pdev->dev, NULL); 1613ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (IS_ERR(fep->clk)) { 1614ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ret = PTR_ERR(fep->clk); 1615ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_clk; 1616ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 16170ebafefcaa7a383b728d977a718e23e69ce84050Richard Zhao clk_prepare_enable(fep->clk); 1618ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 16198649a230e33320b00f778a6f7c17a2764e844730Shawn Guo ret = fec_enet_init(ndev); 1620ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (ret) 1621ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_init; 1622ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1623e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu ret = fec_enet_mii_init(pdev); 1624e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (ret) 1625e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto failed_mii_init; 1626e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 162703c698c93fc15d976738a853a7ccb6ea26396003Oskar Schirmer /* Carrier starts down, phylib will bring it up */ 162803c698c93fc15d976738a853a7ccb6ea26396003Oskar Schirmer netif_carrier_off(ndev); 162903c698c93fc15d976738a853a7ccb6ea26396003Oskar Schirmer 1630ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ret = register_netdev(ndev); 1631ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (ret) 1632ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_register; 1633ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1634ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return 0; 1635ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1636ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_register: 1637e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fec_enet_mii_remove(fep); 1638e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wufailed_mii_init: 1639ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_init: 16400ebafefcaa7a383b728d977a718e23e69ce84050Richard Zhao clk_disable_unprepare(fep->clk); 1641ead731837d142b103eab9870105f50bc40b69255Sascha Hauer clk_put(fep->clk); 1642ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_clk: 1643c7c83d1c95b84cf0e71e947613a5d409cf0ebca1Xiao Jiang for (i = 0; i < FEC_IRQ_NUM; i++) { 1644ead731837d142b103eab9870105f50bc40b69255Sascha Hauer irq = platform_get_irq(pdev, i); 1645ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (irq > 0) 1646ead731837d142b103eab9870105f50bc40b69255Sascha Hauer free_irq(irq, ndev); 1647ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1648ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_irq: 164924e531b401752995493fa36ee8d8f10c45038e75Uwe Kleine-König iounmap(fep->hwp); 1650ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_ioremap: 1651ead731837d142b103eab9870105f50bc40b69255Sascha Hauer free_netdev(ndev); 165228e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-Königfailed_alloc_etherdev: 165328e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König release_mem_region(r->start, resource_size(r)); 1654ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1655ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return ret; 1656ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1657ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1658ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic int __devexit 1659ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfec_drv_remove(struct platform_device *pdev) 1660ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 1661ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct net_device *ndev = platform_get_drvdata(pdev); 1662ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct fec_enet_private *fep = netdev_priv(ndev); 166328e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König struct resource *r; 1664e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann int i; 1665ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1666e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann unregister_netdev(ndev); 1667e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fec_enet_mii_remove(fep); 1668e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann for (i = 0; i < FEC_IRQ_NUM; i++) { 1669e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann int irq = platform_get_irq(pdev, i); 1670e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann if (irq > 0) 1671e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann free_irq(irq, ndev); 1672e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann } 16730ebafefcaa7a383b728d977a718e23e69ce84050Richard Zhao clk_disable_unprepare(fep->clk); 1674ead731837d142b103eab9870105f50bc40b69255Sascha Hauer clk_put(fep->clk); 167524e531b401752995493fa36ee8d8f10c45038e75Uwe Kleine-König iounmap(fep->hwp); 1676ead731837d142b103eab9870105f50bc40b69255Sascha Hauer free_netdev(ndev); 167728e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König 167828e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 167928e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König BUG_ON(!r); 168028e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König release_mem_region(r->start, resource_size(r)); 168128e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König 1682b3cde36cf1e19f696cb302ea426b5cf6ab4afb8aUwe Kleine-König platform_set_drvdata(pdev, NULL); 1683b3cde36cf1e19f696cb302ea426b5cf6ab4afb8aUwe Kleine-König 1684ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return 0; 1685ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1686ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 168759d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov#ifdef CONFIG_PM 1688ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic int 168987cad5c385877ce45244886748564672fd6db035Eric Benardfec_suspend(struct device *dev) 1690ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 169187cad5c385877ce45244886748564672fd6db035Eric Benard struct net_device *ndev = dev_get_drvdata(dev); 169204e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1693ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 169404e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König if (netif_running(ndev)) { 169504e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König fec_stop(ndev); 169604e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König netif_device_detach(ndev); 1697ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 16980ebafefcaa7a383b728d977a718e23e69ce84050Richard Zhao clk_disable_unprepare(fep->clk); 169904e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König 1700ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return 0; 1701ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1702ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1703ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic int 170487cad5c385877ce45244886748564672fd6db035Eric Benardfec_resume(struct device *dev) 1705ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 170687cad5c385877ce45244886748564672fd6db035Eric Benard struct net_device *ndev = dev_get_drvdata(dev); 170704e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1708ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 17090ebafefcaa7a383b728d977a718e23e69ce84050Richard Zhao clk_prepare_enable(fep->clk); 171004e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König if (netif_running(ndev)) { 171104e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König fec_restart(ndev, fep->full_duplex); 171204e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König netif_device_attach(ndev); 1713ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 171404e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König 1715ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return 0; 1716ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1717ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 171859d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanovstatic const struct dev_pm_ops fec_pm_ops = { 171959d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .suspend = fec_suspend, 172059d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .resume = fec_resume, 172159d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .freeze = fec_suspend, 172259d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .thaw = fec_resume, 172359d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .poweroff = fec_suspend, 172459d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .restore = fec_resume, 172559d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov}; 172687cad5c385877ce45244886748564672fd6db035Eric Benard#endif 172759d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov 1728ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic struct platform_driver fec_driver = { 1729ead731837d142b103eab9870105f50bc40b69255Sascha Hauer .driver = { 1730b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo .name = DRIVER_NAME, 173187cad5c385877ce45244886748564672fd6db035Eric Benard .owner = THIS_MODULE, 173287cad5c385877ce45244886748564672fd6db035Eric Benard#ifdef CONFIG_PM 173387cad5c385877ce45244886748564672fd6db035Eric Benard .pm = &fec_pm_ops, 173487cad5c385877ce45244886748564672fd6db035Eric Benard#endif 1735ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo .of_match_table = fec_dt_ids, 1736ead731837d142b103eab9870105f50bc40b69255Sascha Hauer }, 1737b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo .id_table = fec_devtype, 173887cad5c385877ce45244886748564672fd6db035Eric Benard .probe = fec_probe, 173987cad5c385877ce45244886748564672fd6db035Eric Benard .remove = __devexit_p(fec_drv_remove), 1740ead731837d142b103eab9870105f50bc40b69255Sascha Hauer}; 1741ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1742aaca2377e9c08d1964a5cacb95330708a6f6d106Fabio Estevammodule_platform_driver(fec_driver); 17431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1745