blob: 576b256ee3886c992fe8848625afb6fd077842bf [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>
32
33#include "common.h"
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000034#include "dwmac100.h"
Giuseppe CAVALLAROaec7ff22010-01-06 23:07:18 +000035#include "dwmac_dma.h"
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070036
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000037#undef DWMAC100_DEBUG
38/*#define DWMAC100_DEBUG*/
39#ifdef DWMAC100_DEBUG
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070040#define DBG(fmt, args...) printk(fmt, ## args)
41#else
42#define DBG(fmt, args...) do { } while (0)
43#endif
44
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000045static void dwmac100_core_init(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070046{
47 u32 value = readl(ioaddr + MAC_CONTROL);
48
49 writel((value | MAC_CORE_INIT), ioaddr + MAC_CONTROL);
50
51#ifdef STMMAC_VLAN_TAG_USED
52 writel(ETH_P_8021Q, ioaddr + MAC_VLAN1);
53#endif
54 return;
55}
56
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000057static void dwmac100_dump_mac_regs(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070058{
59 pr_info("\t----------------------------------------------\n"
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000060 "\t DWMAC 100 CSR (base addr = 0x%8x)\n"
61 "\t----------------------------------------------\n",
62 (unsigned int)ioaddr);
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070063 pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000064 readl(ioaddr + MAC_CONTROL));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070065 pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000066 readl(ioaddr + MAC_ADDR_HIGH));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070067 pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000068 readl(ioaddr + MAC_ADDR_LOW));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070069 pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000070 MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070071 pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000072 MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070073 pr_info("\tflow control (offset 0x%x): 0x%08x\n",
74 MAC_FLOW_CTRL, readl(ioaddr + MAC_FLOW_CTRL));
75 pr_info("\tVLAN1 tag (offset 0x%x): 0x%08x\n", MAC_VLAN1,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000076 readl(ioaddr + MAC_VLAN1));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070077 pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000078 readl(ioaddr + MAC_VLAN2));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070079 pr_info("\n\tMAC management counter registers\n");
80 pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000081 MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070082 pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000083 MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070084 pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000085 MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070086 pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000087 MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070088 pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000089 MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070090 return;
91}
92
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +000093static int dwmac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -070094 u32 dma_rx)
95{
96 u32 value = readl(ioaddr + DMA_BUS_MODE);
97 /* DMA SW reset */
98 value |= DMA_BUS_MODE_SFT_RESET;
99 writel(value, ioaddr + DMA_BUS_MODE);
100 do {} while ((readl(ioaddr + DMA_BUS_MODE) & DMA_BUS_MODE_SFT_RESET));
101
102 /* Enable Application Access by writing to DMA CSR0 */
103 writel(DMA_BUS_MODE_DEFAULT | (pbl << DMA_BUS_MODE_PBL_SHIFT),
104 ioaddr + DMA_BUS_MODE);
105
106 /* Mask interrupts by writing to CSR7 */
107 writel(DMA_INTR_DEFAULT_MASK, ioaddr + DMA_INTR_ENA);
108
109 /* The base address of the RX/TX descriptor lists must be written into
110 * DMA CSR3 and CSR4, respectively. */
111 writel(dma_tx, ioaddr + DMA_TX_BASE_ADDR);
112 writel(dma_rx, ioaddr + DMA_RCV_BASE_ADDR);
113
114 return 0;
115}
116
117/* Store and Forward capability is not used at all..
118 * The transmit threshold can be programmed by
119 * setting the TTC bits in the DMA control register.*/
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000120static void dwmac100_dma_operation_mode(unsigned long ioaddr, int txmode,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700121 int rxmode)
122{
123 u32 csr6 = readl(ioaddr + DMA_CONTROL);
124
125 if (txmode <= 32)
126 csr6 |= DMA_CONTROL_TTC_32;
127 else if (txmode <= 64)
128 csr6 |= DMA_CONTROL_TTC_64;
129 else
130 csr6 |= DMA_CONTROL_TTC_128;
131
132 writel(csr6, ioaddr + DMA_CONTROL);
133
134 return;
135}
136
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000137static void dwmac100_dump_dma_regs(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700138{
139 int i;
140
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000141 DBG(KERN_DEBUG "DWMAC 100 DMA CSR \n");
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700142 for (i = 0; i < 9; i++)
143 pr_debug("\t CSR%d (offset 0x%x): 0x%08x\n", i,
144 (DMA_BUS_MODE + i * 4),
145 readl(ioaddr + DMA_BUS_MODE + i * 4));
146 DBG(KERN_DEBUG "\t CSR20 (offset 0x%x): 0x%08x\n",
147 DMA_CUR_TX_BUF_ADDR, readl(ioaddr + DMA_CUR_TX_BUF_ADDR));
148 DBG(KERN_DEBUG "\t CSR21 (offset 0x%x): 0x%08x\n",
149 DMA_CUR_RX_BUF_ADDR, readl(ioaddr + DMA_CUR_RX_BUF_ADDR));
150 return;
151}
152
153/* DMA controller has two counters to track the number of
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000154 * the receive missed frames. */
155static void dwmac100_dma_diagnostic_fr(void *data,
156 struct stmmac_extra_stats *x,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700157 unsigned long ioaddr)
158{
159 struct net_device_stats *stats = (struct net_device_stats *)data;
160 u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
161
162 if (unlikely(csr8)) {
163 if (csr8 & DMA_MISSED_FRAME_OVE) {
164 stats->rx_over_errors += 0x800;
165 x->rx_overflow_cntr += 0x800;
166 } else {
167 unsigned int ove_cntr;
168 ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
169 stats->rx_over_errors += ove_cntr;
170 x->rx_overflow_cntr += ove_cntr;
171 }
172
173 if (csr8 & DMA_MISSED_FRAME_OVE_M) {
174 stats->rx_missed_errors += 0xffff;
175 x->rx_missed_cntr += 0xffff;
176 } else {
177 unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
178 stats->rx_missed_errors += miss_f;
179 x->rx_missed_cntr += miss_f;
180 }
181 }
182 return;
183}
184
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000185static int dwmac100_get_tx_frame_status(void *data,
186 struct stmmac_extra_stats *x,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700187 struct dma_desc *p, unsigned long ioaddr)
188{
189 int ret = 0;
190 struct net_device_stats *stats = (struct net_device_stats *)data;
191
192 if (unlikely(p->des01.tx.error_summary)) {
193 if (unlikely(p->des01.tx.underflow_error)) {
194 x->tx_underflow++;
195 stats->tx_fifo_errors++;
196 }
197 if (unlikely(p->des01.tx.no_carrier)) {
198 x->tx_carrier++;
199 stats->tx_carrier_errors++;
200 }
201 if (unlikely(p->des01.tx.loss_carrier)) {
202 x->tx_losscarrier++;
203 stats->tx_carrier_errors++;
204 }
205 if (unlikely((p->des01.tx.excessive_deferral) ||
206 (p->des01.tx.excessive_collisions) ||
207 (p->des01.tx.late_collision)))
208 stats->collisions += p->des01.tx.collision_count;
209 ret = -1;
210 }
211 if (unlikely(p->des01.tx.heartbeat_fail)) {
212 x->tx_heartbeat++;
213 stats->tx_heartbeat_errors++;
214 ret = -1;
215 }
216 if (unlikely(p->des01.tx.deferred))
217 x->tx_deferred++;
218
219 return ret;
220}
221
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000222static int dwmac100_get_tx_len(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700223{
224 return p->des01.tx.buffer1_size;
225}
226
227/* This function verifies if each incoming frame has some errors
228 * and, if required, updates the multicast statistics.
229 * In case of success, it returns csum_none becasue the device
230 * is not able to compute the csum in HW. */
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000231static int dwmac100_get_rx_frame_status(void *data,
232 struct stmmac_extra_stats *x,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700233 struct dma_desc *p)
234{
235 int ret = csum_none;
236 struct net_device_stats *stats = (struct net_device_stats *)data;
237
238 if (unlikely(p->des01.rx.last_descriptor == 0)) {
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000239 pr_warning("dwmac100 Error: Oversized Ethernet "
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700240 "frame spanned multiple buffers\n");
241 stats->rx_length_errors++;
242 return discard_frame;
243 }
244
245 if (unlikely(p->des01.rx.error_summary)) {
246 if (unlikely(p->des01.rx.descriptor_error))
247 x->rx_desc++;
248 if (unlikely(p->des01.rx.partial_frame_error))
249 x->rx_partial++;
250 if (unlikely(p->des01.rx.run_frame))
251 x->rx_runt++;
252 if (unlikely(p->des01.rx.frame_too_long))
253 x->rx_toolong++;
254 if (unlikely(p->des01.rx.collision)) {
255 x->rx_collision++;
256 stats->collisions++;
257 }
258 if (unlikely(p->des01.rx.crc_error)) {
259 x->rx_crc++;
260 stats->rx_crc_errors++;
261 }
262 ret = discard_frame;
263 }
264 if (unlikely(p->des01.rx.dribbling))
265 ret = discard_frame;
266
267 if (unlikely(p->des01.rx.length_error)) {
Giuseppe Cavallaro1b924032010-02-04 09:33:21 -0800268 x->rx_length++;
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700269 ret = discard_frame;
270 }
271 if (unlikely(p->des01.rx.mii_error)) {
272 x->rx_mii++;
273 ret = discard_frame;
274 }
275 if (p->des01.rx.multicast_frame) {
276 x->rx_multicast++;
277 stats->multicast++;
278 }
279 return ret;
280}
281
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000282static void dwmac100_irq_status(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700283{
284 return;
285}
286
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000287static void dwmac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700288 unsigned int reg_n)
289{
290 stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
291}
292
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000293static void dwmac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700294 unsigned int reg_n)
295{
296 stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
297}
298
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000299static void dwmac100_set_filter(struct net_device *dev)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700300{
301 unsigned long ioaddr = dev->base_addr;
302 u32 value = readl(ioaddr + MAC_CONTROL);
303
304 if (dev->flags & IFF_PROMISC) {
305 value |= MAC_CONTROL_PR;
306 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
307 MAC_CONTROL_HP);
Jiri Pirko4cd24ea2010-02-08 04:30:35 +0000308 } else if ((netdev_mc_count(dev) > HASH_TABLE_SIZE)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700309 || (dev->flags & IFF_ALLMULTI)) {
310 value |= MAC_CONTROL_PM;
311 value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
312 writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
313 writel(0xffffffff, ioaddr + MAC_HASH_LOW);
Jiri Pirko4cd24ea2010-02-08 04:30:35 +0000314 } else if (netdev_mc_empty(dev)) { /* no multicast */
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700315 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
316 MAC_CONTROL_HO | MAC_CONTROL_HP);
317 } else {
318 int i;
319 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));
329 for (i = 0, mclist = dev->mc_list;
Jiri Pirko4cd24ea2010-02-08 04:30:35 +0000330 mclist && i < netdev_mc_count(dev); i++, mclist = mclist->next) {
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700331 /* The upper 6 bits of the calculated CRC are used to
332 * index the contens of the hash table */
333 int bit_nr =
334 ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
335 /* The most significant bit determines the register to
336 * use (H/L) while the other 5 bits determine the bit
337 * within the register. */
338 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
339 }
340 writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
341 writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
342 }
343
344 writel(value, ioaddr + MAC_CONTROL);
345
346 DBG(KERN_INFO "%s: CTRL reg: 0x%08x Hash regs: "
347 "HI 0x%08x, LO 0x%08x\n",
348 __func__, readl(ioaddr + MAC_CONTROL),
349 readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
350 return;
351}
352
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000353static void dwmac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700354 unsigned int fc, unsigned int pause_time)
355{
356 unsigned int flow = MAC_FLOW_CTRL_ENABLE;
357
358 if (duplex)
359 flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
360 writel(flow, ioaddr + MAC_FLOW_CTRL);
361
362 return;
363}
364
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000365/* No PMT module supported for this Ethernet Controller.
366 * Tested on ST platforms only.
367 */
368static void dwmac100_pmt(unsigned long ioaddr, unsigned long mode)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700369{
370 return;
371}
372
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000373static void dwmac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700374 int disable_rx_ic)
375{
376 int i;
377 for (i = 0; i < ring_size; i++) {
378 p->des01.rx.own = 1;
379 p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
380 if (i == ring_size - 1)
381 p->des01.rx.end_ring = 1;
382 if (disable_rx_ic)
383 p->des01.rx.disable_ic = 1;
384 p++;
385 }
386 return;
387}
388
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000389static void dwmac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700390{
391 int i;
392 for (i = 0; i < ring_size; i++) {
393 p->des01.tx.own = 0;
394 if (i == ring_size - 1)
395 p->des01.tx.end_ring = 1;
396 p++;
397 }
398 return;
399}
400
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000401static int dwmac100_get_tx_owner(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700402{
403 return p->des01.tx.own;
404}
405
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000406static int dwmac100_get_rx_owner(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700407{
408 return p->des01.rx.own;
409}
410
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000411static void dwmac100_set_tx_owner(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700412{
413 p->des01.tx.own = 1;
414}
415
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000416static void dwmac100_set_rx_owner(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700417{
418 p->des01.rx.own = 1;
419}
420
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000421static int dwmac100_get_tx_ls(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700422{
423 return p->des01.tx.last_segment;
424}
425
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000426static void dwmac100_release_tx_desc(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700427{
428 int ter = p->des01.tx.end_ring;
429
430 /* clean field used within the xmit */
431 p->des01.tx.first_segment = 0;
432 p->des01.tx.last_segment = 0;
433 p->des01.tx.buffer1_size = 0;
434
435 /* clean status reported */
436 p->des01.tx.error_summary = 0;
437 p->des01.tx.underflow_error = 0;
438 p->des01.tx.no_carrier = 0;
439 p->des01.tx.loss_carrier = 0;
440 p->des01.tx.excessive_deferral = 0;
441 p->des01.tx.excessive_collisions = 0;
442 p->des01.tx.late_collision = 0;
443 p->des01.tx.heartbeat_fail = 0;
444 p->des01.tx.deferred = 0;
445
446 /* set termination field */
447 p->des01.tx.end_ring = ter;
448
449 return;
450}
451
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000452static void dwmac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700453 int csum_flag)
454{
455 p->des01.tx.first_segment = is_fs;
456 p->des01.tx.buffer1_size = len;
457}
458
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000459static void dwmac100_clear_tx_ic(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700460{
461 p->des01.tx.interrupt = 0;
462}
463
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000464static void dwmac100_close_tx_desc(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700465{
466 p->des01.tx.last_segment = 1;
467 p->des01.tx.interrupt = 1;
468}
469
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000470static int dwmac100_get_rx_frame_len(struct dma_desc *p)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700471{
472 return p->des01.rx.frame_length;
473}
474
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000475struct stmmac_ops dwmac100_ops = {
476 .core_init = dwmac100_core_init,
477 .dump_regs = dwmac100_dump_mac_regs,
478 .host_irq_status = dwmac100_irq_status,
479 .set_filter = dwmac100_set_filter,
480 .flow_ctrl = dwmac100_flow_ctrl,
481 .pmt = dwmac100_pmt,
482 .set_umac_addr = dwmac100_set_umac_addr,
483 .get_umac_addr = dwmac100_get_umac_addr,
Giuseppe CAVALLAROdb98a0b2010-01-06 23:07:17 +0000484};
485
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000486struct stmmac_dma_ops dwmac100_dma_ops = {
487 .init = dwmac100_dma_init,
488 .dump_regs = dwmac100_dump_dma_regs,
489 .dma_mode = dwmac100_dma_operation_mode,
490 .dma_diagnostic_fr = dwmac100_dma_diagnostic_fr,
Giuseppe CAVALLAROaec7ff22010-01-06 23:07:18 +0000491 .enable_dma_transmission = dwmac_enable_dma_transmission,
492 .enable_dma_irq = dwmac_enable_dma_irq,
493 .disable_dma_irq = dwmac_disable_dma_irq,
494 .start_tx = dwmac_dma_start_tx,
495 .stop_tx = dwmac_dma_stop_tx,
496 .start_rx = dwmac_dma_start_rx,
497 .stop_rx = dwmac_dma_stop_rx,
498 .dma_interrupt = dwmac_dma_interrupt,
Giuseppe CAVALLAROdb98a0b2010-01-06 23:07:17 +0000499};
500
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000501struct stmmac_desc_ops dwmac100_desc_ops = {
502 .tx_status = dwmac100_get_tx_frame_status,
503 .rx_status = dwmac100_get_rx_frame_status,
504 .get_tx_len = dwmac100_get_tx_len,
505 .init_rx_desc = dwmac100_init_rx_desc,
506 .init_tx_desc = dwmac100_init_tx_desc,
507 .get_tx_owner = dwmac100_get_tx_owner,
508 .get_rx_owner = dwmac100_get_rx_owner,
509 .release_tx_desc = dwmac100_release_tx_desc,
510 .prepare_tx_desc = dwmac100_prepare_tx_desc,
511 .clear_tx_ic = dwmac100_clear_tx_ic,
512 .close_tx_desc = dwmac100_close_tx_desc,
513 .get_tx_ls = dwmac100_get_tx_ls,
514 .set_tx_owner = dwmac100_set_tx_owner,
515 .set_rx_owner = dwmac100_set_rx_owner,
516 .get_rx_frame_len = dwmac100_get_rx_frame_len,
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700517};
518
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000519struct mac_device_info *dwmac100_setup(unsigned long ioaddr)
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700520{
521 struct mac_device_info *mac;
522
523 mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
524
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000525 pr_info("\tDWMAC100\n");
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700526
Giuseppe CAVALLARO7e848ae2010-01-06 23:07:19 +0000527 mac->mac = &dwmac100_ops;
528 mac->desc = &dwmac100_desc_ops;
529 mac->dma = &dwmac100_dma_ops;
Giuseppe CAVALLAROdb98a0b2010-01-06 23:07:17 +0000530
531 mac->pmt = PMT_NOT_SUPPORTED;
532 mac->link.port = MAC_CONTROL_PS;
533 mac->link.duplex = MAC_CONTROL_F;
534 mac->link.speed = 0;
535 mac->mii.addr = MAC_MII_ADDR;
536 mac->mii.data = MAC_MII_DATA;
Giuseppe Cavallaro47dd7a52009-10-14 15:13:45 -0700537
538 return mac;
539}