Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 287637
b: refs/heads/master
c: f9c2a0d
h: refs/heads/master
i:
  287635: 9c7ed9e
v: v3
  • Loading branch information
Seungwon Jeon authored and Chris Ball committed Feb 14, 2012
1 parent 84162de commit 109873b
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 72 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 18ee684b8ab666329e0a0a72d8b70f16fb0e2243
refs/heads/master: f9c2a0dc42a6938ff2a80e55ca2bbd1d5581c72e
144 changes: 75 additions & 69 deletions trunk/drivers/mmc/host/dw_mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include <linux/ioport.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/scatterlist.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
#include <linux/stat.h>
Expand Down Expand Up @@ -502,8 +501,14 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
host->dir_status = DW_MCI_SEND_STATUS;

if (dw_mci_submit_data_dma(host, data)) {
int flags = SG_MITER_ATOMIC;
if (host->data->flags & MMC_DATA_READ)
flags |= SG_MITER_TO_SG;
else
flags |= SG_MITER_FROM_SG;

sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
host->sg = data->sg;
host->pio_offset = 0;
host->part_buf_start = 0;
host->part_buf_count = 0;

Expand Down Expand Up @@ -972,6 +977,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
* generates a block interrupt, hence setting
* the scatter-gather pointer to NULL.
*/
sg_miter_stop(&host->sg_miter);
host->sg = NULL;
ctrl = mci_readl(host, CTRL);
ctrl |= SDMMC_CTRL_FIFO_RESET;
Expand Down Expand Up @@ -1311,54 +1317,44 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)

static void dw_mci_read_data_pio(struct dw_mci *host)
{
struct scatterlist *sg = host->sg;
void *buf = sg_virt(sg);
unsigned int offset = host->pio_offset;
struct sg_mapping_iter *sg_miter = &host->sg_miter;
void *buf;
unsigned int offset;
struct mmc_data *data = host->data;
int shift = host->data_shift;
u32 status;
unsigned int nbytes = 0, len;
unsigned int remain, fcnt;

do {
len = host->part_buf_count +
(SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift);
if (offset + len <= sg->length) {
if (!sg_miter_next(sg_miter))
goto done;

host->sg = sg_miter->__sg;
buf = sg_miter->addr;
remain = sg_miter->length;
offset = 0;

do {
fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
<< shift) + host->part_buf_count;
len = min(remain, fcnt);
if (!len)
break;
dw_mci_pull_data(host, (void *)(buf + offset), len);

offset += len;
nbytes += len;

if (offset == sg->length) {
flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
goto done;

offset = 0;
buf = sg_virt(sg);
}
} else {
unsigned int remaining = sg->length - offset;
dw_mci_pull_data(host, (void *)(buf + offset),
remaining);
nbytes += remaining;

flush_dcache_page(sg_page(sg));
host->sg = sg = sg_next(sg);
if (!sg)
goto done;

offset = len - remaining;
buf = sg_virt(sg);
dw_mci_pull_data(host, buf, offset);
nbytes += offset;
}
remain -= len;
} while (remain);
sg_miter->consumed = offset;

status = mci_readl(host, MINTSTS);
mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
if (status & DW_MCI_DATA_ERROR_FLAGS) {
host->data_status = status;
data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb();

set_bit(EVENT_DATA_ERROR, &host->pending_events);
Expand All @@ -1367,65 +1363,66 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
return;
}
} while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
host->pio_offset = offset;
data->bytes_xfered += nbytes;

if (!remain) {
if (!sg_miter_next(sg_miter))
goto done;
sg_miter->consumed = 0;
}
sg_miter_stop(sg_miter);
return;

done:
data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb();
set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
}

static void dw_mci_write_data_pio(struct dw_mci *host)
{
struct scatterlist *sg = host->sg;
void *buf = sg_virt(sg);
unsigned int offset = host->pio_offset;
struct sg_mapping_iter *sg_miter = &host->sg_miter;
void *buf;
unsigned int offset;
struct mmc_data *data = host->data;
int shift = host->data_shift;
u32 status;
unsigned int nbytes = 0, len;
unsigned int fifo_depth = host->fifo_depth;
unsigned int remain, fcnt;

do {
len = ((host->fifo_depth -
SDMMC_GET_FCNT(mci_readl(host, STATUS))) << shift)
- host->part_buf_count;
if (offset + len <= sg->length) {
if (!sg_miter_next(sg_miter))
goto done;

host->sg = sg_miter->__sg;
buf = sg_miter->addr;
remain = sg_miter->length;
offset = 0;

do {
fcnt = ((fifo_depth -
SDMMC_GET_FCNT(mci_readl(host, STATUS)))
<< shift) - host->part_buf_count;
len = min(remain, fcnt);
if (!len)
break;
host->push_data(host, (void *)(buf + offset), len);

offset += len;
nbytes += len;
if (offset == sg->length) {
host->sg = sg = sg_next(sg);
if (!sg)
goto done;

offset = 0;
buf = sg_virt(sg);
}
} else {
unsigned int remaining = sg->length - offset;

host->push_data(host, (void *)(buf + offset),
remaining);
nbytes += remaining;

host->sg = sg = sg_next(sg);
if (!sg)
goto done;

offset = len - remaining;
buf = sg_virt(sg);
host->push_data(host, (void *)buf, offset);
nbytes += offset;
}
remain -= len;
} while (remain);
sg_miter->consumed = offset;

status = mci_readl(host, MINTSTS);
mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
if (status & DW_MCI_DATA_ERROR_FLAGS) {
host->data_status = status;
data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;

smp_wmb();

Expand All @@ -1435,12 +1432,20 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
return;
}
} while (status & SDMMC_INT_TXDR); /* if TXDR write again */
host->pio_offset = offset;
data->bytes_xfered += nbytes;

if (!remain) {
if (!sg_miter_next(sg_miter))
goto done;
sg_miter->consumed = 0;
}
sg_miter_stop(sg_miter);
return;

done:
data->bytes_xfered += nbytes;
sg_miter_stop(sg_miter);
host->sg = NULL;
smp_wmb();
set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
}
Expand Down Expand Up @@ -1643,6 +1648,7 @@ static void dw_mci_work_routine_card(struct work_struct *work)
* block interrupt, hence setting the
* scatter-gather pointer to NULL.
*/
sg_miter_stop(&host->sg_miter);
host->sg = NULL;

ctrl = mci_readl(host, CTRL);
Expand Down
6 changes: 4 additions & 2 deletions trunk/include/linux/mmc/dw_mmc.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#ifndef LINUX_MMC_DW_MMC_H
#define LINUX_MMC_DW_MMC_H

#include <linux/scatterlist.h>

#define MAX_MCI_SLOTS 2

enum dw_mci_state {
Expand All @@ -40,7 +42,7 @@ struct mmc_data;
* @lock: Spinlock protecting the queue and associated data.
* @regs: Pointer to MMIO registers.
* @sg: Scatterlist entry currently being processed by PIO code, if any.
* @pio_offset: Offset into the current scatterlist entry.
* @sg_miter: PIO mapping scatterlist iterator.
* @cur_slot: The slot which is currently using the controller.
* @mrq: The request currently being processed on @cur_slot,
* or NULL if the controller is idle.
Expand Down Expand Up @@ -115,7 +117,7 @@ struct dw_mci {
void __iomem *regs;

struct scatterlist *sg;
unsigned int pio_offset;
struct sg_mapping_iter sg_miter;

struct dw_mci_slot *cur_slot;
struct mmc_request *mrq;
Expand Down

0 comments on commit 109873b

Please sign in to comment.