}
static inline int get_data_buffer(struct s3cmci_host *host,
- u32 *words, u32 **pointer)
+ u32 *bytes, u32 **pointer)
{
struct scatterlist *sg;
}
sg = &host->mrq->data->sg[host->pio_sgptr];
- *words = sg->length >> 2;
+ *bytes = sg->length;
*pointer = sg_virt(sg);
host->pio_sgptr++;
u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
fifostat &= S3C2410_SDIFSTA_COUNTMASK;
- return fifostat >> 2;
+ return fifostat;
}
static inline u32 fifo_free(struct s3cmci_host *host)
u32 fifostat = readl(host->base + S3C2410_SDIFSTA);
fifostat &= S3C2410_SDIFSTA_COUNTMASK;
- return (63 - fifostat) >> 2;
+ return 63 - fifostat;
}
static void do_pio_read(struct s3cmci_host *host)
{
int res;
u32 fifo;
+ u32 fifo_words;
void __iomem *from_ptr;
/* write real prescaler to host, it might be set slow to fix */
from_ptr = host->base + host->sdidata;
while ((fifo = fifo_count(host))) {
- if (!host->pio_words) {
- res = get_data_buffer(host, &host->pio_words,
+ if (!host->pio_bytes) {
+ res = get_data_buffer(host, &host->pio_bytes,
&host->pio_ptr);
if (res) {
host->pio_active = XFER_NONE;
dbg(host, dbg_pio,
"pio_read(): new target: [%i]@[%p]\n",
- host->pio_words, host->pio_ptr);
+ host->pio_bytes, host->pio_ptr);
}
dbg(host, dbg_pio,
"pio_read(): fifo:[%02i] buffer:[%03i] dcnt:[%08X]\n",
- fifo, host->pio_words,
+ fifo, host->pio_bytes,
readl(host->base + S3C2410_SDIDCNT));
- if (fifo > host->pio_words)
- fifo = host->pio_words;
+ /* If we have reached the end of the block, we can
+ * read a word and get 1 to 3 bytes. If we in the
+ * middle of the block, we have to read full words,
+ * otherwise we will write garbage, so round down to
+ * an even multiple of 4. */
+ if (fifo >= host->pio_bytes)
+ fifo = host->pio_bytes;
+ else
+ fifo -= fifo & 3;
- host->pio_words -= fifo;
+ host->pio_bytes -= fifo;
host->pio_count += fifo;
- while (fifo--)
+ fifo_words = fifo >> 2;
+ while (fifo_words--)
*(host->pio_ptr++) = readl(from_ptr);
+
+ if (fifo & 3) {
+ u32 n = fifo & 3;
+ u32 data = readl(from_ptr);
+ u8 *p = (u8 *)host->pio_ptr;
+
+ while (n--) {
+ *p++ = data;
+ data >>= 8;
+ }
+ }
}
- if (!host->pio_words) {
- res = get_data_buffer(host, &host->pio_words, &host->pio_ptr);
+ if (!host->pio_bytes) {
+ res = get_data_buffer(host, &host->pio_bytes, &host->pio_ptr);
if (res) {
dbg(host, dbg_pio,
"pio_read(): complete (no more buffers).\n");
to_ptr = host->base + host->sdidata;
while ((fifo = fifo_free(host))) {
- if (!host->pio_words) {
- res = get_data_buffer(host, &host->pio_words,
+ if (!host->pio_bytes) {
+ res = get_data_buffer(host, &host->pio_bytes,
&host->pio_ptr);
if (res) {
dbg(host, dbg_pio,
dbg(host, dbg_pio,
"pio_write(): new source: [%i]@[%p]\n",
- host->pio_words, host->pio_ptr);
+ host->pio_bytes, host->pio_ptr);
}
- if (fifo > host->pio_words)
- fifo = host->pio_words;
+ /* If we have reached the end of the block, we have to
+ * write exactly the remaining number of bytes. If we
+ * in the middle of the block, we have to write full
+ * words, so round down to an even multiple of 4. */
+ if (fifo >= host->pio_bytes)
+ fifo = host->pio_bytes;
+ else
+ fifo -= fifo & 3;
- host->pio_words -= fifo;
+ host->pio_bytes -= fifo;
host->pio_count += fifo;
+ fifo = (fifo + 3) >> 2;
while (fifo--)
writel(*(host->pio_ptr++), to_ptr);
}
clear_imask(host);
if (host->pio_active != XFER_NONE) {
dbg(host, dbg_err, "unfinished %s "
- "- pio_count:[%u] pio_words:[%u]\n",
+ "- pio_count:[%u] pio_bytes:[%u]\n",
(host->pio_active == XFER_READ) ? "read" : "write",
- host->pio_count, host->pio_words);
+ host->pio_count, host->pio_bytes);
if (host->mrq->data)
host->mrq->data->error = -EINVAL;
/* We cannot deal with unaligned blocks with more than
* one block being transfered. */
- if (data->blocks > 1)
+ if (data->blocks > 1) {
+ pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz);
return -EINVAL;
-
- /* No support yet for non-word block transfers. */
- return -EINVAL;
+ }
}
while (readl(host->base + S3C2410_SDIDSTA) &
BUG_ON((data->flags & BOTH_DIR) == BOTH_DIR);
host->pio_sgptr = 0;
- host->pio_words = 0;
+ host->pio_bytes = 0;
host->pio_count = 0;
host->pio_active = rw ? XFER_WRITE : XFER_READ;