mirror of
https://github.com/torvalds/linux.git
synced 2026-06-03 03:53:37 +02:00
mmc: mxcmmc: Use sg_miter for PIO
Use the scatterlist memory iterator instead of just dereferencing virtual memory using sg_virt(). This make highmem references work properly. Since this driver is using a worker, no atomic trickery is needed. Suggested-by: Christoph Hellwig <hch@lst.de> Link: https://lore.kernel.org/linux-mmc/20240122073423.GA25859@lst.de/ Signed-off-by: Linus Walleij <linus.walleij@linaro.org> Link: https://lore.kernel.org/r/20240127-mmc-proper-kmap-v2-6-d8e732aa97d1@linaro.org Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
This commit is contained in:
parent
2761822c00
commit
12658af54f
|
|
@ -266,11 +266,18 @@ static inline void buffer_swap32(u32 *buf, int len)
|
|||
|
||||
static void mxcmci_swap_buffers(struct mmc_data *data)
|
||||
{
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
struct sg_mapping_iter sgm;
|
||||
u32 *buf;
|
||||
|
||||
for_each_sg(data->sg, sg, data->sg_len, i)
|
||||
buffer_swap32(sg_virt(sg), sg->length);
|
||||
sg_miter_start(&sgm, data->sg, data->sg_len,
|
||||
SG_MITER_TO_SG | SG_MITER_FROM_SG);
|
||||
|
||||
while (sg_miter_next(&sgm)) {
|
||||
buf = sgm.addr;
|
||||
buffer_swap32(buf, sgm.length);
|
||||
}
|
||||
|
||||
sg_miter_stop(&sgm);
|
||||
}
|
||||
#else
|
||||
static inline void mxcmci_swap_buffers(struct mmc_data *data) {}
|
||||
|
|
@ -526,10 +533,9 @@ static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
|
|||
} while (1);
|
||||
}
|
||||
|
||||
static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
|
||||
static int mxcmci_pull(struct mxcmci_host *host, u32 *buf, int bytes)
|
||||
{
|
||||
unsigned int stat;
|
||||
u32 *buf = _buf;
|
||||
|
||||
while (bytes > 3) {
|
||||
stat = mxcmci_poll_status(host,
|
||||
|
|
@ -555,10 +561,9 @@ static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
|
||||
static int mxcmci_push(struct mxcmci_host *host, u32 *buf, int bytes)
|
||||
{
|
||||
unsigned int stat;
|
||||
u32 *buf = _buf;
|
||||
|
||||
while (bytes > 3) {
|
||||
stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
|
||||
|
|
@ -586,31 +591,39 @@ static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
|
|||
static int mxcmci_transfer_data(struct mxcmci_host *host)
|
||||
{
|
||||
struct mmc_data *data = host->req->data;
|
||||
struct scatterlist *sg;
|
||||
int stat, i;
|
||||
struct sg_mapping_iter sgm;
|
||||
int stat;
|
||||
u32 *buf;
|
||||
|
||||
host->data = data;
|
||||
host->datasize = 0;
|
||||
sg_miter_start(&sgm, data->sg, data->sg_len,
|
||||
(data->flags & MMC_DATA_READ) ? SG_MITER_TO_SG : SG_MITER_FROM_SG);
|
||||
|
||||
if (data->flags & MMC_DATA_READ) {
|
||||
for_each_sg(data->sg, sg, data->sg_len, i) {
|
||||
stat = mxcmci_pull(host, sg_virt(sg), sg->length);
|
||||
while (sg_miter_next(&sgm)) {
|
||||
buf = sgm.addr;
|
||||
stat = mxcmci_pull(host, buf, sgm.length);
|
||||
if (stat)
|
||||
return stat;
|
||||
host->datasize += sg->length;
|
||||
goto transfer_error;
|
||||
host->datasize += sgm.length;
|
||||
}
|
||||
} else {
|
||||
for_each_sg(data->sg, sg, data->sg_len, i) {
|
||||
stat = mxcmci_push(host, sg_virt(sg), sg->length);
|
||||
while (sg_miter_next(&sgm)) {
|
||||
buf = sgm.addr;
|
||||
stat = mxcmci_push(host, buf, sgm.length);
|
||||
if (stat)
|
||||
return stat;
|
||||
host->datasize += sg->length;
|
||||
goto transfer_error;
|
||||
host->datasize += sgm.length;
|
||||
}
|
||||
stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE);
|
||||
if (stat)
|
||||
return stat;
|
||||
goto transfer_error;
|
||||
}
|
||||
return 0;
|
||||
|
||||
transfer_error:
|
||||
sg_miter_stop(&sgm);
|
||||
return stat;
|
||||
}
|
||||
|
||||
static void mxcmci_datawork(struct work_struct *work)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user