Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux...
[linux-2.6] / drivers / staging / epl / VirtualEthernetLinux.c
1 /****************************************************************************
2
3   (c) SYSTEC electronic GmbH, D-07973 Greiz, August-Bebel-Str. 29
4       www.systec-electronic.com
5
6   Project:      openPOWERLINK
7
8   Description:  Virtual Ethernet Driver for Linux
9
10   License:
11
12     Redistribution and use in source and binary forms, with or without
13     modification, are permitted provided that the following conditions
14     are met:
15
16     1. Redistributions of source code must retain the above copyright
17        notice, this list of conditions and the following disclaimer.
18
19     2. Redistributions in binary form must reproduce the above copyright
20        notice, this list of conditions and the following disclaimer in the
21        documentation and/or other materials provided with the distribution.
22
23     3. Neither the name of SYSTEC electronic GmbH nor the names of its
24        contributors may be used to endorse or promote products derived
25        from this software without prior written permission. For written
26        permission, please contact info@systec-electronic.com.
27
28     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29     "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30     LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
31     FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
32     COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
34     BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
35     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
36     CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
38     ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
39     POSSIBILITY OF SUCH DAMAGE.
40
41     Severability Clause:
42
43         If a provision of this License is or becomes illegal, invalid or
44         unenforceable in any jurisdiction, that shall not affect:
45         1. the validity or enforceability in that jurisdiction of any other
46            provision of this License; or
47         2. the validity or enforceability in other jurisdictions of that or
48            any other provision of this License.
49
50   -------------------------------------------------------------------------
51
52                 $RCSfile: VirtualEthernetLinux.c,v $
53
54                 $Author: D.Krueger $
55
56                 $Revision: 1.8 $  $Date: 2008/11/20 17:06:51 $
57
58                 $State: Exp $
59
60                 Build Environment:
61
62   -------------------------------------------------------------------------
63
64   Revision History:
65
66   2006/06/12 -ar:   start of the implementation, version 1.00
67
68   2006/09/18 d.k.:  integration into EPL DLLk module
69
70   ToDo:
71
72   void netif_carrier_off(struct net_device *dev);
73   void netif_carrier_on(struct net_device *dev);
74
75 ****************************************************************************/
76
77 #include <linux/version.h>
78 #include <linux/module.h>
79 #include <linux/netdevice.h>
80 #include <linux/etherdevice.h>
81 #include <linux/kernel.h>
82 #include <linux/init.h>
83 #include <linux/if_arp.h>
84 #include <net/arp.h>
85
86 #include <net/protocol.h>
87 #include <net/pkt_sched.h>
88 #include <linux/if_ether.h>
89 #include <linux/in.h>
90 #include <linux/ip.h>
91 #include <linux/udp.h>
92 #include <linux/mm.h>
93 #include <linux/types.h>
94 #include <linux/skbuff.h>       /* for struct sk_buff */
95
96 #include "kernel/VirtualEthernet.h"
97 #include "kernel/EplDllkCal.h"
98 #include "kernel/EplDllk.h"
99
100 #if(((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0)
101
102 /***************************************************************************/
103 /*                                                                         */
104 /*                                                                         */
105 /*          G L O B A L   D E F I N I T I O N S                            */
106 /*                                                                         */
107 /*                                                                         */
108 /***************************************************************************/
109
110 //---------------------------------------------------------------------------
111 // const defines
112 //---------------------------------------------------------------------------
113
114 #ifndef EPL_VETH_TX_TIMEOUT
115 //#define EPL_VETH_TX_TIMEOUT (2*HZ)
116 #define EPL_VETH_TX_TIMEOUT 0   // d.k.: we use no timeout
117 #endif
118
119 //---------------------------------------------------------------------------
120 // local types
121 //---------------------------------------------------------------------------
122
123 //---------------------------------------------------------------------------
124 // modul globale vars
125 //---------------------------------------------------------------------------
126
127 static struct net_device *pVEthNetDevice_g = NULL;
128
129 //---------------------------------------------------------------------------
130 // local function prototypes
131 //---------------------------------------------------------------------------
132
133 static int VEthOpen(struct net_device *pNetDevice_p);
134 static int VEthClose(struct net_device *pNetDevice_p);
135 static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p);
136 static struct net_device_stats *VEthGetStats(struct net_device *pNetDevice_p);
137 static void VEthTimeout(struct net_device *pNetDevice_p);
138 static tEplKernel VEthRecvFrame(tEplFrameInfo * pFrameInfo_p);
139
140 //=========================================================================//
141 //                                                                         //
142 //          P U B L I C   F U N C T I O N S                                //
143 //                                                                         //
144 //=========================================================================//
145
146 //---------------------------------------------------------------------------
147 //
148 // Function:
149 //
150 // Description:
151 //
152 //
153 //
154 // Parameters:
155 //
156 //
157 // Returns:
158 //
159 //
160 // State:
161 //
162 //---------------------------------------------------------------------------
163
164 static int VEthOpen(struct net_device *pNetDevice_p)
165 {
166         tEplKernel Ret = kEplSuccessful;
167
168         //open the device
169 //      struct net_device_stats* pStats = netdev_priv(pNetDevice_p);
170
171         //start the interface queue for the network subsystem
172         netif_start_queue(pNetDevice_p);
173
174         // register callback function in DLL
175         Ret = EplDllkRegAsyncHandler(VEthRecvFrame);
176
177         EPL_DBGLVL_VETH_TRACE1
178             ("VEthOpen: EplDllkRegAsyncHandler returned 0x%02X\n", Ret);
179
180         return 0;
181 }
182
183 static int VEthClose(struct net_device *pNetDevice_p)
184 {
185         tEplKernel Ret = kEplSuccessful;
186
187         EPL_DBGLVL_VETH_TRACE0("VEthClose\n");
188
189         Ret = EplDllkDeregAsyncHandler(VEthRecvFrame);
190
191         //stop the interface queue for the network subsystem
192         netif_stop_queue(pNetDevice_p);
193         return 0;
194 }
195
196 static int VEthXmit(struct sk_buff *pSkb_p, struct net_device *pNetDevice_p)
197 {
198         tEplKernel Ret = kEplSuccessful;
199         tEplFrameInfo FrameInfo;
200
201         //transmit function
202         struct net_device_stats *pStats = netdev_priv(pNetDevice_p);
203
204         //save timestemp
205         pNetDevice_p->trans_start = jiffies;
206
207         FrameInfo.m_pFrame = (tEplFrame *) pSkb_p->data;
208         FrameInfo.m_uiFrameSize = pSkb_p->len;
209
210         //call send fkt on DLL
211         Ret = EplDllkCalAsyncSend(&FrameInfo, kEplDllAsyncReqPrioGeneric);
212         if (Ret != kEplSuccessful) {
213                 EPL_DBGLVL_VETH_TRACE1
214                     ("VEthXmit: EplDllkCalAsyncSend returned 0x%02X\n", Ret);
215                 netif_stop_queue(pNetDevice_p);
216                 goto Exit;
217         } else {
218                 EPL_DBGLVL_VETH_TRACE0("VEthXmit: frame passed to DLL\n");
219                 dev_kfree_skb(pSkb_p);
220
221                 //set stats for the device
222                 pStats->tx_packets++;
223                 pStats->tx_bytes += FrameInfo.m_uiFrameSize;
224         }
225
226       Exit:
227         return 0;
228
229 }
230
231 static struct net_device_stats *VEthGetStats(struct net_device *pNetDevice_p)
232 {
233         EPL_DBGLVL_VETH_TRACE0("VEthGetStats\n");
234
235         return netdev_priv(pNetDevice_p);
236 }
237
238 static void VEthTimeout(struct net_device *pNetDevice_p)
239 {
240         EPL_DBGLVL_VETH_TRACE0("VEthTimeout(\n");
241
242         // $$$ d.k.: move to extra function, which is called by DLL when new space is available in TxFifo
243         if (netif_queue_stopped(pNetDevice_p)) {
244                 netif_wake_queue(pNetDevice_p);
245         }
246 }
247
248 static tEplKernel VEthRecvFrame(tEplFrameInfo * pFrameInfo_p)
249 {
250         tEplKernel Ret = kEplSuccessful;
251         struct net_device *pNetDevice = pVEthNetDevice_g;
252         struct net_device_stats *pStats = netdev_priv(pNetDevice);
253         struct sk_buff *pSkb;
254
255         EPL_DBGLVL_VETH_TRACE1("VEthRecvFrame: FrameSize=%u\n",
256                                pFrameInfo_p->m_uiFrameSize);
257
258         pSkb = dev_alloc_skb(pFrameInfo_p->m_uiFrameSize + 2);
259         if (pSkb == NULL) {
260                 pStats->rx_dropped++;
261                 goto Exit;
262         }
263         pSkb->dev = pNetDevice;
264
265         skb_reserve(pSkb, 2);
266
267         memcpy((void *)skb_put(pSkb, pFrameInfo_p->m_uiFrameSize),
268                pFrameInfo_p->m_pFrame, pFrameInfo_p->m_uiFrameSize);
269
270         pSkb->protocol = eth_type_trans(pSkb, pNetDevice);
271         pSkb->ip_summed = CHECKSUM_UNNECESSARY;
272
273         // call netif_rx with skb
274         netif_rx(pSkb);
275
276         EPL_DBGLVL_VETH_TRACE1("VEthRecvFrame: SrcMAC=0x%llx\n",
277                                AmiGetQword48FromBe(pFrameInfo_p->m_pFrame->
278                                                    m_be_abSrcMac));
279
280         // update receive statistics
281         pStats->rx_packets++;
282         pStats->rx_bytes += pFrameInfo_p->m_uiFrameSize;
283
284       Exit:
285         return Ret;
286 }
287
288 tEplKernel PUBLIC VEthAddInstance(tEplDllkInitParam * pInitParam_p)
289 {
290         tEplKernel Ret = kEplSuccessful;
291
292         // allocate net device structure with priv pointing to stats structure
293         pVEthNetDevice_g =
294             alloc_netdev(sizeof(struct net_device_stats), EPL_VETH_NAME,
295                          ether_setup);
296 //    pVEthNetDevice_g = alloc_etherdev(sizeof (struct net_device_stats));
297
298         if (pVEthNetDevice_g == NULL) {
299                 Ret = kEplNoResource;
300                 goto Exit;
301         }
302
303         pVEthNetDevice_g->open = VEthOpen;
304         pVEthNetDevice_g->stop = VEthClose;
305         pVEthNetDevice_g->get_stats = VEthGetStats;
306         pVEthNetDevice_g->hard_start_xmit = VEthXmit;
307         pVEthNetDevice_g->tx_timeout = VEthTimeout;
308         pVEthNetDevice_g->watchdog_timeo = EPL_VETH_TX_TIMEOUT;
309         pVEthNetDevice_g->destructor = free_netdev;
310
311         // copy own MAC address to net device structure
312         memcpy(pVEthNetDevice_g->dev_addr, pInitParam_p->m_be_abSrcMac, 6);
313
314         //register VEth to the network subsystem
315         if (register_netdev(pVEthNetDevice_g)) {
316                 EPL_DBGLVL_VETH_TRACE0
317                     ("VEthAddInstance: Could not register VEth...\n");
318         } else {
319                 EPL_DBGLVL_VETH_TRACE0
320                     ("VEthAddInstance: Register VEth successfull...\n");
321         }
322
323       Exit:
324         return Ret;
325 }
326
327 tEplKernel PUBLIC VEthDelInstance(void)
328 {
329         tEplKernel Ret = kEplSuccessful;
330
331         if (pVEthNetDevice_g != NULL) {
332                 //unregister VEth from the network subsystem
333                 unregister_netdev(pVEthNetDevice_g);
334                 // destructor was set to free_netdev,
335                 // so we do not need to call free_netdev here
336                 pVEthNetDevice_g = NULL;
337         }
338
339         return Ret;
340 }
341
342 #endif // (((EPL_MODULE_INTEGRATION) & (EPL_MODULE_VETH)) != 0)