Commit 25e803f9 authored by Tomoya MORINAGA's avatar Tomoya MORINAGA Committed by Grant Likely

spi-topcliff-pch: Add recovery processing in case FIFO overrun error occurs

Add recovery processing in case FIFO overrun error occurs with DMA transfer mode.
Signed-off-by: default avatarTomoya MORINAGA <tomoya-linux@dsn.okisemi.com>
Signed-off-by: default avatarGrant Likely <grant.likely@secretlab.ca>
parent 373b0eb6
...@@ -352,16 +352,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id) ...@@ -352,16 +352,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id)
"%s returning due to suspend\n", __func__); "%s returning due to suspend\n", __func__);
return IRQ_NONE; return IRQ_NONE;
} }
if (data->use_dma)
return IRQ_NONE;
io_remap_addr = data->io_remap_addr; io_remap_addr = data->io_remap_addr;
spsr = io_remap_addr + PCH_SPSR; spsr = io_remap_addr + PCH_SPSR;
reg_spsr_val = ioread32(spsr); reg_spsr_val = ioread32(spsr);
if (reg_spsr_val & SPSR_ORF_BIT) if (reg_spsr_val & SPSR_ORF_BIT) {
dev_err(&board_dat->pdev->dev, "%s Over run error", __func__); dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__);
if (data->current_msg->complete != 0) {
data->transfer_complete = true;
data->current_msg->status = -EIO;
data->current_msg->complete(data->current_msg->context);
data->bcurrent_msg_processing = false;
data->current_msg = NULL;
data->cur_trans = NULL;
}
}
if (data->use_dma)
return IRQ_NONE;
/* Check if the interrupt is for SPI device */ /* Check if the interrupt is for SPI device */
if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) { if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) {
...@@ -815,10 +825,11 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw) ...@@ -815,10 +825,11 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw)
} }
} }
static void pch_spi_start_transfer(struct pch_spi_data *data) static int pch_spi_start_transfer(struct pch_spi_data *data)
{ {
struct pch_spi_dma_ctrl *dma; struct pch_spi_dma_ctrl *dma;
unsigned long flags; unsigned long flags;
int rtn;
dma = &data->dma; dma = &data->dma;
...@@ -833,7 +844,9 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) ...@@ -833,7 +844,9 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)
initiating the transfer. */ initiating the transfer. */
dev_dbg(&data->master->dev, dev_dbg(&data->master->dev,
"%s:waiting for transfer to get over\n", __func__); "%s:waiting for transfer to get over\n", __func__);
wait_event_interruptible(data->wait, data->transfer_complete); rtn = wait_event_interruptible_timeout(data->wait,
data->transfer_complete,
msecs_to_jiffies(2 * HZ));
dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent,
DMA_FROM_DEVICE); DMA_FROM_DEVICE);
...@@ -860,6 +873,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) ...@@ -860,6 +873,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data)
pch_spi_clear_fifo(data->master); pch_spi_clear_fifo(data->master);
spin_unlock_irqrestore(&data->lock, flags); spin_unlock_irqrestore(&data->lock, flags);
return rtn;
} }
static void pch_dma_rx_complete(void *arg) static void pch_dma_rx_complete(void *arg)
...@@ -1187,7 +1202,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) ...@@ -1187,7 +1202,8 @@ static void pch_spi_process_messages(struct work_struct *pwork)
if (data->use_dma) { if (data->use_dma) {
pch_spi_handle_dma(data, &bpw); pch_spi_handle_dma(data, &bpw);
pch_spi_start_transfer(data); if (!pch_spi_start_transfer(data))
goto out;
pch_spi_copy_rx_data_for_dma(data, bpw); pch_spi_copy_rx_data_for_dma(data, bpw);
} else { } else {
pch_spi_set_tx(data, &bpw); pch_spi_set_tx(data, &bpw);
...@@ -1225,6 +1241,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) ...@@ -1225,6 +1241,7 @@ static void pch_spi_process_messages(struct work_struct *pwork)
} while (data->cur_trans != NULL); } while (data->cur_trans != NULL);
out:
pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH);
if (data->use_dma) if (data->use_dma)
pch_spi_release_dma(data); pch_spi_release_dma(data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment