mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	sdhci: scatter-gather (ADMA) support
Add support for the scatter-gather DMA mode present on newer controllers. As the mode requires 32-bit alignment, non-aligned chunks are handled by using a bounce buffer. Also add some new quirks to handle controllers that have bugs in the ADMA engine. Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
This commit is contained in:
		
							parent
							
								
									93fc48c785
								
							
						
					
					
						commit
						2134a922c6
					
				
					 3 changed files with 407 additions and 44 deletions
				
			
		| 
						 | 
					@ -142,6 +142,7 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
 | 
				
			||||||
	if (chip->pdev->revision == 0) {
 | 
						if (chip->pdev->revision == 0) {
 | 
				
			||||||
		chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
 | 
							chip->quirks |= SDHCI_QUIRK_32BIT_DMA_ADDR |
 | 
				
			||||||
			  SDHCI_QUIRK_32BIT_DMA_SIZE |
 | 
								  SDHCI_QUIRK_32BIT_DMA_SIZE |
 | 
				
			||||||
 | 
								  SDHCI_QUIRK_32BIT_ADMA_SIZE |
 | 
				
			||||||
			  SDHCI_QUIRK_RESET_AFTER_REQUEST;
 | 
								  SDHCI_QUIRK_RESET_AFTER_REQUEST;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -206,6 +207,22 @@ static void jmicron_enable_mmc(struct sdhci_host *host, int on)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
 | 
					static int jmicron_probe_slot(struct sdhci_pci_slot *slot)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
						if (slot->chip->pdev->revision == 0) {
 | 
				
			||||||
 | 
							u16 version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							version = readl(slot->host->ioaddr + SDHCI_HOST_VERSION);
 | 
				
			||||||
 | 
							version = (version & SDHCI_VENDOR_VER_MASK) >>
 | 
				
			||||||
 | 
								SDHCI_VENDOR_VER_SHIFT;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Older versions of the chip have lots of nasty glitches
 | 
				
			||||||
 | 
							 * in the ADMA engine. It's best just to avoid it
 | 
				
			||||||
 | 
							 * completely.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							if (version < 0xAC)
 | 
				
			||||||
 | 
								slot->host->quirks |= SDHCI_QUIRK_BROKEN_ADMA;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The secondary interface requires a bit set to get the
 | 
						 * The secondary interface requires a bit set to get the
 | 
				
			||||||
	 * interrupts.
 | 
						 * interrupts.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -124,7 +124,8 @@ static void sdhci_init(struct sdhci_host *host)
 | 
				
			||||||
		SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
 | 
							SDHCI_INT_END_BIT | SDHCI_INT_CRC | SDHCI_INT_TIMEOUT |
 | 
				
			||||||
		SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
 | 
							SDHCI_INT_CARD_REMOVE | SDHCI_INT_CARD_INSERT |
 | 
				
			||||||
		SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
 | 
							SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL |
 | 
				
			||||||
		SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE;
 | 
							SDHCI_INT_DMA_END | SDHCI_INT_DATA_END | SDHCI_INT_RESPONSE |
 | 
				
			||||||
 | 
							SDHCI_INT_ADMA_ERROR;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
 | 
						writel(intmask, host->ioaddr + SDHCI_INT_ENABLE);
 | 
				
			||||||
	writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
 | 
						writel(intmask, host->ioaddr + SDHCI_SIGNAL_ENABLE);
 | 
				
			||||||
| 
						 | 
					@ -314,6 +315,196 @@ static void sdhci_transfer_pio(struct sdhci_host *host)
 | 
				
			||||||
	DBG("PIO transfer complete.\n");
 | 
						DBG("PIO transfer complete.\n");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static char *sdhci_kmap_atomic(struct scatterlist *sg, unsigned long *flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						local_irq_save(*flags);
 | 
				
			||||||
 | 
						return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						kunmap_atomic(buffer, KM_BIO_SRC_IRQ);
 | 
				
			||||||
 | 
						local_irq_restore(*flags);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sdhci_adma_table_pre(struct sdhci_host *host,
 | 
				
			||||||
 | 
						struct mmc_data *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int direction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8 *desc;
 | 
				
			||||||
 | 
						u8 *align;
 | 
				
			||||||
 | 
						dma_addr_t addr;
 | 
				
			||||||
 | 
						dma_addr_t align_addr;
 | 
				
			||||||
 | 
						int len, offset;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct scatterlist *sg;
 | 
				
			||||||
 | 
						int i;
 | 
				
			||||||
 | 
						char *buffer;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The spec does not specify endianness of descriptor table.
 | 
				
			||||||
 | 
						 * We currently guess that it is LE.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data->flags & MMC_DATA_READ)
 | 
				
			||||||
 | 
							direction = DMA_FROM_DEVICE;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							direction = DMA_TO_DEVICE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The ADMA descriptor table is mapped further down as we
 | 
				
			||||||
 | 
						 * need to fill it with data first.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						host->align_addr = dma_map_single(mmc_dev(host->mmc),
 | 
				
			||||||
 | 
							host->align_buffer, 128 * 4, direction);
 | 
				
			||||||
 | 
						BUG_ON(host->align_addr & 0x3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						host->sg_count = dma_map_sg(mmc_dev(host->mmc),
 | 
				
			||||||
 | 
							data->sg, data->sg_len, direction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc = host->adma_desc;
 | 
				
			||||||
 | 
						align = host->align_buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						align_addr = host->align_addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for_each_sg(data->sg, sg, host->sg_count, i) {
 | 
				
			||||||
 | 
							addr = sg_dma_address(sg);
 | 
				
			||||||
 | 
							len = sg_dma_len(sg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * The SDHCI specification states that ADMA
 | 
				
			||||||
 | 
							 * addresses must be 32-bit aligned. If they
 | 
				
			||||||
 | 
							 * aren't, then we use a bounce buffer for
 | 
				
			||||||
 | 
							 * the (up to three) bytes that screw up the
 | 
				
			||||||
 | 
							 * alignment.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							offset = (4 - (addr & 0x3)) & 0x3;
 | 
				
			||||||
 | 
							if (offset) {
 | 
				
			||||||
 | 
								if (data->flags & MMC_DATA_WRITE) {
 | 
				
			||||||
 | 
									buffer = sdhci_kmap_atomic(sg, &flags);
 | 
				
			||||||
 | 
									memcpy(align, buffer, offset);
 | 
				
			||||||
 | 
									sdhci_kunmap_atomic(buffer, &flags);
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								desc[7] = (align_addr >> 24) & 0xff;
 | 
				
			||||||
 | 
								desc[6] = (align_addr >> 16) & 0xff;
 | 
				
			||||||
 | 
								desc[5] = (align_addr >> 8) & 0xff;
 | 
				
			||||||
 | 
								desc[4] = (align_addr >> 0) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								BUG_ON(offset > 65536);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								desc[3] = (offset >> 8) & 0xff;
 | 
				
			||||||
 | 
								desc[2] = (offset >> 0) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								desc[1] = 0x00;
 | 
				
			||||||
 | 
								desc[0] = 0x21; /* tran, valid */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								align += 4;
 | 
				
			||||||
 | 
								align_addr += 4;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								desc += 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								addr += offset;
 | 
				
			||||||
 | 
								len -= offset;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							desc[7] = (addr >> 24) & 0xff;
 | 
				
			||||||
 | 
							desc[6] = (addr >> 16) & 0xff;
 | 
				
			||||||
 | 
							desc[5] = (addr >> 8) & 0xff;
 | 
				
			||||||
 | 
							desc[4] = (addr >> 0) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							BUG_ON(len > 65536);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							desc[3] = (len >> 8) & 0xff;
 | 
				
			||||||
 | 
							desc[2] = (len >> 0) & 0xff;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							desc[1] = 0x00;
 | 
				
			||||||
 | 
							desc[0] = 0x21; /* tran, valid */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							desc += 8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * If this triggers then we have a calculation bug
 | 
				
			||||||
 | 
							 * somewhere. :/
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							WARN_ON((desc - host->adma_desc) > (128 * 2 + 1) * 4);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Add a terminating entry.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						desc[7] = 0;
 | 
				
			||||||
 | 
						desc[6] = 0;
 | 
				
			||||||
 | 
						desc[5] = 0;
 | 
				
			||||||
 | 
						desc[4] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc[3] = 0;
 | 
				
			||||||
 | 
						desc[2] = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						desc[1] = 0x00;
 | 
				
			||||||
 | 
						desc[0] = 0x03; /* nop, end, valid */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Resync align buffer as we might have changed it.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (data->flags & MMC_DATA_WRITE) {
 | 
				
			||||||
 | 
							dma_sync_single_for_device(mmc_dev(host->mmc),
 | 
				
			||||||
 | 
								host->align_addr, 128 * 4, direction);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						host->adma_addr = dma_map_single(mmc_dev(host->mmc),
 | 
				
			||||||
 | 
							host->adma_desc, (128 * 2 + 1) * 4, DMA_TO_DEVICE);
 | 
				
			||||||
 | 
						BUG_ON(host->adma_addr & 0x3);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void sdhci_adma_table_post(struct sdhci_host *host,
 | 
				
			||||||
 | 
						struct mmc_data *data)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int direction;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct scatterlist *sg;
 | 
				
			||||||
 | 
						int i, size;
 | 
				
			||||||
 | 
						u8 *align;
 | 
				
			||||||
 | 
						char *buffer;
 | 
				
			||||||
 | 
						unsigned long flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data->flags & MMC_DATA_READ)
 | 
				
			||||||
 | 
							direction = DMA_FROM_DEVICE;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							direction = DMA_TO_DEVICE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dma_unmap_single(mmc_dev(host->mmc), host->adma_addr,
 | 
				
			||||||
 | 
							(128 * 2 + 1) * 4, DMA_TO_DEVICE);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
 | 
				
			||||||
 | 
							128 * 4, direction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (data->flags & MMC_DATA_READ) {
 | 
				
			||||||
 | 
							dma_sync_sg_for_cpu(mmc_dev(host->mmc), data->sg,
 | 
				
			||||||
 | 
								data->sg_len, direction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							align = host->align_buffer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for_each_sg(data->sg, sg, host->sg_count, i) {
 | 
				
			||||||
 | 
								if (sg_dma_address(sg) & 0x3) {
 | 
				
			||||||
 | 
									size = 4 - (sg_dma_address(sg) & 0x3);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									buffer = sdhci_kmap_atomic(sg, &flags);
 | 
				
			||||||
 | 
									memcpy(buffer, align, size);
 | 
				
			||||||
 | 
									sdhci_kunmap_atomic(buffer, &flags);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									align += 4;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dma_unmap_sg(mmc_dev(host->mmc), data->sg,
 | 
				
			||||||
 | 
							data->sg_len, direction);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
 | 
					static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u8 count;
 | 
						u8 count;
 | 
				
			||||||
| 
						 | 
					@ -363,6 +554,7 @@ static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_data *data)
 | 
				
			||||||
static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 | 
					static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	u8 count;
 | 
						u8 count;
 | 
				
			||||||
 | 
						u8 ctrl;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WARN_ON(host->data);
 | 
						WARN_ON(host->data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -383,35 +575,104 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data)
 | 
				
			||||||
	if (host->flags & SDHCI_USE_DMA)
 | 
						if (host->flags & SDHCI_USE_DMA)
 | 
				
			||||||
		host->flags |= SDHCI_REQ_USE_DMA;
 | 
							host->flags |= SDHCI_REQ_USE_DMA;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (unlikely((host->flags & SDHCI_REQ_USE_DMA) &&
 | 
						/*
 | 
				
			||||||
		(host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) &&
 | 
						 * FIXME: This doesn't account for merging when mapping the
 | 
				
			||||||
		((data->blksz * data->blocks) & 0x3))) {
 | 
						 * scatterlist.
 | 
				
			||||||
		DBG("Reverting to PIO because of transfer size (%d)\n",
 | 
						 */
 | 
				
			||||||
			data->blksz * data->blocks);
 | 
						if (host->flags & SDHCI_REQ_USE_DMA) {
 | 
				
			||||||
 | 
							int broken, i;
 | 
				
			||||||
 | 
							struct scatterlist *sg;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							broken = 0;
 | 
				
			||||||
 | 
							if (host->flags & SDHCI_USE_ADMA) {
 | 
				
			||||||
 | 
								if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE)
 | 
				
			||||||
 | 
									broken = 1;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (host->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE)
 | 
				
			||||||
 | 
									broken = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (unlikely(broken)) {
 | 
				
			||||||
 | 
								for_each_sg(data->sg, sg, data->sg_len, i) {
 | 
				
			||||||
 | 
									if (sg->length & 0x3) {
 | 
				
			||||||
 | 
										DBG("Reverting to PIO because of "
 | 
				
			||||||
 | 
											"transfer size (%d)\n",
 | 
				
			||||||
 | 
											sg->length);
 | 
				
			||||||
					host->flags &= ~SDHCI_REQ_USE_DMA;
 | 
										host->flags &= ~SDHCI_REQ_USE_DMA;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The assumption here being that alignment is the same after
 | 
						 * The assumption here being that alignment is the same after
 | 
				
			||||||
	 * translation to device address space.
 | 
						 * translation to device address space.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (unlikely((host->flags & SDHCI_REQ_USE_DMA) &&
 | 
						if (host->flags & SDHCI_REQ_USE_DMA) {
 | 
				
			||||||
		(host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) &&
 | 
							int broken, i;
 | 
				
			||||||
		(data->sg->offset & 0x3))) {
 | 
							struct scatterlist *sg;
 | 
				
			||||||
		DBG("Reverting to PIO because of bad alignment\n");
 | 
					
 | 
				
			||||||
 | 
							broken = 0;
 | 
				
			||||||
 | 
							if (host->flags & SDHCI_USE_ADMA) {
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * As we use 3 byte chunks to work around
 | 
				
			||||||
 | 
								 * alignment problems, we need to check this
 | 
				
			||||||
 | 
								 * quirk.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								if (host->quirks & SDHCI_QUIRK_32BIT_ADMA_SIZE)
 | 
				
			||||||
 | 
									broken = 1;
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
 | 
								if (host->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR)
 | 
				
			||||||
 | 
									broken = 1;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (unlikely(broken)) {
 | 
				
			||||||
 | 
								for_each_sg(data->sg, sg, data->sg_len, i) {
 | 
				
			||||||
 | 
									if (sg->offset & 0x3) {
 | 
				
			||||||
 | 
										DBG("Reverting to PIO because of "
 | 
				
			||||||
 | 
											"bad alignment\n");
 | 
				
			||||||
					host->flags &= ~SDHCI_REQ_USE_DMA;
 | 
										host->flags &= ~SDHCI_REQ_USE_DMA;
 | 
				
			||||||
 | 
										break;
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Always adjust the DMA selection as some controllers
 | 
				
			||||||
 | 
						 * (e.g. JMicron) can't do PIO properly when the selection
 | 
				
			||||||
 | 
						 * is ADMA.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (host->version >= SDHCI_SPEC_200) {
 | 
				
			||||||
 | 
							ctrl = readb(host->ioaddr + SDHCI_HOST_CONTROL);
 | 
				
			||||||
 | 
							ctrl &= ~SDHCI_CTRL_DMA_MASK;
 | 
				
			||||||
 | 
							if ((host->flags & SDHCI_REQ_USE_DMA) &&
 | 
				
			||||||
 | 
								(host->flags & SDHCI_USE_ADMA))
 | 
				
			||||||
 | 
								ctrl |= SDHCI_CTRL_ADMA32;
 | 
				
			||||||
 | 
							else
 | 
				
			||||||
 | 
								ctrl |= SDHCI_CTRL_SDMA;
 | 
				
			||||||
 | 
							writeb(ctrl, host->ioaddr + SDHCI_HOST_CONTROL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (host->flags & SDHCI_REQ_USE_DMA) {
 | 
						if (host->flags & SDHCI_REQ_USE_DMA) {
 | 
				
			||||||
 | 
							if (host->flags & SDHCI_USE_ADMA) {
 | 
				
			||||||
 | 
								sdhci_adma_table_pre(host, data);
 | 
				
			||||||
 | 
								writel(host->adma_addr,
 | 
				
			||||||
 | 
									host->ioaddr + SDHCI_ADMA_ADDRESS);
 | 
				
			||||||
 | 
							} else {
 | 
				
			||||||
			int count;
 | 
								int count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		count = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
 | 
								count = dma_map_sg(mmc_dev(host->mmc),
 | 
				
			||||||
 | 
										data->sg, data->sg_len,
 | 
				
			||||||
					(data->flags & MMC_DATA_READ) ?
 | 
										(data->flags & MMC_DATA_READ) ?
 | 
				
			||||||
					DMA_FROM_DEVICE : DMA_TO_DEVICE);
 | 
											DMA_FROM_DEVICE :
 | 
				
			||||||
 | 
											DMA_TO_DEVICE);
 | 
				
			||||||
			WARN_ON(count != 1);
 | 
								WARN_ON(count != 1);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			writel(sg_dma_address(data->sg),
 | 
								writel(sg_dma_address(data->sg),
 | 
				
			||||||
				host->ioaddr + SDHCI_DMA_ADDRESS);
 | 
									host->ioaddr + SDHCI_DMA_ADDRESS);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		host->cur_sg = data->sg;
 | 
							host->cur_sg = data->sg;
 | 
				
			||||||
		host->num_sg = data->sg_len;
 | 
							host->num_sg = data->sg_len;
 | 
				
			||||||
| 
						 | 
					@ -457,10 +718,14 @@ static void sdhci_finish_data(struct sdhci_host *host)
 | 
				
			||||||
	host->data = NULL;
 | 
						host->data = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (host->flags & SDHCI_REQ_USE_DMA) {
 | 
						if (host->flags & SDHCI_REQ_USE_DMA) {
 | 
				
			||||||
		dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
 | 
							if (host->flags & SDHCI_USE_ADMA)
 | 
				
			||||||
			(data->flags & MMC_DATA_READ) ?
 | 
								sdhci_adma_table_post(host, data);
 | 
				
			||||||
 | 
							else {
 | 
				
			||||||
 | 
								dma_unmap_sg(mmc_dev(host->mmc), data->sg,
 | 
				
			||||||
 | 
									data->sg_len, (data->flags & MMC_DATA_READ) ?
 | 
				
			||||||
					DMA_FROM_DEVICE : DMA_TO_DEVICE);
 | 
										DMA_FROM_DEVICE : DMA_TO_DEVICE);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * The specification states that the block count register must
 | 
						 * The specification states that the block count register must
 | 
				
			||||||
| 
						 | 
					@ -1008,6 +1273,8 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
 | 
				
			||||||
		host->data->error = -ETIMEDOUT;
 | 
							host->data->error = -ETIMEDOUT;
 | 
				
			||||||
	else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
 | 
						else if (intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_DATA_END_BIT))
 | 
				
			||||||
		host->data->error = -EILSEQ;
 | 
							host->data->error = -EILSEQ;
 | 
				
			||||||
 | 
						else if (intmask & SDHCI_INT_ADMA_ERROR)
 | 
				
			||||||
 | 
							host->data->error = -EIO;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (host->data->error)
 | 
						if (host->data->error)
 | 
				
			||||||
		sdhci_finish_data(host);
 | 
							sdhci_finish_data(host);
 | 
				
			||||||
| 
						 | 
					@ -1199,7 +1466,6 @@ int sdhci_add_host(struct sdhci_host *host)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mmc_host *mmc;
 | 
						struct mmc_host *mmc;
 | 
				
			||||||
	unsigned int caps;
 | 
						unsigned int caps;
 | 
				
			||||||
	unsigned int version;
 | 
					 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	WARN_ON(host == NULL);
 | 
						WARN_ON(host == NULL);
 | 
				
			||||||
| 
						 | 
					@ -1213,12 +1479,13 @@ int sdhci_add_host(struct sdhci_host *host)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	sdhci_reset(host, SDHCI_RESET_ALL);
 | 
						sdhci_reset(host, SDHCI_RESET_ALL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	version = readw(host->ioaddr + SDHCI_HOST_VERSION);
 | 
						host->version = readw(host->ioaddr + SDHCI_HOST_VERSION);
 | 
				
			||||||
	version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT;
 | 
						host->version = (host->version & SDHCI_SPEC_VER_MASK)
 | 
				
			||||||
	if (version > 1) {
 | 
									>> SDHCI_SPEC_VER_SHIFT;
 | 
				
			||||||
 | 
						if (host->version > SDHCI_SPEC_200) {
 | 
				
			||||||
		printk(KERN_ERR "%s: Unknown controller version (%d). "
 | 
							printk(KERN_ERR "%s: Unknown controller version (%d). "
 | 
				
			||||||
			"You may experience problems.\n", mmc_hostname(mmc),
 | 
								"You may experience problems.\n", mmc_hostname(mmc),
 | 
				
			||||||
			version);
 | 
								host->version);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
 | 
						caps = readl(host->ioaddr + SDHCI_CAPABILITIES);
 | 
				
			||||||
| 
						 | 
					@ -1236,17 +1503,47 @@ int sdhci_add_host(struct sdhci_host *host)
 | 
				
			||||||
		host->flags &= ~SDHCI_USE_DMA;
 | 
							host->flags &= ~SDHCI_USE_DMA;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (host->flags & SDHCI_USE_DMA) {
 | 
				
			||||||
 | 
							if ((host->version >= SDHCI_SPEC_200) &&
 | 
				
			||||||
 | 
									(caps & SDHCI_CAN_DO_ADMA2))
 | 
				
			||||||
 | 
								host->flags |= SDHCI_USE_ADMA;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if ((host->quirks & SDHCI_QUIRK_BROKEN_ADMA) &&
 | 
				
			||||||
 | 
							(host->flags & SDHCI_USE_ADMA)) {
 | 
				
			||||||
 | 
							DBG("Disabling ADMA as it is marked broken\n");
 | 
				
			||||||
 | 
							host->flags &= ~SDHCI_USE_ADMA;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (host->flags & SDHCI_USE_DMA) {
 | 
						if (host->flags & SDHCI_USE_DMA) {
 | 
				
			||||||
		if (host->ops->enable_dma) {
 | 
							if (host->ops->enable_dma) {
 | 
				
			||||||
			if (host->ops->enable_dma(host)) {
 | 
								if (host->ops->enable_dma(host)) {
 | 
				
			||||||
				printk(KERN_WARNING "%s: No suitable DMA "
 | 
									printk(KERN_WARNING "%s: No suitable DMA "
 | 
				
			||||||
					"available. Falling back to PIO.\n",
 | 
										"available. Falling back to PIO.\n",
 | 
				
			||||||
					mmc_hostname(mmc));
 | 
										mmc_hostname(mmc));
 | 
				
			||||||
				host->flags &= ~SDHCI_USE_DMA;
 | 
									host->flags &= ~(SDHCI_USE_DMA | SDHCI_USE_ADMA);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (host->flags & SDHCI_USE_ADMA) {
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * We need to allocate descriptors for all sg entries
 | 
				
			||||||
 | 
							 * (128) and potentially one alignment transfer for
 | 
				
			||||||
 | 
							 * each of those entries.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							host->adma_desc = kmalloc((128 * 2 + 1) * 4, GFP_KERNEL);
 | 
				
			||||||
 | 
							host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!host->adma_desc || !host->align_buffer) {
 | 
				
			||||||
 | 
								kfree(host->adma_desc);
 | 
				
			||||||
 | 
								kfree(host->align_buffer);
 | 
				
			||||||
 | 
								printk(KERN_WARNING "%s: Unable to allocate ADMA "
 | 
				
			||||||
 | 
									"buffers. Falling back to standard DMA.\n",
 | 
				
			||||||
 | 
									mmc_hostname(mmc));
 | 
				
			||||||
 | 
								host->flags &= ~SDHCI_USE_ADMA;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* XXX: Hack to get MMC layer to avoid highmem */
 | 
						/* XXX: Hack to get MMC layer to avoid highmem */
 | 
				
			||||||
	if (!(host->flags & SDHCI_USE_DMA))
 | 
						if (!(host->flags & SDHCI_USE_DMA))
 | 
				
			||||||
		mmc_dev(host->mmc)->dma_mask = 0;
 | 
							mmc_dev(host->mmc)->dma_mask = 0;
 | 
				
			||||||
| 
						 | 
					@ -1298,13 +1595,16 @@ int sdhci_add_host(struct sdhci_host *host)
 | 
				
			||||||
	spin_lock_init(&host->lock);
 | 
						spin_lock_init(&host->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Maximum number of segments. Hardware cannot do scatter lists.
 | 
						 * Maximum number of segments. Depends on if the hardware
 | 
				
			||||||
 | 
						 * can do scatter/gather or not.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	if (host->flags & SDHCI_USE_DMA)
 | 
						if (host->flags & SDHCI_USE_ADMA)
 | 
				
			||||||
 | 
							mmc->max_hw_segs = 128;
 | 
				
			||||||
 | 
						else if (host->flags & SDHCI_USE_DMA)
 | 
				
			||||||
		mmc->max_hw_segs = 1;
 | 
							mmc->max_hw_segs = 1;
 | 
				
			||||||
	else
 | 
						else /* PIO */
 | 
				
			||||||
		mmc->max_hw_segs = 16;
 | 
							mmc->max_hw_segs = 128;
 | 
				
			||||||
	mmc->max_phys_segs = 16;
 | 
						mmc->max_phys_segs = 128;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Maximum number of sectors in one transfer. Limited by DMA boundary
 | 
						 * Maximum number of sectors in one transfer. Limited by DMA boundary
 | 
				
			||||||
| 
						 | 
					@ -1314,8 +1614,12 @@ int sdhci_add_host(struct sdhci_host *host)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * Maximum segment size. Could be one segment with the maximum number
 | 
						 * Maximum segment size. Could be one segment with the maximum number
 | 
				
			||||||
	 * of bytes.
 | 
						 * of bytes. When doing hardware scatter/gather, each entry cannot
 | 
				
			||||||
 | 
						 * be larger than 64 KiB though.
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
 | 
						if (host->flags & SDHCI_USE_ADMA)
 | 
				
			||||||
 | 
							mmc->max_seg_size = 65536;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
		mmc->max_seg_size = mmc->max_req_size;
 | 
							mmc->max_seg_size = mmc->max_req_size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
| 
						 | 
					@ -1371,8 +1675,9 @@ int sdhci_add_host(struct sdhci_host *host)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mmc_add_host(mmc);
 | 
						mmc_add_host(mmc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s\n",
 | 
						printk(KERN_INFO "%s: SDHCI controller on %s [%s] using %s%s\n",
 | 
				
			||||||
		mmc_hostname(mmc), host->hw_name, mmc_dev(mmc)->bus_id,
 | 
							mmc_hostname(mmc), host->hw_name, mmc_dev(mmc)->bus_id,
 | 
				
			||||||
 | 
							(host->flags & SDHCI_USE_ADMA)?"A":"",
 | 
				
			||||||
		(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
 | 
							(host->flags & SDHCI_USE_DMA)?"DMA":"PIO");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
| 
						 | 
					@ -1426,6 +1731,12 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	tasklet_kill(&host->card_tasklet);
 | 
						tasklet_kill(&host->card_tasklet);
 | 
				
			||||||
	tasklet_kill(&host->finish_tasklet);
 | 
						tasklet_kill(&host->finish_tasklet);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						kfree(host->adma_desc);
 | 
				
			||||||
 | 
						kfree(host->align_buffer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						host->adma_desc = NULL;
 | 
				
			||||||
 | 
						host->align_buffer = NULL;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
EXPORT_SYMBOL_GPL(sdhci_remove_host);
 | 
					EXPORT_SYMBOL_GPL(sdhci_remove_host);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -60,6 +60,11 @@
 | 
				
			||||||
#define  SDHCI_CTRL_LED		0x01
 | 
					#define  SDHCI_CTRL_LED		0x01
 | 
				
			||||||
#define  SDHCI_CTRL_4BITBUS	0x02
 | 
					#define  SDHCI_CTRL_4BITBUS	0x02
 | 
				
			||||||
#define  SDHCI_CTRL_HISPD	0x04
 | 
					#define  SDHCI_CTRL_HISPD	0x04
 | 
				
			||||||
 | 
					#define  SDHCI_CTRL_DMA_MASK	0x18
 | 
				
			||||||
 | 
					#define   SDHCI_CTRL_SDMA	0x00
 | 
				
			||||||
 | 
					#define   SDHCI_CTRL_ADMA1	0x08
 | 
				
			||||||
 | 
					#define   SDHCI_CTRL_ADMA32	0x10
 | 
				
			||||||
 | 
					#define   SDHCI_CTRL_ADMA64	0x18
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SDHCI_POWER_CONTROL	0x29
 | 
					#define SDHCI_POWER_CONTROL	0x29
 | 
				
			||||||
#define  SDHCI_POWER_ON		0x01
 | 
					#define  SDHCI_POWER_ON		0x01
 | 
				
			||||||
| 
						 | 
					@ -105,6 +110,7 @@
 | 
				
			||||||
#define  SDHCI_INT_DATA_END_BIT	0x00400000
 | 
					#define  SDHCI_INT_DATA_END_BIT	0x00400000
 | 
				
			||||||
#define  SDHCI_INT_BUS_POWER	0x00800000
 | 
					#define  SDHCI_INT_BUS_POWER	0x00800000
 | 
				
			||||||
#define  SDHCI_INT_ACMD12ERR	0x01000000
 | 
					#define  SDHCI_INT_ACMD12ERR	0x01000000
 | 
				
			||||||
 | 
					#define  SDHCI_INT_ADMA_ERROR	0x02000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define  SDHCI_INT_NORMAL_MASK	0x00007FFF
 | 
					#define  SDHCI_INT_NORMAL_MASK	0x00007FFF
 | 
				
			||||||
#define  SDHCI_INT_ERROR_MASK	0xFFFF8000
 | 
					#define  SDHCI_INT_ERROR_MASK	0xFFFF8000
 | 
				
			||||||
| 
						 | 
					@ -128,11 +134,14 @@
 | 
				
			||||||
#define  SDHCI_CLOCK_BASE_SHIFT	8
 | 
					#define  SDHCI_CLOCK_BASE_SHIFT	8
 | 
				
			||||||
#define  SDHCI_MAX_BLOCK_MASK	0x00030000
 | 
					#define  SDHCI_MAX_BLOCK_MASK	0x00030000
 | 
				
			||||||
#define  SDHCI_MAX_BLOCK_SHIFT  16
 | 
					#define  SDHCI_MAX_BLOCK_SHIFT  16
 | 
				
			||||||
 | 
					#define  SDHCI_CAN_DO_ADMA2	0x00080000
 | 
				
			||||||
 | 
					#define  SDHCI_CAN_DO_ADMA1	0x00100000
 | 
				
			||||||
#define  SDHCI_CAN_DO_HISPD	0x00200000
 | 
					#define  SDHCI_CAN_DO_HISPD	0x00200000
 | 
				
			||||||
#define  SDHCI_CAN_DO_DMA	0x00400000
 | 
					#define  SDHCI_CAN_DO_DMA	0x00400000
 | 
				
			||||||
#define  SDHCI_CAN_VDD_330	0x01000000
 | 
					#define  SDHCI_CAN_VDD_330	0x01000000
 | 
				
			||||||
#define  SDHCI_CAN_VDD_300	0x02000000
 | 
					#define  SDHCI_CAN_VDD_300	0x02000000
 | 
				
			||||||
#define  SDHCI_CAN_VDD_180	0x04000000
 | 
					#define  SDHCI_CAN_VDD_180	0x04000000
 | 
				
			||||||
 | 
					#define  SDHCI_CAN_64BIT	0x10000000
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 44-47 reserved for more caps */
 | 
					/* 44-47 reserved for more caps */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -140,7 +149,16 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 4C-4F reserved for more max current */
 | 
					/* 4C-4F reserved for more max current */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* 50-FB reserved */
 | 
					#define SDHCI_SET_ACMD12_ERROR	0x50
 | 
				
			||||||
 | 
					#define SDHCI_SET_INT_ERROR	0x52
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SDHCI_ADMA_ERROR	0x54
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 55-57 reserved */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define SDHCI_ADMA_ADDRESS	0x58
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* 60-FB reserved */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define SDHCI_SLOT_INT_STATUS	0xFC
 | 
					#define SDHCI_SLOT_INT_STATUS	0xFC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,6 +167,8 @@
 | 
				
			||||||
#define  SDHCI_VENDOR_VER_SHIFT	8
 | 
					#define  SDHCI_VENDOR_VER_SHIFT	8
 | 
				
			||||||
#define  SDHCI_SPEC_VER_MASK	0x00FF
 | 
					#define  SDHCI_SPEC_VER_MASK	0x00FF
 | 
				
			||||||
#define  SDHCI_SPEC_VER_SHIFT	0
 | 
					#define  SDHCI_SPEC_VER_SHIFT	0
 | 
				
			||||||
 | 
					#define   SDHCI_SPEC_100	0
 | 
				
			||||||
 | 
					#define   SDHCI_SPEC_200	1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct sdhci_ops;
 | 
					struct sdhci_ops;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,16 +190,20 @@ struct sdhci_host {
 | 
				
			||||||
#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
 | 
					#define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS		(1<<4)
 | 
				
			||||||
/* Controller has an unusable DMA engine */
 | 
					/* Controller has an unusable DMA engine */
 | 
				
			||||||
#define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
 | 
					#define SDHCI_QUIRK_BROKEN_DMA				(1<<5)
 | 
				
			||||||
 | 
					/* Controller has an unusable ADMA engine */
 | 
				
			||||||
 | 
					#define SDHCI_QUIRK_BROKEN_ADMA				(1<<6)
 | 
				
			||||||
/* Controller can only DMA from 32-bit aligned addresses */
 | 
					/* Controller can only DMA from 32-bit aligned addresses */
 | 
				
			||||||
#define SDHCI_QUIRK_32BIT_DMA_ADDR			(1<<6)
 | 
					#define SDHCI_QUIRK_32BIT_DMA_ADDR			(1<<7)
 | 
				
			||||||
/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
 | 
					/* Controller can only DMA chunk sizes that are a multiple of 32 bits */
 | 
				
			||||||
#define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<7)
 | 
					#define SDHCI_QUIRK_32BIT_DMA_SIZE			(1<<8)
 | 
				
			||||||
 | 
					/* Controller can only ADMA chunks that are a multiple of 32 bits */
 | 
				
			||||||
 | 
					#define SDHCI_QUIRK_32BIT_ADMA_SIZE			(1<<9)
 | 
				
			||||||
/* Controller needs to be reset after each request to stay stable */
 | 
					/* Controller needs to be reset after each request to stay stable */
 | 
				
			||||||
#define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<8)
 | 
					#define SDHCI_QUIRK_RESET_AFTER_REQUEST			(1<<10)
 | 
				
			||||||
/* Controller needs voltage and power writes to happen separately */
 | 
					/* Controller needs voltage and power writes to happen separately */
 | 
				
			||||||
#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<9)
 | 
					#define SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER		(1<<11)
 | 
				
			||||||
/* Controller provides an incorrect timeout value for transfers */
 | 
					/* Controller provides an incorrect timeout value for transfers */
 | 
				
			||||||
#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL			(1<<10)
 | 
					#define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL			(1<<12)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int			irq;		/* Device IRQ */
 | 
						int			irq;		/* Device IRQ */
 | 
				
			||||||
	void __iomem *		ioaddr;		/* Mapped address */
 | 
						void __iomem *		ioaddr;		/* Mapped address */
 | 
				
			||||||
| 
						 | 
					@ -197,8 +221,11 @@ struct sdhci_host {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	int			flags;		/* Host attributes */
 | 
						int			flags;		/* Host attributes */
 | 
				
			||||||
#define SDHCI_USE_DMA		(1<<0)		/* Host is DMA capable */
 | 
					#define SDHCI_USE_DMA		(1<<0)		/* Host is DMA capable */
 | 
				
			||||||
#define SDHCI_REQ_USE_DMA	(1<<1)		/* Use DMA for this req. */
 | 
					#define SDHCI_USE_ADMA		(1<<1)		/* Host is ADMA capable */
 | 
				
			||||||
#define SDHCI_DEVICE_DEAD	(1<<2)		/* Device unresponsive */
 | 
					#define SDHCI_REQ_USE_DMA	(1<<2)		/* Use DMA for this req. */
 | 
				
			||||||
 | 
					#define SDHCI_DEVICE_DEAD	(1<<3)		/* Device unresponsive */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						unsigned int		version;	/* SDHCI spec. version */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned int		max_clk;	/* Max possible freq (MHz) */
 | 
						unsigned int		max_clk;	/* Max possible freq (MHz) */
 | 
				
			||||||
	unsigned int		timeout_clk;	/* Timeout freq (KHz) */
 | 
						unsigned int		timeout_clk;	/* Timeout freq (KHz) */
 | 
				
			||||||
| 
						 | 
					@ -216,6 +243,14 @@ struct sdhci_host {
 | 
				
			||||||
	int			offset;		/* Offset into current sg */
 | 
						int			offset;		/* Offset into current sg */
 | 
				
			||||||
	int			remain;		/* Bytes left in current */
 | 
						int			remain;		/* Bytes left in current */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						int			sg_count;	/* Mapped sg entries */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8			*adma_desc;	/* ADMA descriptor table */
 | 
				
			||||||
 | 
						u8			*align_buffer;	/* Bounce buffer */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dma_addr_t		adma_addr;	/* Mapped ADMA descr. table */
 | 
				
			||||||
 | 
						dma_addr_t		align_addr;	/* Mapped bounce buffer */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct tasklet_struct	card_tasklet;	/* Tasklet structures */
 | 
						struct tasklet_struct	card_tasklet;	/* Tasklet structures */
 | 
				
			||||||
	struct tasklet_struct	finish_tasklet;
 | 
						struct tasklet_struct	finish_tasklet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue