make fpu emulation support configurable through kernel_menuconfig by adding a prompt...
[openwrt.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");
This page took 0.079056 seconds and 5 git commands to generate.