summaryrefslogtreecommitdiff
path: root/drivers/mmc/core
diff options
context:
space:
mode:
authorAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-12-15 14:52:16 -0300
committerAndré Fabian Silva Delgado <emulatorman@parabola.nu>2015-12-15 14:52:16 -0300
commit8d91c1e411f55d7ea91b1183a2e9f8088fb4d5be (patch)
treee9891aa6c295060d065adffd610c4f49ecf884f3 /drivers/mmc/core
parenta71852147516bc1cb5b0b3cbd13639bfd4022dc8 (diff)
Linux-libre 4.3.2-gnu
Diffstat (limited to 'drivers/mmc/core')
-rw-r--r--drivers/mmc/core/core.c40
-rw-r--r--drivers/mmc/core/host.c42
-rw-r--r--drivers/mmc/core/mmc.c7
3 files changed, 56 insertions, 33 deletions
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 2f4503a7f..a3eb20bdc 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -2172,6 +2172,7 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
unsigned int arg)
{
unsigned int rem, to = from + nr;
+ int err;
if (!(card->host->caps & MMC_CAP_ERASE) ||
!(card->csd.cmdclass & CCC_ERASE))
@@ -2222,6 +2223,22 @@ int mmc_erase(struct mmc_card *card, unsigned int from, unsigned int nr,
/* 'from' and 'to' are inclusive */
to -= 1;
+ /*
+ * Special case where only one erase-group fits in the timeout budget:
+ * If the region crosses an erase-group boundary on this particular
+ * case, we will be trimming more than one erase-group which, does not
+ * fit in the timeout budget of the controller, so we need to split it
+ * and call mmc_do_erase() twice if necessary. This special case is
+ * identified by the card->eg_boundary flag.
+ */
+ rem = card->erase_size - (from % card->erase_size);
+ if ((arg & MMC_TRIM_ARGS) && (card->eg_boundary) && (nr > rem)) {
+ err = mmc_do_erase(card, from, from + rem - 1, arg);
+ from += rem;
+ if ((err) || (to <= from))
+ return err;
+ }
+
return mmc_do_erase(card, from, to, arg);
}
EXPORT_SYMBOL(mmc_erase);
@@ -2237,7 +2254,8 @@ EXPORT_SYMBOL(mmc_can_erase);
int mmc_can_trim(struct mmc_card *card)
{
- if (card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN)
+ if ((card->ext_csd.sec_feature_support & EXT_CSD_SEC_GB_CL_EN) &&
+ (!(card->quirks & MMC_QUIRK_TRIM_BROKEN)))
return 1;
return 0;
}
@@ -2317,16 +2335,28 @@ static unsigned int mmc_do_calc_max_discard(struct mmc_card *card,
if (!qty)
return 0;
+ /*
+ * When specifying a sector range to trim, chances are we might cross
+ * an erase-group boundary even if the amount of sectors is less than
+ * one erase-group.
+ * If we can only fit one erase-group in the controller timeout budget,
+ * we have to care that erase-group boundaries are not crossed by a
+ * single trim operation. We flag that special case with "eg_boundary".
+ * In all other cases we can just decrement qty and pretend that we
+ * always touch (qty + 1) erase-groups as a simple optimization.
+ */
if (qty == 1)
- return 1;
+ card->eg_boundary = 1;
+ else
+ qty--;
/* Convert qty to sectors */
if (card->erase_shift)
- max_discard = --qty << card->erase_shift;
+ max_discard = qty << card->erase_shift;
else if (mmc_card_sd(card))
- max_discard = qty;
+ max_discard = qty + 1;
else
- max_discard = --qty * card->erase_size;
+ max_discard = qty * card->erase_size;
return max_discard;
}
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 79979e9d5..5466f25f0 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -398,7 +398,7 @@ int mmc_of_parse(struct mmc_host *host)
{
struct device_node *np;
u32 bus_width;
- int len, ret;
+ int ret;
bool cd_cap_invert, cd_gpio_invert = false;
bool ro_cap_invert, ro_gpio_invert = false;
@@ -445,12 +445,12 @@ int mmc_of_parse(struct mmc_host *host)
*/
/* Parse Card Detection */
- if (of_find_property(np, "non-removable", &len)) {
+ if (of_property_read_bool(np, "non-removable")) {
host->caps |= MMC_CAP_NONREMOVABLE;
} else {
cd_cap_invert = of_property_read_bool(np, "cd-inverted");
- if (of_find_property(np, "broken-cd", &len))
+ if (of_property_read_bool(np, "broken-cd"))
host->caps |= MMC_CAP_NEEDS_POLL;
ret = mmc_gpiod_request_cd(host, "cd", 0, true,
@@ -491,41 +491,41 @@ int mmc_of_parse(struct mmc_host *host)
if (ro_cap_invert ^ ro_gpio_invert)
host->caps2 |= MMC_CAP2_RO_ACTIVE_HIGH;
- if (of_find_property(np, "cap-sd-highspeed", &len))
+ if (of_property_read_bool(np, "cap-sd-highspeed"))
host->caps |= MMC_CAP_SD_HIGHSPEED;
- if (of_find_property(np, "cap-mmc-highspeed", &len))
+ if (of_property_read_bool(np, "cap-mmc-highspeed"))
host->caps |= MMC_CAP_MMC_HIGHSPEED;
- if (of_find_property(np, "sd-uhs-sdr12", &len))
+ if (of_property_read_bool(np, "sd-uhs-sdr12"))
host->caps |= MMC_CAP_UHS_SDR12;
- if (of_find_property(np, "sd-uhs-sdr25", &len))
+ if (of_property_read_bool(np, "sd-uhs-sdr25"))
host->caps |= MMC_CAP_UHS_SDR25;
- if (of_find_property(np, "sd-uhs-sdr50", &len))
+ if (of_property_read_bool(np, "sd-uhs-sdr50"))
host->caps |= MMC_CAP_UHS_SDR50;
- if (of_find_property(np, "sd-uhs-sdr104", &len))
+ if (of_property_read_bool(np, "sd-uhs-sdr104"))
host->caps |= MMC_CAP_UHS_SDR104;
- if (of_find_property(np, "sd-uhs-ddr50", &len))
+ if (of_property_read_bool(np, "sd-uhs-ddr50"))
host->caps |= MMC_CAP_UHS_DDR50;
- if (of_find_property(np, "cap-power-off-card", &len))
+ if (of_property_read_bool(np, "cap-power-off-card"))
host->caps |= MMC_CAP_POWER_OFF_CARD;
- if (of_find_property(np, "cap-sdio-irq", &len))
+ if (of_property_read_bool(np, "cap-sdio-irq"))
host->caps |= MMC_CAP_SDIO_IRQ;
- if (of_find_property(np, "full-pwr-cycle", &len))
+ if (of_property_read_bool(np, "full-pwr-cycle"))
host->caps2 |= MMC_CAP2_FULL_PWR_CYCLE;
- if (of_find_property(np, "keep-power-in-suspend", &len))
+ if (of_property_read_bool(np, "keep-power-in-suspend"))
host->pm_caps |= MMC_PM_KEEP_POWER;
- if (of_find_property(np, "enable-sdio-wakeup", &len))
+ if (of_property_read_bool(np, "enable-sdio-wakeup"))
host->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
- if (of_find_property(np, "mmc-ddr-1_8v", &len))
+ if (of_property_read_bool(np, "mmc-ddr-1_8v"))
host->caps |= MMC_CAP_1_8V_DDR;
- if (of_find_property(np, "mmc-ddr-1_2v", &len))
+ if (of_property_read_bool(np, "mmc-ddr-1_2v"))
host->caps |= MMC_CAP_1_2V_DDR;
- if (of_find_property(np, "mmc-hs200-1_8v", &len))
+ if (of_property_read_bool(np, "mmc-hs200-1_8v"))
host->caps2 |= MMC_CAP2_HS200_1_8V_SDR;
- if (of_find_property(np, "mmc-hs200-1_2v", &len))
+ if (of_property_read_bool(np, "mmc-hs200-1_2v"))
host->caps2 |= MMC_CAP2_HS200_1_2V_SDR;
- if (of_find_property(np, "mmc-hs400-1_8v", &len))
+ if (of_property_read_bool(np, "mmc-hs400-1_8v"))
host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
- if (of_find_property(np, "mmc-hs400-1_2v", &len))
+ if (of_property_read_bool(np, "mmc-hs400-1_2v"))
host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index e72690317..f6cd995db 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1924,7 +1924,6 @@ EXPORT_SYMBOL(mmc_can_reset);
static int mmc_reset(struct mmc_host *host)
{
struct mmc_card *card = host->card;
- u32 status;
if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
return -EOPNOTSUPP;
@@ -1937,12 +1936,6 @@ static int mmc_reset(struct mmc_host *host)
host->ops->hw_reset(host);
- /* If the reset has happened, then a status command will fail */
- if (!mmc_send_status(card, &status)) {
- mmc_host_clk_release(host);
- return -ENOSYS;
- }
-
/* Set initial state and call mmc_set_ios */
mmc_set_initial_state(host);
mmc_host_clk_release(host);