* 'spi/merge' of git://git.secretlab.ca/git/linux-2.6: spi-topcliff-pch: Fix overrun issue spi-topcliff-pch: Add recovery processing in case FIFO overrun error occurs spi-topcliff-pch: Fix CPU read complete condition issue spi-topcliff-pch: Fix SSN Control issue spi-topcliff-pch: add tx-memory clear after complete transmitting
Unified · Split
| @@ -50,6 +50,8 @@ · 49 unmodified lines | ||
| 50 | 50 | #define PCH_RX_THOLD 7 |
| 51 | 51 | #define PCH_RX_THOLD_MAX 15 |
| 52 | 52 | |
| 53 | +#define PCH_TX_THOLD 2 | |
| 54 | + | |
| 53 | 55 | #define PCH_MAX_BAUDRATE 5000000 |
| 54 | 56 | #define PCH_MAX_FIFO_DEPTH 16 |
| 55 | 57 | |
| @@ -58,6 +60,7 @@ · 2 unmodified lines | ||
| 58 | 60 | #define PCH_SLEEP_TIME 10 |
| 59 | 61 | |
| 60 | 62 | #define SSN_LOW 0x02U |
| 63 | +#define SSN_HIGH 0x03U | |
| 61 | 64 | #define SSN_NO_CONTROL 0x00U |
| 62 | 65 | #define PCH_MAX_CS 0xFF |
| 63 | 66 | #define PCI_DEVICE_ID_GE_SPI 0x8816 |
| @@ -316,16 +319,19 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, · 252 unmodified lines | ||
| 316 | 319 | |
| 317 | 320 | /* if transfer complete interrupt */ |
| 318 | 321 | if (reg_spsr_val & SPSR_FI_BIT) { |
| 319 | − if (tx_index < bpw_len) | |
| 322 | + if ((tx_index == bpw_len) && (rx_index == tx_index)) { | |
| 323 | + /* disable interrupts */ | |
| 324 | + pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); | |
| 325 | + | |
| 326 | + /* transfer is completed; | |
| 327 | + inform pch_spi_process_messages */ | |
| 328 | + data->transfer_complete = true; | |
| 329 | + data->transfer_active = false; | |
| 330 | + wake_up(&data->wait); | |
| 331 | + } else { | |
| 320 | 332 | dev_err(&data->master->dev, |
| 321 | 333 | "%s : Transfer is not completed", __func__); |
| 322 | − /* disable interrupts */ | |
| 323 | − pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); | |
| 324 | − | |
| 325 | − /* transfer is completed;inform pch_spi_process_messages */ | |
| 326 | − data->transfer_complete = true; | |
| 327 | − data->transfer_active = false; | |
| 328 | − wake_up(&data->wait); | |
| 334 | + } | |
| 329 | 335 | } |
| 330 | 336 | } |
| 331 | 337 | |
| @@ -348,16 +354,26 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id) · 16 unmodified lines | ||
| 348 | 354 | "%s returning due to suspend\n", __func__); |
| 349 | 355 | return IRQ_NONE; |
| 350 | 356 | } |
| 351 | − if (data->use_dma) | |
| 352 | − return IRQ_NONE; | |
| 353 | 357 | |
| 354 | 358 | io_remap_addr = data->io_remap_addr; |
| 355 | 359 | spsr = io_remap_addr + PCH_SPSR; |
| 356 | 360 | |
| 357 | 361 | reg_spsr_val = ioread32(spsr); |
| 358 | 362 | |
| 359 | − if (reg_spsr_val & SPSR_ORF_BIT) | |
| 360 | − dev_err(&board_dat->pdev->dev, "%s Over run error", __func__); | |
| 363 | + if (reg_spsr_val & SPSR_ORF_BIT) { | |
| 364 | + dev_err(&board_dat->pdev->dev, "%s Over run error\n", __func__); | |
| 365 | + if (data->current_msg->complete != 0) { | |
| 366 | + data->transfer_complete = true; | |
| 367 | + data->current_msg->status = -EIO; | |
| 368 | + data->current_msg->complete(data->current_msg->context); | |
| 369 | + data->bcurrent_msg_processing = false; | |
| 370 | + data->current_msg = NULL; | |
| 371 | + data->cur_trans = NULL; | |
| 372 | + } | |
| 373 | + } | |
| 374 | + | |
| 375 | + if (data->use_dma) | |
| 376 | + return IRQ_NONE; | |
| 361 | 377 | |
| 362 | 378 | /* Check if the interrupt is for SPI device */ |
| 363 | 379 | if (reg_spsr_val & (SPSR_FI_BIT | SPSR_RFI_BIT)) { |
| @@ -756,10 +772,6 @@ static void pch_spi_set_ir(struct pch_spi_data *data) · 392 unmodified lines | ||
| 756 | 772 | |
| 757 | 773 | wait_event_interruptible(data->wait, data->transfer_complete); |
| 758 | 774 | |
| 759 | − pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); | |
| 760 | − dev_dbg(&data->master->dev, | |
| 761 | − "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); | |
| 762 | − | |
| 763 | 775 | /* clear all interrupts */ |
| 764 | 776 | pch_spi_writereg(data->master, PCH_SPSR, |
| 765 | 777 | pch_spi_readreg(data->master, PCH_SPSR)); |
| @@ -815,10 +827,11 @@ static void pch_spi_copy_rx_data_for_dma(struct pch_spi_data *data, int bpw) · 49 unmodified lines | ||
| 815 | 827 | } |
| 816 | 828 | } |
| 817 | 829 | |
| 818 | −static void pch_spi_start_transfer(struct pch_spi_data *data) | |
| 830 | +static int pch_spi_start_transfer(struct pch_spi_data *data) | |
| 819 | 831 | { |
| 820 | 832 | struct pch_spi_dma_ctrl *dma; |
| 821 | 833 | unsigned long flags; |
| 834 | + int rtn; | |
| 822 | 835 | |
| 823 | 836 | dma = &data->dma; |
| 824 | 837 | |
| @@ -833,19 +846,23 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) · 8 unmodified lines | ||
| 833 | 846 | initiating the transfer. */ |
| 834 | 847 | dev_dbg(&data->master->dev, |
| 835 | 848 | "%s:waiting for transfer to get over\n", __func__); |
| 836 | − wait_event_interruptible(data->wait, data->transfer_complete); | |
| 849 | + rtn = wait_event_interruptible_timeout(data->wait, | |
| 850 | + data->transfer_complete, | |
| 851 | + msecs_to_jiffies(2 * HZ)); | |
| 837 | 852 | |
| 838 | 853 | dma_sync_sg_for_cpu(&data->master->dev, dma->sg_rx_p, dma->nent, |
| 839 | 854 | DMA_FROM_DEVICE); |
| 855 | + | |
| 856 | + dma_sync_sg_for_cpu(&data->master->dev, dma->sg_tx_p, dma->nent, | |
| 857 | + DMA_FROM_DEVICE); | |
| 858 | + memset(data->dma.tx_buf_virt, 0, PAGE_SIZE); | |
| 859 | + | |
| 840 | 860 | async_tx_ack(dma->desc_rx); |
| 841 | 861 | async_tx_ack(dma->desc_tx); |
| 842 | 862 | kfree(dma->sg_tx_p); |
| 843 | 863 | kfree(dma->sg_rx_p); |
| 844 | 864 | |
| 845 | 865 | spin_lock_irqsave(&data->lock, flags); |
| 846 | − pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); | |
| 847 | − dev_dbg(&data->master->dev, | |
| 848 | − "%s:no more control over SSN-writing 0 to SSNXCR.", __func__); | |
| 849 | 866 | |
| 850 | 867 | /* clear fifo threshold, disable interrupts, disable SPI transfer */ |
| 851 | 868 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, |
| @@ -858,6 +875,8 @@ static void pch_spi_start_transfer(struct pch_spi_data *data) · 6 unmodified lines | ||
| 858 | 875 | pch_spi_clear_fifo(data->master); |
| 859 | 876 | |
| 860 | 877 | spin_unlock_irqrestore(&data->lock, flags); |
| 878 | + | |
| 879 | + return rtn; | |
| 861 | 880 | } |
| 862 | 881 | |
| 863 | 882 | static void pch_dma_rx_complete(void *arg) |
| @@ -1023,8 +1042,7 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) · 159 unmodified lines | ||
| 1023 | 1042 | /* set receive fifo threshold and transmit fifo threshold */ |
| 1024 | 1043 | pch_spi_setclr_reg(data->master, PCH_SPCR, |
| 1025 | 1044 | ((size - 1) << SPCR_RFIC_FIELD) | |
| 1026 | − ((PCH_MAX_FIFO_DEPTH - PCH_DMA_TRANS_SIZE) << | |
| 1027 | − SPCR_TFIC_FIELD), | |
| 1045 | + (PCH_TX_THOLD << SPCR_TFIC_FIELD), | |
| 1028 | 1046 | MASK_RFIC_SPCR_BITS | MASK_TFIC_SPCR_BITS); |
| 1029 | 1047 | |
| 1030 | 1048 | spin_unlock_irqrestore(&data->lock, flags); |
| @@ -1035,13 +1053,20 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) · 4 unmodified lines | ||
| 1035 | 1053 | /* offset, length setting */ |
| 1036 | 1054 | sg = dma->sg_rx_p; |
| 1037 | 1055 | for (i = 0; i < num; i++, sg++) { |
| 1038 | − if (i == 0) { | |
| 1039 | − sg->offset = 0; | |
| 1056 | + if (i == (num - 2)) { | |
| 1057 | + sg->offset = size * i; | |
| 1058 | + sg->offset = sg->offset * (*bpw / 8); | |
| 1040 | 1059 | sg_set_page(sg, virt_to_page(dma->rx_buf_virt), rem, |
| 1041 | 1060 | sg->offset); |
| 1042 | 1061 | sg_dma_len(sg) = rem; |
| 1062 | + } else if (i == (num - 1)) { | |
| 1063 | + sg->offset = size * (i - 1) + rem; | |
| 1064 | + sg->offset = sg->offset * (*bpw / 8); | |
| 1065 | + sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, | |
| 1066 | + sg->offset); | |
| 1067 | + sg_dma_len(sg) = size; | |
| 1043 | 1068 | } else { |
| 1044 | − sg->offset = rem + size * (i - 1); | |
| 1069 | + sg->offset = size * i; | |
| 1045 | 1070 | sg->offset = sg->offset * (*bpw / 8); |
| 1046 | 1071 | sg_set_page(sg, virt_to_page(dma->rx_buf_virt), size, |
| 1047 | 1072 | sg->offset); |
| @@ -1065,6 +1090,16 @@ static void pch_spi_handle_dma(struct pch_spi_data *data, int *bpw) · 17 unmodified lines | ||
| 1065 | 1090 | dma->desc_rx = desc_rx; |
| 1066 | 1091 | |
| 1067 | 1092 | /* TX */ |
| 1093 | + if (data->bpw_len > PCH_DMA_TRANS_SIZE) { | |
| 1094 | + num = data->bpw_len / PCH_DMA_TRANS_SIZE; | |
| 1095 | + size = PCH_DMA_TRANS_SIZE; | |
| 1096 | + rem = 16; | |
| 1097 | + } else { | |
| 1098 | + num = 1; | |
| 1099 | + size = data->bpw_len; | |
| 1100 | + rem = data->bpw_len; | |
| 1101 | + } | |
| 1102 | + | |
| 1068 | 1103 | dma->sg_tx_p = kzalloc(sizeof(struct scatterlist)*num, GFP_ATOMIC); |
| 1069 | 1104 | sg_init_table(dma->sg_tx_p, num); /* Initialize SG table */ |
| 1070 | 1105 | /* offset, length setting */ |
| @@ -1162,6 +1197,7 @@ static void pch_spi_process_messages(struct work_struct *pwork) · 91 unmodified lines | ||
| 1162 | 1197 | if (data->use_dma) |
| 1163 | 1198 | pch_spi_request_dma(data, |
| 1164 | 1199 | data->current_msg->spi->bits_per_word); |
| 1200 | + pch_spi_writereg(data->master, PCH_SSNXCR, SSN_NO_CONTROL); | |
| 1165 | 1201 | do { |
| 1166 | 1202 | /* If we are already processing a message get the next |
| 1167 | 1203 | transfer structure from the message otherwise retrieve |
| @@ -1184,7 +1220,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) · 16 unmodified lines | ||
| 1184 | 1220 | |
| 1185 | 1221 | if (data->use_dma) { |
| 1186 | 1222 | pch_spi_handle_dma(data, &bpw); |
| 1187 | − pch_spi_start_transfer(data); | |
| 1223 | + if (!pch_spi_start_transfer(data)) | |
| 1224 | + goto out; | |
| 1188 | 1225 | pch_spi_copy_rx_data_for_dma(data, bpw); |
| 1189 | 1226 | } else { |
| 1190 | 1227 | pch_spi_set_tx(data, &bpw); |
| @@ -1222,6 +1259,8 @@ static void pch_spi_process_messages(struct work_struct *pwork) · 31 unmodified lines | ||
| 1222 | 1259 | |
| 1223 | 1260 | } while (data->cur_trans != NULL); |
| 1224 | 1261 | |
| 1262 | +out: | |
| 1263 | + pch_spi_writereg(data->master, PCH_SSNXCR, SSN_HIGH); | |
| 1225 | 1264 | if (data->use_dma) |
| 1226 | 1265 | pch_spi_release_dma(data); |
| 1227 | 1266 | } |