Merge tag 'mmc-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc

Pull MMC and MEMSTICK updates from Ulf Hansson:
 "MMC core:
   - Fix hanging on I/O during system suspend for removable cards
   - Set read only for SD cards with permanent write protect bit
   - Power cycle the SD/SDIO card if CMD11 fails for UHS voltage
   - Issue a cache flush for eMMC only when it's enabled
   - Adopt to updated cache ctrl settings for eMMC from MMC ioctls
   - Use use device property API when parsing voltages
   - Don't retry eMMC sanitize cmds
   - Use the timeout from the MMC ioctl for eMMC santize cmds

  MMC host:
   - mmc_spi: Make of_mmc_spi.c resource provider agnostic
   - mmc_spi: Use polling for card detect even without voltage-ranges
   - sdhci: Check for reset prior to DMA address unmap
   - sdhci-acpi: Add support for the AMDI0041 eMMC controller variant
   - sdhci-esdhc-imx: Depending on OF Kconfig and cleanup code
   - sdhci-pci: Add PCI IDs for Intel LKF
   - sdhci-pci: Fix initialization of some SD cards for Intel BYT
   - sdhci-pci-gli: Various improvements for GL97xx variants
   - sdhci-of-dwcmshc: Enable support for MMC_CAP_WAIT_WHILE_BUSY
   - sdhci-of-dwcmshc: Add ACPI support for BlueField-3 SoC
   - sdhci-of-dwcmshc: Add Rockchip platform support
   - tmio/renesas_sdhi: Extend support for reset and use a reset controller
   - tmio/renesas_sdhi: Enable support for MMC_CAP_WAIT_WHILE_BUSY
   - tmio/renesas_sdhi: Various improvements

  MEMSTICK:
   - Minor improvements/cleanups"

* tag 'mmc-v5.13' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (79 commits)
  mmc: block: Issue a cache flush only when it's enabled
  memstick: r592: ignore kfifo_out() return code again
  mmc: block: Update ext_csd.cache_ctrl if it was written
  mmc: mmc_spi: Make of_mmc_spi.c resource provider agnostic
  mmc: mmc_spi: Use already parsed IRQ
  mmc: mmc_spi: Drop unused NO_IRQ definition
  mmc: mmc_spi: Set up polling even if voltage-ranges is not present
  mmc: core: Convert mmc_of_parse_voltage() to use device property API
  mmc: core: Correct descriptions in mmc_of_parse()
  mmc: dw_mmc-rockchip: Just set default sample value for legacy mode
  mmc: sdhci-s3c: constify uses of driver/match data
  mmc: sdhci-s3c: correct kerneldoc of sdhci_s3c_drv_data
  mmc: sdhci-s3c: simplify getting of_device_id match data
  mmc: tmio: always restore irq register
  mmc: sdhci-pci-gli: Enlarge ASPM L1 entry delay of GL975x
  mmc: core: Let eMMC sanitize not retry in case of timeout/failure
  mmc: core: Add a retries parameter to __mmc_switch function
  memstick: r592: remove unused variable
  mmc: sdhci-st: Remove unnecessary error log
  mmc: sdhci-msm: Remove unnecessary error log
  ...
This commit is contained in:
Linus Torvalds
2021-04-28 15:56:51 -07:00
59 changed files with 1010 additions and 642 deletions

View File

@@ -0,0 +1,63 @@
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/brcm,iproc-sdhci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Broadcom IPROC SDHCI controller
maintainers:
- Ray Jui <ray.jui@broadcom.com>
- Scott Branden <scott.branden@broadcom.com>
- Nicolas Saenz Julienne <nsaenz@kernel.org>
allOf:
- $ref: mmc-controller.yaml#
properties:
compatible:
enum:
- brcm,bcm2835-sdhci
- brcm,bcm2711-emmc2
- brcm,sdhci-iproc-cygnus
- brcm,sdhci-iproc
reg:
minItems: 1
interrupts:
maxItems: 1
clocks:
maxItems: 1
description:
Handle to core clock for the sdhci controller.
sdhci,auto-cmd12:
type: boolean
description: Specifies that controller should use auto CMD12
required:
- compatible
- reg
- interrupts
- clocks
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/clock/bcm-cygnus.h>
mmc@18041000 {
compatible = "brcm,sdhci-iproc-cygnus";
reg = <0x18041000 0x100>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>;
bus-width = <4>;
sdhci,auto-cmd12;
no-1-8-v;
};
...

View File

@@ -1,37 +0,0 @@
Broadcom IPROC SDHCI controller
This file documents differences between the core properties described
by mmc.txt and the properties that represent the IPROC SDHCI controller.
Required properties:
- compatible : Should be one of the following
"brcm,bcm2835-sdhci"
"brcm,bcm2711-emmc2"
"brcm,sdhci-iproc-cygnus"
"brcm,sdhci-iproc"
Use brcm2835-sdhci for the eMMC controller on the BCM2835 (Raspberry Pi) and
bcm2711-emmc2 for the additional eMMC2 controller on BCM2711.
Use sdhci-iproc-cygnus for Broadcom SDHCI Controllers
restricted to 32bit host accesses to SDHCI registers.
Use sdhci-iproc for Broadcom SDHCI Controllers that allow standard
8, 16, 32-bit host access to SDHCI register.
- clocks : The clock feeding the SDHCI controller.
Optional properties:
- sdhci,auto-cmd12: specifies that controller should use auto CMD12.
Example:
sdhci0: sdhci@18041000 {
compatible = "brcm,sdhci-iproc-cygnus";
reg = <0x18041000 0x100>;
interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&lcpll0_clks BCM_CYGNUS_LCPLL0_SDIO_CLK>;
bus-width = <4>;
sdhci,auto-cmd12;
no-1-8-v;
};

View File

@@ -103,6 +103,26 @@ properties:
Only eMMC HS400 mode need to take care of this property.
default: 0
clocks:
maxItems: 3
description:
Handle clocks for the sdhc controller.
clock-names:
items:
- const: ipg
- const: ahb
- const: per
pinctrl-names:
minItems: 1
maxItems: 4
items:
- const: default
- const: state_100mhz
- const: state_200mhz
- const: sleep
required:
- compatible
- reg

View File

@@ -5,11 +5,11 @@ by mmc.txt and the properties used by the mmc_spi driver.
Required properties:
- spi-max-frequency : maximum frequency for this device (Hz).
- voltage-ranges : two cells are required, first cell specifies minimum
slot voltage (mV), second cell specifies maximum slot voltage (mV).
Several ranges could be specified.
Optional properties:
- voltage-ranges : two cells are required, first cell specifies minimum
slot voltage (mV), second cell specifies maximum slot voltage (mV).
Several ranges could be specified. If not provided, 3.2v..3.4v is assumed.
- gpios : may specify GPIOs in this order: Card-Detect GPIO,
Write-Protect GPIO. Note that this does not follow the
binding from mmc.txt, for historical reasons.

View File

@@ -31,6 +31,7 @@ properties:
- const: mediatek,mt2701-mmc
- items:
- const: mediatek,mt8192-mmc
- const: mediatek,mt8195-mmc
- const: mediatek,mt8183-mmc
clocks:

View File

@@ -1,20 +0,0 @@
* Synopsys DesignWare Cores Mobile Storage Host Controller
Required properties:
- compatible: should be one of the following:
"snps,dwcmshc-sdhci"
- reg: offset and length of the register set for the device.
- interrupts: a single interrupt specifier.
- clocks: Array of clocks required for SDHCI; requires at least one for
core clock.
- clock-names: Array of names corresponding to clocks property; shall be
"core" for core clock and "bus" for optional bus clock.
Example:
sdhci2: sdhci@aa0000 {
compatible = "snps,dwcmshc-sdhci";
reg = <0xaa0000 0x1000>;
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&emmcclk>;
bus-width = <8>;
}

View File

@@ -0,0 +1,87 @@
# SPDX-License-Identifier: GPL-2.0-only
%YAML 1.2
---
$id: http://devicetree.org/schemas/mmc/snps,dwcmshc-sdhci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Synopsys Designware Mobile Storage Host Controller Binding
maintainers:
- Ulf Hansson <ulf.hansson@linaro.org>
- Jisheng Zhang <Jisheng.Zhang@synaptics.com>
allOf:
- $ref: mmc-controller.yaml#
properties:
compatible:
enum:
- rockchip,rk3568-dwcmshc
- snps,dwcmshc-sdhci
reg:
minItems: 1
items:
- description: Offset and length of the register set for the device
interrupts:
maxItems: 1
clocks:
minItems: 1
items:
- description: core clock
- description: bus clock for optional
- description: axi clock for rockchip specified
- description: block clock for rockchip specified
- description: timer clock for rockchip specified
clock-names:
minItems: 1
items:
- const: core
- const: bus
- const: axi
- const: block
- const: timer
rockchip,txclk-tapnum:
description: Specify the number of delay for tx sampling.
$ref: /schemas/types.yaml#/definitions/uint8
required:
- compatible
- reg
- interrupts
- clocks
- clock-names
unevaluatedProperties: false
examples:
- |
mmc@fe310000 {
compatible = "rockchip,rk3568-dwcmshc";
reg = <0xfe310000 0x10000>;
interrupts = <0 25 0x4>;
clocks = <&cru 17>, <&cru 18>, <&cru 19>, <&cru 20>, <&cru 21>;
clock-names = "core", "bus", "axi", "block", "timer";
bus-width = <8>;
#address-cells = <1>;
#size-cells = <0>;
};
- |
mmc@aa0000 {
compatible = "snps,dwcmshc-sdhci";
reg = <0xaa000 0x1000>;
interrupts = <0 25 0x4>;
clocks = <&cru 17>, <&cru 18>;
clock-names = "core", "bus";
bus-width = <8>;
#address-cells = <1>;
#size-cells = <0>;
};
...

View File

@@ -331,18 +331,17 @@ static int h_memstick_read_dev_id(struct memstick_dev *card,
sizeof(struct ms_id_register));
*mrq = &card->current_mrq;
return 0;
} else {
if (!(*mrq)->error) {
memcpy(&id_reg, (*mrq)->data, sizeof(id_reg));
card->id.match_flags = MEMSTICK_MATCH_ALL;
card->id.type = id_reg.type;
card->id.category = id_reg.category;
card->id.class = id_reg.class;
dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode);
}
complete(&card->mrq_complete);
return -EAGAIN;
}
if (!(*mrq)->error) {
memcpy(&id_reg, (*mrq)->data, sizeof(id_reg));
card->id.match_flags = MEMSTICK_MATCH_ALL;
card->id.type = id_reg.type;
card->id.category = id_reg.category;
card->id.class = id_reg.class;
dev_dbg(&card->dev, "if_mode = %02x\n", id_reg.if_mode);
}
complete(&card->mrq_complete);
return -EAGAIN;
}
static int h_memstick_set_rw_addr(struct memstick_dev *card,

View File

@@ -1382,7 +1382,8 @@ static int mspro_block_resume(struct memstick_dev *card)
new_msb->card = card;
memstick_set_drvdata(card, new_msb);
if (mspro_block_init_card(card))
rc = mspro_block_init_card(card);
if (rc)
goto out_free;
for (cnt = 0; new_msb->attr_group.attrs[cnt]

View File

@@ -359,13 +359,15 @@ static void r592_write_fifo_pio(struct r592_device *dev,
/* Flushes the temporary FIFO used to make aligned DWORD writes */
static void r592_flush_fifo_write(struct r592_device *dev)
{
int ret;
u8 buffer[4] = { 0 };
int len;
if (kfifo_is_empty(&dev->pio_fifo))
return;
len = kfifo_out(&dev->pio_fifo, buffer, 4);
ret = kfifo_out(&dev->pio_fifo, buffer, 4);
/* intentionally ignore __must_check return code */
(void)ret;
r592_write_reg_raw_be(dev, R592_FIFO_PIO, *(u32 *)buffer);
}

View File

@@ -539,7 +539,7 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_SANITIZE_START) &&
(cmd.opcode == MMC_SWITCH))
return mmc_sanitize(card);
return mmc_sanitize(card, idata->ic.cmd_timeout_ms);
mmc_wait_for_req(card->host, &mrq);
@@ -572,6 +572,18 @@ static int __mmc_blk_ioctl_cmd(struct mmc_card *card, struct mmc_blk_data *md,
main_md->part_curr = value & EXT_CSD_PART_CONFIG_ACC_MASK;
}
/*
* Make sure to update CACHE_CTRL in case it was changed. The cache
* will get turned back on if the card is re-initialized, e.g.
* suspend/resume or hw reset in recovery.
*/
if ((MMC_EXTRACT_INDEX_FROM_ARG(cmd.arg) == EXT_CSD_CACHE_CTRL) &&
(cmd.opcode == MMC_SWITCH)) {
u8 value = MMC_EXTRACT_VALUE_FROM_ARG(cmd.arg) & 1;
card->ext_csd.cache_ctrl = value;
}
/*
* According to the SD specs, some commands require a delay after
* issuing the command.
@@ -947,7 +959,7 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
md->reset_done |= type;
err = mmc_hw_reset(host);
/* Ensure we switch back to the correct partition */
if (err != -EOPNOTSUPP) {
if (err) {
struct mmc_blk_data *main_md =
dev_get_drvdata(&host->card->dev);
int part_err;
@@ -1933,8 +1945,9 @@ static void mmc_blk_hsq_req_done(struct mmc_request *mrq)
void mmc_blk_mq_complete(struct request *req)
{
struct mmc_queue *mq = req->q->queuedata;
struct mmc_host *host = mq->card->host;
if (mq->use_cqe)
if (host->cqe_enabled)
mmc_blk_cqe_complete_rq(mq, req);
else if (likely(!blk_should_fake_timeout(req->q)))
mmc_blk_mq_complete_rq(mq, req);
@@ -2179,7 +2192,7 @@ out_post_req:
static int mmc_blk_wait_for_idle(struct mmc_queue *mq, struct mmc_host *host)
{
if (mq->use_cqe)
if (host->cqe_enabled)
return host->cqe_ops->cqe_wait_for_idle(host);
return mmc_blk_rw_wait(mq, NULL);
@@ -2224,11 +2237,15 @@ enum mmc_issued mmc_blk_mq_issue_rq(struct mmc_queue *mq, struct request *req)
case MMC_ISSUE_ASYNC:
switch (req_op(req)) {
case REQ_OP_FLUSH:
if (!mmc_cache_enabled(host)) {
blk_mq_end_request(req, BLK_STS_OK);
return MMC_REQ_FINISHED;
}
ret = mmc_blk_cqe_issue_flush(mq, req);
break;
case REQ_OP_READ:
case REQ_OP_WRITE:
if (mq->use_cqe)
if (host->cqe_enabled)
ret = mmc_blk_cqe_issue_rw_rq(mq, req);
else
ret = mmc_blk_mq_issue_rw_rq(mq, req);
@@ -2261,6 +2278,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
{
struct mmc_blk_data *md;
int devidx, ret;
char cap_str[10];
devidx = ida_simple_get(&mmc_blk_ida, 0, max_devices, GFP_KERNEL);
if (devidx < 0) {
@@ -2365,6 +2383,12 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
blk_queue_write_cache(md->queue.queue, true, true);
}
string_get_size((u64)size, 512, STRING_UNITS_2,
cap_str, sizeof(cap_str));
pr_info("%s: %s %s %s %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
cap_str, md->read_only ? "(ro)" : "");
return md;
err_putdisk:
@@ -2407,7 +2431,6 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
const char *subname,
int area_type)
{
char cap_str[10];
struct mmc_blk_data *part_md;
part_md = mmc_blk_alloc_req(card, disk_to_dev(md->disk), size, default_ro,
@@ -2417,11 +2440,6 @@ static int mmc_blk_alloc_part(struct mmc_card *card,
part_md->part_type = part_type;
list_add(&part_md->part, &md->part);
string_get_size((u64)get_capacity(part_md->disk), 512, STRING_UNITS_2,
cap_str, sizeof(cap_str));
pr_info("%s: %s %s partition %u %s\n",
part_md->disk->disk_name, mmc_card_id(card),
mmc_card_name(card), part_md->part_type, cap_str);
return 0;
}
@@ -2558,9 +2576,8 @@ static int mmc_blk_alloc_rpmb_part(struct mmc_card *card,
string_get_size((u64)size, 512, STRING_UNITS_2,
cap_str, sizeof(cap_str));
pr_info("%s: %s %s partition %u %s, chardev (%d:%d)\n",
rpmb_name, mmc_card_id(card),
mmc_card_name(card), EXT_CSD_PART_CONFIG_ACC_RPMB, cap_str,
pr_info("%s: %s %s %s, chardev (%d:%d)\n",
rpmb_name, mmc_card_id(card), mmc_card_name(card), cap_str,
MAJOR(mmc_rpmb_devt), rpmb->id);
return 0;
@@ -2876,7 +2893,7 @@ static void mmc_blk_remove_debugfs(struct mmc_card *card,
static int mmc_blk_probe(struct mmc_card *card)
{
struct mmc_blk_data *md, *part_md;
char cap_str[10];
int ret = 0;
/*
* Check that the card supports the command class(es) we need.
@@ -2888,31 +2905,30 @@ static int mmc_blk_probe(struct mmc_card *card)
card->complete_wq = alloc_workqueue("mmc_complete",
WQ_MEM_RECLAIM | WQ_HIGHPRI, 0);
if (unlikely(!card->complete_wq)) {
if (!card->complete_wq) {
pr_err("Failed to create mmc completion workqueue");
return -ENOMEM;
}
md = mmc_blk_alloc(card);
if (IS_ERR(md))
return PTR_ERR(md);
if (IS_ERR(md)) {
ret = PTR_ERR(md);
goto out_free;
}
string_get_size((u64)get_capacity(md->disk), 512, STRING_UNITS_2,
cap_str, sizeof(cap_str));
pr_info("%s: %s %s %s %s\n",
md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
cap_str, md->read_only ? "(ro)" : "");
if (mmc_blk_alloc_parts(card, md))
ret = mmc_blk_alloc_parts(card, md);
if (ret)
goto out;
dev_set_drvdata(&card->dev, md);
if (mmc_add_disk(md))
ret = mmc_add_disk(md);
if (ret)
goto out;
list_for_each_entry(part_md, &md->part, part) {
if (mmc_add_disk(part_md))
ret = mmc_add_disk(part_md);
if (ret)
goto out;
}
@@ -2933,10 +2949,12 @@ static int mmc_blk_probe(struct mmc_card *card)
return 0;
out:
out:
mmc_blk_remove_parts(card, md);
mmc_blk_remove_req(md);
return 0;
out_free:
destroy_workqueue(card->complete_wq);
return ret;
}
static void mmc_blk_remove(struct mmc_card *card)

View File

@@ -1207,7 +1207,7 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
return err;
goto power_cycle;
if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
return -EIO;
@@ -1377,63 +1377,13 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr)
mmc_power_up(host, ocr);
}
/*
* Cleanup when the last reference to the bus operator is dropped.
*/
static void __mmc_release_bus(struct mmc_host *host)
{
WARN_ON(!host->bus_dead);
host->bus_ops = NULL;
}
/*
* Increase reference count of bus operator
*/
static inline void mmc_bus_get(struct mmc_host *host)
{
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
host->bus_refs++;
spin_unlock_irqrestore(&host->lock, flags);
}
/*
* Decrease reference count of bus operator and free it if
* it is the last reference.
*/
static inline void mmc_bus_put(struct mmc_host *host)
{
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
host->bus_refs--;
if ((host->bus_refs == 0) && host->bus_ops)
__mmc_release_bus(host);
spin_unlock_irqrestore(&host->lock, flags);
}
/*
* Assign a mmc bus handler to a host. Only one bus handler may control a
* host at any given time.
*/
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
unsigned long flags;
WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->bus_ops);
WARN_ON(host->bus_refs);
host->bus_ops = ops;
host->bus_refs = 1;
host->bus_dead = 0;
spin_unlock_irqrestore(&host->lock, flags);
}
/*
@@ -1441,18 +1391,7 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
*/
void mmc_detach_bus(struct mmc_host *host)
{
unsigned long flags;
WARN_ON(!host->claimed);
WARN_ON(!host->bus_ops);
spin_lock_irqsave(&host->lock, flags);
host->bus_dead = 1;
spin_unlock_irqrestore(&host->lock, flags);
mmc_bus_put(host);
host->bus_ops = NULL;
}
void _mmc_detect_change(struct mmc_host *host, unsigned long delay, bool cd_irq)
@@ -2080,18 +2019,7 @@ int mmc_hw_reset(struct mmc_host *host)
{
int ret;
if (!host->card)
return -EINVAL;
mmc_bus_get(host);
if (!host->bus_ops || host->bus_dead || !host->bus_ops->hw_reset) {
mmc_bus_put(host);
return -EOPNOTSUPP;
}
ret = host->bus_ops->hw_reset(host);
mmc_bus_put(host);
if (ret < 0)
pr_warn("%s: tried to HW reset card, got error %d\n",
mmc_hostname(host), ret);
@@ -2104,18 +2032,10 @@ int mmc_sw_reset(struct mmc_host *host)
{
int ret;
if (!host->card)
return -EINVAL;
mmc_bus_get(host);
if (!host->bus_ops || host->bus_dead || !host->bus_ops->sw_reset) {
mmc_bus_put(host);
if (!host->bus_ops->sw_reset)
return -EOPNOTSUPP;
}
ret = host->bus_ops->sw_reset(host);
mmc_bus_put(host);
if (ret)
pr_warn("%s: tried to SW reset card, got error %d\n",
mmc_hostname(host), ret);
@@ -2263,32 +2183,15 @@ void mmc_rescan(struct work_struct *work)
host->trigger_card_event = false;
}
mmc_bus_get(host);
/* Verify a registered card to be functional, else remove it. */
if (host->bus_ops && !host->bus_dead)
if (host->bus_ops)
host->bus_ops->detect(host);
host->detect_change = 0;
/*
* Let mmc_bus_put() free the bus/bus_ops if we've found that
* the card is no longer present.
*/
mmc_bus_put(host);
mmc_bus_get(host);
/* if there still is a card present, stop here */
if (host->bus_ops != NULL) {
mmc_bus_put(host);
if (host->bus_ops != NULL)
goto out;
}
/*
* Only we can add a new handler, so it's safe to
* release the lock here.
*/
mmc_bus_put(host);
mmc_claim_host(host);
if (mmc_card_is_removable(host) && host->ops->get_cd &&
@@ -2351,98 +2254,21 @@ void mmc_stop_host(struct mmc_host *host)
/* clear pm flags now and let card drivers set them as needed */
host->pm_flags = 0;
mmc_bus_get(host);
if (host->bus_ops && !host->bus_dead) {
if (host->bus_ops) {
/* Calling bus_ops->remove() with a claimed host can deadlock */
host->bus_ops->remove(host);
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
mmc_release_host(host);
mmc_bus_put(host);
return;
}
mmc_bus_put(host);
mmc_claim_host(host);
mmc_power_off(host);
mmc_release_host(host);
}
#ifdef CONFIG_PM_SLEEP
/* Do the card removal on suspend if card is assumed removeable
* Do that in pm notifier while userspace isn't yet frozen, so we will be able
to sync the card.
*/
static int mmc_pm_notify(struct notifier_block *notify_block,
unsigned long mode, void *unused)
{
struct mmc_host *host = container_of(
notify_block, struct mmc_host, pm_notify);
unsigned long flags;
int err = 0;
switch (mode) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
case PM_RESTORE_PREPARE:
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 1;
spin_unlock_irqrestore(&host->lock, flags);
cancel_delayed_work_sync(&host->detect);
if (!host->bus_ops)
break;
/* Validate prerequisites for suspend */
if (host->bus_ops->pre_suspend)
err = host->bus_ops->pre_suspend(host);
if (!err)
break;
if (!mmc_card_is_removable(host)) {
dev_warn(mmc_dev(host),
"pre_suspend failed for non-removable host: "
"%d\n", err);
/* Avoid removing non-removable hosts */
break;
}
/* Calling bus_ops->remove() with a claimed host can deadlock */
host->bus_ops->remove(host);
mmc_claim_host(host);
mmc_detach_bus(host);
mmc_power_off(host);
mmc_release_host(host);
host->pm_flags = 0;
break;
case PM_POST_SUSPEND:
case PM_POST_HIBERNATION:
case PM_POST_RESTORE:
spin_lock_irqsave(&host->lock, flags);
host->rescan_disable = 0;
spin_unlock_irqrestore(&host->lock, flags);
_mmc_detect_change(host, 0, false);
}
return 0;
}
void mmc_register_pm_notifier(struct mmc_host *host)
{
host->pm_notify.notifier_call = mmc_pm_notify;
register_pm_notifier(&host->pm_notify);
}
void mmc_unregister_pm_notifier(struct mmc_host *host)
{
unregister_pm_notifier(&host->pm_notify);
}
#endif
static int __init mmc_init(void)
{
int ret;

View File

@@ -29,6 +29,7 @@ struct mmc_bus_ops {
int (*shutdown)(struct mmc_host *);
int (*hw_reset)(struct mmc_host *);
int (*sw_reset)(struct mmc_host *);
bool (*cache_enabled)(struct mmc_host *);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
@@ -93,14 +94,6 @@ int mmc_execute_tuning(struct mmc_card *card);
int mmc_hs200_to_hs400(struct mmc_card *card);
int mmc_hs400_to_hs200(struct mmc_card *card);
#ifdef CONFIG_PM_SLEEP
void mmc_register_pm_notifier(struct mmc_host *host);
void mmc_unregister_pm_notifier(struct mmc_host *host);
#else
static inline void mmc_register_pm_notifier(struct mmc_host *host) { }
static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
#endif
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq);
bool mmc_is_req_done(struct mmc_host *host, struct mmc_request *mrq);
@@ -171,4 +164,12 @@ static inline void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
host->ops->post_req(host, mrq, err);
}
static inline bool mmc_cache_enabled(struct mmc_host *host)
{
if (host->bus_ops->cache_enabled)
return host->bus_ops->cache_enabled(host);
return false;
}
#endif

View File

@@ -35,6 +35,42 @@
static DEFINE_IDA(mmc_host_ida);
#ifdef CONFIG_PM_SLEEP
static int mmc_host_class_prepare(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
/*
* It's safe to access the bus_ops pointer, as both userspace and the
* workqueue for detecting cards are frozen at this point.
*/
if (!host->bus_ops)
return 0;
/* Validate conditions for system suspend. */
if (host->bus_ops->pre_suspend)
return host->bus_ops->pre_suspend(host);
return 0;
}
static void mmc_host_class_complete(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
_mmc_detect_change(host, 0, false);
}
static const struct dev_pm_ops mmc_host_class_dev_pm_ops = {
.prepare = mmc_host_class_prepare,
.complete = mmc_host_class_complete,
};
#define MMC_HOST_CLASS_DEV_PM_OPS (&mmc_host_class_dev_pm_ops)
#else
#define MMC_HOST_CLASS_DEV_PM_OPS NULL
#endif
static void mmc_host_classdev_release(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
@@ -46,6 +82,7 @@ static void mmc_host_classdev_release(struct device *dev)
static struct class mmc_host_class = {
.name = "mmc_host",
.dev_release = mmc_host_classdev_release,
.pm = MMC_HOST_CLASS_DEV_PM_OPS,
};
int mmc_register_host_class(void)
@@ -209,8 +246,8 @@ mmc_of_parse_clk_phase(struct mmc_host *host, struct mmc_clk_phase_map *map)
EXPORT_SYMBOL(mmc_of_parse_clk_phase);
/**
* mmc_of_parse() - parse host's device-tree node
* @host: host whose node should be parsed.
* mmc_of_parse() - parse host's device properties
* @host: host whose properties should be parsed.
*
* To keep the rest of the MMC subsystem unaware of whether DT has been
* used to to instantiate and configure this host instance or not, we
@@ -379,44 +416,62 @@ EXPORT_SYMBOL(mmc_of_parse);
/**
* mmc_of_parse_voltage - return mask of supported voltages
* @np: The device node need to be parsed.
* @host: host whose properties should be parsed.
* @mask: mask of voltages available for MMC/SD/SDIO
*
* Parse the "voltage-ranges" DT property, returning zero if it is not
* Parse the "voltage-ranges" property, returning zero if it is not
* found, negative errno if the voltage-range specification is invalid,
* or one if the voltage-range is specified and successfully parsed.
*/
int mmc_of_parse_voltage(struct device_node *np, u32 *mask)
int mmc_of_parse_voltage(struct mmc_host *host, u32 *mask)
{
const u32 *voltage_ranges;
const char *prop = "voltage-ranges";
struct device *dev = host->parent;
u32 *voltage_ranges;
int num_ranges, i;
int ret;
voltage_ranges = of_get_property(np, "voltage-ranges", &num_ranges);
if (!voltage_ranges) {
pr_debug("%pOF: voltage-ranges unspecified\n", np);
if (!device_property_present(dev, prop)) {
dev_dbg(dev, "%s unspecified\n", prop);
return 0;
}
num_ranges = num_ranges / sizeof(*voltage_ranges) / 2;
ret = device_property_count_u32(dev, prop);
if (ret < 0)
return ret;
num_ranges = ret / 2;
if (!num_ranges) {
pr_err("%pOF: voltage-ranges empty\n", np);
dev_err(dev, "%s empty\n", prop);
return -EINVAL;
}
voltage_ranges = kcalloc(2 * num_ranges, sizeof(*voltage_ranges), GFP_KERNEL);
if (!voltage_ranges)
return -ENOMEM;
ret = device_property_read_u32_array(dev, prop, voltage_ranges, 2 * num_ranges);
if (ret) {
kfree(voltage_ranges);
return ret;
}
for (i = 0; i < num_ranges; i++) {
const int j = i * 2;
u32 ocr_mask;
ocr_mask = mmc_vddrange_to_ocrmask(
be32_to_cpu(voltage_ranges[j]),
be32_to_cpu(voltage_ranges[j + 1]));
ocr_mask = mmc_vddrange_to_ocrmask(voltage_ranges[j + 0],
voltage_ranges[j + 1]);
if (!ocr_mask) {
pr_err("%pOF: voltage-range #%d is invalid\n",
np, i);
dev_err(dev, "range #%d in %s is invalid\n", i, prop);
kfree(voltage_ranges);
return -EINVAL;
}
*mask |= ocr_mask;
}
kfree(voltage_ranges);
return 1;
}
EXPORT_SYMBOL(mmc_of_parse_voltage);
@@ -538,8 +593,6 @@ int mmc_add_host(struct mmc_host *host)
#endif
mmc_start_host(host);
mmc_register_pm_notifier(host);
return 0;
}
@@ -555,7 +608,6 @@ EXPORT_SYMBOL(mmc_add_host);
*/
void mmc_remove_host(struct mmc_host *host)
{
mmc_unregister_pm_notifier(host);
mmc_stop_host(host);
#ifdef CONFIG_DEBUG_FS

View File

@@ -1068,7 +1068,7 @@ static int mmc_select_hs(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time, MMC_TIMING_MMC_HS,
true, true);
true, true, MMC_CMD_RETRIES);
if (err)
pr_warn("%s: switch to high-speed failed, err:%d\n",
mmc_hostname(card->host), err);
@@ -1100,7 +1100,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
ext_csd_bits,
card->ext_csd.generic_cmd6_time,
MMC_TIMING_MMC_DDR52,
true, true);
true, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to bus width %d ddr failed\n",
mmc_hostname(host), 1 << bus_width);
@@ -1168,7 +1168,7 @@ static int mmc_select_hs400(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, 0,
false, true);
false, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
mmc_hostname(host), err);
@@ -1210,7 +1210,7 @@ static int mmc_select_hs400(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, 0,
false, true);
false, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to hs400 failed, err:%d\n",
mmc_hostname(host), err);
@@ -1256,7 +1256,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
val = EXT_CSD_TIMING_HS;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
val, card->ext_csd.generic_cmd6_time, 0,
false, true);
false, true, MMC_CMD_RETRIES);
if (err)
goto out_err;
@@ -1272,7 +1272,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
/* Switch HS DDR to HS */
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
0, false, true);
0, false, true, MMC_CMD_RETRIES);
if (err)
goto out_err;
@@ -1287,7 +1287,7 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
val, card->ext_csd.generic_cmd6_time, 0,
false, true);
false, true, MMC_CMD_RETRIES);
if (err)
goto out_err;
@@ -1371,7 +1371,7 @@ static int mmc_select_hs400es(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
card->ext_csd.generic_cmd6_time, 0,
false, true);
false, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to hs for hs400es failed, err:%d\n",
mmc_hostname(host), err);
@@ -1405,7 +1405,7 @@ static int mmc_select_hs400es(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, 0,
false, true);
false, true, MMC_CMD_RETRIES);
if (err) {
pr_err("%s: switch to hs400es failed, err:%d\n",
mmc_hostname(host), err);
@@ -1470,7 +1470,7 @@ static int mmc_select_hs200(struct mmc_card *card)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_HS_TIMING, val,
card->ext_csd.generic_cmd6_time, 0,
false, true);
false, true, MMC_CMD_RETRIES);
if (err)
goto err;
old_timing = host->ios.timing;
@@ -1975,7 +1975,7 @@ static int mmc_poweroff_notify(struct mmc_card *card, unsigned int notify_type)
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_POWER_OFF_NOTIFICATION,
notify_type, timeout, 0, false, false);
notify_type, timeout, 0, false, false, MMC_CMD_RETRIES);
if (err)
pr_err("%s: Power Off Notification timed out, %u\n",
mmc_hostname(card->host), timeout);
@@ -2029,6 +2029,12 @@ static void mmc_detect(struct mmc_host *host)
}
}
static bool _mmc_cache_enabled(struct mmc_host *host)
{
return host->card->ext_csd.cache_size > 0 &&
host->card->ext_csd.cache_ctrl & 1;
}
static int _mmc_suspend(struct mmc_host *host, bool is_suspend)
{
int err = 0;
@@ -2208,6 +2214,7 @@ static const struct mmc_bus_ops mmc_ops = {
.alive = mmc_alive,
.shutdown = mmc_shutdown,
.hw_reset = _mmc_hw_reset,
.cache_enabled = _mmc_cache_enabled,
};
/*

View File

@@ -296,61 +296,40 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
return 0;
}
static int mmc_spi_send_csd(struct mmc_host *host, u32 *csd)
static int mmc_spi_send_cxd(struct mmc_host *host, u32 *cxd, u32 opcode)
{
int ret, i;
__be32 *csd_tmp;
__be32 *cxd_tmp;
csd_tmp = kzalloc(16, GFP_KERNEL);
if (!csd_tmp)
cxd_tmp = kzalloc(16, GFP_KERNEL);
if (!cxd_tmp)
return -ENOMEM;
ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CSD, csd_tmp, 16);
ret = mmc_send_cxd_data(NULL, host, opcode, cxd_tmp, 16);
if (ret)
goto err;
for (i = 0; i < 4; i++)
csd[i] = be32_to_cpu(csd_tmp[i]);
cxd[i] = be32_to_cpu(cxd_tmp[i]);
err:
kfree(csd_tmp);
kfree(cxd_tmp);
return ret;
}
int mmc_send_csd(struct mmc_card *card, u32 *csd)
{
if (mmc_host_is_spi(card->host))
return mmc_spi_send_csd(card->host, csd);
return mmc_spi_send_cxd(card->host, csd, MMC_SEND_CSD);
return mmc_send_cxd_native(card->host, card->rca << 16, csd,
MMC_SEND_CSD);
}
static int mmc_spi_send_cid(struct mmc_host *host, u32 *cid)
{
int ret, i;
__be32 *cid_tmp;
cid_tmp = kzalloc(16, GFP_KERNEL);
if (!cid_tmp)
return -ENOMEM;
ret = mmc_send_cxd_data(NULL, host, MMC_SEND_CID, cid_tmp, 16);
if (ret)
goto err;
for (i = 0; i < 4; i++)
cid[i] = be32_to_cpu(cid_tmp[i]);
err:
kfree(cid_tmp);
return ret;
}
int mmc_send_cid(struct mmc_host *host, u32 *cid)
{
if (mmc_host_is_spi(host))
return mmc_spi_send_cid(host, cid);
return mmc_spi_send_cxd(host, cid, MMC_SEND_CID);
return mmc_send_cxd_native(host, 0, cid, MMC_ALL_SEND_CID);
}
@@ -553,12 +532,13 @@ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
* @timing: new timing to change to
* @send_status: send status cmd to poll for busy
* @retry_crc_err: retry when CRC errors when polling with CMD13 for busy
* @retries: number of retries
*
* Modifies the EXT_CSD register for selected card.
*/
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, unsigned char timing,
bool send_status, bool retry_crc_err)
bool send_status, bool retry_crc_err, unsigned int retries)
{
struct mmc_host *host = card->host;
int err;
@@ -598,7 +578,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
cmd.flags |= MMC_RSP_SPI_R1 | MMC_RSP_R1;
}
err = mmc_wait_for_cmd(host, &cmd, MMC_CMD_RETRIES);
err = mmc_wait_for_cmd(host, &cmd, retries);
if (err)
goto out;
@@ -633,7 +613,7 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms)
{
return __mmc_switch(card, set, index, value, timeout_ms, 0,
true, false);
true, false, MMC_CMD_RETRIES);
}
EXPORT_SYMBOL_GPL(mmc_switch);
@@ -988,9 +968,7 @@ int mmc_flush_cache(struct mmc_card *card)
{
int err = 0;
if (mmc_card_mmc(card) &&
(card->ext_csd.cache_size > 0) &&
(card->ext_csd.cache_ctrl & 1)) {
if (mmc_cache_enabled(card->host)) {
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
EXT_CSD_FLUSH_CACHE, 1,
MMC_CACHE_FLUSH_TIMEOUT_MS);
@@ -1031,7 +1009,7 @@ int mmc_cmdq_disable(struct mmc_card *card)
}
EXPORT_SYMBOL_GPL(mmc_cmdq_disable);
int mmc_sanitize(struct mmc_card *card)
int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms)
{
struct mmc_host *host = card->host;
int err;
@@ -1041,12 +1019,15 @@ int mmc_sanitize(struct mmc_card *card)
return -EOPNOTSUPP;
}
if (!timeout_ms)
timeout_ms = MMC_SANITIZE_TIMEOUT_MS;
pr_debug("%s: Sanitize in progress...\n", mmc_hostname(host));
mmc_retune_hold(host);
err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_SANITIZE_START,
1, MMC_SANITIZE_TIMEOUT_MS);
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_SANITIZE_START,
1, timeout_ms, 0, true, false, 0);
if (err)
pr_err("%s: Sanitize failed err=%d\n", mmc_hostname(host), err);

View File

@@ -39,14 +39,14 @@ int mmc_poll_for_busy(struct mmc_card *card, unsigned int timeout_ms,
enum mmc_busy_cmd busy_cmd);
int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms, unsigned char timing,
bool send_status, bool retry_crc_err);
bool send_status, bool retry_crc_err, unsigned int retries);
int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
unsigned int timeout_ms);
void mmc_run_bkops(struct mmc_card *card);
int mmc_flush_cache(struct mmc_card *card);
int mmc_cmdq_enable(struct mmc_card *card);
int mmc_cmdq_disable(struct mmc_card *card);
int mmc_sanitize(struct mmc_card *card);
int mmc_sanitize(struct mmc_card *card, unsigned int timeout_ms);
#endif

View File

@@ -60,7 +60,7 @@ enum mmc_issue_type mmc_issue_type(struct mmc_queue *mq, struct request *req)
{
struct mmc_host *host = mq->card->host;
if (mq->use_cqe && !host->hsq_enabled)
if (host->cqe_enabled && !host->hsq_enabled)
return mmc_cqe_issue_type(host, req);
if (req_op(req) == REQ_OP_READ || req_op(req) == REQ_OP_WRITE)
@@ -127,7 +127,7 @@ static enum blk_eh_timer_return mmc_mq_timed_out(struct request *req,
bool ignore_tout;
spin_lock_irqsave(&mq->lock, flags);
ignore_tout = mq->recovery_needed || !mq->use_cqe || host->hsq_enabled;
ignore_tout = mq->recovery_needed || !host->cqe_enabled || host->hsq_enabled;
spin_unlock_irqrestore(&mq->lock, flags);
return ignore_tout ? BLK_EH_RESET_TIMER : mmc_cqe_timed_out(req);
@@ -144,7 +144,7 @@ static void mmc_mq_recovery_handler(struct work_struct *work)
mq->in_recovery = true;
if (mq->use_cqe && !host->hsq_enabled)
if (host->cqe_enabled && !host->hsq_enabled)
mmc_blk_cqe_recovery(mq);
else
mmc_blk_mq_recovery(mq);
@@ -315,7 +315,7 @@ static blk_status_t mmc_mq_queue_rq(struct blk_mq_hw_ctx *hctx,
if (get_card)
mmc_get_card(card, &mq->ctx);
if (mq->use_cqe) {
if (host->cqe_enabled) {
host->retune_now = host->need_retune && cqe_retune_ok &&
!host->hold_retune;
}
@@ -430,7 +430,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
int ret;
mq->card = card;
mq->use_cqe = host->cqe_enabled;
spin_lock_init(&mq->lock);
@@ -440,7 +439,7 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card)
* The queue depth for CQE must match the hardware because the request
* tag is used to index the hardware queue.
*/
if (mq->use_cqe && !host->hsq_enabled)
if (host->cqe_enabled && !host->hsq_enabled)
mq->tag_set.queue_depth =
min_t(int, card->ext_csd.cmdq_depth, host->cqe_qdepth);
else

View File

@@ -82,7 +82,6 @@ struct mmc_queue {
unsigned int cqe_busy;
#define MMC_CQE_DCMD_BUSY BIT(0)
bool busy;
bool use_cqe;
bool recovery_needed;
bool in_recovery;
bool rw_wait;

View File

@@ -135,6 +135,9 @@ static int mmc_decode_csd(struct mmc_card *card)
csd->erase_size = UNSTUFF_BITS(resp, 39, 7) + 1;
csd->erase_size <<= csd->write_blkbits - 9;
}
if (UNSTUFF_BITS(resp, 13, 1))
mmc_card_set_readonly(card);
break;
case 1:
/*
@@ -169,6 +172,9 @@ static int mmc_decode_csd(struct mmc_card *card)
csd->write_blkbits = 9;
csd->write_partial = 0;
csd->erase_size = 1;
if (UNSTUFF_BITS(resp, 13, 1))
mmc_card_set_readonly(card);
break;
default:
pr_err("%s: unrecognised CSD structure version %d\n",

Some files were not shown because too many files have changed in this diff Show More