@@ -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);