diff options
author | Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com> | 2011-09-06 04:16:37 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-10-04 12:10:50 -0400 |
commit | 25e803f9c339a070cd7361e853aebde11b1f9217 (patch) | |
tree | db699d232879b967830c47f91cced54786a3605b | |
parent | 373b0eb64b9c97a14720896dcfdebfa3268b1991 (diff) |
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: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
-rw-r--r-- | drivers/spi/spi-topcliff-pch.c | 31 |
1 files changed, 24 insertions, 7 deletions
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 6cb2fdbe5dba..c8efa757fdaa 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c | |||
@@ -352,16 +352,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id) | |||
352 | "%s returning due to suspend\n", __func__); | 352 | "%s returning due to suspend\n", __func__); |
353 | return IRQ_NONE; | 353 | return IRQ_NONE; |
354 | } | 354 | } |
355 | if (data->use_dma) | ||
356 | return IRQ_NONE; | ||
357 | 355 | ||
358 | io_remap_addr = data->io_remap_addr; | 356 | io_remap_addr = data->io_remap_addr; |
359 | spsr = io_remap_addr + PCH_SPSR; | 357 | spsr = io_remap_addr + PCH_SPSR; |
360 | 358 | ||
361 | reg_spsr_val = ioread32(spsr); | 359 | reg_spsr_val = ioread32(spsr); |
362 | 360 | ||
363 | if (reg_spsr_val & SPSR_ORF_BIT) | 361 | if (reg_spsr_val & SPSR_ORF_BIT) { |
364 | dev_err(&board_dat->pdev->dev, "%s Over run error", __func__); | 362 | dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__); |
363 | if (data->current_msg->complete != 0) { | ||
364 | data->transfer_complete = true; | ||
365 | data->current_msg->status = -EIO; | ||
366 | data->current_msg->complete(data->current_msg->context); | ||
367 | data->bcurrent_msg_processing = false; | ||
368 | data->current_msg = NULL; | ||
369 | data->cur_trans = NULL; | ||
370 | } | ||
371 | } | ||
372 | |||
373 | if (data->use_dma) | ||
374 | return IRQ_NONE; | ||
365 | 375 | ||
366 | /* Check if the interrupt is for SPI device */ | 376 | /* Check if the interrupt is for SPI device */ |
367 | if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) { | 377 | 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 | } | 825 | } |
816 | } | 826 | } |
817 | 827 | ||
818 | static void pch_spi_start_transfer(struct pch_spi_data *data) | 828 | static int pch_spi_start_transfer(struct pch_spi_data *data) |
819 | { | 829 | { |
820 | struct pch_spi_dma_ctrl *dma; | 830 | struct pch_spi_dma_ctrl *dma; |
821 | unsigned long flags; | 831 | unsigned long flags; |
832 | int rtn; | ||
822 | 833 | ||
823 | dma = &data->dma; | 834 | dma = &data->dma; |
824 | 835 | ||
@@ -833,7 +844,9 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) | |||
833 | initiating the transfer. */ | 844 | initiating the transfer. */ |
834 | dev_dbg(&data->master->dev, | 845 | dev_dbg(&data->master->dev, |
835 | "%s:waiting for transfer to get over\n", __func__); | 846 | "%s:waiting for transfer to get over\n", __func__); |
836 | wait_event_interruptible(data->wait, data->transfer_complete); | 847 | rtn = wait_event_interruptible_timeout(data->wait, |
848 | data->transfer_complete, | ||
849 | msecs_to_jiffies(2 * HZ)); | ||
837 | 850 | ||
838 | dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, | 851 | dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, |
839 | DMA_FROM_DEVICE); | 852 | DMA_FROM_DEVICE); |
@@ -860,6 +873,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) | |||
860 | pch_spi_clear_fifo(data->master); | 873 | pch_spi_clear_fifo(data->master); |
861 | 874 | ||
862 | spin_unlock_irqrestore(&data->lock, flags); | 875 | spin_unlock_irqrestore(&data->lock, flags); |
876 | |||
877 | return rtn; | ||
863 | } | 878 | } |
864 | 879 | ||
865 | static void pch_dma_rx_complete(void *arg) | 880 | static void pch_dma_rx_complete(void *arg) |
@@ -1187,7 +1202,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1187 | 1202 | ||
1188 | if (data->use_dma) { | 1203 | if (data->use_dma) { |
1189 | pch_spi_handle_dma(data, &bpw); | 1204 | pch_spi_handle_dma(data, &bpw); |
1190 | pch_spi_start_transfer(data); | 1205 | if (!pch_spi_start_transfer(data)) |
1206 | goto out; | ||
1191 | pch_spi_copy_rx_data_for_dma(data, bpw); | 1207 | pch_spi_copy_rx_data_for_dma(data, bpw); |
1192 | } else { | 1208 | } else { |
1193 | pch_spi_set_tx(data, &bpw); | 1209 | pch_spi_set_tx(data, &bpw); |
@@ -1225,6 +1241,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
1225 | 1241 | ||
1226 | } while (data->cur_trans != NULL); | 1242 | } while (data->cur_trans != NULL); |
1227 | 1243 | ||
1244 | out: | ||
1228 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); | 1245 | pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); |
1229 | if (data->use_dma) | 1246 | if (data->use_dma) |
1230 | pch_spi_release_dma(data); | 1247 | pch_spi_release_dma(data); |