OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [isdn/] [tpam/] [tpam_queues.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.