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