blob: 11f2cce260054497246fc8b328c632720cdb740c [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/* $Id: hysdn_net.c,v 1.8.6.4 2001/09/23 22:24:54 kai Exp $
2 *
3 * Linux driver for HYSDN cards, net (ethernet type) handling routines.
4 *
5 * Author Werner Cornelius (werner@titro.de) for Hypercope GmbH
6 * Copyright 1999 by Werner Cornelius (werner@titro.de)
7 *
8 * This software may be used and distributed according to the terms
9 * of the GNU General Public License, incorporated herein by reference.
10 *
11 * This net module has been inspired by the skeleton driver from
12 * Donald Becker (becker@CESDIS.gsfc.nasa.gov)
13 *
14 */
15
16#include <linux/module.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/signal.h>
18#include <linux/kernel.h>
19#include <linux/netdevice.h>
20#include <linux/etherdevice.h>
21#include <linux/skbuff.h>
22#include <linux/inetdevice.h>
23
24#include "hysdn_defs.h"
25
26unsigned int hynet_enable = 0xffffffff;
Rusty Russell8d3b33f2006-03-25 03:07:05 -080027module_param(hynet_enable, uint, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -070028
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */
30
31/****************************************************************************/
32/* structure containing the complete network data. The structure is aligned */
33/* in a way that both, the device and statistics are kept inside it. */
34/* for proper access, the device structure MUST be the first var/struct */
35/* inside the definition. */
36/****************************************************************************/
37struct net_local {
Linus Torvalds1da177e2005-04-16 15:20:36 -070038 /* Tx control lock. This protects the transmit buffer ring
39 * state along with the "tx full" state of the driver. This
40 * means all netif_queue flow control actions are protected
41 * by this lock as well.
42 */
Stephen Hemminger0e2445f2009-01-07 18:03:43 -080043 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -070044 spinlock_t lock;
45 struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */
46 int in_idx, out_idx; /* indexes to buffer ring */
47 int sk_count; /* number of buffers currently in ring */
48}; /* net_local */
49
50
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52/*********************************************************************/
53/* Open/initialize the board. This is called (in the current kernel) */
54/* sometime after booting when the 'ifconfig' program is run. */
55/* This routine should set everything up anew at each open, even */
56/* registers that "should" only need to be set once at boot, so that */
57/* there is non-reboot way to recover if something goes wrong. */
58/*********************************************************************/
59static int
60net_open(struct net_device *dev)
61{
62 struct in_device *in_dev;
Wang Chen25dd7e62008-12-03 15:49:07 -080063 hysdn_card *card = dev->ml_priv;
Linus Torvalds1da177e2005-04-16 15:20:36 -070064 int i;
65
66 netif_start_queue(dev); /* start tx-queueing */
67
68 /* Fill in the MAC-level header (if not already set) */
69 if (!card->mac_addr[0]) {
Pascal Terjanbd091412008-12-01 12:24:25 +000070 for (i = 0; i < ETH_ALEN; i++)
Linus Torvalds1da177e2005-04-16 15:20:36 -070071 dev->dev_addr[i] = 0xfc;
72 if ((in_dev = dev->ip_ptr) != NULL) {
73 struct in_ifaddr *ifa = in_dev->ifa_list;
74 if (ifa != NULL)
Pascal Terjanbd091412008-12-01 12:24:25 +000075 memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local));
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 }
77 } else
78 memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
79
80 return (0);
81} /* net_open */
82
83/*******************************************/
84/* flush the currently occupied tx-buffers */
85/* must only be called when device closed */
86/*******************************************/
87static void
88flush_tx_buffers(struct net_local *nl)
89{
90
91 while (nl->sk_count) {
92 dev_kfree_skb(nl->skbs[nl->out_idx++]); /* free skb */
93 if (nl->out_idx >= MAX_SKB_BUFFERS)
94 nl->out_idx = 0; /* wrap around */
95 nl->sk_count--;
96 }
97} /* flush_tx_buffers */
98
99
100/*********************************************************************/
101/* close/decativate the device. The device is not removed, but only */
102/* deactivated. */
103/*********************************************************************/
104static int
105net_close(struct net_device *dev)
106{
107
108 netif_stop_queue(dev); /* disable queueing */
109
110 flush_tx_buffers((struct net_local *) dev);
111
112 return (0); /* success */
113} /* net_close */
114
115/************************************/
116/* send a packet on this interface. */
117/* new style for kernel >= 2.3.33 */
118/************************************/
Stephen Hemminger8b62ff22009-08-31 19:50:44 +0000119static netdev_tx_t
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120net_send_packet(struct sk_buff *skb, struct net_device *dev)
121{
122 struct net_local *lp = (struct net_local *) dev;
123
124 spin_lock_irq(&lp->lock);
125
126 lp->skbs[lp->in_idx++] = skb; /* add to buffer list */
127 if (lp->in_idx >= MAX_SKB_BUFFERS)
128 lp->in_idx = 0; /* wrap around */
129 lp->sk_count++; /* adjust counter */
130 dev->trans_start = jiffies;
131
132 /* If we just used up the very last entry in the
133 * TX ring on this device, tell the queueing
134 * layer to send no more.
135 */
136 if (lp->sk_count >= MAX_SKB_BUFFERS)
137 netif_stop_queue(dev);
138
139 /* When the TX completion hw interrupt arrives, this
140 * is when the transmit statistics are updated.
141 */
142
143 spin_unlock_irq(&lp->lock);
144
145 if (lp->sk_count <= 3) {
Wang Chen25dd7e62008-12-03 15:49:07 -0800146 schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147 }
Patrick McHardyec634fe2009-07-05 19:23:38 -0700148 return NETDEV_TX_OK; /* success */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149} /* net_send_packet */
150
151
152
153/***********************************************************************/
154/* acknowlegde a packet send. The network layer will be informed about */
155/* completion */
156/***********************************************************************/
157void
158hysdn_tx_netack(hysdn_card * card)
159{
160 struct net_local *lp = card->netif;
161
162 if (!lp)
163 return; /* non existing device */
164
165
166 if (!lp->sk_count)
167 return; /* error condition */
168
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800169 lp->dev->stats.tx_packets++;
170 lp->dev->stats.tx_bytes += lp->skbs[lp->out_idx]->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700171
172 dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */
173 if (lp->out_idx >= MAX_SKB_BUFFERS)
174 lp->out_idx = 0; /* wrap around */
175
176 if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */
177 netif_start_queue((struct net_device *) lp);
178} /* hysdn_tx_netack */
179
180/*****************************************************/
181/* we got a packet from the network, go and queue it */
182/*****************************************************/
183void
Andrew Mortonc721bcc2006-03-25 03:07:04 -0800184hysdn_rx_netpkt(hysdn_card * card, unsigned char *buf, unsigned short len)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185{
186 struct net_local *lp = card->netif;
Jiri Slabyd41de3c2010-06-22 01:41:36 +0000187 struct net_device *dev;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 struct sk_buff *skb;
189
190 if (!lp)
191 return; /* non existing device */
192
Jiri Slabyd41de3c2010-06-22 01:41:36 +0000193 dev = lp->dev;
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800194 dev->stats.rx_bytes += len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196 skb = dev_alloc_skb(len);
197 if (skb == NULL) {
198 printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800199 dev->name);
200 dev->stats.rx_dropped++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 return;
202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 /* copy the data */
204 memcpy(skb_put(skb, len), buf, len);
205
206 /* determine the used protocol */
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800207 skb->protocol = eth_type_trans(skb, dev);
208
209 dev->stats.rx_packets++; /* adjust packet count */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
211 netif_rx(skb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212} /* hysdn_rx_netpkt */
213
214/*****************************************************/
215/* return the pointer to a network packet to be send */
216/*****************************************************/
217struct sk_buff *
218hysdn_tx_netget(hysdn_card * card)
219{
220 struct net_local *lp = card->netif;
221
222 if (!lp)
223 return (NULL); /* non existing device */
224
225 if (!lp->sk_count)
226 return (NULL); /* nothing available */
227
228 return (lp->skbs[lp->out_idx]); /* next packet to send */
229} /* hysdn_tx_netget */
230
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800231static const struct net_device_ops hysdn_netdev_ops = {
232 .ndo_open = net_open,
233 .ndo_stop = net_close,
234 .ndo_start_xmit = net_send_packet,
235 .ndo_change_mtu = eth_change_mtu,
236 .ndo_set_mac_address = eth_mac_addr,
237 .ndo_validate_addr = eth_validate_addr,
238};
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
Linus Torvalds1da177e2005-04-16 15:20:36 -0700240
241/*****************************************************************************/
242/* hysdn_net_create creates a new net device for the given card. If a device */
243/* already exists, it will be deleted and created a new one. The return value */
244/* 0 announces success, else a negative error code will be returned. */
245/*****************************************************************************/
246int
247hysdn_net_create(hysdn_card * card)
248{
249 struct net_device *dev;
250 int i;
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800251 struct net_local *lp;
252
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 if(!card) {
254 printk(KERN_WARNING "No card-pt in hysdn_net_create!\n");
255 return (-ENOMEM);
256 }
257 hysdn_net_release(card); /* release an existing net device */
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800258
259 dev = alloc_etherdev(sizeof(struct net_local));
260 if (!dev) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261 printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
262 return (-ENOMEM);
263 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700264
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800265 lp = netdev_priv(dev);
266 lp->dev = dev;
267
268 dev->netdev_ops = &hysdn_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700269 spin_lock_init(&((struct net_local *) dev)->lock);
270
271 /* initialise necessary or informing fields */
272 dev->base_addr = card->iobase; /* IO address */
273 dev->irq = card->irq; /* irq */
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800274
275 dev->netdev_ops = &hysdn_netdev_ops;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700276 if ((i = register_netdev(dev))) {
277 printk(KERN_WARNING "HYSDN: unable to create network device\n");
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800278 free_netdev(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700279 return (i);
280 }
Wang Chen25dd7e62008-12-03 15:49:07 -0800281 dev->ml_priv = card; /* remember pointer to own data structure */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 card->netif = dev; /* setup the local pointer */
283
284 if (card->debug_flags & LOG_NET_INIT)
285 hysdn_addlog(card, "network device created");
286 return (0); /* and return success */
287} /* hysdn_net_create */
288
289/***************************************************************************/
290/* hysdn_net_release deletes the net device for the given card. The return */
291/* value 0 announces success, else a negative error code will be returned. */
292/***************************************************************************/
293int
294hysdn_net_release(hysdn_card * card)
295{
296 struct net_device *dev = card->netif;
297
298 if (!dev)
299 return (0); /* non existing */
300
301 card->netif = NULL; /* clear out pointer */
Stephen Hemminger0e2445f2009-01-07 18:03:43 -0800302 net_close(dev);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700303
304 flush_tx_buffers((struct net_local *) dev); /* empty buffers */
305
306 unregister_netdev(dev); /* release the device */
307 free_netdev(dev); /* release the memory allocated */
308 if (card->debug_flags & LOG_NET_INIT)
309 hysdn_addlog(card, "network device deleted");
310
311 return (0); /* always successful */
312} /* hysdn_net_release */
313
314/*****************************************************************************/
315/* hysdn_net_getname returns a pointer to the name of the network interface. */
316/* if the interface is not existing, a "-" is returned. */
317/*****************************************************************************/
318char *
319hysdn_net_getname(hysdn_card * card)
320{
321 struct net_device *dev = card->netif;
322
323 if (!dev)
324 return ("-"); /* non existing */
325
326 return (dev->name);
327} /* hysdn_net_getname */