Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: moxart-mmc: 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.

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-4-d8e732aa97d1@linaro.org
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>

authored by

Linus Walleij and committed by
Ulf Hansson
3ee0e7c3 54fd8cd6

+34 -43
+34 -43
drivers/mmc/host/moxart-mmc.c
··· 131 131 struct dma_async_tx_descriptor *tx_desc; 132 132 struct mmc_host *mmc; 133 133 struct mmc_request *mrq; 134 - struct scatterlist *cur_sg; 135 134 struct completion dma_complete; 136 135 struct completion pio_complete; 137 136 138 - u32 num_sg; 139 - u32 data_remain; 137 + struct sg_mapping_iter sg_miter; 140 138 u32 data_len; 141 139 u32 fifo_width; 142 140 u32 timeout; ··· 145 147 bool have_dma; 146 148 bool is_removed; 147 149 }; 148 - 149 - static inline void moxart_init_sg(struct moxart_host *host, 150 - struct mmc_data *data) 151 - { 152 - host->cur_sg = data->sg; 153 - host->num_sg = data->sg_len; 154 - host->data_remain = host->cur_sg->length; 155 - 156 - if (host->data_remain > host->data_len) 157 - host->data_remain = host->data_len; 158 - } 159 - 160 - static inline int moxart_next_sg(struct moxart_host *host) 161 - { 162 - int remain; 163 - struct mmc_data *data = host->mrq->cmd->data; 164 - 165 - host->cur_sg++; 166 - host->num_sg--; 167 - 168 - if (host->num_sg > 0) { 169 - host->data_remain = host->cur_sg->length; 170 - remain = host->data_len - data->bytes_xfered; 171 - if (remain > 0 && remain < host->data_remain) 172 - host->data_remain = remain; 173 - } 174 - 175 - return host->num_sg; 176 - } 177 150 178 151 static int moxart_wait_for_status(struct moxart_host *host, 179 152 u32 mask, u32 *status) ··· 278 309 279 310 static void moxart_transfer_pio(struct moxart_host *host) 280 311 { 312 + struct sg_mapping_iter *sgm = &host->sg_miter; 281 313 struct mmc_data *data = host->mrq->cmd->data; 282 314 u32 *sgp, len = 0, remain, status; 283 315 284 316 if (host->data_len == data->bytes_xfered) 285 317 return; 286 318 287 - sgp = sg_virt(host->cur_sg); 288 - remain = host->data_remain; 319 + /* 320 + * By updating sgm->consumes this will get a proper pointer into the 321 + * buffer at any time. 322 + */ 323 + if (!sg_miter_next(sgm)) { 324 + /* This shold not happen */ 325 + dev_err(mmc_dev(host->mmc), "ran out of scatterlist prematurely\n"); 326 + data->error = -EINVAL; 327 + complete(&host->pio_complete); 328 + return; 329 + } 330 + sgp = sgm->addr; 331 + remain = sgm->length; 332 + if (remain > host->data_len) 333 + remain = host->data_len; 289 334 290 335 if (data->flags & MMC_DATA_WRITE) { 291 336 while (remain > 0) { ··· 314 331 sgp++; 315 332 len += 4; 316 333 } 334 + sgm->consumed += len; 317 335 remain -= len; 318 336 } 319 337 ··· 331 347 sgp++; 332 348 len += 4; 333 349 } 350 + sgm->consumed += len; 334 351 remain -= len; 335 352 } 336 353 } 337 354 338 - data->bytes_xfered += host->data_remain - remain; 339 - host->data_remain = remain; 340 - 341 - if (host->data_len != data->bytes_xfered) 342 - moxart_next_sg(host); 343 - else 355 + data->bytes_xfered += sgm->consumed; 356 + if (host->data_len == data->bytes_xfered) { 344 357 complete(&host->pio_complete); 358 + return; 359 + } 345 360 } 346 361 347 362 static void moxart_prepare_data(struct moxart_host *host) 348 363 { 349 364 struct mmc_data *data = host->mrq->cmd->data; 365 + unsigned int flags = SG_MITER_ATOMIC; /* Used from IRQ */ 350 366 u32 datactrl; 351 367 int blksz_bits; 352 368 ··· 357 373 blksz_bits = ffs(data->blksz) - 1; 358 374 BUG_ON(1 << blksz_bits != data->blksz); 359 375 360 - moxart_init_sg(host, data); 361 - 362 376 datactrl = DCR_DATA_EN | (blksz_bits & DCR_BLK_SIZE); 363 377 364 - if (data->flags & MMC_DATA_WRITE) 378 + if (data->flags & MMC_DATA_WRITE) { 379 + flags |= SG_MITER_FROM_SG; 365 380 datactrl |= DCR_DATA_WRITE; 381 + } else { 382 + flags |= SG_MITER_TO_SG; 383 + } 366 384 367 385 if (moxart_use_dma(host)) 368 386 datactrl |= DCR_DMA_EN; 387 + else 388 + sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags); 369 389 370 390 writel(DCR_DATA_FIFO_RESET, host->base + REG_DATA_CONTROL); 371 391 writel(MASK_DATA | FIFO_URUN | FIFO_ORUN, host->base + REG_CLEAR); ··· 442 454 } 443 455 444 456 request_done: 457 + if (!moxart_use_dma(host)) 458 + sg_miter_stop(&host->sg_miter); 459 + 445 460 spin_unlock_irqrestore(&host->lock, flags); 446 461 mmc_request_done(host->mmc, mrq); 447 462 }