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