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)
}
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);
if (brq.cmd.error) {
printk(KERN_ERR "%s: error %d sending read/write command\n",
......
......@@ -80,7 +80,7 @@ static int mmc_queue_thread(void *d)
set_current_state(TASK_INTERRUPTIBLE);
if (!blk_queue_plugged(q))
mq->req = req = elv_next_request(q);
spin_unlock(q->queue_lock);
spin_unlock_irq(q->queue_lock);
if (!req) {
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
mq->queue->queuedata = mq;
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_waitqueue_head(&mq->thread_wq);
init_MUTEX(&mq->thread_sem);
ret = kernel_thread(mmc_queue_thread, mq, CLONE_KERNEL);
if (ret < 0) {
blk_cleanup_queue(mq->queue);
} else {
if (ret >= 0) {
wait_for_completion(&mq->thread_complete);
init_completion(&mq->thread_complete);
ret = 0;
goto out;
}
cleanup:
kfree(mq->sg);
mq->sg = NULL;
blk_cleanup_queue(mq->queue);
out:
return ret;
}
EXPORT_SYMBOL(mmc_init_queue);
......@@ -169,6 +181,10 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
mq->flags |= MMC_QUEUE_EXIT;
wake_up(&mq->thread_wq);
wait_for_completion(&mq->thread_complete);
kfree(mq->sg);
mq->sg = NULL;
blk_cleanup_queue(mq->queue);
mq->card = NULL;
......
......@@ -15,6 +15,7 @@ struct mmc_queue {
int (*issue_fn)(struct mmc_queue *, struct request *);
void *data;
struct request_queue *queue;
struct scatterlist *sg;
};
struct mmc_io_request {
......
......@@ -501,7 +501,7 @@ static int mmci_probe(struct amba_device *dev, void *id)
* We can do SGIO
*/
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
......
......@@ -139,7 +139,6 @@ struct mmci_host {
struct timer_list timer;
unsigned int oldstat;
struct scatterlist sg[NR_SG];
unsigned int sg_len;
/* pio stuff */
......@@ -150,14 +149,11 @@ struct mmci_host {
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.
*/
host->sg_len = blk_rq_map_sg(req->q, req, sg);
host->sg_ptr = sg;
host->sg_len = data->sg_len;
host->sg_ptr = data->sg;
host->sg_off = 0;
}
......
......@@ -44,6 +44,10 @@
#define DBG(x...) do { } while (0)
#endif
#define DRIVER_NAME "pxa2xx-mci"
#define NR_SG 1
struct pxamci_host {
struct mmc_host *mmc;
spinlock_t lock;
......@@ -63,9 +67,8 @@ struct pxamci_host {
dma_addr_t sg_dma;
struct pxa_dma_desc *sg_cpu;
unsigned int dma_len;
dma_addr_t dma_buf;
unsigned int dma_size;
unsigned int dma_dir;
};
......@@ -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)
{
unsigned int nob = data->blocks;
unsigned int timeout, size;
dma_addr_t dma;
unsigned int timeout;
u32 dcmd;
int i;
int i, len;
host->data = data;
......@@ -152,35 +154,22 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data)
dcmd |= DCMD_BURST32 | DCMD_WIDTH1;
host->dma_size = data->blocks << data->blksz_bits;
host->dma_buf = dma_map_single(mmc_dev(host->mmc), data->req->buffer,
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;
host->dma_len = dma_map_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
host->dma_dir);
for (i = 0; i < host->dma_len; i++) {
if (data->flags & MMC_DATA_READ) {
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 {
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].dcmd = dcmd | len;
dma += len;
size -= len;
if (size) {
host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
sizeof(struct pxa_dma_desc);
} else {
host->sg_cpu[i].ddadr = DDADR_STOP;
}
host->sg_cpu[i].dcmd = dcmd | sg_dma_len(&data->sg[i]);
host->sg_cpu[i].ddadr = host->sg_dma + (i + 1) *
sizeof(struct pxa_dma_desc);
}
host->sg_cpu[host->dma_len - 1].ddadr = DDADR_STOP;
wmb();
DDADR(host->dma) = host->sg_dma;
......@@ -276,8 +265,8 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat)
return 0;
DCSR(host->dma) = 0;
dma_unmap_single(mmc_dev(host->mmc), host->dma_buf, host->dma_size,
host->dma_dir);
dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_len,
host->dma_dir);
if (stat & STAT_READ_TIME_OUT)
data->error = MMC_ERR_TIMEOUT;
......@@ -429,7 +418,7 @@ static int pxamci_probe(struct device *dev)
if (!r || irq == NO_IRQ)
return -ENXIO;
r = request_mem_region(r->start, SZ_4K, "PXAMCI");
r = request_mem_region(r->start, SZ_4K, DRIVER_NAME);
if (!r)
return -EBUSY;
......@@ -443,6 +432,17 @@ static int pxamci_probe(struct device *dev)
mmc->f_min = 312500;
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 = mmc;
host->dma = -1;
......@@ -482,13 +482,14 @@ static int pxamci_probe(struct device *dev)
pxa_gpio_mode(GPIO8_MMCCS0_MD);
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) {
ret = -EBUSY;
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)
goto out;
......@@ -579,7 +580,7 @@ static int pxamci_resume(struct device *dev, u32 level)
#endif
static struct device_driver pxamci_driver = {
.name = "pxa2xx-mci",
.name = DRIVER_NAME,
.bus = &platform_bus_type,
.probe = pxamci_probe,
.remove = pxamci_remove,
......
......@@ -57,7 +57,7 @@ struct mmc_data {
unsigned int timeout_clks; /* data timeout (in clocks) */
unsigned int blksz_bits; /* data block size */
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 flags;
......@@ -69,6 +69,9 @@ struct mmc_data {
struct mmc_command *stop; /* stop command */
struct mmc_request *mrq; /* assoicated request */
unsigned int sg_len; /* size of scatter list */
struct scatterlist *sg; /* I/O scatter list */
};
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