diff options
Diffstat (limited to 'drivers/mmc')
-rw-r--r-- | drivers/mmc/card/block.c | 22 | ||||
-rw-r--r-- | drivers/mmc/card/queue.c | 3 | ||||
-rw-r--r-- | drivers/mmc/card/sdio_uart.c | 2 | ||||
-rw-r--r-- | drivers/mmc/host/mmc_spi.c | 10 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.c | 63 | ||||
-rw-r--r-- | drivers/mmc/host/sdhci.h | 3 | ||||
-rw-r--r-- | drivers/mmc/host/tifm_sd.c | 18 |
7 files changed, 83 insertions, 38 deletions
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c index e38d5a3b2a8..aeb32a93f6a 100644 --- a/drivers/mmc/card/block.c +++ b/drivers/mmc/card/block.c @@ -44,6 +44,9 @@ * max 8 partitions per card */ #define MMC_SHIFT 3 +#define MMC_NUM_MINORS (256 >> MMC_SHIFT) + +static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; /* * There is one mmc_blk_data per slot. @@ -80,6 +83,9 @@ static void mmc_blk_put(struct mmc_blk_data *md) mutex_lock(&open_lock); md->usage--; if (md->usage == 0) { + int devidx = md->disk->first_minor >> MMC_SHIFT; + __clear_bit(devidx, dev_use); + put_disk(md->disk); kfree(md); } @@ -321,7 +327,13 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) req->rq_disk->disk_name, err); goto cmd_err; } - } while (!(cmd.resp[0] & R1_READY_FOR_DATA)); + /* + * Some cards mishandle the status bits, + * so make sure to check both the busy + * indication and the card state. + */ + } while (!(cmd.resp[0] & R1_READY_FOR_DATA) || + (R1_CURRENT_STATE(cmd.resp[0]) == 7)); #if 0 if (cmd.resp[0] & ~0x00000900) @@ -400,9 +412,6 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) return 0; } -#define MMC_NUM_MINORS (256 >> MMC_SHIFT) - -static unsigned long dev_use[MMC_NUM_MINORS/(8*sizeof(unsigned long))]; static inline int mmc_blk_readonly(struct mmc_card *card) { @@ -568,17 +577,12 @@ static void mmc_blk_remove(struct mmc_card *card) struct mmc_blk_data *md = mmc_get_drvdata(card); if (md) { - int devidx; - /* Stop new requests from getting into the queue */ del_gendisk(md->disk); /* Then flush out any already in there */ mmc_cleanup_queue(&md->queue); - devidx = md->disk->first_minor >> MMC_SHIFT; - __clear_bit(devidx, dev_use); - mmc_blk_put(md); } mmc_set_drvdata(card, NULL); diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c index 1b9c9b6da5b..30cd13b13ac 100644 --- a/drivers/mmc/card/queue.c +++ b/drivers/mmc/card/queue.c @@ -180,12 +180,13 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock blk_queue_max_hw_segments(mq->queue, host->max_hw_segs); blk_queue_max_segment_size(mq->queue, host->max_seg_size); - mq->sg = kzalloc(sizeof(struct scatterlist) * + mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs, GFP_KERNEL); if (!mq->sg) { ret = -ENOMEM; goto cleanup_queue; } + sg_init_table(mq->sg, host->max_phys_segs); } init_MUTEX(&mq->thread_sem); diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index d552de68311..eeea84c309e 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -386,7 +386,7 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port) sdio_out(port, UART_IER, port->ier); } -static void sdio_uart_receive_chars(struct sdio_uart_port *port, int *status) +static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *status) { struct tty_struct *tty = port->tty; unsigned int ch, flag; diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c index a6469218f19..365024b83d3 100644 --- a/drivers/mmc/host/mmc_spi.c +++ b/drivers/mmc/host/mmc_spi.c @@ -176,8 +176,6 @@ mmc_spi_readbytes(struct mmc_spi_host *host, unsigned len) DMA_FROM_DEVICE); status = spi_sync(host->spi, &host->readback); - if (status == 0) - status = host->readback.status; if (host->dma_dev) dma_sync_single_for_cpu(host->dma_dev, @@ -480,8 +478,6 @@ mmc_spi_command_send(struct mmc_spi_host *host, DMA_BIDIRECTIONAL); } status = spi_sync(host->spi, &host->m); - if (status == 0) - status = host->m.status; if (host->dma_dev) dma_sync_single_for_cpu(host->dma_dev, @@ -624,8 +620,6 @@ mmc_spi_writeblock(struct mmc_spi_host *host, struct spi_transfer *t) DMA_BIDIRECTIONAL); status = spi_sync(spi, &host->m); - if (status == 0) - status = host->m.status; if (status != 0) { dev_dbg(&spi->dev, "write error (%d)\n", status); @@ -726,8 +720,6 @@ mmc_spi_readblock(struct mmc_spi_host *host, struct spi_transfer *t) } status = spi_sync(spi, &host->m); - if (status == 0) - status = host->m.status; if (host->dma_dev) { dma_sync_single_for_cpu(host->dma_dev, @@ -905,8 +897,6 @@ mmc_spi_data_do(struct mmc_spi_host *host, struct mmc_command *cmd, DMA_BIDIRECTIONAL); tmp = spi_sync(spi, &host->m); - if (tmp == 0) - tmp = host->m.status; if (host->dma_dev) dma_sync_single_for_cpu(host->dma_dev, diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index ff59d2e0475..785bbdcf4a5 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -7,6 +7,10 @@ * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or (at * your option) any later version. + * + * Thanks to the following companies for their support: + * + * - JMicron (hardware and technical support) */ #include <linux/delay.h> @@ -26,13 +30,29 @@ static unsigned int debug_quirks = 0; +/* + * Different quirks to handle when the hardware deviates from a strict + * interpretation of the SDHCI specification. + */ + +/* Controller doesn't honor resets unless we touch the clock register */ #define SDHCI_QUIRK_CLOCK_BEFORE_RESET (1<<0) +/* Controller has bad caps bits, but really supports DMA */ #define SDHCI_QUIRK_FORCE_DMA (1<<1) /* Controller doesn't like some resets when there is no card inserted. */ #define SDHCI_QUIRK_NO_CARD_NO_RESET (1<<2) +/* Controller doesn't like clearing the power reg before a change */ #define SDHCI_QUIRK_SINGLE_POWER_WRITE (1<<3) +/* Controller has flaky internal state so reset it on each ios change */ #define SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS (1<<4) +/* Controller has an unusable DMA engine */ #define SDHCI_QUIRK_BROKEN_DMA (1<<5) +/* Controller can only DMA from 32-bit aligned addresses */ +#define SDHCI_QUIRK_32BIT_DMA_ADDR (1<<6) +/* Controller can only DMA chunk sizes that are a multiple of 32 bits */ +#define SDHCI_QUIRK_32BIT_DMA_SIZE (1<<7) +/* Controller needs to be reset after each request to stay stable */ +#define SDHCI_QUIRK_RESET_AFTER_REQUEST (1<<8) static const struct pci_device_id pci_ids[] __devinitdata = { { @@ -97,6 +117,16 @@ static const struct pci_device_id pci_ids[] __devinitdata = { SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS, }, + { + .vendor = PCI_VENDOR_ID_JMICRON, + .device = PCI_DEVICE_ID_JMICRON_JMB38X_SD, + .subvendor = PCI_ANY_ID, + .subdevice = PCI_ANY_ID, + .driver_data = SDHCI_QUIRK_32BIT_DMA_ADDR | + SDHCI_QUIRK_32BIT_DMA_SIZE | + SDHCI_QUIRK_RESET_AFTER_REQUEST, + }, + { /* Generic SD host controller */ PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00) }, @@ -419,7 +449,29 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_data *data) writeb(count, host->ioaddr + SDHCI_TIMEOUT_CONTROL); - if (host->flags & SDHCI_USE_DMA) { + if (host->flags & SDHCI_USE_DMA) + host->flags |= SDHCI_REQ_USE_DMA; + + if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && + (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_SIZE) && + ((data->blksz * data->blocks) & 0x3))) { + DBG("Reverting to PIO because of transfer size (%d)\n", + data->blksz * data->blocks); + host->flags &= ~SDHCI_REQ_USE_DMA; + } + + /* + * The assumption here being that alignment is the same after + * translation to device address space. + */ + if (unlikely((host->flags & SDHCI_REQ_USE_DMA) && + (host->chip->quirks & SDHCI_QUIRK_32BIT_DMA_ADDR) && + (data->sg->offset & 0x3))) { + DBG("Reverting to PIO because of bad alignment\n"); + host->flags &= ~SDHCI_REQ_USE_DMA; + } + + if (host->flags & SDHCI_REQ_USE_DMA) { int count; count = pci_map_sg(host->chip->pdev, data->sg, data->sg_len, @@ -456,7 +508,7 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host, mode |= SDHCI_TRNS_MULTI; if (data->flags & MMC_DATA_READ) mode |= SDHCI_TRNS_READ; - if (host->flags & SDHCI_USE_DMA) + if (host->flags & SDHCI_REQ_USE_DMA) mode |= SDHCI_TRNS_DMA; writew(mode, host->ioaddr + SDHCI_TRANSFER_MODE); @@ -472,7 +524,7 @@ static void sdhci_finish_data(struct sdhci_host *host) data = host->data; host->data = NULL; - if (host->flags & SDHCI_USE_DMA) { + if (host->flags & SDHCI_REQ_USE_DMA) { pci_unmap_sg(host->chip->pdev, data->sg, data->sg_len, (data->flags & MMC_DATA_READ)?PCI_DMA_FROMDEVICE:PCI_DMA_TODEVICE); } @@ -886,7 +938,8 @@ static void sdhci_tasklet_finish(unsigned long param) */ if (mrq->cmd->error || (mrq->data && (mrq->data->error || - (mrq->data->stop && mrq->data->stop->error)))) { + (mrq->data->stop && mrq->data->stop->error))) || + (host->chip->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST)) { /* Some controllers need this kick or reset won't work here */ if (host->chip->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET) { @@ -1284,7 +1337,7 @@ static int __devinit sdhci_probe_slot(struct pci_dev *pdev, int slot) version = readw(host->ioaddr + SDHCI_HOST_VERSION); version = (version & SDHCI_SPEC_VER_MASK) >> SDHCI_SPEC_VER_SHIFT; - if (version != 0) { + if (version > 1) { printk(KERN_ERR "%s: Unknown controller version (%d). " "You may experience problems.\n", host->slot_descr, version); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index 05195ea900f..e4d77b038bf 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -171,7 +171,8 @@ struct sdhci_host { spinlock_t lock; /* Mutex */ int flags; /* Host attributes */ -#define SDHCI_USE_DMA (1<<0) +#define SDHCI_USE_DMA (1<<0) /* Host is DMA capable */ +#define SDHCI_REQ_USE_DMA (1<<1) /* Use DMA for this req. */ unsigned int max_clk; /* Max possible freq (MHz) */ unsigned int timeout_clk; /* Timeout freq (KHz) */ diff --git a/drivers/mmc/host/tifm_sd.c b/drivers/mmc/host/tifm_sd.c index c11a3d25605..20d5c7bd940 100644 --- a/drivers/mmc/host/tifm_sd.c +++ b/drivers/mmc/host/tifm_sd.c @@ -16,7 +16,6 @@ #include <linux/mmc/host.h> #include <linux/highmem.h> #include <linux/scatterlist.h> -#include <linux/log2.h> #include <asm/io.h> #define DRIVER_NAME "tifm_sd" @@ -638,17 +637,15 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) goto err_out; } - if (mrq->data && !is_power_of_2(mrq->data->blksz)) { - printk(KERN_ERR "%s: Unsupported block size (%d bytes)\n", - sock->dev.bus_id, mrq->data->blksz); - mrq->cmd->error = -EINVAL; - goto err_out; - } - host->cmd_flags = 0; host->block_pos = 0; host->sg_pos = 0; + if (mrq->data && !is_power_of_2(mrq->data->blksz)) + host->no_dma = 1; + else + host->no_dma = no_dma ? 1 : 0; + if (r_data) { tifm_sd_set_data_timeout(host, r_data); @@ -676,7 +673,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) : PCI_DMA_FROMDEVICE)) { printk(KERN_ERR "%s : scatterlist map failed\n", sock->dev.bus_id); - spin_unlock_irqrestore(&sock->lock, flags); + mrq->cmd->error = -ENOMEM; goto err_out; } host->sg_len = tifm_map_sg(sock, r_data->sg, @@ -692,7 +689,7 @@ static void tifm_sd_request(struct mmc_host *mmc, struct mmc_request *mrq) r_data->flags & MMC_DATA_WRITE ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE); - spin_unlock_irqrestore(&sock->lock, flags); + mrq->cmd->error = -ENOMEM; goto err_out; } @@ -966,7 +963,6 @@ static int tifm_sd_probe(struct tifm_dev *sock) return -ENOMEM; host = mmc_priv(mmc); - host->no_dma = no_dma; tifm_set_drvdata(sock, mmc); host->dev = sock; host->timeout_jiffies = msecs_to_jiffies(1000); |