/* * SBE 2T3E3 synchronous serial card driver for Linux * * Copyright (C) 2009-2010 Krzysztof Halasa * * This program is free software; you can redistribute it and/or modify it * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * * This code is based on a driver written by SBE Inc. */ #include #include #include #include "2t3e3.h" irqreturn_t t3e3_intr(int irq, void *dev_instance) { struct channel *sc = dev_to_priv(dev_instance); u32 val; irqreturn_t ret = IRQ_NONE; sc->interrupt_active = 1; val = cpld_read(sc, SBE_2T3E3_CPLD_REG_PICSR); if (val & SBE_2T3E3_CPLD_VAL_RECEIVE_LOSS_OF_SIGNAL_CHANGE) { dev_dbg(&sc->pdev->dev, "Rx LOS Chng Int r=%02x (LOS|OOF=%02x)\n", val, (sc->s.LOS << 4) | sc->s.OOF); cpld_LOS_update(sc); ret = IRQ_HANDLED; } if (val & SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_ETHERNET_ASSERTED) { dc_intr(sc); ret = IRQ_HANDLED; } if (val & SBE_2T3E3_CPLD_VAL_INTERRUPT_FROM_FRAMER_ASSERTED) { exar7250_intr(sc); ret = IRQ_HANDLED; } /* we don't care about other interrupt sources (DMO, LOS, LCV) because they are handled by Framer too */ sc->interrupt_active = 0; return ret; } void dc_intr(struct channel *sc) { u32 val; /* disable ethernet interrupts */ /* grrr this clears interrupt summary bits !!! */ dc_write(sc->addr, SBE_2T3E3_21143_REG_INTERRUPT_ENABLE, 0); while ((val = dc_read(sc->addr, SBE_2T3E3_21143_REG_STATUS)) & (SBE_2T3E3_21143_VAL_RECEIVE_PROCESS_STOPPED | SBE_2T3E3_21143_VAL_RECEIVE_BUFFER_UNAVAILABLE | SBE_2T3E3_21143_VAL_RECEIVE_INTERRUPT | SBE_2T3E3_21143_VAL_TRANSMIT_UNDERFLOW | SBE_2T3E3_21143_VAL_TRANSMIT_BUFFER_UNAVAILABLE | SBE_2T3E3_21143_VAL_TRANSMIT_PROCESS_STOPPED | SBE_2T3E3_21143_VAL_TRANSMIT_INTERRUPT)) { dc_write(sc->addr, SBE_2T3E3_21143_REG_STATUS, val); dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Ethernet controller interrupt! (CSR5 = %08X)\n", val); if (val & (SBE_2T3E3_21143_VAL_RECEIVE_INTERRUPT | SBE_2T3E3_21143_VAL_RECEIVE_BUFFER_UNAVAILABLE | SBE_2T3E3_21143_VAL_RECEIVE_PROCESS_STOPPED)) { if (val & SBE_2T3E3_21143_VAL_RECEIVE_INTERRUPT) dev_dbg(&sc->pdev->dev, "Receive interrupt (LOS=%d, OOF=%d)\n", sc->s.LOS, sc->s.OOF); if (val & SBE_2T3E3_21143_VAL_RECEIVE_BUFFER_UNAVAILABLE) dev_dbg(&sc->pdev->dev, "Receive buffer unavailable\n"); if (val & SBE_2T3E3_21143_VAL_RECEIVE_PROCESS_STOPPED) dev_dbg(&sc->pdev->dev, "Receive process stopped\n"); dc_intr_rx(sc); } if (val & SBE_2T3E3_21143_VAL_TRANSMIT_UNDERFLOW) { dev_dbg(&sc->pdev->dev, "Transmit underflow\n"); dc_intr_tx_underflow(sc); } if (val & (SBE_2T3E3_21143_VAL_TRANSMIT_BUFFER_UNAVAILABLE | SBE_2T3E3_21143_VAL_TRANSMIT_INTERRUPT | SBE_2T3E3_21143_VAL_TRANSMIT_PROCESS_STOPPED)) { if (val & SBE_2T3E3_21143_VAL_TRANSMIT_INTERRUPT) dev_dbg(&sc->pdev->dev, "Transmit interrupt\n"); if (val & SBE_2T3E3_21143_VAL_TRANSMIT_BUFFER_UNAVAILABLE) dev_dbg(&sc->pdev->dev, "Transmit buffer unavailable\n"); if (val & SBE_2T3E3_21143_VAL_TRANSMIT_PROCESS_STOPPED) dev_dbg(&sc->pdev->dev, "Transmit process stopped\n"); dc_intr_tx(sc); } } /* enable ethernet interrupts */ dc_write(sc->addr, SBE_2T3E3_21143_REG_INTERRUPT_ENABLE, sc->ether.interrupt_enable_mask); } void dc_intr_rx(struct channel *sc) { u32 current_read; u32 error_mask, error; t3e3_rx_desc_t *current_desc; struct sk_buff *m, *m2; unsigned rcv_len; sc->rcv_count++; /* for the activity LED */ current_read = sc->ether.rx_ring_current_read; dev_dbg(&sc->pdev->dev, "intr_rx current_read = %d\n", current_read); /* when ethernet loopback is set, ignore framer signals */ if ((sc->p.loopback != SBE_2T3E3_LOOPBACK_ETHERNET) && sc->s.OOF) { while (!(sc->ether.rx_ring[current_read].rdes0 & SBE_2T3E3_RX_DESC_21143_OWN)) { current_desc = &sc->ether.rx_ring[current_read]; current_desc->rdes1 &= SBE_2T3E3_RX_DESC_END_OF_RING | SBE_2T3E3_RX_DESC_SECOND_ADDRESS_CHAINED; current_desc->rdes1 |= SBE_2T3E3_MTU; current_desc->rdes0 = SBE_2T3E3_RX_DESC_21143_OWN; current_read = (current_read + 1) % SBE_2T3E3_RX_DESC_RING_SIZE; } sc->ether.rx_ring_current_read = current_read; return; } while (!(sc->ether.rx_ring[current_read].rdes0 & SBE_2T3E3_RX_DESC_21143_OWN)) { current_desc = &sc->ether.rx_ring[current_read]; dev_dbg(&sc->pdev->dev, "rdes0: %08X rdes1: %08X\n", current_desc->rdes0, current_desc->rdes1); m = sc->ether.rx_data[current_read]; rcv_len = (current_desc->rdes0 & SBE_2T3E3_RX_DESC_FRAME_LENGTH) >> SBE_2T3E3_RX_DESC_FRAME_LENGTH_SHIFT; dev_dbg(&sc->pdev->dev, "mbuf was received (mbuf len = %d)\n", rcv_len); switch (sc->p.crc) { case SBE_2T3E3_CRC_16: rcv_len -= SBE_2T3E3_CRC16_LENGTH; break; case SBE_2T3E3_CRC_32: rcv_len -= SBE_2T3E3_CRC32_LENGTH; break; default: break; } if (current_desc->rdes0 & SBE_2T3E3_RX_DESC_LAST_DESC) { /* TODO: is collision possible? */ error_mask = SBE_2T3E3_RX_DESC_DESC_ERROR | SBE_2T3E3_RX_DESC_COLLISION_SEEN | SBE_2T3E3_RX_DESC_DRIBBLING_BIT; switch (sc->p.frame_mode) { case SBE_2T3E3_FRAME_MODE_HDLC: error_mask |= SBE_2T3E3_RX_DESC_MII_ERROR; if (sc->p.crc == SBE_2T3E3_CRC_32) error_mask |= SBE_2T3E3_RX_DESC_CRC_ERROR; break; case SBE_2T3E3_FRAME_MODE_TRANSPARENT: case SBE_2T3E3_FRAME_MODE_RAW: break; default: error_mask = 0; } if (sc->s.LOS) { error_mask &= ~(SBE_2T3E3_RX_DESC_DRIBBLING_BIT | SBE_2T3E3_RX_DESC_MII_ERROR); } error = current_desc->rdes0 & error_mask; if (error) { sc->s.in_errors++; dev_dbg(&sc->pdev->dev, "error interrupt: NO_ERROR_MESSAGE = %d\n", sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES ? 1 : 0); current_desc->rdes1 &= SBE_2T3E3_RX_DESC_END_OF_RING | SBE_2T3E3_RX_DESC_SECOND_ADDRESS_CHAINED; current_desc->rdes1 |= SBE_2T3E3_MTU; current_desc->rdes0 = SBE_2T3E3_RX_DESC_21143_OWN; if (error & SBE_2T3E3_RX_DESC_DESC_ERROR) { if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) dev_err(&sc->pdev->dev, "SBE 2T3E3: descriptor error\n"); sc->s.in_error_desc++; } if (error & SBE_2T3E3_RX_DESC_COLLISION_SEEN) { if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) dev_err(&sc->pdev->dev, "SBE 2T3E3: collision seen\n"); sc->s.in_error_coll++; } else { if (error & SBE_2T3E3_RX_DESC_DRIBBLING_BIT) { if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) dev_err(&sc->pdev->dev, "SBE 2T3E3: dribbling bits error\n"); sc->s.in_error_drib++; } if (error & SBE_2T3E3_RX_DESC_CRC_ERROR) { if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) dev_err(&sc->pdev->dev, "SBE 2T3E3: crc error\n"); sc->s.in_error_crc++; } } if (error & SBE_2T3E3_RX_DESC_MII_ERROR) { if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) dev_err(&sc->pdev->dev, "SBE 2T3E3: mii error\n"); sc->s.in_error_mii++; } current_read = (current_read + 1) % SBE_2T3E3_RX_DESC_RING_SIZE; sc->r.flags |= SBE_2T3E3_FLAG_NO_ERROR_MESSAGES; continue; } } current_desc->rdes1 &= SBE_2T3E3_RX_DESC_END_OF_RING | SBE_2T3E3_RX_DESC_SECOND_ADDRESS_CHAINED; current_desc->rdes1 |= SBE_2T3E3_MTU; if (rcv_len > 1600) { sc->s.in_errors++; sc->s.in_dropped++; if (!(sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES)) dev_err(&sc->pdev->dev, "SBE 2T3E3: oversized rx: rdes0 = %08X\n", current_desc->rdes0); } else { m2 = dev_alloc_skb(MCLBYTES); if (m2 != NULL) { current_desc->rdes2 = virt_to_phys(m2->data); sc->ether.rx_data[current_read] = m2; sc->s.in_packets++; sc->s.in_bytes += rcv_len; m->dev = sc->dev; skb_put(m, rcv_len); skb_reset_mac_header(m); m->protocol = hdlc_type_trans(m, m->dev); netif_rx(m); /* good packet was received so we will show error messages again... */ if (sc->r.flags & SBE_2T3E3_FLAG_NO_ERROR_MESSAGES) { dev_dbg(&sc->pdev->dev, "setting ERROR_MESSAGES->0\n"); sc->r.flags &= ~SBE_2T3E3_FLAG_NO_ERROR_MESSAGES; } } else { sc->s.in_errors++; sc->s.in_dropped++; } } current_desc->rdes0 = SBE_2T3E3_RX_DESC_21143_OWN; current_read = (current_read + 1) % SBE_2T3E3_RX_DESC_RING_SIZE; } sc->ether.rx_ring_current_read = current_read; dc_write(sc->addr, SBE_2T3E3_21143_REG_RECEIVE_POLL_DEMAND, 0xFFFFFFFF); } void dc_intr_tx(struct channel *sc) { u32 current_read, current_write; u32 last_segment, error; t3e3_tx_desc_t *current_desc; spin_lock(&sc->ether.tx_lock); current_read = sc->ether.tx_ring_current_read; current_write = sc->ether.tx_ring_current_write; while (current_read != current_write) { current_desc = &sc->ether.tx_ring[current_read]; if (current_desc->tdes0 & SBE_2T3E3_RX_DESC_21143_OWN) break; dev_dbg(&sc->pdev->dev, "txeof: tdes0 = %08X tdes1 = %08X\n", current_desc->tdes0, current_desc->tdes1); error = current_desc->tdes0 & (SBE_2T3E3_TX_DESC_ERROR_SUMMARY | SBE_2T3E3_TX_DESC_TRANSMIT_JABBER_TIMEOUT | SBE_2T3E3_TX_DESC_LOSS_OF_CARRIER | SBE_2T3E3_TX_DESC_NO_CARRIER | SBE_2T3E3_TX_DESC_LINK_FAIL_REPORT | SBE_2T3E3_TX_DESC_UNDERFLOW_ERROR | SBE_2T3E3_TX_DESC_DEFFERED); last_segment = current_desc->tdes1 & SBE_2T3E3_TX_DESC_LAST_SEGMENT; current_desc->tdes0 = 0; current_desc->tdes1 &= SBE_2T3E3_TX_DESC_END_OF_RING | SBE_2T3E3_TX_DESC_SECOND_ADDRESS_CHAINED; current_desc->tdes2 = 0; sc->ether.tx_free_cnt++; if (last_segment != SBE_2T3E3_TX_DESC_LAST_SEGMENT) { current_read = (current_read + 1) % SBE_2T3E3_TX_DESC_RING_SIZE; continue; } if (sc->ether.tx_data[current_read]) { sc->s.out_packets++; sc->s.out_bytes += sc->ether.tx_data[current_read]->len; dev_kfree_skb_any(sc->ether.tx_data[current_read]); sc->ether.tx_data[current_read] = NULL; } if (error > 0) { sc->s.out_errors++; if (error & SBE_2T3E3_TX_DESC_TRANSMIT_JABBER_TIMEOUT) { dev_err(&sc->pdev->dev, "SBE 2T3E3: transmit jabber timeout\n"); sc->s.out_error_jab++; } if (sc->p.loopback != SBE_2T3E3_LOOPBACK_ETHERNET) { if (error & SBE_2T3E3_TX_DESC_LOSS_OF_CARRIER) { dev_err(&sc->pdev->dev, "SBE 2T3E3: loss of carrier\n"); sc->s.out_error_lost_carr++; } if (error & SBE_2T3E3_TX_DESC_NO_CARRIER) { dev_err(&sc->pdev->dev, "SBE 2T3E3: no carrier\n"); sc->s.out_error_no_carr++; } } if (error & SBE_2T3E3_TX_DESC_LINK_FAIL_REPORT) { dev_err(&sc->pdev->dev, "SBE 2T3E3: link fail report\n"); sc->s.out_error_link_fail++; } if (error & SBE_2T3E3_TX_DESC_UNDERFLOW_ERROR) { dev_err(&sc->pdev->dev, "SBE 2T3E3:" " transmission underflow error\n"); sc->s.out_error_underflow++; spin_unlock(&sc->ether.tx_lock); dc_restart(sc); return; } if (error & SBE_2T3E3_TX_DESC_DEFFERED) { dev_err(&sc->pdev->dev, "SBE 2T3E3: transmission deferred\n"); sc->s.out_error_dereferred++; } } current_read = (current_read + 1) % SBE_2T3E3_TX_DESC_RING_SIZE; } sc->ether.tx_ring_current_read = current_read; /* Relieve flow control when the TX queue is drained at least half way */ if (sc->ether.tx_full && (sc->ether.tx_free_cnt >= (SBE_2T3E3_TX_DESC_RING_SIZE / 2))) { sc->ether.tx_full = 0; netif_wake_queue(sc->dev); } spin_unlock(&sc->ether.tx_lock); } void dc_intr_tx_underflow(struct channel *sc) { u32 val; dc_transmitter_onoff(sc, SBE_2T3E3_OFF); val = dc_read(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE); dc_clear_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS); switch (val & SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS) { case SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_1: dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_2); break; case SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_2: dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_3); break; case SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_3: dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_4); break; case SBE_2T3E3_21143_VAL_THRESHOLD_CONTROL_BITS_4: default: dc_set_bits(sc->addr, SBE_2T3E3_21143_REG_OPERATION_MODE, SBE_2T3E3_21143_VAL_STORE_AND_FORWARD); break; } dc_transmitter_onoff(sc, SBE_2T3E3_ON); } void exar7250_intr(struct channel *sc) { u32 status, old_OOF; old_OOF = sc->s.OOF; status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_BLOCK_INTERRUPT_STATUS); dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Framer interrupt! (REG[0x05] = %02X)\n", status); switch (sc->p.frame_type) { case SBE_2T3E3_FRAME_TYPE_E3_G751: case SBE_2T3E3_FRAME_TYPE_E3_G832: exar7250_E3_intr(sc, status); break; case SBE_2T3E3_FRAME_TYPE_T3_CBIT: case SBE_2T3E3_FRAME_TYPE_T3_M13: exar7250_T3_intr(sc, status); break; default: break; } if (sc->s.OOF != old_OOF) { if (sc->s.OOF) { if (sc->p.loopback == SBE_2T3E3_LOOPBACK_NONE) { dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Disabling eth interrupts\n"); /* turn off ethernet interrupts */ dc_stop_intr(sc); } } else if (sc->r.flags & SBE_2T3E3_FLAG_NETWORK_UP) { dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Enabling eth interrupts\n"); /* start interrupts */ sc->s.OOF = 1; dc_intr_rx(sc); sc->s.OOF = 0; if (sc->p.receiver_on) { dc_receiver_onoff(sc, SBE_2T3E3_OFF); dc_receiver_onoff(sc, SBE_2T3E3_ON); } dc_start_intr(sc); } } } void exar7250_T3_intr(struct channel *sc, u32 block_status) { u32 status, result; if (block_status & SBE_2T3E3_FRAMER_VAL_RX_INTERRUPT_STATUS) { status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_STATUS); if (status) { dev_dbg(&sc->pdev->dev, "Framer interrupt T3 RX (REG[0x13] = %02X)\n", status); result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_CONFIGURATION_STATUS); cpld_LOS_update(sc); if (status & SBE_2T3E3_FRAMER_VAL_T3_RX_OOF_INTERRUPT_STATUS) { sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_T3_RX_OOF ? 1 : 0; dev_dbg(&sc->pdev->dev, "Framer interrupt T3: OOF (%d)\n", sc->s.OOF); } exar7250_write(sc, SBE_2T3E3_FRAMER_REG_T3_RX_INTERRUPT_ENABLE, SBE_2T3E3_FRAMER_VAL_T3_RX_LOS_INTERRUPT_ENABLE | SBE_2T3E3_FRAMER_VAL_T3_RX_OOF_INTERRUPT_ENABLE); } status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_FEAC_INTERRUPT_ENABLE_STATUS); if (status) { dev_dbg(&sc->pdev->dev, "Framer interrupt T3 RX (REG[0x17] = %02X)\n", status); } status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_RX_LAPD_CONTROL); if (status) dev_dbg(&sc->pdev->dev, "Framer interrupt T3 RX (REG[0x18] = %02X)\n", status); } if (block_status & SBE_2T3E3_FRAMER_VAL_TX_INTERRUPT_STATUS) { status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_TX_FEAC_CONFIGURATION_STATUS); dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Framer interrupt T3 TX (REG[0x31] = %02X)\n", status); status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_T3_TX_LAPD_STATUS); dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Framer interrupt T3 TX (REG[0x34] = %02X)\n", status); } } void exar7250_E3_intr(struct channel *sc, u32 block_status) { u32 status, result; if (block_status & SBE_2T3E3_FRAMER_VAL_RX_INTERRUPT_STATUS) { status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_1); if (status) { dev_dbg(&sc->pdev->dev, "Framer interrupt E3 RX (REG[0x14] = %02X)\n", status); result = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_CONFIGURATION_STATUS_2); cpld_LOS_update(sc); if (status & SBE_2T3E3_FRAMER_VAL_E3_RX_OOF_INTERRUPT_STATUS) { sc->s.OOF = result & SBE_2T3E3_FRAMER_VAL_E3_RX_OOF ? 1 : 0; dev_dbg(&sc->pdev->dev, "Framer interrupt E3: OOF (%d)\n", sc->s.OOF); } exar7250_write(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_ENABLE_1, SBE_2T3E3_FRAMER_VAL_E3_RX_OOF_INTERRUPT_ENABLE | SBE_2T3E3_FRAMER_VAL_E3_RX_LOS_INTERRUPT_ENABLE ); } status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_RX_INTERRUPT_STATUS_2); if (status) { dev_dbg(&sc->pdev->dev, "Framer interrupt E3 RX (REG[0x15] = %02X)\n", status); } } if (block_status & SBE_2T3E3_FRAMER_VAL_TX_INTERRUPT_STATUS) { status = exar7250_read(sc, SBE_2T3E3_FRAMER_REG_E3_TX_LAPD_STATUS); dev_dbg(&sc->pdev->dev, "SBE 2T3E3: Framer interrupt E3 TX (REG[0x34] = %02X)\n", status); } }