aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mmc/host/dw_mmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mmc/host/dw_mmc.c')
-rw-r--r--drivers/mmc/host/dw_mmc.c144
1 files changed, 75 insertions, 69 deletions
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 0e342793ff14..8bec1c36b159 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -22,7 +22,6 @@
22#include <linux/ioport.h> 22#include <linux/ioport.h>
23#include <linux/module.h> 23#include <linux/module.h>
24#include <linux/platform_device.h> 24#include <linux/platform_device.h>
25#include <linux/scatterlist.h>
26#include <linux/seq_file.h> 25#include <linux/seq_file.h>
27#include <linux/slab.h> 26#include <linux/slab.h>
28#include <linux/stat.h> 27#include <linux/stat.h>
@@ -502,8 +501,14 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
502 host->dir_status = DW_MCI_SEND_STATUS; 501 host->dir_status = DW_MCI_SEND_STATUS;
503 502
504 if (dw_mci_submit_data_dma(host, data)) { 503 if (dw_mci_submit_data_dma(host, data)) {
504 int flags = SG_MITER_ATOMIC;
505 if (host->data->flags & MMC_DATA_READ)
506 flags |= SG_MITER_TO_SG;
507 else
508 flags |= SG_MITER_FROM_SG;
509
510 sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
505 host->sg = data->sg; 511 host->sg = data->sg;
506 host->pio_offset = 0;
507 host->part_buf_start = 0; 512 host->part_buf_start = 0;
508 host->part_buf_count = 0; 513 host->part_buf_count = 0;
509 514
@@ -972,6 +977,7 @@ static void dw_mci_tasklet_func(unsigned long priv)
972 * generates a block interrupt, hence setting 977 * generates a block interrupt, hence setting
973 * the scatter-gather pointer to NULL. 978 * the scatter-gather pointer to NULL.
974 */ 979 */
980 sg_miter_stop(&host->sg_miter);
975 host->sg = NULL; 981 host->sg = NULL;
976 ctrl = mci_readl(host, CTRL); 982 ctrl = mci_readl(host, CTRL);
977 ctrl |= SDMMC_CTRL_FIFO_RESET; 983 ctrl |= SDMMC_CTRL_FIFO_RESET;
@@ -1311,54 +1317,44 @@ static void dw_mci_pull_data(struct dw_mci *host, void *buf, int cnt)
1311 1317
1312static void dw_mci_read_data_pio(struct dw_mci *host) 1318static void dw_mci_read_data_pio(struct dw_mci *host)
1313{ 1319{
1314 struct scatterlist *sg = host->sg; 1320 struct sg_mapping_iter *sg_miter = &host->sg_miter;
1315 void *buf = sg_virt(sg); 1321 void *buf;
1316 unsigned int offset = host->pio_offset; 1322 unsigned int offset;
1317 struct mmc_data *data = host->data; 1323 struct mmc_data *data = host->data;
1318 int shift = host->data_shift; 1324 int shift = host->data_shift;
1319 u32 status; 1325 u32 status;
1320 unsigned int nbytes = 0, len; 1326 unsigned int nbytes = 0, len;
1327 unsigned int remain, fcnt;
1321 1328
1322 do { 1329 do {
1323 len = host->part_buf_count + 1330 if (!sg_miter_next(sg_miter))
1324 (SDMMC_GET_FCNT(mci_readl(host, STATUS)) << shift); 1331 goto done;
1325 if (offset + len <= sg->length) { 1332
1333 host->sg = sg_miter->__sg;
1334 buf = sg_miter->addr;
1335 remain = sg_miter->length;
1336 offset = 0;
1337
1338 do {
1339 fcnt = (SDMMC_GET_FCNT(mci_readl(host, STATUS))
1340 << shift) + host->part_buf_count;
1341 len = min(remain, fcnt);
1342 if (!len)
1343 break;
1326 dw_mci_pull_data(host, (void *)(buf + offset), len); 1344 dw_mci_pull_data(host, (void *)(buf + offset), len);
1327
1328 offset += len; 1345 offset += len;
1329 nbytes += len; 1346 nbytes += len;
1330 1347 remain -= len;
1331 if (offset == sg->length) { 1348 } while (remain);
1332 flush_dcache_page(sg_page(sg)); 1349 sg_miter->consumed = offset;
1333 host->sg = sg = sg_next(sg);
1334 if (!sg)
1335 goto done;
1336
1337 offset = 0;
1338 buf = sg_virt(sg);
1339 }
1340 } else {
1341 unsigned int remaining = sg->length - offset;
1342 dw_mci_pull_data(host, (void *)(buf + offset),
1343 remaining);
1344 nbytes += remaining;
1345
1346 flush_dcache_page(sg_page(sg));
1347 host->sg = sg = sg_next(sg);
1348 if (!sg)
1349 goto done;
1350
1351 offset = len - remaining;
1352 buf = sg_virt(sg);
1353 dw_mci_pull_data(host, buf, offset);
1354 nbytes += offset;
1355 }
1356 1350
1357 status = mci_readl(host, MINTSTS); 1351 status = mci_readl(host, MINTSTS);
1358 mci_writel(host, RINTSTS, SDMMC_INT_RXDR); 1352 mci_writel(host, RINTSTS, SDMMC_INT_RXDR);
1359 if (status & DW_MCI_DATA_ERROR_FLAGS) { 1353 if (status & DW_MCI_DATA_ERROR_FLAGS) {
1360 host->data_status = status; 1354 host->data_status = status;
1361 data->bytes_xfered += nbytes; 1355 data->bytes_xfered += nbytes;
1356 sg_miter_stop(sg_miter);
1357 host->sg = NULL;
1362 smp_wmb(); 1358 smp_wmb();
1363 1359
1364 set_bit(EVENT_DATA_ERROR, &host->pending_events); 1360 set_bit(EVENT_DATA_ERROR, &host->pending_events);
@@ -1367,65 +1363,66 @@ static void dw_mci_read_data_pio(struct dw_mci *host)
1367 return; 1363 return;
1368 } 1364 }
1369 } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/ 1365 } while (status & SDMMC_INT_RXDR); /*if the RXDR is ready read again*/
1370 host->pio_offset = offset;
1371 data->bytes_xfered += nbytes; 1366 data->bytes_xfered += nbytes;
1367
1368 if (!remain) {
1369 if (!sg_miter_next(sg_miter))
1370 goto done;
1371 sg_miter->consumed = 0;
1372 }
1373 sg_miter_stop(sg_miter);
1372 return; 1374 return;
1373 1375
1374done: 1376done:
1375 data->bytes_xfered += nbytes; 1377 data->bytes_xfered += nbytes;
1378 sg_miter_stop(sg_miter);
1379 host->sg = NULL;
1376 smp_wmb(); 1380 smp_wmb();
1377 set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 1381 set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1378} 1382}
1379 1383
1380static void dw_mci_write_data_pio(struct dw_mci *host) 1384static void dw_mci_write_data_pio(struct dw_mci *host)
1381{ 1385{
1382 struct scatterlist *sg = host->sg; 1386 struct sg_mapping_iter *sg_miter = &host->sg_miter;
1383 void *buf = sg_virt(sg); 1387 void *buf;
1384 unsigned int offset = host->pio_offset; 1388 unsigned int offset;
1385 struct mmc_data *data = host->data; 1389 struct mmc_data *data = host->data;
1386 int shift = host->data_shift; 1390 int shift = host->data_shift;
1387 u32 status; 1391 u32 status;
1388 unsigned int nbytes = 0, len; 1392 unsigned int nbytes = 0, len;
1393 unsigned int fifo_depth = host->fifo_depth;
1394 unsigned int remain, fcnt;
1389 1395
1390 do { 1396 do {
1391 len = ((host->fifo_depth - 1397 if (!sg_miter_next(sg_miter))
1392 SDMMC_GET_FCNT(mci_readl(host, STATUS))) << shift) 1398 goto done;
1393 - host->part_buf_count; 1399
1394 if (offset + len <= sg->length) { 1400 host->sg = sg_miter->__sg;
1401 buf = sg_miter->addr;
1402 remain = sg_miter->length;
1403 offset = 0;
1404
1405 do {
1406 fcnt = ((fifo_depth -
1407 SDMMC_GET_FCNT(mci_readl(host, STATUS)))
1408 << shift) - host->part_buf_count;
1409 len = min(remain, fcnt);
1410 if (!len)
1411 break;
1395 host->push_data(host, (void *)(buf + offset), len); 1412 host->push_data(host, (void *)(buf + offset), len);
1396
1397 offset += len; 1413 offset += len;
1398 nbytes += len; 1414 nbytes += len;
1399 if (offset == sg->length) { 1415 remain -= len;
1400 host->sg = sg = sg_next(sg); 1416 } while (remain);
1401 if (!sg) 1417 sg_miter->consumed = offset;
1402 goto done;
1403
1404 offset = 0;
1405 buf = sg_virt(sg);
1406 }
1407 } else {
1408 unsigned int remaining = sg->length - offset;
1409
1410 host->push_data(host, (void *)(buf + offset),
1411 remaining);
1412 nbytes += remaining;
1413
1414 host->sg = sg = sg_next(sg);
1415 if (!sg)
1416 goto done;
1417
1418 offset = len - remaining;
1419 buf = sg_virt(sg);
1420 host->push_data(host, (void *)buf, offset);
1421 nbytes += offset;
1422 }
1423 1418
1424 status = mci_readl(host, MINTSTS); 1419 status = mci_readl(host, MINTSTS);
1425 mci_writel(host, RINTSTS, SDMMC_INT_TXDR); 1420 mci_writel(host, RINTSTS, SDMMC_INT_TXDR);
1426 if (status & DW_MCI_DATA_ERROR_FLAGS) { 1421 if (status & DW_MCI_DATA_ERROR_FLAGS) {
1427 host->data_status = status; 1422 host->data_status = status;
1428 data->bytes_xfered += nbytes; 1423 data->bytes_xfered += nbytes;
1424 sg_miter_stop(sg_miter);
1425 host->sg = NULL;
1429 1426
1430 smp_wmb(); 1427 smp_wmb();
1431 1428
@@ -1435,12 +1432,20 @@ static void dw_mci_write_data_pio(struct dw_mci *host)
1435 return; 1432 return;
1436 } 1433 }
1437 } while (status & SDMMC_INT_TXDR); /* if TXDR write again */ 1434 } while (status & SDMMC_INT_TXDR); /* if TXDR write again */
1438 host->pio_offset = offset;
1439 data->bytes_xfered += nbytes; 1435 data->bytes_xfered += nbytes;
1436
1437 if (!remain) {
1438 if (!sg_miter_next(sg_miter))
1439 goto done;
1440 sg_miter->consumed = 0;
1441 }
1442 sg_miter_stop(sg_miter);
1440 return; 1443 return;
1441 1444
1442done: 1445done:
1443 data->bytes_xfered += nbytes; 1446 data->bytes_xfered += nbytes;
1447 sg_miter_stop(sg_miter);
1448 host->sg = NULL;
1444 smp_wmb(); 1449 smp_wmb();
1445 set_bit(EVENT_XFER_COMPLETE, &host->pending_events); 1450 set_bit(EVENT_XFER_COMPLETE, &host->pending_events);
1446} 1451}
@@ -1643,6 +1648,7 @@ static void dw_mci_work_routine_card(struct work_struct *work)
1643 * block interrupt, hence setting the 1648 * block interrupt, hence setting the
1644 * scatter-gather pointer to NULL. 1649 * scatter-gather pointer to NULL.
1645 */ 1650 */
1651 sg_miter_stop(&host->sg_miter);
1646 host->sg = NULL; 1652 host->sg = NULL;
1647 1653
1648 ctrl = mci_readl(host, CTRL); 1654 ctrl = mci_readl(host, CTRL);