1a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/*
23396c7823efb3a5b8630388c464e1034ea031cedPaul Gortmaker * linux/drivers/net/ethernet/ethoc.c
3a1702857724fb39cb68ce581490010df99168fd0Thierry Reding *
4a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * Copyright (C) 2007-2008 Avionic Design Development GmbH
5a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * Copyright (C) 2008-2009 Avionic Design GmbH
6a1702857724fb39cb68ce581490010df99168fd0Thierry Reding *
7a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * This program is free software; you can redistribute it and/or modify
8a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * it under the terms of the GNU General Public License version 2 as
9a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * published by the Free Software Foundation.
10a1702857724fb39cb68ce581490010df99168fd0Thierry Reding *
11a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * Written by Thierry Reding <thierry.reding@avionic-design.de>
12a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */
13a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
14b7f080cfe223b3b7424872639d153695615a9255Alexey Dobriyan#include <linux/dma-mapping.h>
15a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/etherdevice.h>
16a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/crc32.h>
17a6b7a407865aab9f849dd99a71072b7cd1175116Alexey Dobriyan#include <linux/interrupt.h>
18a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/io.h>
19a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/mii.h>
20a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/phy.h>
21a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <linux/platform_device.h>
22d43c36dc6b357fa1806800f18aa30123c747a6d1Alexey Dobriyan#include <linux/sched.h>
235a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/slab.h>
24e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn#include <linux/of.h>
259d9779e723a5d23b94abbe5bb7d1197921f6f3ddPaul Gortmaker#include <linux/module.h>
26a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#include <net/ethoc.h>
27a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
280baa080c75cea6357bfba9b93ba598d747457cbdThomas Choustatic int buffer_size = 0x8000; /* 32 KBytes */
290baa080c75cea6357bfba9b93ba598d747457cbdThomas Choumodule_param(buffer_size, int, 0);
300baa080c75cea6357bfba9b93ba598d747457cbdThomas ChouMODULE_PARM_DESC(buffer_size, "DMA buffer allocation size");
310baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou
32a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* register offsets */
33a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER		0x00
34a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_SOURCE	0x04
35a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK	0x08
36a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	IPGT		0x0c
37a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	IPGR1		0x10
38a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	IPGR2		0x14
39a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	PACKETLEN	0x18
40a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	COLLCONF	0x1c
41a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_NUM	0x20
42a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	CTRLMODER	0x24
43a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIIMODER	0x28
44a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIICOMMAND	0x2c
45a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIIADDRESS	0x30
46a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIITX_DATA	0x34
47a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIIRX_DATA	0x38
48a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIISTATUS	0x3c
49a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MAC_ADDR0	0x40
50a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MAC_ADDR1	0x44
51a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	ETH_HASH0	0x48
52a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	ETH_HASH1	0x4c
53a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	ETH_TXCTRL	0x50
54a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
55a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* mode register */
56a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_RXEN	(1 <<  0) /* receive enable */
57a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_TXEN	(1 <<  1) /* transmit enable */
58a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_NOPRE	(1 <<  2) /* no preamble */
59a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_BRO	(1 <<  3) /* broadcast address */
60a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_IAM	(1 <<  4) /* individual address mode */
61a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_PRO	(1 <<  5) /* promiscuous mode */
62a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_IFG	(1 <<  6) /* interframe gap for incoming frames */
63a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_LOOP	(1 <<  7) /* loopback */
64a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_NBO	(1 <<  8) /* no back-off */
65a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_EDE	(1 <<  9) /* excess defer enable */
66a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_FULLD	(1 << 10) /* full duplex */
67a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_RESET	(1 << 11) /* FIXME: reset (undocumented) */
68a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_DCRC	(1 << 12) /* delayed CRC enable */
69a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_CRC	(1 << 13) /* CRC enable */
70a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_HUGE	(1 << 14) /* huge packets enable */
71a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_PAD	(1 << 15) /* padding enabled */
72a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MODER_RSM	(1 << 16) /* receive small packets */
73a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
74a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* interrupt source and mask registers */
75a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_TXF	(1 << 0) /* transmit frame */
76a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_TXE	(1 << 1) /* transmit error */
77a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_RXF	(1 << 2) /* receive frame */
78a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_RXE	(1 << 3) /* receive error */
79a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_BUSY	(1 << 4)
80a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_TXC	(1 << 5) /* transmit control frame */
81a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_RXC	(1 << 6) /* receive control frame */
82a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
83a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_TX	(INT_MASK_TXF | INT_MASK_TXE)
84a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_RX	(INT_MASK_RXF | INT_MASK_RXE)
85a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
86a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	INT_MASK_ALL ( \
87a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		INT_MASK_TXF | INT_MASK_TXE | \
88a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		INT_MASK_RXF | INT_MASK_RXE | \
89a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		INT_MASK_TXC | INT_MASK_RXC | \
90a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		INT_MASK_BUSY \
91a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	)
92a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
93a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* packet length register */
94a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	PACKETLEN_MIN(min)		(((min) & 0xffff) << 16)
95a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	PACKETLEN_MAX(max)		(((max) & 0xffff) <<  0)
96a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	PACKETLEN_MIN_MAX(min, max)	(PACKETLEN_MIN(min) | \
97a1702857724fb39cb68ce581490010df99168fd0Thierry Reding					PACKETLEN_MAX(max))
98a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
99a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* transmit buffer number register */
100a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_NUM_VAL(x)	(((x) <= 0x80) ? (x) : 0x80)
101a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
102a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* control module mode register */
103a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	CTRLMODER_PASSALL	(1 << 0) /* pass all receive frames */
104a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	CTRLMODER_RXFLOW	(1 << 1) /* receive control flow */
105a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	CTRLMODER_TXFLOW	(1 << 2) /* transmit control flow */
106a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
107a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII mode register */
108a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIIMODER_CLKDIV(x)	((x) & 0xfe) /* needs to be an even number */
109a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIIMODER_NOPRE		(1 << 8) /* no preamble */
110a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
111a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII command register */
112a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIICOMMAND_SCAN		(1 << 0) /* scan status */
113a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIICOMMAND_READ		(1 << 1) /* read status */
114a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIICOMMAND_WRITE	(1 << 2) /* write control data */
115a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
116a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII address register */
117a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIIADDRESS_FIAD(x)		(((x) & 0x1f) << 0)
118a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIIADDRESS_RGAD(x)		(((x) & 0x1f) << 8)
119a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIIADDRESS_ADDR(phy, reg)	(MIIADDRESS_FIAD(phy) | \
120a1702857724fb39cb68ce581490010df99168fd0Thierry Reding					MIIADDRESS_RGAD(reg))
121a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
122a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII transmit data register */
123a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIITX_DATA_VAL(x)	((x) & 0xffff)
124a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
125a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII receive data register */
126a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIIRX_DATA_VAL(x)	((x) & 0xffff)
127a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
128a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* MII status register */
129a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIISTATUS_LINKFAIL	(1 << 0)
130a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIISTATUS_BUSY		(1 << 1)
131a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	MIISTATUS_INVALID	(1 << 2)
132a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
133a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* TX buffer descriptor */
134a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_CS		(1 <<  0) /* carrier sense lost */
135a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_DF		(1 <<  1) /* defer indication */
136a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_LC		(1 <<  2) /* late collision */
137a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_RL		(1 <<  3) /* retransmission limit */
138a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_RETRY_MASK	(0x00f0)
139a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_RETRY(x)		(((x) & 0x00f0) >>  4)
140a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_UR		(1 <<  8) /* transmitter underrun */
141a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_CRC		(1 << 11) /* TX CRC enable */
142a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_PAD		(1 << 12) /* pad enable for short packets */
143a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_WRAP		(1 << 13)
144a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_IRQ		(1 << 14) /* interrupt request enable */
145a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_READY		(1 << 15) /* TX buffer ready */
146a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_LEN(x)		(((x) & 0xffff) << 16)
147a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_LEN_MASK		(0xffff << 16)
148a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
149a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	TX_BD_STATS		(TX_BD_CS | TX_BD_DF | TX_BD_LC | \
150a1702857724fb39cb68ce581490010df99168fd0Thierry Reding				TX_BD_RL | TX_BD_RETRY_MASK | TX_BD_UR)
151a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
152a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/* RX buffer descriptor */
153a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_LC	(1 <<  0) /* late collision */
154a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_CRC	(1 <<  1) /* RX CRC error */
155a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_SF	(1 <<  2) /* short frame */
156a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_TL	(1 <<  3) /* too long */
157a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_DN	(1 <<  4) /* dribble nibble */
158a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_IS	(1 <<  5) /* invalid symbol */
159a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_OR	(1 <<  6) /* receiver overrun */
160a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_MISS	(1 <<  7)
161a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_CF	(1 <<  8) /* control frame */
162a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_WRAP	(1 << 13)
163a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_IRQ	(1 << 14) /* interrupt request enable */
164a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_EMPTY	(1 << 15)
165a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_LEN(x)	(((x) & 0xffff) << 16)
166a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
167a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	RX_BD_STATS	(RX_BD_LC | RX_BD_CRC | RX_BD_SF | RX_BD_TL | \
168a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			RX_BD_DN | RX_BD_IS | RX_BD_OR | RX_BD_MISS)
169a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
170a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	ETHOC_BUFSIZ		1536
171a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	ETHOC_ZLEN		64
172a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	ETHOC_BD_BASE		0x400
173a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	ETHOC_TIMEOUT		(HZ / 2)
174a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#define	ETHOC_MII_TIMEOUT	(1 + (HZ / 5))
175a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
176a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/**
177a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * struct ethoc - driver-private device structure
178a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @iobase:	pointer to I/O memory region
179a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @membase:	pointer to buffer memory region
1800baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou * @dma_alloc:	dma allocated buffer size
181ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou * @io_region_size:	I/O memory region size
182a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @num_tx:	number of send buffers
183a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @cur_tx:	last send buffer written
184a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @dty_tx:	last buffer actually sent
185a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @num_rx:	number of receive buffers
186a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @cur_rx:	current receive buffer
187f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn * @vma:        pointer to array of virtual memory addresses for buffers
188a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @netdev:	pointer to network device structure
189a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @napi:	NAPI structure
190a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @msg_enable:	device state flags
191a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @lock:	device lock
192a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @phy:	attached PHY
193a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @mdio:	MDIO bus for PHY access
194a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @phy_id:	address of attached PHY
195a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */
196a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstruct ethoc {
197a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	void __iomem *iobase;
198a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	void __iomem *membase;
1990baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou	int dma_alloc;
200ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou	resource_size_t io_region_size;
201a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
202a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	unsigned int num_tx;
203a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	unsigned int cur_tx;
204a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	unsigned int dty_tx;
205a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
206a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	unsigned int num_rx;
207a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	unsigned int cur_rx;
208a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
209f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn	void** vma;
210f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn
211a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct net_device *netdev;
212a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct napi_struct napi;
213a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 msg_enable;
214a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
215a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	spinlock_t lock;
216a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
217a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct phy_device *phy;
218a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct mii_bus *mdio;
219a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	s8 phy_id;
220a1702857724fb39cb68ce581490010df99168fd0Thierry Reding};
221a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
222a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/**
223a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * struct ethoc_bd - buffer descriptor
224a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @stat:	buffer statistics
225a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @addr:	physical memory address
226a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */
227a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstruct ethoc_bd {
228a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 stat;
229a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 addr;
230a1702857724fb39cb68ce581490010df99168fd0Thierry Reding};
231a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
23216dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline u32 ethoc_read(struct ethoc *dev, loff_t offset)
233a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
234a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return ioread32(dev->iobase + offset);
235a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
236a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
23716dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_write(struct ethoc *dev, loff_t offset, u32 data)
238a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
239a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	iowrite32(data, dev->iobase + offset);
240a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
241a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
24216dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_read_bd(struct ethoc *dev, int index,
24316dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Chou		struct ethoc_bd *bd)
244a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
245a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
246a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	bd->stat = ethoc_read(dev, offset + 0);
247a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	bd->addr = ethoc_read(dev, offset + 4);
248a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
249a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
25016dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_write_bd(struct ethoc *dev, int index,
251a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		const struct ethoc_bd *bd)
252a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
253a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	loff_t offset = ETHOC_BD_BASE + (index * sizeof(struct ethoc_bd));
254a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, offset + 0, bd->stat);
255a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, offset + 4, bd->addr);
256a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
257a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
25816dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_enable_irq(struct ethoc *dev, u32 mask)
259a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
260a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 imask = ethoc_read(dev, INT_MASK);
261a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	imask |= mask;
262a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, INT_MASK, imask);
263a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
264a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
26516dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_disable_irq(struct ethoc *dev, u32 mask)
266a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
267a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 imask = ethoc_read(dev, INT_MASK);
268a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	imask &= ~mask;
269a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, INT_MASK, imask);
270a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
271a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
27216dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_ack_irq(struct ethoc *dev, u32 mask)
273a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
274a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, INT_SOURCE, mask);
275a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
276a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
27716dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_enable_rx_and_tx(struct ethoc *dev)
278a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
279a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 mode = ethoc_read(dev, MODER);
280a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mode |= MODER_RXEN | MODER_TXEN;
281a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, MODER, mode);
282a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
283a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
28416dd18b0837dee46f1a6b0c01830c5f2b7187266Thomas Choustatic inline void ethoc_disable_rx_and_tx(struct ethoc *dev)
285a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
286a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 mode = ethoc_read(dev, MODER);
287a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mode &= ~(MODER_RXEN | MODER_TXEN);
288a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, MODER, mode);
289a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
290a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
2915cf3e03457aa905f17f9765702850316b69aad1eDavid S. Millerstatic int ethoc_init_ring(struct ethoc *dev, unsigned long mem_start)
292a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
293a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc_bd bd;
294a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	int i;
295f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn	void* vma;
296a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
297a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	dev->cur_tx = 0;
298a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	dev->dty_tx = 0;
299a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	dev->cur_rx = 0;
300a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
301ee4f56b990391f0ea333121ebc0e9fba28619b52Jonas Bonn	ethoc_write(dev, TX_BD_NUM, dev->num_tx);
302ee4f56b990391f0ea333121ebc0e9fba28619b52Jonas Bonn
303a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* setup transmission buffers */
304f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn	bd.addr = mem_start;
305a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	bd.stat = TX_BD_IRQ | TX_BD_CRC;
306f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn	vma = dev->membase;
307a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
308a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	for (i = 0; i < dev->num_tx; i++) {
309a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		if (i == dev->num_tx - 1)
310a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			bd.stat |= TX_BD_WRAP;
311a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
312a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ethoc_write_bd(dev, i, &bd);
313a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		bd.addr += ETHOC_BUFSIZ;
314f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn
315f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn		dev->vma[i] = vma;
316f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn		vma += ETHOC_BUFSIZ;
317a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
318a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
319a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	bd.stat = RX_BD_EMPTY | RX_BD_IRQ;
320a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
321a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	for (i = 0; i < dev->num_rx; i++) {
322a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		if (i == dev->num_rx - 1)
323a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			bd.stat |= RX_BD_WRAP;
324a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
325a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ethoc_write_bd(dev, dev->num_tx + i, &bd);
326a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		bd.addr += ETHOC_BUFSIZ;
327f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn
328f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn		dev->vma[dev->num_tx + i] = vma;
329f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn		vma += ETHOC_BUFSIZ;
330a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
331a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
332a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return 0;
333a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
334a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
335a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_reset(struct ethoc *dev)
336a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
337a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 mode;
338a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
339a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* TODO: reset controller? */
340a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
341a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_disable_rx_and_tx(dev);
342a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
343a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* TODO: setup registers */
344a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
345a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* enable FCS generation and automatic padding */
346a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mode = ethoc_read(dev, MODER);
347a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mode |= MODER_CRC | MODER_PAD;
348a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, MODER, mode);
349a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
350a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* set full-duplex mode */
351a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mode = ethoc_read(dev, MODER);
352a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mode |= MODER_FULLD;
353a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, MODER, mode);
354a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(dev, IPGT, 0x15);
355a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
356a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_ack_irq(dev, INT_MASK_ALL);
357a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_enable_irq(dev, INT_MASK_ALL);
358a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_enable_rx_and_tx(dev);
359a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return 0;
360a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
361a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
362a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic unsigned int ethoc_update_rx_stats(struct ethoc *dev,
363a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		struct ethoc_bd *bd)
364a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
365a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct net_device *netdev = dev->netdev;
366a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	unsigned int ret = 0;
367a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
368a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & RX_BD_TL) {
369a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "RX: frame too long\n");
37057616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.rx_length_errors++;
371a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret++;
372a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
373a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
374a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & RX_BD_SF) {
375a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "RX: frame too short\n");
37657616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.rx_length_errors++;
377a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret++;
378a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
379a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
380a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & RX_BD_DN) {
381a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "RX: dribble nibble\n");
38257616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.rx_frame_errors++;
383a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
384a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
385a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & RX_BD_CRC) {
386a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "RX: wrong CRC\n");
38757616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.rx_crc_errors++;
388a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret++;
389a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
390a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
391a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & RX_BD_OR) {
392a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "RX: overrun\n");
39357616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.rx_over_errors++;
394a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret++;
395a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
396a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
397a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & RX_BD_MISS)
39857616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.rx_missed_errors++;
399a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
400a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & RX_BD_LC) {
401a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "RX: late collision\n");
40257616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.collisions++;
403a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret++;
404a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
405a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
406a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return ret;
407a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
408a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
409a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_rx(struct net_device *dev, int limit)
410a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
411a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
412a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	int count;
413a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
414a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	for (count = 0; count < limit; ++count) {
415a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		unsigned int entry;
416a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		struct ethoc_bd bd;
417a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
4186a632625c7da7594d059b88dae0e9c591af147baJonas Bonn		entry = priv->num_tx + priv->cur_rx;
419a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ethoc_read_bd(priv, entry, &bd);
42020f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn		if (bd.stat & RX_BD_EMPTY) {
42120f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			ethoc_ack_irq(priv, INT_MASK_RX);
42220f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			/* If packet (interrupt) came in between checking
42320f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			 * BD_EMTPY and clearing the interrupt source, then we
42420f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			 * risk missing the packet as the RX interrupt won't
42520f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			 * trigger right away when we reenable it; hence, check
42620f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			 * BD_EMTPY here again to make sure there isn't such a
42720f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			 * packet waiting for us...
42820f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			 */
42920f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			ethoc_read_bd(priv, entry, &bd);
43020f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn			if (bd.stat & RX_BD_EMPTY)
43120f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn				break;
43220f70ddd6558a39a89dba4af675686c5a8dbd7b3Jonas Bonn		}
433a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
434a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		if (ethoc_update_rx_stats(priv, &bd) == 0) {
435a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			int size = bd.stat >> 16;
43689d71a66c40d629e3b1285def543ab1425558cd5Eric Dumazet			struct sk_buff *skb;
437050f91dcd9a45a14449dded5180f633692b588d2Thomas Chou
438050f91dcd9a45a14449dded5180f633692b588d2Thomas Chou			size -= 4; /* strip the CRC */
43989d71a66c40d629e3b1285def543ab1425558cd5Eric Dumazet			skb = netdev_alloc_skb_ip_align(dev, size);
440050f91dcd9a45a14449dded5180f633692b588d2Thomas Chou
441a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			if (likely(skb)) {
442f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn				void *src = priv->vma[entry];
443a1702857724fb39cb68ce581490010df99168fd0Thierry Reding				memcpy_fromio(skb_put(skb, size), src, size);
444a1702857724fb39cb68ce581490010df99168fd0Thierry Reding				skb->protocol = eth_type_trans(skb, dev);
44557616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy				dev->stats.rx_packets++;
44657616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy				dev->stats.rx_bytes += size;
447a1702857724fb39cb68ce581490010df99168fd0Thierry Reding				netif_receive_skb(skb);
448a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			} else {
449a1702857724fb39cb68ce581490010df99168fd0Thierry Reding				if (net_ratelimit())
450a1702857724fb39cb68ce581490010df99168fd0Thierry Reding					dev_warn(&dev->dev, "low on memory - "
451a1702857724fb39cb68ce581490010df99168fd0Thierry Reding							"packet dropped\n");
452a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
45357616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy				dev->stats.rx_dropped++;
454a1702857724fb39cb68ce581490010df99168fd0Thierry Reding				break;
455a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			}
456a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		}
457a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
458a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		/* clear the buffer descriptor so it can be reused */
459a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		bd.stat &= ~RX_BD_STATS;
460a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		bd.stat |=  RX_BD_EMPTY;
461a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ethoc_write_bd(priv, entry, &bd);
4626a632625c7da7594d059b88dae0e9c591af147baJonas Bonn		if (++priv->cur_rx == priv->num_rx)
4636a632625c7da7594d059b88dae0e9c591af147baJonas Bonn			priv->cur_rx = 0;
464a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
465a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
466a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return count;
467a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
468a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
4694f64bcb2fc093a3a9d7d41220004491ce88e4dd3Jonas Bonnstatic void ethoc_update_tx_stats(struct ethoc *dev, struct ethoc_bd *bd)
470a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
471a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct net_device *netdev = dev->netdev;
472a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
473a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & TX_BD_LC) {
474a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "TX: late collision\n");
47557616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.tx_window_errors++;
476a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
477a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
478a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & TX_BD_RL) {
479a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "TX: retransmit limit\n");
48057616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.tx_aborted_errors++;
481a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
482a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
483a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & TX_BD_UR) {
484a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "TX: underrun\n");
48557616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.tx_fifo_errors++;
486a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
487a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
488a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & TX_BD_CS) {
489a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "TX: carrier sense lost\n");
49057616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.tx_carrier_errors++;
491a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
492a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
493a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (bd->stat & TX_BD_STATS)
49457616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		netdev->stats.tx_errors++;
495a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
49657616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy	netdev->stats.collisions += (bd->stat >> 4) & 0xf;
49757616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy	netdev->stats.tx_bytes += bd->stat >> 16;
49857616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy	netdev->stats.tx_packets++;
499a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
500a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
501fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonnstatic int ethoc_tx(struct net_device *dev, int limit)
502a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
503a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
504fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	int count;
505fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	struct ethoc_bd bd;
506a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
507fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	for (count = 0; count < limit; ++count) {
508fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn		unsigned int entry;
509a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
5106a632625c7da7594d059b88dae0e9c591af147baJonas Bonn		entry = priv->dty_tx & (priv->num_tx-1);
511a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
512a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ethoc_read_bd(priv, entry, &bd);
513a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
514fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn		if (bd.stat & TX_BD_READY || (priv->dty_tx == priv->cur_tx)) {
515fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			ethoc_ack_irq(priv, INT_MASK_TX);
516fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			/* If interrupt came in between reading in the BD
517fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			 * and clearing the interrupt source, then we risk
518fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			 * missing the event as the TX interrupt won't trigger
519fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			 * right away when we reenable it; hence, check
520fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			 * BD_EMPTY here again to make sure there isn't such an
521fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			 * event pending...
522fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			 */
523fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			ethoc_read_bd(priv, entry, &bd);
524fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			if (bd.stat & TX_BD_READY ||
525fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn			    (priv->dty_tx == priv->cur_tx))
526fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn				break;
527fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn		}
528fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn
5294f64bcb2fc093a3a9d7d41220004491ce88e4dd3Jonas Bonn		ethoc_update_tx_stats(priv, &bd);
530fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn		priv->dty_tx++;
531a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
532a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
533a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if ((priv->cur_tx - priv->dty_tx) <= (priv->num_tx / 2))
534a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		netif_wake_queue(dev);
535a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
536fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	return count;
537a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
538a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
539a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic irqreturn_t ethoc_interrupt(int irq, void *dev_id)
540a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
54157616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy	struct net_device *dev = dev_id;
542a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
543a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 pending;
544fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	u32 mask;
545fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn
546fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	/* Figure out what triggered the interrupt...
547fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	 * The tricky bit here is that the interrupt source bits get
54825985edcedea6396277003854657b5f3cb31a628Lucas De Marchi	 * set in INT_SOURCE for an event regardless of whether that
549fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	 * event is masked or not.  Thus, in order to figure out what
550fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	 * triggered the interrupt, we need to remove the sources
551fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	 * for all events that are currently masked.  This behaviour
552fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	 * is not particularly well documented but reasonable...
553fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	 */
554fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	mask = ethoc_read(priv, INT_MASK);
555a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	pending = ethoc_read(priv, INT_SOURCE);
556fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	pending &= mask;
557fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn
558a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (unlikely(pending == 0)) {
559a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		return IRQ_NONE;
560a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
561a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
56250c54a57dfbd392e17f1473717b8e125afcb01a3Thomas Chou	ethoc_ack_irq(priv, pending);
563a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
564fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	/* We always handle the dropped packet interrupt */
565a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (pending & INT_MASK_BUSY) {
566a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&dev->dev, "packet dropped\n");
56757616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		dev->stats.rx_dropped++;
568a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
569a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
570fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	/* Handle receive/transmit event by switching to polling */
571fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	if (pending & (INT_MASK_TX | INT_MASK_RX)) {
572fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn		ethoc_disable_irq(priv, INT_MASK_TX | INT_MASK_RX);
573fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn		napi_schedule(&priv->napi);
574a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
575a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
576a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return IRQ_HANDLED;
577a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
578a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
579a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_get_mac_address(struct net_device *dev, void *addr)
580a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
581a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
582a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u8 *mac = (u8 *)addr;
583a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 reg;
584a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
585a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	reg = ethoc_read(priv, MAC_ADDR0);
586a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mac[2] = (reg >> 24) & 0xff;
587a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mac[3] = (reg >> 16) & 0xff;
588a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mac[4] = (reg >>  8) & 0xff;
589a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mac[5] = (reg >>  0) & 0xff;
590a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
591a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	reg = ethoc_read(priv, MAC_ADDR1);
592a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mac[0] = (reg >>  8) & 0xff;
593a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mac[1] = (reg >>  0) & 0xff;
594a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
595a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return 0;
596a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
597a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
598a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_poll(struct napi_struct *napi, int budget)
599a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
600a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = container_of(napi, struct ethoc, napi);
601fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	int rx_work_done = 0;
602fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	int tx_work_done = 0;
603fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn
604fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	rx_work_done = ethoc_rx(priv->netdev, budget);
605fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	tx_work_done = ethoc_tx(priv->netdev, budget);
606a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
607fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	if (rx_work_done < budget && tx_work_done < budget) {
608a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		napi_complete(napi);
609fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn		ethoc_enable_irq(priv, INT_MASK_TX | INT_MASK_RX);
610a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
611a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
612fa98eb0e867c6c16e239545d4deb7ad8f40631b3Jonas Bonn	return rx_work_done;
613a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
614a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
615a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_mdio_read(struct mii_bus *bus, int phy, int reg)
616a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
617a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = bus->priv;
6188dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn	int i;
619a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
620a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
621a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, MIICOMMAND, MIICOMMAND_READ);
622a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
6238dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn	for (i=0; i < 5; i++) {
624a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		u32 status = ethoc_read(priv, MIISTATUS);
625a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		if (!(status & MIISTATUS_BUSY)) {
626a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			u32 data = ethoc_read(priv, MIIRX_DATA);
627a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			/* reset MII command register */
628a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			ethoc_write(priv, MIICOMMAND, 0);
629a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			return data;
630a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		}
6318dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn		usleep_range(100,200);
632a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
633a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
634a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return -EBUSY;
635a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
636a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
637a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_mdio_write(struct mii_bus *bus, int phy, int reg, u16 val)
638a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
639a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = bus->priv;
6408dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn	int i;
641a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
642a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, MIIADDRESS, MIIADDRESS_ADDR(phy, reg));
643a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, MIITX_DATA, val);
644a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, MIICOMMAND, MIICOMMAND_WRITE);
645a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
6468dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn	for (i=0; i < 5; i++) {
647a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		u32 stat = ethoc_read(priv, MIISTATUS);
648b46773db64c264a6600f58d9da1ae43708b47fdaJonas Bonn		if (!(stat & MIISTATUS_BUSY)) {
649b46773db64c264a6600f58d9da1ae43708b47fdaJonas Bonn			/* reset MII command register */
650b46773db64c264a6600f58d9da1ae43708b47fdaJonas Bonn			ethoc_write(priv, MIICOMMAND, 0);
651a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			return 0;
652b46773db64c264a6600f58d9da1ae43708b47fdaJonas Bonn		}
6538dac428ae9ae54d8e8540ac157d92925dd7ebed8Jonas Bonn		usleep_range(100,200);
654a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
655a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
656a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return -EBUSY;
657a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
658a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
659a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_mdio_reset(struct mii_bus *bus)
660a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
661a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return 0;
662a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
663a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
664a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic void ethoc_mdio_poll(struct net_device *dev)
665a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
666a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
667a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
668f78f09f76540c9a986bc321a186a291f4bb40925Jonas Bonnstatic int __devinit ethoc_mdio_probe(struct net_device *dev)
669a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
670a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
671a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct phy_device *phy;
672637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn	int err;
673a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
674637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn	if (priv->phy_id != -1) {
675637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn		phy = priv->mdio->phy_map[priv->phy_id];
676637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn	} else {
677637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn		phy = phy_find_first(priv->mdio);
678a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
679a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
680a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!phy) {
681a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&dev->dev, "no PHY found\n");
682a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		return -ENXIO;
683a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
684a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
685637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn	err = phy_connect_direct(dev, phy, ethoc_mdio_poll, 0,
686a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			PHY_INTERFACE_MODE_GMII);
687637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn	if (err) {
688a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&dev->dev, "could not attach to PHY\n");
689637f33b80d774060646772a22fd728e198d9ebf9Jonas Bonn		return err;
690a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
691a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
692a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->phy = phy;
693a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return 0;
694a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
695a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
696a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_open(struct net_device *dev)
697a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
698a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
699a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	int ret;
700a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
701a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ret = request_irq(dev->irq, ethoc_interrupt, IRQF_SHARED,
702a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			dev->name, dev);
703a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (ret)
704a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		return ret;
705a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
7065cf3e03457aa905f17f9765702850316b69aad1eDavid S. Miller	ethoc_init_ring(priv, dev->mem_start);
707a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_reset(priv);
708a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
709a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (netif_queue_stopped(dev)) {
710a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_dbg(&dev->dev, " resuming queue\n");
711a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		netif_wake_queue(dev);
712a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	} else {
713a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_dbg(&dev->dev, " starting queue\n");
714a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		netif_start_queue(dev);
715a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
716a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
717a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	phy_start(priv->phy);
718a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	napi_enable(&priv->napi);
719a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
720a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (netif_msg_ifup(priv)) {
721a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_info(&dev->dev, "I/O: %08lx Memory: %08lx-%08lx\n",
722a1702857724fb39cb68ce581490010df99168fd0Thierry Reding				dev->base_addr, dev->mem_start, dev->mem_end);
723a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
724a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
725a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return 0;
726a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
727a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
728a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_stop(struct net_device *dev)
729a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
730a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
731a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
732a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	napi_disable(&priv->napi);
733a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
734a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (priv->phy)
735a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		phy_stop(priv->phy);
736a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
737a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_disable_rx_and_tx(priv);
738a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	free_irq(dev->irq, dev);
739a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
740a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!netif_queue_stopped(dev))
741a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		netif_stop_queue(dev);
742a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
743a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return 0;
744a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
745a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
746a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
747a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
748a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
749a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct mii_ioctl_data *mdio = if_mii(ifr);
750a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct phy_device *phy = NULL;
751a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
752a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!netif_running(dev))
753a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		return -EINVAL;
754a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
755a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (cmd != SIOCGMIIPHY) {
756a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		if (mdio->phy_id >= PHY_MAX_ADDR)
757a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			return -ERANGE;
758a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
759a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		phy = priv->mdio->phy_map[mdio->phy_id];
760a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		if (!phy)
761a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			return -ENODEV;
762a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	} else {
763a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		phy = priv->phy;
764a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
765a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
76628b041139e344ecd0f144d6205b004ae354cfa1eRichard Cochran	return phy_mii_ioctl(phy, ifr, cmd);
767a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
768a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
769a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_config(struct net_device *dev, struct ifmap *map)
770a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
771a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return -ENOSYS;
772a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
773a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
774a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_set_mac_address(struct net_device *dev, void *addr)
775a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
776a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
777a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u8 *mac = (u8 *)addr;
778a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
779939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	if (!is_valid_ether_addr(mac))
780939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka		return -EADDRNOTAVAIL;
781939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka
782a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, MAC_ADDR0, (mac[2] << 24) | (mac[3] << 16) |
783a1702857724fb39cb68ce581490010df99168fd0Thierry Reding				     (mac[4] <<  8) | (mac[5] <<  0));
784a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, MAC_ADDR1, (mac[0] <<  8) | (mac[1] <<  0));
785a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
786939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	memcpy(dev->dev_addr, mac, ETH_ALEN);
787939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
788939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka
789a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return 0;
790a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
791a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
792a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic void ethoc_set_multicast_list(struct net_device *dev)
793a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
794a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
795a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 mode = ethoc_read(priv, MODER);
79622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	struct netdev_hw_addr *ha;
797a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 hash[2] = { 0, 0 };
798a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
799a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* set loopback mode if requested */
800a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (dev->flags & IFF_LOOPBACK)
801a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		mode |=  MODER_LOOP;
802a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	else
803a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		mode &= ~MODER_LOOP;
804a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
805a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* receive broadcast frames if requested */
806a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (dev->flags & IFF_BROADCAST)
807a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		mode &= ~MODER_BRO;
808a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	else
809a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		mode |=  MODER_BRO;
810a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
811a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* enable promiscuous mode if requested */
812a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (dev->flags & IFF_PROMISC)
813a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		mode |=  MODER_PRO;
814a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	else
815a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		mode &= ~MODER_PRO;
816a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
817a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, MODER, mode);
818a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
819a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* receive multicast frames */
820a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (dev->flags & IFF_ALLMULTI) {
821a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		hash[0] = 0xffffffff;
822a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		hash[1] = 0xffffffff;
823a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	} else {
82422bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko		netdev_for_each_mc_addr(ha, dev) {
82522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko			u32 crc = ether_crc(ETH_ALEN, ha->addr);
826a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			int bit = (crc >> 26) & 0x3f;
827a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			hash[bit >> 5] |= 1 << (bit & 0x1f);
828a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		}
829a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
830a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
831a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, ETH_HASH0, hash[0]);
832a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write(priv, ETH_HASH1, hash[1]);
833a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
834a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
835a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_change_mtu(struct net_device *dev, int new_mtu)
836a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
837a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return -ENOSYS;
838a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
839a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
840a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic void ethoc_tx_timeout(struct net_device *dev)
841a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
842a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
843a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	u32 pending = ethoc_read(priv, INT_SOURCE);
844a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (likely(pending))
845a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ethoc_interrupt(dev->irq, dev);
846a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
847a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
84861357325f377889a1daffa14962d705dc814dd0eStephen Hemmingerstatic netdev_tx_t ethoc_start_xmit(struct sk_buff *skb, struct net_device *dev)
849a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
850a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(dev);
851a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc_bd bd;
852a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	unsigned int entry;
853a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	void *dest;
854a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
855a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (unlikely(skb->len > ETHOC_BUFSIZ)) {
85657616ee4405b82c3ba4d20111697a4416f3967a6Kulikov Vasiliy		dev->stats.tx_errors++;
8573790c8cdb99f23824b23cb16df608281b335ee91Patrick McHardy		goto out;
858a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
859a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
860a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	entry = priv->cur_tx % priv->num_tx;
861a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	spin_lock_irq(&priv->lock);
862a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->cur_tx++;
863a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
864a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_read_bd(priv, entry, &bd);
865a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (unlikely(skb->len < ETHOC_ZLEN))
866a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		bd.stat |=  TX_BD_PAD;
867a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	else
868a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		bd.stat &= ~TX_BD_PAD;
869a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
870f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn	dest = priv->vma[entry];
871a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	memcpy_toio(dest, skb->data, skb->len);
872a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
873a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	bd.stat &= ~(TX_BD_STATS | TX_BD_LEN_MASK);
874a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	bd.stat |= TX_BD_LEN(skb->len);
875a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write_bd(priv, entry, &bd);
876a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
877a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	bd.stat |= TX_BD_READY;
878a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ethoc_write_bd(priv, entry, &bd);
879a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
880a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (priv->cur_tx == (priv->dty_tx + priv->num_tx)) {
881a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_dbg(&dev->dev, "stopping queue\n");
882a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		netif_stop_queue(dev);
883a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
884a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
885a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	spin_unlock_irq(&priv->lock);
88668f51394073b30ef8648f8516d5a7d40c68b1f8aRichard Cochran	skb_tx_timestamp(skb);
8873790c8cdb99f23824b23cb16df608281b335ee91Patrick McHardyout:
8883790c8cdb99f23824b23cb16df608281b335ee91Patrick McHardy	dev_kfree_skb(skb);
889a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return NETDEV_TX_OK;
890a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
891a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
892a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic const struct net_device_ops ethoc_netdev_ops = {
893a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.ndo_open = ethoc_open,
894a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.ndo_stop = ethoc_stop,
895a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.ndo_do_ioctl = ethoc_ioctl,
896a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.ndo_set_config = ethoc_config,
897a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.ndo_set_mac_address = ethoc_set_mac_address,
898afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode = ethoc_set_multicast_list,
899a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.ndo_change_mtu = ethoc_change_mtu,
900a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.ndo_tx_timeout = ethoc_tx_timeout,
901a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.ndo_start_xmit = ethoc_start_xmit,
902a1702857724fb39cb68ce581490010df99168fd0Thierry Reding};
903a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
904a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/**
905a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * ethoc_probe() - initialize OpenCores ethernet MAC
906a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * pdev:	platform device
907a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */
908f78f09f76540c9a986bc321a186a291f4bb40925Jonas Bonnstatic int __devinit ethoc_probe(struct platform_device *pdev)
909a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
910a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct net_device *netdev = NULL;
911a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct resource *res = NULL;
912a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct resource *mmio = NULL;
913a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct resource *mem = NULL;
914a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = NULL;
915a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	unsigned int phy;
916c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn	int num_bd;
917a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	int ret = 0;
918939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	bool random_mac = false;
919a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
920a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* allocate networking device */
921a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	netdev = alloc_etherdev(sizeof(struct ethoc));
922a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!netdev) {
923a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret = -ENOMEM;
924a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		goto out;
925a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
926a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
927a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	SET_NETDEV_DEV(netdev, &pdev->dev);
928a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	platform_set_drvdata(pdev, netdev);
929a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
930a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* obtain I/O memory space */
931a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
932a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!res) {
933a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&pdev->dev, "cannot obtain I/O memory space\n");
934a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret = -ENXIO;
935a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		goto free;
936a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
937a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
938a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mmio = devm_request_mem_region(&pdev->dev, res->start,
939d86458471aadffe93b741024b5a879ea5dc8df35Tobias Klauser			resource_size(res), res->name);
940463889e27e6f4f097374a6c9de5611f520766dadJulia Lawall	if (!mmio) {
941a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&pdev->dev, "cannot request I/O memory space\n");
942a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret = -ENXIO;
943a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		goto free;
944a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
945a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
946a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	netdev->base_addr = mmio->start;
947a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
948a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* obtain buffer memory space */
949a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
9500baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou	if (res) {
9510baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		mem = devm_request_mem_region(&pdev->dev, res->start,
952d86458471aadffe93b741024b5a879ea5dc8df35Tobias Klauser			resource_size(res), res->name);
9530baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		if (!mem) {
9540baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			dev_err(&pdev->dev, "cannot request memory space\n");
9550baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			ret = -ENXIO;
9560baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			goto free;
9570baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		}
9580baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou
9590baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		netdev->mem_start = mem->start;
9600baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		netdev->mem_end   = mem->end;
961a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
962a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
963a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
964a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* obtain device IRQ number */
965a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
966a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!res) {
967a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&pdev->dev, "cannot obtain IRQ\n");
968a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret = -ENXIO;
969a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		goto free;
970a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
971a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
972a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	netdev->irq = res->start;
973a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
974a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* setup driver-private data */
975a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv = netdev_priv(netdev);
976a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->netdev = netdev;
9770baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou	priv->dma_alloc = 0;
97828f65c11f2ffb3957259dece647a24f8ad2e241bJoe Perches	priv->io_region_size = resource_size(mmio);
979a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
980a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->iobase = devm_ioremap_nocache(&pdev->dev, netdev->base_addr,
981d86458471aadffe93b741024b5a879ea5dc8df35Tobias Klauser			resource_size(mmio));
982a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!priv->iobase) {
983a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&pdev->dev, "cannot remap I/O memory space\n");
984a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret = -ENXIO;
985a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		goto error;
986a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
987a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
9880baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou	if (netdev->mem_end) {
9890baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		priv->membase = devm_ioremap_nocache(&pdev->dev,
990d86458471aadffe93b741024b5a879ea5dc8df35Tobias Klauser			netdev->mem_start, resource_size(mem));
9910baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		if (!priv->membase) {
9920baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			dev_err(&pdev->dev, "cannot remap memory space\n");
9930baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			ret = -ENXIO;
9940baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			goto error;
9950baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		}
9960baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou	} else {
9970baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		/* Allocate buffer memory */
998a71fba97295db924c0b90266e9833e5059fead24Jonas Bonn		priv->membase = dmam_alloc_coherent(&pdev->dev,
9990baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			buffer_size, (void *)&netdev->mem_start,
10000baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			GFP_KERNEL);
10010baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		if (!priv->membase) {
10020baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			dev_err(&pdev->dev, "cannot allocate %dB buffer\n",
10030baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou				buffer_size);
10040baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			ret = -ENOMEM;
10050baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou			goto error;
10060baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		}
10070baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		netdev->mem_end = netdev->mem_start + buffer_size;
10080baa080c75cea6357bfba9b93ba598d747457cbdThomas Chou		priv->dma_alloc = buffer_size;
1009a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
1010a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1011c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn	/* calculate the number of TX/RX buffers, maximum 128 supported */
1012c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn	num_bd = min_t(unsigned int,
1013c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn		128, (netdev->mem_end - netdev->mem_start + 1) / ETHOC_BUFSIZ);
10146a632625c7da7594d059b88dae0e9c591af147baJonas Bonn	if (num_bd < 4) {
10156a632625c7da7594d059b88dae0e9c591af147baJonas Bonn		ret = -ENODEV;
10166a632625c7da7594d059b88dae0e9c591af147baJonas Bonn		goto error;
10176a632625c7da7594d059b88dae0e9c591af147baJonas Bonn	}
10186a632625c7da7594d059b88dae0e9c591af147baJonas Bonn	/* num_tx must be a power of two */
10196a632625c7da7594d059b88dae0e9c591af147baJonas Bonn	priv->num_tx = rounddown_pow_of_two(num_bd >> 1);
1020c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn	priv->num_rx = num_bd - priv->num_tx;
1021c527f81475aaa18123eebe3d72a40a25d8e244afJonas Bonn
10226a632625c7da7594d059b88dae0e9c591af147baJonas Bonn	dev_dbg(&pdev->dev, "ethoc: num_tx: %d num_rx: %d\n",
10236a632625c7da7594d059b88dae0e9c591af147baJonas Bonn		priv->num_tx, priv->num_rx);
10246a632625c7da7594d059b88dae0e9c591af147baJonas Bonn
1025f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn	priv->vma = devm_kzalloc(&pdev->dev, num_bd*sizeof(void*), GFP_KERNEL);
1026f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn	if (!priv->vma) {
1027f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn		ret = -ENOMEM;
1028f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn		goto error;
1029f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn	}
1030f8555ad0cfb0ba6cbc8729f337341fb11c82db89Jonas Bonn
1031a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* Allow the platform setup code to pass in a MAC address. */
1032a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (pdev->dev.platform_data) {
1033e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn		struct ethoc_platform_data *pdata = pdev->dev.platform_data;
1034a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		memcpy(netdev->dev_addr, pdata->hwaddr, IFHWADDRLEN);
1035a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		priv->phy_id = pdata->phy_id;
1036e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn	} else {
1037e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn		priv->phy_id = -1;
1038e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn
1039e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn#ifdef CONFIG_OF
1040e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn		{
1041e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn		const uint8_t* mac;
1042e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn
1043e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn		mac = of_get_property(pdev->dev.of_node,
1044e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn				      "local-mac-address",
1045e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn				      NULL);
1046e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn		if (mac)
1047e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn			memcpy(netdev->dev_addr, mac, IFHWADDRLEN);
1048e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn		}
1049e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn#endif
1050a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
1051a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1052a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* Check that the given MAC address is valid. If it isn't, read the
1053a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	 * current MAC from the controller. */
1054a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!is_valid_ether_addr(netdev->dev_addr))
1055a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ethoc_get_mac_address(netdev, netdev->dev_addr);
1056a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1057a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* Check the MAC again for validity, if it still isn't choose and
1058a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	 * program a random one. */
1059939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	if (!is_valid_ether_addr(netdev->dev_addr)) {
1060a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		random_ether_addr(netdev->dev_addr);
1061939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka		random_mac = true;
1062939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	}
1063939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka
1064939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	ret = ethoc_set_mac_address(netdev, netdev->dev_addr);
1065939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	if (ret) {
1066939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka		dev_err(&netdev->dev, "failed to set MAC address\n");
1067939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka		goto error;
1068939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	}
1069a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1070939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka	if (random_mac)
1071939d2254fc259fd5ca0872f96b56f6966d804e24Danny Kukawka		netdev->addr_assign_type |= NET_ADDR_RANDOM;
1072a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1073a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* register MII bus */
1074a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->mdio = mdiobus_alloc();
1075a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!priv->mdio) {
1076a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret = -ENOMEM;
1077a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		goto free;
1078a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
1079a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1080a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->mdio->name = "ethoc-mdio";
1081a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	snprintf(priv->mdio->id, MII_BUS_ID_SIZE, "%s-%d",
1082a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			priv->mdio->name, pdev->id);
1083a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->mdio->read = ethoc_mdio_read;
1084a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->mdio->write = ethoc_mdio_write;
1085a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->mdio->reset = ethoc_mdio_reset;
1086a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->mdio->priv = priv;
1087a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1088a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	priv->mdio->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
1089a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (!priv->mdio->irq) {
1090a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		ret = -ENOMEM;
1091a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		goto free_mdio;
1092a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
1093a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1094a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	for (phy = 0; phy < PHY_MAX_ADDR; phy++)
1095a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		priv->mdio->irq[phy] = PHY_POLL;
1096a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1097a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ret = mdiobus_register(priv->mdio);
1098a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (ret) {
1099a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "failed to register MDIO bus\n");
1100a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		goto free_mdio;
1101a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
1102a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1103a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ret = ethoc_mdio_probe(netdev);
1104a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (ret) {
1105a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "failed to probe MDIO bus\n");
1106a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		goto error;
1107a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
1108a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1109a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ether_setup(netdev);
1110a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1111a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* setup the net_device structure */
1112a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	netdev->netdev_ops = &ethoc_netdev_ops;
1113a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	netdev->watchdog_timeo = ETHOC_TIMEOUT;
1114a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	netdev->features |= 0;
1115a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1116a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	/* setup NAPI */
1117a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	netif_napi_add(netdev, &priv->napi, ethoc_poll, 64);
1118a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1119a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	spin_lock_init(&priv->lock);
1120a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1121a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	ret = register_netdev(netdev);
1122a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (ret < 0) {
1123a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		dev_err(&netdev->dev, "failed to register interface\n");
1124ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou		goto error2;
1125a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
1126a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1127a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	goto out;
1128a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1129ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chouerror2:
1130ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou	netif_napi_del(&priv->napi);
1131a1702857724fb39cb68ce581490010df99168fd0Thierry Redingerror:
1132a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mdiobus_unregister(priv->mdio);
1133a1702857724fb39cb68ce581490010df99168fd0Thierry Redingfree_mdio:
1134a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	kfree(priv->mdio->irq);
1135a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	mdiobus_free(priv->mdio);
1136a1702857724fb39cb68ce581490010df99168fd0Thierry Redingfree:
1137a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	free_netdev(netdev);
1138a1702857724fb39cb68ce581490010df99168fd0Thierry Redingout:
1139a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return ret;
1140a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
1141a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1142a1702857724fb39cb68ce581490010df99168fd0Thierry Reding/**
1143a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * ethoc_remove() - shutdown OpenCores ethernet MAC
1144a1702857724fb39cb68ce581490010df99168fd0Thierry Reding * @pdev:	platform device
1145a1702857724fb39cb68ce581490010df99168fd0Thierry Reding */
1146f78f09f76540c9a986bc321a186a291f4bb40925Jonas Bonnstatic int __devexit ethoc_remove(struct platform_device *pdev)
1147a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
1148a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct net_device *netdev = platform_get_drvdata(pdev);
1149a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	struct ethoc *priv = netdev_priv(netdev);
1150a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1151a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	platform_set_drvdata(pdev, NULL);
1152a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1153a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	if (netdev) {
1154ee02a4ef40f2e049c80f9cc04e21a9b48288b6ffThomas Chou		netif_napi_del(&priv->napi);
1155a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		phy_disconnect(priv->phy);
1156a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		priv->phy = NULL;
1157a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1158a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		if (priv->mdio) {
1159a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			mdiobus_unregister(priv->mdio);
1160a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			kfree(priv->mdio->irq);
1161a1702857724fb39cb68ce581490010df99168fd0Thierry Reding			mdiobus_free(priv->mdio);
1162a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		}
1163a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		unregister_netdev(netdev);
1164a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		free_netdev(netdev);
1165a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	}
1166a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1167a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return 0;
1168a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
1169a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1170a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#ifdef CONFIG_PM
1171a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_suspend(struct platform_device *pdev, pm_message_t state)
1172a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
1173a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return -ENOSYS;
1174a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
1175a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1176a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic int ethoc_resume(struct platform_device *pdev)
1177a1702857724fb39cb68ce581490010df99168fd0Thierry Reding{
1178a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	return -ENOSYS;
1179a1702857724fb39cb68ce581490010df99168fd0Thierry Reding}
1180a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#else
1181a1702857724fb39cb68ce581490010df99168fd0Thierry Reding# define ethoc_suspend NULL
1182a1702857724fb39cb68ce581490010df99168fd0Thierry Reding# define ethoc_resume  NULL
1183a1702857724fb39cb68ce581490010df99168fd0Thierry Reding#endif
1184a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1185e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonnstatic struct of_device_id ethoc_match[] = {
1186c9e358dfc4a8cb2227172ef77908c2e0ee17bcb9Grant Likely	{ .compatible = "opencores,ethoc", },
1187e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn	{},
1188e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn};
1189e0f4258be2515afce8ef1e6fb22312525c281798Jonas BonnMODULE_DEVICE_TABLE(of, ethoc_match);
1190e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn
1191a1702857724fb39cb68ce581490010df99168fd0Thierry Redingstatic struct platform_driver ethoc_driver = {
1192a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.probe   = ethoc_probe,
1193f78f09f76540c9a986bc321a186a291f4bb40925Jonas Bonn	.remove  = __devexit_p(ethoc_remove),
1194a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.suspend = ethoc_suspend,
1195a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.resume  = ethoc_resume,
1196a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	.driver  = {
1197a1702857724fb39cb68ce581490010df99168fd0Thierry Reding		.name = "ethoc",
1198e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn		.owner = THIS_MODULE,
1199e0f4258be2515afce8ef1e6fb22312525c281798Jonas Bonn		.of_match_table = ethoc_match,
1200a1702857724fb39cb68ce581490010df99168fd0Thierry Reding	},
1201a1702857724fb39cb68ce581490010df99168fd0Thierry Reding};
1202a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1203db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(ethoc_driver);
1204a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1205a1702857724fb39cb68ce581490010df99168fd0Thierry RedingMODULE_AUTHOR("Thierry Reding <thierry.reding@avionic-design.de>");
1206a1702857724fb39cb68ce581490010df99168fd0Thierry RedingMODULE_DESCRIPTION("OpenCores Ethernet MAC driver");
1207a1702857724fb39cb68ce581490010df99168fd0Thierry RedingMODULE_LICENSE("GPL v2");
1208a1702857724fb39cb68ce581490010df99168fd0Thierry Reding
1209