hysdn_net.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. /* $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. #include <linux/module.h>
  16. #include <linux/signal.h>
  17. #include <linux/kernel.h>
  18. #include <linux/netdevice.h>
  19. #include <linux/etherdevice.h>
  20. #include <linux/skbuff.h>
  21. #include <linux/inetdevice.h>
  22. #include "hysdn_defs.h"
  23. unsigned int hynet_enable = 0xffffffff;
  24. module_param(hynet_enable, uint, 0);
  25. /* store the actual version for log reporting */
  26. char *hysdn_net_revision = "$Revision: 1.8.6.4 $";
  27. #define MAX_SKB_BUFFERS 20 /* number of buffers for keeping TX-data */
  28. /****************************************************************************/
  29. /* structure containing the complete network data. The structure is aligned */
  30. /* in a way that both, the device and statistics are kept inside it. */
  31. /* for proper access, the device structure MUST be the first var/struct */
  32. /* inside the definition. */
  33. /****************************************************************************/
  34. struct net_local {
  35. /* Tx control lock. This protects the transmit buffer ring
  36. * state along with the "tx full" state of the driver. This
  37. * means all netif_queue flow control actions are protected
  38. * by this lock as well.
  39. */
  40. struct net_device *dev;
  41. spinlock_t lock;
  42. struct sk_buff *skbs[MAX_SKB_BUFFERS]; /* pointers to tx-skbs */
  43. int in_idx, out_idx; /* indexes to buffer ring */
  44. int sk_count; /* number of buffers currently in ring */
  45. }; /* net_local */
  46. /*********************************************************************/
  47. /* Open/initialize the board. This is called (in the current kernel) */
  48. /* sometime after booting when the 'ifconfig' program is run. */
  49. /* This routine should set everything up anew at each open, even */
  50. /* registers that "should" only need to be set once at boot, so that */
  51. /* there is non-reboot way to recover if something goes wrong. */
  52. /*********************************************************************/
  53. static int
  54. net_open(struct net_device *dev)
  55. {
  56. struct in_device *in_dev;
  57. hysdn_card *card = dev->ml_priv;
  58. int i;
  59. netif_start_queue(dev); /* start tx-queueing */
  60. /* Fill in the MAC-level header (if not already set) */
  61. if (!card->mac_addr[0]) {
  62. for (i = 0; i < ETH_ALEN; i++)
  63. dev->dev_addr[i] = 0xfc;
  64. if ((in_dev = dev->ip_ptr) != NULL) {
  65. struct in_ifaddr *ifa = in_dev->ifa_list;
  66. if (ifa != NULL)
  67. memcpy(dev->dev_addr + (ETH_ALEN - sizeof(ifa->ifa_local)), &ifa->ifa_local, sizeof(ifa->ifa_local));
  68. }
  69. } else
  70. memcpy(dev->dev_addr, card->mac_addr, ETH_ALEN);
  71. return (0);
  72. } /* net_open */
  73. /*******************************************/
  74. /* flush the currently occupied tx-buffers */
  75. /* must only be called when device closed */
  76. /*******************************************/
  77. static void
  78. flush_tx_buffers(struct net_local *nl)
  79. {
  80. while (nl->sk_count) {
  81. dev_kfree_skb(nl->skbs[nl->out_idx++]); /* free skb */
  82. if (nl->out_idx >= MAX_SKB_BUFFERS)
  83. nl->out_idx = 0; /* wrap around */
  84. nl->sk_count--;
  85. }
  86. } /* flush_tx_buffers */
  87. /*********************************************************************/
  88. /* close/decativate the device. The device is not removed, but only */
  89. /* deactivated. */
  90. /*********************************************************************/
  91. static int
  92. net_close(struct net_device *dev)
  93. {
  94. netif_stop_queue(dev); /* disable queueing */
  95. flush_tx_buffers((struct net_local *) dev);
  96. return (0); /* success */
  97. } /* net_close */
  98. /************************************/
  99. /* send a packet on this interface. */
  100. /* new style for kernel >= 2.3.33 */
  101. /************************************/
  102. static int
  103. net_send_packet(struct sk_buff *skb, struct net_device *dev)
  104. {
  105. struct net_local *lp = (struct net_local *) dev;
  106. spin_lock_irq(&lp->lock);
  107. lp->skbs[lp->in_idx++] = skb; /* add to buffer list */
  108. if (lp->in_idx >= MAX_SKB_BUFFERS)
  109. lp->in_idx = 0; /* wrap around */
  110. lp->sk_count++; /* adjust counter */
  111. dev->trans_start = jiffies;
  112. /* If we just used up the very last entry in the
  113. * TX ring on this device, tell the queueing
  114. * layer to send no more.
  115. */
  116. if (lp->sk_count >= MAX_SKB_BUFFERS)
  117. netif_stop_queue(dev);
  118. /* When the TX completion hw interrupt arrives, this
  119. * is when the transmit statistics are updated.
  120. */
  121. spin_unlock_irq(&lp->lock);
  122. if (lp->sk_count <= 3) {
  123. schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue);
  124. }
  125. return (0); /* success */
  126. } /* net_send_packet */
  127. /***********************************************************************/
  128. /* acknowlegde a packet send. The network layer will be informed about */
  129. /* completion */
  130. /***********************************************************************/
  131. void
  132. hysdn_tx_netack(hysdn_card * card)
  133. {
  134. struct net_local *lp = card->netif;
  135. if (!lp)
  136. return; /* non existing device */
  137. if (!lp->sk_count)
  138. return; /* error condition */
  139. lp->dev->stats.tx_packets++;
  140. lp->dev->stats.tx_bytes += lp->skbs[lp->out_idx]->len;
  141. dev_kfree_skb(lp->skbs[lp->out_idx++]); /* free skb */
  142. if (lp->out_idx >= MAX_SKB_BUFFERS)
  143. lp->out_idx = 0; /* wrap around */
  144. if (lp->sk_count-- == MAX_SKB_BUFFERS) /* dec usage count */
  145. netif_start_queue((struct net_device *) lp);
  146. } /* hysdn_tx_netack */
  147. /*****************************************************/
  148. /* we got a packet from the network, go and queue it */
  149. /*****************************************************/
  150. void
  151. hysdn_rx_netpkt(hysdn_card * card, unsigned char *buf, unsigned short len)
  152. {
  153. struct net_local *lp = card->netif;
  154. struct net_device *dev = lp->dev;
  155. struct sk_buff *skb;
  156. if (!lp)
  157. return; /* non existing device */
  158. dev->stats.rx_bytes += len;
  159. skb = dev_alloc_skb(len);
  160. if (skb == NULL) {
  161. printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n",
  162. dev->name);
  163. dev->stats.rx_dropped++;
  164. return;
  165. }
  166. /* copy the data */
  167. memcpy(skb_put(skb, len), buf, len);
  168. /* determine the used protocol */
  169. skb->protocol = eth_type_trans(skb, dev);
  170. dev->stats.rx_packets++; /* adjust packet count */
  171. netif_rx(skb);
  172. } /* hysdn_rx_netpkt */
  173. /*****************************************************/
  174. /* return the pointer to a network packet to be send */
  175. /*****************************************************/
  176. struct sk_buff *
  177. hysdn_tx_netget(hysdn_card * card)
  178. {
  179. struct net_local *lp = card->netif;
  180. if (!lp)
  181. return (NULL); /* non existing device */
  182. if (!lp->sk_count)
  183. return (NULL); /* nothing available */
  184. return (lp->skbs[lp->out_idx]); /* next packet to send */
  185. } /* hysdn_tx_netget */
  186. static const struct net_device_ops hysdn_netdev_ops = {
  187. .ndo_open = net_open,
  188. .ndo_stop = net_close,
  189. .ndo_start_xmit = net_send_packet,
  190. .ndo_change_mtu = eth_change_mtu,
  191. .ndo_set_mac_address = eth_mac_addr,
  192. .ndo_validate_addr = eth_validate_addr,
  193. };
  194. /*****************************************************************************/
  195. /* hysdn_net_create creates a new net device for the given card. If a device */
  196. /* already exists, it will be deleted and created a new one. The return value */
  197. /* 0 announces success, else a negative error code will be returned. */
  198. /*****************************************************************************/
  199. int
  200. hysdn_net_create(hysdn_card * card)
  201. {
  202. struct net_device *dev;
  203. int i;
  204. struct net_local *lp;
  205. if(!card) {
  206. printk(KERN_WARNING "No card-pt in hysdn_net_create!\n");
  207. return (-ENOMEM);
  208. }
  209. hysdn_net_release(card); /* release an existing net device */
  210. dev = alloc_etherdev(sizeof(struct net_local));
  211. if (!dev) {
  212. printk(KERN_WARNING "HYSDN: unable to allocate mem\n");
  213. return (-ENOMEM);
  214. }
  215. lp = netdev_priv(dev);
  216. lp->dev = dev;
  217. dev->netdev_ops = &hysdn_netdev_ops;
  218. spin_lock_init(&((struct net_local *) dev)->lock);
  219. /* initialise necessary or informing fields */
  220. dev->base_addr = card->iobase; /* IO address */
  221. dev->irq = card->irq; /* irq */
  222. dev->netdev_ops = &hysdn_netdev_ops;
  223. if ((i = register_netdev(dev))) {
  224. printk(KERN_WARNING "HYSDN: unable to create network device\n");
  225. free_netdev(dev);
  226. return (i);
  227. }
  228. dev->ml_priv = card; /* remember pointer to own data structure */
  229. card->netif = dev; /* setup the local pointer */
  230. if (card->debug_flags & LOG_NET_INIT)
  231. hysdn_addlog(card, "network device created");
  232. return (0); /* and return success */
  233. } /* hysdn_net_create */
  234. /***************************************************************************/
  235. /* hysdn_net_release deletes the net device for the given card. The return */
  236. /* value 0 announces success, else a negative error code will be returned. */
  237. /***************************************************************************/
  238. int
  239. hysdn_net_release(hysdn_card * card)
  240. {
  241. struct net_device *dev = card->netif;
  242. if (!dev)
  243. return (0); /* non existing */
  244. card->netif = NULL; /* clear out pointer */
  245. net_close(dev);
  246. flush_tx_buffers((struct net_local *) dev); /* empty buffers */
  247. unregister_netdev(dev); /* release the device */
  248. free_netdev(dev); /* release the memory allocated */
  249. if (card->debug_flags & LOG_NET_INIT)
  250. hysdn_addlog(card, "network device deleted");
  251. return (0); /* always successful */
  252. } /* hysdn_net_release */
  253. /*****************************************************************************/
  254. /* hysdn_net_getname returns a pointer to the name of the network interface. */
  255. /* if the interface is not existing, a "-" is returned. */
  256. /*****************************************************************************/
  257. char *
  258. hysdn_net_getname(hysdn_card * card)
  259. {
  260. struct net_device *dev = card->netif;
  261. if (!dev)
  262. return ("-"); /* non existing */
  263. return (dev->name);
  264. } /* hysdn_net_getname */