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 --- |