230-xway_etop.patch 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. --- a/drivers/net/Kconfig
  2. +++ b/drivers/net/Kconfig
  3. @@ -358,6 +358,12 @@
  4. source "drivers/net/arm/Kconfig"
  5. +config LANTIQ_ETOP
  6. + tristate "Lantiq SoC ETOP driver"
  7. + depends on SOC_LANTIQ_XWAY
  8. + help
  9. + Support for the MII0 inside the Lantiq SoC
  10. +
  11. config AX88796
  12. tristate "ASIX AX88796 NE2000 clone support"
  13. depends on ARM || MIPS || SUPERH
  14. --- a/drivers/net/Makefile
  15. +++ b/drivers/net/Makefile
  16. @@ -213,6 +213,7 @@
  17. obj-$(CONFIG_MVME16x_NET) += 82596.o
  18. obj-$(CONFIG_BVME6000_NET) += 82596.o
  19. obj-$(CONFIG_SC92031) += sc92031.o
  20. +obj-$(CONFIG_LANTIQ_ETOP) += lantiq_etop.o
  21. # This is also a 82596 and should probably be merged
  22. obj-$(CONFIG_LP486E) += lp486e.o
  23. --- /dev/null
  24. +++ b/drivers/net/lantiq_etop.c
  25. @@ -0,0 +1,552 @@
  26. +/*
  27. + * This program is free software; you can redistribute it and/or modify it
  28. + * under the terms of the GNU General Public License version 2 as published
  29. + * by the Free Software Foundation.
  30. + *
  31. + * This program is distributed in the hope that it will be useful,
  32. + * but WITHOUT ANY WARRANTY; without even the implied warranty of
  33. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  34. + * GNU General Public License for more details.
  35. + *
  36. + * You should have received a copy of the GNU General Public License
  37. + * along with this program; if not, write to the Free Software
  38. + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
  39. + *
  40. + * Copyright (C) 2005 Wu Qi Ming <[email protected]>
  41. + * Copyright (C) 2008 John Crispin <[email protected]>
  42. + */
  43. +
  44. +#include <linux/kernel.h>
  45. +#include <linux/slab.h>
  46. +#include <linux/errno.h>
  47. +#include <linux/types.h>
  48. +#include <linux/interrupt.h>
  49. +#include <linux/uaccess.h>
  50. +#include <linux/in.h>
  51. +#include <linux/netdevice.h>
  52. +#include <linux/etherdevice.h>
  53. +#include <linux/phy.h>
  54. +#include <linux/ip.h>
  55. +#include <linux/tcp.h>
  56. +#include <linux/skbuff.h>
  57. +#include <linux/mm.h>
  58. +#include <linux/platform_device.h>
  59. +#include <linux/ethtool.h>
  60. +#include <linux/init.h>
  61. +#include <linux/delay.h>
  62. +
  63. +#include <asm/checksum.h>
  64. +
  65. +#include <xway.h>
  66. +#include <xway_dma.h>
  67. +#include <lantiq_platform.h>
  68. +
  69. +#define ETHERNET_PACKET_DMA_BUFFER_SIZE 0x600
  70. +#define LQ_PPE32_MEM_MAP ((u32 *)(LQ_PPE32_BASE_ADDR + 0x10000))
  71. +#define LQ_PPE32_SRST ((u32 *)(LQ_PPE32_BASE_ADDR + 0x10080))
  72. +
  73. +/* mdio access */
  74. +#define LQ_PPE32_MDIO_CFG ((u32 *)(LQ_PPE32_BASE_ADDR + 0x11800))
  75. +#define LQ_PPE32_MDIO_ACC ((u32 *)(LQ_PPE32_BASE_ADDR + 0x11804))
  76. +
  77. +#define MDIO_ACC_REQUEST 0x80000000
  78. +#define MDIO_ACC_READ 0x40000000
  79. +#define MDIO_ACC_ADDR_MASK 0x1f
  80. +#define MDIO_ACC_ADDR_OFFSET 0x15
  81. +#define MDIO_ACC_REG_MASK 0x1f
  82. +#define MDIO_ACC_REG_OFFSET 0x10
  83. +#define MDIO_ACC_VAL_MASK 0xffff
  84. +
  85. +/* configuration */
  86. +#define LQ_PPE32_CFG ((u32 *)(LQ_PPE32_MEM_MAP + 0x1808))
  87. +
  88. +#define PPE32_MII_MASK 0xfffffffc
  89. +#define PPE32_MII_NORMAL 0x8
  90. +#define PPE32_MII_REVERSE 0xe
  91. +
  92. +/* packet length */
  93. +#define LQ_PPE32_IG_PLEN_CTRL ((u32 *)(LQ_PPE32_MEM_MAP + 0x1820))
  94. +
  95. +#define PPE32_PLEN_OVER 0x5ee
  96. +#define PPE32_PLEN_UNDER 0x400000
  97. +
  98. +/* enet */
  99. +#define LQ_PPE32_ENET_MAC_CFG ((u32 *)(LQ_PPE32_MEM_MAP + 0x1840))
  100. +
  101. +#define PPE32_CGEN 0x800
  102. +
  103. +struct lq_mii_priv {
  104. + struct net_device_stats stats;
  105. + struct dma_device_info *dma_device;
  106. + struct sk_buff *skb;
  107. +
  108. + struct mii_bus *mii_bus;
  109. + struct phy_device *phydev;
  110. + int oldlink, oldspeed, oldduplex;
  111. +};
  112. +
  113. +static struct net_device *lq_etop_dev;
  114. +static unsigned char mac_addr[MAX_ADDR_LEN];
  115. +
  116. +static int lq_mdiobus_write(struct mii_bus *bus, int phy_addr,
  117. + int phy_reg, u16 phy_data)
  118. +{
  119. + u32 val = MDIO_ACC_REQUEST |
  120. + ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
  121. + ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET) |
  122. + phy_data;
  123. +
  124. + while (lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
  125. + ;
  126. + lq_w32(val, LQ_PPE32_MDIO_ACC);
  127. +
  128. + return 0;
  129. +}
  130. +
  131. +static int lq_mdiobus_read(struct mii_bus *bus, int phy_addr, int phy_reg)
  132. +{
  133. + u32 val = MDIO_ACC_REQUEST | MDIO_ACC_READ |
  134. + ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) |
  135. + ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET);
  136. +
  137. + while (lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
  138. + ;
  139. + lq_w32(val, LQ_PPE32_MDIO_ACC);
  140. + while (lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST)
  141. + ;
  142. + val = lq_r32(LQ_PPE32_MDIO_ACC) & MDIO_ACC_VAL_MASK;
  143. + return val;
  144. +}
  145. +
  146. +int lq_mii_open(struct net_device *dev)
  147. +{
  148. + struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
  149. + struct dma_device_info *dma_dev = priv->dma_device;
  150. + int i;
  151. +
  152. + for (i = 0; i < dma_dev->max_rx_chan_num; i++) {
  153. + if ((dma_dev->rx_chan[i])->control == LQ_DMA_CH_ON)
  154. + (dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]);
  155. + }
  156. + netif_start_queue(dev);
  157. + return 0;
  158. +}
  159. +
  160. +int lq_mii_release(struct net_device *dev)
  161. +{
  162. + struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
  163. + struct dma_device_info *dma_dev = priv->dma_device;
  164. + int i;
  165. +
  166. + for (i = 0; i < dma_dev->max_rx_chan_num; i++)
  167. + dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]);
  168. + netif_stop_queue(dev);
  169. + return 0;
  170. +}
  171. +
  172. +int lq_mii_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev)
  173. +{
  174. + struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
  175. + unsigned char *buf = NULL;
  176. + struct sk_buff *skb = NULL;
  177. + int len = 0;
  178. +
  179. + len = dma_device_read(dma_dev, &buf, (void **)&skb);
  180. +
  181. + if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) {
  182. + printk(KERN_INFO "lq_etop: packet too large %d\n", len);
  183. + goto lq_mii_hw_receive_err_exit;
  184. + }
  185. +
  186. + /* remove CRC */
  187. + len -= 4;
  188. + if (skb == NULL) {
  189. + printk(KERN_INFO "lq_etop: cannot restore pointer\n");
  190. + goto lq_mii_hw_receive_err_exit;
  191. + }
  192. +
  193. + if (len > (skb->end - skb->tail)) {
  194. + printk(KERN_INFO "lq_etop: BUG, len:%d end:%p tail:%p\n",
  195. + (len+4), skb->end, skb->tail);
  196. + goto lq_mii_hw_receive_err_exit;
  197. + }
  198. +
  199. + skb_put(skb, len);
  200. + skb->dev = dev;
  201. + skb->protocol = eth_type_trans(skb, dev);
  202. + netif_rx(skb);
  203. +
  204. + priv->stats.rx_packets++;
  205. + priv->stats.rx_bytes += len;
  206. + return 0;
  207. +
  208. +lq_mii_hw_receive_err_exit:
  209. + if (len == 0) {
  210. + if (skb)
  211. + dev_kfree_skb_any(skb);
  212. + priv->stats.rx_errors++;
  213. + priv->stats.rx_dropped++;
  214. + return -EIO;
  215. + } else {
  216. + return len;
  217. + }
  218. +}
  219. +
  220. +int lq_mii_hw_tx(char *buf, int len, struct net_device *dev)
  221. +{
  222. + int ret = 0;
  223. + struct lq_mii_priv *priv = netdev_priv(dev);
  224. + struct dma_device_info *dma_dev = priv->dma_device;
  225. + ret = dma_device_write(dma_dev, buf, len, priv->skb);
  226. + return ret;
  227. +}
  228. +
  229. +int lq_mii_tx(struct sk_buff *skb, struct net_device *dev)
  230. +{
  231. + int len;
  232. + char *data;
  233. + struct lq_mii_priv *priv = netdev_priv(dev);
  234. + struct dma_device_info *dma_dev = priv->dma_device;
  235. +
  236. + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
  237. + data = skb->data;
  238. + priv->skb = skb;
  239. + dev->trans_start = jiffies;
  240. + /* TODO: we got more than 1 dma channel,
  241. + so we should do something intelligent here to select one */
  242. + dma_dev->current_tx_chan = 0;
  243. +
  244. + wmb();
  245. +
  246. + if (lq_mii_hw_tx(data, len, dev) != len) {
  247. + dev_kfree_skb_any(skb);
  248. + priv->stats.tx_errors++;
  249. + priv->stats.tx_dropped++;
  250. + } else {
  251. + priv->stats.tx_packets++;
  252. + priv->stats.tx_bytes += len;
  253. + }
  254. +
  255. + return 0;
  256. +}
  257. +
  258. +void lq_mii_tx_timeout(struct net_device *dev)
  259. +{
  260. + int i;
  261. + struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
  262. +
  263. + priv->stats.tx_errors++;
  264. + for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
  265. + priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]);
  266. + netif_wake_queue(dev);
  267. + return;
  268. +}
  269. +
  270. +int dma_intr_handler(struct dma_device_info *dma_dev, int status)
  271. +{
  272. + int i;
  273. +
  274. + switch (status) {
  275. + case RCV_INT:
  276. + lq_mii_hw_receive(lq_etop_dev, dma_dev);
  277. + break;
  278. +
  279. + case TX_BUF_FULL_INT:
  280. + printk(KERN_INFO "lq_etop: tx buffer full\n");
  281. + netif_stop_queue(lq_etop_dev);
  282. + for (i = 0; i < dma_dev->max_tx_chan_num; i++) {
  283. + if ((dma_dev->tx_chan[i])->control == LQ_DMA_CH_ON)
  284. + dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]);
  285. + }
  286. + break;
  287. +
  288. + case TRANSMIT_CPT_INT:
  289. + for (i = 0; i < dma_dev->max_tx_chan_num; i++)
  290. + dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]);
  291. +
  292. + netif_wake_queue(lq_etop_dev);
  293. + break;
  294. + }
  295. +
  296. + return 0;
  297. +}
  298. +
  299. +unsigned char *lq_etop_dma_buffer_alloc(int len, int *byte_offset, void **opt)
  300. +{
  301. + unsigned char *buffer = NULL;
  302. + struct sk_buff *skb = NULL;
  303. +
  304. + skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE);
  305. + if (skb == NULL)
  306. + return NULL;
  307. +
  308. + buffer = (unsigned char *)(skb->data);
  309. + skb_reserve(skb, 2);
  310. + *(int *)opt = (int)skb;
  311. + *byte_offset = 2;
  312. +
  313. + return buffer;
  314. +}
  315. +
  316. +void lq_etop_dma_buffer_free(unsigned char *dataptr, void *opt)
  317. +{
  318. + struct sk_buff *skb = NULL;
  319. +
  320. + if (opt == NULL) {
  321. + kfree(dataptr);
  322. + } else {
  323. + skb = (struct sk_buff *)opt;
  324. + dev_kfree_skb_any(skb);
  325. + }
  326. +}
  327. +
  328. +static void
  329. +lq_adjust_link(struct net_device *dev)
  330. +{
  331. + struct lq_mii_priv *priv = netdev_priv(dev);
  332. + struct phy_device *phydev = priv->phydev;
  333. + int new_state = 0;
  334. +
  335. + /* Did anything change? */
  336. + if (priv->oldlink != phydev->link ||
  337. + priv->oldduplex != phydev->duplex ||
  338. + priv->oldspeed != phydev->speed) {
  339. + /* Yes, so update status and mark as changed */
  340. + new_state = 1;
  341. + priv->oldduplex = phydev->duplex;
  342. + priv->oldspeed = phydev->speed;
  343. + priv->oldlink = phydev->link;
  344. + }
  345. +
  346. + /* If link status changed, show new status */
  347. + if (new_state)
  348. + phy_print_status(phydev);
  349. +}
  350. +
  351. +static int mii_probe(struct net_device *dev)
  352. +{
  353. + struct lq_mii_priv *priv = netdev_priv(dev);
  354. + struct phy_device *phydev = NULL;
  355. + int phy_addr;
  356. +
  357. + priv->oldlink = 0;
  358. + priv->oldspeed = 0;
  359. + priv->oldduplex = -1;
  360. +
  361. + /* find the first (lowest address) PHY on the current MAC's MII bus */
  362. + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
  363. + if (priv->mii_bus->phy_map[phy_addr]) {
  364. + phydev = priv->mii_bus->phy_map[phy_addr];
  365. + break; /* break out with first one found */
  366. + }
  367. + }
  368. +
  369. + if (!phydev) {
  370. + printk (KERN_ERR "%s: no PHY found\n", dev->name);
  371. + return -ENODEV;
  372. + }
  373. +
  374. + /* now we are supposed to have a proper phydev, to attach to... */
  375. + BUG_ON(!phydev);
  376. + BUG_ON(phydev->attached_dev);
  377. +
  378. + phydev = phy_connect(dev, dev_name(&phydev->dev), &lq_adjust_link,
  379. + 0, PHY_INTERFACE_MODE_MII);
  380. +
  381. + if (IS_ERR(phydev)) {
  382. + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
  383. + return PTR_ERR(phydev);
  384. + }
  385. +
  386. + /* mask with MAC supported features */
  387. + phydev->supported &= (SUPPORTED_10baseT_Half
  388. + | SUPPORTED_10baseT_Full
  389. + | SUPPORTED_100baseT_Half
  390. + | SUPPORTED_100baseT_Full
  391. + | SUPPORTED_Autoneg
  392. + /* | SUPPORTED_Pause | SUPPORTED_Asym_Pause */
  393. + | SUPPORTED_MII
  394. + | SUPPORTED_TP);
  395. +
  396. + phydev->advertising = phydev->supported;
  397. +
  398. + priv->phydev = phydev;
  399. +
  400. + printk(KERN_INFO "%s: attached PHY driver [%s] "
  401. + "(mii_bus:phy_addr=%s, irq=%d)\n",
  402. + dev->name, phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
  403. +
  404. + return 0;
  405. +}
  406. +
  407. +
  408. +static int lq_mii_dev_init(struct net_device *dev)
  409. +{
  410. + int i;
  411. + struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(dev);
  412. + ether_setup(dev);
  413. + dev->watchdog_timeo = 10 * HZ;
  414. + dev->mtu = 1500;
  415. + memset(priv, 0, sizeof(struct lq_mii_priv));
  416. + priv->dma_device = dma_device_reserve("PPE");
  417. + if (!priv->dma_device) {
  418. + BUG();
  419. + return -ENODEV;
  420. + }
  421. + priv->dma_device->buffer_alloc = &lq_etop_dma_buffer_alloc;
  422. + priv->dma_device->buffer_free = &lq_etop_dma_buffer_free;
  423. + priv->dma_device->intr_handler = &dma_intr_handler;
  424. + priv->dma_device->max_rx_chan_num = 4;
  425. +
  426. + for (i = 0; i < priv->dma_device->max_rx_chan_num; i++) {
  427. + priv->dma_device->rx_chan[i]->packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE;
  428. + priv->dma_device->rx_chan[i]->control = LQ_DMA_CH_ON;
  429. + }
  430. +
  431. + for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
  432. + if (i == 0)
  433. + priv->dma_device->tx_chan[i]->control = LQ_DMA_CH_ON;
  434. + else
  435. + priv->dma_device->tx_chan[i]->control = LQ_DMA_CH_OFF;
  436. +
  437. + dma_device_register(priv->dma_device);
  438. +
  439. + printk(KERN_INFO "%s: using mac=", dev->name);
  440. + for (i = 0; i < 6; i++) {
  441. + dev->dev_addr[i] = mac_addr[i];
  442. + printk("%02X%c", dev->dev_addr[i], (i == 5) ? ('\n') : (':'));
  443. + }
  444. +
  445. + priv->mii_bus = mdiobus_alloc();
  446. + if (priv->mii_bus == NULL)
  447. + return -ENOMEM;
  448. +
  449. + priv->mii_bus->priv = dev;
  450. + priv->mii_bus->read = lq_mdiobus_read;
  451. + priv->mii_bus->write = lq_mdiobus_write;
  452. + priv->mii_bus->name = "lq_mii";
  453. + snprintf(priv->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
  454. + priv->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
  455. + for(i = 0; i < PHY_MAX_ADDR; ++i)
  456. + priv->mii_bus->irq[i] = PHY_POLL;
  457. +
  458. + mdiobus_register(priv->mii_bus);
  459. +
  460. + return mii_probe(dev);
  461. +}
  462. +
  463. +static void lq_mii_chip_init(int mode)
  464. +{
  465. + lq_pmu_enable(PMU_DMA);
  466. + lq_pmu_enable(PMU_PPE);
  467. +
  468. + if (mode == REV_MII_MODE)
  469. + lq_w32_mask(PPE32_MII_MASK, PPE32_MII_REVERSE, LQ_PPE32_CFG);
  470. + else if (mode == MII_MODE)
  471. + lq_w32_mask(PPE32_MII_MASK, PPE32_MII_NORMAL, LQ_PPE32_CFG);
  472. + lq_w32(PPE32_PLEN_UNDER | PPE32_PLEN_OVER, LQ_PPE32_IG_PLEN_CTRL);
  473. + lq_w32(PPE32_CGEN, LQ_PPE32_ENET_MAC_CFG);
  474. + wmb();
  475. +}
  476. +
  477. +static int lq_mii_eth_mac_addr(struct net_device *dev, void *p)
  478. +{
  479. + int retcode;
  480. +
  481. + retcode = eth_mac_addr(dev, p);
  482. +
  483. + if (retcode)
  484. + return retcode;
  485. +
  486. + // set rx_addr for unicast filter
  487. + lq_w32(((dev->dev_addr[0]<<24)|(dev->dev_addr[1]<<16)|(dev->dev_addr[2]<< 8)|dev->dev_addr[3]), (u32*)(LQ_PPE32_BASE_ADDR|(0x461b<<2)));
  488. + lq_w32(((dev->dev_addr[4]<<24)|(dev->dev_addr[5]<<16)), (u32*)(LQ_PPE32_BASE_ADDR|(0x461c<<2)));
  489. +
  490. + return 0;
  491. +}
  492. +
  493. +static void lq_mii_set_rx_mode (struct net_device *dev)
  494. +{
  495. + // rx_mode promisc: unset unicast filter
  496. + if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI))
  497. + lq_w32(lq_r32((u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2))) & ~(1<<28), (u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2)));
  498. + // enable unicast filter
  499. + else
  500. + lq_w32(lq_r32((u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2))) | (1<<28), (u32*)(LQ_PPE32_BASE_ADDR|(0x4614<<2)));
  501. +}
  502. +
  503. +static const struct net_device_ops lq_eth_netdev_ops = {
  504. + .ndo_init = lq_mii_dev_init,
  505. + .ndo_open = lq_mii_open,
  506. + .ndo_stop = lq_mii_release,
  507. + .ndo_start_xmit = lq_mii_tx,
  508. + .ndo_tx_timeout = lq_mii_tx_timeout,
  509. + .ndo_change_mtu = eth_change_mtu,
  510. + .ndo_set_mac_address = lq_mii_eth_mac_addr,
  511. + .ndo_validate_addr = eth_validate_addr,
  512. + .ndo_set_multicast_list = lq_mii_set_rx_mode,
  513. +};
  514. +
  515. +static int
  516. +lq_mii_probe(struct platform_device *dev)
  517. +{
  518. + int result = 0;
  519. + struct lq_eth_data *eth = (struct lq_eth_data*)dev->dev.platform_data;
  520. + lq_etop_dev = alloc_etherdev(sizeof(struct lq_mii_priv));
  521. + lq_etop_dev->netdev_ops = &lq_eth_netdev_ops;
  522. + memcpy(mac_addr, eth->mac, 6);
  523. + strcpy(lq_etop_dev->name, "eth%d");
  524. + lq_mii_chip_init(eth->mii_mode);
  525. + result = register_netdev(lq_etop_dev);
  526. + if (result) {
  527. + printk(KERN_INFO "lq_etop: error %i registering device \"%s\"\n", result, lq_etop_dev->name);
  528. + goto out;
  529. + }
  530. +
  531. + printk(KERN_INFO "lq_etop: driver loaded!\n");
  532. +
  533. +out:
  534. + return result;
  535. +}
  536. +
  537. +static int lq_mii_remove(struct platform_device *dev)
  538. +{
  539. + struct lq_mii_priv *priv = (struct lq_mii_priv *)netdev_priv(lq_etop_dev);
  540. +
  541. + printk(KERN_INFO "lq_etop: lq_etop cleanup\n");
  542. +
  543. + dma_device_unregister(priv->dma_device);
  544. + dma_device_release(priv->dma_device);
  545. + kfree(priv->dma_device);
  546. + unregister_netdev(lq_etop_dev);
  547. + return 0;
  548. +}
  549. +
  550. +static struct platform_driver lq_mii_driver = {
  551. + .probe = lq_mii_probe,
  552. + .remove = lq_mii_remove,
  553. + .driver = {
  554. + .name = "lq_etop",
  555. + .owner = THIS_MODULE,
  556. + },
  557. +};
  558. +
  559. +int __init lq_mii_init(void)
  560. +{
  561. + int ret = platform_driver_register(&lq_mii_driver);
  562. + if (ret)
  563. + printk(KERN_INFO "lq_etop: Error registering platfom driver!");
  564. + return ret;
  565. +}
  566. +
  567. +static void __exit lq_mii_cleanup(void)
  568. +{
  569. + platform_driver_unregister(&lq_mii_driver);
  570. +}
  571. +
  572. +module_init(lq_mii_init);
  573. +module_exit(lq_mii_cleanup);
  574. +
  575. +MODULE_LICENSE("GPL");
  576. +MODULE_AUTHOR("John Crispin <[email protected]>");
  577. +MODULE_DESCRIPTION("ethernet driver for IFXMIPS boards");