Root/target/linux/lantiq/files/drivers/net/ethernet/svip_eth.c

1/************************************************************************
2 *
3 * Copyright (c) 2005
4 * Infineon Technologies AG
5 * St. Martin Strasse 53; 81669 Muenchen; Germany
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
11 *
12 ************************************************************************/
13
14#include <linux/kernel.h>
15#include <linux/slab.h>
16#include <linux/errno.h>
17#include <linux/types.h>
18#include <linux/interrupt.h>
19#include <linux/uaccess.h>
20#include <linux/in.h>
21#include <linux/netdevice.h>
22#include <linux/etherdevice.h>
23#include <linux/ip.h>
24#include <linux/tcp.h>
25#include <linux/skbuff.h>
26#include <linux/mm.h>
27#include <linux/platform_device.h>
28#include <linux/ethtool.h>
29#include <linux/init.h>
30#include <linux/module.h>
31#include <linux/delay.h>
32#include <asm/checksum.h>
33
34#if 1 /** TODO: MOVE TO APPROPRIATE PLACE */
35
36#define ETHERNET_PACKET_DMA_BUFFER_SIZE 0x600
37#define REV_MII_MODE 2
38
39#endif
40
41#define DRV_NAME "ifxmips_mii0"
42
43#include <lantiq_soc.h>
44#include <svip_dma.h>
45
46#ifdef CONFIG_DEBUG_MINI_BOOT
47#define IKOS_MINI_BOOT
48#endif
49
50/* debugging */
51#undef INCAIP2_SW_DUMP
52
53#define INCAIP2_SW_EMSG(fmt,args...) printk("%s: " fmt, __FUNCTION__ , ##args)
54
55#define INCAIP2_SW_CHIP_NO 1
56#define INCAIP2_SW_CHIP_ID 0
57#define INCAIP2_SW_DEVICE_NO 1
58
59#ifdef INCAIP2_SW_DEBUG_MSG
60#define INCAIP2_SW_DMSG(fmt,args...) printk("%s: " fmt, __FUNCTION__ , ##args)
61#else
62#define INCAIP2_SW_DMSG(fmt,args...)
63#endif
64
65/************************** Module Parameters *****************************/
66static char *mode = "bridge";
67module_param(mode, charp, 0000);
68MODULE_PARM_DESC(mode, "<description>");
69
70#ifdef HAVE_TX_TIMEOUT
71static int timeout = 10*HZ;
72module_param(timeout, int, 0);
73MODULE_PARM_DESC(timeout, "Transmission watchdog timeout in seconds>");
74#endif
75
76#ifdef IKOS_MINI_BOOT
77#ifdef CONFIG_INCAIP2
78extern s32 incaip2_sw_to_mbx(struct sk_buff* skb);
79#endif
80extern s32 svip_sw_to_mbx(struct sk_buff* skb);
81#endif
82
83struct svip_mii_priv {
84    struct net_device_stats stats;
85    struct dma_device_info *dma_device;
86    struct sk_buff *skb;
87};
88
89static struct net_device *svip_mii0_dev;
90static unsigned char mac_addr[MAX_ADDR_LEN];
91static unsigned char my_ethaddr[MAX_ADDR_LEN];
92
93/**
94 * Initialize MAC address.
95 * This function copies the ethernet address from kernel command line.
96 *
97 * \param line Pointer to parameter
98 * \return 0 OK
99 * \ingroup Internal
100 */
101static int __init svip_eth_ethaddr_setup(char *line)
102{
103    char *ep;
104    int i;
105
106    memset(my_ethaddr, 0, MAX_ADDR_LEN);
107    /* there should really be routines to do this stuff */
108    for (i = 0; i < 6; i++)
109    {
110        my_ethaddr[i] = line ? simple_strtoul(line, &ep, 16) : 0;
111        if (line)
112            line = (*ep) ? ep+1 : ep;
113    }
114    INCAIP2_SW_DMSG("mac address %2x-%2x-%2x-%2x-%2x-%2x \n"
115            ,my_ethaddr[0]
116            ,my_ethaddr[1]
117            ,my_ethaddr[2]
118            ,my_ethaddr[3]
119            ,my_ethaddr[4]
120            ,my_ethaddr[5]);
121    return 0;
122}
123__setup("ethaddr=", svip_eth_ethaddr_setup);
124
125
126/**
127 * Open RX DMA channels.
128 * This function opens all DMA rx channels.
129 *
130 * \param dma_dev pointer to DMA device information
131 * \ingroup Internal
132 */
133static void svip_eth_open_rx_dma(struct dma_device_info *dma_dev)
134{
135    int i;
136
137    for(i=0; i<dma_dev->num_rx_chan; i++)
138    {
139        dma_dev->rx_chan[i]->open(dma_dev->rx_chan[i]);
140    }
141}
142
143
144/**
145 * Open TX DMA channels.
146 * This function opens all DMA tx channels.
147 *
148 * \param dev pointer to net device structure that comprises
149 * DMA device information pointed to by it's priv field.
150 * \ingroup Internal
151 */
152static void svip_eth_open_tx_dma(struct dma_device_info *dma_dev)
153{
154    int i;
155
156    for (i=0; i<dma_dev->num_tx_chan; i++)
157    {
158        dma_dev->tx_chan[i]->open(dma_dev->tx_chan[i]);
159    }
160}
161
162
163#ifdef CONFIG_NET_HW_FLOWCONTROL
164/**
165 * Enable receiving DMA.
166 * This function enables the receiving DMA channel.
167 *
168 * \param dev pointer to net device structure that comprises
169 * DMA device information pointed to by it's priv field.
170 * \ingroup Internal
171 */
172void svip_eth_xon(struct net_device *dev)
173{
174    struct switch_priv *sw_dev = (struct switch_priv *)dev->priv;
175    struct dma_device_info* dma_dev =
176        (struct dma_device_info *)sw_dev->dma_device;
177    unsigned long flag;
178
179    local_irq_save(flag);
180
181    INCAIP2_SW_DMSG("wakeup\n");
182    svip_eth_open_rx_dma(dma_dev);
183
184    local_irq_restore(flag);
185}
186#endif /* CONFIG_NET_HW_FLOWCONTROL */
187
188
189/**
190 * Open network device.
191 * This functions opens the network device and starts the interface queue.
192 *
193 * \param dev Device structure for Ethernet device
194 * \return 0 OK, device opened
195 * \return -1 Error, registering DMA device
196 * \ingroup API
197 */
198int svip_mii_open(struct net_device *dev)
199{
200    struct svip_mii_priv *priv = netdev_priv(dev);
201    struct dma_device_info *dma_dev = priv->dma_device;
202
203    svip_eth_open_rx_dma(dma_dev);
204    svip_eth_open_tx_dma(dma_dev);
205
206    netif_start_queue(dev);
207    return 0;
208}
209
210
211/**
212 * Close network device.
213 * This functions closes the network device, which will also stop the interface
214 * queue.
215 *
216 * \param dev Device structure for Ethernet device
217 * \return 0 OK, device closed (cannot fail)
218 * \ingroup API
219 */
220int svip_mii_release(struct net_device *dev)
221{
222    struct svip_mii_priv *priv = netdev_priv(dev);
223    struct dma_device_info *dma_dev = priv->dma_device;
224    int i;
225
226    for (i = 0; i < dma_dev->max_rx_chan_num; i++)
227        dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]);
228    netif_stop_queue(dev);
229    return 0;
230}
231
232
233/**
234 * Read data from DMA device.
235 * This function reads data from the DMA device. The function is called by
236 * the switch/DMA pseudo interrupt handler dma_intr_handler on occurence of
237 * a DMA receive interrupt.
238 *
239 * \param dev Pointer to network device structure
240 * \param dma_dev Pointer to dma device structure
241 * \return OK In case of successful data reception from dma
242 * -EIO Incorrect opt pointer provided by device
243 * \ingroup Internal
244 */
245int svip_mii_hw_receive(struct net_device *dev, struct dma_device_info *dma_dev)
246{
247    struct svip_mii_priv *priv = netdev_priv(dev);
248    unsigned char *buf = NULL;
249    struct sk_buff *skb = NULL;
250    int len = 0;
251
252    len = dma_device_read(dma_dev, &buf, (void **)&skb);
253
254    if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) {
255        printk(KERN_INFO DRV_NAME ": packet too large %d\n", len);
256        goto mii_hw_receive_err_exit;
257    }
258
259    if (skb == NULL) {
260        printk(KERN_INFO DRV_NAME ": cannot restore pointer\n");
261        goto mii_hw_receive_err_exit;
262    }
263
264    if (len > (skb->end - skb->tail)) {
265        printk(KERN_INFO DRV_NAME ": BUG, len:%d end:%p tail:%p\n",
266               len, skb->end, skb->tail);
267        goto mii_hw_receive_err_exit;
268    }
269
270    skb_put(skb, len);
271    skb->dev = dev;
272    skb->protocol = eth_type_trans(skb, dev);
273    netif_rx(skb);
274
275    priv->stats.rx_packets++;
276    priv->stats.rx_bytes += len;
277    return 0;
278
279mii_hw_receive_err_exit:
280    if (len == 0) {
281        if (skb)
282            dev_kfree_skb_any(skb);
283        priv->stats.rx_errors++;
284        priv->stats.rx_dropped++;
285        return -EIO;
286    } else {
287        return len;
288    }
289}
290
291
292/**
293 * Write data to Ethernet switch.
294 * This function writes the data comprised in skb structure via DMA to the
295 * Ethernet Switch. It is installed as the switch driver's hard_start_xmit
296 * method.
297 *
298 * \param skb Pointer to socket buffer structure that contains the data
299 * to be sent
300 * \param dev Pointer to network device structure which is used for
301 * data transmission
302 * \return 1 Transmission error
303 * \return 0 OK, successful data transmission
304 * \ingroup API
305 */
306static int svip_mii_hw_tx(char *buf, int len, struct net_device *dev)
307{
308    int ret = 0;
309    struct svip_mii_priv *priv = netdev_priv(dev);
310    struct dma_device_info *dma_dev = priv->dma_device;
311    ret = dma_device_write(dma_dev, buf, len, priv->skb);
312    return ret;
313}
314
315static int svip_mii_tx(struct sk_buff *skb, struct net_device *dev)
316{
317    int len;
318    char *data;
319    struct svip_mii_priv *priv = netdev_priv(dev);
320    struct dma_device_info *dma_dev = priv->dma_device;
321
322    len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len;
323    data = skb->data;
324    priv->skb = skb;
325    dev->trans_start = jiffies;
326    /* TODO: we got more than 1 dma channel,
327       so we should do something intelligent here to select one */
328    dma_dev->current_tx_chan = 0;
329
330    wmb();
331
332    if (svip_mii_hw_tx(data, len, dev) != len) {
333        dev_kfree_skb_any(skb);
334        priv->stats.tx_errors++;
335        priv->stats.tx_dropped++;
336    } else {
337        priv->stats.tx_packets++;
338        priv->stats.tx_bytes += len;
339    }
340
341    return 0;
342}
343
344
345/**
346 * Transmission timeout callback.
347 * This functions is called when a trasmission timeout occurs. It will wake up
348 * the interface queue again.
349 *
350 * \param dev Device structure for Ethernet device
351 * \ingroup API
352 */
353void svip_mii_tx_timeout(struct net_device *dev)
354{
355    int i;
356    struct svip_mii_priv *priv = netdev_priv(dev);
357
358    priv->stats.tx_errors++;
359    for (i = 0; i < priv->dma_device->max_tx_chan_num; i++)
360        priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]);
361    netif_wake_queue(dev);
362    return;
363}
364
365
366/**
367 * Get device statistics.
368 * This functions returns the device statistics, stored in the device structure.
369 *
370 * \param dev Device structure for Ethernet device
371 * \return stats Pointer to statistics structure
372 * \ingroup API
373 */
374static struct net_device_stats *svip_get_stats(struct net_device *dev)
375{
376    struct svip_mii_priv *priv = netdev_priv(dev);
377    return &priv->stats;
378}
379
380
381/**
382 * Pseudo Interrupt handler for DMA.
383 * This function processes DMA interrupts notified to the switch device driver.
384 * The function is installed at the DMA core as interrupt handler for the
385 * switch dma device.
386 * It handles the following DMA interrupts:
387 * passes received data to the upper layer in case of rx interrupt,
388 * In case of a dma receive interrupt the received data is passed to the upper layer.
389 * In case of a transmit buffer full interrupt the transmit queue is stopped.
390 * In case of a transmission complete interrupt the transmit queue is restarted.
391 *
392 * \param dma_dev pointer to dma device structure
393 * \param status type of interrupt being notified (RCV_INT: dma receive
394 * interrupt, TX_BUF_FULL_INT: transmit buffer full interrupt,
395 * TRANSMIT_CPT_INT: transmission complete interrupt)
396 * \return OK In case of successful data reception from dma
397 * \ingroup Internal
398 */
399int dma_intr_handler(struct dma_device_info *dma_dev, int status)
400{
401    int i;
402
403    switch (status) {
404    case RCV_INT:
405        svip_mii_hw_receive(svip_mii0_dev, dma_dev);
406        break;
407
408    case TX_BUF_FULL_INT:
409        printk(KERN_INFO DRV_NAME ": tx buffer full\n");
410        netif_stop_queue(svip_mii0_dev);
411        for (i = 0; i < dma_dev->max_tx_chan_num; i++) {
412            if ((dma_dev->tx_chan[i])->control == LTQ_DMA_CH_ON)
413                dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]);
414        }
415        break;
416
417    case TRANSMIT_CPT_INT:
418
419#if 0
420        for (i = 0; i < dma_dev->max_tx_chan_num; i++)
421#if 0
422            dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]);
423#else
424        dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i], (char *)__FUNCTION__);
425#endif
426        netif_wake_queue(svip_mii0_dev);
427#endif
428        break;
429    }
430
431    return 0;
432}
433
434
435/**
436 * Allocates buffer sufficient for Ethernet Frame.
437 * This function is installed as DMA callback function to be called on DMA
438 * receive interrupt.
439 *
440 * \param len Unused
441 * \param *byte_offset Pointer to byte offset
442 * \param **opt pointer to skb structure
443 * \return NULL In case of buffer allocation fails
444 * buffer Pointer to allocated memory
445 * \ingroup Internal
446 */
447unsigned char *svip_etop_dma_buffer_alloc(int len, int *byte_offset, void **opt)
448{
449    unsigned char *buffer = NULL;
450    struct sk_buff *skb = NULL;
451
452    skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE);
453    if (skb == NULL)
454        return NULL;
455
456    buffer = (unsigned char *)(skb->data);
457    skb_reserve(skb, 2);
458    *(int *)opt = (int)skb;
459    *byte_offset = 2;
460
461    return buffer;
462}
463
464
465/**
466 * Free DMA buffer.
467 * This function frees a buffer, which can be either a data buffer or an
468 * skb structure.
469 *
470 * \param *dataptr Pointer to data buffer
471 * \param *opt Pointer to skb structure
472 * \return 0 OK
473 * \ingroup Internal
474 */
475void svip_etop_dma_buffer_free(unsigned char *dataptr, void *opt)
476{
477    struct sk_buff *skb = NULL;
478
479    if (opt == NULL) {
480        kfree(dataptr);
481    } else {
482        skb = (struct sk_buff *)opt;
483        dev_kfree_skb_any(skb);
484    }
485}
486
487static int svip_mii_dev_init(struct net_device *dev);
488
489static const struct net_device_ops svip_eth_netdev_ops = {
490    .ndo_init = svip_mii_dev_init,
491    .ndo_open = svip_mii_open,
492    .ndo_stop = svip_mii_release,
493    .ndo_start_xmit = svip_mii_tx,
494    .ndo_get_stats = svip_get_stats,
495    .ndo_tx_timeout = svip_mii_tx_timeout,
496};
497
498//#include <linux/device.h>
499
500/**
501 * Initialize switch driver.
502 * This functions initializes the switch driver structures and registers the
503 * Ethernet device.
504 *
505 * \param dev Device structure for Ethernet device
506 * \return 0 OK
507 * \return ENOMEM No memory for structures available
508 * \return -1 Error during DMA init or Ethernet address configuration.
509 * \ingroup API
510 */
511static int svip_mii_dev_init(struct net_device *dev)
512{
513    int i;
514    struct svip_mii_priv *priv = netdev_priv(dev);
515
516
517    ether_setup(dev);
518    printk(KERN_INFO DRV_NAME ": %s is up\n", dev->name);
519    dev->watchdog_timeo = 10 * HZ;
520    memset(priv, 0, sizeof(*priv));
521    priv->dma_device = dma_device_reserve("SW");
522    if (!priv->dma_device) {
523        BUG();
524        return -ENODEV;
525    }
526    priv->dma_device->buffer_alloc = svip_etop_dma_buffer_alloc;
527    priv->dma_device->buffer_free = svip_etop_dma_buffer_free;
528    priv->dma_device->intr_handler = dma_intr_handler;
529
530    for (i = 0; i < priv->dma_device->max_rx_chan_num; i++)
531        priv->dma_device->rx_chan[i]->packet_size =
532            ETHERNET_PACKET_DMA_BUFFER_SIZE;
533
534    for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) {
535        priv->dma_device->tx_chan[i]->tx_weight=DEFAULT_SW_CHANNEL_WEIGHT;
536        priv->dma_device->tx_chan[i]->packet_size =
537            ETHERNET_PACKET_DMA_BUFFER_SIZE;
538    }
539
540    dma_device_register(priv->dma_device);
541
542    printk(KERN_INFO DRV_NAME ": using mac=");
543
544    for (i = 0; i < 6; i++) {
545        dev->dev_addr[i] = mac_addr[i];
546        printk("%02X%c", dev->dev_addr[i], (i == 5) ? ('\n') : (':'));
547    }
548
549    return 0;
550}
551
552static void svip_mii_chip_init(int mode)
553{
554}
555
556static int svip_mii_probe(struct platform_device *dev)
557{
558    int result = 0;
559    unsigned char *mac = (unsigned char *)dev->dev.platform_data;
560    svip_mii0_dev = alloc_etherdev(sizeof(struct svip_mii_priv));
561    svip_mii0_dev->netdev_ops = &svip_eth_netdev_ops;
562    memcpy(mac_addr, mac, 6);
563    strcpy(svip_mii0_dev->name, "eth%d");
564    svip_mii_chip_init(REV_MII_MODE);
565    result = register_netdev(svip_mii0_dev);
566    if (result) {
567        printk(KERN_INFO DRV_NAME
568               ": error %i registering device \"%s\"\n",
569               result, svip_mii0_dev->name);
570        goto out;
571    }
572    printk(KERN_INFO DRV_NAME ": driver loaded!\n");
573
574out:
575    return result;
576}
577
578static int svip_mii_remove(struct platform_device *dev)
579{
580    struct svip_mii_priv *priv = netdev_priv(svip_mii0_dev);
581
582    printk(KERN_INFO DRV_NAME ": cleanup\n");
583
584    dma_device_unregister(priv->dma_device);
585    dma_device_release(priv->dma_device);
586    kfree(priv->dma_device);
587    unregister_netdev(svip_mii0_dev);
588    free_netdev(svip_mii0_dev);
589    return 0;
590}
591
592
593static struct platform_driver svip_mii_driver = {
594    .probe = svip_mii_probe,
595    .remove = svip_mii_remove,
596    .driver = {
597        .name = DRV_NAME,
598        .owner = THIS_MODULE,
599    },
600};
601
602
603/**
604 * Initialize switch driver as module.
605 * This functions initializes the switch driver structures and registers the
606 * Ethernet device for module usage.
607 *
608 * \return 0 OK
609 * \return ENODEV An error occured during initialization
610 * \ingroup API
611 */
612int __init svip_mii_init(void)
613{
614    int ret = platform_driver_register(&svip_mii_driver);
615    if (ret)
616        printk(KERN_INFO DRV_NAME
617               ": Error registering platfom driver!\n");
618    return ret;
619}
620
621
622/**
623 * Remove driver module.
624 * This functions removes the driver and unregisters all devices.
625 *
626 * \ingroup API
627 */
628static void __exit svip_mii_cleanup(void)
629{
630    platform_driver_unregister(&svip_mii_driver);
631}
632
633module_init(svip_mii_init);
634module_exit(svip_mii_cleanup);
635
636MODULE_LICENSE("GPL");
637

Archive Download this file



interactive