static irqreturn_t c4_handle_interrupt(avmcard *card) { unsigned long flags; u32 status; spin_lock_irqsave(&card->lock, flags); status = c4inmeml(card->mbase+DOORBELL); if (status & DBELL_RESET_HOST) { u_int i; c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); spin_unlock_irqrestore(&card->lock, flags); if (card->nlogcontr == 0) return IRQ_HANDLED; printk(KERN_ERR "%s: unexpected reset\n", card->name); for (i=0; i < card->nr_controllers; i++) { avmctrl_info *cinfo = &card->ctrlinfo[i]; memset(cinfo->version, 0, sizeof(cinfo->version)); spin_lock_irqsave(&card->lock, flags); capilib_release(&cinfo->ncci_head); spin_unlock_irqrestore(&card->lock, flags); capi_ctr_down(&cinfo->capi_ctrl); } card->nlogcontr = 0; return IRQ_HANDLED; } status &= (DBELL_UP_HOST | DBELL_DOWN_HOST); if (!status) { spin_unlock_irqrestore(&card->lock, flags); return IRQ_HANDLED; } c4outmeml(card->mbase+DOORBELL, status); if ((status & DBELL_UP_HOST) != 0) { card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN); c4outmeml(card->mbase+MBOX_UP_LEN, 0); c4_handle_rx(card); card->dma->recvlen = 0; c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size); c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); } if ((status & DBELL_DOWN_HOST) != 0) { card->csr &= ~DBELL_DOWN_ARM; c4_dispatch_tx(card); } else if (card->csr & DBELL_DOWN_HOST) { if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) { card->csr &= ~DBELL_DOWN_ARM; c4_dispatch_tx(card); } } spin_unlock_irqrestore(&card->lock, flags); return IRQ_HANDLED; }
static int c4_peek(avmcard *card, unsigned long off, unsigned long *valuep) { if (wait_for_doorbell(card, HZ/10) < 0) return -1; c4outmeml(card->mbase+MBOX_PEEK_POKE, off); c4outmeml(card->mbase+DOORBELL, DBELL_RNWR | DBELL_ADDR); if (wait_for_doorbell(card, HZ/10) < 0) return -1; *valuep = c4inmeml(card->mbase+MBOX_PEEK_POKE); return 0; }
static void c4_reset(avmcard *card) { unsigned long stop; c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM); stop = jiffies + HZ*10; while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { if (!time_before(jiffies, stop)) return; c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); } c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); }
static int c4_poke(avmcard *card, unsigned long off, unsigned long value) { if (wait_for_doorbell(card, HZ/10) < 0) return -1; c4outmeml(card->mbase+MBOX_PEEK_POKE, off); c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); if (wait_for_doorbell(card, HZ/10) < 0) return -1; c4outmeml(card->mbase+MBOX_PEEK_POKE, value); c4outmeml(card->mbase+DOORBELL, DBELL_DATA | DBELL_ADDR); return 0; }
static void c4_handle_interrupt(avmcard *card) { __u32 status = c4inmeml(card->mbase+DOORBELL); if (status & DBELL_RESET_HOST) { int i; c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); if (card->nlogcontr == 0) return; printk(KERN_ERR "%s: unexpected reset\n", card->name); for (i=0; i < 4; i++) { avmctrl_info *cinfo = &card->ctrlinfo[i]; memset(cinfo->version, 0, sizeof(cinfo->version)); if (cinfo->capi_ctrl) cinfo->capi_ctrl->reseted(cinfo->capi_ctrl); } card->nlogcontr = 0; return; } status &= (DBELL_UP_HOST | DBELL_DOWN_HOST); if (!status) return; c4outmeml(card->mbase+DOORBELL, status); if ((status & DBELL_UP_HOST) != 0) { card->dma->recvlen = c4inmeml(card->mbase+MBOX_UP_LEN); c4outmeml(card->mbase+MBOX_UP_LEN, 0); c4_handle_rx(card); card->dma->recvlen = 0; c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size); c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); } if ((status & DBELL_DOWN_HOST) != 0) { card->csr &= ~DBELL_DOWN_ARM; c4_dispatch_tx(card); } else if (card->csr & DBELL_DOWN_HOST) { if (c4inmeml(card->mbase+MBOX_DOWN_LEN) == 0) { card->csr &= ~DBELL_DOWN_ARM; c4_dispatch_tx(card); } } }
static int c4_load_firmware(struct capi_ctr *ctrl, capiloaddata *data) { avmctrl_info *cinfo = (avmctrl_info *)(ctrl->driverdata); avmcard *card = cinfo->card; unsigned long flags; int retval; if ((retval = c4_load_t4file(card, &data->firmware))) { printk(KERN_ERR "%s: failed to load t4file!!\n", card->name); c4_reset(card); return retval; } save_flags(flags); cli(); card->csr = 0; c4outmeml(card->mbase+MBOX_UP_LEN, 0); c4outmeml(card->mbase+MBOX_DOWN_LEN, 0); c4outmeml(card->mbase+DOORBELL, DBELL_INIT); mdelay(1); c4outmeml(card->mbase+DOORBELL, DBELL_UP_HOST | DBELL_DOWN_HOST | DBELL_RESET_HOST); c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x08); card->dma->recvlen = 0; c4outmeml(card->mbase+MBOX_UP_ADDR, card->dma->recvbuf.dmaaddr); c4outmeml(card->mbase+MBOX_UP_LEN, card->dma->recvbuf.size); c4outmeml(card->mbase+DOORBELL, DBELL_UP_ARM); restore_flags(flags); if (data->configuration.len > 0 && data->configuration.data) { retval = c4_send_config(card, &data->configuration); if (retval) { printk(KERN_ERR "%s: failed to set config!!\n", card->name); c4_reset(card); return retval; } } c4_send_init(card); return 0; }
static void c4_dispatch_tx(avmcard *card) { avmcard_dmainfo *dma = card->dma; struct sk_buff *skb; u8 cmd, subcmd; u16 len; u32 txlen; void *p; if (card->csr & DBELL_DOWN_ARM) { /* tx busy */ return; } skb = skb_dequeue(&dma->send_queue); if (!skb) { #ifdef AVM_C4_DEBUG printk(KERN_DEBUG "%s: tx underrun\n", card->name); #endif return; } len = CAPIMSG_LEN(skb->data); if (len) { cmd = CAPIMSG_COMMAND(skb->data); subcmd = CAPIMSG_SUBCOMMAND(skb->data); p = dma->sendbuf.dmabuf; if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { u16 dlen = CAPIMSG_DATALEN(skb->data); _put_byte(&p, SEND_DATA_B3_REQ); _put_slice(&p, skb->data, len); _put_slice(&p, skb->data + len, dlen); } else { _put_byte(&p, SEND_MESSAGE); _put_slice(&p, skb->data, len); } txlen = (u8 *)p - (u8 *)dma->sendbuf.dmabuf; #ifdef AVM_C4_DEBUG printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen); #endif } else { txlen = skb->len-2; #ifdef AVM_C4_POLLDEBUG if (skb->data[2] == SEND_POLLACK) printk(KERN_INFO "%s: ack to c4\n", card->name); #endif #ifdef AVM_C4_DEBUG printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n", card->name, skb->data[2], txlen); #endif skb_copy_from_linear_data_offset(skb, 2, dma->sendbuf.dmabuf, skb->len - 2); } txlen = (txlen + 3) & ~3; c4outmeml(card->mbase+MBOX_DOWN_ADDR, dma->sendbuf.dmaaddr); c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen); card->csr |= DBELL_DOWN_ARM; c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM); dev_kfree_skb_any(skb); }
static int c4_detect(avmcard *card) { unsigned long stop, dummy; c4outmeml(card->mbase+PCI_OUT_INT_MASK, 0x0c); if (c4inmeml(card->mbase+PCI_OUT_INT_MASK) != 0x0c) return 1; c4outmeml(card->mbase+DOORBELL, DBELL_RESET_ARM); stop = jiffies + HZ*10; while (c4inmeml(card->mbase+DOORBELL) != 0xffffffff) { if (!time_before(jiffies, stop)) return 2; c4outmeml(card->mbase+DOORBELL, DBELL_ADDR); mb(); } c4_poke(card, DC21285_ARMCSR_BASE + CHAN_1_CONTROL, 0); c4_poke(card, DC21285_ARMCSR_BASE + CHAN_2_CONTROL, 0); c4outmeml(card->mbase+MAILBOX_0, 0x55aa55aa); if (c4inmeml(card->mbase+MAILBOX_0) != 0x55aa55aa) return 3; c4outmeml(card->mbase+MAILBOX_0, 0xaa55aa55); if (c4inmeml(card->mbase+MAILBOX_0) != 0xaa55aa55) return 4; if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_SA_MASK, 0)) return 5; if (c4_poke(card, DC21285_ARMCSR_BASE+DBELL_PCI_MASK, 0)) return 6; if (c4_poke(card, DC21285_ARMCSR_BASE+SA_CONTROL, SA_CTL_ALLRIGHT)) return 7; if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_CYCLE, INIT_XBUS_CYCLE)) return 8; if (c4_poke(card, DC21285_ARMCSR_BASE+XBUS_STROBE, INIT_XBUS_STROBE)) return 8; if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, 0)) return 9; mdelay(1); if (c4_peek(card, DC21285_DRAM_A0MR, &dummy)) return 10; if (c4_peek(card, DC21285_DRAM_A1MR, &dummy)) return 11; if (c4_peek(card, DC21285_DRAM_A2MR, &dummy)) return 12; if (c4_peek(card, DC21285_DRAM_A3MR, &dummy)) return 13; if (c4_poke(card, DC21285_DRAM_A0MR+CAS_OFFSET, 0)) return 14; if (c4_poke(card, DC21285_DRAM_A1MR+CAS_OFFSET, 0)) return 15; if (c4_poke(card, DC21285_DRAM_A2MR+CAS_OFFSET, 0)) return 16; if (c4_poke(card, DC21285_DRAM_A3MR+CAS_OFFSET, 0)) return 17; mdelay(1); if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_TIMING, DRAM_TIMING_DEF)) return 18; if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_0,DRAM_AD_SZ_DEF0)) return 19; if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_1,DRAM_AD_SZ_NULL)) return 20; if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_2,DRAM_AD_SZ_NULL)) return 21; if (c4_poke(card, DC21285_ARMCSR_BASE+DRAM_ADDR_SIZE_3,DRAM_AD_SZ_NULL)) return 22; /* Transputer test */ if ( c4_poke(card, 0x000000, 0x11111111) || c4_poke(card, 0x400000, 0x22222222) || c4_poke(card, 0x800000, 0x33333333) || c4_poke(card, 0xC00000, 0x44444444)) return 23; if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x11111111 || c4_peek(card, 0x400000, &dummy) || dummy != 0x22222222 || c4_peek(card, 0x800000, &dummy) || dummy != 0x33333333 || c4_peek(card, 0xC00000, &dummy) || dummy != 0x44444444) return 24; if ( c4_poke(card, 0x000000, 0x55555555) || c4_poke(card, 0x400000, 0x66666666) || c4_poke(card, 0x800000, 0x77777777) || c4_poke(card, 0xC00000, 0x88888888)) return 25; if ( c4_peek(card, 0x000000, &dummy) || dummy != 0x55555555 || c4_peek(card, 0x400000, &dummy) || dummy != 0x66666666 || c4_peek(card, 0x800000, &dummy) || dummy != 0x77777777 || c4_peek(card, 0xC00000, &dummy) || dummy != 0x88888888) return 26; return 0; }
static void c4_dispatch_tx(avmcard *card) { avmcard_dmainfo *dma = card->dma; unsigned long flags; struct sk_buff *skb; __u8 cmd, subcmd; __u16 len; __u32 txlen; void *p; save_flags(flags); cli(); if (card->csr & DBELL_DOWN_ARM) { /* tx busy */ restore_flags(flags); return; } skb = skb_dequeue(&dma->send_queue); if (!skb) { #ifdef CONFIG_C4_DEBUG printk(KERN_DEBUG "%s: tx underrun\n", card->name); #endif restore_flags(flags); return; } len = CAPIMSG_LEN(skb->data); if (len) { cmd = CAPIMSG_COMMAND(skb->data); subcmd = CAPIMSG_SUBCOMMAND(skb->data); p = dma->sendbuf; if (CAPICMD(cmd, subcmd) == CAPI_DATA_B3_REQ) { __u16 dlen = CAPIMSG_DATALEN(skb->data); _put_byte(&p, SEND_DATA_B3_REQ); _put_slice(&p, skb->data, len); _put_slice(&p, skb->data + len, dlen); } else { _put_byte(&p, SEND_MESSAGE); _put_slice(&p, skb->data, len); } txlen = (__u8 *)p - (__u8 *)dma->sendbuf; #ifdef CONFIG_C4_DEBUG printk(KERN_DEBUG "%s: tx put msg len=%d\n", card->name, txlen); #endif } else { txlen = skb->len-2; #ifdef CONFIG_C4_POLLDEBUG if (skb->data[2] == SEND_POLLACK) printk(KERN_INFO "%s: ack to c4\n", card->name); #endif #ifdef CONFIG_C4_DEBUG printk(KERN_DEBUG "%s: tx put 0x%x len=%d\n", card->name, skb->data[2], txlen); #endif memcpy(dma->sendbuf, skb->data+2, skb->len-2); } txlen = (txlen + 3) & ~3; c4outmeml(card->mbase+MBOX_DOWN_ADDR, virt_to_phys(dma->sendbuf)); c4outmeml(card->mbase+MBOX_DOWN_LEN, txlen); card->csr |= DBELL_DOWN_ARM; c4outmeml(card->mbase+DOORBELL, DBELL_DOWN_ARM); restore_flags(flags); dev_kfree_skb_any(skb); }