1e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/*
22fb9d6f5a39d7753d2d2cc286079a94e92440bcdMike Frysinger * Blackfin On-Chip MAC Driver
3e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu *
402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang * Copyright 2004-2010 Analog Devices Inc.
5e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu *
62fb9d6f5a39d7753d2d2cc286079a94e92440bcdMike Frysinger * Enter bugs at http://blackfin.uclinux.org/
7e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu *
82fb9d6f5a39d7753d2d2cc286079a94e92440bcdMike Frysinger * Licensed under the GPL-2 or later.
9e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu */
10e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
11c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger#define DRV_VERSION	"1.1"
12c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger#define DRV_DESC	"Blackfin on-chip Ethernet MAC driver"
13c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger
14c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger
16e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/init.h>
17e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/module.h>
18e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/kernel.h>
19e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/sched.h>
20e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/slab.h>
21e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/delay.h>
22e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/timer.h>
23e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/errno.h>
24e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/irq.h>
25e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/io.h>
26e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/ioport.h>
27e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/crc32.h>
28e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/device.h>
29e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/spinlock.h>
30e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/mii.h>
31e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/netdevice.h>
32e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/etherdevice.h>
33679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu#include <linux/ethtool.h>
34e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/skbuff.h>
35e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/platform_device.h>
36e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
37e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <asm/dma.h>
38e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <linux/dma-mapping.h>
39e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
40fe92afedee23e1d91f0133360a24d2bf48270739Barry Song#include <asm/div64.h>
4198f672ca9978c6e5997dbe905c91a73593148a7eMike Frysinger#include <asm/dpmc.h>
42e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <asm/blackfin.h>
43e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <asm/cacheflush.h>
44e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include <asm/portmux.h>
453dcc1e7f9fd48f20beefd41a684cd471a96565c5David Howells#include <mach/pll.h>
46e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
47e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#include "bfin_mac.h"
48e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
49c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike FrysingerMODULE_AUTHOR("Bryan Wu, Luke Yang");
50e190d6b140079c104ba57e5130a9b4ebea618e92Bryan WuMODULE_LICENSE("GPL");
51e190d6b140079c104ba57e5130a9b4ebea618e92Bryan WuMODULE_DESCRIPTION(DRV_DESC);
5272abb46101fb5c47a9592914adb221b430ff26bdKay SieversMODULE_ALIAS("platform:bfin_mac");
53e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
54e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#if defined(CONFIG_BFIN_MAC_USE_L1)
55118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang# define bfin_mac_alloc(dma_handle, size, num)  l1_data_sram_zalloc(size*num)
56118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang# define bfin_mac_free(dma_handle, ptr, num)    l1_data_sram_free(ptr)
57e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#else
58118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang# define bfin_mac_alloc(dma_handle, size, num) \
59118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang	dma_alloc_coherent(NULL, size*num, dma_handle, GFP_KERNEL)
60118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang# define bfin_mac_free(dma_handle, ptr, num) \
61118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang	dma_free_coherent(NULL, sizeof(*ptr)*num, ptr, dma_handle)
62e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#endif
63e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
64e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#define PKT_BUF_SZ 1580
65e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
66e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#define MAX_TIMEOUT_CNT	500
67e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
68e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/* pointers to maintain transmit list */
69e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic struct net_dma_desc_tx *tx_list_head;
70e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic struct net_dma_desc_tx *tx_list_tail;
71e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic struct net_dma_desc_rx *rx_list_head;
72e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic struct net_dma_desc_rx *rx_list_tail;
73e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic struct net_dma_desc_rx *current_rx_ptr;
74e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic struct net_dma_desc_tx *current_tx_ptr;
75e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic struct net_dma_desc_tx *tx_desc;
76e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic struct net_dma_desc_rx *rx_desc;
77e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
78e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic void desc_list_free(void)
79e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
80e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	struct net_dma_desc_rx *r;
81e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	struct net_dma_desc_tx *t;
82e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	int i;
83e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#if !defined(CONFIG_BFIN_MAC_USE_L1)
84e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	dma_addr_t dma_handle = 0;
85e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#endif
86e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
87e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (tx_desc) {
88e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		t = tx_list_head;
89e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
90e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu			if (t) {
91e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				if (t->skb) {
92e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu					dev_kfree_skb(t->skb);
93e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu					t->skb = NULL;
94e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				}
95e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				t = t->next;
96e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu			}
97e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		}
98118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang		bfin_mac_free(dma_handle, tx_desc, CONFIG_BFIN_TX_DESC_NUM);
99e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
100e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
101e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (rx_desc) {
102e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		r = rx_list_head;
103e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
104e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu			if (r) {
105e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				if (r->skb) {
106e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu					dev_kfree_skb(r->skb);
107e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu					r->skb = NULL;
108e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				}
109e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				r = r->next;
110e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu			}
111e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		}
112118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang		bfin_mac_free(dma_handle, rx_desc, CONFIG_BFIN_RX_DESC_NUM);
113e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
114e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
115e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1161ab0d2ec9aeb4489c05158e8a2b00bad89f67e03Pradeep A. Dalvistatic int desc_list_init(struct net_device *dev)
117e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
118e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	int i;
119e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	struct sk_buff *new_skb;
120e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#if !defined(CONFIG_BFIN_MAC_USE_L1)
121e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/*
122e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	 * This dma_handle is useless in Blackfin dma_alloc_coherent().
123e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	 * The real dma handler is the return value of dma_alloc_coherent().
124e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	 */
125e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	dma_addr_t dma_handle;
126e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#endif
127e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
128e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	tx_desc = bfin_mac_alloc(&dma_handle,
129118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang				sizeof(struct net_dma_desc_tx),
130e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				CONFIG_BFIN_TX_DESC_NUM);
131e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (tx_desc == NULL)
132e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		goto init_error;
133e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
134e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	rx_desc = bfin_mac_alloc(&dma_handle,
135118133e6580a0c912cda86109b6468b5ffe73f1cSonic Zhang				sizeof(struct net_dma_desc_rx),
136e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				CONFIG_BFIN_RX_DESC_NUM);
137e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (rx_desc == NULL)
138e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		goto init_error;
139e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
140e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* init tx_list */
141e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	tx_list_head = tx_list_tail = tx_desc;
142e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
143e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	for (i = 0; i < CONFIG_BFIN_TX_DESC_NUM; i++) {
144e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		struct net_dma_desc_tx *t = tx_desc + i;
145e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		struct dma_descriptor *a = &(t->desc_a);
146e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		struct dma_descriptor *b = &(t->desc_b);
147e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
148e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		/*
149e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * disable DMA
150e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * read from memory WNR = 0
151e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * wordsize is 32 bits
152e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * 6 half words is desc size
153e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * large desc flow
154e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 */
155e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		a->config = WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
156e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		a->start_addr = (unsigned long)t->packet;
157e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		a->x_count = 0;
158e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		a->next_dma_desc = b;
159e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
160e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		/*
161e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * enabled DMA
162e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * write to memory WNR = 1
163e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * wordsize is 32 bits
164e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * disable interrupt
165e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * 6 half words is desc size
166e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * large desc flow
167e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 */
168e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		b->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
169e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		b->start_addr = (unsigned long)(&(t->status));
170e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		b->x_count = 0;
171e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
172e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		t->skb = NULL;
173e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		tx_list_tail->desc_b.next_dma_desc = a;
174e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		tx_list_tail->next = t;
175e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		tx_list_tail = t;
176e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
177e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	tx_list_tail->next = tx_list_head;	/* tx_list is a circle */
178e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	tx_list_tail->desc_b.next_dma_desc = &(tx_list_head->desc_a);
179e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	current_tx_ptr = tx_list_head;
180e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
181e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* init rx_list */
182e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	rx_list_head = rx_list_tail = rx_desc;
183e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
184e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	for (i = 0; i < CONFIG_BFIN_RX_DESC_NUM; i++) {
185e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		struct net_dma_desc_rx *r = rx_desc + i;
186e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		struct dma_descriptor *a = &(r->desc_a);
187e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		struct dma_descriptor *b = &(r->desc_b);
188e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
189e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		/* allocate a new skb for next time receive */
1901ab0d2ec9aeb4489c05158e8a2b00bad89f67e03Pradeep A. Dalvi		new_skb = netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN);
191e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		if (!new_skb) {
192c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger			pr_notice("init: low on mem - packet dropped\n");
193e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu			goto init_error;
194e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		}
195015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		skb_reserve(new_skb, NET_IP_ALIGN);
196f6e1e4f3e511589dd0c47d42b870501659e7195fSonic Zhang		/* Invidate the data cache of skb->data range when it is write back
197f6e1e4f3e511589dd0c47d42b870501659e7195fSonic Zhang		 * cache. It will prevent overwritting the new data from DMA
198f6e1e4f3e511589dd0c47d42b870501659e7195fSonic Zhang		 */
199f6e1e4f3e511589dd0c47d42b870501659e7195fSonic Zhang		blackfin_dcache_invalidate_range((unsigned long)new_skb->head,
200f6e1e4f3e511589dd0c47d42b870501659e7195fSonic Zhang					 (unsigned long)new_skb->end);
201e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		r->skb = new_skb;
202e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
203e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		/*
204e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * enabled DMA
205e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * write to memory WNR = 1
206e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * wordsize is 32 bits
207e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * disable interrupt
208e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * 6 half words is desc size
209e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * large desc flow
210e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 */
211e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		a->config = DMAEN | WNR | WDSIZE_32 | NDSIZE_6 | DMAFLOW_LARGE;
212e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		/* since RXDWA is enabled */
213e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		a->start_addr = (unsigned long)new_skb->data - 2;
214e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		a->x_count = 0;
215e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		a->next_dma_desc = b;
216e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
217e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		/*
218e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * enabled DMA
219e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * write to memory WNR = 1
220e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * wordsize is 32 bits
221e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * enable interrupt
222e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * 6 half words is desc size
223e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 * large desc flow
224e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		 */
225e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		b->config = DMAEN | WNR | WDSIZE_32 | DI_EN |
226e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				NDSIZE_6 | DMAFLOW_LARGE;
227e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		b->start_addr = (unsigned long)(&(r->status));
228e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		b->x_count = 0;
229e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
230e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		rx_list_tail->desc_b.next_dma_desc = a;
231e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		rx_list_tail->next = r;
232e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		rx_list_tail = r;
233e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
234e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	rx_list_tail->next = rx_list_head;	/* rx_list is a circle */
235e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	rx_list_tail->desc_b.next_dma_desc = &(rx_list_head->desc_a);
236e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	current_rx_ptr = rx_list_head;
237e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
238e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	return 0;
239e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
240e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wuinit_error:
241e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	desc_list_free();
242c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger	pr_err("kmalloc failed\n");
243e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	return -ENOMEM;
244e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
245e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
246e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
247e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/*---PHY CONTROL AND CONFIGURATION-----------------------------------------*/
248e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
2494ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu/*
2504ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu * MII operations
2514ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu */
252e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/* Wait until the previous MDC/MDIO transaction has completed */
2532bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysingerstatic int bfin_mdio_poll(void)
254e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
255e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	int timeout_cnt = MAX_TIMEOUT_CNT;
256e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
257e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* poll the STABUSY bit */
258e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	while ((bfin_read_EMAC_STAADD()) & STABUSY) {
2596db9e4617e9bdf9d31fbea165b10cb95318adf8cBryan Wu		udelay(1);
260e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		if (timeout_cnt-- < 0) {
261c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger			pr_err("wait MDC/MDIO transaction to complete timeout\n");
2622bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger			return -ETIMEDOUT;
263e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		}
264e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
2652bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger
2662bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	return 0;
267e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
268e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
269e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/* Read an off-chip register in a PHY through the MDC/MDIO port */
2700ed0563e14dcb9986241d30f08ecd33f9bcc3572Adrian Bunkstatic int bfin_mdiobus_read(struct mii_bus *bus, int phy_addr, int regnum)
271e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
2722bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	int ret;
2732bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger
2742bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	ret = bfin_mdio_poll();
2752bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	if (ret)
2762bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger		return ret;
2774ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
278e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* read mode */
2794ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
2804ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu				SET_REGAD((u16) regnum) |
281e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				STABUSY);
282e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
2832bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	ret = bfin_mdio_poll();
2842bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	if (ret)
2852bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger		return ret;
2864ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
2874ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	return (int) bfin_read_EMAC_STADAT();
288e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
289e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
290e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/* Write an off-chip register in a PHY through the MDC/MDIO port */
2910ed0563e14dcb9986241d30f08ecd33f9bcc3572Adrian Bunkstatic int bfin_mdiobus_write(struct mii_bus *bus, int phy_addr, int regnum,
2920ed0563e14dcb9986241d30f08ecd33f9bcc3572Adrian Bunk			      u16 value)
293e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
2942bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	int ret;
2952bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger
2962bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	ret = bfin_mdio_poll();
2972bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	if (ret)
2982bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger		return ret;
2994ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
3004ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	bfin_write_EMAC_STADAT((u32) value);
301e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
302e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* write mode */
3034ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	bfin_write_EMAC_STAADD(SET_PHYAD((u16) phy_addr) |
3044ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu				SET_REGAD((u16) regnum) |
305e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				STAOP |
306e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				STABUSY);
307e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3082bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	return bfin_mdio_poll();
309e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
310e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3110ed0563e14dcb9986241d30f08ecd33f9bcc3572Adrian Bunkstatic int bfin_mdiobus_reset(struct mii_bus *bus)
312e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
3134ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	return 0;
314e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
315e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3167ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic void bfin_mac_adjust_link(struct net_device *dev)
317e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
3187ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	struct bfin_mac_local *lp = netdev_priv(dev);
3194ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	struct phy_device *phydev = lp->phydev;
3204ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	unsigned long flags;
3214ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	int new_state = 0;
3224ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
3234ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	spin_lock_irqsave(&lp->lock, flags);
3244ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	if (phydev->link) {
3254ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		/* Now we make sure that we can be in full duplex mode.
3264ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		 * If not, we operate in half-duplex mode. */
3274ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		if (phydev->duplex != lp->old_duplex) {
3284ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			u32 opmode = bfin_read_EMAC_OPMODE();
3294ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			new_state = 1;
3304ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
3314ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			if (phydev->duplex)
3324ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu				opmode |= FDMODE;
3334ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			else
3344ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu				opmode &= ~(FDMODE);
3354ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
3364ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			bfin_write_EMAC_OPMODE(opmode);
3374ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			lp->old_duplex = phydev->duplex;
3384ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		}
339e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3404ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		if (phydev->speed != lp->old_speed) {
34102460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang			if (phydev->interface == PHY_INTERFACE_MODE_RMII) {
34202460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang				u32 opmode = bfin_read_EMAC_OPMODE();
34302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang				switch (phydev->speed) {
34402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang				case 10:
34502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang					opmode |= RMII_10;
34602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang					break;
34702460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang				case 100:
34802460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang					opmode &= ~RMII_10;
34902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang					break;
35002460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang				default:
351c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger					netdev_warn(dev,
352c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger						"Ack! Speed (%d) is not 10/100!\n",
353c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger						phydev->speed);
35402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang					break;
35502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang				}
35602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang				bfin_write_EMAC_OPMODE(opmode);
3574ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			}
358e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3594ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			new_state = 1;
3604ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			lp->old_speed = phydev->speed;
3614ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		}
362e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3634ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		if (!lp->old_link) {
3644ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			new_state = 1;
3654ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			lp->old_link = 1;
3664ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		}
3674ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	} else if (lp->old_link) {
3684ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		new_state = 1;
3694ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		lp->old_link = 0;
3704ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		lp->old_speed = 0;
3714ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		lp->old_duplex = -1;
372e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
373e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3744ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	if (new_state) {
3754ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		u32 opmode = bfin_read_EMAC_OPMODE();
3764ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		phy_print_status(phydev);
3774ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		pr_debug("EMAC_OPMODE = 0x%08x\n", opmode);
378e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
3794ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
3804ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	spin_unlock_irqrestore(&lp->lock, flags);
381e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
382e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3837cc8f38188133e0c278b9f207d63c2c2b4d98236Bryan Wu/* MDC  = 2.5 MHz */
3847cc8f38188133e0c278b9f207d63c2c2b4d98236Bryan Wu#define MDC_CLK 2500000
3857cc8f38188133e0c278b9f207d63c2c2b4d98236Bryan Wu
38602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhangstatic int mii_probe(struct net_device *dev, int phy_mode)
387e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
3887ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	struct bfin_mac_local *lp = netdev_priv(dev);
3894ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	struct phy_device *phydev = NULL;
3904ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	unsigned short sysctl;
3914ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	int i;
3927cc8f38188133e0c278b9f207d63c2c2b4d98236Bryan Wu	u32 sclk, mdc_div;
393e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3944ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	/* Enable PHY output early */
39598f672ca9978c6e5997dbe905c91a73593148a7eMike Frysinger	if (!(bfin_read_VR_CTL() & CLKBUFOE))
39698f672ca9978c6e5997dbe905c91a73593148a7eMike Frysinger		bfin_write_VR_CTL(bfin_read_VR_CTL() | CLKBUFOE);
397e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
3987cc8f38188133e0c278b9f207d63c2c2b4d98236Bryan Wu	sclk = get_sclk();
3997cc8f38188133e0c278b9f207d63c2c2b4d98236Bryan Wu	mdc_div = ((sclk / MDC_CLK) / 2) - 1;
4007cc8f38188133e0c278b9f207d63c2c2b4d98236Bryan Wu
4014ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	sysctl = bfin_read_EMAC_SYSCTL();
4029dc7f30e3bac329998a2a9bb814bd0abc7cb58e2Bryan Wu	sysctl = (sysctl & ~MDCDIV) | SET_MDCDIV(mdc_div);
403e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_EMAC_SYSCTL(sysctl);
404e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
40502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	/* search for connected PHY device */
40602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	for (i = 0; i < PHY_MAX_ADDR; ++i) {
407298cf9beb9679522de995e249eccbd82f7c51999Lennert Buytenhek		struct phy_device *const tmp_phydev = lp->mii_bus->phy_map[i];
408e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
4094ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		if (!tmp_phydev)
4104ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			continue; /* no PHY here... */
411e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
4124ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		phydev = tmp_phydev;
4134ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		break; /* found it */
4144ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	}
4154ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
4164ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	/* now we are supposed to have a proper phydev, to attach to... */
4174ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	if (!phydev) {
418c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger		netdev_err(dev, "no phy device found\n");
4194ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		return -ENODEV;
420e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
421e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
42202460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	if (phy_mode != PHY_INTERFACE_MODE_RMII &&
42302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		phy_mode != PHY_INTERFACE_MODE_MII) {
424c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger		netdev_err(dev, "invalid phy interface mode\n");
42502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		return -EINVAL;
42602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	}
42702460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
428c23135573f37facd18edb2e8e8512c67928c54acKay Sievers	phydev = phy_connect(dev, dev_name(&phydev->dev), &bfin_mac_adjust_link,
42902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang			0, phy_mode);
430e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
4314ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	if (IS_ERR(phydev)) {
432c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger		netdev_err(dev, "could not attach PHY\n");
4334ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu		return PTR_ERR(phydev);
4344ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	}
4354ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
4364ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	/* mask with MAC supported features */
4374ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	phydev->supported &= (SUPPORTED_10baseT_Half
4384ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			      | SUPPORTED_10baseT_Full
4394ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			      | SUPPORTED_100baseT_Half
4404ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			      | SUPPORTED_100baseT_Full
4414ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			      | SUPPORTED_Autoneg
4424ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			      | SUPPORTED_Pause | SUPPORTED_Asym_Pause
4434ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			      | SUPPORTED_MII
4444ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu			      | SUPPORTED_TP);
4454ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
4464ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	phydev->advertising = phydev->supported;
4474ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
4484ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	lp->old_link = 0;
4494ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	lp->old_speed = 0;
4504ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	lp->old_duplex = -1;
4514ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	lp->phydev = phydev;
4524ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
453c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger	pr_info("attached PHY driver [%s] "
454c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger	        "(mii_bus:phy_addr=%s, irq=%d, mdc_clk=%dHz(mdc_div=%d)@sclk=%dMHz)\n",
455c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger	        phydev->drv->name, dev_name(&phydev->dev), phydev->irq,
456c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger	        MDC_CLK, mdc_div, sclk/1000000);
4574ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
4584ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	return 0;
4594ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu}
4604ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
461679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu/*
462679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu * Ethtool support
463679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu */
464679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
46553fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich/*
46653fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich * interrupt routine for magic packet wakeup
46753fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich */
46853fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerichstatic irqreturn_t bfin_mac_wake_interrupt(int irq, void *dev_id)
46953fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich{
47053fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	return IRQ_HANDLED;
47153fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich}
47253fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
473679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wustatic int
474679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wubfin_mac_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd)
475679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu{
476679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	struct bfin_mac_local *lp = netdev_priv(dev);
477679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
478679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	if (lp->phydev)
479679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu		return phy_ethtool_gset(lp->phydev, cmd);
480679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
481679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	return -EINVAL;
482679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu}
483679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
484679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wustatic int
485679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wubfin_mac_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd)
486679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu{
487679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	struct bfin_mac_local *lp = netdev_priv(dev);
488679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
489679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	if (!capable(CAP_NET_ADMIN))
490679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu		return -EPERM;
491679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
492679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	if (lp->phydev)
493679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu		return phy_ethtool_sset(lp->phydev, cmd);
494679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
495679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	return -EINVAL;
496679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu}
497679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
498679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wustatic void bfin_mac_ethtool_getdrvinfo(struct net_device *dev,
499679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu					struct ethtool_drvinfo *info)
500679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu{
501c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger	strcpy(info->driver, KBUILD_MODNAME);
502679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	strcpy(info->version, DRV_VERSION);
503679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	strcpy(info->fw_version, "N/A");
504c23135573f37facd18edb2e8e8512c67928c54acKay Sievers	strcpy(info->bus_info, dev_name(&dev->dev));
505679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu}
506679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
50753fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerichstatic void bfin_mac_ethtool_getwol(struct net_device *dev,
50853fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	struct ethtool_wolinfo *wolinfo)
50953fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich{
51053fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	struct bfin_mac_local *lp = netdev_priv(dev);
51153fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
51253fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	wolinfo->supported = WAKE_MAGIC;
51353fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	wolinfo->wolopts = lp->wol;
51453fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich}
51553fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
51653fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerichstatic int bfin_mac_ethtool_setwol(struct net_device *dev,
51753fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	struct ethtool_wolinfo *wolinfo)
51853fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich{
51953fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	struct bfin_mac_local *lp = netdev_priv(dev);
52053fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	int rc;
52153fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
52253fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	if (wolinfo->wolopts & (WAKE_MAGICSECURE |
52353fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich				WAKE_UCAST |
52453fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich				WAKE_MCAST |
52553fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich				WAKE_BCAST |
52653fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich				WAKE_ARP))
52753fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		return -EOPNOTSUPP;
52853fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
52953fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	lp->wol = wolinfo->wolopts;
53053fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
53153fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	if (lp->wol && !lp->irq_wake_requested) {
53253fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		/* register wake irq handler */
53353fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		rc = request_irq(IRQ_MAC_WAKEDET, bfin_mac_wake_interrupt,
53453fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich				 IRQF_DISABLED, "EMAC_WAKE", dev);
53553fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		if (rc)
53653fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich			return rc;
53753fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		lp->irq_wake_requested = true;
53853fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	}
53953fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
54053fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	if (!lp->wol && lp->irq_wake_requested) {
54153fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		free_irq(IRQ_MAC_WAKEDET, dev);
54253fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		lp->irq_wake_requested = false;
54353fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	}
54453fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
54553fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	/* Make sure the PHY driver doesn't suspend */
54653fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	device_init_wakeup(&dev->dev, lp->wol);
54753fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
54853fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	return 0;
54953fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich}
55053fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich
5510fc0b732eaa38beb93a6fb62f77c7bd9622c76ecStephen Hemmingerstatic const struct ethtool_ops bfin_mac_ethtool_ops = {
552679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	.get_settings = bfin_mac_ethtool_getsettings,
553679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	.set_settings = bfin_mac_ethtool_setsettings,
554679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	.get_link = ethtool_op_get_link,
555679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	.get_drvinfo = bfin_mac_ethtool_getdrvinfo,
55653fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	.get_wol = bfin_mac_ethtool_getwol,
55753fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	.set_wol = bfin_mac_ethtool_setwol,
558679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu};
559679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu
5604ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu/**************************************************************************/
5615ca1bb5aceb0bccf532ffc21588585a925cdee20Mike Frysingerstatic void setup_system_regs(struct net_device *dev)
5624ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu{
56302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	struct bfin_mac_local *lp = netdev_priv(dev);
56402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	int i;
5654ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	unsigned short sysctl;
5664ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
5674ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	/*
5684ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	 * Odd word alignment for Receive Frame DMA word
5694ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	 * Configure checksum support and rcve frame word alignment
5704ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	 */
5714ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	sysctl = bfin_read_EMAC_SYSCTL();
57202460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	/*
57302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	 * check if interrupt is requested for any PHY,
57402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	 * enable PHY interrupt only if needed
57502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	 */
57602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	for (i = 0; i < PHY_MAX_ADDR; ++i)
57702460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		if (lp->mii_bus->irq[i] != PHY_POLL)
57802460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang			break;
57902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	if (i < PHY_MAX_ADDR)
58002460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		sysctl |= PHYIE;
581812a9de71512e5da6f3177f7249a2448b6a4322eSonic Zhang	sysctl |= RXDWA;
5824ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu#if defined(BFIN_MAC_CSUM_OFFLOAD)
583812a9de71512e5da6f3177f7249a2448b6a4322eSonic Zhang	sysctl |= RXCKS;
5844ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu#else
585812a9de71512e5da6f3177f7249a2448b6a4322eSonic Zhang	sysctl &= ~RXCKS;
5864ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu#endif
5874ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	bfin_write_EMAC_SYSCTL(sysctl);
588e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
589e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_EMAC_MMC_CTL(RSTC | CROLL);
590e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
591c599bd6b9ac8926b03e6bf332a8c14ae2ffb43a3Mike Frysinger	/* Set vlan regs to let 1522 bytes long packets pass through */
592c599bd6b9ac8926b03e6bf332a8c14ae2ffb43a3Mike Frysinger	bfin_write_EMAC_VLAN1(lp->vlan1_mask);
593c599bd6b9ac8926b03e6bf332a8c14ae2ffb43a3Mike Frysinger	bfin_write_EMAC_VLAN2(lp->vlan2_mask);
594c599bd6b9ac8926b03e6bf332a8c14ae2ffb43a3Mike Frysinger
595e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Initialize the TX DMA channel registers */
596e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA2_X_COUNT(0);
597e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA2_X_MODIFY(4);
598e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA2_Y_COUNT(0);
599e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA2_Y_MODIFY(0);
600e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
601e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Initialize the RX DMA channel registers */
602e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA1_X_COUNT(0);
603e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA1_X_MODIFY(4);
604e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA1_Y_COUNT(0);
605e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA1_Y_MODIFY(0);
606e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
607e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
60873f83182862a2c9113421720997c75ee939902f8Alex Landaustatic void setup_mac_addr(u8 *mac_addr)
609e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
610e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	u32 addr_low = le32_to_cpu(*(__le32 *) & mac_addr[0]);
611e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	u16 addr_hi = le16_to_cpu(*(__le16 *) & mac_addr[4]);
612e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
613e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* this depends on a little-endian machine */
614e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_EMAC_ADDRLO(addr_low);
615e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_EMAC_ADDRHI(addr_hi);
616e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
617e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
6187ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic int bfin_mac_set_mac_address(struct net_device *dev, void *p)
61973f83182862a2c9113421720997c75ee939902f8Alex Landau{
62073f83182862a2c9113421720997c75ee939902f8Alex Landau	struct sockaddr *addr = p;
62173f83182862a2c9113421720997c75ee939902f8Alex Landau	if (netif_running(dev))
62273f83182862a2c9113421720997c75ee939902f8Alex Landau		return -EBUSY;
62373f83182862a2c9113421720997c75ee939902f8Alex Landau	memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
6245055d2f236e1495d68c468eeb684fd5789673f1dDanny Kukawka	dev->addr_assign_type &= ~NET_ADDR_RANDOM;
62573f83182862a2c9113421720997c75ee939902f8Alex Landau	setup_mac_addr(dev->dev_addr);
62673f83182862a2c9113421720997c75ee939902f8Alex Landau	return 0;
62773f83182862a2c9113421720997c75ee939902f8Alex Landau}
62873f83182862a2c9113421720997c75ee939902f8Alex Landau
629fe92afedee23e1d91f0133360a24d2bf48270739Barry Song#ifdef CONFIG_BFIN_MAC_USE_HWSTAMP
630fe92afedee23e1d91f0133360a24d2bf48270739Barry Song#define bfin_mac_hwtstamp_is_none(cfg) ((cfg) == HWTSTAMP_FILTER_NONE)
631fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
632fe92afedee23e1d91f0133360a24d2bf48270739Barry Songstatic int bfin_mac_hwtstamp_ioctl(struct net_device *netdev,
633fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		struct ifreq *ifr, int cmd)
634fe92afedee23e1d91f0133360a24d2bf48270739Barry Song{
635fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	struct hwtstamp_config config;
636fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	struct bfin_mac_local *lp = netdev_priv(netdev);
637fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	u16 ptpctl;
638fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	u32 ptpfv1, ptpfv2, ptpfv3, ptpfoff;
639fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
640fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	if (copy_from_user(&config, ifr->ifr_data, sizeof(config)))
641fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		return -EFAULT;
642fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
643fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	pr_debug("%s config flag:0x%x, tx_type:0x%x, rx_filter:0x%x\n",
644fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			__func__, config.flags, config.tx_type, config.rx_filter);
645fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
646fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	/* reserved for future extensions */
647fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	if (config.flags)
648fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		return -EINVAL;
649fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
650fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	if ((config.tx_type != HWTSTAMP_TX_OFF) &&
651fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			(config.tx_type != HWTSTAMP_TX_ON))
652fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		return -ERANGE;
653fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
654fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	ptpctl = bfin_read_EMAC_PTP_CTL();
655fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
656fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	switch (config.rx_filter) {
657fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_NONE:
658fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
659fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Dont allow any timestamping
660fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
661fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv3 = 0xFFFFFFFF;
662fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV3(ptpfv3);
663fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		break;
664fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
665fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
666fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
667fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
668fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Clear the five comparison mask bits (bits[12:8]) in EMAC_PTP_CTL)
669fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * to enable all the field matches.
670fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
671fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpctl &= ~0x1F00;
672fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_CTL(ptpctl);
673fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
674fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Keep the default values of the EMAC_PTP_FOFF register.
675fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
676fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfoff = 0x4A24170C;
677fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FOFF(ptpfoff);
678fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
679fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Keep the default values of the EMAC_PTP_FV1 and EMAC_PTP_FV2
680fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * registers.
681fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
682fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv1 = 0x11040800;
683fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV1(ptpfv1);
684fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv2 = 0x0140013F;
685fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV2(ptpfv2);
686fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
687fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * The default value (0xFFFC) allows the timestamping of both
688fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * received Sync messages and Delay_Req messages.
689fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
690fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv3 = 0xFFFFFFFC;
691fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV3(ptpfv3);
692fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
693fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		config.rx_filter = HWTSTAMP_FILTER_PTP_V1_L4_EVENT;
694fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		break;
695fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
696fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
697fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
698fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/* Clear all five comparison mask bits (bits[12:8]) in the
699fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * EMAC_PTP_CTL register to enable all the field matches.
700fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
701fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpctl &= ~0x1F00;
702fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_CTL(ptpctl);
703fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
704fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Keep the default values of the EMAC_PTP_FOFF register, except set
705fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * the PTPCOF field to 0x2A.
706fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
707fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfoff = 0x2A24170C;
708fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FOFF(ptpfoff);
709fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
710fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Keep the default values of the EMAC_PTP_FV1 and EMAC_PTP_FV2
711fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * registers.
712fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
713fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv1 = 0x11040800;
714fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV1(ptpfv1);
715fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv2 = 0x0140013F;
716fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV2(ptpfv2);
717fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
718fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * To allow the timestamping of Pdelay_Req and Pdelay_Resp, set
719fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * the value to 0xFFF0.
720fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
721fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv3 = 0xFFFFFFF0;
722fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV3(ptpfv3);
723fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
724fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L4_EVENT;
725fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		break;
726fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
727fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
728fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
729fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
730fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Clear bits 8 and 12 of the EMAC_PTP_CTL register to enable only the
731fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * EFTM and PTPCM field comparison.
732fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
733fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpctl &= ~0x1100;
734fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_CTL(ptpctl);
735fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
736fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Keep the default values of all the fields of the EMAC_PTP_FOFF
737fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * register, except set the PTPCOF field to 0x0E.
738fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
739fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfoff = 0x0E24170C;
740fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FOFF(ptpfoff);
741fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
742fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Program bits [15:0] of the EMAC_PTP_FV1 register to 0x88F7, which
743fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * corresponds to PTP messages on the MAC layer.
744fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
745fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv1 = 0x110488F7;
746fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV1(ptpfv1);
747fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv2 = 0x0140013F;
748fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV2(ptpfv2);
749fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
750fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * To allow the timestamping of Pdelay_Req and Pdelay_Resp
751fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * messages, set the value to 0xFFF0.
752fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
753fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpfv3 = 0xFFFFFFF0;
754fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_FV3(ptpfv3);
755fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
756fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		config.rx_filter = HWTSTAMP_FILTER_PTP_V2_L2_EVENT;
757fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		break;
758fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	default:
759fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		return -ERANGE;
760fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	}
761fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
762fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	if (config.tx_type == HWTSTAMP_TX_OFF &&
763fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	    bfin_mac_hwtstamp_is_none(config.rx_filter)) {
764fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpctl &= ~PTP_EN;
765fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_CTL(ptpctl);
766fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
767fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		SSYNC();
768fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	} else {
769fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		ptpctl |= PTP_EN;
770fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_CTL(ptpctl);
771fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
772fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
773fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * clear any existing timestamp
774fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
775fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_read_EMAC_PTP_RXSNAPLO();
776fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_read_EMAC_PTP_RXSNAPHI();
777fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
778fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_read_EMAC_PTP_TXSNAPLO();
779fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_read_EMAC_PTP_TXSNAPHI();
780fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
781fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
782fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * Set registers so that rollover occurs soon to test this.
783fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
784fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_TIMELO(0x00000000);
785fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		bfin_write_EMAC_PTP_TIMEHI(0xFF800000);
786fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
787fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		SSYNC();
788fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
789fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		lp->compare.last_update = 0;
790fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		timecounter_init(&lp->clock,
791fe92afedee23e1d91f0133360a24d2bf48270739Barry Song				&lp->cycles,
792fe92afedee23e1d91f0133360a24d2bf48270739Barry Song				ktime_to_ns(ktime_get_real()));
793fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		timecompare_update(&lp->compare, 0);
794fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	}
795fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
796fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->stamp_cfg = config;
797fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ?
798fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		-EFAULT : 0;
799fe92afedee23e1d91f0133360a24d2bf48270739Barry Song}
800fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
801fe92afedee23e1d91f0133360a24d2bf48270739Barry Songstatic void bfin_dump_hwtamp(char *s, ktime_t *hw, ktime_t *ts, struct timecompare *cmp)
802fe92afedee23e1d91f0133360a24d2bf48270739Barry Song{
803fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	ktime_t sys = ktime_get_real();
804fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
805fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	pr_debug("%s %s hardware:%d,%d transform system:%d,%d system:%d,%d, cmp:%lld, %lld\n",
806fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			__func__, s, hw->tv.sec, hw->tv.nsec, ts->tv.sec, ts->tv.nsec, sys.tv.sec,
807fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			sys.tv.nsec, cmp->offset, cmp->skew);
808fe92afedee23e1d91f0133360a24d2bf48270739Barry Song}
809fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
810fe92afedee23e1d91f0133360a24d2bf48270739Barry Songstatic void bfin_tx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
811fe92afedee23e1d91f0133360a24d2bf48270739Barry Song{
812fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	struct bfin_mac_local *lp = netdev_priv(netdev);
813fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
8142244d07bfa2097cb00600da91c715a8aa547917eOliver Hartkopp	if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) {
815fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		int timeout_cnt = MAX_TIMEOUT_CNT;
816fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
817fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/* When doing time stamping, keep the connection to the socket
818fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * a while longer
819fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
8202244d07bfa2097cb00600da91c715a8aa547917eOliver Hartkopp		skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
821fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
822fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
823fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * The timestamping is done at the EMAC module's MII/RMII interface
824fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * when the module sees the Start of Frame of an event message packet. This
825fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * interface is the closest possible place to the physical Ethernet transmission
826fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * medium, providing the best timing accuracy.
827fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
828fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		while ((!(bfin_read_EMAC_PTP_ISTAT() & TXTL)) && (--timeout_cnt))
829fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			udelay(1);
830fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		if (timeout_cnt == 0)
831c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger			netdev_err(netdev, "timestamp the TX packet failed\n");
832fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		else {
833fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			struct skb_shared_hwtstamps shhwtstamps;
834fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			u64 ns;
835fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			u64 regval;
836fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
837fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			regval = bfin_read_EMAC_PTP_TXSNAPLO();
838fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			regval |= (u64)bfin_read_EMAC_PTP_TXSNAPHI() << 32;
839fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			memset(&shhwtstamps, 0, sizeof(shhwtstamps));
840fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			ns = timecounter_cyc2time(&lp->clock,
841fe92afedee23e1d91f0133360a24d2bf48270739Barry Song					regval);
842fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			timecompare_update(&lp->compare, ns);
843fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			shhwtstamps.hwtstamp = ns_to_ktime(ns);
844fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			shhwtstamps.syststamp =
845fe92afedee23e1d91f0133360a24d2bf48270739Barry Song				timecompare_transform(&lp->compare, ns);
846fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			skb_tstamp_tx(skb, &shhwtstamps);
847fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
848fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			bfin_dump_hwtamp("TX", &shhwtstamps.hwtstamp, &shhwtstamps.syststamp, &lp->compare);
849fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		}
850fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	}
851fe92afedee23e1d91f0133360a24d2bf48270739Barry Song}
852fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
853fe92afedee23e1d91f0133360a24d2bf48270739Barry Songstatic void bfin_rx_hwtstamp(struct net_device *netdev, struct sk_buff *skb)
854fe92afedee23e1d91f0133360a24d2bf48270739Barry Song{
855fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	struct bfin_mac_local *lp = netdev_priv(netdev);
856fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	u32 valid;
857fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	u64 regval, ns;
858fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	struct skb_shared_hwtstamps *shhwtstamps;
859fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
860fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	if (bfin_mac_hwtstamp_is_none(lp->stamp_cfg.rx_filter))
861fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		return;
862fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
863fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	valid = bfin_read_EMAC_PTP_ISTAT() & RXEL;
864fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	if (!valid)
865fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		return;
866fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
867fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	shhwtstamps = skb_hwtstamps(skb);
868fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
869fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	regval = bfin_read_EMAC_PTP_RXSNAPLO();
870fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	regval |= (u64)bfin_read_EMAC_PTP_RXSNAPHI() << 32;
871fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	ns = timecounter_cyc2time(&lp->clock, regval);
872fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	timecompare_update(&lp->compare, ns);
873fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	memset(shhwtstamps, 0, sizeof(*shhwtstamps));
874fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	shhwtstamps->hwtstamp = ns_to_ktime(ns);
875fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	shhwtstamps->syststamp = timecompare_transform(&lp->compare, ns);
876fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
877fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	bfin_dump_hwtamp("RX", &shhwtstamps->hwtstamp, &shhwtstamps->syststamp, &lp->compare);
878fe92afedee23e1d91f0133360a24d2bf48270739Barry Song}
879fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
880fe92afedee23e1d91f0133360a24d2bf48270739Barry Song/*
881fe92afedee23e1d91f0133360a24d2bf48270739Barry Song * bfin_read_clock - read raw cycle counter (to be used by time counter)
882fe92afedee23e1d91f0133360a24d2bf48270739Barry Song */
883fe92afedee23e1d91f0133360a24d2bf48270739Barry Songstatic cycle_t bfin_read_clock(const struct cyclecounter *tc)
884fe92afedee23e1d91f0133360a24d2bf48270739Barry Song{
885fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	u64 stamp;
886fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
887fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	stamp =  bfin_read_EMAC_PTP_TIMELO();
888fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	stamp |= (u64)bfin_read_EMAC_PTP_TIMEHI() << 32ULL;
889fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
890fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	return stamp;
891fe92afedee23e1d91f0133360a24d2bf48270739Barry Song}
892fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
893fe92afedee23e1d91f0133360a24d2bf48270739Barry Song#define PTP_CLK 25000000
894fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
895fe92afedee23e1d91f0133360a24d2bf48270739Barry Songstatic void bfin_mac_hwtstamp_init(struct net_device *netdev)
896fe92afedee23e1d91f0133360a24d2bf48270739Barry Song{
897fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	struct bfin_mac_local *lp = netdev_priv(netdev);
898fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	u64 append;
899fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
900fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	/* Initialize hardware timer */
901fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	append = PTP_CLK * (1ULL << 32);
902fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	do_div(append, get_sclk());
903fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	bfin_write_EMAC_PTP_ADDEND((u32)append);
904fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
905fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	memset(&lp->cycles, 0, sizeof(lp->cycles));
906fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->cycles.read = bfin_read_clock;
907fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->cycles.mask = CLOCKSOURCE_MASK(64);
908fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->cycles.mult = 1000000000 / PTP_CLK;
909fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->cycles.shift = 0;
910fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
911fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	/* Synchronize our NIC clock against system wall clock */
912fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	memset(&lp->compare, 0, sizeof(lp->compare));
913fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->compare.source = &lp->clock;
914fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->compare.target = ktime_get_real;
915fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->compare.num_samples = 10;
916fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
917fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	/* Initialize hwstamp config */
918fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->stamp_cfg.rx_filter = HWTSTAMP_FILTER_NONE;
919fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	lp->stamp_cfg.tx_type = HWTSTAMP_TX_OFF;
920fe92afedee23e1d91f0133360a24d2bf48270739Barry Song}
921fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
922fe92afedee23e1d91f0133360a24d2bf48270739Barry Song#else
923fe92afedee23e1d91f0133360a24d2bf48270739Barry Song# define bfin_mac_hwtstamp_is_none(cfg) 0
924fe92afedee23e1d91f0133360a24d2bf48270739Barry Song# define bfin_mac_hwtstamp_init(dev)
925fe92afedee23e1d91f0133360a24d2bf48270739Barry Song# define bfin_mac_hwtstamp_ioctl(dev, ifr, cmd) (-EOPNOTSUPP)
926fe92afedee23e1d91f0133360a24d2bf48270739Barry Song# define bfin_rx_hwtstamp(dev, skb)
927fe92afedee23e1d91f0133360a24d2bf48270739Barry Song# define bfin_tx_hwtstamp(dev, skb)
928fe92afedee23e1d91f0133360a24d2bf48270739Barry Song#endif
929fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
9304fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhangstatic inline void _tx_reclaim_skb(void)
9314fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang{
9324fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	do {
9334fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		tx_list_head->desc_a.config &= ~DMAEN;
9344fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		tx_list_head->status.status_word = 0;
9354fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		if (tx_list_head->skb) {
9364fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			dev_kfree_skb(tx_list_head->skb);
9374fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			tx_list_head->skb = NULL;
9384fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		}
9394fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		tx_list_head = tx_list_head->next;
9404fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
9414fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	} while (tx_list_head->status.status_word != 0);
9424fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang}
9434fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
9444fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhangstatic void tx_reclaim_skb(struct bfin_mac_local *lp)
945e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
946e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	int timeout_cnt = MAX_TIMEOUT_CNT;
947e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
9484fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	if (tx_list_head->status.status_word != 0)
9494fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		_tx_reclaim_skb();
950e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
9514fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	if (current_tx_ptr->next == tx_list_head) {
952e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		while (tx_list_head->status.status_word == 0) {
9534fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			/* slow down polling to avoid too many queue stop. */
954015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich			udelay(10);
9554fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			/* reclaim skb if DMA is not running. */
9564fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			if (!(bfin_read_DMA2_IRQ_STATUS() & DMA_RUN))
9574fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang				break;
9584fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			if (timeout_cnt-- < 0)
959e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				break;
960e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		}
9614fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
9624fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		if (timeout_cnt >= 0)
9634fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			_tx_reclaim_skb();
9644fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		else
9654fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			netif_stop_queue(lp->ndev);
966e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
967e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
9684fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	if (current_tx_ptr->next != tx_list_head &&
9694fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		netif_queue_stopped(lp->ndev))
9704fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		netif_wake_queue(lp->ndev);
9714fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
9724fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	if (tx_list_head != current_tx_ptr) {
9734fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		/* shorten the timer interval if tx queue is stopped */
9744fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		if (netif_queue_stopped(lp->ndev))
9754fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			lp->tx_reclaim_timer.expires =
9764fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang				jiffies + (TX_RECLAIM_JIFFIES >> 4);
9774fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		else
9784fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			lp->tx_reclaim_timer.expires =
9794fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang				jiffies + TX_RECLAIM_JIFFIES;
9804fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
9814fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		mod_timer(&lp->tx_reclaim_timer,
9824fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			lp->tx_reclaim_timer.expires);
9834fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	}
984e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
985e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	return;
9864fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang}
987e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
9884fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhangstatic void tx_reclaim_skb_timeout(unsigned long lp)
9894fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang{
9904fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	tx_reclaim_skb((struct bfin_mac_local *)lp);
991e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
992e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
9937ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic int bfin_mac_hard_start_xmit(struct sk_buff *skb,
994e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				struct net_device *dev)
995e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
9964fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	struct bfin_mac_local *lp = netdev_priv(dev);
997a50c0c05c3bdead1ac405ca8cefd8dc290043933Bryan Wu	u16 *data;
998015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich	u32 data_align = (unsigned long)(skb->data) & 0x3;
999fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
1000e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	current_tx_ptr->skb = skb;
1001e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1002015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich	if (data_align == 0x2) {
1003015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		/* move skb->data to current_tx_ptr payload */
1004015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		data = (u16 *)(skb->data) - 1;
1005fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		*data = (u16)(skb->len);
1006fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/*
1007fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * When transmitting an Ethernet packet, the PTP_TSYNC module requires
1008fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * a DMA_Length_Word field associated with the packet. The lower 12 bits
1009fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * of this field are the length of the packet payload in bytes and the higher
1010fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 * 4 bits are the timestamping enable field.
1011fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		 */
10122244d07bfa2097cb00600da91c715a8aa547917eOliver Hartkopp		if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
1013fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			*data |= 0x1000;
1014fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
1015015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		current_tx_ptr->desc_a.start_addr = (u32)data;
1016015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		/* this is important! */
1017015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		blackfin_dcache_flush_range((u32)data,
1018015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich				(u32)((u8 *)data + skb->len + 4));
1019e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	} else {
1020015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		*((u16 *)(current_tx_ptr->packet)) = (u16)(skb->len);
1021fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		/* enable timestamping for the sent packet */
10222244d07bfa2097cb00600da91c715a8aa547917eOliver Hartkopp		if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)
1023fe92afedee23e1d91f0133360a24d2bf48270739Barry Song			*((u16 *)(current_tx_ptr->packet)) |= 0x1000;
1024015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		memcpy((u8 *)(current_tx_ptr->packet + 2), skb->data,
1025015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich			skb->len);
1026015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		current_tx_ptr->desc_a.start_addr =
1027015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich			(u32)current_tx_ptr->packet;
1028015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich		blackfin_dcache_flush_range(
1029015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich			(u32)current_tx_ptr->packet,
1030015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich			(u32)(current_tx_ptr->packet + skb->len + 2));
1031e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
1032e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1033805a8ab3ce1be83e9a98c21a625ebbb549a2d317Sonic Zhang	/* make sure the internal data buffers in the core are drained
1034805a8ab3ce1be83e9a98c21a625ebbb549a2d317Sonic Zhang	 * so that the DMA descriptors are completely written when the
1035805a8ab3ce1be83e9a98c21a625ebbb549a2d317Sonic Zhang	 * DMA engine goes to fetch them below
1036805a8ab3ce1be83e9a98c21a625ebbb549a2d317Sonic Zhang	 */
1037805a8ab3ce1be83e9a98c21a625ebbb549a2d317Sonic Zhang	SSYNC();
1038805a8ab3ce1be83e9a98c21a625ebbb549a2d317Sonic Zhang
10394fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	/* always clear status buffer before start tx dma */
10404fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	current_tx_ptr->status.status_word = 0;
10414fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
1042e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* enable this packet's dma */
1043e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	current_tx_ptr->desc_a.config |= DMAEN;
1044e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1045e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* tx dma is running, just return */
1046015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich	if (bfin_read_DMA2_IRQ_STATUS() & DMA_RUN)
1047e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		goto out;
1048e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1049e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* tx dma is not running */
1050e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA2_NEXT_DESC_PTR(&(current_tx_ptr->desc_a));
1051e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* dma enabled, read from memory, size is 6 */
1052e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA2_CONFIG(current_tx_ptr->desc_a.config);
1053e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Turn on the EMAC tx */
1054e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
1055e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1056e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wuout:
1057fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	bfin_tx_hwtstamp(dev, skb);
1058fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
1059e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	current_tx_ptr = current_tx_ptr->next;
106009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_packets++;
106109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.tx_bytes += (skb->len);
10624fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
10634fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	tx_reclaim_skb(lp);
10644fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
10656ed106549d17474ca17a16057f4c0ed4eba5a7caPatrick McHardy	return NETDEV_TX_OK;
1066e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1067e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1068ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang#define IP_HEADER_OFF  0
1069ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald#define RX_ERROR_MASK (RX_LONG | RX_ALIGN | RX_CRC | RX_LEN | \
1070ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald	RX_FRAG | RX_ADDR | RX_DMAO | RX_PHY | RX_LATE | RX_RANGE)
1071ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald
10727ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic void bfin_mac_rx(struct net_device *dev)
1073e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1074e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	struct sk_buff *skb, *new_skb;
1075e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	unsigned short len;
1076fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	struct bfin_mac_local *lp __maybe_unused = netdev_priv(dev);
1077ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang#if defined(BFIN_MAC_CSUM_OFFLOAD)
1078ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	unsigned int i;
1079ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	unsigned char fcs[ETH_FCS_LEN + 1];
1080ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang#endif
1081e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1082ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald	/* check if frame status word reports an error condition
1083ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald	 * we which case we simply drop the packet
1084ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald	 */
1085ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald	if (current_rx_ptr->status.status_word & RX_ERROR_MASK) {
1086c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger		netdev_notice(dev, "rx: receive error - packet dropped\n");
1087ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald		dev->stats.rx_dropped++;
1088ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald		goto out;
1089ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald	}
1090ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwald
1091e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* allocate a new skb for next time receive */
1092e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	skb = current_rx_ptr->skb;
1093fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
10941ab0d2ec9aeb4489c05158e8a2b00bad89f67e03Pradeep A. Dalvi	new_skb = netdev_alloc_skb(dev, PKT_BUF_SZ + NET_IP_ALIGN);
1095e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (!new_skb) {
1096c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger		netdev_notice(dev, "rx: low on mem - packet dropped\n");
109709f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik		dev->stats.rx_dropped++;
1098e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		goto out;
1099e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
1100e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* reserve 2 bytes for RXDWA padding */
1101015dac8886b5c48d62ebc33a964b9086d6a71bd7Michael Hennerich	skb_reserve(new_skb, NET_IP_ALIGN);
11026e01d1a4b2f7110201e7fe16e561a721d76fab3eAlexey Demin	/* Invidate the data cache of skb->data range when it is write back
11036e01d1a4b2f7110201e7fe16e561a721d76fab3eAlexey Demin	 * cache. It will prevent overwritting the new data from DMA
11046e01d1a4b2f7110201e7fe16e561a721d76fab3eAlexey Demin	 */
11056e01d1a4b2f7110201e7fe16e561a721d76fab3eAlexey Demin	blackfin_dcache_invalidate_range((unsigned long)new_skb->head,
11066e01d1a4b2f7110201e7fe16e561a721d76fab3eAlexey Demin					 (unsigned long)new_skb->end);
11076e01d1a4b2f7110201e7fe16e561a721d76fab3eAlexey Demin
1108f6e1e4f3e511589dd0c47d42b870501659e7195fSonic Zhang	current_rx_ptr->skb = new_skb;
1109f6e1e4f3e511589dd0c47d42b870501659e7195fSonic Zhang	current_rx_ptr->desc_a.start_addr = (unsigned long)new_skb->data - 2;
1110f6e1e4f3e511589dd0c47d42b870501659e7195fSonic Zhang
1111e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	len = (unsigned short)((current_rx_ptr->status.status_word) & RX_FRLEN);
1112ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	/* Deduce Ethernet FCS length from Ethernet payload length */
1113ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	len -= ETH_FCS_LEN;
1114e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	skb_put(skb, len);
1115e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1116e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	skb->protocol = eth_type_trans(skb, dev);
1117fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
1118fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	bfin_rx_hwtstamp(dev, skb);
1119fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
1120e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#if defined(BFIN_MAC_CSUM_OFFLOAD)
1121ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	/* Checksum offloading only works for IPv4 packets with the standard IP header
1122ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	 * length of 20 bytes, because the blackfin MAC checksum calculation is
1123ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	 * based on that assumption. We must NOT use the calculated checksum if our
1124ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	 * IP version or header break that assumption.
1125ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	 */
1126ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	if (skb->data[IP_HEADER_OFF] == 0x45) {
1127ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		skb->csum = current_rx_ptr->status.ip_payload_csum;
1128ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		/*
1129ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		 * Deduce Ethernet FCS from hardware generated IP payload checksum.
1130ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		 * IP checksum is based on 16-bit one's complement algorithm.
1131ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		 * To deduce a value from checksum is equal to add its inversion.
1132ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		 * If the IP payload len is odd, the inversed FCS should also
1133ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		 * begin from odd address and leave first byte zero.
1134ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		 */
1135ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		if (skb->len % 2) {
1136ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang			fcs[0] = 0;
1137ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang			for (i = 0; i < ETH_FCS_LEN; i++)
1138ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang				fcs[i + 1] = ~skb->data[skb->len + i];
1139ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang			skb->csum = csum_partial(fcs, ETH_FCS_LEN + 1, skb->csum);
1140ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		} else {
1141ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang			for (i = 0; i < ETH_FCS_LEN; i++)
1142ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang				fcs[i] = ~skb->data[skb->len + i];
1143ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang			skb->csum = csum_partial(fcs, ETH_FCS_LEN, skb->csum);
1144ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		}
1145ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang		skb->ip_summed = CHECKSUM_COMPLETE;
1146ad2864d88718714d8b347b6209b07abb2ecd3a49Sonic Zhang	}
1147e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#endif
1148e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1149e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	netif_rx(skb);
115009f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.rx_packets++;
115109f75cd7bf13720738e6a196cc0107ce9a5bd5a0Jeff Garzik	dev->stats.rx_bytes += len;
1152ec497b32c311b1e1aac22a76d294d24285d06331Peter Meerwaldout:
1153e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	current_rx_ptr->status.status_word = 0x00000000;
1154e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	current_rx_ptr = current_rx_ptr->next;
1155e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1156e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1157e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/* interrupt routine to handle rx and error signal */
11587ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic irqreturn_t bfin_mac_interrupt(int irq, void *dev_id)
1159e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1160e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	struct net_device *dev = dev_id;
1161e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	int number = 0;
1162e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1163e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wuget_one_packet:
1164e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (current_rx_ptr->status.status_word == 0) {
1165e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		/* no more new packet received */
1166e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		if (number == 0) {
1167e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu			if (current_rx_ptr->next->status.status_word != 0) {
1168e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				current_rx_ptr = current_rx_ptr->next;
1169e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu				goto real_rx;
1170e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu			}
1171e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		}
1172e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		bfin_write_DMA1_IRQ_STATUS(bfin_read_DMA1_IRQ_STATUS() |
1173e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu					   DMA_DONE | DMA_ERR);
1174e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		return IRQ_HANDLED;
1175e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
1176e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1177e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wureal_rx:
11787ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	bfin_mac_rx(dev);
1179e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	number++;
1180e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	goto get_one_packet;
1181e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1182e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1183e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#ifdef CONFIG_NET_POLL_CONTROLLER
11847ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic void bfin_mac_poll(struct net_device *dev)
1185e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
11864fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	struct bfin_mac_local *lp = netdev_priv(dev);
11874fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
1188e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	disable_irq(IRQ_MAC_RX);
11897ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	bfin_mac_interrupt(IRQ_MAC_RX, dev);
11904fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	tx_reclaim_skb(lp);
1191e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	enable_irq(IRQ_MAC_RX);
1192e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1193e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#endif				/* CONFIG_NET_POLL_CONTROLLER */
1194e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
11957ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic void bfin_mac_disable(void)
1196e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1197e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	unsigned int opmode;
1198e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1199e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	opmode = bfin_read_EMAC_OPMODE();
1200e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	opmode &= (~RE);
1201e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	opmode &= (~TE);
1202e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Turn off the EMAC */
1203e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_EMAC_OPMODE(opmode);
1204e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1205e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1206e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/*
1207e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * Enable Interrupts, Receive, and Transmit
1208e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu */
120902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhangstatic int bfin_mac_enable(struct phy_device *phydev)
1210e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
12112bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	int ret;
1212e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	u32 opmode;
1213e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1214c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger	pr_debug("%s\n", __func__);
1215e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1216e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Set RX DMA */
1217e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA1_NEXT_DESC_PTR(&(rx_list_head->desc_a));
1218e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA1_CONFIG(rx_list_head->desc_a.config);
1219e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1220e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Wait MII done */
12212bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	ret = bfin_mdio_poll();
12222bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	if (ret)
12232bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger		return ret;
1224e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1225e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* We enable only RX here */
1226e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* ASTP   : Enable Automatic Pad Stripping
1227e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	   PR     : Promiscuous Mode for test
1228e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	   PSF    : Receive frames with total length less than 64 bytes.
1229e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	   FDMODE : Full Duplex Mode
1230e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	   LB     : Internal Loopback for test
1231e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	   RE     : Receiver Enable */
1232e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	opmode = bfin_read_EMAC_OPMODE();
1233e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (opmode & FDMODE)
1234e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		opmode |= PSF;
1235e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	else
1236e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		opmode |= DRO | DC | PSF;
1237e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	opmode |= RE;
1238e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
123902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	if (phydev->interface == PHY_INTERFACE_MODE_RMII) {
124002460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		opmode |= RMII; /* For Now only 100MBit are supported */
124172f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger#if defined(CONFIG_BF537) || defined(CONFIG_BF536)
124272f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger		if (__SILICON_REVISION__ < 3) {
124372f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger			/*
124472f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger			 * This isn't publicly documented (fun times!), but in
124572f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger			 * silicon <=0.2, the RX and TX pins are clocked together.
124672f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger			 * So in order to recv, we must enable the transmit side
124772f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger			 * as well.  This will cause a spurious TX interrupt too,
124872f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger			 * but we can easily consume that.
124972f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger			 */
125072f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger			opmode |= TE;
125172f49050ba18959472aac723cd9d094bc3547e89Mike Frysinger		}
1252e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu#endif
125302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	}
125402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
1255e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Turn on the EMAC rx */
1256e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_EMAC_OPMODE(opmode);
12572bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger
12582bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	return 0;
1259e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1260e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1261e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/* Our watchdog timed out. Called by the networking layer */
12627ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic void bfin_mac_timeout(struct net_device *dev)
1263e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
12644fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	struct bfin_mac_local *lp = netdev_priv(dev);
12654fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
1266b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison	pr_debug("%s: %s\n", dev->name, __func__);
1267e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
12687ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	bfin_mac_disable();
1269e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
12704fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	del_timer(&lp->tx_reclaim_timer);
12714fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
12724fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	/* reset tx queue and free skb */
12734fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	while (tx_list_head != current_tx_ptr) {
12744fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		tx_list_head->desc_a.config &= ~DMAEN;
12754fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		tx_list_head->status.status_word = 0;
12764fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		if (tx_list_head->skb) {
12774fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			dev_kfree_skb(tx_list_head->skb);
12784fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang			tx_list_head->skb = NULL;
12794fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		}
12804fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		tx_list_head = tx_list_head->next;
12814fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	}
12824fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
12834fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	if (netif_queue_stopped(lp->ndev))
12844fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang		netif_wake_queue(lp->ndev);
1285e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
128602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	bfin_mac_enable(lp->phydev);
1287e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1288e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* We can accept TX packets again */
12891ae5dc342ac78d7a42965fd1f323815f6f5ef2c1Eric Dumazet	dev->trans_start = jiffies; /* prevent tx timeout */
1290e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	netif_wake_queue(dev);
1291e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1292e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
12937ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic void bfin_mac_multicast_hash(struct net_device *dev)
1294775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams{
1295775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams	u32 emac_hashhi, emac_hashlo;
129622bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	struct netdev_hw_addr *ha;
1297775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams	u32 crc;
1298775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams
1299775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams	emac_hashhi = emac_hashlo = 0;
1300775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams
130122bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko	netdev_for_each_mc_addr(ha, dev) {
1302f767b6df8a796f901b2bd595ae22234636be4124Joe Perches		crc = ether_crc(ETH_ALEN, ha->addr);
1303775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams		crc >>= 26;
1304775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams
1305775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams		if (crc & 0x20)
1306775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams			emac_hashhi |= 1 << (crc & 0x1f);
1307775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams		else
1308775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams			emac_hashlo |= 1 << (crc & 0x1f);
1309775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams	}
1310775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams
1311775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams	bfin_write_EMAC_HASHHI(emac_hashhi);
1312775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams	bfin_write_EMAC_HASHLO(emac_hashlo);
1313775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams}
1314775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams
1315e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/*
1316e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * This routine will, depending on the values passed to it,
1317e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * either make it accept multicast packets, go into
1318e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * promiscuous mode (for TCPDUMP and cousins) or accept
1319e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * a select set of multicast packets
1320e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu */
13217ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic void bfin_mac_set_multicast_list(struct net_device *dev)
1322e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1323e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	u32 sysctl;
1324e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1325e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (dev->flags & IFF_PROMISC) {
1326c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger		netdev_info(dev, "set promisc mode\n");
1327e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		sysctl = bfin_read_EMAC_OPMODE();
1328c0da776bde79e5d5e2c955ff37a8a09fe05433b2Sonic Zhang		sysctl |= PR;
1329e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		bfin_write_EMAC_OPMODE(sysctl);
1330775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams	} else if (dev->flags & IFF_ALLMULTI) {
1331e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		/* accept all multicast */
1332e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		sysctl = bfin_read_EMAC_OPMODE();
1333e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		sysctl |= PAM;
1334e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		bfin_write_EMAC_OPMODE(sysctl);
13354cd24eaf0c6ee7f0242e34ee77ec899f255e66b5Jiri Pirko	} else if (!netdev_mc_empty(dev)) {
1336775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams		/* set up multicast hash table */
1337775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams		sysctl = bfin_read_EMAC_OPMODE();
1338775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams		sysctl |= HM;
1339775919bc23880f250ca1029a6420187ee4bb5b26Aidan Williams		bfin_write_EMAC_OPMODE(sysctl);
13407ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		bfin_mac_multicast_hash(dev);
1341e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	} else {
1342e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		/* clear promisc or multicast mode */
1343e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		sysctl = bfin_read_EMAC_OPMODE();
1344e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		sysctl &= ~(RAF | PAM);
1345e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		bfin_write_EMAC_OPMODE(sysctl);
1346e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
1347e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1348e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1349fe92afedee23e1d91f0133360a24d2bf48270739Barry Songstatic int bfin_mac_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
1350fe92afedee23e1d91f0133360a24d2bf48270739Barry Song{
135102460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	struct bfin_mac_local *lp = netdev_priv(netdev);
135202460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
135302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	if (!netif_running(netdev))
135402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		return -EINVAL;
135502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
1356fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	switch (cmd) {
1357fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	case SIOCSHWTSTAMP:
1358fe92afedee23e1d91f0133360a24d2bf48270739Barry Song		return bfin_mac_hwtstamp_ioctl(netdev, ifr, cmd);
1359fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	default:
136002460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		if (lp->phydev)
136102460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang			return phy_mii_ioctl(lp->phydev, ifr, cmd);
136202460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		else
136302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang			return -EOPNOTSUPP;
1364fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	}
1365fe92afedee23e1d91f0133360a24d2bf48270739Barry Song}
1366fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
1367e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/*
1368e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * this puts the device in an inactive state
1369e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu */
13707ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic void bfin_mac_shutdown(struct net_device *dev)
1371e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1372e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Turn off the EMAC */
1373e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_EMAC_OPMODE(0x00000000);
1374e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Turn off the EMAC RX DMA */
1375e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA1_CONFIG(0x0000);
1376e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_DMA2_CONFIG(0x0000);
1377e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1378e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1379e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/*
1380e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * Open and Initialize the interface
1381e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu *
1382e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * Set up everything, reset the card, etc..
1383e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu */
13847ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic int bfin_mac_open(struct net_device *dev)
1385e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
13867ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	struct bfin_mac_local *lp = netdev_priv(dev);
13872bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	int ret;
1388b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison	pr_debug("%s: %s\n", dev->name, __func__);
1389e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1390e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/*
1391e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	 * Check that the address is valid.  If its not, refuse
1392e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	 * to bring the device up.  The user must specify an
1393e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	 * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx
1394e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	 */
1395e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (!is_valid_ether_addr(dev->dev_addr)) {
1396c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger		netdev_warn(dev, "no valid ethernet hw addr\n");
1397e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu		return -EINVAL;
1398e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
1399e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1400e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* initial rx and tx list */
14011ab0d2ec9aeb4489c05158e8a2b00bad89f67e03Pradeep A. Dalvi	ret = desc_list_init(dev);
14022bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	if (ret)
14032bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger		return ret;
1404e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
14054ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	phy_start(lp->phydev);
1406136492b275e0dd02d842b94507d66267d18d341cVitja Makarov	phy_write(lp->phydev, MII_BMCR, BMCR_RESET);
1407e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	setup_system_regs(dev);
1408ee02fee8f698aee72f43b3ee5fd818393b110402Michael Hennerich	setup_mac_addr(dev->dev_addr);
14092bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger
14107ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	bfin_mac_disable();
141102460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	ret = bfin_mac_enable(lp->phydev);
14122bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger	if (ret)
14132bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger		return ret;
1414e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	pr_debug("hardware init finished\n");
14152bfa0f0c9a37460ee69128da411f6d310c1c983dMike Frysinger
1416e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	netif_start_queue(dev);
1417e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	netif_carrier_on(dev);
1418e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1419e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	return 0;
1420e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1421e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1422e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu/*
1423e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * this makes the board clean up everything that it can
1424e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * and not talk to the outside world.   Caused by
1425e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu * an 'ifconfig ethX down'
1426e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu */
14277ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wustatic int bfin_mac_close(struct net_device *dev)
1428e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
14297ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	struct bfin_mac_local *lp = netdev_priv(dev);
1430b39d66a81fb4f5ab555f86a2e49f3714f8369a3dHarvey Harrison	pr_debug("%s: %s\n", dev->name, __func__);
1431e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1432e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	netif_stop_queue(dev);
1433e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	netif_carrier_off(dev);
1434e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
14354ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu	phy_stop(lp->phydev);
1436136492b275e0dd02d842b94507d66267d18d341cVitja Makarov	phy_write(lp->phydev, MII_BMCR, BMCR_PDOWN);
14374ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
1438e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* clear everything */
14397ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	bfin_mac_shutdown(dev);
1440e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1441e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* free the rx/tx buffers */
1442e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	desc_list_free();
1443e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1444e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	return 0;
1445e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1446e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1447b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysingerstatic const struct net_device_ops bfin_mac_netdev_ops = {
1448b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger	.ndo_open		= bfin_mac_open,
1449b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger	.ndo_stop		= bfin_mac_close,
1450b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger	.ndo_start_xmit		= bfin_mac_hard_start_xmit,
1451b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger	.ndo_set_mac_address	= bfin_mac_set_mac_address,
1452b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger	.ndo_tx_timeout		= bfin_mac_timeout,
1453afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko	.ndo_set_rx_mode	= bfin_mac_set_multicast_list,
1454fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	.ndo_do_ioctl           = bfin_mac_ioctl,
1455b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger	.ndo_validate_addr	= eth_validate_addr,
1456b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger	.ndo_change_mtu		= eth_change_mtu,
1457b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger#ifdef CONFIG_NET_POLL_CONTROLLER
1458b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger	.ndo_poll_controller	= bfin_mac_poll,
1459b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger#endif
1460b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger};
1461b63dc8fef7ca5c51d163295d824e78c770d48ccfMike Frysinger
1462d7b843d393cec677583e1aa971df09b140dcfd5eMike Frysingerstatic int __devinit bfin_mac_probe(struct platform_device *pdev)
1463e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
14647ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	struct net_device *ndev;
14657ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	struct bfin_mac_local *lp;
1466080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	struct platform_device *pd;
146702460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	struct bfin_mii_bus_platform_data *mii_bus_data;
1468080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	int rc;
14697ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu
14707ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	ndev = alloc_etherdev(sizeof(struct bfin_mac_local));
147141de8d4cff21a2e81e3d9ff66f5f7c903f9c3ab1Joe Perches	if (!ndev)
14727ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		return -ENOMEM;
14737ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu
14747ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	SET_NETDEV_DEV(ndev, &pdev->dev);
14757ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	platform_set_drvdata(pdev, ndev);
14767ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	lp = netdev_priv(ndev);
14774fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	lp->ndev = ndev;
1478e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1479e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Grab the MAC address in the MAC */
14807ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	*(__le32 *) (&(ndev->dev_addr[0])) = cpu_to_le32(bfin_read_EMAC_ADDRLO());
14817ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	*(__le16 *) (&(ndev->dev_addr[4])) = cpu_to_le16((u16) bfin_read_EMAC_ADDRHI());
1482e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1483e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* probe mac */
1484e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/*todo: how to proble? which is revision_register */
1485e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	bfin_write_EMAC_ADDRLO(0x12345678);
1486e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	if (bfin_read_EMAC_ADDRLO() != 0x12345678) {
14877ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		dev_err(&pdev->dev, "Cannot detect Blackfin on-chip ethernet MAC controller!\n");
14887ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		rc = -ENODEV;
14897ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		goto out_err_probe_mac;
1490e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
1491e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1492e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
14937ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	/*
14947ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	 * Is it valid? (Did bootloader initialize it?)
14957ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	 * Grab the MAC from the board somehow
14967ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	 * this is done in the arch/blackfin/mach-bfxxx/boards/eth_mac.c
14977ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	 */
14985055d2f236e1495d68c468eeb684fd5789673f1dDanny Kukawka	if (!is_valid_ether_addr(ndev->dev_addr)) {
14995055d2f236e1495d68c468eeb684fd5789673f1dDanny Kukawka		if (bfin_get_ether_addr(ndev->dev_addr) ||
15005055d2f236e1495d68c468eeb684fd5789673f1dDanny Kukawka		     !is_valid_ether_addr(ndev->dev_addr)) {
15015055d2f236e1495d68c468eeb684fd5789673f1dDanny Kukawka			/* Still not valid, get a random one */
15025055d2f236e1495d68c468eeb684fd5789673f1dDanny Kukawka			netdev_warn(ndev, "Setting Ethernet MAC to a random one\n");
15035055d2f236e1495d68c468eeb684fd5789673f1dDanny Kukawka			eth_hw_addr_random(ndev);
15045055d2f236e1495d68c468eeb684fd5789673f1dDanny Kukawka		}
15055055d2f236e1495d68c468eeb684fd5789673f1dDanny Kukawka	}
1506e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
15077ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	setup_mac_addr(ndev->dev_addr);
1508e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1509080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	if (!pdev->dev.platform_data) {
1510080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		dev_err(&pdev->dev, "Cannot get platform device bfin_mii_bus!\n");
1511080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		rc = -ENODEV;
1512080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		goto out_err_probe_mac;
15137ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	}
1514080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	pd = pdev->dev.platform_data;
1515080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	lp->mii_bus = platform_get_drvdata(pd);
15160e995cd3d3c78377a0bc7d38236fc50e5438fabbSonic Zhang	if (!lp->mii_bus) {
15170e995cd3d3c78377a0bc7d38236fc50e5438fabbSonic Zhang		dev_err(&pdev->dev, "Cannot get mii_bus!\n");
15180e995cd3d3c78377a0bc7d38236fc50e5438fabbSonic Zhang		rc = -ENODEV;
151902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		goto out_err_probe_mac;
15200e995cd3d3c78377a0bc7d38236fc50e5438fabbSonic Zhang	}
1521080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	lp->mii_bus->priv = ndev;
152202460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	mii_bus_data = pd->dev.platform_data;
15234ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
152402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	rc = mii_probe(ndev, mii_bus_data->phy_mode);
15257ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	if (rc) {
15267ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		dev_err(&pdev->dev, "MII Probe failed!\n");
15277ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		goto out_err_mii_probe;
15287ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	}
15294ae5a3ad5aa35972863f9c656ebd35446fbb5192Bryan Wu
1530c599bd6b9ac8926b03e6bf332a8c14ae2ffb43a3Mike Frysinger	lp->vlan1_mask = ETH_P_8021Q | mii_bus_data->vlan1_mask;
1531c599bd6b9ac8926b03e6bf332a8c14ae2ffb43a3Mike Frysinger	lp->vlan2_mask = ETH_P_8021Q | mii_bus_data->vlan2_mask;
1532c599bd6b9ac8926b03e6bf332a8c14ae2ffb43a3Mike Frysinger
1533e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* Fill in the fields of the device structure with ethernet values. */
15347ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	ether_setup(ndev);
15357ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu
1536149da651bf340b796576a078574fbb49ed09b7aeAlexander Beregalov	ndev->netdev_ops = &bfin_mac_netdev_ops;
1537679dce39e3cdfcc641b2888ce04f1cd5ff0b3b92Bryan Wu	ndev->ethtool_ops = &bfin_mac_ethtool_ops;
1538e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
15394fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	init_timer(&lp->tx_reclaim_timer);
15404fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	lp->tx_reclaim_timer.data = (unsigned long)lp;
15414fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang	lp->tx_reclaim_timer.function = tx_reclaim_skb_timeout;
15424fcc3d3409b0ab37c1f790e04a1f7c984b436167Sonic Zhang
1543e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	spin_lock_init(&lp->lock);
1544e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1545e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* now, enable interrupts */
1546e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	/* register irq handler */
15477ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	rc = request_irq(IRQ_MAC_RX, bfin_mac_interrupt,
154891a455f089810625eb94a36ccc40ae963f451b06Michael Hennerich			IRQF_DISABLED, "EMAC_RX", ndev);
15497ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	if (rc) {
15507ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		dev_err(&pdev->dev, "Cannot request Blackfin MAC RX IRQ!\n");
15517ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		rc = -EBUSY;
15527ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		goto out_err_request_irq;
1553e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
1554e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
15557ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	rc = register_netdev(ndev);
15567ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	if (rc) {
15577ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		dev_err(&pdev->dev, "Cannot register net device!\n");
15587ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu		goto out_err_reg_ndev;
1559e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	}
1560e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1561fe92afedee23e1d91f0133360a24d2bf48270739Barry Song	bfin_mac_hwtstamp_init(ndev);
1562fe92afedee23e1d91f0133360a24d2bf48270739Barry Song
15637ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	/* now, print out the card info, in a short format.. */
1564c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger	netdev_info(ndev, "%s, Version %s\n", DRV_DESC, DRV_VERSION);
1565e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
15667ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	return 0;
1567e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
15687ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wuout_err_reg_ndev:
15697ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	free_irq(IRQ_MAC_RX, ndev);
15707ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wuout_err_request_irq:
15717ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wuout_err_mii_probe:
1572298cf9beb9679522de995e249eccbd82f7c51999Lennert Buytenhek	mdiobus_unregister(lp->mii_bus);
1573298cf9beb9679522de995e249eccbd82f7c51999Lennert Buytenhek	mdiobus_free(lp->mii_bus);
15747ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wuout_err_probe_mac:
15757ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	platform_set_drvdata(pdev, NULL);
15767ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	free_netdev(ndev);
1577e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
15787ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	return rc;
1579e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1580e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1581d7b843d393cec677583e1aa971df09b140dcfd5eMike Frysingerstatic int __devexit bfin_mac_remove(struct platform_device *pdev)
1582e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1583e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	struct net_device *ndev = platform_get_drvdata(pdev);
15847ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu	struct bfin_mac_local *lp = netdev_priv(ndev);
1585e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1586e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	platform_set_drvdata(pdev, NULL);
1587e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1588080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	lp->mii_bus->priv = NULL;
15897ef0a7ee2f9ac7ee8e2a597821adb2a78b882791Bryan Wu
1590e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	unregister_netdev(ndev);
1591e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1592e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	free_irq(IRQ_MAC_RX, ndev);
1593e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1594e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	free_netdev(ndev);
1595e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1596e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	return 0;
1597e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1598e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1599496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu#ifdef CONFIG_PM
1600496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wustatic int bfin_mac_suspend(struct platform_device *pdev, pm_message_t mesg)
1601e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1602496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu	struct net_device *net_dev = platform_get_drvdata(pdev);
160353fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	struct bfin_mac_local *lp = netdev_priv(net_dev);
1604496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu
160553fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	if (lp->wol) {
160653fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		bfin_write_EMAC_OPMODE((bfin_read_EMAC_OPMODE() & ~TE) | RE);
160753fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		bfin_write_EMAC_WKUP_CTL(MPKE);
160853fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		enable_irq_wake(IRQ_MAC_WAKEDET);
160953fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	} else {
161053fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		if (netif_running(net_dev))
161153fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich			bfin_mac_close(net_dev);
161253fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	}
1613496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu
1614e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	return 0;
1615e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1616e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1617e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic int bfin_mac_resume(struct platform_device *pdev)
1618e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1619496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu	struct net_device *net_dev = platform_get_drvdata(pdev);
162053fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	struct bfin_mac_local *lp = netdev_priv(net_dev);
1621496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu
162253fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	if (lp->wol) {
162353fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		bfin_write_EMAC_OPMODE(bfin_read_EMAC_OPMODE() | TE);
162453fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		bfin_write_EMAC_WKUP_CTL(0);
162553fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		disable_irq_wake(IRQ_MAC_WAKEDET);
162653fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	} else {
162753fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich		if (netif_running(net_dev))
162853fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich			bfin_mac_open(net_dev);
162953fd3f2829268703729a2db0e24c0e36360b68a2Michael Hennerich	}
1630496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu
1631e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	return 0;
1632e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1633496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu#else
1634496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu#define bfin_mac_suspend NULL
1635496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu#define bfin_mac_resume NULL
1636496a34c2249fecc87ee689eede2bb8510c1b37a9Bryan Wu#endif	/* CONFIG_PM */
1637e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1638080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yangstatic int __devinit bfin_mii_bus_probe(struct platform_device *pdev)
1639080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang{
1640080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	struct mii_bus *miibus;
164102460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	struct bfin_mii_bus_platform_data *mii_bus_pd;
164202460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	const unsigned short *pin_req;
1643080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	int rc, i;
1644080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
164502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	mii_bus_pd = dev_get_platdata(&pdev->dev);
164602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	if (!mii_bus_pd) {
164702460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		dev_err(&pdev->dev, "No peripherals in platform data!\n");
164802460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		return -EINVAL;
164902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	}
165002460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
1651080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	/*
1652080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	 * We are setting up a network card,
1653080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	 * so set the GPIO pins to Ethernet mode
1654080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	 */
165502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	pin_req = mii_bus_pd->mac_peripherals;
1656c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger	rc = peripheral_request_list(pin_req, KBUILD_MODNAME);
1657080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	if (rc) {
1658080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		dev_err(&pdev->dev, "Requesting peripherals failed!\n");
1659080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		return rc;
1660080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	}
1661080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
1662080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	rc = -ENOMEM;
1663080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	miibus = mdiobus_alloc();
1664080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	if (miibus == NULL)
1665080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		goto out_err_alloc;
1666080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	miibus->read = bfin_mdiobus_read;
1667080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	miibus->write = bfin_mdiobus_write;
1668080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	miibus->reset = bfin_mdiobus_reset;
1669080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
1670080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	miibus->parent = &pdev->dev;
1671080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	miibus->name = "bfin_mii_bus";
167202460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	miibus->phy_mask = mii_bus_pd->phy_mask;
167302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
167475432fd2913e03696f56289a853754ef0124545fFlorian Fainelli	snprintf(miibus->id, MII_BUS_ID_SIZE, "%s-%x",
167575432fd2913e03696f56289a853754ef0124545fFlorian Fainelli		pdev->name, pdev->id);
1676080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	miibus->irq = kmalloc(sizeof(int)*PHY_MAX_ADDR, GFP_KERNEL);
167702460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	if (!miibus->irq)
167802460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		goto out_err_irq_alloc;
167902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
168002460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	for (i = rc; i < PHY_MAX_ADDR; ++i)
1681080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		miibus->irq[i] = PHY_POLL;
1682080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
168302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	rc = clamp(mii_bus_pd->phydev_number, 0, PHY_MAX_ADDR);
168402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	if (rc != mii_bus_pd->phydev_number)
168502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		dev_err(&pdev->dev, "Invalid number (%i) of phydevs\n",
168602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang			mii_bus_pd->phydev_number);
168702460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	for (i = 0; i < rc; ++i) {
168802460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		unsigned short phyaddr = mii_bus_pd->phydev_data[i].addr;
168902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		if (phyaddr < PHY_MAX_ADDR)
169002460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang			miibus->irq[phyaddr] = mii_bus_pd->phydev_data[i].irq;
169102460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		else
169202460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang			dev_err(&pdev->dev,
169302460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang				"Invalid PHY address %i for phydev %i\n",
169402460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang				phyaddr, i);
169502460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	}
169602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
1697080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	rc = mdiobus_register(miibus);
1698080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	if (rc) {
1699080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		dev_err(&pdev->dev, "Cannot register MDIO bus!\n");
1700080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		goto out_err_mdiobus_register;
1701080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	}
1702080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
1703080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	platform_set_drvdata(pdev, miibus);
1704080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	return 0;
1705080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
1706080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yangout_err_mdiobus_register:
17077f267de41fde594500cbbccb1b29acb4475f2da2Denis Kirjanov	kfree(miibus->irq);
170802460d08930656b3a50381cfb119864efcd4eef9Sonic Zhangout_err_irq_alloc:
1709080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	mdiobus_free(miibus);
1710080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yangout_err_alloc:
1711080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	peripheral_free_list(pin_req);
1712080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
1713080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	return rc;
1714080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang}
1715080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
1716080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yangstatic int __devexit bfin_mii_bus_remove(struct platform_device *pdev)
1717080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang{
1718080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	struct mii_bus *miibus = platform_get_drvdata(pdev);
171902460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	struct bfin_mii_bus_platform_data *mii_bus_pd =
172002460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang		dev_get_platdata(&pdev->dev);
172102460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
1722080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	platform_set_drvdata(pdev, NULL);
1723080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	mdiobus_unregister(miibus);
17247f267de41fde594500cbbccb1b29acb4475f2da2Denis Kirjanov	kfree(miibus->irq);
1725080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	mdiobus_free(miibus);
172602460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang	peripheral_free_list(mii_bus_pd->mac_peripherals);
172702460d08930656b3a50381cfb119864efcd4eef9Sonic Zhang
1728080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	return 0;
1729080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang}
1730080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
1731080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yangstatic struct platform_driver bfin_mii_bus_driver = {
1732080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	.probe = bfin_mii_bus_probe,
1733080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	.remove = __devexit_p(bfin_mii_bus_remove),
1734080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	.driver = {
1735080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		.name = "bfin_mii_bus",
1736080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		.owner	= THIS_MODULE,
1737080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	},
1738080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang};
1739080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang
1740e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic struct platform_driver bfin_mac_driver = {
1741e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	.probe = bfin_mac_probe,
1742d7b843d393cec677583e1aa971df09b140dcfd5eMike Frysinger	.remove = __devexit_p(bfin_mac_remove),
1743e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	.resume = bfin_mac_resume,
1744e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	.suspend = bfin_mac_suspend,
1745e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	.driver = {
1746c6dd5098f47268976f7d0af3dad29084fd8b6b98Mike Frysinger		.name = KBUILD_MODNAME,
174772abb46101fb5c47a9592914adb221b430ff26bdKay Sievers		.owner	= THIS_MODULE,
174872abb46101fb5c47a9592914adb221b430ff26bdKay Sievers	},
1749e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu};
1750e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1751e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic int __init bfin_mac_init(void)
1752e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1753080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	int ret;
1754080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	ret = platform_driver_register(&bfin_mii_bus_driver);
1755080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	if (!ret)
1756080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang		return platform_driver_register(&bfin_mac_driver);
1757080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	return -ENODEV;
1758e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1759e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1760e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wumodule_init(bfin_mac_init);
1761e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1762e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wustatic void __exit bfin_mac_cleanup(void)
1763e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu{
1764e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu	platform_driver_unregister(&bfin_mac_driver);
1765080c82550dc1dc3c0d4207ce32d7a8d0ae96fba5Graf Yang	platform_driver_unregister(&bfin_mii_bus_driver);
1766e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu}
1767e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wu
1768e190d6b140079c104ba57e5130a9b4ebea618e92Bryan Wumodule_exit(bfin_mac_cleanup);
176972abb46101fb5c47a9592914adb221b430ff26bdKay Sievers
1770