wbsd.c (594ce0b8a998aa4d05827cd7c0d0dcec9a1e3ae2) wbsd.c (921c87ba3893b5d3608e7f248366266b40b86c75)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * linux/drivers/mmc/host/wbsd.c - Winbond W83L51xD SD/MMC driver
4 *
5 * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
6 *
7 * Warning!
8 *

--- 445 unchanged lines hidden (view full) ---

454 kunmap_local(buffer);
455
456 /*
457 * This is a very dirty hack to solve a
458 * hardware problem. The chip doesn't trigger
459 * FIFO threshold interrupts properly.
460 */
461 if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * linux/drivers/mmc/host/wbsd.c - Winbond W83L51xD SD/MMC driver
4 *
5 * Copyright (C) 2004-2007 Pierre Ossman, All Rights Reserved.
6 *
7 * Warning!
8 *

--- 445 unchanged lines hidden (view full) ---

454 kunmap_local(buffer);
455
456 /*
457 * This is a very dirty hack to solve a
458 * hardware problem. The chip doesn't trigger
459 * FIFO threshold interrupts properly.
460 */
461 if ((data->blocks * data->blksz - data->bytes_xfered) < 16)
462 tasklet_schedule(&host->fifo_tasklet);
462 queue_work(system_bh_wq, &host->fifo_bh_work);
463}
464
465static void wbsd_fill_fifo(struct wbsd_host *host)
466{
467 struct mmc_data *data = host->mrq->cmd->data;
468 char *buffer;
469 int i, idx, fsr, fifo;
470

--- 48 unchanged lines hidden (view full) ---

519 }
520 kunmap_local(buffer);
521
522 /*
523 * The controller stops sending interrupts for
524 * 'FIFO empty' under certain conditions. So we
525 * need to be a bit more pro-active.
526 */
463}
464
465static void wbsd_fill_fifo(struct wbsd_host *host)
466{
467 struct mmc_data *data = host->mrq->cmd->data;
468 char *buffer;
469 int i, idx, fsr, fifo;
470

--- 48 unchanged lines hidden (view full) ---

519 }
520 kunmap_local(buffer);
521
522 /*
523 * The controller stops sending interrupts for
524 * 'FIFO empty' under certain conditions. So we
525 * need to be a bit more pro-active.
526 */
527 tasklet_schedule(&host->fifo_tasklet);
527 queue_work(system_bh_wq, &host->fifo_bh_work);
528}
529
530static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
531{
532 u16 blksize;
533 u8 setup;
534 unsigned long dmaflags;
535 unsigned int size;

--- 205 unchanged lines hidden (view full) ---

741\*****************************************************************************/
742
743static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
744{
745 struct wbsd_host *host = mmc_priv(mmc);
746 struct mmc_command *cmd;
747
748 /*
528}
529
530static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data)
531{
532 u16 blksize;
533 u8 setup;
534 unsigned long dmaflags;
535 unsigned int size;

--- 205 unchanged lines hidden (view full) ---

741\*****************************************************************************/
742
743static void wbsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
744{
745 struct wbsd_host *host = mmc_priv(mmc);
746 struct mmc_command *cmd;
747
748 /*
749 * Disable tasklets to avoid a deadlock.
749 * Disable bh works to avoid a deadlock.
750 */
751 spin_lock_bh(&host->lock);
752
753 BUG_ON(host->mrq != NULL);
754
755 cmd = mrq->cmd;
756
757 host->mrq = mrq;

--- 58 unchanged lines hidden (view full) ---

816 * will be finished after the data has
817 * transferred.
818 */
819 if (cmd->data && !cmd->error) {
820 /*
821 * Dirty fix for hardware bug.
822 */
823 if (host->dma == -1)
750 */
751 spin_lock_bh(&host->lock);
752
753 BUG_ON(host->mrq != NULL);
754
755 cmd = mrq->cmd;
756
757 host->mrq = mrq;

--- 58 unchanged lines hidden (view full) ---

816 * will be finished after the data has
817 * transferred.
818 */
819 if (cmd->data && !cmd->error) {
820 /*
821 * Dirty fix for hardware bug.
822 */
823 if (host->dma == -1)
824 tasklet_schedule(&host->fifo_tasklet);
824 queue_work(system_bh_wq, &host->fifo_bh_work);
825
826 spin_unlock_bh(&host->lock);
827
828 return;
829 }
830
831done:
832 wbsd_request_end(host, mrq);

--- 123 unchanged lines hidden (view full) ---

956 spin_lock_bh(&host->lock);
957
958 host->flags &= ~WBSD_FIGNORE_DETECT;
959
960 /*
961 * Card status might have changed during the
962 * blackout.
963 */
825
826 spin_unlock_bh(&host->lock);
827
828 return;
829 }
830
831done:
832 wbsd_request_end(host, mrq);

--- 123 unchanged lines hidden (view full) ---

956 spin_lock_bh(&host->lock);
957
958 host->flags &= ~WBSD_FIGNORE_DETECT;
959
960 /*
961 * Card status might have changed during the
962 * blackout.
963 */
964 tasklet_schedule(&host->card_tasklet);
964 queue_work(system_bh_wq, &host->card_bh_work);
965
966 spin_unlock_bh(&host->lock);
967}
968
969/*
965
966 spin_unlock_bh(&host->lock);
967}
968
969/*
970 * Tasklets
970 * BH Works
971 */
972
973static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
974{
975 WARN_ON(!host->mrq);
976 if (!host->mrq)
977 return NULL;
978
979 WARN_ON(!host->mrq->cmd);
980 if (!host->mrq->cmd)
981 return NULL;
982
983 WARN_ON(!host->mrq->cmd->data);
984 if (!host->mrq->cmd->data)
985 return NULL;
986
987 return host->mrq->cmd->data;
988}
989
971 */
972
973static inline struct mmc_data *wbsd_get_data(struct wbsd_host *host)
974{
975 WARN_ON(!host->mrq);
976 if (!host->mrq)
977 return NULL;
978
979 WARN_ON(!host->mrq->cmd);
980 if (!host->mrq->cmd)
981 return NULL;
982
983 WARN_ON(!host->mrq->cmd->data);
984 if (!host->mrq->cmd->data)
985 return NULL;
986
987 return host->mrq->cmd->data;
988}
989
990static void wbsd_tasklet_card(struct tasklet_struct *t)
990static void wbsd_card_bh_work(struct work_struct *t)
991{
991{
992 struct wbsd_host *host = from_tasklet(host, t, card_tasklet);
992 struct wbsd_host *host = from_work(host, t, card_bh_work);
993 u8 csr;
994 int delay = -1;
995
996 spin_lock(&host->lock);
997
998 if (host->flags & WBSD_FIGNORE_DETECT) {
999 spin_unlock(&host->lock);
1000 return;

--- 14 unchanged lines hidden (view full) ---

1015 host->flags &= ~WBSD_FCARD_PRESENT;
1016
1017 if (host->mrq) {
1018 pr_err("%s: Card removed during transfer!\n",
1019 mmc_hostname(host->mmc));
1020 wbsd_reset(host);
1021
1022 host->mrq->cmd->error = -ENOMEDIUM;
993 u8 csr;
994 int delay = -1;
995
996 spin_lock(&host->lock);
997
998 if (host->flags & WBSD_FIGNORE_DETECT) {
999 spin_unlock(&host->lock);
1000 return;

--- 14 unchanged lines hidden (view full) ---

1015 host->flags &= ~WBSD_FCARD_PRESENT;
1016
1017 if (host->mrq) {
1018 pr_err("%s: Card removed during transfer!\n",
1019 mmc_hostname(host->mmc));
1020 wbsd_reset(host);
1021
1022 host->mrq->cmd->error = -ENOMEDIUM;
1023 tasklet_schedule(&host->finish_tasklet);
1023 queue_work(system_bh_wq, &host->finish_bh_work);
1024 }
1025
1026 delay = 0;
1027 }
1028
1029 /*
1030 * Unlock first since we might get a call back.
1031 */
1032
1033 spin_unlock(&host->lock);
1034
1035 if (delay != -1)
1036 mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
1037}
1038
1024 }
1025
1026 delay = 0;
1027 }
1028
1029 /*
1030 * Unlock first since we might get a call back.
1031 */
1032
1033 spin_unlock(&host->lock);
1034
1035 if (delay != -1)
1036 mmc_detect_change(host->mmc, msecs_to_jiffies(delay));
1037}
1038
1039static void wbsd_tasklet_fifo(struct tasklet_struct *t)
1039static void wbsd_fifo_bh_work(struct work_struct *t)
1040{
1040{
1041 struct wbsd_host *host = from_tasklet(host, t, fifo_tasklet);
1041 struct wbsd_host *host = from_work(host, t, fifo_bh_work);
1042 struct mmc_data *data;
1043
1044 spin_lock(&host->lock);
1045
1046 if (!host->mrq)
1047 goto end;
1048
1049 data = wbsd_get_data(host);

--- 5 unchanged lines hidden (view full) ---

1055 else
1056 wbsd_empty_fifo(host);
1057
1058 /*
1059 * Done?
1060 */
1061 if (host->num_sg == 0) {
1062 wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
1042 struct mmc_data *data;
1043
1044 spin_lock(&host->lock);
1045
1046 if (!host->mrq)
1047 goto end;
1048
1049 data = wbsd_get_data(host);

--- 5 unchanged lines hidden (view full) ---

1055 else
1056 wbsd_empty_fifo(host);
1057
1058 /*
1059 * Done?
1060 */
1061 if (host->num_sg == 0) {
1062 wbsd_write_index(host, WBSD_IDX_FIFOEN, 0);
1063 tasklet_schedule(&host->finish_tasklet);
1063 queue_work(system_bh_wq, &host->finish_bh_work);
1064 }
1065
1066end:
1067 spin_unlock(&host->lock);
1068}
1069
1064 }
1065
1066end:
1067 spin_unlock(&host->lock);
1068}
1069
1070static void wbsd_tasklet_crc(struct tasklet_struct *t)
1070static void wbsd_crc_bh_work(struct work_struct *t)
1071{
1071{
1072 struct wbsd_host *host = from_tasklet(host, t, crc_tasklet);
1072 struct wbsd_host *host = from_work(host, t, crc_bh_work);
1073 struct mmc_data *data;
1074
1075 spin_lock(&host->lock);
1076
1077 if (!host->mrq)
1078 goto end;
1079
1080 data = wbsd_get_data(host);
1081 if (!data)
1082 goto end;
1083
1084 DBGF("CRC error\n");
1085
1086 data->error = -EILSEQ;
1087
1073 struct mmc_data *data;
1074
1075 spin_lock(&host->lock);
1076
1077 if (!host->mrq)
1078 goto end;
1079
1080 data = wbsd_get_data(host);
1081 if (!data)
1082 goto end;
1083
1084 DBGF("CRC error\n");
1085
1086 data->error = -EILSEQ;
1087
1088 tasklet_schedule(&host->finish_tasklet);
1088 queue_work(system_bh_wq, &host->finish_bh_work);
1089
1090end:
1091 spin_unlock(&host->lock);
1092}
1093
1089
1090end:
1091 spin_unlock(&host->lock);
1092}
1093
1094static void wbsd_tasklet_timeout(struct tasklet_struct *t)
1094static void wbsd_timeout_bh_work(struct work_struct *t)
1095{
1095{
1096 struct wbsd_host *host = from_tasklet(host, t, timeout_tasklet);
1096 struct wbsd_host *host = from_work(host, t, timeout_bh_work);
1097 struct mmc_data *data;
1098
1099 spin_lock(&host->lock);
1100
1101 if (!host->mrq)
1102 goto end;
1103
1104 data = wbsd_get_data(host);
1105 if (!data)
1106 goto end;
1107
1108 DBGF("Timeout\n");
1109
1110 data->error = -ETIMEDOUT;
1111
1097 struct mmc_data *data;
1098
1099 spin_lock(&host->lock);
1100
1101 if (!host->mrq)
1102 goto end;
1103
1104 data = wbsd_get_data(host);
1105 if (!data)
1106 goto end;
1107
1108 DBGF("Timeout\n");
1109
1110 data->error = -ETIMEDOUT;
1111
1112 tasklet_schedule(&host->finish_tasklet);
1112 queue_work(system_bh_wq, &host->finish_bh_work);
1113
1114end:
1115 spin_unlock(&host->lock);
1116}
1117
1113
1114end:
1115 spin_unlock(&host->lock);
1116}
1117
1118static void wbsd_tasklet_finish(struct tasklet_struct *t)
1118static void wbsd_finish_bh_work(struct work_struct *t)
1119{
1119{
1120 struct wbsd_host *host = from_tasklet(host, t, finish_tasklet);
1120 struct wbsd_host *host = from_work(host, t, finish_bh_work);
1121 struct mmc_data *data;
1122
1123 spin_lock(&host->lock);
1124
1125 WARN_ON(!host->mrq);
1126 if (!host->mrq)
1127 goto end;
1128

--- 22 unchanged lines hidden (view full) ---

1151 * Was it actually our hardware that caused the interrupt?
1152 */
1153 if (isr == 0xff || isr == 0x00)
1154 return IRQ_NONE;
1155
1156 host->isr |= isr;
1157
1158 /*
1121 struct mmc_data *data;
1122
1123 spin_lock(&host->lock);
1124
1125 WARN_ON(!host->mrq);
1126 if (!host->mrq)
1127 goto end;
1128

--- 22 unchanged lines hidden (view full) ---

1151 * Was it actually our hardware that caused the interrupt?
1152 */
1153 if (isr == 0xff || isr == 0x00)
1154 return IRQ_NONE;
1155
1156 host->isr |= isr;
1157
1158 /*
1159 * Schedule tasklets as needed.
1159 * Schedule bh work as needed.
1160 */
1161 if (isr & WBSD_INT_CARD)
1160 */
1161 if (isr & WBSD_INT_CARD)
1162 tasklet_schedule(&host->card_tasklet);
1162 queue_work(system_bh_wq, &host->card_bh_work);
1163 if (isr & WBSD_INT_FIFO_THRE)
1163 if (isr & WBSD_INT_FIFO_THRE)
1164 tasklet_schedule(&host->fifo_tasklet);
1164 queue_work(system_bh_wq, &host->fifo_bh_work);
1165 if (isr & WBSD_INT_CRC)
1165 if (isr & WBSD_INT_CRC)
1166 tasklet_hi_schedule(&host->crc_tasklet);
1166 queue_work(system_bh_highpri_wq, &host->crc_bh_work);
1167 if (isr & WBSD_INT_TIMEOUT)
1167 if (isr & WBSD_INT_TIMEOUT)
1168 tasklet_hi_schedule(&host->timeout_tasklet);
1168 queue_work(system_bh_highpri_wq, &host->timeout_bh_work);
1169 if (isr & WBSD_INT_TC)
1169 if (isr & WBSD_INT_TC)
1170 tasklet_schedule(&host->finish_tasklet);
1170 queue_work(system_bh_wq, &host->finish_bh_work);
1171
1172 return IRQ_HANDLED;
1173}
1174
1175/*****************************************************************************\
1176 * *
1177 * Device initialisation and shutdown *
1178 * *

--- 259 unchanged lines hidden (view full) ---

1438 * Allocate/free IRQ.
1439 */
1440
1441static int wbsd_request_irq(struct wbsd_host *host, int irq)
1442{
1443 int ret;
1444
1445 /*
1171
1172 return IRQ_HANDLED;
1173}
1174
1175/*****************************************************************************\
1176 * *
1177 * Device initialisation and shutdown *
1178 * *

--- 259 unchanged lines hidden (view full) ---

1438 * Allocate/free IRQ.
1439 */
1440
1441static int wbsd_request_irq(struct wbsd_host *host, int irq)
1442{
1443 int ret;
1444
1445 /*
1446 * Set up tasklets. Must be done before requesting interrupt.
1446 * Set up bh works. Must be done before requesting interrupt.
1447 */
1447 */
1448 tasklet_setup(&host->card_tasklet, wbsd_tasklet_card);
1449 tasklet_setup(&host->fifo_tasklet, wbsd_tasklet_fifo);
1450 tasklet_setup(&host->crc_tasklet, wbsd_tasklet_crc);
1451 tasklet_setup(&host->timeout_tasklet, wbsd_tasklet_timeout);
1452 tasklet_setup(&host->finish_tasklet, wbsd_tasklet_finish);
1448 INIT_WORK(&host->card_bh_work, wbsd_card_bh_work);
1449 INIT_WORK(&host->fifo_bh_work, wbsd_fifo_bh_work);
1450 INIT_WORK(&host->crc_bh_work, wbsd_crc_bh_work);
1451 INIT_WORK(&host->timeout_bh_work, wbsd_timeout_bh_work);
1452 INIT_WORK(&host->finish_bh_work, wbsd_finish_bh_work);
1453
1454 /*
1455 * Allocate interrupt.
1456 */
1457 ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
1458 if (ret)
1459 return ret;
1460

--- 6 unchanged lines hidden (view full) ---

1467{
1468 if (!host->irq)
1469 return;
1470
1471 free_irq(host->irq, host);
1472
1473 host->irq = 0;
1474
1453
1454 /*
1455 * Allocate interrupt.
1456 */
1457 ret = request_irq(irq, wbsd_irq, IRQF_SHARED, DRIVER_NAME, host);
1458 if (ret)
1459 return ret;
1460

--- 6 unchanged lines hidden (view full) ---

1467{
1468 if (!host->irq)
1469 return;
1470
1471 free_irq(host->irq, host);
1472
1473 host->irq = 0;
1474
1475 tasklet_kill(&host->card_tasklet);
1476 tasklet_kill(&host->fifo_tasklet);
1477 tasklet_kill(&host->crc_tasklet);
1478 tasklet_kill(&host->timeout_tasklet);
1479 tasklet_kill(&host->finish_tasklet);
1475 cancel_work_sync(&host->card_bh_work);
1476 cancel_work_sync(&host->fifo_bh_work);
1477 cancel_work_sync(&host->crc_bh_work);
1478 cancel_work_sync(&host->timeout_bh_work);
1479 cancel_work_sync(&host->finish_bh_work);
1480}
1481
1482/*
1483 * Allocate all resources for the host.
1484 */
1485
1486static int wbsd_request_resources(struct wbsd_host *host,
1487 int base, int irq, int dma)

--- 514 unchanged lines hidden ---
1480}
1481
1482/*
1483 * Allocate all resources for the host.
1484 */
1485
1486static int wbsd_request_resources(struct wbsd_host *host,
1487 int base, int irq, int dma)

--- 514 unchanged lines hidden ---