static u_char Read_hfc8_stable(hfc4s8s_hw * hw, int reg) { u_char ref8; u_char in8; ref8 = Read_hfc8(hw, reg); while (((in8 = Read_hfc8(hw, reg)) != ref8)) { ref8 = in8; } return in8; }
static irqreturn_t hfc4s8s_interrupt(int intno, void *dev_id) { hfc4s8s_hw *hw = dev_id; u_char b, ovr; volatile u_char *ovp; int idx; u_char old_ioreg; if (!hw || !(hw->mr.r_irq_ctrl & M_GLOB_IRQ_EN)) return IRQ_NONE; #ifndef HISAX_HFC4S8S_PCIMEM /* read current selected regsister */ old_ioreg = GetRegAddr(hw); #endif /* Layer 1 State change */ hw->mr.r_irq_statech |= (Read_hfc8(hw, R_SCI) & hw->mr.r_irqmsk_statchg); if (! (b = (Read_hfc8(hw, R_STATUS) & (M_MISC_IRQSTA | M_FR_IRQSTA))) && !hw->mr.r_irq_statech) { #ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(hw, old_ioreg); #endif return IRQ_NONE; } /* timer event */ if (Read_hfc8(hw, R_IRQ_MISC) & M_TI_IRQ) { hw->mr.timer_irq = 1; hw->fifo_sched_cnt--; } /* FIFO event */ if ((ovr = Read_hfc8(hw, R_IRQ_OVIEW))) { hw->mr.r_irq_oview |= ovr; idx = R_IRQ_FIFO_BL0; ovp = hw->mr.r_irq_fifo_blx; while (ovr) { if ((ovr & 1)) { *ovp |= Read_hfc8(hw, idx); } ovp++; idx++; ovr >>= 1; } }
static void tx_d_frame(struct hfc4s8s_l1 *l1p) { struct sk_buff *skb; u_char f1, f2; u_char *cp; long cnt; if (l1p->l1_state != 7) return; /* TX fifo */ Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + 4)); wait_busy(l1p->hw); f1 = Read_hfc8(l1p->hw, A_F1); f2 = Read_hfc8_stable(l1p->hw, A_F2); if ((f1 ^ f2) & MAX_F_CNT) return; /* fifo is still filled */ if (l1p->tx_cnt > 0) { cnt = l1p->tx_cnt; l1p->tx_cnt = 0; l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | CONFIRM, (void *) cnt); } if ((skb = skb_dequeue(&l1p->d_tx_queue))) { cp = skb->data; cnt = skb->len; SetRegAddr(l1p->hw, A_FIFO_DATA0); while (cnt >= 4) { SetRegAddr(l1p->hw, A_FIFO_DATA0); fWrite_hfc32(l1p->hw, *(unsigned long *) cp); cp += 4; cnt -= 4; } while (cnt--) fWrite_hfc8(l1p->hw, *cp++); l1p->tx_cnt = skb->truesize; Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ wait_busy(l1p->hw); dev_kfree_skb(skb); } } /* tx_d_frame */
static void tx_b_frame(struct hfc4s8s_btype *bch) { struct sk_buff *skb; struct hfc4s8s_l1 *l1 = bch->l1p; u_char *cp; int cnt, max, hdlc_num; long ack_len = 0; if (!l1->enabled || (bch->mode == L1_MODE_NULL)) return; /* TX fifo */ Write_hfc8(l1->hw, R_FIFO, (l1->st_num * 8 + ((bch->bchan == 1) ? 0 : 2))); wait_busy(l1->hw); do { if (bch->mode == L1_MODE_HDLC) { hdlc_num = Read_hfc8(l1->hw, A_F1) & MAX_F_CNT; hdlc_num -= (Read_hfc8_stable(l1->hw, A_F2) & MAX_F_CNT); if (hdlc_num < 0) hdlc_num += 16; if (hdlc_num >= 15) break; /* fifo still filled up with hdlc frames */ } else hdlc_num = 0; if (!(skb = bch->tx_skb)) { if (!(skb = skb_dequeue(&bch->tx_queue))) { l1->hw->mr.fifo_slow_timer_service[l1-> st_num] &= ~((bch->bchan == 1) ? 1 : 4); break; /* list empty */ } bch->tx_skb = skb; bch->tx_cnt = 0; } if (!hdlc_num) l1->hw->mr.fifo_slow_timer_service[l1->st_num] |= ((bch->bchan == 1) ? 1 : 4); else l1->hw->mr.fifo_slow_timer_service[l1->st_num] &= ~((bch->bchan == 1) ? 1 : 4); max = Read_hfc16_stable(l1->hw, A_Z2); max -= Read_hfc16(l1->hw, A_Z1); if (max <= 0) max += 384; max--; if (max < 16) break; /* don't write to small amounts of bytes */ cnt = skb->len - bch->tx_cnt; if (cnt > max) cnt = max; cp = skb->data + bch->tx_cnt; bch->tx_cnt += cnt; #ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1->hw, A_FIFO_DATA0); #endif while (cnt >= 4) { #ifdef HISAX_HFC4S8S_PCIMEM fWrite_hfc32(l1->hw, A_FIFO_DATA0, *(unsigned long *) cp); #else fWrite_hfc32(l1->hw, *(unsigned long *) cp); #endif cp += 4; cnt -= 4; } while (cnt--) #ifdef HISAX_HFC4S8S_PCIMEM fWrite_hfc8(l1->hw, A_FIFO_DATA0, *cp++); #else fWrite_hfc8(l1->hw, *cp++); #endif if (bch->tx_cnt >= skb->len) { if (bch->mode == L1_MODE_HDLC) { /* increment f counter */ Write_hfc8(l1->hw, A_INC_RES_FIFO, 1); } ack_len += skb->truesize; bch->tx_skb = NULL; bch->tx_cnt = 0; dev_kfree_skb(skb); } else /* Re-Select */ Write_hfc8(l1->hw, R_FIFO, (l1->st_num * 8 + ((bch->bchan == 1) ? 0 : 2))); wait_busy(l1->hw); } while (1); if (ack_len) bch->b_if.ifc.l1l2((struct hisax_if *) &bch->b_if, PH_DATA | CONFIRM, (void *) ack_len); } /* tx_b_frame */
static void rx_b_frame(struct hfc4s8s_btype *bch) { int z1, z2, hdlc_complete; u_char f1, f2; struct hfc4s8s_l1 *l1 = bch->l1p; struct sk_buff *skb; if (!l1->enabled || (bch->mode == L1_MODE_NULL)) return; do { /* RX Fifo */ Write_hfc8(l1->hw, R_FIFO, (l1->st_num * 8 + ((bch->bchan == 1) ? 1 : 3))); wait_busy(l1->hw); if (bch->mode == L1_MODE_HDLC) { f1 = Read_hfc8_stable(l1->hw, A_F1); f2 = Read_hfc8(l1->hw, A_F2); hdlc_complete = ((f1 ^ f2) & MAX_F_CNT); } else hdlc_complete = 0; z1 = Read_hfc16_stable(l1->hw, A_Z1); z2 = Read_hfc16(l1->hw, A_Z2); z1 = (z1 - z2); if (hdlc_complete) z1++; if (z1 < 0) z1 += 384; if (!z1) break; if (!(skb = bch->rx_skb)) { if (! (skb = dev_alloc_skb((bch->mode == L1_MODE_TRANS) ? z1 : (MAX_B_FRAME_SIZE + 3)))) { printk(KERN_ERR "HFC-4S/8S: Could not allocate B " "channel receive buffer"); return; } bch->rx_ptr = skb->data; bch->rx_skb = skb; } skb->len = (bch->rx_ptr - skb->data) + z1; /* HDLC length check */ if ((bch->mode == L1_MODE_HDLC) && ((hdlc_complete && (skb->len < 4)) || (skb->len > (MAX_B_FRAME_SIZE + 3)))) { skb->len = 0; bch->rx_ptr = skb->data; Write_hfc8(l1->hw, A_INC_RES_FIFO, 2); /* reset fifo */ wait_busy(l1->hw); return; } #ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1->hw, A_FIFO_DATA0); #endif while (z1 >= 4) { #ifdef HISAX_HFC4S8S_PCIMEM *((unsigned long *) bch->rx_ptr) = Read_hfc32(l1->hw, A_FIFO_DATA0); #else *((unsigned long *) bch->rx_ptr) = fRead_hfc32(l1->hw); #endif bch->rx_ptr += 4; z1 -= 4; } while (z1--) #ifdef HISAX_HFC4S8S_PCIMEM *(bch->rx_ptr++) = Read_hfc8(l1->hw, A_FIFO_DATA0); #else *(bch->rx_ptr++) = fRead_hfc8(l1->hw); #endif if (hdlc_complete) { /* increment f counter */ Write_hfc8(l1->hw, A_INC_RES_FIFO, 1); wait_busy(l1->hw); /* hdlc crc check */ bch->rx_ptr--; if (*bch->rx_ptr) { skb->len = 0; bch->rx_ptr = skb->data; continue; } skb->len -= 3; } if (hdlc_complete || (bch->mode == L1_MODE_TRANS)) { bch->rx_skb = NULL; bch->rx_ptr = NULL; bch->b_if.ifc.l1l2(&bch->b_if.ifc, PH_DATA | INDICATION, skb); } } while (1); } /* rx_b_frame */
static void rx_d_frame(struct hfc4s8s_l1 *l1p, int ech) { int z1, z2; u_char f1, f2, df; struct sk_buff *skb; u_char *cp; if (!l1p->enabled) return; do { /* E/D RX fifo */ Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + ((ech) ? 7 : 5))); wait_busy(l1p->hw); f1 = Read_hfc8_stable(l1p->hw, A_F1); f2 = Read_hfc8(l1p->hw, A_F2); df = f1 - f2; if ((f1 - f2) < 0) df = f1 - f2 + MAX_F_CNT + 1; if (!df) { return; /* no complete frame in fifo */ } z1 = Read_hfc16_stable(l1p->hw, A_Z1); z2 = Read_hfc16(l1p->hw, A_Z2); z1 = z1 - z2 + 1; if (z1 < 0) z1 += 384; if (!(skb = dev_alloc_skb(MAX_D_FRAME_SIZE))) { printk(KERN_INFO "HFC-4S/8S: Could not allocate D/E " "channel receive buffer"); Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2); wait_busy(l1p->hw); return; } if (((z1 < 4) || (z1 > MAX_D_FRAME_SIZE))) { if (skb) dev_kfree_skb(skb); /* remove errornous D frame */ if (df == 1) { /* reset fifo */ Write_hfc8(l1p->hw, A_INC_RES_FIFO, 2); wait_busy(l1p->hw); return; } else { /* read errornous D frame */ #ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0); #endif while (z1 >= 4) { #ifdef HISAX_HFC4S8S_PCIMEM Read_hfc32(l1p->hw, A_FIFO_DATA0); #else fRead_hfc32(l1p->hw); #endif z1 -= 4; } while (z1--) #ifdef HISAX_HFC4S8S_PCIMEM Read_hfc8(l1p->hw, A_FIFO_DATA0); #else fRead_hfc8(l1p->hw); #endif Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); wait_busy(l1p->hw); return; } } cp = skb->data; #ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0); #endif while (z1 >= 4) { #ifdef HISAX_HFC4S8S_PCIMEM *((unsigned long *) cp) = Read_hfc32(l1p->hw, A_FIFO_DATA0); #else *((unsigned long *) cp) = fRead_hfc32(l1p->hw); #endif cp += 4; z1 -= 4; } while (z1--) #ifdef HISAX_HFC4S8S_PCIMEM *cp++ = Read_hfc8(l1p->hw, A_FIFO_DATA0); #else *cp++ = fRead_hfc8(l1p->hw); #endif Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* increment f counter */ wait_busy(l1p->hw); if (*(--cp)) { dev_kfree_skb(skb); } else { skb->len = (cp - skb->data) - 2; if (ech) l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA_E | INDICATION, skb); else l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | INDICATION, skb); } } while (1); } /* rx_d_frame */
static void hfc4s8s_bh(struct work_struct *work) { hfc4s8s_hw *hw = container_of(work, hfc4s8s_hw, tqueue); u_char b; struct hfc4s8s_l1 *l1p; volatile u_char *fifo_stat; int idx; /* handle layer 1 state changes */ b = 1; l1p = hw->l1; while (b) { if ((b & hw->mr.r_irq_statech)) { /* reset l1 event */ hw->mr.r_irq_statech &= ~b; if (l1p->enabled) { if (l1p->nt_mode) { u_char oldstate = l1p->l1_state; Write_hfc8(l1p->hw, R_ST_SEL, l1p->st_num); l1p->l1_state = Read_hfc8(l1p->hw, A_ST_RD_STA) & 0xf; if ((oldstate == 3) && (l1p->l1_state != 3)) l1p->d_if.ifc.l1l2(&l1p-> d_if. ifc, PH_DEACTIVATE | INDICATION, NULL); if (l1p->l1_state != 2) { del_timer(&l1p->l1_timer); if (l1p->l1_state == 3) { l1p->d_if.ifc. l1l2(&l1p-> d_if.ifc, PH_ACTIVATE | INDICATION, NULL); } } else { /* allow transition */ Write_hfc8(hw, A_ST_WR_STA, M_SET_G2_G3); mod_timer(&l1p->l1_timer, jiffies + L1_TIMER_T1); } printk(KERN_INFO "HFC-4S/8S: NT ch %d l1 state %d -> %d\n", l1p->st_num, oldstate, l1p->l1_state); } else { u_char oldstate = l1p->l1_state; Write_hfc8(l1p->hw, R_ST_SEL, l1p->st_num); l1p->l1_state = Read_hfc8(l1p->hw, A_ST_RD_STA) & 0xf; if (((l1p->l1_state == 3) && ((oldstate == 7) || (oldstate == 8))) || ((timer_pending (&l1p->l1_timer)) && (l1p->l1_state == 8))) { mod_timer(&l1p->l1_timer, L1_TIMER_T4 + jiffies); } else { if (l1p->l1_state == 7) { del_timer(&l1p-> l1_timer); l1p->d_if.ifc. l1l2(&l1p-> d_if.ifc, PH_ACTIVATE | INDICATION, NULL); tx_d_frame(l1p); } if (l1p->l1_state == 3) { if (oldstate != 3) l1p->d_if. ifc. l1l2 (&l1p-> d_if. ifc, PH_DEACTIVATE | INDICATION, NULL); } } printk(KERN_INFO "HFC-4S/8S: TE %d ch %d l1 state %d -> %d\n", l1p->hw->cardnum, l1p->st_num, oldstate, l1p->l1_state); } } } b <<= 1; l1p++; } /* now handle the fifos */ idx = 0; fifo_stat = hw->mr.r_irq_fifo_blx; l1p = hw->l1; while (idx < hw->driver_data.max_st_ports) { if (hw->mr.timer_irq) { *fifo_stat |= hw->mr.fifo_rx_trans_enables[idx]; if (hw->fifo_sched_cnt <= 0) { *fifo_stat |= hw->mr.fifo_slow_timer_service[l1p-> st_num]; } } /* ignore fifo 6 (TX E fifo) */ *fifo_stat &= 0xff - 0x40; while (*fifo_stat) { if (!l1p->nt_mode) { /* RX Fifo has data to read */ if ((*fifo_stat & 0x20)) { *fifo_stat &= ~0x20; rx_d_frame(l1p, 0); } /* E Fifo has data to read */ if ((*fifo_stat & 0x80)) { *fifo_stat &= ~0x80; rx_d_frame(l1p, 1); } /* TX Fifo completed send */ if ((*fifo_stat & 0x10)) { *fifo_stat &= ~0x10; tx_d_frame(l1p); } } /* B1 RX Fifo has data to read */ if ((*fifo_stat & 0x2)) { *fifo_stat &= ~0x2; rx_b_frame(l1p->b_ch); } /* B1 TX Fifo has send completed */ if ((*fifo_stat & 0x1)) { *fifo_stat &= ~0x1; tx_b_frame(l1p->b_ch); } /* B2 RX Fifo has data to read */ if ((*fifo_stat & 0x8)) { *fifo_stat &= ~0x8; rx_b_frame(l1p->b_ch + 1); } /* B2 TX Fifo has send completed */ if ((*fifo_stat & 0x4)) { *fifo_stat &= ~0x4; tx_b_frame(l1p->b_ch + 1); } } fifo_stat++; l1p++; idx++; } if (hw->fifo_sched_cnt <= 0) hw->fifo_sched_cnt += (1 << (7 - TRANS_TIMER_MODE)); hw->mr.timer_irq = 0; /* clear requested timer irq */ } /* hfc4s8s_bh */
static void tx_d_frame(struct hfc4s8s_l1 *l1p) { struct sk_buff *skb; u_char f1, f2; u_char *cp; long cnt; if (l1p->l1_state != 7) return; /* */ Write_hfc8(l1p->hw, R_FIFO, (l1p->st_num * 8 + 4)); wait_busy(l1p->hw); f1 = Read_hfc8(l1p->hw, A_F1); f2 = Read_hfc8_stable(l1p->hw, A_F2); if ((f1 ^ f2) & MAX_F_CNT) return; /* */ if (l1p->tx_cnt > 0) { cnt = l1p->tx_cnt; l1p->tx_cnt = 0; l1p->d_if.ifc.l1l2(&l1p->d_if.ifc, PH_DATA | CONFIRM, (void *) cnt); } if ((skb = skb_dequeue(&l1p->d_tx_queue))) { cp = skb->data; cnt = skb->len; #ifndef HISAX_HFC4S8S_PCIMEM SetRegAddr(l1p->hw, A_FIFO_DATA0); #endif while (cnt >= 4) { #ifdef HISAX_HFC4S8S_PCIMEM fWrite_hfc32(l1p->hw, A_FIFO_DATA0, *(unsigned long *) cp); #else SetRegAddr(l1p->hw, A_FIFO_DATA0); fWrite_hfc32(l1p->hw, *(unsigned long *) cp); #endif cp += 4; cnt -= 4; } #ifdef HISAX_HFC4S8S_PCIMEM while (cnt--) fWrite_hfc8(l1p->hw, A_FIFO_DATA0, *cp++); #else while (cnt--) fWrite_hfc8(l1p->hw, *cp++); #endif l1p->tx_cnt = skb->truesize; Write_hfc8(l1p->hw, A_INC_RES_FIFO, 1); /* */ wait_busy(l1p->hw); dev_kfree_skb(skb); } } /* */