1a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/*
2a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * Copyright (c) 2008-2009 Nuvoton technology corporation.
3a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun *
4a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * Wan ZongShun <mcuos.com@gmail.com>
5a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun *
6a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * This program is free software; you can redistribute it and/or modify
7a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * it under the terms of the GNU General Public License as published by
8a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun * the Free Software Foundation;version 2 of the License.
9a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun *
10a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun */
11a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
12a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/module.h>
13a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/init.h>
14a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/mii.h>
15a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/netdevice.h>
16a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/etherdevice.h>
17a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/skbuff.h>
18a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/ethtool.h>
19a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/platform_device.h>
20a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#include <linux/clk.h>
215a0e3ad6af8660be21ca98a971cd00f331318c05Tejun Heo#include <linux/gfp.h>
22a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
23a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define DRV_MODULE_NAME		"w90p910-emc"
24a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define DRV_MODULE_VERSION	"0.1"
25a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
26a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* Ethernet MAC Registers */
27a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CAMCMR		0x00
28a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CAMEN		0x04
29a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CAMM_BASE		0x08
30a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CAML_BASE		0x0c
31a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_TXDLSA		0x88
32a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_RXDLSA		0x8C
33a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MCMDR		0x90
34a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MIID		0x94
35a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MIIDA		0x98
36a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_FFTCR		0x9C
37a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_TSDR		0xa0
38a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_RSDR		0xa4
39a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_DMARFC		0xa8
40a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MIEN		0xac
41a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_MISTA		0xb0
42a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CTXDSA		0xcc
43a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CTXBSA		0xd0
44a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CRXDSA		0xd4
45a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define REG_CRXBSA		0xd8
46a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
47a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* mac controller bit */
48a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_RXON		0x01
49a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_ACP		(0x01 << 3)
50a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_SPCRC		(0x01 << 5)
51a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_TXON		(0x01 << 8)
52a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_FDUP		(0x01 << 18)
53a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_ENMDC		(0x01 << 19)
54a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MCMDR_OPMOD		(0x01 << 20)
55a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define SWR			(0x01 << 24)
56a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
57a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* cam command regiser */
58a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_AUP		0x01
59a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_AMP		(0x01 << 1)
60a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_ABP		(0x01 << 2)
61a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_CCAM		(0x01 << 3)
62a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAMCMR_ECMP		(0x01 << 4)
63a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAM0EN			0x01
64a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
65a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* mac mii controller bit */
66a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MDCCR			(0x0a << 20)
67a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYAD			(0x01 << 8)
68a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYWR			(0x01 << 16)
69a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYBUSY			(0x01 << 17)
70a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYPRESP		(0x01 << 18)
71a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAM_ENTRY_SIZE		0x08
72a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
73a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* rx and tx status */
74a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TXDS_TXCP		(0x01 << 19)
75a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_CRCE		(0x01 << 17)
76a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_PTLE		(0x01 << 19)
77a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_RXGD		(0x01 << 20)
78a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_ALIE		(0x01 << 21)
79a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RXDS_RP			(0x01 << 22)
80a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
81a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* mac interrupt status*/
82a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_EXDEF		(0x01 << 19)
83a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_TXBERR		(0x01 << 24)
84a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_TDU		(0x01 << 23)
85a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_RDU		(0x01 << 10)
86a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MISTA_RXBERR		(0x01 << 11)
87a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
88a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENSTART			0x01
89a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENRXINTR		0x01
90a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENRXGD			(0x01 << 4)
91a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENRXBERR		(0x01 << 11)
92a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENTXINTR		(0x01 << 16)
93a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENTXCP			(0x01 << 18)
94a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENTXABT			(0x01 << 21)
95a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENTXBERR		(0x01 << 24)
96a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define ENMDC			(0x01 << 19)
97a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PHYBUSY			(0x01 << 17)
98a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MDCCR_VAL		0xa00000
99a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
100a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* rx and tx owner bit */
101a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RX_OWEN_DMA		(0x01 << 31)
102a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RX_OWEN_CPU		(~(0x03 << 30))
103a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TX_OWEN_DMA		(0x01 << 31)
104a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TX_OWEN_CPU		(~(0x01 << 31))
105a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
106a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* tx frame desc controller bit */
107a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MACTXINTEN		0x04
108a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CRCMODE			0x02
109a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define PADDINGMODE		0x01
110a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
111a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* fftcr controller bit */
112a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TXTHD 			(0x03 << 8)
113a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define BLENGTH			(0x01 << 20)
114a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
115a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun/* global setting for driver */
116a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define RX_DESC_SIZE		50
117a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define TX_DESC_SIZE		10
118a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MAX_RBUFF_SZ		0x600
119a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define MAX_TBUFF_SZ		0x600
120c63fdf46ad0a7f8fe3c0252a0e763515617e0ea7Eric Dumazet#define TX_TIMEOUT		(HZ/2)
121a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define DELAY			1000
122a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun#define CAM0			0x0
123a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
124a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg);
125a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
126a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct w90p910_rxbd {
127a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int sl;
128a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int buffer;
129a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int reserved;
130a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int next;
131a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun};
132a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
133a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct w90p910_txbd {
134a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int mode;
135a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int buffer;
136a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int sl;
137a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int next;
138a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun};
139a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
140a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct recv_pdesc {
141a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_rxbd desclist[RX_DESC_SIZE];
142a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	char recv_buf[RX_DESC_SIZE][MAX_RBUFF_SZ];
143a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun};
144a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
145a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct tran_pdesc {
146a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_txbd desclist[TX_DESC_SIZE];
1471e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	char tran_buf[TX_DESC_SIZE][MAX_TBUFF_SZ];
148a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun};
149a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
150a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstruct  w90p910_ether {
151a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct recv_pdesc *rdesc;
152a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct tran_pdesc *tdesc;
1531e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	dma_addr_t rdesc_phys;
1541e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	dma_addr_t tdesc_phys;
155a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct net_device_stats stats;
156a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
1571e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	struct resource *res;
158a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct sk_buff *skb;
159a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct clk *clk;
160a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct clk *rmiiclk;
161a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct mii_if_info mii;
162a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct timer_list check_timer;
163a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	void __iomem *reg;
164ddb1417529559810ec2024fd8ca21e4d497a3275Wan ZongShun	int rxirq;
165ddb1417529559810ec2024fd8ca21e4d497a3275Wan ZongShun	int txirq;
166a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int cur_tx;
167a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int cur_rx;
168a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int finish_tx;
169a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int rx_packets;
170a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int rx_bytes;
171a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int start_tx_ptr;
172a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int start_rx_ptr;
173a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int linkflag;
174a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun};
175a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
176a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void update_linkspeed_register(struct net_device *dev,
177a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun				unsigned int speed, unsigned int duplex)
178a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
179a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
180a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val;
181a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
182a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = __raw_readl(ether->reg + REG_MCMDR);
183a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
184a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (speed == SPEED_100) {
185a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		/* 100 full/half duplex */
186a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if (duplex == DUPLEX_FULL) {
187a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			val |= (MCMDR_OPMOD | MCMDR_FDUP);
188a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		} else {
189a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			val |= MCMDR_OPMOD;
190a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			val &= ~MCMDR_FDUP;
191a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		}
192a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	} else {
193a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		/* 10 full/half duplex */
194a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if (duplex == DUPLEX_FULL) {
195a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			val |= MCMDR_FDUP;
196a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			val &= ~MCMDR_OPMOD;
197a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		} else {
198a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			val &= ~(MCMDR_FDUP | MCMDR_OPMOD);
199a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		}
200a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
201a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
202a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_MCMDR);
203a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
204a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
205a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void update_linkspeed(struct net_device *dev)
206a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
207a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
208a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
209a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int bmsr, bmcr, lpa, speed, duplex;
210a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
211a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	pdev = ether->pdev;
212a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
213a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (!mii_link_ok(&ether->mii)) {
214a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		ether->linkflag = 0x0;
215a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		netif_carrier_off(dev);
216a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_warn(&pdev->dev, "%s: Link down.\n", dev->name);
217a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		return;
218a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
219a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
220a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (ether->linkflag == 1)
221a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		return;
222a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
223a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	bmsr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMSR);
224a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	bmcr = w90p910_mdio_read(dev, ether->mii.phy_id, MII_BMCR);
225a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
226a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (bmcr & BMCR_ANENABLE) {
227a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if (!(bmsr & BMSR_ANEGCOMPLETE))
228a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			return;
229a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
230a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		lpa = w90p910_mdio_read(dev, ether->mii.phy_id, MII_LPA);
231a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
232a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if ((lpa & LPA_100FULL) || (lpa & LPA_100HALF))
233a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			speed = SPEED_100;
234a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		else
235a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			speed = SPEED_10;
236a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
237a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if ((lpa & LPA_100FULL) || (lpa & LPA_10FULL))
238a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			duplex = DUPLEX_FULL;
239a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		else
240a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			duplex = DUPLEX_HALF;
241a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
242a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	} else {
243a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		speed = (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10;
244a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		duplex = (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
245a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
246a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
247a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	update_linkspeed_register(dev, speed, duplex);
248a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
249a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	dev_info(&pdev->dev, "%s: Link now %i-%s\n", dev->name, speed,
250a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			(duplex == DUPLEX_FULL) ? "FullDuplex" : "HalfDuplex");
251a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->linkflag = 0x01;
252a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
253a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	netif_carrier_on(dev);
254a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
255a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
256a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_check_link(unsigned long dev_id)
257a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
258a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct net_device *dev = (struct net_device *) dev_id;
259a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
260a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
261a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	update_linkspeed(dev);
262a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	mod_timer(&ether->check_timer, jiffies + msecs_to_jiffies(1000));
263a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
264a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
265a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_write_cam(struct net_device *dev,
266a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun				unsigned int x, unsigned char *pval)
267a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
268a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
269a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int msw, lsw;
270a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
271a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	msw = (pval[0] << 24) | (pval[1] << 16) | (pval[2] << 8) | pval[3];
272a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
273a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	lsw = (pval[4] << 24) | (pval[5] << 16);
274a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
275a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(lsw, ether->reg + REG_CAML_BASE + x * CAM_ENTRY_SIZE);
276a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(msw, ether->reg + REG_CAMM_BASE + x * CAM_ENTRY_SIZE);
277a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
278a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
2791e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShunstatic int w90p910_init_desc(struct net_device *dev)
280a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
281a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether;
2821e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	struct w90p910_txbd  *tdesc;
2831e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	struct w90p910_rxbd  *rdesc;
2841e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	struct platform_device *pdev;
2851e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	unsigned int i;
286a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
287a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether = netdev_priv(dev);
2881e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	pdev = ether->pdev;
289a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
290a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->tdesc = (struct tran_pdesc *)
2911e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		dma_alloc_coherent(&pdev->dev, sizeof(struct tran_pdesc),
2921e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun					&ether->tdesc_phys, GFP_KERNEL);
2931e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
2941e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	if (!ether->tdesc) {
2951e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		dev_err(&pdev->dev, "Failed to allocate memory for tx desc\n");
2961e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		return -ENOMEM;
2971e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	}
298a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
299a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->rdesc = (struct recv_pdesc *)
3001e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		dma_alloc_coherent(&pdev->dev, sizeof(struct recv_pdesc),
3011e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun					&ether->rdesc_phys, GFP_KERNEL);
3021e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
3031e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	if (!ether->rdesc) {
3041e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		dev_err(&pdev->dev, "Failed to allocate memory for rx desc\n");
3051e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
3061e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun					ether->tdesc, ether->tdesc_phys);
3071e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		return -ENOMEM;
3081e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	}
309a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
310a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	for (i = 0; i < TX_DESC_SIZE; i++) {
3111e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		unsigned int offset;
312a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
3131e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		tdesc = &(ether->tdesc->desclist[i]);
314a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
3151e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		if (i == TX_DESC_SIZE - 1)
3161e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			offset = offsetof(struct tran_pdesc, desclist[0]);
3171e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		else
3181e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			offset = offsetof(struct tran_pdesc, desclist[i + 1]);
319a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
3201e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		tdesc->next = ether->tdesc_phys + offset;
3211e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		tdesc->buffer = ether->tdesc_phys +
3221e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			offsetof(struct tran_pdesc, tran_buf[i]);
323a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		tdesc->sl = 0;
324a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		tdesc->mode = 0;
325a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
326a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
3271e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	ether->start_tx_ptr = ether->tdesc_phys;
3281e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
329a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	for (i = 0; i < RX_DESC_SIZE; i++) {
3301e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		unsigned int offset;
331a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
3321e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		rdesc = &(ether->rdesc->desclist[i]);
333a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
3341e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		if (i == RX_DESC_SIZE - 1)
3351e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			offset = offsetof(struct recv_pdesc, desclist[0]);
3361e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		else
3371e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			offset = offsetof(struct recv_pdesc, desclist[i + 1]);
338a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
3391e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		rdesc->next = ether->rdesc_phys + offset;
340a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		rdesc->sl = RX_OWEN_DMA;
3411e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		rdesc->buffer = ether->rdesc_phys +
3421e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			offsetof(struct recv_pdesc, recv_buf[i]);
343a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	  }
3441e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
3451e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	ether->start_rx_ptr = ether->rdesc_phys;
3461e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
3471e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	return 0;
348a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
349a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
350a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_set_fifo_threshold(struct net_device *dev)
351a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
352a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
353a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val;
354a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
355a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = TXTHD | BLENGTH;
356a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_FFTCR);
357a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
358a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
359a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_return_default_idle(struct net_device *dev)
360a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
361a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
362a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val;
363a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
364a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = __raw_readl(ether->reg + REG_MCMDR);
365a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val |= SWR;
366a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_MCMDR);
367a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
368a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
369a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_trigger_rx(struct net_device *dev)
370a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
371a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
372a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
373a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(ENSTART, ether->reg + REG_RSDR);
374a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
375a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
376a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_trigger_tx(struct net_device *dev)
377a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
378a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
379a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
380a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(ENSTART, ether->reg + REG_TSDR);
381a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
382a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
383a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_mac_interrupt(struct net_device *dev)
384a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
385a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
386a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val;
387a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
388a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = ENTXINTR | ENRXINTR | ENRXGD | ENTXCP;
389a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val |= ENTXBERR | ENRXBERR | ENTXABT;
390a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
391a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_MIEN);
392a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
393a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
394a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_get_and_clear_int(struct net_device *dev,
395a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun							unsigned int *val)
396a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
397a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
398a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
399a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	*val = __raw_readl(ether->reg + REG_MISTA);
400a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(*val, ether->reg + REG_MISTA);
401a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
402a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
403a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_set_global_maccmd(struct net_device *dev)
404a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
405a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
406a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val;
407a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
408a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = __raw_readl(ether->reg + REG_MCMDR);
409a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val |= MCMDR_SPCRC | MCMDR_ENMDC | MCMDR_ACP | ENMDC;
410a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_MCMDR);
411a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
412a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
413a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_cam(struct net_device *dev)
414a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
415a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
416a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val;
417a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
418a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_write_cam(dev, CAM0, dev->dev_addr);
419a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
420a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = __raw_readl(ether->reg + REG_CAMEN);
421a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val |= CAM0EN;
422a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_CAMEN);
423a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
424a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
425a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_cam_command(struct net_device *dev)
426a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
427a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
428a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val;
429a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
430a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = CAMCMR_ECMP | CAMCMR_ABP | CAMCMR_AMP;
431a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_CAMCMR);
432a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
433a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
434a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_tx(struct net_device *dev, unsigned int enable)
435a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
436a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
437a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val;
438a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
439a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = __raw_readl(ether->reg + REG_MCMDR);
440a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
441a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (enable)
442a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		val |= MCMDR_TXON;
443a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	else
444a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		val &= ~MCMDR_TXON;
445a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
446a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_MCMDR);
447a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
448a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
449a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_enable_rx(struct net_device *dev, unsigned int enable)
450a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
451a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
452a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val;
453a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
454a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = __raw_readl(ether->reg + REG_MCMDR);
455a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
456a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (enable)
457a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		val |= MCMDR_RXON;
458a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	else
459a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		val &= ~MCMDR_RXON;
460a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
461a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_MCMDR);
462a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
463a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
464a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_set_curdest(struct net_device *dev)
465a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
466a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
467a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
468a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(ether->start_rx_ptr, ether->reg + REG_RXDLSA);
469a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(ether->start_tx_ptr, ether->reg + REG_TXDLSA);
470a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
471a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
472a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_reset_mac(struct net_device *dev)
473a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
474a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
475a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
476a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_tx(dev, 0);
477a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_rx(dev, 0);
478a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_set_fifo_threshold(dev);
479a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_return_default_idle(dev);
480a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
481a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (!netif_queue_stopped(dev))
482a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		netif_stop_queue(dev);
483a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
484a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_init_desc(dev);
485a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
4861ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	dev->trans_start = jiffies; /* prevent tx timeout */
487a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->cur_tx = 0x0;
488a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->finish_tx = 0x0;
489a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->cur_rx = 0x0;
490a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
491a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_set_curdest(dev);
492a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_cam(dev);
493a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_cam_command(dev);
494a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_mac_interrupt(dev);
495a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_tx(dev, 1);
496a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_rx(dev, 1);
497a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_trigger_tx(dev);
498a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_trigger_rx(dev);
499a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
5001ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	dev->trans_start = jiffies; /* prevent tx timeout */
501a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
502a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (netif_queue_stopped(dev))
503a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		netif_wake_queue(dev);
504a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
505a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
506a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_mdio_write(struct net_device *dev,
507a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun					int phy_id, int reg, int data)
508a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
509a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
510a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
511a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val, i;
512a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
513a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	pdev = ether->pdev;
514a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
515a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(data, ether->reg + REG_MIID);
516a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
517a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = (phy_id << 0x08) | reg;
518a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val |= PHYBUSY | PHYWR | MDCCR_VAL;
519a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_MIIDA);
520a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
521a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	for (i = 0; i < DELAY; i++) {
522a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0)
523a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			break;
524a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
525a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
526a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (i == DELAY)
527a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_warn(&pdev->dev, "mdio write timed out\n");
528a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
529a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
530a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_mdio_read(struct net_device *dev, int phy_id, int reg)
531a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
532a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
533a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
534a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int val, i, data;
535a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
536a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	pdev = ether->pdev;
537a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
538a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val = (phy_id << 0x08) | reg;
539a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	val |= PHYBUSY | MDCCR_VAL;
540a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(val, ether->reg + REG_MIIDA);
541a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
542a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	for (i = 0; i < DELAY; i++) {
543a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if ((__raw_readl(ether->reg + REG_MIIDA) & PHYBUSY) == 0)
544a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			break;
545a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
546a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
547a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (i == DELAY) {
548a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_warn(&pdev->dev, "mdio read timed out\n");
549a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		data = 0xffff;
550a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	} else {
551a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		data = __raw_readl(ether->reg + REG_MIID);
552a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
553a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
554a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return data;
555a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
556a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
5571e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShunstatic int w90p910_set_mac_address(struct net_device *dev, void *addr)
558a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
559a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct sockaddr *address = addr;
560a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
561a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (!is_valid_ether_addr(address->sa_data))
562a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		return -EADDRNOTAVAIL;
563a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
564a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	memcpy(dev->dev_addr, address->sa_data, dev->addr_len);
565a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_write_cam(dev, CAM0, dev->dev_addr);
566a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
567a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return 0;
568a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
569a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
570a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_close(struct net_device *dev)
571a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
572a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
5731e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	struct platform_device *pdev;
574a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
5751e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	pdev = ether->pdev;
5761e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
5771e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	dma_free_coherent(&pdev->dev, sizeof(struct recv_pdesc),
5781e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun					ether->rdesc, ether->rdesc_phys);
5791e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	dma_free_coherent(&pdev->dev, sizeof(struct tran_pdesc),
5801e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun					ether->tdesc, ether->tdesc_phys);
581a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
582a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	netif_stop_queue(dev);
583a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
584a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	del_timer_sync(&ether->check_timer);
585a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	clk_disable(ether->rmiiclk);
586a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	clk_disable(ether->clk);
587a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
588a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	free_irq(ether->txirq, dev);
589a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	free_irq(ether->rxirq, dev);
590a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
591a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return 0;
592a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
593a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
594a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic struct net_device_stats *w90p910_ether_stats(struct net_device *dev)
595a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
596a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether;
597a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
598a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether = netdev_priv(dev);
599a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
600a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return &ether->stats;
601a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
602a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
603a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_send_frame(struct net_device *dev,
604a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun					unsigned char *data, int length)
605a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
606a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether;
607a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_txbd *txbd;
608a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
609a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned char *buffer;
610a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
611a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether = netdev_priv(dev);
612a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	pdev = ether->pdev;
613a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
614a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	txbd = &ether->tdesc->desclist[ether->cur_tx];
615a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	buffer = ether->tdesc->tran_buf[ether->cur_tx];
6161e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
617a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (length > 1514) {
618a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "send data %d bytes, check it\n", length);
619a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		length = 1514;
620a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
621a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
622a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	txbd->sl = length & 0xFFFF;
623a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
624a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	memcpy(buffer, data, length);
625a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
626a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	txbd->mode = TX_OWEN_DMA | PADDINGMODE | CRCMODE | MACTXINTEN;
627a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
628a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_tx(dev, 1);
629a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
630a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_trigger_tx(dev);
631a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
6321e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	if (++ether->cur_tx >= TX_DESC_SIZE)
6331e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		ether->cur_tx = 0;
6341e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
635a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	txbd = &ether->tdesc->desclist[ether->cur_tx];
636a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
637a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (txbd->mode & TX_OWEN_DMA)
638a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		netif_stop_queue(dev);
639a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
640a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return 0;
641a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
642a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
643a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_start_xmit(struct sk_buff *skb, struct net_device *dev)
644a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
645a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
646a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
647a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (!(w90p910_send_frame(dev, skb->data, skb->len))) {
648a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		ether->skb = skb;
649a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_kfree_skb_irq(skb);
650a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		return 0;
651a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
6521e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	return -EAGAIN;
653a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
654a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
655a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic irqreturn_t w90p910_tx_interrupt(int irq, void *dev_id)
656a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
657a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether;
658a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_txbd  *txbd;
659a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
660a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct net_device *dev;
661a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int cur_entry, entry, status;
662a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
6631e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	dev = dev_id;
664a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether = netdev_priv(dev);
665a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	pdev = ether->pdev;
666a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
667a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_get_and_clear_int(dev, &status);
668a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
669a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	cur_entry = __raw_readl(ether->reg + REG_CTXDSA);
670a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
6711e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	entry = ether->tdesc_phys +
6721e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
673a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
674a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	while (entry != cur_entry) {
675a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		txbd = &ether->tdesc->desclist[ether->finish_tx];
676a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
6771e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		if (++ether->finish_tx >= TX_DESC_SIZE)
6781e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			ether->finish_tx = 0;
679a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
680a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if (txbd->sl & TXDS_TXCP) {
681a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			ether->stats.tx_packets++;
682a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			ether->stats.tx_bytes += txbd->sl & 0xFFFF;
683a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		} else {
684a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			ether->stats.tx_errors++;
685a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		}
686a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
687a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		txbd->sl = 0x0;
688a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		txbd->mode = 0x0;
689a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
690a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if (netif_queue_stopped(dev))
691a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			netif_wake_queue(dev);
692a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
6931e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		entry = ether->tdesc_phys +
6941e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			offsetof(struct tran_pdesc, desclist[ether->finish_tx]);
695a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
696a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
697a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (status & MISTA_EXDEF) {
698a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "emc defer exceed interrupt\n");
699a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	} else if (status & MISTA_TXBERR) {
7001e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		dev_err(&pdev->dev, "emc bus error interrupt\n");
7011e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		w90p910_reset_mac(dev);
7021e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	} else if (status & MISTA_TDU) {
7031e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		if (netif_queue_stopped(dev))
7041e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			netif_wake_queue(dev);
7051e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	}
706a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
707a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return IRQ_HANDLED;
708a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
709a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
710a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void netdev_rx(struct net_device *dev)
711a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
712a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether;
713a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_rxbd *rxbd;
714a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
715a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct sk_buff *skb;
716a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned char *data;
717a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int length, status, val, entry;
718a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
719a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether = netdev_priv(dev);
720a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	pdev = ether->pdev;
721a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
722a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	rxbd = &ether->rdesc->desclist[ether->cur_rx];
723a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
724a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	do {
725a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		val = __raw_readl(ether->reg + REG_CRXDSA);
7261e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
7271e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		entry = ether->rdesc_phys +
7281e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			offsetof(struct recv_pdesc, desclist[ether->cur_rx]);
729a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
730a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if (val == entry)
731a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			break;
732a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
733a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		status = rxbd->sl;
734a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		length = status & 0xFFFF;
735a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
736a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		if (status & RXDS_RXGD) {
737a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			data = ether->rdesc->recv_buf[ether->cur_rx];
738a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			skb = dev_alloc_skb(length+2);
739a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			if (!skb) {
740a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun				dev_err(&pdev->dev, "get skb buffer error\n");
741a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun				ether->stats.rx_dropped++;
742a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun				return;
743a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			}
744a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
745a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			skb_reserve(skb, 2);
746a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			skb_put(skb, length);
747a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			skb_copy_to_linear_data(skb, data, length);
748a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			skb->protocol = eth_type_trans(skb, dev);
749a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			ether->stats.rx_packets++;
750a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			ether->stats.rx_bytes += length;
751a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			netif_rx(skb);
752a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		} else {
753a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			ether->stats.rx_errors++;
754a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
755a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			if (status & RXDS_RP) {
756a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun				dev_err(&pdev->dev, "rx runt err\n");
757a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun				ether->stats.rx_length_errors++;
758a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			} else if (status & RXDS_CRCE) {
7591e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun				dev_err(&pdev->dev, "rx crc err\n");
7601e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun				ether->stats.rx_crc_errors++;
7611e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			} else if (status & RXDS_ALIE) {
762a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun				dev_err(&pdev->dev, "rx aligment err\n");
763a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun				ether->stats.rx_frame_errors++;
764a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			} else if (status & RXDS_PTLE) {
7651e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun				dev_err(&pdev->dev, "rx longer err\n");
7661e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun				ether->stats.rx_over_errors++;
767a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun			}
7681e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		}
769a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
770a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		rxbd->sl = RX_OWEN_DMA;
771a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		rxbd->reserved = 0x0;
7721e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
7731e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		if (++ether->cur_rx >= RX_DESC_SIZE)
7741e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun			ether->cur_rx = 0;
7751e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
776a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		rxbd = &ether->rdesc->desclist[ether->cur_rx];
777a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
778a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	} while (1);
779a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
780a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
781a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic irqreturn_t w90p910_rx_interrupt(int irq, void *dev_id)
782a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
783a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct net_device *dev;
784a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether  *ether;
785a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
786a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int status;
787a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
7881e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	dev = dev_id;
789a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether = netdev_priv(dev);
790a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	pdev = ether->pdev;
791a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
792a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_get_and_clear_int(dev, &status);
793a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
794a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (status & MISTA_RDU) {
795a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		netdev_rx(dev);
796a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		w90p910_trigger_rx(dev);
797a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
798a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		return IRQ_HANDLED;
799a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	} else if (status & MISTA_RXBERR) {
8001e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		dev_err(&pdev->dev, "emc rx bus error\n");
8011e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		w90p910_reset_mac(dev);
8021e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	}
803a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
804a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	netdev_rx(dev);
805a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return IRQ_HANDLED;
806a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
807a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
808a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_open(struct net_device *dev)
809a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
810a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether;
811a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
812a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
813a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether = netdev_priv(dev);
814a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	pdev = ether->pdev;
815a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
816a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_reset_mac(dev);
817a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_set_fifo_threshold(dev);
818a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_set_curdest(dev);
819a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_cam(dev);
820a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_cam_command(dev);
821a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_mac_interrupt(dev);
822a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_set_global_maccmd(dev);
823a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_enable_rx(dev, 1);
824a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
825d1853dc8fa8e6478707bf5d8e9d0b949974c2ddeWan ZongShun	clk_enable(ether->rmiiclk);
826d1853dc8fa8e6478707bf5d8e9d0b949974c2ddeWan ZongShun	clk_enable(ether->clk);
827d1853dc8fa8e6478707bf5d8e9d0b949974c2ddeWan ZongShun
828a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->rx_packets = 0x0;
829a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->rx_bytes = 0x0;
830a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
831a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (request_irq(ether->txirq, w90p910_tx_interrupt,
832a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun						0x0, pdev->name, dev)) {
833a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "register irq tx failed\n");
834a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		return -EAGAIN;
835a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
836a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
837a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (request_irq(ether->rxirq, w90p910_rx_interrupt,
838a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun						0x0, pdev->name, dev)) {
839a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "register irq rx failed\n");
8401e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun		free_irq(ether->txirq, dev);
841a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		return -EAGAIN;
842a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
843a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
844a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	mod_timer(&ether->check_timer, jiffies + msecs_to_jiffies(1000));
845a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	netif_start_queue(dev);
846a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_trigger_rx(dev);
847a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
848a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	dev_info(&pdev->dev, "%s is OPENED\n", dev->name);
849a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
850a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return 0;
851a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
852a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
853a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_ether_set_multicast_list(struct net_device *dev)
854a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
855a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether;
856a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unsigned int rx_mode;
857a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
858a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether = netdev_priv(dev);
859a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
860a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (dev->flags & IFF_PROMISC)
861a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		rx_mode = CAMCMR_AUP | CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
8623b9a7728d878a3e7adc79fb89c3bb9ebc23760d7Jiri Pirko	else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev))
8633b9a7728d878a3e7adc79fb89c3bb9ebc23760d7Jiri Pirko		rx_mode = CAMCMR_AMP | CAMCMR_ABP | CAMCMR_ECMP;
8643b9a7728d878a3e7adc79fb89c3bb9ebc23760d7Jiri Pirko	else
8653b9a7728d878a3e7adc79fb89c3bb9ebc23760d7Jiri Pirko		rx_mode = CAMCMR_ECMP | CAMCMR_ABP;
866a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	__raw_writel(rx_mode, ether->reg + REG_CAMCMR);
867a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
868a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
869a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_ioctl(struct net_device *dev,
870a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun						struct ifreq *ifr, int cmd)
871a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
872a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
873a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct mii_ioctl_data *data = if_mii(ifr);
874a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
875a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return generic_mii_ioctl(&ether->mii, data, cmd, NULL);
876a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
877a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
878a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void w90p910_get_drvinfo(struct net_device *dev,
879a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun					struct ethtool_drvinfo *info)
880a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
881a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	strcpy(info->driver, DRV_MODULE_NAME);
882a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	strcpy(info->version, DRV_MODULE_VERSION);
883a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
884a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
885a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
886a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
887a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
888a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return mii_ethtool_gset(&ether->mii, cmd);
889a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
890a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
891a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
892a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
893a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
894a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return mii_ethtool_sset(&ether->mii, cmd);
895a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
896a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
897a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_nway_reset(struct net_device *dev)
898a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
899a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
900a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return mii_nway_restart(&ether->mii);
901a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
902a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
903a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic u32 w90p910_get_link(struct net_device *dev)
904a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
905a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
906a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return mii_link_ok(&ether->mii);
907a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
908a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
909a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic const struct ethtool_ops w90p910_ether_ethtool_ops = {
910a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.get_settings	= w90p910_get_settings,
911a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.set_settings	= w90p910_set_settings,
912a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.get_drvinfo	= w90p910_get_drvinfo,
913a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.nway_reset	= w90p910_nway_reset,
914a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.get_link	= w90p910_get_link,
915a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun};
916a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
917a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic const struct net_device_ops w90p910_ether_netdev_ops = {
918a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.ndo_open		= w90p910_ether_open,
919a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.ndo_stop		= w90p910_ether_close,
920a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.ndo_start_xmit		= w90p910_ether_start_xmit,
921a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.ndo_get_stats		= w90p910_ether_stats,
922afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= w90p910_ether_set_multicast_list,
9231e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	.ndo_set_mac_address	= w90p910_set_mac_address,
924a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.ndo_do_ioctl		= w90p910_ether_ioctl,
925a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.ndo_validate_addr	= eth_validate_addr,
926a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.ndo_change_mtu		= eth_change_mtu,
927a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun};
928a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
929a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic void __init get_mac_address(struct net_device *dev)
930a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
931a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
932a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct platform_device *pdev;
933a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	char addr[6];
934a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
935a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	pdev = ether->pdev;
936a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
937a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	addr[0] = 0x00;
938a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	addr[1] = 0x02;
939a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	addr[2] = 0xac;
940a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	addr[3] = 0x55;
941a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	addr[4] = 0x88;
942a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	addr[5] = 0xa8;
943a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
944a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (is_valid_ether_addr(addr))
945a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		memcpy(dev->dev_addr, &addr, 0x06);
946a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	else
947a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "invalid mac address\n");
948a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
949a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
950a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int w90p910_ether_setup(struct net_device *dev)
951a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
952a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
953a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
954a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether_setup(dev);
955a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	dev->netdev_ops = &w90p910_ether_netdev_ops;
956a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	dev->ethtool_ops = &w90p910_ether_ethtool_ops;
957a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
958a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	dev->tx_queue_len = 16;
959a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	dev->dma = 0x0;
960a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	dev->watchdog_timeo = TX_TIMEOUT;
961a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
962a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	get_mac_address(dev);
963a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
964a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->cur_tx = 0x0;
965a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->cur_rx = 0x0;
966a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->finish_tx = 0x0;
967a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->linkflag = 0x0;
968a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->mii.phy_id = 0x01;
969a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->mii.phy_id_mask = 0x1f;
970a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->mii.reg_num_mask = 0x1f;
971a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->mii.dev = dev;
972a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->mii.mdio_read = w90p910_mdio_read;
973a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->mii.mdio_write = w90p910_mdio_write;
974a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
975a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	setup_timer(&ether->check_timer, w90p910_check_link,
976a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun						(unsigned long)dev);
977a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
978a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return 0;
979a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
980a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
981a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int __devinit w90p910_ether_probe(struct platform_device *pdev)
982a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
983a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether;
984a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct net_device *dev;
985a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	int error;
986a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
987a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	dev = alloc_etherdev(sizeof(struct w90p910_ether));
988a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (!dev)
989a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		return -ENOMEM;
990a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
9911e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	ether = netdev_priv(dev);
9921e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
9931e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	ether->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
9941e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	if (ether->res == NULL) {
995a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "failed to get I/O memory\n");
996a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		error = -ENXIO;
997a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		goto failed_free;
998a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
999a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
10001e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	if (!request_mem_region(ether->res->start,
10011e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun				resource_size(ether->res), pdev->name)) {
1002a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "failed to request I/O memory\n");
1003a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		error = -EBUSY;
1004a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		goto failed_free;
1005a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
1006a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
10071e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	ether->reg = ioremap(ether->res->start, resource_size(ether->res));
1008a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (ether->reg == NULL) {
1009a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "failed to remap I/O memory\n");
1010a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		error = -ENXIO;
1011a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		goto failed_free_mem;
1012a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
1013a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1014a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->txirq = platform_get_irq(pdev, 0);
1015a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (ether->txirq < 0) {
1016a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "failed to get ether tx irq\n");
1017a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		error = -ENXIO;
1018a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		goto failed_free_io;
1019a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
1020a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1021a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->rxirq = platform_get_irq(pdev, 1);
1022a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (ether->rxirq < 0) {
1023a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "failed to get ether rx irq\n");
1024a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		error = -ENXIO;
1025a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		goto failed_free_txirq;
1026a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
1027a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1028a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	platform_set_drvdata(pdev, dev);
1029a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1030a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->clk = clk_get(&pdev->dev, NULL);
1031a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (IS_ERR(ether->clk)) {
1032a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "failed to get ether clock\n");
1033a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		error = PTR_ERR(ether->clk);
1034a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		goto failed_free_rxirq;
1035a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
1036a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1037a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->rmiiclk = clk_get(&pdev->dev, "RMII");
1038a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (IS_ERR(ether->rmiiclk)) {
1039a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "failed to get ether clock\n");
1040a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		error = PTR_ERR(ether->rmiiclk);
1041a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		goto failed_put_clk;
1042a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
1043a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1044a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	ether->pdev = pdev;
1045a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1046a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	w90p910_ether_setup(dev);
1047a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1048a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	error = register_netdev(dev);
1049a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	if (error != 0) {
1050a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		dev_err(&pdev->dev, "Regiter EMC w90p910 FAILED\n");
1051a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		error = -ENODEV;
1052a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		goto failed_put_rmiiclk;
1053a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	}
1054a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1055a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return 0;
1056a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_put_rmiiclk:
1057a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	clk_put(ether->rmiiclk);
1058a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_put_clk:
1059a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	clk_put(ether->clk);
1060a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free_rxirq:
1061a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	free_irq(ether->rxirq, pdev);
1062a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	platform_set_drvdata(pdev, NULL);
1063a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free_txirq:
1064a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	free_irq(ether->txirq, pdev);
1065a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free_io:
1066a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	iounmap(ether->reg);
1067a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free_mem:
10681e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	release_mem_region(ether->res->start, resource_size(ether->res));
1069a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunfailed_free:
1070a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	free_netdev(dev);
1071a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return error;
1072a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
1073a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1074a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic int __devexit w90p910_ether_remove(struct platform_device *pdev)
1075a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun{
1076a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct net_device *dev = platform_get_drvdata(pdev);
1077a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	struct w90p910_ether *ether = netdev_priv(dev);
1078a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1079a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	unregister_netdev(dev);
10801e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
1081a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	clk_put(ether->rmiiclk);
1082a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	clk_put(ether->clk);
10831e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
10841e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	iounmap(ether->reg);
10851e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	release_mem_region(ether->res->start, resource_size(ether->res));
10861e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
10871e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	free_irq(ether->txirq, dev);
10881e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun	free_irq(ether->rxirq, dev);
10891e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
1090a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	del_timer_sync(&ether->check_timer);
1091a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	platform_set_drvdata(pdev, NULL);
10921e5053b7635c6a985a7cd8108e538883d961de2aWan ZongShun
1093a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	free_netdev(dev);
1094a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	return 0;
1095a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun}
1096a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1097a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunstatic struct platform_driver w90p910_ether_driver = {
1098a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.probe		= w90p910_ether_probe,
1099a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.remove		= __devexit_p(w90p910_ether_remove),
1100a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	.driver		= {
1101456d8991a795ff5e44dbc1c2a7f8d5b4ed675866Wan ZongShun		.name	= "nuc900-emc",
1102a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun		.owner	= THIS_MODULE,
1103a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun	},
1104a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun};
1105a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1106db62f684deeb291ab2533b99843d5df9a36b1f19Axel Linmodule_platform_driver(w90p910_ether_driver);
1107a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1108a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunMODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>");
1109a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunMODULE_DESCRIPTION("w90p910 MAC driver!");
1110a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShunMODULE_LICENSE("GPL");
1111456d8991a795ff5e44dbc1c2a7f8d5b4ed675866Wan ZongShunMODULE_ALIAS("platform:nuc900-emc");
1112a50a97d415d839e6db9df288ff0205528e52c03eWan ZongShun
1113