mmc: wbsd: handle highmem pages
Use sg_copy_{from,to}_buffer to bounce buffer and kmap_atomic to map the scatterlist entry before using it. Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
a403417382
commit
9181ece38c
|
@ -268,43 +268,29 @@ static inline int wbsd_next_sg(struct wbsd_host *host)
|
||||||
return host->num_sg;
|
return host->num_sg;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char *wbsd_sg_to_buffer(struct wbsd_host *host)
|
static inline char *wbsd_map_sg(struct wbsd_host *host)
|
||||||
{
|
{
|
||||||
return sg_virt(host->cur_sg);
|
return kmap_atomic(sg_page(host->cur_sg)) + host->cur_sg->offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
|
static inline void wbsd_sg_to_dma(struct wbsd_host *host, struct mmc_data *data)
|
||||||
{
|
{
|
||||||
unsigned int len, i;
|
size_t len = 0;
|
||||||
struct scatterlist *sg;
|
int i;
|
||||||
char *dmabuf = host->dma_buffer;
|
|
||||||
char *sgbuf;
|
|
||||||
|
|
||||||
sg = data->sg;
|
for (i = 0; i < data->sg_len; i++)
|
||||||
len = data->sg_len;
|
len += data->sg[i].length;
|
||||||
|
sg_copy_to_buffer(data->sg, data->sg_len, host->dma_buffer, len);
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
sgbuf = sg_virt(&sg[i]);
|
|
||||||
memcpy(dmabuf, sgbuf, sg[i].length);
|
|
||||||
dmabuf += sg[i].length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
|
static inline void wbsd_dma_to_sg(struct wbsd_host *host, struct mmc_data *data)
|
||||||
{
|
{
|
||||||
unsigned int len, i;
|
size_t len = 0;
|
||||||
struct scatterlist *sg;
|
int i;
|
||||||
char *dmabuf = host->dma_buffer;
|
|
||||||
char *sgbuf;
|
|
||||||
|
|
||||||
sg = data->sg;
|
for (i = 0; i < data->sg_len; i++)
|
||||||
len = data->sg_len;
|
len += data->sg[i].length;
|
||||||
|
sg_copy_from_buffer(data->sg, data->sg_len, host->dma_buffer, len);
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
sgbuf = sg_virt(&sg[i]);
|
|
||||||
memcpy(sgbuf, dmabuf, sg[i].length);
|
|
||||||
dmabuf += sg[i].length;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -418,7 +404,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
|
||||||
{
|
{
|
||||||
struct mmc_data *data = host->mrq->cmd->data;
|
struct mmc_data *data = host->mrq->cmd->data;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
int i, fsr, fifo;
|
int i, idx, fsr, fifo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle excessive data.
|
* Handle excessive data.
|
||||||
|
@ -426,7 +412,8 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
|
||||||
if (host->num_sg == 0)
|
if (host->num_sg == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
buffer = wbsd_sg_to_buffer(host) + host->offset;
|
buffer = wbsd_map_sg(host) + host->offset;
|
||||||
|
idx = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Drain the fifo. This has a tendency to loop longer
|
* Drain the fifo. This has a tendency to loop longer
|
||||||
|
@ -445,8 +432,7 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
|
||||||
fifo = 1;
|
fifo = 1;
|
||||||
|
|
||||||
for (i = 0; i < fifo; i++) {
|
for (i = 0; i < fifo; i++) {
|
||||||
*buffer = inb(host->base + WBSD_DFR);
|
buffer[idx++] = inb(host->base + WBSD_DFR);
|
||||||
buffer++;
|
|
||||||
host->offset++;
|
host->offset++;
|
||||||
host->remain--;
|
host->remain--;
|
||||||
|
|
||||||
|
@ -456,16 +442,19 @@ static void wbsd_empty_fifo(struct wbsd_host *host)
|
||||||
* End of scatter list entry?
|
* End of scatter list entry?
|
||||||
*/
|
*/
|
||||||
if (host->remain == 0) {
|
if (host->remain == 0) {
|
||||||
|
kunmap_atomic(buffer);
|
||||||
/*
|
/*
|
||||||
* Get next entry. Check if last.
|
* Get next entry. Check if last.
|
||||||
*/
|
*/
|
||||||
if (!wbsd_next_sg(host))
|
if (!wbsd_next_sg(host))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
buffer = wbsd_sg_to_buffer(host);
|
buffer = wbsd_map_sg(host);
|
||||||
|
idx = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
kunmap_atomic(buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a very dirty hack to solve a
|
* This is a very dirty hack to solve a
|
||||||
|
@ -480,7 +469,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
|
||||||
{
|
{
|
||||||
struct mmc_data *data = host->mrq->cmd->data;
|
struct mmc_data *data = host->mrq->cmd->data;
|
||||||
char *buffer;
|
char *buffer;
|
||||||
int i, fsr, fifo;
|
int i, idx, fsr, fifo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that we aren't being called after the
|
* Check that we aren't being called after the
|
||||||
|
@ -489,7 +478,8 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
|
||||||
if (host->num_sg == 0)
|
if (host->num_sg == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
buffer = wbsd_sg_to_buffer(host) + host->offset;
|
buffer = wbsd_map_sg(host) + host->offset;
|
||||||
|
idx = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fill the fifo. This has a tendency to loop longer
|
* Fill the fifo. This has a tendency to loop longer
|
||||||
|
@ -508,8 +498,7 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
|
||||||
fifo = 15;
|
fifo = 15;
|
||||||
|
|
||||||
for (i = 16; i > fifo; i--) {
|
for (i = 16; i > fifo; i--) {
|
||||||
outb(*buffer, host->base + WBSD_DFR);
|
outb(buffer[idx], host->base + WBSD_DFR);
|
||||||
buffer++;
|
|
||||||
host->offset++;
|
host->offset++;
|
||||||
host->remain--;
|
host->remain--;
|
||||||
|
|
||||||
|
@ -519,16 +508,19 @@ static void wbsd_fill_fifo(struct wbsd_host *host)
|
||||||
* End of scatter list entry?
|
* End of scatter list entry?
|
||||||
*/
|
*/
|
||||||
if (host->remain == 0) {
|
if (host->remain == 0) {
|
||||||
|
kunmap_atomic(buffer);
|
||||||
/*
|
/*
|
||||||
* Get next entry. Check if last.
|
* Get next entry. Check if last.
|
||||||
*/
|
*/
|
||||||
if (!wbsd_next_sg(host))
|
if (!wbsd_next_sg(host))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
buffer = wbsd_sg_to_buffer(host);
|
buffer = wbsd_map_sg(host);
|
||||||
|
idx = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
kunmap_atomic(buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The controller stops sending interrupts for
|
* The controller stops sending interrupts for
|
||||||
|
|
Loading…
Reference in New Issue
Block a user