/* * Read n bytes from the board memory and writes them into the user memory. * * card: the board * to: the destination address (in the userspace memory) * from: the source address (in the board memory) * n: number of bytes * * Return: 0 if OK, <0 if error. */ int copy_from_pam_to_user(tpam_card *card, void *to, const void *from, u32 n) { void *page; u32 count; /* allocate a free page for the data transfer */ if (!(page = (void *)__get_free_page(GFP_KERNEL))) { printk(KERN_ERR "TurboPAM(copy_from_pam_to_user): " "get_free_page failed\n"); return -ENOMEM; } while (n) { count = n < PAGE_SIZE ? n : PAGE_SIZE; /* copy data from the board into the kernel memory */ spin_lock_irq(&card->lock); copy_from_pam(card, page, from, count); spin_unlock_irq(&card->lock); /* copy it from the kernel memory into the user memory */ if (copy_to_user(to, page, count)) { /* this can fail... */ free_page((u32)page); return -EFAULT; } from += count; to += count; n -= count; } /* release allocated memory */ free_page((u32)page); return 0; }
/* * IRQ handler. * * If a message comes from the board we read it, construct a sk_buff containing * the message and we queue the sk_buff on the board's receive queue, and we * trigger the execution of the board's receive task queue. * * If a message ack comes from the board we can go on and send a new message, * so we trigger the execution of the board's send task queue. * * irq: the irq number * dev_id: the registered board to the irq * regs: not used. */ void tpam_irq(int irq, void *dev_id, struct pt_regs *regs) { tpam_card *card = (tpam_card *)dev_id; u32 ackupload, uploadptr; u32 waiting_too_long; u32 hpic; struct sk_buff *skb; pci_mpb mpb; skb_header *skbh; dprintk("TurboPAM(tpam_irq): IRQ received, card=%d\n", card->id); /* grab the board lock */ spin_lock(&card->lock); /* get the message type */ ackupload = copy_from_pam_dword(card, (void *)TPAM_ACKUPLOAD_REGISTER); /* acknowledge the interrupt */ copy_to_pam_dword(card, (void *)TPAM_INTERRUPTACK_REGISTER, 0); readl(card->bar0 + TPAM_HINTACK_REGISTER); if (!ackupload) { /* it is a new message from the board */ dprintk("TurboPAM(tpam_irq): message received, card=%d\n", card->id); /* get the upload pointer */ uploadptr = copy_from_pam_dword(card, (void *)TPAM_UPLOADPTR_REGISTER); /* get the beginning of the message (pci_mpb part) */ copy_from_pam(card, &mpb, (void *)uploadptr, sizeof(pci_mpb)); /* allocate the sk_buff */ if (!(skb = alloc_skb(sizeof(skb_header) + sizeof(pci_mpb) + mpb.actualBlockTLVSize + mpb.actualDataSize, GFP_ATOMIC))) { printk(KERN_ERR "TurboPAM(tpam_irq): " "alloc_skb failed\n"); spin_unlock(&card->lock); return; } /* build the skb_header */ skbh = (skb_header *)skb_put(skb, sizeof(skb_header)); skbh->size = sizeof(pci_mpb) + mpb.actualBlockTLVSize; skbh->data_size = mpb.actualDataSize; skbh->ack = 0; skbh->ack_size = 0; /* copy the pci_mpb into the sk_buff */ memcpy(skb_put(skb, sizeof(pci_mpb)), &mpb, sizeof(pci_mpb)); /* copy the TLV block into the sk_buff */ copy_from_pam(card, skb_put(skb, mpb.actualBlockTLVSize), (void *)uploadptr + sizeof(pci_mpb), mpb.actualBlockTLVSize); /* if existent, copy the data block into the sk_buff */ if (mpb.actualDataSize) copy_from_pam(card, skb_put(skb, mpb.actualDataSize), (void *)uploadptr + sizeof(pci_mpb) + 4096, mpb.actualDataSize); /* wait for the board to become ready */ waiting_too_long = 0; do { hpic = readl(card->bar0 + TPAM_HPIC_REGISTER); if (waiting_too_long++ > 0xfffffff) { spin_unlock(&card->lock); printk(KERN_ERR "TurboPAM(tpam_irq): " "waiting too long...\n"); return; } } while (hpic & 0x00000002); /* acknowledge the message */ copy_to_pam_dword(card, (void *)TPAM_ACKDOWNLOAD_REGISTER, 0xffffffff); readl(card->bar0 + TPAM_DSPINT_REGISTER); /* release the board lock */ spin_unlock(&card->lock); if (mpb.messageID == ID_U3ReadyToReceiveInd) { /* this message needs immediate treatment */ tpam_recv_U3ReadyToReceiveInd(card, skb); kfree_skb(skb); } else { /* put the message in the receive queue */ skb_queue_tail(&card->recvq, skb); queue_task(&card->recv_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); } return; } else { /* it is a ack from the board */ dprintk("TurboPAM(tpam_irq): message acknowledged, card=%d\n", card->id); /* board is not busy anymore */ card->busy = 0; /* release the lock */ spin_unlock(&card->lock); /* schedule the send queue for execution */ queue_task(&card->send_tq, &tq_immediate); mark_bh(IMMEDIATE_BH); return; } /* not reached */ }