Skip to content

Commit

Permalink
Merge tag 'mmc-fixes-for-3.3-rc4' of git://git.kernel.org/pub/scm/lin…
Browse files Browse the repository at this point in the history
…ux/kernel/git/cjb/mmc

MMC fixes for 3.3-rc4:
 * The most visible fix here is against a regression introduced in 3.3-rc1
   that ran cards in Ultra High Speed mode even when they failed to initialize
   in that mode, leading to lower-speed cards failing to mount.
 * A lockdep warning introduced in 3.3-rc1 is fixed.
 * Various other small driver fixes, most notably for a NULL dereference
   when using highmem with dw_mmc.

* tag 'mmc-fixes-for-3.3-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/cjb/mmc:
  mmc: dw_mmc: Fix PIO mode with support of highmem
  mmc: atmel-mci: save and restore sdioirq when soft reset is performed
  mmc: block: Init ro_lock sysfs attr to fix lockdep warnings
  mmc: sh_mmcif: fix late delayed work initialisation
  mmc: tmio_mmc: fix card eject during IO with DMA
  mmc: core: Fix comparison issue in mmc_compare_ext_csds
  mmc: core: Fix PowerOff Notify suspend/resume
  mmc: sdhci-pci: set Medfield SDIO as non-removable
  mmc: core: add the capability for broken voltage
  mmc: core: Fix low speed mmc card detection failure
  mmc: esdhc: set the timeout to the max value
  mmc: esdhc: add PIO mode support
  mmc: core: Ensure clocks are always enabled before host interaction
  mmc: of_mmc_spi: fix little endian support
  mmc: core: UHS sdio card that fails should not exceed 50MHz
  mmc: esdhc: fix errors when booting kernel on Freescale eSDHC version 2.3
  • Loading branch information
torvalds committed Feb 14, 2012
2 parents 694ce18 + f9c2a0d commit 8b36ac5
Show file tree
Hide file tree
Showing 20 changed files with 269 additions and 133 deletions.
1 change: 1 addition & 0 deletions drivers/mmc/card/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -1694,6 +1694,7 @@ static int mmc_add_disk(struct mmc_blk_data *md)

md->power_ro_lock.show = power_ro_lock_show;
md->power_ro_lock.store = power_ro_lock_store;
sysfs_attr_init(&md->power_ro_lock.attr);
md->power_ro_lock.attr.mode = mode;
md->power_ro_lock.attr.name =
"ro_lock_until_next_power_on";
Expand Down
49 changes: 39 additions & 10 deletions drivers/mmc/core/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -290,8 +290,11 @@ static void mmc_wait_for_req_done(struct mmc_host *host,
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
bool is_first_req)
{
if (host->ops->pre_req)
if (host->ops->pre_req) {
mmc_host_clk_hold(host);
host->ops->pre_req(host, mrq, is_first_req);
mmc_host_clk_release(host);
}
}

/**
Expand All @@ -306,8 +309,11 @@ static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
int err)
{
if (host->ops->post_req)
if (host->ops->post_req) {
mmc_host_clk_hold(host);
host->ops->post_req(host, mrq, err);
mmc_host_clk_release(host);
}
}

/**
Expand Down Expand Up @@ -620,7 +626,9 @@ int mmc_host_enable(struct mmc_host *host)
int err;

host->en_dis_recurs = 1;
mmc_host_clk_hold(host);
err = host->ops->enable(host);
mmc_host_clk_release(host);
host->en_dis_recurs = 0;

if (err) {
Expand All @@ -640,7 +648,9 @@ static int mmc_host_do_disable(struct mmc_host *host, int lazy)
int err;

host->en_dis_recurs = 1;
mmc_host_clk_hold(host);
err = host->ops->disable(host, lazy);
mmc_host_clk_release(host);
host->en_dis_recurs = 0;

if (err < 0) {
Expand Down Expand Up @@ -1121,6 +1131,10 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
* might not allow this operation
*/
voltage = regulator_get_voltage(supply);

if (mmc->caps2 & MMC_CAP2_BROKEN_VOLTAGE)
min_uV = max_uV = voltage;

if (voltage < 0)
result = voltage;
else if (voltage < min_uV || voltage > max_uV)
Expand Down Expand Up @@ -1203,8 +1217,11 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, bool cmd11

host->ios.signal_voltage = signal_voltage;

if (host->ops->start_signal_voltage_switch)
if (host->ops->start_signal_voltage_switch) {
mmc_host_clk_hold(host);
err = host->ops->start_signal_voltage_switch(host, &host->ios);
mmc_host_clk_release(host);
}

return err;
}
Expand Down Expand Up @@ -1239,6 +1256,7 @@ static void mmc_poweroff_notify(struct mmc_host *host)
int err = 0;

card = host->card;
mmc_claim_host(host);

/*
* Send power notify command only if card
Expand Down Expand Up @@ -1269,6 +1287,7 @@ static void mmc_poweroff_notify(struct mmc_host *host)
/* Set the card state to no notification after the poweroff */
card->poweroff_notify_state = MMC_NO_POWER_NOTIFICATION;
}
mmc_release_host(host);
}

/*
Expand Down Expand Up @@ -1327,12 +1346,28 @@ static void mmc_power_up(struct mmc_host *host)

void mmc_power_off(struct mmc_host *host)
{
int err = 0;
mmc_host_clk_hold(host);

host->ios.clock = 0;
host->ios.vdd = 0;

mmc_poweroff_notify(host);
/*
* For eMMC 4.5 device send AWAKE command before
* POWER_OFF_NOTIFY command, because in sleep state
* eMMC 4.5 devices respond to only RESET and AWAKE cmd
*/
if (host->card && mmc_card_is_sleep(host->card) &&
host->bus_ops->resume) {
err = host->bus_ops->resume(host);

if (!err)
mmc_poweroff_notify(host);
else
pr_warning("%s: error %d during resume "
"(continue with poweroff sequence)\n",
mmc_hostname(host), err);
}

/*
* Reset ocr mask to be the highest possible voltage supported for
Expand Down Expand Up @@ -2386,12 +2421,6 @@ int mmc_suspend_host(struct mmc_host *host)
*/
if (mmc_try_claim_host(host)) {
if (host->bus_ops->suspend) {
/*
* For eMMC 4.5 device send notify command
* before sleep, because in sleep state eMMC 4.5
* devices respond to only RESET and AWAKE cmd
*/
mmc_poweroff_notify(host);
err = host->bus_ops->suspend(host);
}
mmc_do_release_host(host);
Expand Down
21 changes: 0 additions & 21 deletions drivers/mmc/core/host.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,27 +14,6 @@

int mmc_register_host_class(void);
void mmc_unregister_host_class(void);

#ifdef CONFIG_MMC_CLKGATE
void mmc_host_clk_hold(struct mmc_host *host);
void mmc_host_clk_release(struct mmc_host *host);
unsigned int mmc_host_clk_rate(struct mmc_host *host);

#else
static inline void mmc_host_clk_hold(struct mmc_host *host)
{
}

static inline void mmc_host_clk_release(struct mmc_host *host)
{
}

static inline unsigned int mmc_host_clk_rate(struct mmc_host *host)
{
return host->ios.clock;
}
#endif

void mmc_host_deeper_disable(struct work_struct *work);

#endif
Expand Down
26 changes: 17 additions & 9 deletions drivers/mmc/core/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
}

card->ext_csd.raw_hc_erase_gap_size =
ext_csd[EXT_CSD_PARTITION_ATTRIBUTE];
ext_csd[EXT_CSD_HC_WP_GRP_SIZE];
card->ext_csd.raw_sec_trim_mult =
ext_csd[EXT_CSD_SEC_TRIM_MULT];
card->ext_csd.raw_sec_erase_mult =
Expand Down Expand Up @@ -551,7 +551,7 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
goto out;

/* only compare read only fields */
err = (!(card->ext_csd.raw_partition_support ==
err = !((card->ext_csd.raw_partition_support ==
bw_ext_csd[EXT_CSD_PARTITION_SUPPORT]) &&
(card->ext_csd.raw_erased_mem_count ==
bw_ext_csd[EXT_CSD_ERASED_MEM_CONT]) &&
Expand Down Expand Up @@ -1006,7 +1006,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
err = mmc_select_hs200(card);
else if (host->caps & MMC_CAP_MMC_HIGHSPEED)
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, 1, 0);
EXT_CSD_HS_TIMING, 1,
card->ext_csd.generic_cmd6_time);

if (err && err != -EBADMSG)
goto free_card;
Expand Down Expand Up @@ -1116,7 +1117,7 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
* Activate wide bus and DDR (if supported).
*/
if (!mmc_card_hs200(card) &&
(card->csd.mmca_vsn >= CSD_SPEC_VER_3) &&
(card->csd.mmca_vsn >= CSD_SPEC_VER_4) &&
(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA))) {
static unsigned ext_csd_bits[][2] = {
{ EXT_CSD_BUS_WIDTH_8, EXT_CSD_DDR_BUS_WIDTH_8 },
Expand Down Expand Up @@ -1315,11 +1316,13 @@ static int mmc_suspend(struct mmc_host *host)
BUG_ON(!host->card);

mmc_claim_host(host);
if (mmc_card_can_sleep(host))
if (mmc_card_can_sleep(host)) {
err = mmc_card_sleep(host);
else if (!mmc_host_is_spi(host))
if (!err)
mmc_card_set_sleep(host->card);
} else if (!mmc_host_is_spi(host))
mmc_deselect_cards(host);
host->card->state &= ~MMC_STATE_HIGHSPEED;
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_release_host(host);

return err;
Expand All @@ -1339,7 +1342,11 @@ static int mmc_resume(struct mmc_host *host)
BUG_ON(!host->card);

mmc_claim_host(host);
err = mmc_init_card(host, host->ocr, host->card);
if (mmc_card_is_sleep(host->card)) {
err = mmc_card_awake(host);
mmc_card_clr_sleep(host->card);
} else
err = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);

return err;
Expand All @@ -1349,7 +1356,8 @@ static int mmc_power_restore(struct mmc_host *host)
{
int ret;

host->card->state &= ~MMC_STATE_HIGHSPEED;
host->card->state &= ~(MMC_STATE_HIGHSPEED | MMC_STATE_HIGHSPEED_200);
mmc_card_clr_sleep(host->card);
mmc_claim_host(host);
ret = mmc_init_card(host, host->ocr, host->card);
mmc_release_host(host);
Expand Down
22 changes: 18 additions & 4 deletions drivers/mmc/core/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -451,9 +451,11 @@ static int sd_select_driver_type(struct mmc_card *card, u8 *status)
* information and let the hardware specific code
* return what is possible given the options
*/
mmc_host_clk_hold(card->host);
drive_strength = card->host->ops->select_drive_strength(
card->sw_caps.uhs_max_dtr,
host_drv_type, card_drv_type);
mmc_host_clk_release(card->host);

err = mmc_sd_switch(card, 1, 2, drive_strength, status);
if (err)
Expand Down Expand Up @@ -660,9 +662,12 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
goto out;

/* SPI mode doesn't define CMD19 */
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning)
if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning) {
mmc_host_clk_hold(card->host);
err = card->host->ops->execute_tuning(card->host,
MMC_SEND_TUNING_BLOCK);
mmc_host_clk_release(card->host);
}

out:
kfree(status);
Expand Down Expand Up @@ -850,8 +855,11 @@ int mmc_sd_setup_card(struct mmc_host *host, struct mmc_card *card,
if (!reinit) {
int ro = -1;

if (host->ops->get_ro)
if (host->ops->get_ro) {
mmc_host_clk_hold(card->host);
ro = host->ops->get_ro(host);
mmc_host_clk_release(card->host);
}

if (ro < 0) {
pr_warning("%s: host does not "
Expand Down Expand Up @@ -967,8 +975,11 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
* Since initialization is now complete, enable preset
* value registers for UHS-I cards.
*/
if (host->ops->enable_preset_value)
if (host->ops->enable_preset_value) {
mmc_host_clk_hold(card->host);
host->ops->enable_preset_value(host, true);
mmc_host_clk_release(card->host);
}
} else {
/*
* Attempt to change to high-speed (if supported)
Expand Down Expand Up @@ -1151,8 +1162,11 @@ int mmc_attach_sd(struct mmc_host *host)
return err;

/* Disable preset value enable if already set since last time */
if (host->ops->enable_preset_value)
if (host->ops->enable_preset_value) {
mmc_host_clk_hold(host);
host->ops->enable_preset_value(host, false);
mmc_host_clk_release(host);
}

err = mmc_send_app_op_cond(host, 0, &ocr);
if (err)
Expand Down
7 changes: 4 additions & 3 deletions drivers/mmc/core/sdio.c
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,11 @@ static int sdio_init_func(struct mmc_card *card, unsigned int fn)
return ret;
}

static int sdio_read_cccr(struct mmc_card *card)
static int sdio_read_cccr(struct mmc_card *card, u32 ocr)
{
int ret;
int cccr_vsn;
int uhs = ocr & R4_18V_PRESENT;
unsigned char data;
unsigned char speed;

Expand Down Expand Up @@ -149,7 +150,7 @@ static int sdio_read_cccr(struct mmc_card *card)
card->scr.sda_spec3 = 0;
card->sw_caps.sd3_bus_mode = 0;
card->sw_caps.sd3_drv_type = 0;
if (cccr_vsn >= SDIO_CCCR_REV_3_00) {
if (cccr_vsn >= SDIO_CCCR_REV_3_00 && uhs) {
card->scr.sda_spec3 = 1;
ret = mmc_io_rw_direct(card, 0, 0,
SDIO_CCCR_UHS, 0, &data);
Expand Down Expand Up @@ -712,7 +713,7 @@ static int mmc_sdio_init_card(struct mmc_host *host, u32 ocr,
/*
* Read the common registers.
*/
err = sdio_read_cccr(card);
err = sdio_read_cccr(card, ocr);
if (err)
goto remove;

Expand Down
10 changes: 8 additions & 2 deletions drivers/mmc/core/sdio_irq.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,15 +146,21 @@ static int sdio_irq_thread(void *_host)
}

set_current_state(TASK_INTERRUPTIBLE);
if (host->caps & MMC_CAP_SDIO_IRQ)
if (host->caps & MMC_CAP_SDIO_IRQ) {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 1);
mmc_host_clk_release(host);
}
if (!kthread_should_stop())
schedule_timeout(period);
set_current_state(TASK_RUNNING);
} while (!kthread_should_stop());

if (host->caps & MMC_CAP_SDIO_IRQ)
if (host->caps & MMC_CAP_SDIO_IRQ) {
mmc_host_clk_hold(host);
host->ops->enable_sdio_irq(host, 0);
mmc_host_clk_release(host);
}

pr_debug("%s: IRQ thread exiting with code %d\n",
mmc_hostname(host), ret);
Expand Down
3 changes: 3 additions & 0 deletions drivers/mmc/host/atmel-mci.c
Original file line number Diff line number Diff line change
Expand Up @@ -969,11 +969,14 @@ static void atmci_start_request(struct atmel_mci *host,
host->data_status = 0;

if (host->need_reset) {
iflags = atmci_readl(host, ATMCI_IMR);
iflags &= (ATMCI_SDIOIRQA | ATMCI_SDIOIRQB);
atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
atmci_writel(host, ATMCI_MR, host->mode_reg);
if (host->caps.has_cfg_reg)
atmci_writel(host, ATMCI_CFG, host->cfg_reg);
atmci_writel(host, ATMCI_IER, iflags);
host->need_reset = false;
}
atmci_writel(host, ATMCI_SDCR, slot->sdc_reg);
Expand Down
Loading

0 comments on commit 8b36ac5

Please sign in to comment.