Commit 251f6b40 authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://bk.arm.linux.org.uk/linux-2.6-mmc

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 6228bab7 93309015
...@@ -200,6 +200,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) ...@@ -200,6 +200,9 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
} }
brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL; brq.mrq.stop = brq.data.blocks > 1 ? &brq.stop : NULL;
brq.data.sg = mq->sg;
brq.data.sg_len = blk_rq_map_sg(req->q, req, brq.data.sg);
mmc_wait_for_req(card->host, &brq.mrq); mmc_wait_for_req(card->host, &brq.mrq);
if (brq.cmd.error) { if (brq.cmd.error) {
printk(KERN_ERR "%s: error %d sending read/write command\n", printk(KERN_ERR "%s: error %d sending read/write command\n",
......
...@@ -80,7 +80,7 @@ static int mmc_queue_thread(void *d) ...@@ -80,7 +80,7 @@ static int mmc_queue_thread(void *d)
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
if (!blk_queue_plugged(q)) if (!blk_queue_plugged(q))
mq->req = req = elv_next_request(q); mq->req = req = elv_next_request(q);
spin_unlock(q->queue_lock); spin_unlock_irq(q->queue_lock);
if (!req) { if (!req) {
if (mq->flags & MMC_QUEUE_EXIT) if (mq->flags & MMC_QUEUE_EXIT)
...@@ -147,19 +147,31 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock ...@@ -147,19 +147,31 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card, spinlock_t *lock
mq->queue->queuedata = mq; mq->queue->queuedata = mq;
mq->req = NULL; mq->req = NULL;
mq->sg = kmalloc(sizeof(struct scatterlist) * host->max_phys_segs,
GFP_KERNEL);
if (!mq->sg) {
ret = -ENOMEM;
goto cleanup;
}
init_completion(&mq->thread_complete); init_completion(&mq->thread_complete);
init_waitqueue_head(&mq->thread_wq); init_waitqueue_head(&mq->thread_wq);
init_MUTEX(&mq->thread_sem); init_MUTEX(&mq->thread_sem);
ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL); ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL);
if (ret < 0) { if (ret >= 0) {
blk_cleanup_queue(mq->queue);
} else {
wait_for_completion(&mq->thread_complete); wait_for_completion(&mq->thread_complete);
init_completion(&mq->thread_complete); init_completion(&mq->thread_complete);
ret = 0; ret = 0;
goto out;
} }
cleanup:
kfree(mq->sg);
mq->sg = NULL;
blk_cleanup_queue(mq->queue);
out:
return ret; return ret;
} }
EXPORT_SYMBOL(mmc_init_queue); EXPORT_SYMBOL(mmc_init_queue);
...@@ -169,6 +181,10 @@ void mmc_cleanup_queue(struct mmc_queue *mq) ...@@ -169,6 +181,10 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
mq->flags |= MMC_QUEUE_EXIT; mq->flags |= MMC_QUEUE_EXIT;
wake_up(&mq->thread_wq); wake_up(&mq->thread_wq);
wait_for_completion(&mq->thread_complete); wait_for_completion(&mq->thread_complete);
kfree(mq->sg);
mq->sg = NULL;
blk_cleanup_queue(mq->queue); blk_cleanup_queue(mq->queue);
mq->card = NULL; mq->card = NULL;
......
...@@ -15,6 +15,7 @@ struct mmc_queue { ...@@ -15,6 +15,7 @@ struct mmc_queue {
int (*issue_fn)(struct mmc_queue *, struct request *); int (*issue_fn)(struct mmc_queue *, struct request *);
void *data; void *data;
struct request_queue *queue; struct request_queue *queue;
struct scatterlist *sg;
}; };
struct mmc_io_request { struct mmc_io_request {
......
...@@ -501,7 +501,7 @@ static int mmci_probe(struct amba_device *dev, void *id) ...@@ -501,7 +501,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
* We can do SGIO * We can do SGIO
*/ */
mmc->max_hw_segs = 16; mmc->max_hw_segs = 16;
mmc->max_phys_segs = 16; mmc->max_phys_segs = NR_SG;
/* /*
* Since we only have a 16-bit data length register, we must * Since we only have a 16-bit data length register, we must
......
...@@ -139,7 +139,6 @@ struct mmci_host { ...@@ -139,7 +139,6 @@ struct mmci_host {
struct timer_list timer; struct timer_list timer;
unsigned int oldstat; unsigned int oldstat;
struct scatterlist sg[NR_SG];
unsigned int sg_len; unsigned int sg_len;
/* pio stuff */ /* pio stuff */
...@@ -150,14 +149,11 @@ struct mmci_host { ...@@ -150,14 +149,11 @@ struct mmci_host {
static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data) static inline void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
{ {
struct scatterlist *sg = host->sg;
struct request *req = data->req;
/* /*
* Ideally, we want the higher levels to pass us a scatter list. * Ideally, we want the higher levels to pass us a scatter list.
*/ */
host->sg_len = blk_rq_map_sg(req->q, req, sg); host->sg_len = data->sg_len;
host->sg_ptr = sg; host->sg_ptr = data->sg;
host->sg_off = 0; host->sg_off = 0;
} }
......
...@@ -44,6 +44,10 @@ ...@@ -44,6 +44,10 @@
#define DBG(x...) do { } while (0) #define DBG(x...) do { } while (0)
#endif #endif
#define DRIVER_NAME "pxa2xx-mci"
#define NR_SG 1
struct pxamci_host { struct pxamci_host {
struct mmc_host *mmc; struct mmc_host *mmc;
spinlock_t lock; spinlock_t lock;
...@@ -63,9 +67,8 @@ struct pxamci_host { ...@@ -63,9 +67,8 @@ struct pxamci_host {
dma_addr_t sg_dma; dma_addr_t sg_dma;
struct pxa_dma_desc *sg_cpu; struct pxa_dma_desc *sg_cpu;
unsigned int dma_len;
dma_addr_t dma_buf;
unsigned int dma_size;
unsigned int dma_dir; unsigned int dma_dir;
}; };
...@@ -122,10 +125,9 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask) ...@@ -122,10 +125,9 @@ static void pxamci_disable_irq(struct pxamci_host *host, unsigned int mask)
static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
{ {
unsigned int nob = data->blocks; unsigned int nob = data->blocks;
unsigned int timeout, size; unsigned int timeout;
dma_addr_t dma;
u32 dcmd; u32 dcmd;
int i; int i, len;
host->data = data; host->data = data;
...@@ -152,35 +154,22 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) ...@@ -152,35 +154,22 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
dcmd |= DCMD_BURST32 | DCMD_WIDTH1; dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
host->dma_size = data->blocks << data->blksz_bits; host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
host->dma_buf = dma_map_single(mmc_dev(host->mmc), data->req->buffer, host->dma_dir);
host->dma_size, host->dma_dir);
for (i = 0, size = host->dma_size, dma = host->dma_buf; size; i++) {
u32 len = size;
if (len > DCMD_LENGTH)
len = 0x1000;
for (i = 0; i < host->dma_len; i++) {
if (data->flags & MMC_DATA_READ) { if (data->flags & MMC_DATA_READ) {
host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO; host->sg_cpu[i].dsadr = host->res->start + MMC_RXFIFO;
host->sg_cpu[i].dtadr = dma; host->sg_cpu[i].dtadr = sg_dma_address(&data->sg[i]);
} else { } else {
host->sg_cpu[i].dsadr = dma; host->sg_cpu[i].dsadr = sg_dma_address(&data->sg[i]);
host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO; host->sg_cpu[i].dtadr = host->res->start + MMC_TXFIFO;
} }
host->sg_cpu[i].dcmd = dcmd | len; host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
dma += len;
size -= len;
if (size) {
host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) * host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
sizeof(struct pxa_dma_desc); sizeof(struct pxa_dma_desc);
} else {
host->sg_cpu[i].ddadr = DDADR_STOP;
}
} }
host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
wmb(); wmb();
DDADR(host->dma) = host->sg_dma; DDADR(host->dma) = host->sg_dma;
...@@ -276,7 +265,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) ...@@ -276,7 +265,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
return 0; return 0;
DCSR(host->dma) = 0; DCSR(host->dma) = 0;
dma_unmap_single(mmc_dev(host->mmc), host->dma_buf, host->dma_size, dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
host->dma_dir); host->dma_dir);
if (stat & STAT_READ_TIME_OUT) if (stat & STAT_READ_TIME_OUT)
...@@ -429,7 +418,7 @@ static int pxamci_probe(struct device *dev) ...@@ -429,7 +418,7 @@ static int pxamci_probe(struct device *dev)
if (!r || irq == NO_IRQ) if (!r || irq == NO_IRQ)
return -ENXIO; return -ENXIO;
r = request_mem_region(r->start, SZ_4K, "PXAMCI"); r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
if (!r) if (!r)
return -EBUSY; return -EBUSY;
...@@ -443,6 +432,17 @@ static int pxamci_probe(struct device *dev) ...@@ -443,6 +432,17 @@ static int pxamci_probe(struct device *dev)
mmc->f_min = 312500; mmc->f_min = 312500;
mmc->f_max = 20000000; mmc->f_max = 20000000;
/*
* We can do SG-DMA, but we don't because we never know how much
* data we successfully wrote to the card.
*/
mmc->max_phys_segs = NR_SG;
/*
* Our hardware DMA can handle a maximum of one page per SG entry.
*/
mmc->max_seg_size = PAGE_SIZE;
host = mmc_priv(mmc); host = mmc_priv(mmc);
host->mmc = mmc; host->mmc = mmc;
host->dma = -1; host->dma = -1;
...@@ -482,13 +482,14 @@ static int pxamci_probe(struct device *dev) ...@@ -482,13 +482,14 @@ static int pxamci_probe(struct device *dev)
pxa_gpio_mode(GPIO8_MMCCS0_MD); pxa_gpio_mode(GPIO8_MMCCS0_MD);
pxa_set_cken(CKEN12_MMC, 1); pxa_set_cken(CKEN12_MMC, 1);
host->dma = pxa_request_dma("PXAMCI", DMA_PRIO_LOW, pxamci_dma_irq, host); host->dma = pxa_request_dma(DRIVER_NAME, DMA_PRIO_LOW,
pxamci_dma_irq, host);
if (host->dma < 0) { if (host->dma < 0) {
ret = -EBUSY; ret = -EBUSY;
goto out; goto out;
} }
ret = request_irq(host->irq, pxamci_irq, 0, "PXAMCI", host); ret = request_irq(host->irq, pxamci_irq, 0, DRIVER_NAME, host);
if (ret) if (ret)
goto out; goto out;
...@@ -579,7 +580,7 @@ static int pxamci_resume(struct device *dev, u32 level) ...@@ -579,7 +580,7 @@ static int pxamci_resume(struct device *dev, u32 level)
#endif #endif
static struct device_driver pxamci_driver = { static struct device_driver pxamci_driver = {
.name = "pxa2xx-mci", .name = DRIVER_NAME,
.bus = &platform_bus_type, .bus = &platform_bus_type,
.probe = pxamci_probe, .probe = pxamci_probe,
.remove = pxamci_remove, .remove = pxamci_remove,
......
...@@ -57,7 +57,7 @@ struct mmc_data { ...@@ -57,7 +57,7 @@ struct mmc_data {
unsigned int timeout_clks; /* data timeout (in clocks) */ unsigned int timeout_clks; /* data timeout (in clocks) */
unsigned int blksz_bits; /* data block size */ unsigned int blksz_bits; /* data block size */
unsigned int blocks; /* number of blocks */ unsigned int blocks; /* number of blocks */
struct request *req; /* request structure */ struct request *req __attribute__((deprecated));/* request structure (use the sg list instead) */
unsigned int error; /* data error */ unsigned int error; /* data error */
unsigned int flags; unsigned int flags;
...@@ -69,6 +69,9 @@ struct mmc_data { ...@@ -69,6 +69,9 @@ struct mmc_data {
struct mmc_command *stop; /* stop command */ struct mmc_command *stop; /* stop command */
struct mmc_request *mrq; /* assoicated request */ struct mmc_request *mrq; /* assoicated request */
unsigned int sg_len; /* size of scatter list */
struct scatterlist *sg; /* I/O scatter list */
}; };
struct mmc_request { struct mmc_request {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment