|
@@ -99,6 +99,9 @@ struct idmac_desc {
|
|
|
|
|
|
__le32 des3; /* buffer 2 physical address */
|
|
|
};
|
|
|
+
|
|
|
+/* Each descriptor can transfer up to 4KB of data in chained mode */
|
|
|
+#define DW_MCI_DESC_DATA_LENGTH 0x1000
|
|
|
#endif /* CONFIG_MMC_DW_IDMAC */
|
|
|
|
|
|
static bool dw_mci_reset(struct dw_mci *host);
|
|
@@ -462,66 +465,96 @@ static void dw_mci_idmac_complete_dma(struct dw_mci *host)
|
|
|
static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
|
|
|
unsigned int sg_len)
|
|
|
{
|
|
|
+ unsigned int desc_len;
|
|
|
int i;
|
|
|
if (host->dma_64bit_address == 1) {
|
|
|
- struct idmac_desc_64addr *desc = host->sg_cpu;
|
|
|
+ struct idmac_desc_64addr *desc_first, *desc_last, *desc;
|
|
|
+
|
|
|
+ desc_first = desc_last = desc = host->sg_cpu;
|
|
|
|
|
|
- for (i = 0; i < sg_len; i++, desc++) {
|
|
|
+ for (i = 0; i < sg_len; i++) {
|
|
|
unsigned int length = sg_dma_len(&data->sg[i]);
|
|
|
u64 mem_addr = sg_dma_address(&data->sg[i]);
|
|
|
|
|
|
- /*
|
|
|
- * Set the OWN bit and disable interrupts for this
|
|
|
- * descriptor
|
|
|
- */
|
|
|
- desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
|
|
|
- IDMAC_DES0_CH;
|
|
|
- /* Buffer length */
|
|
|
- IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length);
|
|
|
-
|
|
|
- /* Physical address to DMA to/from */
|
|
|
- desc->des4 = mem_addr & 0xffffffff;
|
|
|
- desc->des5 = mem_addr >> 32;
|
|
|
+ for ( ; length ; desc++) {
|
|
|
+ desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
|
|
|
+ length : DW_MCI_DESC_DATA_LENGTH;
|
|
|
+
|
|
|
+ length -= desc_len;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Set the OWN bit and disable interrupts
|
|
|
+ * for this descriptor
|
|
|
+ */
|
|
|
+ desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
|
|
|
+ IDMAC_DES0_CH;
|
|
|
+
|
|
|
+ /* Buffer length */
|
|
|
+ IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, desc_len);
|
|
|
+
|
|
|
+ /* Physical address to DMA to/from */
|
|
|
+ desc->des4 = mem_addr & 0xffffffff;
|
|
|
+ desc->des5 = mem_addr >> 32;
|
|
|
+
|
|
|
+ /* Update physical address for the next desc */
|
|
|
+ mem_addr += desc_len;
|
|
|
+
|
|
|
+ /* Save pointer to the last descriptor */
|
|
|
+ desc_last = desc;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Set first descriptor */
|
|
|
- desc = host->sg_cpu;
|
|
|
- desc->des0 |= IDMAC_DES0_FD;
|
|
|
+ desc_first->des0 |= IDMAC_DES0_FD;
|
|
|
|
|
|
/* Set last descriptor */
|
|
|
- desc = host->sg_cpu + (i - 1) *
|
|
|
- sizeof(struct idmac_desc_64addr);
|
|
|
- desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
|
|
|
- desc->des0 |= IDMAC_DES0_LD;
|
|
|
+ desc_last->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
|
|
|
+ desc_last->des0 |= IDMAC_DES0_LD;
|
|
|
|
|
|
} else {
|
|
|
- struct idmac_desc *desc = host->sg_cpu;
|
|
|
+ struct idmac_desc *desc_first, *desc_last, *desc;
|
|
|
+
|
|
|
+ desc_first = desc_last = desc = host->sg_cpu;
|
|
|
|
|
|
- for (i = 0; i < sg_len; i++, desc++) {
|
|
|
+ for (i = 0; i < sg_len; i++) {
|
|
|
unsigned int length = sg_dma_len(&data->sg[i]);
|
|
|
u32 mem_addr = sg_dma_address(&data->sg[i]);
|
|
|
|
|
|
- /*
|
|
|
- * Set the OWN bit and disable interrupts for this
|
|
|
- * descriptor
|
|
|
- */
|
|
|
- desc->des0 = cpu_to_le32(IDMAC_DES0_OWN |
|
|
|
- IDMAC_DES0_DIC | IDMAC_DES0_CH);
|
|
|
- /* Buffer length */
|
|
|
- IDMAC_SET_BUFFER1_SIZE(desc, length);
|
|
|
+ for ( ; length ; desc++) {
|
|
|
+ desc_len = (length <= DW_MCI_DESC_DATA_LENGTH) ?
|
|
|
+ length : DW_MCI_DESC_DATA_LENGTH;
|
|
|
+
|
|
|
+ length -= desc_len;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Set the OWN bit and disable interrupts
|
|
|
+ * for this descriptor
|
|
|
+ */
|
|
|
+ desc->des0 = cpu_to_le32(IDMAC_DES0_OWN |
|
|
|
+ IDMAC_DES0_DIC |
|
|
|
+ IDMAC_DES0_CH);
|
|
|
+
|
|
|
+ /* Buffer length */
|
|
|
+ IDMAC_SET_BUFFER1_SIZE(desc, desc_len);
|
|
|
|
|
|
- /* Physical address to DMA to/from */
|
|
|
- desc->des2 = cpu_to_le32(mem_addr);
|
|
|
+ /* Physical address to DMA to/from */
|
|
|
+ desc->des2 = cpu_to_le32(mem_addr);
|
|
|
+
|
|
|
+ /* Update physical address for the next desc */
|
|
|
+ mem_addr += desc_len;
|
|
|
+
|
|
|
+ /* Save pointer to the last descriptor */
|
|
|
+ desc_last = desc;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/* Set first descriptor */
|
|
|
- desc = host->sg_cpu;
|
|
|
- desc->des0 |= cpu_to_le32(IDMAC_DES0_FD);
|
|
|
+ desc_first->des0 |= cpu_to_le32(IDMAC_DES0_FD);
|
|
|
|
|
|
/* Set last descriptor */
|
|
|
- desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
|
|
|
- desc->des0 &= cpu_to_le32(~(IDMAC_DES0_CH | IDMAC_DES0_DIC));
|
|
|
- desc->des0 |= cpu_to_le32(IDMAC_DES0_LD);
|
|
|
+ desc_last->des0 &= cpu_to_le32(~(IDMAC_DES0_CH |
|
|
|
+ IDMAC_DES0_DIC));
|
|
|
+ desc_last->des0 |= cpu_to_le32(IDMAC_DES0_LD);
|
|
|
}
|
|
|
|
|
|
wmb();
|
|
@@ -2394,7 +2427,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
|
|
|
#ifdef CONFIG_MMC_DW_IDMAC
|
|
|
mmc->max_segs = host->ring_size;
|
|
|
mmc->max_blk_size = 65536;
|
|
|
- mmc->max_seg_size = 0x1000;
|
|
|
+ mmc->max_seg_size = DW_MCI_DESC_DATA_LENGTH;
|
|
|
mmc->max_req_size = mmc->max_seg_size * host->ring_size;
|
|
|
mmc->max_blk_count = mmc->max_req_size / 512;
|
|
|
#else
|