aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/stmmac/mac100.c
diff options
context:
space:
mode:
authorGiuseppe Cavallaro <peppe.cavallaro@st.com>2009-10-14 18:13:45 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-14 18:13:45 -0400
commit47dd7a540b8a0cdc028914b7351fca0cf0a1d305 (patch)
treedea632b2d4175a2bf4296069047a1bc63cda5ba6 /drivers/net/stmmac/mac100.c
parent47a01a0c94a3ff1716adb5f37b83975550e1ebbb (diff)
net: add support for STMicroelectronics Ethernet controllers.
This is the driver for the ST MAC 10/100/1000 on-chip Ethernet controllers (Synopsys IP blocks). Driver documentation: o http://stlinux.com/drupal/kernel/network/stmmac Revisions: o http://stlinux.com/drupal/kernel/network/stmmac-driver-revisions Performances: o http://stlinux.com/drupal/benchmarks/networking/stmmac Signed-off-by: Giuseppe Cavallaro <peppe.cavallaro@st.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/stmmac/mac100.c')
-rw-r--r--drivers/net/stmmac/mac100.c517
1 files changed, 517 insertions, 0 deletions
diff --git a/drivers/net/stmmac/mac100.c b/drivers/net/stmmac/mac100.c
new file mode 100644
index 000000000000..625171b6062b
--- /dev/null
+++ b/drivers/net/stmmac/mac100.c
@@ -0,0 +1,517 @@
1/*******************************************************************************
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
29#include <linux/netdevice.h>
30#include <linux/crc32.h>
31#include <linux/mii.h>
32#include <linux/phy.h>
33
34#include "common.h"
35#include "mac100.h"
36
37#undef MAC100_DEBUG
38/*#define MAC100_DEBUG*/
39#ifdef MAC100_DEBUG
40#define DBG(fmt, args...) printk(fmt, ## args)
41#else
42#define DBG(fmt, args...) do { } while (0)
43#endif
44
45static void mac100_core_init(unsigned long ioaddr)
46{
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
57static void mac100_dump_mac_regs(unsigned long ioaddr)
58{
59 pr_info("\t----------------------------------------------\n"
60 "\t MAC100 CSR (base addr = 0x%8x)\n"
61 "\t----------------------------------------------\n",
62 (unsigned int)ioaddr);
63 pr_info("\tcontrol reg (offset 0x%x): 0x%08x\n", MAC_CONTROL,
64 readl(ioaddr + MAC_CONTROL));
65 pr_info("\taddr HI (offset 0x%x): 0x%08x\n ", MAC_ADDR_HIGH,
66 readl(ioaddr + MAC_ADDR_HIGH));
67 pr_info("\taddr LO (offset 0x%x): 0x%08x\n", MAC_ADDR_LOW,
68 readl(ioaddr + MAC_ADDR_LOW));
69 pr_info("\tmulticast hash HI (offset 0x%x): 0x%08x\n",
70 MAC_HASH_HIGH, readl(ioaddr + MAC_HASH_HIGH));
71 pr_info("\tmulticast hash LO (offset 0x%x): 0x%08x\n",
72 MAC_HASH_LOW, readl(ioaddr + MAC_HASH_LOW));
73 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,
76 readl(ioaddr + MAC_VLAN1));
77 pr_info("\tVLAN2 tag (offset 0x%x): 0x%08x\n", MAC_VLAN2,
78 readl(ioaddr + MAC_VLAN2));
79 pr_info("\n\tMAC management counter registers\n");
80 pr_info("\t MMC crtl (offset 0x%x): 0x%08x\n",
81 MMC_CONTROL, readl(ioaddr + MMC_CONTROL));
82 pr_info("\t MMC High Interrupt (offset 0x%x): 0x%08x\n",
83 MMC_HIGH_INTR, readl(ioaddr + MMC_HIGH_INTR));
84 pr_info("\t MMC Low Interrupt (offset 0x%x): 0x%08x\n",
85 MMC_LOW_INTR, readl(ioaddr + MMC_LOW_INTR));
86 pr_info("\t MMC High Interrupt Mask (offset 0x%x): 0x%08x\n",
87 MMC_HIGH_INTR_MASK, readl(ioaddr + MMC_HIGH_INTR_MASK));
88 pr_info("\t MMC Low Interrupt Mask (offset 0x%x): 0x%08x\n",
89 MMC_LOW_INTR_MASK, readl(ioaddr + MMC_LOW_INTR_MASK));
90 return;
91}
92
93static int mac100_dma_init(unsigned long ioaddr, int pbl, u32 dma_tx,
94 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.*/
120static void mac100_dma_operation_mode(unsigned long ioaddr, int txmode,
121 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
137static void mac100_dump_dma_regs(unsigned long ioaddr)
138{
139 int i;
140
141 DBG(KERN_DEBUG "MAC100 DMA CSR \n");
142 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
154 the receive missed frames. */
155static void mac100_dma_diagnostic_fr(void *data, struct stmmac_extra_stats *x,
156 unsigned long ioaddr)
157{
158 struct net_device_stats *stats = (struct net_device_stats *)data;
159 u32 csr8 = readl(ioaddr + DMA_MISSED_FRAME_CTR);
160
161 if (unlikely(csr8)) {
162 if (csr8 & DMA_MISSED_FRAME_OVE) {
163 stats->rx_over_errors += 0x800;
164 x->rx_overflow_cntr += 0x800;
165 } else {
166 unsigned int ove_cntr;
167 ove_cntr = ((csr8 & DMA_MISSED_FRAME_OVE_CNTR) >> 17);
168 stats->rx_over_errors += ove_cntr;
169 x->rx_overflow_cntr += ove_cntr;
170 }
171
172 if (csr8 & DMA_MISSED_FRAME_OVE_M) {
173 stats->rx_missed_errors += 0xffff;
174 x->rx_missed_cntr += 0xffff;
175 } else {
176 unsigned int miss_f = (csr8 & DMA_MISSED_FRAME_M_CNTR);
177 stats->rx_missed_errors += miss_f;
178 x->rx_missed_cntr += miss_f;
179 }
180 }
181 return;
182}
183
184static int mac100_get_tx_frame_status(void *data, struct stmmac_extra_stats *x,
185 struct dma_desc *p, unsigned long ioaddr)
186{
187 int ret = 0;
188 struct net_device_stats *stats = (struct net_device_stats *)data;
189
190 if (unlikely(p->des01.tx.error_summary)) {
191 if (unlikely(p->des01.tx.underflow_error)) {
192 x->tx_underflow++;
193 stats->tx_fifo_errors++;
194 }
195 if (unlikely(p->des01.tx.no_carrier)) {
196 x->tx_carrier++;
197 stats->tx_carrier_errors++;
198 }
199 if (unlikely(p->des01.tx.loss_carrier)) {
200 x->tx_losscarrier++;
201 stats->tx_carrier_errors++;
202 }
203 if (unlikely((p->des01.tx.excessive_deferral) ||
204 (p->des01.tx.excessive_collisions) ||
205 (p->des01.tx.late_collision)))
206 stats->collisions += p->des01.tx.collision_count;
207 ret = -1;
208 }
209 if (unlikely(p->des01.tx.heartbeat_fail)) {
210 x->tx_heartbeat++;
211 stats->tx_heartbeat_errors++;
212 ret = -1;
213 }
214 if (unlikely(p->des01.tx.deferred))
215 x->tx_deferred++;
216
217 return ret;
218}
219
220static int mac100_get_tx_len(struct dma_desc *p)
221{
222 return p->des01.tx.buffer1_size;
223}
224
225/* This function verifies if each incoming frame has some errors
226 * and, if required, updates the multicast statistics.
227 * In case of success, it returns csum_none becasue the device
228 * is not able to compute the csum in HW. */
229static int mac100_get_rx_frame_status(void *data, struct stmmac_extra_stats *x,
230 struct dma_desc *p)
231{
232 int ret = csum_none;
233 struct net_device_stats *stats = (struct net_device_stats *)data;
234
235 if (unlikely(p->des01.rx.last_descriptor == 0)) {
236 pr_warning("mac100 Error: Oversized Ethernet "
237 "frame spanned multiple buffers\n");
238 stats->rx_length_errors++;
239 return discard_frame;
240 }
241
242 if (unlikely(p->des01.rx.error_summary)) {
243 if (unlikely(p->des01.rx.descriptor_error))
244 x->rx_desc++;
245 if (unlikely(p->des01.rx.partial_frame_error))
246 x->rx_partial++;
247 if (unlikely(p->des01.rx.run_frame))
248 x->rx_runt++;
249 if (unlikely(p->des01.rx.frame_too_long))
250 x->rx_toolong++;
251 if (unlikely(p->des01.rx.collision)) {
252 x->rx_collision++;
253 stats->collisions++;
254 }
255 if (unlikely(p->des01.rx.crc_error)) {
256 x->rx_crc++;
257 stats->rx_crc_errors++;
258 }
259 ret = discard_frame;
260 }
261 if (unlikely(p->des01.rx.dribbling))
262 ret = discard_frame;
263
264 if (unlikely(p->des01.rx.length_error)) {
265 x->rx_lenght++;
266 ret = discard_frame;
267 }
268 if (unlikely(p->des01.rx.mii_error)) {
269 x->rx_mii++;
270 ret = discard_frame;
271 }
272 if (p->des01.rx.multicast_frame) {
273 x->rx_multicast++;
274 stats->multicast++;
275 }
276 return ret;
277}
278
279static void mac100_irq_status(unsigned long ioaddr)
280{
281 return;
282}
283
284static void mac100_set_umac_addr(unsigned long ioaddr, unsigned char *addr,
285 unsigned int reg_n)
286{
287 stmmac_set_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
288}
289
290static void mac100_get_umac_addr(unsigned long ioaddr, unsigned char *addr,
291 unsigned int reg_n)
292{
293 stmmac_get_mac_addr(ioaddr, addr, MAC_ADDR_HIGH, MAC_ADDR_LOW);
294}
295
296static void mac100_set_filter(struct net_device *dev)
297{
298 unsigned long ioaddr = dev->base_addr;
299 u32 value = readl(ioaddr + MAC_CONTROL);
300
301 if (dev->flags & IFF_PROMISC) {
302 value |= MAC_CONTROL_PR;
303 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_IF | MAC_CONTROL_HO |
304 MAC_CONTROL_HP);
305 } else if ((dev->mc_count > HASH_TABLE_SIZE)
306 || (dev->flags & IFF_ALLMULTI)) {
307 value |= MAC_CONTROL_PM;
308 value &= ~(MAC_CONTROL_PR | MAC_CONTROL_IF | MAC_CONTROL_HO);
309 writel(0xffffffff, ioaddr + MAC_HASH_HIGH);
310 writel(0xffffffff, ioaddr + MAC_HASH_LOW);
311 } else if (dev->mc_count == 0) { /* no multicast */
312 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF |
313 MAC_CONTROL_HO | MAC_CONTROL_HP);
314 } else {
315 int i;
316 u32 mc_filter[2];
317 struct dev_mc_list *mclist;
318
319 /* Perfect filter mode for physical address and Hash
320 filter for multicast */
321 value |= MAC_CONTROL_HP;
322 value &= ~(MAC_CONTROL_PM | MAC_CONTROL_PR | MAC_CONTROL_IF
323 | MAC_CONTROL_HO);
324
325 memset(mc_filter, 0, sizeof(mc_filter));
326 for (i = 0, mclist = dev->mc_list;
327 mclist && i < dev->mc_count; i++, mclist = mclist->next) {
328 /* The upper 6 bits of the calculated CRC are used to
329 * index the contens of the hash table */
330 int bit_nr =
331 ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26;
332 /* The most significant bit determines the register to
333 * use (H/L) while the other 5 bits determine the bit
334 * within the register. */
335 mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31);
336 }
337 writel(mc_filter[0], ioaddr + MAC_HASH_LOW);
338 writel(mc_filter[1], ioaddr + MAC_HASH_HIGH);
339 }
340
341 writel(value, ioaddr + MAC_CONTROL);
342
343 DBG(KERN_INFO "%s: CTRL reg: 0x%08x Hash regs: "
344 "HI 0x%08x, LO 0x%08x\n",
345 __func__, readl(ioaddr + MAC_CONTROL),
346 readl(ioaddr + MAC_HASH_HIGH), readl(ioaddr + MAC_HASH_LOW));
347 return;
348}
349
350static void mac100_flow_ctrl(unsigned long ioaddr, unsigned int duplex,
351 unsigned int fc, unsigned int pause_time)
352{
353 unsigned int flow = MAC_FLOW_CTRL_ENABLE;
354
355 if (duplex)
356 flow |= (pause_time << MAC_FLOW_CTRL_PT_SHIFT);
357 writel(flow, ioaddr + MAC_FLOW_CTRL);
358
359 return;
360}
361
362/* No PMT module supported in our SoC for the Ethernet Controller. */
363static void mac100_pmt(unsigned long ioaddr, unsigned long mode)
364{
365 return;
366}
367
368static void mac100_init_rx_desc(struct dma_desc *p, unsigned int ring_size,
369 int disable_rx_ic)
370{
371 int i;
372 for (i = 0; i < ring_size; i++) {
373 p->des01.rx.own = 1;
374 p->des01.rx.buffer1_size = BUF_SIZE_2KiB - 1;
375 if (i == ring_size - 1)
376 p->des01.rx.end_ring = 1;
377 if (disable_rx_ic)
378 p->des01.rx.disable_ic = 1;
379 p++;
380 }
381 return;
382}
383
384static void mac100_init_tx_desc(struct dma_desc *p, unsigned int ring_size)
385{
386 int i;
387 for (i = 0; i < ring_size; i++) {
388 p->des01.tx.own = 0;
389 if (i == ring_size - 1)
390 p->des01.tx.end_ring = 1;
391 p++;
392 }
393 return;
394}
395
396static int mac100_get_tx_owner(struct dma_desc *p)
397{
398 return p->des01.tx.own;
399}
400
401static int mac100_get_rx_owner(struct dma_desc *p)
402{
403 return p->des01.rx.own;
404}
405
406static void mac100_set_tx_owner(struct dma_desc *p)
407{
408 p->des01.tx.own = 1;
409}
410
411static void mac100_set_rx_owner(struct dma_desc *p)
412{
413 p->des01.rx.own = 1;
414}
415
416static int mac100_get_tx_ls(struct dma_desc *p)
417{
418 return p->des01.tx.last_segment;
419}
420
421static void mac100_release_tx_desc(struct dma_desc *p)
422{
423 int ter = p->des01.tx.end_ring;
424
425 /* clean field used within the xmit */
426 p->des01.tx.first_segment = 0;
427 p->des01.tx.last_segment = 0;
428 p->des01.tx.buffer1_size = 0;
429
430 /* clean status reported */
431 p->des01.tx.error_summary = 0;
432 p->des01.tx.underflow_error = 0;
433 p->des01.tx.no_carrier = 0;
434 p->des01.tx.loss_carrier = 0;
435 p->des01.tx.excessive_deferral = 0;
436 p->des01.tx.excessive_collisions = 0;
437 p->des01.tx.late_collision = 0;
438 p->des01.tx.heartbeat_fail = 0;
439 p->des01.tx.deferred = 0;
440
441 /* set termination field */
442 p->des01.tx.end_ring = ter;
443
444 return;
445}
446
447static void mac100_prepare_tx_desc(struct dma_desc *p, int is_fs, int len,
448 int csum_flag)
449{
450 p->des01.tx.first_segment = is_fs;
451 p->des01.tx.buffer1_size = len;
452}
453
454static void mac100_clear_tx_ic(struct dma_desc *p)
455{
456 p->des01.tx.interrupt = 0;
457}
458
459static void mac100_close_tx_desc(struct dma_desc *p)
460{
461 p->des01.tx.last_segment = 1;
462 p->des01.tx.interrupt = 1;
463}
464
465static int mac100_get_rx_frame_len(struct dma_desc *p)
466{
467 return p->des01.rx.frame_length;
468}
469
470struct stmmac_ops mac100_driver = {
471 .core_init = mac100_core_init,
472 .dump_mac_regs = mac100_dump_mac_regs,
473 .dma_init = mac100_dma_init,
474 .dump_dma_regs = mac100_dump_dma_regs,
475 .dma_mode = mac100_dma_operation_mode,
476 .dma_diagnostic_fr = mac100_dma_diagnostic_fr,
477 .tx_status = mac100_get_tx_frame_status,
478 .rx_status = mac100_get_rx_frame_status,
479 .get_tx_len = mac100_get_tx_len,
480 .set_filter = mac100_set_filter,
481 .flow_ctrl = mac100_flow_ctrl,
482 .pmt = mac100_pmt,
483 .init_rx_desc = mac100_init_rx_desc,
484 .init_tx_desc = mac100_init_tx_desc,
485 .get_tx_owner = mac100_get_tx_owner,
486 .get_rx_owner = mac100_get_rx_owner,
487 .release_tx_desc = mac100_release_tx_desc,
488 .prepare_tx_desc = mac100_prepare_tx_desc,
489 .clear_tx_ic = mac100_clear_tx_ic,
490 .close_tx_desc = mac100_close_tx_desc,
491 .get_tx_ls = mac100_get_tx_ls,
492 .set_tx_owner = mac100_set_tx_owner,
493 .set_rx_owner = mac100_set_rx_owner,
494 .get_rx_frame_len = mac100_get_rx_frame_len,
495 .host_irq_status = mac100_irq_status,
496 .set_umac_addr = mac100_set_umac_addr,
497 .get_umac_addr = mac100_get_umac_addr,
498};
499
500struct mac_device_info *mac100_setup(unsigned long ioaddr)
501{
502 struct mac_device_info *mac;
503
504 mac = kzalloc(sizeof(const struct mac_device_info), GFP_KERNEL);
505
506 pr_info("\tMAC 10/100\n");
507
508 mac->ops = &mac100_driver;
509 mac->hw.pmt = PMT_NOT_SUPPORTED;
510 mac->hw.link.port = MAC_CONTROL_PS;
511 mac->hw.link.duplex = MAC_CONTROL_F;
512 mac->hw.link.speed = 0;
513 mac->hw.mii.addr = MAC_MII_ADDR;
514 mac->hw.mii.data = MAC_MII_DATA;
515
516 return mac;
517}