/*
 * SBE 2T3E3 synchronous serial card driver for Linux
 *
 * Copyright (C) 2009-2010 Krzysztof Halasa <khc@pm.waw.pl>
 *
 * 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 <linux/hdlc.h>
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#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);
	}
}