From 27504be5c10bdc61761ec0126b3645428598ad91 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:34 +0900 Subject: [PATCH 1/5] spi-topcliff-pch: add tx-memory clear after complete transmitting Currently, in case of reading date from SPI flash, command is sent twice. The cause is that tx-memory clear processing is missing . This patch adds the tx-momory clear processing. Signed-off-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 1d23f3831866..7a98caa3aed2 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -837,6 +837,11 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, DMA_FROM_DEVICE); + + dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent, + DMA_FROM_DEVICE); + memset(data->dma.tx_buf_virt, 0, PAGE_SIZE); + async_tx_ack(dma->desc_rx); async_tx_ack(dma->desc_tx); kfree(dma->sg_tx_p); From 8b7aa961a815dad389525dcd1c36a44c249b1760 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:35 +0900 Subject: [PATCH 2/5] spi-topcliff-pch: Fix SSN Control issue During processing 1 command/data series, SSN should keep LOW. However, currently, SSN becomes HIGH. This patch fixes the issue. Signed-off-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 7a98caa3aed2..c36d51657066 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -58,6 +58,7 @@ #define PCH_SLEEP_TIME 10 #define SSN_LOW 0x02U +#define SSN_HIGH 0x03U #define SSN_NO_CONTROL 0x00U #define PCH_MAX_CS 0xFF #define PCI_DEVICE_ID_GE_SPI 0x8816 @@ -756,10 +757,6 @@ static void pch_spi_set_ir(struct pch_spi_data *data) wait_event_interruptible(data->wait, data->transfer_complete); - pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); - dev_dbg(&data->master->dev, - "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); - /* clear all interrupts */ pch_spi_writereg(data->master, PCH_SPSR, pch_spi_readreg(data->master, PCH_SPSR)); @@ -848,9 +845,6 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) kfree(dma->sg_rx_p); spin_lock_irqsave(&data->lock, flags); - pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); - dev_dbg(&data->master->dev, - "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); /* clear fifo threshold, disable interrupts, disable SPI transfer */ pch_spi_setclr_reg(data->master, PCH_SPCR, 0, @@ -1167,6 +1161,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) if (data->use_dma) pch_spi_request_dma(data, data->current_msg->spi->bits_per_word); + pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); do { /* If we are already processing a message get the next transfer structure from the message otherwise retrieve @@ -1227,6 +1222,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) } while (data->cur_trans != NULL); + pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); if (data->use_dma) pch_spi_release_dma(data); } From 373b0eb64b9c97a14720896dcfdebfa3268b1991 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:36 +0900 Subject: [PATCH 3/5] spi-topcliff-pch: Fix CPU read complete condition issue We found Rx data sometimes drops.(with non-DMA transfer mode) The cause is read complete condition is not true. This patch fixes the issue. Signed-off-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index c36d51657066..6cb2fdbe5dba 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -317,16 +317,19 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, /* if transfer complete interrupt */ if (reg_spsr_val & SPSR_FI_BIT) { - if (tx_index < bpw_len) + if ((tx_index == bpw_len) && (rx_index == tx_index)) { + /* disable interrupts */ + pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); + + /* transfer is completed; + inform pch_spi_process_messages */ + data->transfer_complete = true; + data->transfer_active = false; + wake_up(&data->wait); + } else { dev_err(&data->master->dev, "%s : Transfer is not completed", __func__); - /* disable interrupts */ - pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); - - /* transfer is completed;inform pch_spi_process_messages */ - data->transfer_complete = true; - data->transfer_active = false; - wake_up(&data->wait); + } } } From 25e803f9c339a070cd7361e853aebde11b1f9217 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:37 +0900 Subject: [PATCH 4/5] 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 Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 31 ++++++++++++++++++++++++------- 1 file 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) "%s returning due to suspend\n", __func__); return IRQ_NONE; } - if (data->use_dma) - return IRQ_NONE; io_remap_addr = data->io_remap_addr; spsr = io_remap_addr + PCH_SPSR; reg_spsr_val = ioread32(spsr); - if (reg_spsr_val & SPSR_ORF_BIT) - dev_err(&board_dat->pdev->dev, "%s Over run error", __func__); + if (reg_spsr_val & SPSR_ORF_BIT) { + 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 */ 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) } } -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; unsigned long flags; + int rtn; dma = &data->dma; @@ -833,7 +844,9 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) initiating the transfer. */ dev_dbg(&data->master->dev, "%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_FROM_DEVICE); @@ -860,6 +873,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) pch_spi_clear_fifo(data->master); spin_unlock_irqrestore(&data->lock, flags); + + return rtn; } static void pch_dma_rx_complete(void *arg) @@ -1187,7 +1202,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) if (data->use_dma) { 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); } else { pch_spi_set_tx(data, &bpw); @@ -1225,6 +1241,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) } while (data->cur_trans != NULL); +out: pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); if (data->use_dma) pch_spi_release_dma(data); From f3e03e2eb0bcd9266720695b82a523e6bc526ff7 Mon Sep 17 00:00:00 2001 From: Tomoya MORINAGA Date: Tue, 6 Sep 2011 17:16:38 +0900 Subject: [PATCH 5/5] spi-topcliff-pch: Fix overrun issue We found that adding load, Rx data sometimes drops.(with DMA transfer mode) The cause is that before starting Rx-DMA processing, Tx-DMA processing starts. This causes FIFO overrun occurs. This patch fixes the issue by modifying FIFO tx-threshold and DMA descriptor size like below. Current this patch Rx-descriptor 4Byte+12Byte*341 --> 12Byte*340-4Byte-12Byte Rx-threshold (Not modified) Tx-descriptor 4Byte+12Byte*341 --> 16Byte-12Byte*340 Rx-threshold 12Byte --> 2Byte Signed-off-by: Tomoya MORINAGA Signed-off-by: Grant Likely --- drivers/spi/spi-topcliff-pch.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index c8efa757fdaa..6a80749391db 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c @@ -50,6 +50,8 @@ #define PCH_RX_THOLD 7 #define PCH_RX_THOLD_MAX 15 +#define PCH_TX_THOLD 2 + #define PCH_MAX_BAUDRATE 5000000 #define PCH_MAX_FIFO_DEPTH 16 @@ -1040,8 +1042,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) /* set receive fifo threshold and transmit fifo threshold */ pch_spi_setclr_reg(data->master, PCH_SPCR, ((size - 1) << SPCR_RFIC_FIELD) | - ((PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE) << - SPCR_TFIC_FIELD), + (PCH_TX_THOLD << SPCR_TFIC_FIELD), MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS); spin_unlock_irqrestore(&data->lock, flags); @@ -1052,13 +1053,20 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) /* offset, length setting */ sg = dma->sg_rx_p; for (i = 0; i < num; i++, sg++) { - if (i == 0) { - sg->offset = 0; + if (i == (num - 2)) { + sg->offset = size * i; + sg->offset = sg->offset * (*bpw / 8); sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem, sg->offset); sg_dma_len(sg) = rem; + } else if (i == (num - 1)) { + sg->offset = size * (i - 1) + rem; + sg->offset = sg->offset * (*bpw / 8); + sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, + sg->offset); + sg_dma_len(sg) = size; } else { - sg->offset = rem + size * (i - 1); + sg->offset = size * i; sg->offset = sg->offset * (*bpw / 8); sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, sg->offset); @@ -1082,6 +1090,16 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) dma->desc_rx = desc_rx; /* TX */ + if (data->bpw_len > PCH_DMA_TRANS_SIZE) { + num = data->bpw_len / PCH_DMA_TRANS_SIZE; + size = PCH_DMA_TRANS_SIZE; + rem = 16; + } else { + num = 1; + size = data->bpw_len; + rem = data->bpw_len; + } + dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */ /* offset, length setting */