ar71xx: fix mac address for 5GHz interface on WNDR3700
[librecmc/librecmc.git] / target / linux / amazon / files / drivers / net / amazon_sw.c
1 /*
2  *   This program is free software; you can redistribute it and/or modify
3  *   it under the terms of the GNU General Public License as published by
4  *   the Free Software Foundation; either version 2 of the License, or
5  *   (at your option) any later version.
6  *
7  *   This program is distributed in the hope that it will be useful,
8  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *   GNU General Public License for more details.
11  *
12  *   You should have received a copy of the GNU General Public License
13  *   along with this program; if not, write to the Free Software
14  *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
15  */
16 //-----------------------------------------------------------------------
17 /*
18  * Description:
19  *      Driver for Infineon Amazon 3 port switch
20  */
21 //-----------------------------------------------------------------------
22 /* Author:      Wu Qi Ming[Qi-Ming.Wu@infineon.com]
23  * Created:     7-April-2004
24  */
25 //-----------------------------------------------------------------------
26 /* History
27  * Changed on: Jun 28, 2004
28  * Changed by: peng.liu@infineon.com
29  * Reason:      add hardware flow control (HFC) (CONFIG_NET_HW_FLOWCONTROL)
30  *
31  * Changed on: Apr 6, 2005
32  * Changed by: mars.lin@infineon.com
33  * Reason    : supoort port identification
34  */
35
36
37 // copyright 2004-2005 infineon.com
38
39 // copyright 2007 john crispin <blogic@openwrt.org>
40 // copyright 2007 felix fietkau <nbd@openwrt.org>
41
42
43 // TODO
44 //              port vlan code from bcrm target... the tawainese code was scrapped due to crappyness
45 //              check all the mmi reg settings and possibly document them better
46 //              verify the ethtool code
47 //              remove the while(1) stuff
48 //              further clean up and rework ... but it works for now
49 //              check the mode[]=bridge stuff
50 //              verify that the ethaddr can be set from u-boot
51
52
53 #ifndef __KERNEL__
54 #define __KERNEL__
55 #endif
56
57
58 #if defined(CONFIG_MODVERSIONS) && !defined(MODVERSIONS)
59 #define MODVERSIONS
60 #endif
61
62 #if defined(MODVERSIONS) && !defined(__GENKSYMS__)
63 #include <linux/modversions.h>
64 #endif
65
66 #include <linux/module.h>
67 #include <linux/string.h>
68 #include <linux/sched.h>
69 #include <linux/kernel.h>
70 #include <linux/slab.h>
71 #include <linux/errno.h>
72 #include <linux/types.h>
73 #include <linux/interrupt.h>
74 #include <linux/mii.h>
75 #include <asm/uaccess.h>
76 #include <linux/in.h>
77 #include <linux/netdevice.h>
78 #include <linux/etherdevice.h>
79 #include <linux/ip.h>
80 #include <linux/tcp.h>
81 #include <linux/skbuff.h>
82 #include <linux/in6.h>
83 #include <linux/proc_fs.h>
84 #include <linux/mm.h>
85 #include <linux/ethtool.h>
86 #include <asm/checksum.h>
87 #include <linux/init.h>
88
89 #include <asm/amazon/amazon.h>
90 #include <asm/amazon/amazon_dma.h>
91 #include <asm/amazon/amazon_sw.h>
92
93 // how many mii ports are there ?
94 #define AMAZON_SW_INT_NO 2
95
96 #define ETHERNET_PACKET_DMA_BUFFER_SIZE 1536
97
98 /***************************************** Module Parameters *************************************/
99 char mode[] = "bridge";
100 module_param_array(mode, charp, NULL, 0);
101
102 static int timeout = 1 * HZ;
103 module_param(timeout, int, 0);
104
105 int switch_init(struct net_device *dev);
106 void switch_tx_timeout(struct net_device *dev);
107
108 struct net_device switch_devs[2] = {
109         {init:switch_init,},
110         {init:switch_init,}
111 };
112
113 int add_mac_table_entry(u64 entry_value)
114 {
115         int i;
116         u32 data1, data2;
117
118         AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) = ~7;
119
120         for (i = 0; i < 32; i++) {
121                 AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0x80000000 | 0x20 | i;
122                 while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {};
123                 data1 = AMAZON_SW_REG32(AMAZON_SW_DATA1);
124                 data2 = AMAZON_SW_REG32(AMAZON_SW_DATA2);
125                 if ((data1 & (0x00700000)) != 0x00700000)
126                         continue;
127                 AMAZON_SW_REG32(AMAZON_SW_DATA1) = (u32) (entry_value >> 32);
128                 AMAZON_SW_REG32(AMAZON_SW_DATA2) = (u32) entry_value & 0xffffffff;
129                 AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0xc0000020 | i;
130                 while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {};
131                 break;
132         }
133         AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) |= 7;
134         if (i >= 32)
135                 return -1;
136         return OK;
137 }
138
139 u64 read_mac_table_entry(int index)
140 {
141         u32 data1, data2;
142         u64 value;
143         AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0x80000000 | 0x20 | index;
144         while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {};
145         data1 = AMAZON_SW_REG32(AMAZON_SW_DATA1) & 0xffffff;
146         data2 = AMAZON_SW_REG32(AMAZON_SW_DATA2);
147         value = (u64) data1 << 32 | (u64) data2;
148         return value;
149 }
150
151 int write_mac_table_entry(int index, u64 value)
152 {
153         u32 data1, data2;
154         data1 = (u32) (value >> 32);
155         data2 = (u32) value & 0xffffffff;
156         AMAZON_SW_REG32(AMAZON_SW_DATA1) = data1;
157         AMAZON_SW_REG32(AMAZON_SW_DATA2) = data2;
158         AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) = 0xc0000020 | index;
159         while (AMAZON_SW_REG32(AMAZON_SW_CPU_ACTL) & (0x80000000)) {};
160         return OK;
161 }
162
163 u32 get_mdio_reg(int phy_addr, int reg_num)
164 {
165         u32 value;
166         AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = (3 << 30) | ((phy_addr & 0x1f) << 21) | ((reg_num & 0x1f) << 16);
167         while (AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & (1 << 31)) {};
168         value = AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & 0xffff;
169         return value;
170 }
171
172 int set_mdio_reg(int phy_addr, int reg_num, u32 value)
173 {
174         AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = (2 << 30) | ((phy_addr & 0x1f) << 21) | ((reg_num & 0x1f) << 16) | (value & 0xffff);
175         while (AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) & (1 << 31)) {};
176         return OK;
177 }
178
179 int auto_negotiate(int phy_addr)
180 {
181         u32 value = 0;
182         value = get_mdio_reg(phy_addr, MDIO_BASE_CONTROL_REG);
183         set_mdio_reg(phy_addr, MDIO_BASE_CONTROL_REG, (value | RESTART_AUTO_NEGOTIATION | AUTO_NEGOTIATION_ENABLE | PHY_RESET));
184         return OK;
185 }
186
187 /*
188      In this version of switch driver, we split the dma channels for the switch.
189      2 for port0 and 2 for port1. So that we can do internal bridging if necessary.
190      In switch mode, packets coming in from port0 or port1 is able to do Destination 
191      address lookup. Packets coming from port0 with destination address of port1 should 
192      not go to pmac again. The switch hardware should be able to do the switch in the hard 
193      ware level. Packets coming from the pmac should not do the DA look up in that the
194      desination is already known for the kernel. It only needs to go to the correct NIC to 
195      find its way out.
196   */
197 int amazon_sw_chip_init(void)
198 {
199         u32 tmp1;
200         int i = 0;
201
202         /* Aging tick select: 5mins */
203         tmp1 = 0xa0;
204         if (strcmp(mode, "bridge") == 0) {
205                 // bridge mode, set militarised mode to 1, no learning!
206                 tmp1 |= 0xC00;
207         } else {
208                 // enable learning for P0 and P1,
209                 tmp1 |= 3;
210         }
211
212         /* unknown broadcast/multicast/unicast to all ports */
213         AMAZON_SW_REG32(AMAZON_SW_UN_DEST) = 0x1ff;
214
215         AMAZON_SW_REG32(AMAZON_SW_ARL_CTL) = tmp1;
216
217         /* OCS:1 set OCS bit, split the two NIC in rx direction EDL:1 (enable DA lookup) */
218 #if defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT) || defined(CONFIG_IFX_NFEXT_AMAZON_SWITCH_PHYPORT_MODULE)
219         AMAZON_SW_REG32(AMAZON_SW_P2_PCTL) = 0x700;
220 #else
221         AMAZON_SW_REG32(AMAZON_SW_P2_PCTL) = 0x401;
222 #endif
223
224         /* EPC: 1 split the two NIC in tx direction CRC is generated */
225         AMAZON_SW_REG32(AMAZON_SW_P2_CTL) = 0x6;
226
227         // for bi-directional 
228         AMAZON_SW_REG32(AMAZON_SW_P0_WM) = 0x14141412;
229         AMAZON_SW_REG32(AMAZON_SW_P1_WM) = 0x14141412;
230         AMAZON_SW_REG32(AMAZON_SW_P2_WM) = 0x28282826;
231         AMAZON_SW_REG32(AMAZON_SW_GBL_WM) = 0x0;
232
233         AMAZON_SW_REG32(AMAZON_CGU_PLL0SR) = (AMAZON_SW_REG32(AMAZON_CGU_PLL0SR)) | 0x58000000;
234         // clock for PHY
235         AMAZON_SW_REG32(AMAZON_CGU_IFCCR) =     (AMAZON_SW_REG32(AMAZON_CGU_IFCCR)) | 0x80000004;
236         // enable power for PHY
237         AMAZON_SW_REG32(AMAZON_PMU_PWDCR) = (AMAZON_SW_REG32(AMAZON_PMU_PWDCR)) | AMAZON_PMU_PWDCR_EPHY;
238         // set reverse MII, enable MDIO statemachine
239         AMAZON_SW_REG32(AMAZON_SW_MDIO_CFG) = 0x800027bf;
240         while (1)
241                 if (((AMAZON_SW_REG32(AMAZON_SW_MDIO_CFG)) & 0x80000000) == 0)
242                         break;
243         AMAZON_SW_REG32(AMAZON_SW_EPHY) = 0xff;
244
245         // auto negotiation
246         AMAZON_SW_REG32(AMAZON_SW_MDIO_ACC) = 0x83e08000;
247         auto_negotiate(0x1f);
248
249         /* enable all ports */
250         AMAZON_SW_REG32(AMAZON_SW_PS_CTL) = 0x7;
251         for (i = 0; i < 32; i++)
252                 write_mac_table_entry(i, 1 << 50);
253         return 0;
254 }
255
256 static unsigned char my_ethaddr[MAX_ADDR_LEN];
257 /* need to get the ether addr from u-boot */
258 static int __init ethaddr_setup(char *line)
259 {
260         char *ep;
261         int i;
262
263         memset(my_ethaddr, 0, MAX_ADDR_LEN);
264         for (i = 0; i < 6; i++) {
265                 my_ethaddr[i] = line ? simple_strtoul(line, &ep, 16) : 0;
266                 if (line)
267                         line = (*ep) ? ep + 1 : ep;
268         }
269         printk("mac address %2x-%2x-%2x-%2x-%2x-%2x \n", my_ethaddr[0], my_ethaddr[1], my_ethaddr[2], my_ethaddr[3], my_ethaddr[4], my_ethaddr[5]);
270         return 0;
271 }
272
273 __setup("ethaddr=", ethaddr_setup);
274
275 static void open_rx_dma(struct net_device *dev)
276 {
277         struct switch_priv *priv = (struct switch_priv *) dev->priv;
278         struct dma_device_info *dma_dev = priv->dma_device;
279         int i;
280
281         for (i = 0; i < dma_dev->num_rx_chan; i++)
282                 dma_dev->rx_chan[i].control = 1;
283         dma_device_update_rx(dma_dev);
284 }
285
286 #ifdef CONFIG_NET_HW_FLOWCONTROL
287 static void close_rx_dma(struct net_device *dev)
288 {
289         struct switch_priv *priv = (struct switch_priv *) dev->priv;
290         struct dma_device_info *dma_dev = priv->dma_device;
291         int i;
292
293         for (i = 0; i < dma_dev->num_rx_chan; i++)
294                 dma_dev->rx_chan[i].control = 0;
295         dma_device_update_rx(dma_dev);
296 }
297
298 void amazon_xon(struct net_device *dev)
299 {
300         unsigned long flag;
301         local_irq_save(flag);
302         open_rx_dma(dev);
303         local_irq_restore(flag);
304 }
305 #endif
306
307 int switch_open(struct net_device *dev)
308 {
309         struct switch_priv *priv = (struct switch_priv *) dev->priv;
310         if (!strcmp(dev->name, "eth1")) {
311                 priv->mdio_phy_addr = PHY0_ADDR;
312         }
313         open_rx_dma(dev);                       
314
315 #ifdef CONFIG_NET_HW_FLOWCONTROL
316         if ((priv->fc_bit = netdev_register_fc(dev, amazon_xon)) == 0) {
317                 printk("Hardware Flow Control register fails\n");
318         }
319 #endif
320
321         netif_start_queue(dev);
322         return OK;
323 }
324
325 int switch_release(struct net_device *dev)
326 {
327         int i;
328         struct switch_priv *priv = (struct switch_priv *) dev->priv;
329         struct dma_device_info *dma_dev = priv->dma_device;
330
331         for (i = 0; i < dma_dev->num_tx_chan; i++)
332                 dma_dev->tx_chan[i].control = 0;
333         for (i = 0; i < dma_dev->num_rx_chan; i++)
334                 dma_dev->rx_chan[i].control = 0;
335
336         dma_device_update(dma_dev);
337
338 #ifdef CONFIG_NET_HW_FLOWCONTROL
339         if (priv->fc_bit) {
340                 netdev_unregister_fc(priv->fc_bit);
341         }
342 #endif
343         netif_stop_queue(dev);
344
345         return OK;
346 }
347
348
349 void switch_rx(struct net_device *dev, int len, struct sk_buff *skb)
350 {
351         struct switch_priv *priv = (struct switch_priv *) dev->priv;
352 #ifdef CONFIG_NET_HW_FLOWCONTROL
353         int mit_sel = 0;
354 #endif
355         skb->dev = dev;
356         skb->protocol = eth_type_trans(skb, dev);
357
358 #ifdef CONFIG_NET_HW_FLOWCONTROL
359         mit_sel = netif_rx(skb);
360         switch (mit_sel) {
361         case NET_RX_SUCCESS:
362         case NET_RX_CN_LOW:
363         case NET_RX_CN_MOD:
364                 break;
365         case NET_RX_CN_HIGH:
366                 break;
367         case NET_RX_DROP:
368                 if ((priv->fc_bit)
369                         && (!test_and_set_bit(priv->fc_bit, &netdev_fc_xoff))) {
370                         close_rx_dma(dev);
371                 }
372                 break;
373         }
374 #else
375         netif_rx(skb);
376 #endif
377         priv->stats.rx_packets++;
378         priv->stats.rx_bytes += len;
379         return;
380 }
381
382 int asmlinkage switch_hw_tx(char *buf, int len, struct net_device *dev)
383 {
384         struct switch_priv *priv = dev->priv;
385         struct dma_device_info *dma_dev = priv->dma_device;
386
387         dma_dev->current_tx_chan = 0;
388         return dma_device_write(dma_dev, buf, len, priv->skb);
389 }
390
391 int asmlinkage switch_tx(struct sk_buff *skb, struct net_device *dev)
392 {
393         int len;
394         char *data;
395         struct switch_priv *priv = (struct switch_priv *) dev->priv;
396
397         len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
398         data = skb->data;
399         priv->skb = skb;
400         dev->trans_start = jiffies;
401
402         if (switch_hw_tx(data, len, dev) != len) {
403                 dev_kfree_skb_any(skb);
404                 return OK;
405         }
406
407         priv->stats.tx_packets++;
408         priv->stats.tx_bytes += len;
409         return OK;
410 }
411
412 void switch_tx_timeout(struct net_device *dev)
413 {
414         struct switch_priv *priv = (struct switch_priv *) dev->priv;
415         priv->stats.tx_errors++;
416         netif_wake_queue(dev);
417         return;
418 }
419
420 void negotiate(struct net_device *dev)
421 {
422         struct switch_priv *priv = (struct switch_priv *) dev->priv;
423         unsigned short data = get_mdio_reg(priv->mdio_phy_addr, MDIO_ADVERTISMENT_REG);
424
425         data &= ~(MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD);
426
427         switch (priv->current_speed_selection) {
428         case 10:
429                 if (priv->current_duplex == full)
430                         data |= MDIO_ADVERT_10_FD;
431                 else if (priv->current_duplex == half)
432                         data |= MDIO_ADVERT_10_HD;
433                 else
434                         data |= MDIO_ADVERT_10_HD | MDIO_ADVERT_10_FD;
435                 break;
436
437         case 100:
438                 if (priv->current_duplex == full)
439                         data |= MDIO_ADVERT_100_FD;
440                 else if (priv->current_duplex == half)
441                         data |= MDIO_ADVERT_100_HD;
442                 else
443                         data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD;
444                 break;
445
446         case 0:                                 /* Auto */
447                 if (priv->current_duplex == full)
448                         data |= MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD;
449                 else if (priv->current_duplex == half)
450                         data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_10_HD;
451                 else
452                         data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD     | MDIO_ADVERT_10_HD;
453                 break;
454
455         default:                                        /* assume autoneg speed and duplex */
456                 data |= MDIO_ADVERT_100_HD | MDIO_ADVERT_100_FD | MDIO_ADVERT_10_FD | MDIO_ADVERT_10_HD;
457         }
458
459         set_mdio_reg(priv->mdio_phy_addr, MDIO_ADVERTISMENT_REG, data);
460
461         /* Renegotiate with link partner */
462
463         data = get_mdio_reg(priv->mdio_phy_addr, MDIO_BASE_CONTROL_REG);
464         data |= MDIO_BC_NEGOTIATE;
465
466         set_mdio_reg(priv->mdio_phy_addr, MDIO_BASE_CONTROL_REG, data);
467
468 }
469
470
471 void set_duplex(struct net_device *dev, enum duplex new_duplex)
472 {
473         struct switch_priv *priv = (struct switch_priv *) dev->priv;
474         if (new_duplex != priv->current_duplex) {
475                 priv->current_duplex = new_duplex;
476                 negotiate(dev);
477         }
478 }
479
480 void set_speed(struct net_device *dev, unsigned long speed)
481 {
482         struct switch_priv *priv = (struct switch_priv *) dev->priv;
483         priv->current_speed_selection = speed;
484         negotiate(dev);
485 }
486
487 static int switch_ethtool_ioctl(struct net_device *dev, struct ifreq *ifr)
488 {
489         struct switch_priv *priv = (struct switch_priv *) dev->priv;
490         struct ethtool_cmd ecmd;
491
492         if (copy_from_user(&ecmd, ifr->ifr_data, sizeof(ecmd)))
493                 return -EFAULT;
494
495         switch (ecmd.cmd) {
496         case ETHTOOL_GSET:
497                 memset((void *) &ecmd, 0, sizeof(ecmd));
498                 ecmd.supported = SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII |     SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
499                                                 SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full;
500                 ecmd.port = PORT_TP;
501                 ecmd.transceiver = XCVR_EXTERNAL;
502                 ecmd.phy_address = priv->mdio_phy_addr;
503
504                 ecmd.speed = priv->current_speed;
505
506                 ecmd.duplex = priv->full_duplex ? DUPLEX_FULL : DUPLEX_HALF;
507
508                 ecmd.advertising = ADVERTISED_TP;
509                 if (priv->current_duplex == autoneg && priv->current_speed_selection == 0)
510                         ecmd.advertising |= ADVERTISED_Autoneg;
511                 else {
512                         ecmd.advertising |=     ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full |
513                                 ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full;
514                         if (priv->current_speed_selection == 10)
515                                 ecmd.advertising &=     ~(ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full);
516                         else if (priv->current_speed_selection == 100)
517                                 ecmd.advertising &=     ~(ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full);
518                         if (priv->current_duplex == half)
519                                 ecmd.advertising &=     ~(ADVERTISED_10baseT_Full | ADVERTISED_100baseT_Full);
520                         else if (priv->current_duplex == full)
521                                 ecmd.advertising &=     ~(ADVERTISED_10baseT_Half | ADVERTISED_100baseT_Half);
522                 }
523                 ecmd.autoneg = AUTONEG_ENABLE;
524                 if (copy_to_user(ifr->ifr_data, &ecmd, sizeof(ecmd)))
525                         return -EFAULT;
526                 break;
527
528         case ETHTOOL_SSET:
529                 if (!capable(CAP_NET_ADMIN)) {
530                         return -EPERM;
531                 }
532                 if (ecmd.autoneg == AUTONEG_ENABLE) {
533                         set_duplex(dev, autoneg);
534                         set_speed(dev, 0);
535                 } else {
536                         set_duplex(dev, ecmd.duplex == DUPLEX_HALF ? half : full);
537                         set_speed(dev, ecmd.speed == SPEED_10 ? 10 : 100);
538                 }
539                 break;
540
541         case ETHTOOL_GDRVINFO:
542                 {
543                         struct ethtool_drvinfo info;
544                         memset((void *) &info, 0, sizeof(info));
545                         strncpy(info.driver, "AMAZONE", sizeof(info.driver) - 1);
546                         strncpy(info.fw_version, "N/A", sizeof(info.fw_version) - 1);
547                         strncpy(info.bus_info, "N/A", sizeof(info.bus_info) - 1);
548                         info.regdump_len = 0;
549                         info.eedump_len = 0;
550                         info.testinfo_len = 0;
551                         if (copy_to_user(ifr->ifr_data, &info, sizeof(info)))
552                                 return -EFAULT;
553                 }
554                 break;
555         case ETHTOOL_NWAY_RST:
556                 if (priv->current_duplex == autoneg     && priv->current_speed_selection == 0)
557                         negotiate(dev);
558                 break;
559         default:
560                 return -EOPNOTSUPP;
561                 break;
562         }
563         return 0;
564 }
565
566
567
568 int mac_table_tools_ioctl(struct net_device *dev, struct mac_table_req *req)
569 {
570         int cmd;
571         int i;
572         cmd = req->cmd;
573         switch (cmd) {
574         case RESET_MAC_TABLE:
575                 for (i = 0; i < 32; i++) {
576                         write_mac_table_entry(i, 0);
577                 }
578                 break;
579         case READ_MAC_ENTRY:
580                 req->entry_value = read_mac_table_entry(req->index);
581                 break;
582         case WRITE_MAC_ENTRY:
583                 write_mac_table_entry(req->index, req->entry_value);
584                 break;
585         case ADD_MAC_ENTRY:
586                 add_mac_table_entry(req->entry_value);
587                 break;
588         default:
589                 return -EINVAL;
590         }
591
592         return 0;
593 }
594
595
596 /*
597     the ioctl for the switch driver is developed in the conventional way
598     the control type falls into some basic categories, among them, the 
599     SIOCETHTOOL is the traditional eth interface. VLAN_TOOLS and  
600     MAC_TABLE_TOOLS are designed specifically for amazon chip. User 
601     should be aware of the data structures used in these interfaces. 
602 */
603 int switch_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
604 {
605         struct data_req *switch_data_req = (struct data_req *) ifr->ifr_data;
606         struct mac_table_req *switch_mac_table_req;
607         switch (cmd) {
608         case SIOCETHTOOL:
609                 switch_ethtool_ioctl(dev, ifr);
610                 break;
611         case SIOCGMIIPHY:                       /* Get PHY address */
612                 break;
613         case SIOCGMIIREG:                       /* Read MII register */
614                 break;
615         case SIOCSMIIREG:                       /* Write MII register */
616                 break;
617         case SET_ETH_SPEED_10:          /* 10 Mbps */
618                 break;
619         case SET_ETH_SPEED_100: /* 100 Mbps */
620                 break;
621         case SET_ETH_SPEED_AUTO:        /* Auto negotiate speed */
622                 break;
623         case SET_ETH_DUPLEX_HALF:       /* Half duplex. */
624                 break;
625         case SET_ETH_DUPLEX_FULL:       /* Full duplex. */
626                 break;
627         case SET_ETH_DUPLEX_AUTO:       /* Autonegotiate duplex */
628                 break;
629         case SET_ETH_REG:
630                 AMAZON_SW_REG32(switch_data_req->index) = switch_data_req->value;
631                 break;
632         case MAC_TABLE_TOOLS:
633                 switch_mac_table_req = (struct mac_table_req *) ifr->ifr_data;
634                 mac_table_tools_ioctl(dev, switch_mac_table_req);
635                 break;
636         default:
637                 return -EINVAL;
638         }
639
640         return 0;
641 }
642
643 struct net_device_stats *switch_stats(struct net_device *dev)
644 {
645         struct switch_priv *priv = (struct switch_priv *) dev->priv;
646         return &priv->stats;
647 }
648
649 int switch_change_mtu(struct net_device *dev, int new_mtu)
650 {
651         if (new_mtu >= 1516)
652                 new_mtu = 1516;
653         dev->mtu = new_mtu;
654         return 0;
655 }
656
657 int switch_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev)
658 {
659         u8 *buf = NULL;
660         int len = 0;
661         struct sk_buff *skb = NULL;
662
663         len = dma_device_read(dma_dev, &buf, (void **) &skb);
664
665         if (len >= 0x600) {
666                 printk("packet too large %d\n", len);
667                 goto switch_hw_receive_err_exit;
668         }
669
670         /* remove CRC */
671         len -= 4;
672         if (skb == NULL) {
673                 printk("cannot restore pointer\n");
674                 goto switch_hw_receive_err_exit;
675         }
676         if (len > (skb->end - skb->tail)) {
677                 printk("BUG, len:%d end:%p tail:%p\n", (len + 4), skb->end, skb->tail);
678                 goto switch_hw_receive_err_exit;
679         }
680         skb_put(skb, len);
681         skb->dev = dev;
682         switch_rx(dev, len, skb);
683         return OK;
684   
685   switch_hw_receive_err_exit:
686         if (skb)
687                 dev_kfree_skb_any(skb);
688         return -EIO;
689 }
690
691 int dma_intr_handler(struct dma_device_info *dma_dev, int status)
692 {
693         struct net_device *dev;
694
695         dev = switch_devs + (u32) dma_dev->priv;
696         switch (status) {
697         case RCV_INT:
698                 switch_hw_receive(dev, dma_dev);
699                 break;
700         case TX_BUF_FULL_INT:
701                 netif_stop_queue(dev);
702                 break;
703         case TRANSMIT_CPT_INT:
704                 netif_wake_queue(dev);
705                 break;
706         }
707         return OK;
708 }
709
710 /* reserve 2 bytes in front of data pointer*/
711 u8 *dma_buffer_alloc(int len, int *byte_offset, void **opt)
712 {
713         u8 *buffer = NULL;
714         struct sk_buff *skb = NULL;
715         skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE);
716         if (skb == NULL) {
717                 return NULL;
718         }
719         buffer = (u8 *) (skb->data);
720         skb_reserve(skb, 2);
721         *(int *) opt = (int) skb;
722         *byte_offset = 2;
723         return buffer;
724 }
725
726 int dma_buffer_free(u8 * dataptr, void *opt)
727 {
728         struct sk_buff *skb = NULL;
729         if (opt == NULL) {
730                 kfree(dataptr);
731         } else {
732                 skb = (struct sk_buff *) opt;
733                 dev_kfree_skb_any(skb);
734         }
735         return OK;
736 }
737
738 int init_dma_device(_dma_device_info * dma_dev)
739 {
740         int i;
741         int num_tx_chan, num_rx_chan;
742         if (strcmp(dma_dev->device_name, "switch1") == 0) {
743                 num_tx_chan = 1;
744                 num_rx_chan = 2;
745                 dma_dev->priv = (void *) 0;
746         } else {
747                 num_tx_chan = 1;
748                 num_rx_chan = 2;
749                 dma_dev->priv = (void *) 1;
750         }
751
752         dma_dev->weight = 1;
753         dma_dev->num_tx_chan = num_tx_chan;
754         dma_dev->num_rx_chan = num_rx_chan;
755         dma_dev->ack = 1;
756         dma_dev->tx_burst_len = 4;
757         dma_dev->rx_burst_len = 4;
758         for (i = 0; i < dma_dev->num_tx_chan; i++) {
759                 dma_dev->tx_chan[i].weight = QOS_DEFAULT_WGT;
760                 dma_dev->tx_chan[i].desc_num = 10;
761                 dma_dev->tx_chan[i].packet_size = 0;
762                 dma_dev->tx_chan[i].control = 0;
763         }
764         for (i = 0; i < num_rx_chan; i++) {
765                 dma_dev->rx_chan[i].weight = QOS_DEFAULT_WGT;
766                 dma_dev->rx_chan[i].desc_num = 10;
767                 dma_dev->rx_chan[i].packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE;
768                 dma_dev->rx_chan[i].control = 0;
769         }
770         dma_dev->intr_handler = dma_intr_handler;
771         dma_dev->buffer_alloc = dma_buffer_alloc;
772         dma_dev->buffer_free = dma_buffer_free;
773         return 0;
774 }
775
776 int switch_set_mac_address(struct net_device *dev, void *p)
777 {
778         struct sockaddr *addr = p;
779         memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
780         return OK;
781 }
782
783
784 int switch_init(struct net_device *dev)
785 {
786         u64 retval = 0;
787         int i;
788         int result;
789         struct switch_priv *priv;
790         ether_setup(dev);                       /* assign some of the fields */
791         printk("%s up using ", dev->name);
792         dev->open = switch_open;
793         dev->stop = switch_release;
794         dev->hard_start_xmit = switch_tx;
795         dev->do_ioctl = switch_ioctl;
796         dev->get_stats = switch_stats;
797         dev->change_mtu = switch_change_mtu;
798         dev->set_mac_address = switch_set_mac_address;
799         dev->tx_timeout = switch_tx_timeout;
800         dev->watchdog_timeo = timeout;
801
802         SET_MODULE_OWNER(dev);
803
804         dev->priv = kmalloc(sizeof(struct switch_priv), GFP_KERNEL);
805         if (dev->priv == NULL)
806                 return -ENOMEM;
807         memset(dev->priv, 0, sizeof(struct switch_priv));
808         priv = dev->priv;
809         priv->dma_device = (struct dma_device_info *) kmalloc(sizeof(struct dma_device_info), GFP_KERNEL);
810         if ((dev - switch_devs) == 0) {
811                 sprintf(priv->dma_device->device_name, "switch1");
812         } else if ((dev - switch_devs) == 1) {
813                 sprintf(priv->dma_device->device_name, "switch2");
814         }
815         printk("\"%s\"\n", priv->dma_device->device_name);
816         init_dma_device(priv->dma_device);
817         result = dma_device_register(priv->dma_device);
818
819         /* read the mac address from the mac table and put them into the mac table. */
820         for (i = 0; i < 6; i++) {
821                 retval += my_ethaddr[i];
822         }
823         /* ethaddr not set in u-boot ? */
824         if (retval == 0) {
825                 dev->dev_addr[0] = 0x00;
826                 dev->dev_addr[1] = 0x20;
827                 dev->dev_addr[2] = 0xda;
828                 dev->dev_addr[3] = 0x86;
829                 dev->dev_addr[4] = 0x23;
830                 dev->dev_addr[5] = 0x74 + (unsigned char) (dev - switch_devs);
831         } else {
832                 for (i = 0; i < 6; i++) {
833                         dev->dev_addr[i] = my_ethaddr[i];
834                 }
835                 dev->dev_addr[5] += +(unsigned char) (dev - switch_devs);
836         }
837         return OK;
838 }
839
840 int switch_init_module(void)
841 {
842         int i = 0, result, device_present = 0;
843
844         for (i = 0; i < AMAZON_SW_INT_NO; i++) {
845                 sprintf(switch_devs[i].name, "eth%d", i);
846
847                 if ((result = register_netdev(switch_devs + i)))
848                         printk("error %i registering device \"%s\"\n", result, switch_devs[i].name);
849                 else
850                         device_present++;
851         }
852         amazon_sw_chip_init();
853         return device_present ? 0 : -ENODEV;
854 }
855
856 void switch_cleanup(void)
857 {
858         int i;
859         struct switch_priv *priv;
860         for (i = 0; i < AMAZON_SW_INT_NO; i++) {
861                 priv = switch_devs[i].priv;
862                 if (priv->dma_device) {
863                         dma_device_unregister(priv->dma_device);
864                         kfree(priv->dma_device);
865                 }
866                 kfree(switch_devs[i].priv);
867                 unregister_netdev(switch_devs + i);
868         }
869         return;
870 }
871
872 module_init(switch_init_module);
873 module_exit(switch_cleanup);
874
875 MODULE_LICENSE("GPL");
876 MODULE_AUTHOR("Wu Qi Ming");