fec.c revision c3b084c24c8a372026d95497dbb0da22c6eb591c
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) { 47945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* disable the gasket and wait */ 48045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0, fep->hwp + FEC_MIIGSK_ENR); 48145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) 48245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König udelay(1); 48345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 48445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* 48545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * configure the gasket: 48645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * RMII, 50 MHz, no loopback, no echo 4870ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo * MII, 25 MHz, no loopback, no echo 48845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König */ 4890ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo writel((fep->phy_interface == PHY_INTERFACE_MODE_RMII) ? 4900ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo 1 : 0, fep->hwp + FEC_MIIGSK_CFGR); 4910ca1e290b7c517300bf6cc4f14ebcedb5dfea5ccShawn Guo 49245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 49345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* re-enable the gasket */ 49445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(2, fep->hwp + FEC_MIIGSK_ENR); 49597b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach } 49645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König#endif 49745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 498cd1f402c18cf31b38bb304bc0c320669762ac50bUwe Kleine-König writel(rcntl, fep->hwp + FEC_R_CNTRL); 4993b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior 500230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { 501230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo /* enable ENET endian swap */ 502230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo ecntl |= (1 << 8); 503230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo /* enable ENET store and forward mode */ 504230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo writel(1 << 8, fep->hwp + FEC_X_WMRK); 505230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo } 506230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo 50745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* And last, enable the transmit and receive processing */ 508230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo writel(ecntl, fep->hwp + FEC_ECNTRL); 50945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(0, fep->hwp + FEC_R_DES_ACTIVE); 51045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 51145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Enable interrupts we wish to service */ 51245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 51345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König} 51445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 51545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königstatic void 51645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königfec_stop(struct net_device *ndev) 51745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König{ 51845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 519230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo const struct platform_device_id *id_entry = 520230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo platform_get_device_id(fep->pdev); 52142431dc24de343d62bb8fb885586de7f408919c8Lothar Waßmann u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); 52245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 52345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* We cannot expect a graceful transmit stop without link !!! */ 52445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (fep->link) { 52545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */ 52645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König udelay(10); 52745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA)) 52845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König printk("fec_stop : Graceful transmit stop did not complete !\n"); 52945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 53045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 53145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Whack a reset. We should wait for this. */ 53245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(1, fep->hwp + FEC_ECNTRL); 53345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König udelay(10); 53445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 53545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); 536230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo 537230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo /* We have to keep ENET enabled to have MII interrupt stay working */ 53842431dc24de343d62bb8fb885586de7f408919c8Lothar Waßmann if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { 539230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo writel(2, fep->hwp + FEC_ECNTRL); 54042431dc24de343d62bb8fb885586de7f408919c8Lothar Waßmann writel(rmii_mode, fep->hwp + FEC_R_CNTRL); 54142431dc24de343d62bb8fb885586de7f408919c8Lothar Waßmann } 5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 54645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königfec_timeout(struct net_device *ndev) 54745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König{ 54845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 54945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 55045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König ndev->stats.tx_errors++; 55145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 55245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fec_restart(ndev, fep->full_duplex); 55345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König netif_wake_queue(ndev); 55445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König} 55545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 55645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königstatic void 557c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_enet_tx(struct net_device *ndev) 5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct fec_enet_private *fep; 5602e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer struct bufdesc *bdp; 5610e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer unsigned short status; 5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 564c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fep = netdev_priv(ndev); 56581538e74ca12a71ea37ce72f809ebc65a90b9538Uwe Kleine-König spin_lock(&fep->hw_lock); 5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp = fep->dirty_tx; 5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5680e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { 569f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (bdp == fep->cur_tx && fep->tx_full == 0) 570f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer break; 571f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 572d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, 573d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); 574f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_bufaddr = 0; 5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds skb = fep->tx_skbuff[fep->skb_dirty]; 5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Check for errors. */ 5780e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | 5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BD_ENET_TX_RL | BD_ENET_TX_UN | 5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BD_ENET_TX_CSL)) { 581c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_errors++; 5820e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_HB) /* No heartbeat */ 583c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_heartbeat_errors++; 5840e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_LC) /* Late collision */ 585c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_window_errors++; 5860e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_RL) /* Retrans limit */ 587c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_aborted_errors++; 5880e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_UN) /* Underrun */ 589c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_fifo_errors++; 5900e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_CSL) /* Carrier lost */ 591c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_carrier_errors++; 5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 593c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.tx_packets++; 5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 5960e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_READY) 5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds printk("HEY! Enet xmit interrupt and TX_READY.\n"); 59822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer 5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Deferred means some collisions occurred during transmit, 6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but we eventually sent the packet OK. 6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6020e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_DEF) 603c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.collisions++; 6046aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 60522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Free the sk buffer associated with this last transmit */ 6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev_kfree_skb_any(skb); 6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->tx_skbuff[fep->skb_dirty] = NULL; 6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; 6096aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 61022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Update pointer to next buffer descriptor to be transmitted */ 6110e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer if (status & BD_ENET_TX_WRAP) 6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp = fep->tx_bd_base; 6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp++; 6156aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 61622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Since we have freed up a buffer, the ring is no longer full 6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (fep->tx_full) { 6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->tx_full = 0; 620c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König if (netif_queue_stopped(ndev)) 621c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König netif_wake_queue(ndev); 6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6242e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer fep->dirty_tx = bdp; 62581538e74ca12a71ea37ce72f809ebc65a90b9538Uwe Kleine-König spin_unlock(&fep->hw_lock); 6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* During a receive, the cur_rx points to the current incoming buffer. 6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * When we update through the ring, if the next incoming buffer has 6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * not been given to the system, we just set the empty indicator, 6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * effectively tossing the packet. 6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void 635c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_enet_rx(struct net_device *ndev) 6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 637c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 638b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo const struct platform_device_id *id_entry = 639b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo platform_get_device_id(fep->pdev); 6402e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer struct bufdesc *bdp; 6410e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer unsigned short status; 6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sk_buff *skb; 6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ushort pkt_len; 6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds __u8 *data; 6456aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 6460e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer#ifdef CONFIG_M532x 6470e702ab38b0eed1ea5968f3b60b352e814172c27Greg Ungerer flush_cache_all(); 6486aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik#endif 6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65081538e74ca12a71ea37ce72f809ebc65a90b9538Uwe Kleine-König spin_lock(&fep->hw_lock); 6513b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior 6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* First, grab all of the stats for the incoming packet. 6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * These get messed up if we get called due to a busy condition. 6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds bdp = fep->cur_rx; 6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { 6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 65922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Since we have allocated space to hold a complete frame, 66022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * the last indicator should be set. 66122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer */ 66222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if ((status & BD_ENET_RX_LAST) == 0) 66322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer printk("FEC ENET: rcv is not +last\n"); 6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (!fep->opened) 66622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer goto rx_processing_done; 6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 66822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Check for errors. */ 66922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | 6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds BD_ENET_RX_CR | BD_ENET_RX_OV)) { 671c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_errors++; 67222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { 67322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Frame too long or too short. */ 674c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_length_errors++; 67522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } 67622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_NO) /* Frame alignment */ 677c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_frame_errors++; 67822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_CR) /* CRC Error */ 679c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_crc_errors++; 68022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_OV) /* FIFO overrun */ 681c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_fifo_errors++; 6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 68422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Report late collisions as a frame error. 68522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * On this error, the BD is closed, but we don't know what we 68622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * have in the buffer. So, just drop this frame on the floor. 68722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer */ 68822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_CL) { 689c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_errors++; 690c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_frame_errors++; 69122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer goto rx_processing_done; 69222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } 6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 69422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Process the incoming frame. */ 695c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_packets++; 69622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer pkt_len = bdp->cbd_datlen; 697c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_bytes += pkt_len; 69822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer data = (__u8*)__va(bdp->cbd_bufaddr); 6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 700d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, 701d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); 702ccdc4f198193eb4956b8dbc00745270525c4cd6eSascha Hauer 703b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) 704b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo swap_buffer(data, pkt_len); 705b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 70622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* This does 16 byte alignment, exactly what we need. 70722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * The packet length includes FCS, but we don't want to 70822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * include that when passing upstream as it messes up 70922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * bridging applications. 71022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer */ 7118549889c3369f7653bd98861c3d2cf97d810dc37Sascha Hauer skb = dev_alloc_skb(pkt_len - 4 + NET_IP_ALIGN); 7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 7138549889c3369f7653bd98861c3d2cf97d810dc37Sascha Hauer if (unlikely(!skb)) { 71422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer printk("%s: Memory squeeze, dropping packet.\n", 715c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->name); 716c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->stats.rx_dropped++; 71722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } else { 7188549889c3369f7653bd98861c3d2cf97d810dc37Sascha Hauer skb_reserve(skb, NET_IP_ALIGN); 71922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer skb_put(skb, pkt_len - 4); /* Make room */ 72022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer skb_copy_to_linear_data(skb, data, pkt_len - 4); 721c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König skb->protocol = eth_type_trans(skb, ndev); 72218a03b9772da749efb8d92bd9893bfe3bd442425Richard Cochran if (!skb_defer_rx_timestamp(skb)) 72318a03b9772da749efb8d92bd9893bfe3bd442425Richard Cochran netif_rx(skb); 72422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } 725f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 726d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data, 727d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); 72822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauerrx_processing_done: 72922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Clear the status flags for this buffer */ 73022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer status &= ~BD_ENET_RX_STATS; 7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 73222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Mark the buffer empty */ 73322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer status |= BD_ENET_RX_EMPTY; 73422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer bdp->cbd_sc = status; 7356aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 73622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Update BD pointer to next entry */ 73722f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer if (status & BD_ENET_RX_WRAP) 73822f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer bdp = fep->rx_bd_base; 73922f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer else 74022f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer bdp++; 74122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Doing this here will keep the FEC running while we process 74222f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * incoming frames. On a heavily loaded network, we should be 74322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer * able to keep up at the expense of system resources. 74422f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer */ 74522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer writel(0, fep->hwp + FEC_R_DES_ACTIVE); 74622f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer } 7472e28532f7e63c3011f7b3c1516cfebd5321bdd15Sascha Hauer fep->cur_rx = bdp; 7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 74981538e74ca12a71ea37ce72f809ebc65a90b9538Uwe Kleine-König spin_unlock(&fep->hw_lock); 7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 75245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königstatic irqreturn_t 75345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-Königfec_enet_interrupt(int irq, void *dev_id) 75445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König{ 75545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König struct net_device *ndev = dev_id; 75645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 75745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König uint int_events; 75845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König irqreturn_t ret = IRQ_NONE; 75945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 76045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König do { 76145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König int_events = readl(fep->hwp + FEC_IEVENT); 76245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König writel(int_events, fep->hwp + FEC_IEVENT); 76345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 76445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (int_events & FEC_ENET_RXF) { 76545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König ret = IRQ_HANDLED; 76645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fec_enet_rx(ndev); 76745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 76845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 76945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König /* Transmit OK, or non-fatal error. Update the buffer 77045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * descriptors. FEC handles all errors, we just discover 77145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König * them as part of the transmit process. 77245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König */ 77345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (int_events & FEC_ENET_TXF) { 77445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König ret = IRQ_HANDLED; 77545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König fec_enet_tx(ndev); 77645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 77745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 77845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König if (int_events & FEC_ENET_MII) { 77945993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König ret = IRQ_HANDLED; 78045993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König complete(&fep->mdio_done); 78145993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } 78245993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König } while (int_events); 78345993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 78445993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König return ret; 78545993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König} 78645993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 78745993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 78845993653bd5935dbf975bc26a834f2ff23c9f914Uwe Kleine-König 789e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu/* ------------------------------------------------------------------------- */ 790c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void __inline__ fec_get_mac(struct net_device *ndev) 7911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 792c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 79349da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo struct fec_platform_data *pdata = fep->pdev->dev.platform_data; 794e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu unsigned char *iap, tmpaddr[ETH_ALEN]; 7951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 79649da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* 79749da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo * try to get mac address in following order: 79849da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo * 79949da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo * 1) module parameter via kernel command line in form 80049da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo * fec.macaddr=0x00,0x04,0x9f,0x01,0x30,0xe0 80149da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo */ 80249da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo iap = macaddr; 80349da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo 804ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#ifdef CONFIG_OF 805ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo /* 806ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * 2) from device tree data 807ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo */ 808ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (!is_valid_ether_addr(iap)) { 809ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo struct device_node *np = fep->pdev->dev.of_node; 810ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (np) { 811ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo const char *mac = of_get_mac_address(np); 812ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (mac) 813ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo iap = (unsigned char *) mac; 814ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } 815ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } 816ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#endif 817ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 81849da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* 819ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * 3) from flash or fuse (via platform data) 82049da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo */ 82149da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (!is_valid_ether_addr(iap)) { 82249da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo#ifdef CONFIG_M5272 82349da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (FEC_FLASHMAC) 82449da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo iap = (unsigned char *)FEC_FLASHMAC; 82549da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo#else 82649da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (pdata) 827589efdc7f7327bc8ddf597bdaf9de38fcea31744Lothar Waßmann iap = (unsigned char *)&pdata->mac; 82849da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo#endif 82949da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo } 83049da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo 83149da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* 832ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * 4) FEC mac registers set by bootloader 83349da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo */ 83449da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (!is_valid_ether_addr(iap)) { 83549da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo *((unsigned long *) &tmpaddr[0]) = 83649da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo be32_to_cpu(readl(fep->hwp + FEC_ADDR_LOW)); 83749da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo *((unsigned short *) &tmpaddr[4]) = 83849da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo be16_to_cpu(readl(fep->hwp + FEC_ADDR_HIGH) >> 16); 839e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu iap = &tmpaddr[0]; 8401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 842c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König memcpy(ndev->dev_addr, iap, ETH_ALEN); 8431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 84449da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* Adjust MAC if using macaddr */ 84549da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo if (iap == macaddr) 84643af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo ndev->dev_addr[ETH_ALEN-1] = macaddr[ETH_ALEN-1] + fep->dev_id; 8471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 8481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 849e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu/* ------------------------------------------------------------------------- */ 8501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 851e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu/* 852e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu * Phy section 853e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu */ 854c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void fec_enet_adjust_link(struct net_device *ndev) 8551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 856c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 857e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phy_dev = fep->phy_dev; 858e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu unsigned long flags; 8591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 860e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu int status_change = 0; 8611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 862e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu spin_lock_irqsave(&fep->hw_lock, flags); 8631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 864e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* Prevent a state halted on mii error */ 865e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (fep->mii_timeout && phy_dev->state == PHY_HALTED) { 866e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu phy_dev->state = PHY_RESUMING; 867e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto spin_unlock; 868e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 8691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 870e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* Duplex link change */ 871e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (phy_dev->link) { 872e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (fep->full_duplex != phy_dev->duplex) { 873c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_restart(ndev, phy_dev->duplex); 8746ea0722fb8cdeacc774733c259d33bf45529e91bLothar Waßmann /* prevent unnecessary second fec_restart() below */ 8756ea0722fb8cdeacc774733c259d33bf45529e91bLothar Waßmann fep->link = phy_dev->link; 876e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu status_change = 1; 877e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 878e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 8791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 880e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* Link on or off change */ 881e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (phy_dev->link != fep->link) { 882e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->link = phy_dev->link; 883e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (phy_dev->link) 884c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_restart(ndev, phy_dev->duplex); 8851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds else 886c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_stop(ndev); 887e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu status_change = 1; 8881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 8896aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 890e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wuspin_unlock: 891e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu spin_unlock_irqrestore(&fep->hw_lock, flags); 8921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 893e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (status_change) 894e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu phy_print_status(phy_dev); 895e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu} 8961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 897e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic int fec_enet_mdio_read(struct mii_bus *bus, int mii_id, int regnum) 8981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 899e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct fec_enet_private *fep = bus->priv; 90097b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach unsigned long time_left; 9011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 902e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_timeout = 0; 90397b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach init_completion(&fep->mdio_done); 904e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 905e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* start a read op */ 906e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu writel(FEC_MMFR_ST | FEC_MMFR_OP_READ | 907e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | 908e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu FEC_MMFR_TA, fep->hwp + FEC_MII_DATA); 909e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 910e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* wait for end of transfer */ 91197b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach time_left = wait_for_completion_timeout(&fep->mdio_done, 91297b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach usecs_to_jiffies(FEC_MII_TIMEOUT)); 91397b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach if (time_left == 0) { 91497b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach fep->mii_timeout = 1; 91597b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach printk(KERN_ERR "FEC: MDIO read timeout\n"); 91697b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach return -ETIMEDOUT; 9171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 9181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 919e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* return value */ 920e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return FEC_MMFR_DATA(readl(fep->hwp + FEC_MII_DATA)); 9217dd6a2aa27a7a8036fbaf60cbce38a64128d1d4dGreg Ungerer} 9226aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 923e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic int fec_enet_mdio_write(struct mii_bus *bus, int mii_id, int regnum, 924e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu u16 value) 9251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 926e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct fec_enet_private *fep = bus->priv; 92797b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach unsigned long time_left; 9281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 929e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_timeout = 0; 93097b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach init_completion(&fep->mdio_done); 9311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 932862f0982eadcea0e114576c57ea426d3d51a69a6Shawn Guo /* start a write op */ 933862f0982eadcea0e114576c57ea426d3d51a69a6Shawn Guo writel(FEC_MMFR_ST | FEC_MMFR_OP_WRITE | 934e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu FEC_MMFR_PA(mii_id) | FEC_MMFR_RA(regnum) | 935e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu FEC_MMFR_TA | FEC_MMFR_DATA(value), 936e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->hwp + FEC_MII_DATA); 937e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 938e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* wait for end of transfer */ 93997b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach time_left = wait_for_completion_timeout(&fep->mdio_done, 94097b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach usecs_to_jiffies(FEC_MII_TIMEOUT)); 94197b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach if (time_left == 0) { 94297b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach fep->mii_timeout = 1; 94397b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach printk(KERN_ERR "FEC: MDIO write timeout\n"); 94497b72e4320a9aaa4a7f1592ee7d2da7e2c9bd349Baruch Siach return -ETIMEDOUT; 945e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 9461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 947e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return 0; 948e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu} 9491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 950e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic int fec_enet_mdio_reset(struct mii_bus *bus) 9511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 952e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return 0; 9531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 9541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 955c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_mii_probe(struct net_device *ndev) 956562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer{ 957c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 958230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo const struct platform_device_id *id_entry = 959230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo platform_get_device_id(fep->pdev); 960e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phy_dev = NULL; 9616fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer char mdio_bus_id[MII_BUS_ID_SIZE]; 9626fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer char phy_name[MII_BUS_ID_SIZE + 3]; 9636fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer int phy_id; 96443af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo int dev_id = fep->dev_id; 965562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer 966418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu fep->phy_dev = NULL; 967418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu 9686fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer /* check for attached phy */ 9696fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer for (phy_id = 0; (phy_id < PHY_MAX_ADDR); phy_id++) { 9706fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if ((fep->mii_bus->phy_mask & (1 << phy_id))) 9716fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer continue; 9726fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if (fep->mii_bus->phy_map[phy_id] == NULL) 9736fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer continue; 9746fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if (fep->mii_bus->phy_map[phy_id]->phy_id == 0) 9756fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer continue; 976b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo if (dev_id--) 977b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo continue; 9786fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer strncpy(mdio_bus_id, fep->mii_bus->id, MII_BUS_ID_SIZE); 9796fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer break; 980e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 9811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 9826fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if (phy_id >= PHY_MAX_ADDR) { 983a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann printk(KERN_INFO 984a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann "%s: no PHY, assuming direct connection to switch\n", 985a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann ndev->name); 9866fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer strncpy(mdio_bus_id, "0", MII_BUS_ID_SIZE); 9876fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer phy_id = 0; 9886fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer } 9896fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer 9906fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer snprintf(phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, mdio_bus_id, phy_id); 991c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König phy_dev = phy_connect(ndev, phy_name, &fec_enet_adjust_link, 0, 992230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo fep->phy_interface); 9936fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer if (IS_ERR(phy_dev)) { 994c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König printk(KERN_ERR "%s: could not attach to PHY\n", ndev->name); 9956fcc040f02d281c7e9563127358a77ce2bbfe284Greg Ungerer return PTR_ERR(phy_dev); 996e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu } 9971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 998e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* mask with MAC supported features */ 999230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo if (id_entry->driver_data & FEC_QUIRK_HAS_GBIT) 1000230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo phy_dev->supported &= PHY_GBIT_FEATURES; 1001230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo else 1002230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo phy_dev->supported &= PHY_BASIC_FEATURES; 1003230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo 1004e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu phy_dev->advertising = phy_dev->supported; 10051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1006e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->phy_dev = phy_dev; 1007e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->link = 0; 1008e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->full_duplex = 0; 10091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1010a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann printk(KERN_INFO 1011a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann "%s: Freescale FEC PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", 1012a7dd3219b915577e12612ac5d269e1bd22c6fb65Lothar Waßmann ndev->name, 1013418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu fep->phy_dev->drv->name, dev_name(&fep->phy_dev->dev), 1014418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu fep->phy_dev->irq); 1015418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu 1016e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return 0; 10171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 10181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1019e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic int fec_enet_mii_init(struct platform_device *pdev) 1020562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer{ 1021b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo static struct mii_bus *fec0_mii_bus; 1022c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct net_device *ndev = platform_get_drvdata(pdev); 1023c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1024b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo const struct platform_device_id *id_entry = 1025b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo platform_get_device_id(fep->pdev); 1026e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu int err = -ENXIO, i; 10276b2652936b9e61df47664a8dde46872a74d7dba2Matt Waddel 1028b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo /* 1029b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * The dual fec interfaces are not equivalent with enet-mac. 1030b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * Here are the differences: 1031b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * 1032b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * - fec0 supports MII & RMII modes while fec1 only supports RMII 1033b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * - fec0 acts as the 1588 time master while fec1 is slave 1034b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * - external phys can only be configured by fec0 1035b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * 1036b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * That is to say fec1 can not work independently. It only works 1037b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * when fec0 is working. The reason behind this design is that the 1038b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * second interface is added primarily for Switch mode. 1039b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * 1040b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * Because of the last point above, both phys are attached on fec0 1041b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * mdio interface in board design, and need to be configured by 1042b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo * fec0 mii_bus. 1043b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo */ 104443af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo if ((id_entry->driver_data & FEC_QUIRK_ENET_MAC) && fep->dev_id > 0) { 1045b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo /* fec1 uses fec0 mii_bus */ 1046e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann if (mii_cnt && fec0_mii_bus) { 1047e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann fep->mii_bus = fec0_mii_bus; 1048e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann mii_cnt++; 1049e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann return 0; 1050e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann } 1051e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann return -ENOENT; 1052b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo } 1053b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 1054e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_timeout = 0; 10551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1056e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu /* 1057e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu * Set MII speed to 2.5 MHz (= clk_get_rate() / 2 * phy_speed) 1058230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * 1059230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * The formula for FEC MDC is 'ref_freq / (MII_SPEED x 2)' while 1060230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * for ENET-MAC is 'ref_freq / ((MII_SPEED + 1) x 2)'. The i.MX28 1061230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * Reference Manual has an error on this, and gets fixed on i.MX6Q 1062230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo * document. 1063e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu */ 1064230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo fep->phy_speed = DIV_ROUND_UP(clk_get_rate(fep->clk), 5000000); 1065230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) 1066230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo fep->phy_speed--; 1067230dec61313dc5f5720311d0b492f69f5466b0a4Shawn Guo fep->phy_speed <<= 1; 1068e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); 10691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1070e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus = mdiobus_alloc(); 1071e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (fep->mii_bus == NULL) { 1072e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu err = -ENOMEM; 1073e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto err_out; 10741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1076e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->name = "fec_enet_mii_bus"; 1077e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->read = fec_enet_mdio_read; 1078e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->write = fec_enet_mdio_write; 1079e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->reset = fec_enet_mdio_reset; 108043af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo snprintf(fep->mii_bus->id, MII_BUS_ID_SIZE, "%x", fep->dev_id + 1); 1081e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->priv = fep; 1082e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->parent = &pdev->dev; 1083e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 1084e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); 1085e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (!fep->mii_bus->irq) { 1086e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu err = -ENOMEM; 1087e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto err_out_free_mdiobus; 10881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 10891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1090e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu for (i = 0; i < PHY_MAX_ADDR; i++) 1091e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->mii_bus->irq[i] = PHY_POLL; 10921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1093e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (mdiobus_register(fep->mii_bus)) 1094e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto err_out_free_mdio_irq; 10951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1096e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann mii_cnt++; 1097e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann 1098b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo /* save fec0 mii_bus */ 1099b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) 1100b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo fec0_mii_bus = fep->mii_bus; 1101b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo 1102e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return 0; 11031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1104e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wuerr_out_free_mdio_irq: 1105e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu kfree(fep->mii_bus->irq); 1106e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wuerr_out_free_mdiobus: 1107e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu mdiobus_free(fep->mii_bus); 1108e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wuerr_out: 1109e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return err; 11101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1112e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic void fec_enet_mii_remove(struct fec_enet_private *fep) 11131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1114e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann if (--mii_cnt == 0) { 1115e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann mdiobus_unregister(fep->mii_bus); 1116e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann kfree(fep->mii_bus->irq); 1117e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann mdiobus_free(fep->mii_bus); 1118e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann } 11191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1121c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_get_settings(struct net_device *ndev, 1122e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct ethtool_cmd *cmd) 11231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1124c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1125e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phydev = fep->phy_dev; 11261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1127e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (!phydev) 1128e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return -ENODEV; 11291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1130e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return phy_ethtool_gset(phydev, cmd); 11311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1133c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_set_settings(struct net_device *ndev, 1134e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct ethtool_cmd *cmd) 11351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1136c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1137e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phydev = fep->phy_dev; 11381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1139e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (!phydev) 1140e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return -ENODEV; 11411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1142e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return phy_ethtool_sset(phydev, cmd); 11431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1145c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void fec_enet_get_drvinfo(struct net_device *ndev, 1146e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct ethtool_drvinfo *info) 11471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1148c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 11496aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 1150e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu strcpy(info->driver, fep->pdev->dev.driver->name); 1151e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu strcpy(info->version, "Revision: 1.0"); 1152c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König strcpy(info->bus_info, dev_name(&ndev->dev)); 11531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1155e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wustatic struct ethtool_ops fec_enet_ethtool_ops = { 1156e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu .get_settings = fec_enet_get_settings, 1157e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu .set_settings = fec_enet_set_settings, 1158e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu .get_drvinfo = fec_enet_get_drvinfo, 1159e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu .get_link = ethtool_op_get_link, 1160e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu}; 11611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1162c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) 11631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1164c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1165e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu struct phy_device *phydev = fep->phy_dev; 11661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1167c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König if (!netif_running(ndev)) 1168e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return -EINVAL; 11691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1170e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (!phydev) 1171e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu return -ENODEV; 1172e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 117328b041139e344ecd0f144d6205b004ae354cfa1eRichard Cochran return phy_mii_ioctl(phydev, rq, cmd); 11741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 11751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1176c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void fec_enet_free_buffers(struct net_device *ndev) 1177f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer{ 1178c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1179f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer int i; 1180f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct sk_buff *skb; 1181f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct bufdesc *bdp; 1182f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1183f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp = fep->rx_bd_base; 1184f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer for (i = 0; i < RX_RING_SIZE; i++) { 1185f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer skb = fep->rx_skbuff[i]; 1186f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1187f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (bdp->cbd_bufaddr) 1188d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, 1189f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); 1190f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (skb) 1191f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer dev_kfree_skb(skb); 1192f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp++; 1193f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer } 1194f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1195f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp = fep->tx_bd_base; 1196f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer for (i = 0; i < TX_RING_SIZE; i++) 1197f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer kfree(fep->tx_bounce[i]); 1198f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer} 1199f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1200c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_alloc_buffers(struct net_device *ndev) 1201f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer{ 1202c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1203f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer int i; 1204f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct sk_buff *skb; 1205f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct bufdesc *bdp; 1206f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1207f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp = fep->rx_bd_base; 1208f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer for (i = 0; i < RX_RING_SIZE; i++) { 1209f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE); 1210f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (!skb) { 1211c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_enet_free_buffers(ndev); 1212f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer return -ENOMEM; 1213f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer } 1214f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer fep->rx_skbuff[i] = skb; 1215f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1216d1ab1f54a1b0fb0ae6479fad6e26983f09fd263aUwe Kleine-König bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, skb->data, 1217f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer FEC_ENET_RX_FRSIZE, DMA_FROM_DEVICE); 1218f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_sc = BD_ENET_RX_EMPTY; 1219f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp++; 1220f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer } 1221f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1222f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer /* Set the last buffer to wrap. */ 1223f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp--; 1224f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_sc |= BD_SC_WRAP; 1225f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1226f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp = fep->tx_bd_base; 1227f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer for (i = 0; i < TX_RING_SIZE; i++) { 1228f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer fep->tx_bounce[i] = kmalloc(FEC_ENET_TX_FRSIZE, GFP_KERNEL); 1229f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1230f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_sc = 0; 1231f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_bufaddr = 0; 1232f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp++; 1233f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer } 1234f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1235f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer /* Set the last buffer to wrap. */ 1236f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp--; 1237f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer bdp->cbd_sc |= BD_SC_WRAP; 1238f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1239f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer return 0; 1240f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer} 1241f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 12421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 1243c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_enet_open(struct net_device *ndev) 12441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1245c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1246f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer int ret; 12471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* I should reset the ring buffers here, but I don't yet know 12491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a simple way to do that. 12501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1252c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ret = fec_enet_alloc_buffers(ndev); 1253f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer if (ret) 1254f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer return ret; 1255f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 1256418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu /* Probe and connect to PHY when open the interface */ 1257c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ret = fec_enet_mii_probe(ndev); 1258418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu if (ret) { 1259c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_enet_free_buffers(ndev); 1260418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu return ret; 1261418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu } 1262e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu phy_start(fep->phy_dev); 1263c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König netif_start_queue(ndev); 12641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->opened = 1; 126522f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer return 0; 12661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int 1269c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_enet_close(struct net_device *ndev) 12701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1271c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 12721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 127322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* Don't know what to do yet. */ 12741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->opened = 0; 1275c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König netif_stop_queue(ndev); 1276c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_stop(ndev); 12771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1278e497ba825b60727f02d8bc21869f445c5aad34e2Uwe Kleine-König if (fep->phy_dev) { 1279e497ba825b60727f02d8bc21869f445c5aad34e2Uwe Kleine-König phy_stop(fep->phy_dev); 1280418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu phy_disconnect(fep->phy_dev); 1281e497ba825b60727f02d8bc21869f445c5aad34e2Uwe Kleine-König } 1282418bd0d4dfbff25ffe4365ddd3e7cba8c70ccba8Bryan Wu 1283db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König fec_enet_free_buffers(ndev); 1284f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer 12851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 12861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 12871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Set or clear the multicast filter for this adaptor. 12891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Skeleton taken from sunlance driver. 12901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * The CPM Ethernet implementation allows Multicast as well as individual 12911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MAC address filtering. Some of the drivers check to make sure it is 12921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * a group multicast address, and discard those that are not. I guess I 12931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * will do the same for now, but just remove the test if you want 12941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * individual filtering as well (do the upper net layers want or support 12951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * this kind of feature?). 12961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 12971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define HASH_BITS 6 /* #bits in hash */ 12991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define CRC32_POLY 0xEDB88320 13001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1301c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic void set_multicast_list(struct net_device *ndev) 13021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1303c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 130422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 130548e2f183cb1709600012265a2e723f45a350d5feJiri Pirko unsigned int i, bit, data, crc, tmp; 13061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds unsigned char hash; 13071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1308c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König if (ndev->flags & IFF_PROMISC) { 1309f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer tmp = readl(fep->hwp + FEC_R_CNTRL); 1310f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer tmp |= 0x8; 1311f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer writel(tmp, fep->hwp + FEC_R_CNTRL); 13124e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer return; 13134e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer } 13141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13154e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp = readl(fep->hwp + FEC_R_CNTRL); 13164e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp &= ~0x8; 13174e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(tmp, fep->hwp + FEC_R_CNTRL); 13184e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 1319c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König if (ndev->flags & IFF_ALLMULTI) { 13204e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer /* Catch all multicast addresses, so set the 13214e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer * filter to all 1's 13224e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer */ 13234e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); 13244e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(0xffffffff, fep->hwp + FEC_GRP_HASH_TABLE_LOW); 13254e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 13264e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer return; 13274e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer } 13284e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 13294e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer /* Clear filter and add the addresses in hash register 13304e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer */ 13314e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); 13324e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); 13334e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 1334c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König netdev_for_each_mc_addr(ha, ndev) { 13354e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer /* calculate crc32 value of mac address */ 13364e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer crc = 0xffffffff; 13374e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 1338c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König for (i = 0; i < ndev->addr_len; i++) { 133922bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko data = ha->addr[i]; 13404e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer for (bit = 0; bit < 8; bit++, data >>= 1) { 13414e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer crc = (crc >> 1) ^ 13424e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer (((crc ^ data) & 1) ? CRC32_POLY : 0); 13431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13454e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 13464e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer /* only upper 6 bits (HASH_BITS) are used 13474e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer * which point to specific bit in he hash registers 13484e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer */ 13494e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer hash = (crc >> (32 - HASH_BITS)) & 0x3f; 13504e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer 13514e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer if (hash > 31) { 13524e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_HIGH); 13534e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp |= 1 << (hash - 32); 13544e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); 13554e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer } else { 13564e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp = readl(fep->hwp + FEC_GRP_HASH_TABLE_LOW); 13574e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer tmp |= 1 << hash; 13584e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer writel(tmp, fep->hwp + FEC_GRP_HASH_TABLE_LOW); 13594e8318368af44488f6438a31537ddb57de0d4e00Sascha Hauer } 13601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 13611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 136322f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer/* Set a MAC change in hardware. */ 1364009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauerstatic int 1365c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königfec_set_mac_address(struct net_device *ndev, void *p) 13661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1367c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1368009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer struct sockaddr *addr = p; 1369009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer 1370009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer if (!is_valid_ether_addr(addr->sa_data)) 1371009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer return -EADDRNOTAVAIL; 1372009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer 1373c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len); 13741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1375c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König writel(ndev->dev_addr[3] | (ndev->dev_addr[2] << 8) | 1376c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König (ndev->dev_addr[1] << 16) | (ndev->dev_addr[0] << 24), 1377f44d6305280378cb34319e0118e18d84cc7ac773Sascha Hauer fep->hwp + FEC_ADDR_LOW); 1378c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König writel((ndev->dev_addr[5] << 16) | (ndev->dev_addr[4] << 24), 13797cff0943a1104479fc9fc2d6ced24c02ba81e73eMattias Walström fep->hwp + FEC_ADDR_HIGH); 1380009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer return 0; 13811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 13821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13837f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang#ifdef CONFIG_NET_POLL_CONTROLLER 13847f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang/* 13857f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * fec_poll_controller: FEC Poll controller function 13867f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * @dev: The FEC network adapter 13877f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * 13887f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * Polled functionality used by netconsole and others in non interrupt mode 13897f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang * 13907f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang */ 13917f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiangvoid fec_poll_controller(struct net_device *dev) 13927f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang{ 13937f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang int i; 13947f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang struct fec_enet_private *fep = netdev_priv(dev); 13957f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang 13967f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang for (i = 0; i < FEC_IRQ_NUM; i++) { 13977f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang if (fep->irq[i] > 0) { 13987f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang disable_irq(fep->irq[i]); 13997f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang fec_enet_interrupt(fep->irq[i], dev); 14007f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang enable_irq(fep->irq[i]); 14017f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang } 14027f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang } 14037f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang} 14047f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang#endif 14057f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang 1406009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauerstatic const struct net_device_ops fec_netdev_ops = { 1407009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_open = fec_enet_open, 1408009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_stop = fec_enet_close, 1409009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_start_xmit = fec_enet_start_xmit, 1410afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = set_multicast_list, 1411635ecaa70e862f85f652581305fe0074810893beBen Hutchings .ndo_change_mtu = eth_change_mtu, 1412009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_validate_addr = eth_validate_addr, 1413009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_tx_timeout = fec_timeout, 1414009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer .ndo_set_mac_address = fec_set_mac_address, 1415db8880bc92657559320ba8384acb2547d4255521Uwe Kleine-König .ndo_do_ioctl = fec_enet_ioctl, 14167f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang#ifdef CONFIG_NET_POLL_CONTROLLER 14177f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang .ndo_poll_controller = fec_poll_controller, 14187f5c6addcdc039c1a7c435857e6284ecac5d97c8Xiao Jiang#endif 1419009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer}; 1420009fda83ee2f38e5deb9d62fc54a904a92645fe4Sascha Hauer 14211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* 14221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * XXX: We need to clean up on failure exits here. 1423ead731837d142b103eab9870105f50bc40b69255Sascha Hauer * 14241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 1425c556167f819160e157b4d73937885de8754ea53cUwe Kleine-Königstatic int fec_enet_init(struct net_device *ndev) 14261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1427c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1428f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer struct bufdesc *cbd_base; 1429633e7533cec78b99d806248e832fc83e689d2453Rob Herring struct bufdesc *bdp; 1430f0b3fbeae11a526c3d308b691684589ee37c359bSascha Hauer int i; 14311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14328d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer /* Allocate memory for buffer descriptors. */ 14338d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer cbd_base = dma_alloc_coherent(NULL, PAGE_SIZE, &fep->bd_dma, 14348d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer GFP_KERNEL); 14358d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer if (!cbd_base) { 1436562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer printk("FEC: allocate descriptor memory failed?\n"); 1437562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer return -ENOMEM; 1438562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer } 1439562d2f8ce4e463e1427ddfab5e84440323856f43Greg Ungerer 14403b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior spin_lock_init(&fep->hw_lock); 14413b2b74cad34e7a0cf6d4929ee9e8ad4e11a84867Sebastian Siewior 1442c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fep->netdev = ndev; 14431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 144449da97dcb6b00a6869bbc3fa6ec7fdfd8a6e41a3Shawn Guo /* Get the Ethernet address */ 1445c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_get_mac(ndev); 14461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14478d4dd5cff892e18a34422852c05a88b79ff978edSascha Hauer /* Set receive and transmit descriptor base. */ 14481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->rx_bd_base = cbd_base; 14491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds fep->tx_bd_base = cbd_base + RX_RING_SIZE; 14501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 145122f6b860da25abe2c3e33347ccb806e6bcc57390Sascha Hauer /* The FEC Ethernet specific entries in the device structure */ 1452c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->watchdog_timeo = TX_TIMEOUT; 1453c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->netdev_ops = &fec_netdev_ops; 1454c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König ndev->ethtool_ops = &fec_enet_ethtool_ops; 1455633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1456633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Initialize the receive buffer descriptors. */ 1457633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp = fep->rx_bd_base; 1458633e7533cec78b99d806248e832fc83e689d2453Rob Herring for (i = 0; i < RX_RING_SIZE; i++) { 1459633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1460633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Initialize the BD for every fragment in the page. */ 1461633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_sc = 0; 1462633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp++; 1463633e7533cec78b99d806248e832fc83e689d2453Rob Herring } 1464633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1465633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Set the last buffer to wrap */ 1466633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp--; 1467633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_sc |= BD_SC_WRAP; 1468633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1469633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* ...and the same for transmit */ 1470633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp = fep->tx_bd_base; 1471633e7533cec78b99d806248e832fc83e689d2453Rob Herring for (i = 0; i < TX_RING_SIZE; i++) { 1472633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1473633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Initialize the BD for every fragment in the page. */ 1474633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_sc = 0; 1475633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_bufaddr = 0; 1476633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp++; 1477633e7533cec78b99d806248e832fc83e689d2453Rob Herring } 1478633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1479633e7533cec78b99d806248e832fc83e689d2453Rob Herring /* Set the last buffer to wrap */ 1480633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp--; 1481633e7533cec78b99d806248e832fc83e689d2453Rob Herring bdp->cbd_sc |= BD_SC_WRAP; 1482633e7533cec78b99d806248e832fc83e689d2453Rob Herring 1483c556167f819160e157b4d73937885de8754ea53cUwe Kleine-König fec_restart(ndev, 0); 14841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 14851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 14861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 14871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1488ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#ifdef CONFIG_OF 1489ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guostatic int __devinit fec_get_phy_mode_dt(struct platform_device *pdev) 1490ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo{ 1491ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo struct device_node *np = pdev->dev.of_node; 1492ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1493ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (np) 1494ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo return of_get_phy_mode(np); 1495ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1496ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo return -ENODEV; 1497ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo} 1498ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1499a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guostatic void __devinit fec_reset_phy(struct platform_device *pdev) 1500ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo{ 1501ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo int err, phy_reset; 1502ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo struct device_node *np = pdev->dev.of_node; 1503ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1504ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (!np) 1505a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guo return; 1506ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1507ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0); 1508ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo err = gpio_request_one(phy_reset, GPIOF_OUT_INIT_LOW, "phy-reset"); 1509ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (err) { 1510a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guo pr_debug("FEC: failed to get gpio phy-reset: %d\n", err); 1511a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guo return; 1512ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } 1513ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo msleep(1); 1514ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo gpio_set_value(phy_reset, 1); 1515ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo} 1516ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#else /* CONFIG_OF */ 1517ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guostatic inline int fec_get_phy_mode_dt(struct platform_device *pdev) 1518ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo{ 1519ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo return -ENODEV; 1520ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo} 1521ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1522a9b2c8ef1585e1f14cec03777b1238e0d5ec4ea1Shawn Guostatic inline void fec_reset_phy(struct platform_device *pdev) 1523ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo{ 1524ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo /* 1525ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * In case of platform probe, the reset has been done 1526ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo * by machine code. 1527ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo */ 1528ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo} 1529ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo#endif /* CONFIG_OF */ 1530ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1531ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic int __devinit 1532ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfec_probe(struct platform_device *pdev) 1533ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 1534ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct fec_enet_private *fep; 15355eb32bd059379530fc3809a7fcf183feca75f601Baruch Siach struct fec_platform_data *pdata; 1536ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct net_device *ndev; 1537ead731837d142b103eab9870105f50bc40b69255Sascha Hauer int i, irq, ret = 0; 1538ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct resource *r; 1539ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo const struct of_device_id *of_id; 154043af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo static int dev_id; 1541ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1542ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo of_id = of_match_device(fec_dt_ids, &pdev->dev); 1543ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (of_id) 1544ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo pdev->id_entry = of_id->data; 1545ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1546ead731837d142b103eab9870105f50bc40b69255Sascha Hauer r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1547ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (!r) 1548ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return -ENXIO; 1549ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1550ead731837d142b103eab9870105f50bc40b69255Sascha Hauer r = request_mem_region(r->start, resource_size(r), pdev->name); 1551ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (!r) 1552ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return -EBUSY; 1553ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1554ead731837d142b103eab9870105f50bc40b69255Sascha Hauer /* Init network device */ 1555ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ndev = alloc_etherdev(sizeof(struct fec_enet_private)); 155628e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König if (!ndev) { 155728e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König ret = -ENOMEM; 155828e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König goto failed_alloc_etherdev; 155928e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König } 1560ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1561ead731837d142b103eab9870105f50bc40b69255Sascha Hauer SET_NETDEV_DEV(ndev, &pdev->dev); 1562ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1563ead731837d142b103eab9870105f50bc40b69255Sascha Hauer /* setup board info structure */ 1564ead731837d142b103eab9870105f50bc40b69255Sascha Hauer fep = netdev_priv(ndev); 1565ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 156624e531b401752995493fa36ee8d8f10c45038e75Uwe Kleine-König fep->hwp = ioremap(r->start, resource_size(r)); 1567e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fep->pdev = pdev; 156843af940c54d712ab5e6d6798a82498b25c2af299Shawn Guo fep->dev_id = dev_id++; 1569ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 157024e531b401752995493fa36ee8d8f10c45038e75Uwe Kleine-König if (!fep->hwp) { 1571ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ret = -ENOMEM; 1572ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_ioremap; 1573ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1574ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1575ead731837d142b103eab9870105f50bc40b69255Sascha Hauer platform_set_drvdata(pdev, ndev); 1576ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1577ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo ret = fec_get_phy_mode_dt(pdev); 1578ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (ret < 0) { 1579ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo pdata = pdev->dev.platform_data; 1580ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo if (pdata) 1581ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo fep->phy_interface = pdata->phy; 1582ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo else 1583ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo fep->phy_interface = PHY_INTERFACE_MODE_MII; 1584ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } else { 1585ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo fep->phy_interface = ret; 1586ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo } 1587ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo 1588ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo fec_reset_phy(pdev); 15895eb32bd059379530fc3809a7fcf183feca75f601Baruch Siach 1590c7c83d1c95b84cf0e71e947613a5d409cf0ebca1Xiao Jiang for (i = 0; i < FEC_IRQ_NUM; i++) { 1591ead731837d142b103eab9870105f50bc40b69255Sascha Hauer irq = platform_get_irq(pdev, i); 159286f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann if (irq < 0) { 159386f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann if (i) 159486f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann break; 159586f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann ret = irq; 159686f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann goto failed_irq; 159786f9f2c81c44223b1be129d0b15cf6edac2a5278Lothar Waßmann } 1598ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ret = request_irq(irq, fec_enet_interrupt, IRQF_DISABLED, pdev->name, ndev); 1599ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (ret) { 1600b2b09ad63cc09448e49f6a4addae6e078c0e5e36Uwe Kleine-König while (--i >= 0) { 1601ead731837d142b103eab9870105f50bc40b69255Sascha Hauer irq = platform_get_irq(pdev, i); 1602ead731837d142b103eab9870105f50bc40b69255Sascha Hauer free_irq(irq, ndev); 1603ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1604ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_irq; 1605ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1606ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1607ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 16085b1436c1f94e591e240845edee835658ce98985eLothar Waßmann fep->clk = clk_get(&pdev->dev, NULL); 1609ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (IS_ERR(fep->clk)) { 1610ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ret = PTR_ERR(fep->clk); 1611ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_clk; 1612ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1613ead731837d142b103eab9870105f50bc40b69255Sascha Hauer clk_enable(fep->clk); 1614ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 16158649a230e33320b00f778a6f7c17a2764e844730Shawn Guo ret = fec_enet_init(ndev); 1616ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (ret) 1617ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_init; 1618ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1619e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu ret = fec_enet_mii_init(pdev); 1620e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu if (ret) 1621e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu goto failed_mii_init; 1622e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu 162303c698c93fc15d976738a853a7ccb6ea26396003Oskar Schirmer /* Carrier starts down, phylib will bring it up */ 162403c698c93fc15d976738a853a7ccb6ea26396003Oskar Schirmer netif_carrier_off(ndev); 162503c698c93fc15d976738a853a7ccb6ea26396003Oskar Schirmer 1626ead731837d142b103eab9870105f50bc40b69255Sascha Hauer ret = register_netdev(ndev); 1627ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (ret) 1628ead731837d142b103eab9870105f50bc40b69255Sascha Hauer goto failed_register; 1629ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1630ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return 0; 1631ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1632ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_register: 1633e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fec_enet_mii_remove(fep); 1634e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wufailed_mii_init: 1635ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_init: 1636ead731837d142b103eab9870105f50bc40b69255Sascha Hauer clk_disable(fep->clk); 1637ead731837d142b103eab9870105f50bc40b69255Sascha Hauer clk_put(fep->clk); 1638ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_clk: 1639c7c83d1c95b84cf0e71e947613a5d409cf0ebca1Xiao Jiang for (i = 0; i < FEC_IRQ_NUM; i++) { 1640ead731837d142b103eab9870105f50bc40b69255Sascha Hauer irq = platform_get_irq(pdev, i); 1641ead731837d142b103eab9870105f50bc40b69255Sascha Hauer if (irq > 0) 1642ead731837d142b103eab9870105f50bc40b69255Sascha Hauer free_irq(irq, ndev); 1643ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 1644ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_irq: 164524e531b401752995493fa36ee8d8f10c45038e75Uwe Kleine-König iounmap(fep->hwp); 1646ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfailed_ioremap: 1647ead731837d142b103eab9870105f50bc40b69255Sascha Hauer free_netdev(ndev); 164828e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-Königfailed_alloc_etherdev: 164928e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König release_mem_region(r->start, resource_size(r)); 1650ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1651ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return ret; 1652ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1653ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1654ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic int __devexit 1655ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfec_drv_remove(struct platform_device *pdev) 1656ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 1657ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct net_device *ndev = platform_get_drvdata(pdev); 1658ead731837d142b103eab9870105f50bc40b69255Sascha Hauer struct fec_enet_private *fep = netdev_priv(ndev); 165928e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König struct resource *r; 1660e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann int i; 1661ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1662e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann unregister_netdev(ndev); 1663e6b043d512fa8d9a3801bf5d72bfa3b8fc3b3cc8Bryan Wu fec_enet_mii_remove(fep); 1664e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann for (i = 0; i < FEC_IRQ_NUM; i++) { 1665e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann int irq = platform_get_irq(pdev, i); 1666e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann if (irq > 0) 1667e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann free_irq(irq, ndev); 1668e163cc97f9ac169f00e86df57bee365e82e9c365Lothar Waßmann } 1669ead731837d142b103eab9870105f50bc40b69255Sascha Hauer clk_disable(fep->clk); 1670ead731837d142b103eab9870105f50bc40b69255Sascha Hauer clk_put(fep->clk); 167124e531b401752995493fa36ee8d8f10c45038e75Uwe Kleine-König iounmap(fep->hwp); 1672ead731837d142b103eab9870105f50bc40b69255Sascha Hauer free_netdev(ndev); 167328e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König 167428e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König r = platform_get_resource(pdev, IORESOURCE_MEM, 0); 167528e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König BUG_ON(!r); 167628e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König release_mem_region(r->start, resource_size(r)); 167728e2188efc614c714c69dd5c3f063e066e80d3baUwe Kleine-König 1678b3cde36cf1e19f696cb302ea426b5cf6ab4afb8aUwe Kleine-König platform_set_drvdata(pdev, NULL); 1679b3cde36cf1e19f696cb302ea426b5cf6ab4afb8aUwe Kleine-König 1680ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return 0; 1681ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1682ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 168359d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov#ifdef CONFIG_PM 1684ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic int 168587cad5c385877ce45244886748564672fd6db035Eric Benardfec_suspend(struct device *dev) 1686ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 168787cad5c385877ce45244886748564672fd6db035Eric Benard struct net_device *ndev = dev_get_drvdata(dev); 168804e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1689ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 169004e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König if (netif_running(ndev)) { 169104e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König fec_stop(ndev); 169204e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König netif_device_detach(ndev); 1693ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 169404e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König clk_disable(fep->clk); 169504e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König 1696ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return 0; 1697ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1698ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1699ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic int 170087cad5c385877ce45244886748564672fd6db035Eric Benardfec_resume(struct device *dev) 1701ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 170287cad5c385877ce45244886748564672fd6db035Eric Benard struct net_device *ndev = dev_get_drvdata(dev); 170304e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König struct fec_enet_private *fep = netdev_priv(ndev); 1704ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 170504e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König clk_enable(fep->clk); 170604e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König if (netif_running(ndev)) { 170704e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König fec_restart(ndev, fep->full_duplex); 170804e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König netif_device_attach(ndev); 1709ead731837d142b103eab9870105f50bc40b69255Sascha Hauer } 171004e5216d44e173fab619d03e2f746f444ea21ebdUwe Kleine-König 1711ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return 0; 1712ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1713ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 171459d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanovstatic const struct dev_pm_ops fec_pm_ops = { 171559d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .suspend = fec_suspend, 171659d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .resume = fec_resume, 171759d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .freeze = fec_suspend, 171859d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .thaw = fec_resume, 171959d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .poweroff = fec_suspend, 172059d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov .restore = fec_resume, 172159d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov}; 172287cad5c385877ce45244886748564672fd6db035Eric Benard#endif 172359d4289b83b11379d867e2f7146904b19cc96404Denis Kirjanov 1724ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic struct platform_driver fec_driver = { 1725ead731837d142b103eab9870105f50bc40b69255Sascha Hauer .driver = { 1726b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo .name = DRIVER_NAME, 172787cad5c385877ce45244886748564672fd6db035Eric Benard .owner = THIS_MODULE, 172887cad5c385877ce45244886748564672fd6db035Eric Benard#ifdef CONFIG_PM 172987cad5c385877ce45244886748564672fd6db035Eric Benard .pm = &fec_pm_ops, 173087cad5c385877ce45244886748564672fd6db035Eric Benard#endif 1731ca2cc333920690db87a03c2ee3bd6f43adb3e7fbShawn Guo .of_match_table = fec_dt_ids, 1732ead731837d142b103eab9870105f50bc40b69255Sascha Hauer }, 1733b5680e0b591f2701c5ba7d5fc8f96b55414073c8Shawn Guo .id_table = fec_devtype, 173487cad5c385877ce45244886748564672fd6db035Eric Benard .probe = fec_probe, 173587cad5c385877ce45244886748564672fd6db035Eric Benard .remove = __devexit_p(fec_drv_remove), 1736ead731837d142b103eab9870105f50bc40b69255Sascha Hauer}; 1737ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1738ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic int __init 1739ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfec_enet_module_init(void) 1740ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 1741ead731837d142b103eab9870105f50bc40b69255Sascha Hauer printk(KERN_INFO "FEC Ethernet Driver\n"); 1742ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1743ead731837d142b103eab9870105f50bc40b69255Sascha Hauer return platform_driver_register(&fec_driver); 1744ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1745ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1746ead731837d142b103eab9870105f50bc40b69255Sascha Hauerstatic void __exit 1747ead731837d142b103eab9870105f50bc40b69255Sascha Hauerfec_enet_cleanup(void) 1748ead731837d142b103eab9870105f50bc40b69255Sascha Hauer{ 1749ead731837d142b103eab9870105f50bc40b69255Sascha Hauer platform_driver_unregister(&fec_driver); 1750ead731837d142b103eab9870105f50bc40b69255Sascha Hauer} 1751ead731837d142b103eab9870105f50bc40b69255Sascha Hauer 1752ead731837d142b103eab9870105f50bc40b69255Sascha Hauermodule_exit(fec_enet_cleanup); 17531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(fec_enet_module_init); 17541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 17551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 1756