Skip to content

Commit

Permalink
[media] nuvoton-cir: add proper rx fifo overrun handling
Browse files Browse the repository at this point in the history
Per discussion with Andy Walls on irc, rx fifo overruns are not all that
uncommon on a busy system, and the initial posting of the nuvoton-cir
driver doesn't handle them well enough. With this addition, we'll drain
the hw fifo, attempt to process any ir pulse trains completed with that
flush, then we'll issue a hw rx fifo clear and reset the raw ir sample
kfifo and start over collecting raw ir data.

Also slightly refactors the cir interrupt enabling so that we always get
consistent flags set and only have to modify them in one place, should
they need to be altered.

Signed-off-by: Jarod Wilson <jarod@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Jarod Wilson authored and Mauro Carvalho Chehab committed Oct 21, 2010
1 parent 6d2f5c2 commit fbdc781
Showing 1 changed file with 29 additions and 8 deletions.
37 changes: 29 additions & 8 deletions drivers/media/IR/nuvoton-cir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) */
Expand All @@ -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)
Expand Down Expand Up @@ -639,24 +648,33 @@ 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 */
fifocount = nvt_cir_reg_read(nvt, CIR_RXFCONT);
/* 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);
Expand All @@ -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);
}

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit fbdc781

Please sign in to comment.