tpam_queues.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:11k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /* $Id: tpam_queues.c,v 1.1.2.1 2001/11/20 14:19:37 kai Exp $
  2.  *
  3.  * Turbo PAM ISDN driver for Linux. (Kernel Driver)
  4.  *
  5.  * Copyright 2001 Stelian Pop <stelian.pop@fr.alcove.com>, Alc魐e
  6.  *
  7.  * This software may be used and distributed according to the terms
  8.  * of the GNU General Public License, incorporated herein by reference.
  9.  *
  10.  * For all support questions please contact: <support@auvertech.fr>
  11.  *
  12.  */
  13. #include <linux/pci.h>
  14. #include <linux/sched.h>
  15. #include <linux/tqueue.h>
  16. #include <linux/interrupt.h>
  17. #include <asm/io.h>
  18. #include "tpam.h"
  19. /* Local function prototype */
  20. static int tpam_sendpacket(tpam_card *card, tpam_channel *channel);
  21. /*
  22.  * Queue a message to be send to the card when possible.
  23.  *
  24.  *  card: the board
  25.  *  skb: the sk_buff containing the message.
  26.  */
  27. void tpam_enqueue(tpam_card *card, struct sk_buff *skb) {
  28. dprintk("TurboPAM(tpam_enqueue): card=%dn", card->id);
  29. /* queue the sk_buff on the board's send queue */
  30. skb_queue_tail(&card->sendq, skb);
  31. /* queue the board's send task struct for immediate treatment */
  32. queue_task(&card->send_tq, &tq_immediate);
  33. mark_bh(IMMEDIATE_BH);
  34. }
  35. /*
  36.  * Queue a data message to be send to the card when possible.
  37.  *
  38.  *  card: the board
  39.  *  skb: the sk_buff containing the message and the data. This parameter
  40.  *  can be NULL if we want just to trigger the send of queued 
  41.  *  messages.
  42.  */
  43. void tpam_enqueue_data(tpam_channel *channel, struct sk_buff *skb) {
  44. dprintk("TurboPAM(tpam_enqueue_data): card=%d, channel=%dn", 
  45. channel->card->id, channel->num);
  46. /* if existant, queue the sk_buff on the channel's send queue */
  47. if (skb)
  48. skb_queue_tail(&channel->sendq, skb);
  49. /* queue the channel's send task struct for immediate treatment */
  50. queue_task(&channel->card->send_tq, &tq_immediate);
  51. mark_bh(IMMEDIATE_BH);
  52. }
  53. /*
  54.  * IRQ handler.
  55.  *
  56.  * If a message comes from the board we read it, construct a sk_buff containing
  57.  * the message and we queue the sk_buff on the board's receive queue, and we
  58.  * trigger the execution of the board's receive task queue.
  59.  *
  60.  * If a message ack comes from the board we can go on and send a new message,
  61.  * so we trigger the execution of the board's send task queue.
  62.  *
  63.  *  irq: the irq number
  64.  *  dev_id: the registered board to the irq
  65.  *  regs: not used.
  66.  */
  67. void tpam_irq(int irq, void *dev_id, struct pt_regs *regs) {
  68. tpam_card *card = (tpam_card *)dev_id;
  69. u32 ackupload, uploadptr;
  70. u32 waiting_too_long;
  71. u32 hpic;
  72. struct sk_buff *skb;
  73. pci_mpb mpb;
  74. skb_header *skbh;
  75. dprintk("TurboPAM(tpam_irq): IRQ received, card=%dn", card->id);
  76. /* grab the board lock */
  77. spin_lock(&card->lock);
  78. /* get the message type */
  79. ackupload = copy_from_pam_dword(card, (void *)TPAM_ACKUPLOAD_REGISTER);
  80. /* acknowledge the interrupt */
  81. copy_to_pam_dword(card, (void *)TPAM_INTERRUPTACK_REGISTER, 0);
  82. readl(card->bar0 + TPAM_HINTACK_REGISTER);
  83. if (!ackupload) {
  84. /* it is a new message from the board */
  85. dprintk("TurboPAM(tpam_irq): message received, card=%dn", 
  86. card->id);
  87. /* get the upload pointer */
  88. uploadptr = copy_from_pam_dword(card, 
  89.     (void *)TPAM_UPLOADPTR_REGISTER);
  90. /* get the beginning of the message (pci_mpb part) */
  91. copy_from_pam(card, &mpb, (void *)uploadptr, sizeof(pci_mpb));
  92. /* allocate the sk_buff */
  93. if (!(skb = alloc_skb(sizeof(skb_header) + sizeof(pci_mpb) + 
  94.       mpb.actualBlockTLVSize + 
  95.       mpb.actualDataSize, GFP_ATOMIC))) {
  96. printk(KERN_ERR "TurboPAM(tpam_irq): "
  97.        "alloc_skb failedn");
  98. spin_unlock(&card->lock);
  99. return;
  100. }
  101. /* build the skb_header */
  102. skbh = (skb_header *)skb_put(skb, sizeof(skb_header));
  103. skbh->size = sizeof(pci_mpb) + mpb.actualBlockTLVSize;
  104. skbh->data_size = mpb.actualDataSize;
  105. skbh->ack = 0;
  106. skbh->ack_size = 0;
  107. /* copy the pci_mpb into the sk_buff */
  108. memcpy(skb_put(skb, sizeof(pci_mpb)), &mpb, sizeof(pci_mpb));
  109. /* copy the TLV block into the sk_buff */
  110. copy_from_pam(card, skb_put(skb, mpb.actualBlockTLVSize),
  111.       (void *)uploadptr + sizeof(pci_mpb), 
  112.       mpb.actualBlockTLVSize);
  113. /* if existent, copy the data block into the sk_buff */
  114. if (mpb.actualDataSize)
  115. copy_from_pam(card, skb_put(skb, mpb.actualDataSize),
  116. (void *)uploadptr + sizeof(pci_mpb) + 4096, 
  117. mpb.actualDataSize);
  118. /* wait for the board to become ready */
  119. waiting_too_long = 0;
  120. do {
  121. hpic = readl(card->bar0 + TPAM_HPIC_REGISTER);
  122. if (waiting_too_long++ > 0xfffffff) {
  123. spin_unlock(&card->lock);
  124. printk(KERN_ERR "TurboPAM(tpam_irq): "
  125. "waiting too long...n");
  126. return;
  127. }
  128. } while (hpic & 0x00000002);
  129. /* acknowledge the message */
  130.          copy_to_pam_dword(card, (void *)TPAM_ACKDOWNLOAD_REGISTER, 
  131.   0xffffffff);
  132.          readl(card->bar0 + TPAM_DSPINT_REGISTER);
  133. /* release the board lock */
  134. spin_unlock(&card->lock);
  135. if (mpb.messageID == ID_U3ReadyToReceiveInd) {
  136. /* this message needs immediate treatment */
  137. tpam_recv_U3ReadyToReceiveInd(card, skb);
  138. kfree_skb(skb);
  139. }
  140. else {
  141. /* put the message in the receive queue */
  142. skb_queue_tail(&card->recvq, skb);
  143. queue_task(&card->recv_tq, &tq_immediate);
  144. mark_bh(IMMEDIATE_BH);
  145. }
  146. return;
  147. }
  148. else {
  149. /* it is a ack from the board */
  150. dprintk("TurboPAM(tpam_irq): message acknowledged, card=%dn",
  151. card->id);
  152. /* board is not busy anymore */
  153. card->busy = 0;
  154. /* release the lock */
  155. spin_unlock(&card->lock);
  156. /* schedule the send queue for execution */
  157. queue_task(&card->send_tq, &tq_immediate);
  158. mark_bh(IMMEDIATE_BH);
  159. return;
  160. }
  161. /* not reached */
  162. }
  163. /*
  164.  * Run the board's receive task queue, dispatching each message on the queue,
  165.  * to its treatment function.
  166.  *
  167.  *  card: the board.
  168.  */
  169. void tpam_recv_tq(tpam_card *card) {
  170. pci_mpb *p;
  171. struct sk_buff *skb;
  172. /* for each message on the receive queue... */
  173.         while ((skb = skb_dequeue(&card->recvq))) {
  174. /* point to the pci_mpb block */
  175. p = (pci_mpb *)(skb->data + sizeof(skb_header));
  176. /* dispatch the message */
  177. switch (p->messageID) {
  178. case ID_ACreateNCOCnf:
  179. tpam_recv_ACreateNCOCnf(card, skb);
  180. break;
  181. case ID_ADestroyNCOCnf:
  182. tpam_recv_ADestroyNCOCnf(card, skb);
  183. break;
  184. case ID_CConnectCnf:
  185. tpam_recv_CConnectCnf(card, skb);
  186. break;
  187. case ID_CConnectInd:
  188. tpam_recv_CConnectInd(card, skb);
  189. break;
  190. case ID_CDisconnectInd:
  191. tpam_recv_CDisconnectInd(card, skb);
  192. break;
  193. case ID_CDisconnectCnf:
  194. tpam_recv_CDisconnectCnf(card, skb);
  195. break;
  196. case ID_U3DataInd:
  197. tpam_recv_U3DataInd(card, skb);
  198. break;
  199. default:
  200. dprintk("TurboPAM(tpam_recv_tq): "
  201. "unknown messageID %d, card=%dn", 
  202. p->messageID, card->id);
  203. break;
  204. }
  205. /* free the sk_buff */
  206. kfree_skb(skb);
  207. }
  208. }
  209. /*
  210.  * Run the board's send task queue. If there is a message in the board's send
  211.  * queue, it gets sended. If not, it examines each channel (one at the time,
  212.  * using a round robin algorithm). For each channel, if there is a message
  213.  * in the channel's send queue, it gets sended. This function sends only one
  214.  * message, it does not consume all the queue.
  215.  */
  216. void tpam_send_tq(tpam_card *card) {
  217. int i;
  218. /* first, try to send a packet from the board's send queue */
  219. if (tpam_sendpacket(card, NULL))
  220. return;
  221. /* then, try each channel, in a round-robin manner */
  222. for (i=card->roundrobin; i<card->roundrobin+card->channels_used; i++) {
  223. if (tpam_sendpacket(card, 
  224.     &card->channels[i % card->channels_used])) {
  225. card->roundrobin = (i + 1) % card->channels_used;
  226. return;
  227. }
  228. }
  229. }
  230. /*
  231.  * Try to send a packet from the board's send queue or from the channel's
  232.  * send queue.
  233.  *
  234.  *  card: the board.
  235.  *  channel: the channel (if NULL, the packet will be taken from the 
  236.  *  board's send queue. If not, it will be taken from the 
  237.  *  channel's send queue.
  238.  *
  239.  * Return: 0 if tpam_send_tq must try another card/channel combination
  240.  *  (meaning that no packet has been send), 1 if no more packets
  241.  *  can be send at that time (a packet has been send or the card is
  242.  *  still busy from a previous send).
  243.  */
  244. static int tpam_sendpacket(tpam_card *card, tpam_channel *channel) {
  245.         struct sk_buff *skb;
  246. u32 hpic;
  247.         u32 downloadptr;
  248. skb_header *skbh;
  249. u32 waiting_too_long;
  250. dprintk("TurboPAM(tpam_sendpacket), card=%d, channel=%dn", 
  251. card->id, channel ? channel->num : -1);
  252. if (channel) {
  253. /* dequeue a packet from the channel's send queue */
  254. if (!(skb = skb_dequeue(&channel->sendq))) {
  255. dprintk("TurboPAM(tpam_sendpacket): "
  256. "card=%d, channel=%d, no packetn", 
  257. card->id, channel->num);
  258. return 0;
  259. }
  260. /* if the channel is not ready to receive, requeue the packet
  261.  * and return 0 to give a chance to another channel */
  262. if (!channel->readytoreceive) {
  263. dprintk("TurboPAM(tpam_sendpacket): "
  264. "card=%d, channel=%d, channel not readyn",
  265. card->id, channel->num);
  266. skb_queue_head(&channel->sendq, skb);
  267. return 0;
  268. }
  269. /* grab the board lock */
  270. spin_lock_irq(&card->lock);
  271. /* if the board is busy, requeue the packet and return 1 since
  272.  * there is no need to try another channel */
  273. if (card->busy) {
  274. dprintk("TurboPAM(tpam_sendpacket): "
  275. "card=%d, channel=%d, card busyn",
  276. card->id, channel->num);
  277. skb_queue_head(&channel->sendq, skb);
  278. spin_unlock_irq(&card->lock);
  279. return 1;
  280. }
  281. }
  282. else {
  283. /* dequeue a packet from the board's send queue */
  284. if (!(skb = skb_dequeue(&card->sendq))) {
  285. dprintk("TurboPAM(tpam_sendpacket): "
  286. "card=%d, no packetn", card->id);
  287. return 0;
  288. }
  289. /* grab the board lock */
  290. spin_lock_irq(&card->lock);
  291. /* if the board is busy, requeue the packet and return 1 since
  292.  * there is no need to try another channel */
  293. if (card->busy) {
  294. dprintk("TurboPAM(tpam_sendpacket): "
  295. "card=%d, card busyn", card->id);
  296. skb_queue_head(&card->sendq, skb);
  297. spin_unlock_irq(&card->lock);
  298. return 1;
  299. }
  300. }
  301. /* wait for the board to become ready */
  302. waiting_too_long = 0;
  303. do {
  304. hpic = readl(card->bar0 + TPAM_HPIC_REGISTER);
  305. if (waiting_too_long++ > 0xfffffff) {
  306. spin_unlock_irq(&card->lock);
  307. printk(KERN_ERR "TurboPAM(tpam_sendpacket): "
  308. "waiting too long...n");
  309. return 1;
  310. }
  311. } while (hpic & 0x00000002);
  312. skbh = (skb_header *)skb->data;
  313. dprintk("TurboPAM(tpam_sendpacket): "
  314. "card=%d, card ready, sending %d/%d bytesn", 
  315. card->id, skbh->size, skbh->data_size);
  316. /* get the board's download pointer */
  317.         downloadptr = copy_from_pam_dword(card, 
  318.   (void *)TPAM_DOWNLOADPTR_REGISTER);
  319. /* copy the packet to the board at the downloadptr location */
  320.         copy_to_pam(card, (void *)downloadptr, skb->data + sizeof(skb_header), 
  321.     skbh->size);
  322. if (skbh->data_size)
  323. /* if there is some data in the packet, copy it too */
  324. copy_to_pam(card, (void *)downloadptr + sizeof(pci_mpb) + 4096,
  325.     skb->data + sizeof(skb_header) + skbh->size, 
  326.     skbh->data_size);
  327. /* card will become busy right now */
  328. card->busy = 1;
  329. /* interrupt the board */
  330. copy_to_pam_dword(card, (void *)TPAM_ACKDOWNLOAD_REGISTER, 0);
  331. readl(card->bar0 + TPAM_DSPINT_REGISTER);
  332. /* release the lock */
  333. spin_unlock_irq(&card->lock);
  334. /* if a data ack was requested by the ISDN link layer, send it now */
  335. if (skbh->ack) {
  336. isdn_ctrl ctrl;
  337. ctrl.driver = card->id;
  338. ctrl.command = ISDN_STAT_BSENT;
  339. ctrl.arg = channel->num;
  340. ctrl.parm.length = skbh->ack_size;
  341. (* card->interface.statcallb)(&ctrl);
  342. }
  343. /* free the sk_buff */
  344. kfree_skb(skb);
  345. return 1;
  346. }