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

1/******************************************************************************
2
3                               Copyright (c) 2007
4                            Infineon Technologies AG
5                     Am Campeon 1-12; 81726 Munich, Germany
6
7  THE DELIVERY OF THIS SOFTWARE AS WELL AS THE HEREBY GRANTED NON-EXCLUSIVE,
8  WORLDWIDE LICENSE TO USE, COPY, MODIFY, DISTRIBUTE AND SUBLICENSE THIS
9  SOFTWARE IS FREE OF CHARGE.
10
11  THE LICENSED SOFTWARE IS PROVIDED "AS IS" AND INFINEON EXPRESSLY DISCLAIMS
12  ALL REPRESENTATIONS AND WARRANTIES, WHETHER EXPRESS OR IMPLIED, INCLUDING
13  WITHOUT LIMITATION, WARRANTIES OR REPRESENTATIONS OF WORKMANSHIP,
14  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, DURABILITY, THAT THE
15  OPERATING OF THE LICENSED SOFTWARE WILL BE ERROR FREE OR FREE OF ANY THIRD
16  PARTY CLAIMS, INCLUDING WITHOUT LIMITATION CLAIMS OF THIRD PARTY INTELLECTUAL
17  PROPERTY INFRINGEMENT.
18
19  EXCEPT FOR ANY LIABILITY DUE TO WILFUL ACTS OR GROSS NEGLIGENCE AND EXCEPT
20  FOR ANY PERSONAL INJURY INFINEON SHALL IN NO EVENT BE LIABLE FOR ANY CLAIM
21  OR DAMAGES OF ANY KIND, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  DEALINGS IN THE SOFTWARE.
24
25 ****************************************************************************
26Module : svip_virtual_eth.c
27
28Description : This file contains network driver implementation for a
29Virtual Ethernet interface. The Virtual Ethernet interface
30is part of Infineon's VINETIC-SVIP Linux BSP.
31 *******************************************************************************/
32#include <linux/module.h>
33#include <linux/kernel.h>
34#include <linux/netdevice.h>
35#include <linux/platform_device.h>
36#include <linux/etherdevice.h>
37#include <linux/init.h>
38
39#define SVIP_VETH_VER_STR "3.0"
40#define SVIP_VETH_INFO_STR \
41    "@(#)SVIP virtual ethernet interface, version " SVIP_VETH_VER_STR
42
43/******************************************************************************
44 * Local define/macro definitions
45 ******************************************************************************/
46struct svip_ve_priv
47{
48    struct net_device_stats stats;
49};
50
51/******************************************************************************
52 * Global function declarations
53 ******************************************************************************/
54int svip_ve_rx(struct sk_buff *skb);
55
56/******************************************************************************
57 * Local variable declarations
58 ******************************************************************************/
59static struct net_device *svip_ve_dev;
60static int watchdog_timeout = 10*HZ;
61static int (*svip_ve_mps_xmit)(struct sk_buff *skb) = NULL;
62
63
64/******************************************************************************
65 * Global function declarations
66 ******************************************************************************/
67
68/**
69 * Called by MPS driver to register a transmit routine called for each outgoing
70 * VoFW0 message.
71 *
72 * \param mps_xmit pointer to transmit routine
73 *
74 * \return none
75 *
76 * \ingroup Internal
77 */
78void register_mps_xmit_routine(int (*mps_xmit)(struct sk_buff *skb))
79{
80    svip_ve_mps_xmit = mps_xmit;
81}
82EXPORT_SYMBOL(register_mps_xmit_routine);
83
84/**
85 * Returns a pointer to the routine used to deliver an incoming packet/message
86 * from the MPS mailbox to the networking layer. This routine is called by MPS
87 * driver during initialisation time.
88 *
89 * \param skb pointer to incoming socket buffer
90 *
91 * \return svip_ve_rx pointer to incoming messages delivering routine
92 *
93 * \ingroup Internal
94 */
95int (*register_mps_recv_routine(void)) (struct sk_buff *skb)
96{
97    return svip_ve_rx;
98}
99
100/**
101 * Used to deliver outgoing packets to VoFW0 module through the MPS driver.
102 * Upon loading/initialisation the MPS driver is registering a transmitting
103 * routine, which is called here to deliver the packet to the VoFW0 module.
104 *
105 * \param skb pointer to skb containing outgoing data
106 * \param dev pointer to this networking device's data
107 *
108 * \return 0 on success
109 * \return non-zero on error
110 *
111 * \ingroup Internal
112 */
113static int svip_ve_xmit(struct sk_buff *skb, struct net_device *dev)
114{
115    int err;
116    struct svip_ve_priv *priv = netdev_priv(dev);
117    struct net_device_stats *stats = &priv->stats;
118
119    stats->tx_packets++;
120    stats->tx_bytes += skb->len;
121
122    if (svip_ve_mps_xmit)
123    {
124        err = svip_ve_mps_xmit(skb);
125        if (err)
126            stats->tx_errors++;
127        dev->trans_start = jiffies;
128        return err;
129    }
130    else
131        printk(KERN_ERR "%s: MPS driver not registered, outgoing packet not delivered\n", dev->name);
132
133    dev_kfree_skb(skb);
134
135    return -1;
136}
137
138/**
139 * Called by MPS driver upon receipt of a new message from VoFW0 module in
140 * the data inbox. The packet is pushed up the IP module for further processing.
141 *
142 * \param skb pointer to skb containing the incoming message
143 *
144 * \return 0 on success
145 * \return non-zero on error
146 *
147 * \ingroup Internal
148 */
149int svip_ve_rx(struct sk_buff *skb)
150{
151    int err;
152    struct svip_ve_priv *priv = netdev_priv(svip_ve_dev);
153    struct net_device_stats *stats = &priv->stats;
154
155    skb->dev = svip_ve_dev;
156    skb->protocol = eth_type_trans(skb, svip_ve_dev);
157
158    stats->rx_packets++;
159    stats->rx_bytes += skb->len;
160
161    err = netif_rx(skb);
162    switch (err)
163    {
164    case NET_RX_SUCCESS:
165        return 0;
166        break;
167    case NET_RX_DROP:
168    default:
169        stats->rx_dropped++;
170        break;
171    }
172
173    return 1;
174}
175EXPORT_SYMBOL(svip_ve_rx);
176
177/**
178 * Returns a pointer to the device's networking statistics data
179 *
180 * \param dev pointer to this networking device's data
181 *
182 * \return stats pointer to this network device's statistics data
183 *
184 * \ingroup Internal
185 */
186static struct net_device_stats *svip_ve_get_stats(struct net_device *dev)
187{
188    struct svip_ve_priv *priv = netdev_priv(dev);
189
190    return &priv->stats;
191}
192
193static void svip_ve_tx_timeout(struct net_device *dev)
194{
195    struct svip_ve_priv *priv = netdev_priv(dev);
196
197    priv->stats.tx_errors++;
198    netif_wake_queue(dev);
199}
200
201/**
202 * Device open routine. Called e.g. upon setting of an IP address using,
203 * 'ifconfig veth0 YYY.YYY.YYY.YYY netmask ZZZ.ZZZ.ZZZ.ZZZ' or
204 * 'ifconfig veth0 up'
205 *
206 * \param dev pointer to this network device's data
207 *
208 * \return 0 on success
209 * \return non-zero on error
210 *
211 * \ingroup Internal
212 */
213int svip_ve_open(struct net_device *dev)
214{
215    netif_start_queue(dev);
216    return 0;
217}
218
219/**
220 * Device close routine. Called e.g. upon calling
221 * 'ifconfig veth0 down'
222 *
223 * \param dev pointer to this network device's data
224 *
225 * \return 0 on success
226 * \return non-zero on error
227 *
228 * \ingroup Internal
229 */
230
231int svip_ve_release(struct net_device *dev)
232{
233    netif_stop_queue(dev);
234    return 0;
235}
236
237static int svip_ve_dev_init(struct net_device *dev);
238
239static const struct net_device_ops svip_virtual_eth_netdev_ops = {
240    .ndo_init = svip_ve_dev_init,
241    .ndo_open = svip_ve_open,
242    .ndo_stop = svip_ve_release,
243    .ndo_start_xmit = svip_ve_xmit,
244    .ndo_get_stats = svip_ve_get_stats,
245    .ndo_tx_timeout = svip_ve_tx_timeout,
246};
247
248
249/**
250 * Device initialisation routine which registers device interface routines.
251 * It is called upon execution of 'register_netdev' routine.
252 *
253 * \param dev pointer to this network device's data
254 *
255 * \return 0 on success
256 * \return non-zero on error
257 *
258 * \ingroup Internal
259 */
260static int svip_ve_dev_init(struct net_device *dev)
261{
262    ether_setup(dev); /* assign some of the fields */
263
264    dev->watchdog_timeo = watchdog_timeout;
265    memset(netdev_priv(dev), 0, sizeof(struct svip_ve_priv));
266    dev->flags |= IFF_NOARP|IFF_PROMISC;
267    dev->flags &= ~IFF_MULTICAST;
268
269    /* dedicated MAC address to veth0, 00:03:19:00:15:80 */
270    dev->dev_addr[0] = 0x00;
271    dev->dev_addr[1] = 0x03;
272    dev->dev_addr[2] = 0x19;
273    dev->dev_addr[3] = 0x00;
274    dev->dev_addr[4] = 0x15;
275    dev->dev_addr[5] = 0x80;
276
277    return 0;
278}
279
280static int svip_ve_probe(struct platform_device *dev)
281{
282    int result = 0;
283
284    svip_ve_dev = alloc_etherdev(sizeof(struct svip_ve_priv));
285    svip_ve_dev->netdev_ops = &svip_virtual_eth_netdev_ops;
286
287    strcpy(svip_ve_dev->name, "veth%d");
288
289    result = register_netdev(svip_ve_dev);
290    if (result)
291    {
292        printk(KERN_INFO "error %i registering device \"%s\"\n", result, svip_ve_dev->name);
293        goto out;
294    }
295
296    printk (KERN_INFO "%s, (c) 2009, Lantiq Deutschland GmbH\n", &SVIP_VETH_INFO_STR[4]);
297
298out:
299    return result;
300}
301
302static int svip_ve_remove(struct platform_device *dev)
303{
304    unregister_netdev(svip_ve_dev);
305    free_netdev(svip_ve_dev);
306
307    printk(KERN_INFO "%s removed\n", svip_ve_dev->name);
308    return 0;
309}
310
311static struct platform_driver svip_ve_driver = {
312    .probe = svip_ve_probe,
313    .remove = svip_ve_remove,
314    .driver = {
315        .name = "ifxmips_svip_ve",
316        .owner = THIS_MODULE,
317    },
318};
319
320/**
321 * Module/driver entry routine
322 */
323static int __init svip_ve_init_module(void)
324{
325    int ret;
326
327    ret = platform_driver_register(&svip_ve_driver);
328    if (ret)
329        printk(KERN_INFO "SVIP: error(%d) registering virtual Ethernet driver!\n", ret);
330    return ret;
331}
332
333/**
334 * Module exit routine (never called for statically linked driver)
335 */
336static void __exit svip_ve_cleanup_module(void)
337{
338    platform_driver_unregister(&svip_ve_driver);
339}
340
341module_init(svip_ve_init_module);
342module_exit(svip_ve_cleanup_module);
343MODULE_LICENSE("GPL");
344MODULE_DESCRIPTION("virtual ethernet driver for LANTIQ SVIP system");
345
346EXPORT_SYMBOL(register_mps_recv_routine);
347

Archive Download this file



interactive