blob: 4cacca614fc12b10e3ba44adc79c136655839a5e [file] [log] [blame]
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -07001/*******************************************************************************
2 This is the driver for the MAC 10/100 on-chip Ethernet controller
3 currently tested on all the ST boards based on STb7109 and stx7200 SoCs.
4
5 DWC Ether MAC 10/100 Universal version 4.0 has been used for developing
6 this code.
7
8 Copyright (C) 2007-2009 STMicroelectronics Ltd
9
10 This program is free software; you can redistribute it and/or modify it
11 under the terms and conditions of the GNU General Public License,
12 version 2, as published by the Free Software Foundation.
13
14 This program is distributed in the hope it will be useful, but WITHOUT
15 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 more details.
18
19 You should have received a copy of the GNU General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc.,
21 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
22
23 The full GNU General Public License is included in this distribution in
24 the file called "COPYING".
25
26 Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
27*******************************************************************************/
28
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070029#include <linux/crc32.h>
30#include <linux/mii.h>
31#include <linux/phy.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090032#include <linux/slab.h>
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070033
34#include "common.h"
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000035#include "dwmac100.h"
Giuseppe CAVALLAROaec7ff22010-01-06 23:07:18 +000036#include "dwmac_dma.h"
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070037
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000038#undef DWMAC100_DEBUG
39/*#define DWMAC100_DEBUG*/
40#ifdef DWMAC100_DEBUG
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070041#define DBG(fmt, args...) printk(fmt, ## args)
42#else
43#define DBG(fmt, args...) do { } while (0)
44#endif
45
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000046static void dwmac100_core_init(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070047{
48 u32 value = readl(ioaddr + MAC_CONTROL);
49
50 writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
51
52#ifdef STMMAC_VLAN_TAG_USED
53 writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
54#endif
55 return;
56}
57
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000058static void dwmac100_dump_mac_regs(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070059{
60 pr_info("\t----------------------------------------------\n"
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000061 "\t DWMAC 100 CSR (base addr = 0x%8x)\n"
62 "\t----------------------------------------------\n",
63 (unsigned int)ioaddr);
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070064 pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000065 readl(ioaddr + MAC_CONTROL));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070066 pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000067 readl(ioaddr + MAC_ADDR_HIGH));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070068 pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000069 readl(ioaddr + MAC_ADDR_LOW));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070070 pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000071 MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070072 pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000073 MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070074 pr_info("\tflow control (offset 0x%x): 0x%08x\n",
75 MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL));
76 pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000077 readl(ioaddr + MAC_VLAN1));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070078 pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000079 readl(ioaddr + MAC_VLAN2));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070080 pr_info("\n\tMAC management counter registers\n");
81 pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000082 MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070083 pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000084 MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070085 pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000086 MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070087 pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000088 MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070089 pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000090 MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070091 return;
92}
93
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000094static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070095 u32 dma_rx)
96{
97 u32 value = readl(ioaddr + DMA_BUS_MODE);
98 /* DMA SW reset */
99 value |= DMA_BUS_MODE_SFT_RESET;
100 writel(value, ioaddr + DMA_BUS_MODE);
101 do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
102
103 /* Enable Application Access by writing to DMA CSR0 */
104 writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
105 ioaddr + DMA_BUS_MODE);
106
107 /* Mask interrupts by writing to CSR7 */
108 writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
109
110 /* The base address of the RX/TX descriptor lists must be written into
111 * DMA CSR3 and CSR4, respectively. */
112 writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
113 writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
114
115 return 0;
116}
117
118/* Store and Forward capability is not used at all..
119 * The transmit threshold can be programmed by
120 * setting the TTC bits in the DMA control register.*/
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000121static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700122 int rxmode)
123{
124 u32 csr6 = readl(ioaddr + DMA_CONTROL);
125
126 if (txmode <= 32)
127 csr6 |= DMA_CONTROL_TTC_32;
128 else if (txmode <= 64)
129 csr6 |= DMA_CONTROL_TTC_64;
130 else
131 csr6 |= DMA_CONTROL_TTC_128;
132
133 writel(csr6, ioaddr + DMA_CONTROL);
134
135 return;
136}
137
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000138static void dwmac100_dump_dma_regs(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700139{
140 int i;
141
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000142 DBG(KERN_DEBUG "DWMAC 100 DMA CSR \n");
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700143 for (i = 0; i < 9; i++)
144 pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
145 (DMA_BUS_MODE + i * 4),
146 readl(ioaddr + DMA_BUS_MODE + i * 4));
147 DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n",
148 DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
149 DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n",
150 DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
151 return;
152}
153
154/* DMA controller has two counters to track the number of
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000155 * the receive missed frames. */
156static void dwmac100_dma_diagnostic_fr(void *data,
157 struct stmmac_extra_stats *x,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700158 unsigned long ioaddr)
159{
160 struct net_device_stats *stats = (struct net_device_stats *)data;
161 u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
162
163 if (unlikely(csr8)) {
164 if (csr8 & DMA_MISSED_FRAME_OVE) {
165 stats->rx_over_errors += 0x800;
166 x->rx_overflow_cntr += 0x800;
167 } else {
168 unsigned int ove_cntr;
169 ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
170 stats->rx_over_errors += ove_cntr;
171 x->rx_overflow_cntr += ove_cntr;
172 }
173
174 if (csr8 & DMA_MISSED_FRAME_OVE_M) {
175 stats->rx_missed_errors += 0xffff;
176 x->rx_missed_cntr += 0xffff;
177 } else {
178 unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
179 stats->rx_missed_errors += miss_f;
180 x->rx_missed_cntr += miss_f;
181 }
182 }
183 return;
184}
185
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000186static int dwmac100_get_tx_frame_status(void *data,
187 struct stmmac_extra_stats *x,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700188 struct dma_desc *p, unsigned long ioaddr)
189{
190 int ret = 0;
191 struct net_device_stats *stats = (struct net_device_stats *)data;
192
193 if (unlikely(p->des01.tx.error_summary)) {
194 if (unlikely(p->des01.tx.underflow_error)) {
195 x->tx_underflow++;
196 stats->tx_fifo_errors++;
197 }
198 if (unlikely(p->des01.tx.no_carrier)) {
199 x->tx_carrier++;
200 stats->tx_carrier_errors++;
201 }
202 if (unlikely(p->des01.tx.loss_carrier)) {
203 x->tx_losscarrier++;
204 stats->tx_carrier_errors++;
205 }
206 if (unlikely((p->des01.tx.excessive_deferral) ||
207 (p->des01.tx.excessive_collisions) ||
208 (p->des01.tx.late_collision)))
209 stats->collisions += p->des01.tx.collision_count;
210 ret = -1;
211 }
212 if (unlikely(p->des01.tx.heartbeat_fail)) {
213 x->tx_heartbeat++;
214 stats->tx_heartbeat_errors++;
215 ret = -1;
216 }
217 if (unlikely(p->des01.tx.deferred))
218 x->tx_deferred++;
219
220 return ret;
221}
222
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000223static int dwmac100_get_tx_len(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700224{
225 return p->des01.tx.buffer1_size;
226}
227
228/* This function verifies if each incoming frame has some errors
229 * and, if required, updates the multicast statistics.
230 * In case of success, it returns csum_none becasue the device
231 * is not able to compute the csum in HW. */
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000232static int dwmac100_get_rx_frame_status(void *data,
233 struct stmmac_extra_stats *x,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700234 struct dma_desc *p)
235{
236 int ret = csum_none;
237 struct net_device_stats *stats = (struct net_device_stats *)data;
238
239 if (unlikely(p->des01.rx.last_descriptor == 0)) {
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000240 pr_warning("dwmac100 Error: Oversized Ethernet "
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700241 "frame spanned multiple buffers\n");
242 stats->rx_length_errors++;
243 return discard_frame;
244 }
245
246 if (unlikely(p->des01.rx.error_summary)) {
247 if (unlikely(p->des01.rx.descriptor_error))
248 x->rx_desc++;
249 if (unlikely(p->des01.rx.partial_frame_error))
250 x->rx_partial++;
251 if (unlikely(p->des01.rx.run_frame))
252 x->rx_runt++;
253 if (unlikely(p->des01.rx.frame_too_long))
254 x->rx_toolong++;
255 if (unlikely(p->des01.rx.collision)) {
256 x->rx_collision++;
257 stats->collisions++;
258 }
259 if (unlikely(p->des01.rx.crc_error)) {
260 x->rx_crc++;
261 stats->rx_crc_errors++;
262 }
263 ret = discard_frame;
264 }
265 if (unlikely(p->des01.rx.dribbling))
266 ret = discard_frame;
267
268 if (unlikely(p->des01.rx.length_error)) {
Giuseppe Cavallaro1b924032010-02-04 09:33:21 -0800269 x->rx_length++;
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700270 ret = discard_frame;
271 }
272 if (unlikely(p->des01.rx.mii_error)) {
273 x->rx_mii++;
274 ret = discard_frame;
275 }
276 if (p->des01.rx.multicast_frame) {
277 x->rx_multicast++;
278 stats->multicast++;
279 }
280 return ret;
281}
282
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000283static void dwmac100_irq_status(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700284{
285 return;
286}
287
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000288static void dwmac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700289 unsigned int reg_n)
290{
291 stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
292}
293
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000294static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700295 unsigned int reg_n)
296{
297 stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
298}
299
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000300static void dwmac100_set_filter(struct net_device *dev)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700301{
302 unsigned long ioaddr = dev->base_addr;
303 u32 value = readl(ioaddr + MAC_CONTROL);
304
305 if (dev->flags & IFF_PROMISC) {
306 value |= MAC_CONTROL_PR;
307 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
308 MAC_CONTROL_HP);
Jiri Pirko4cd24ea2010-02-08 04:30:35 +0000309 } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700310 || (dev->flags & IFF_ALLMULTI)) {
311 value |= MAC_CONTROL_PM;
312 value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
313 writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
314 writel(0xffffffff, ioaddr + MAC_HASH_LOW);
Jiri Pirko4cd24ea2010-02-08 04:30:35 +0000315 } else if (netdev_mc_empty(dev)) { /* no multicast */
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700316 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
317 MAC_CONTROL_HO | MAC_CONTROL_HP);
318 } else {
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700319 u32 mc_filter[2];
320 struct dev_mc_list *mclist;
321
322 /* Perfect filter mode for physical address and Hash
323 filter for multicast */
324 value |= MAC_CONTROL_HP;
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000325 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR |
326 MAC_CONTROL_IF | MAC_CONTROL_HO);
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700327
328 memset(mc_filter, 0, sizeof(mc_filter));
Jiri Pirko55085902010-02-18 00:42:54 +0000329 netdev_for_each_mc_addr(mclist, dev) {
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700330 /* The upper 6 bits of the calculated CRC are used to
331 * index the contens of the hash table */
332 int bit_nr =
333 ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
334 /* The most significant bit determines the register to
335 * use (H/L) while the other 5 bits determine the bit
336 * within the register. */
337 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
338 }
339 writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
340 writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
341 }
342
343 writel(value, ioaddr + MAC_CONTROL);
344
345 DBG(KERN_INFO "%s: CTRL reg: 0x%08x Hash regs: "
346 "HI 0x%08x, LO 0x%08x\n",
347 __func__, readl(ioaddr + MAC_CONTROL),
348 readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
349 return;
350}
351
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000352static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700353 unsigned int fc, unsigned int pause_time)
354{
355 unsigned int flow = MAC_FLOW_CTRL_ENABLE;
356
357 if (duplex)
358 flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
359 writel(flow, ioaddr + MAC_FLOW_CTRL);
360
361 return;
362}
363
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000364/* No PMT module supported for this Ethernet Controller.
365 * Tested on ST platforms only.
366 */
367static void dwmac100_pmt(unsigned long ioaddr, unsigned long mode)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700368{
369 return;
370}
371
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000372static void dwmac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700373 int disable_rx_ic)
374{
375 int i;
376 for (i = 0; i < ring_size; i++) {
377 p->des01.rx.own = 1;
378 p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
379 if (i == ring_size - 1)
380 p->des01.rx.end_ring = 1;
381 if (disable_rx_ic)
382 p->des01.rx.disable_ic = 1;
383 p++;
384 }
385 return;
386}
387
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000388static void dwmac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700389{
390 int i;
391 for (i = 0; i < ring_size; i++) {
392 p->des01.tx.own = 0;
393 if (i == ring_size - 1)
394 p->des01.tx.end_ring = 1;
395 p++;
396 }
397 return;
398}
399
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000400static int dwmac100_get_tx_owner(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700401{
402 return p->des01.tx.own;
403}
404
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000405static int dwmac100_get_rx_owner(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700406{
407 return p->des01.rx.own;
408}
409
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000410static void dwmac100_set_tx_owner(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700411{
412 p->des01.tx.own = 1;
413}
414
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000415static void dwmac100_set_rx_owner(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700416{
417 p->des01.rx.own = 1;
418}
419
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000420static int dwmac100_get_tx_ls(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700421{
422 return p->des01.tx.last_segment;
423}
424
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000425static void dwmac100_release_tx_desc(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700426{
427 int ter = p->des01.tx.end_ring;
428
429 /* clean field used within the xmit */
430 p->des01.tx.first_segment = 0;
431 p->des01.tx.last_segment = 0;
432 p->des01.tx.buffer1_size = 0;
433
434 /* clean status reported */
435 p->des01.tx.error_summary = 0;
436 p->des01.tx.underflow_error = 0;
437 p->des01.tx.no_carrier = 0;
438 p->des01.tx.loss_carrier = 0;
439 p->des01.tx.excessive_deferral = 0;
440 p->des01.tx.excessive_collisions = 0;
441 p->des01.tx.late_collision = 0;
442 p->des01.tx.heartbeat_fail = 0;
443 p->des01.tx.deferred = 0;
444
445 /* set termination field */
446 p->des01.tx.end_ring = ter;
447
448 return;
449}
450
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000451static void dwmac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700452 int csum_flag)
453{
454 p->des01.tx.first_segment = is_fs;
455 p->des01.tx.buffer1_size = len;
456}
457
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000458static void dwmac100_clear_tx_ic(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700459{
460 p->des01.tx.interrupt = 0;
461}
462
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000463static void dwmac100_close_tx_desc(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700464{
465 p->des01.tx.last_segment = 1;
466 p->des01.tx.interrupt = 1;
467}
468
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000469static int dwmac100_get_rx_frame_len(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700470{
471 return p->des01.rx.frame_length;
472}
473
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000474struct stmmac_ops dwmac100_ops = {
475 .core_init = dwmac100_core_init,
476 .dump_regs = dwmac100_dump_mac_regs,
477 .host_irq_status = dwmac100_irq_status,
478 .set_filter = dwmac100_set_filter,
479 .flow_ctrl = dwmac100_flow_ctrl,
480 .pmt = dwmac100_pmt,
481 .set_umac_addr = dwmac100_set_umac_addr,
482 .get_umac_addr = dwmac100_get_umac_addr,
Giuseppe CAVALLAROdb98a0b2010-01-06 23:07:17 +0000483};
484
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000485struct stmmac_dma_ops dwmac100_dma_ops = {
486 .init = dwmac100_dma_init,
487 .dump_regs = dwmac100_dump_dma_regs,
488 .dma_mode = dwmac100_dma_operation_mode,
489 .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
Giuseppe CAVALLAROaec7ff22010-01-06 23:07:18 +0000490 .enable_dma_transmission = dwmac_enable_dma_transmission,
491 .enable_dma_irq = dwmac_enable_dma_irq,
492 .disable_dma_irq = dwmac_disable_dma_irq,
493 .start_tx = dwmac_dma_start_tx,
494 .stop_tx = dwmac_dma_stop_tx,
495 .start_rx = dwmac_dma_start_rx,
496 .stop_rx = dwmac_dma_stop_rx,
497 .dma_interrupt = dwmac_dma_interrupt,
Giuseppe CAVALLAROdb98a0b2010-01-06 23:07:17 +0000498};
499
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000500struct stmmac_desc_ops dwmac100_desc_ops = {
501 .tx_status = dwmac100_get_tx_frame_status,
502 .rx_status = dwmac100_get_rx_frame_status,
503 .get_tx_len = dwmac100_get_tx_len,
504 .init_rx_desc = dwmac100_init_rx_desc,
505 .init_tx_desc = dwmac100_init_tx_desc,
506 .get_tx_owner = dwmac100_get_tx_owner,
507 .get_rx_owner = dwmac100_get_rx_owner,
508 .release_tx_desc = dwmac100_release_tx_desc,
509 .prepare_tx_desc = dwmac100_prepare_tx_desc,
510 .clear_tx_ic = dwmac100_clear_tx_ic,
511 .close_tx_desc = dwmac100_close_tx_desc,
512 .get_tx_ls = dwmac100_get_tx_ls,
513 .set_tx_owner = dwmac100_set_tx_owner,
514 .set_rx_owner = dwmac100_set_rx_owner,
515 .get_rx_frame_len = dwmac100_get_rx_frame_len,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700516};
517
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000518struct mac_device_info *dwmac100_setup(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700519{
520 struct mac_device_info *mac;
521
522 mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
523
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000524 pr_info("\tDWMAC100\n");
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700525
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000526 mac->mac = &dwmac100_ops;
527 mac->desc = &dwmac100_desc_ops;
528 mac->dma = &dwmac100_dma_ops;
Giuseppe CAVALLAROdb98a0b2010-01-06 23:07:17 +0000529
530 mac->pmt = PMT_NOT_SUPPORTED;
531 mac->link.port = MAC_CONTROL_PS;
532 mac->link.duplex = MAC_CONTROL_F;
533 mac->link.speed = 0;
534 mac->mii.addr = MAC_MII_ADDR;
535 mac->mii.data = MAC_MII_DATA;
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700536
537 return mac;
538}