diff mbox

nuvoton-cir: add proper rx fifo overrun handling

Message ID 20101008192109.GD5165@redhat.com (mailing list archive)
State Accepted
Headers show

Commit Message

Jarod Wilson Oct. 8, 2010, 7:21 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/media/IR/nuvoton-cir.c b/drivers/media/IR/nuvoton-cir.c
index 1ce9359..fdb280e 100644
--- a/drivers/media/IR/nuvoton-cir.c
+++ b/drivers/media/IR/nuvoton-cir.c
@@ -339,6 +339,15 @@  static void nvt_clear_tx_fifo(struct nvt_dev *nvt)
 	nvt_cir_reg_write(nvt, val | CIR_FIFOCON_TXFIFOCLR, CIR_FIFOCON);
 }
 
+/* enable RX Trigger Level Reach and Packet End interrupts */
+static void nvt_set_cir_iren(struct nvt_dev *nvt)
+{
+	u8 iren;
+
+	iren = CIR_IREN_RTR | CIR_IREN_PE;
+	nvt_cir_reg_write(nvt, iren, CIR_IREN);
+}
+
 static void nvt_cir_regs_init(struct nvt_dev *nvt)
 {
 	/* set sample limit count (PE interrupt raised when reached) */
@@ -363,8 +372,8 @@  static void nvt_cir_regs_init(struct nvt_dev *nvt)
 	/* clear any and all stray interrupts */
 	nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
 
-	/* and finally, enable RX Trigger Level Read and Packet End interrupts */
-	nvt_cir_reg_write(nvt, CIR_IREN_RTR | CIR_IREN_PE, CIR_IREN);
+	/* and finally, enable interrupts */
+	nvt_set_cir_iren(nvt);
 }
 
 static void nvt_cir_wake_regs_init(struct nvt_dev *nvt)
@@ -639,12 +648,22 @@  static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
 	nvt_dbg_verbose("%s done", __func__);
 }
 
+static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt)
+{
+	nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!");
+
+	nvt->pkts = 0;
+	nvt_clear_cir_fifo(nvt);
+	ir_raw_event_reset(nvt->rdev);
+}
+
 /* copy data from hardware rx fifo into driver buffer */
 static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
 {
 	unsigned long flags;
 	u8 fifocount, val;
 	unsigned int b_idx;
+	bool overrun = false;
 	int i;
 
 	/* Get count of how many bytes to read from RX FIFO */
@@ -652,11 +671,10 @@  static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
 	/* if we get 0xff, probably means the logical dev is disabled */
 	if (fifocount == 0xff)
 		return;
-	/* this would suggest a fifo overrun, not good... */
+	/* watch out for a fifo overrun condition */
 	else if (fifocount > RX_BUF_LEN) {
-		nvt_pr(KERN_WARNING, "fifocount %d over fifo len (%d)!",
-		       fifocount, RX_BUF_LEN);
-		return;
+		overrun = true;
+		fifocount = RX_BUF_LEN;
 	}
 
 	nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount);
@@ -682,6 +700,9 @@  static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
 
 	nvt_process_rx_ir_data(nvt);
 
+	if (overrun)
+		nvt_handle_rx_fifo_overrun(nvt);
+
 	spin_unlock_irqrestore(&nvt->nvt_lock, flags);
 }
 
@@ -886,7 +907,7 @@  static void nvt_enable_cir(struct nvt_dev *nvt)
 	nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
 
 	/* enable interrupts */
-	nvt_cir_reg_write(nvt, CIR_IREN_RTR | CIR_IREN_PE, CIR_IREN);
+	nvt_set_cir_iren(nvt);
 }
 
 static void nvt_disable_cir(struct nvt_dev *nvt)
@@ -1155,7 +1176,7 @@  static int nvt_resume(struct pnp_dev *pdev)
 	nvt_dbg("%s called", __func__);
 
 	/* open interrupt */
-	nvt_cir_reg_write(nvt, CIR_IREN_RTR | CIR_IREN_PE, CIR_IREN);
+	nvt_set_cir_iren(nvt);
 
 	/* Enable CIR logical device */
 	nvt_efm_enable(nvt);