mirror of
https://github.com/Dasharo/linux.git
synced 2026-03-06 15:25:10 -08:00
Merge tag 'mmc-v4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson: "MMC core: - Introduce host claiming by context to support blkmq - Preparations for enabling CQE (eMMC CMDQ) requests - Re-factorizations to prepare for blkmq support - Re-factorizations to prepare for CQE support - Fix signal voltage switch for SD cards without power cycle - Convert RPMB to a character device - Export eMMC revision via sysfs - Support eMMC DT binding for fixed driver type - Document mmc_regulator_get_supply() API MMC host: - omap_hsmmc: Updated regulator management for PBIAS - sdhci-omap: Add new OMAP SDHCI driver - meson-mx-sdio: New driver for the Amlogic Meson8 and Meson8b SoCs - sdhci-pci: Add support for Intel CDF - sdhci-acpi: Fix voltage switch for some Intel host controllers - sdhci-msm: Enable delay circuit calibration clocks - sdhci-msm: Manage power IRQ properly - mediatek: Add support of mt2701/mt2712 - mediatek: Updates management of clocks and tunings - mediatek: Upgrade eMMC HS400 support - rtsx_pci: Update tuning for gen3 PCI-Express - renesas_sdhi: Support R-Car Gen[123] fallback compatibility strings - Catch all errors when getting regulators - Various additional improvements and cleanups" * tag 'mmc-v4.15' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (91 commits) sdhci-fujitsu: add support for setting the CMD_DAT_DELAY attribute dt-bindings: sdhci-fujitsu: document cmd-dat-delay property mmc: tmio: Replace msleep() of 20ms or less with usleep_range() mmc: dw_mmc: Convert timers to use timer_setup() mmc: dw_mmc: Cleanup the DTO timer like the CTO one mmc: vub300: Use common code in __download_offload_pseudocode() mmc: tmio: Use common error handling code in tmio_mmc_host_probe() mmc: Convert timers to use timer_setup() mmc: sdhci-acpi: Fix voltage switch for some Intel host controllers mmc: sdhci-acpi: Let devices define their own private data mmc: mediatek: perfer to use rise edge latching for cmd line mmc: mediatek: improve eMMC hs400 mode read performance mmc: mediatek: add latch-ck support mmc: mediatek: add support of source_cg clock mmc: mediatek: add stop_clk fix and enhance_rx support mmc: mediatek: add busy_check support mmc: mediatek: add async fifo and data tune support mmc: mediatek: add pad_tune0 support mmc: mediatek: make hs400_tune_response only for mt8173 arm64: dts: mt8173: remove "mediatek, mt8135-mmc" from mmc nodes ...
This commit is contained in:
4
Documentation/ABI/testing/sysfs-bus-mmc
Normal file
4
Documentation/ABI/testing/sysfs-bus-mmc
Normal file
@@ -0,0 +1,4 @@
|
||||
What: /sys/bus/mmc/devices/.../rev
|
||||
Date: October 2017
|
||||
Contact: Jin Qian <jinqian@android.com>
|
||||
Description: Extended CSD revision number
|
||||
@@ -0,0 +1,54 @@
|
||||
* Amlogic Meson6, Meson8 and Meson8b SDIO/MMC controller
|
||||
|
||||
The highspeed MMC host controller on Amlogic SoCs provides an interface
|
||||
for MMC, SD, SDIO and SDHC types of memory cards.
|
||||
|
||||
Supported maximum speeds are the ones of the eMMC standard 4.41 as well
|
||||
as the speed of SD standard 2.0.
|
||||
|
||||
The hardware provides an internal "mux" which allows up to three slots
|
||||
to be controlled. Only one slot can be accessed at a time.
|
||||
|
||||
Required properties:
|
||||
- compatible : must be one of
|
||||
- "amlogic,meson8-sdio"
|
||||
- "amlogic,meson8b-sdio"
|
||||
along with the generic "amlogic,meson-mx-sdio"
|
||||
- reg : mmc controller base registers
|
||||
- interrupts : mmc controller interrupt
|
||||
- #address-cells : must be 1
|
||||
- size-cells : must be 0
|
||||
- clocks : phandle to clock providers
|
||||
- clock-names : must contain "core" and "clkin"
|
||||
|
||||
Required child nodes:
|
||||
A node for each slot provided by the MMC controller is required.
|
||||
NOTE: due to a driver limitation currently only one slot (= child node)
|
||||
is supported!
|
||||
|
||||
Required properties on each child node (= slot):
|
||||
- compatible : must be "mmc-slot" (see mmc.txt within this directory)
|
||||
- reg : the slot (or "port") ID
|
||||
|
||||
Optional properties on each child node (= slot):
|
||||
- bus-width : must be 1 or 4 (8-bit bus is not supported)
|
||||
- for cd and all other additional generic mmc parameters
|
||||
please refer to mmc.txt within this directory
|
||||
|
||||
Examples:
|
||||
mmc@c1108c20 {
|
||||
compatible = "amlogic,meson8-sdio", "amlogic,meson-mx-sdio";
|
||||
reg = <0xc1108c20 0x20>;
|
||||
interrupts = <0 28 1>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
clocks = <&clkc CLKID_SDIO>, <&clkc CLKID_CLK81>;
|
||||
clock-names = "core", "clkin";
|
||||
|
||||
slot@1 {
|
||||
compatible = "mmc-slot";
|
||||
reg = <1>;
|
||||
|
||||
bus-width = <4>;
|
||||
};
|
||||
};
|
||||
@@ -53,6 +53,9 @@ Optional properties:
|
||||
- no-sdio: controller is limited to send sdio cmd during initialization
|
||||
- no-sd: controller is limited to send sd cmd during initialization
|
||||
- no-mmc: controller is limited to send mmc cmd during initialization
|
||||
- fixed-emmc-driver-type: for non-removable eMMC, enforce this driver type.
|
||||
The value <n> is the driver type as specified in the eMMC specification
|
||||
(table 206 in spec version 5.1).
|
||||
|
||||
*NOTE* on CD and WP polarity. To use common for all SD/MMC host controllers line
|
||||
polarity properties, we have to fix the meaning of the "normal" and "inverted"
|
||||
|
||||
@@ -7,10 +7,18 @@ This file documents differences between the core properties in mmc.txt
|
||||
and the properties used by the msdc driver.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "mediatek,mt8173-mmc","mediatek,mt8135-mmc"
|
||||
- compatible: value should be either of the following.
|
||||
"mediatek,mt8135-mmc": for mmc host ip compatible with mt8135
|
||||
"mediatek,mt8173-mmc": for mmc host ip compatible with mt8173
|
||||
"mediatek,mt2701-mmc": for mmc host ip compatible with mt2701
|
||||
"mediatek,mt2712-mmc": for mmc host ip compatible with mt2712
|
||||
- reg: physical base address of the controller and length
|
||||
- interrupts: Should contain MSDC interrupt number
|
||||
- clocks: MSDC source clock, HCLK
|
||||
- clock-names: "source", "hclk"
|
||||
- clocks: Should contain phandle for the clock feeding the MMC controller
|
||||
- clock-names: Should contain the following:
|
||||
"source" - source clock (required)
|
||||
"hclk" - HCLK which used for host (required)
|
||||
"source_cg" - independent source clock gate (required for MT2712)
|
||||
- pinctrl-names: should be "default", "state_uhs"
|
||||
- pinctrl-0: should contain default/high speed pin ctrl
|
||||
- pinctrl-1: should contain uhs mode pin ctrl
|
||||
@@ -30,6 +38,10 @@ Optional properties:
|
||||
- mediatek,hs400-cmd-resp-sel-rising: HS400 command response sample selection
|
||||
If present,HS400 command responses are sampled on rising edges.
|
||||
If not present,HS400 command responses are sampled on falling edges.
|
||||
- mediatek,latch-ck: Some SoCs do not support enhance_rx, need set correct latch-ck to avoid data crc
|
||||
error caused by stop clock(fifo full)
|
||||
Valid range = [0:0x7]. if not present, default value is 0.
|
||||
applied to compatible "mediatek,mt2701-mmc".
|
||||
|
||||
Examples:
|
||||
mmc0: mmc@11230000 {
|
||||
|
||||
@@ -15,6 +15,8 @@ Required properties:
|
||||
Optional properties:
|
||||
- vqmmc-supply: phandle to the regulator device tree node, mentioned
|
||||
as the VCCQ/VDD_IO supply in the eMMC/SD specs.
|
||||
- fujitsu,cmd-dat-delay-select: boolean property indicating that this host
|
||||
requires the CMD_DAT_DELAY control to be enabled.
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ Required properties:
|
||||
"core" - SDC MMC clock (MCLK) (required)
|
||||
"bus" - SDCC bus voter clock (optional)
|
||||
"xo" - TCXO clock (optional)
|
||||
"cal" - reference clock for RCLK delay calibration (optional)
|
||||
"sleep" - sleep clock for RCLK delay calibration (optional)
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
16
Documentation/devicetree/bindings/mmc/sdhci-omap.txt
Normal file
16
Documentation/devicetree/bindings/mmc/sdhci-omap.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
* TI OMAP SDHCI Controller
|
||||
|
||||
Refer to mmc.txt for standard MMC bindings.
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "ti,dra7-sdhci" for DRA7 and DRA72 controllers
|
||||
- ti,hwmods: Must be "mmc<n>", <n> is controller instance starting 1
|
||||
|
||||
Example:
|
||||
mmc1: mmc@4809c000 {
|
||||
compatible = "ti,dra7-sdhci";
|
||||
reg = <0x4809c000 0x400>;
|
||||
ti,hwmods = "mmc1";
|
||||
bus-width = <4>;
|
||||
vmmc-supply = <&vmmc>; /* phandle to regulator node */
|
||||
};
|
||||
@@ -10,7 +10,7 @@ described in mmc.txt, can be used. Additionally the following tmio_mmc-specific
|
||||
optional bindings can be used.
|
||||
|
||||
Required properties:
|
||||
- compatible: "renesas,sdhi-shmobile" - a generic sh-mobile SDHI unit
|
||||
- compatible: should contain one or more of the following:
|
||||
"renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
|
||||
"renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
|
||||
"renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
|
||||
@@ -26,6 +26,16 @@ Required properties:
|
||||
"renesas,sdhi-r8a7794" - SDHI IP on R8A7794 SoC
|
||||
"renesas,sdhi-r8a7795" - SDHI IP on R8A7795 SoC
|
||||
"renesas,sdhi-r8a7796" - SDHI IP on R8A7796 SoC
|
||||
"renesas,sdhi-shmobile" - a generic sh-mobile SDHI controller
|
||||
"renesas,rcar-gen1-sdhi" - a generic R-Car Gen1 SDHI controller
|
||||
"renesas,rcar-gen2-sdhi" - a generic R-Car Gen2 or RZ/G1
|
||||
SDHI controller
|
||||
"renesas,rcar-gen3-sdhi" - a generic R-Car Gen3 SDHI controller
|
||||
|
||||
|
||||
When compatible with the generic version, nodes must list
|
||||
the SoC-specific version corresponding to the platform
|
||||
first followed by the generic version.
|
||||
|
||||
- clocks: Most controllers only have 1 clock source per channel. However, on
|
||||
some variations of this controller, the internal card detection
|
||||
@@ -43,3 +53,61 @@ Optional properties:
|
||||
- pinctrl-names: should be "default", "state_uhs"
|
||||
- pinctrl-0: should contain default/high speed pin ctrl
|
||||
- pinctrl-1: should contain uhs mode pin ctrl
|
||||
|
||||
Example: R8A7790 (R-Car H2) SDHI controller nodes
|
||||
|
||||
sdhi0: sd@ee100000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0 0xee100000 0 0x328>;
|
||||
interrupts = <GIC_SPI 165 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 314>;
|
||||
dmas = <&dmac0 0xcd>, <&dmac0 0xce>,
|
||||
<&dmac1 0xcd>, <&dmac1 0xce>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <195000000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 314>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sdhi1: sd@ee120000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0 0xee120000 0 0x328>;
|
||||
interrupts = <GIC_SPI 166 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 313>;
|
||||
dmas = <&dmac0 0xc9>, <&dmac0 0xca>,
|
||||
<&dmac1 0xc9>, <&dmac1 0xca>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <195000000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 313>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sdhi2: sd@ee140000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0 0xee140000 0 0x100>;
|
||||
interrupts = <GIC_SPI 167 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 312>;
|
||||
dmas = <&dmac0 0xc1>, <&dmac0 0xc2>,
|
||||
<&dmac1 0xc1>, <&dmac1 0xc2>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <97500000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 312>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
sdhi3: sd@ee160000 {
|
||||
compatible = "renesas,sdhi-r8a7790", "renesas,rcar-gen2-sdhi";
|
||||
reg = <0 0xee160000 0 0x100>;
|
||||
interrupts = <GIC_SPI 168 IRQ_TYPE_LEVEL_HIGH>;
|
||||
clocks = <&cpg CPG_MOD 311>;
|
||||
dmas = <&dmac0 0xd3>, <&dmac0 0xd4>,
|
||||
<&dmac1 0xd3>, <&dmac1 0xd4>;
|
||||
dma-names = "tx", "rx", "tx", "rx";
|
||||
max-frequency = <97500000>;
|
||||
power-domains = <&sysc R8A7790_PD_ALWAYS_ON>;
|
||||
resets = <&cpg 311>;
|
||||
status = "disabled";
|
||||
};
|
||||
|
||||
@@ -12067,6 +12067,12 @@ L: linux-mmc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/mmc/host/sdhci-spear.c
|
||||
|
||||
SECURE DIGITAL HOST CONTROLLER INTERFACE (SDHCI) TI OMAP DRIVER
|
||||
M: Kishon Vijay Abraham I <kishon@ti.com>
|
||||
L: linux-mmc@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/mmc/host/sdhci-omap.c
|
||||
|
||||
SECURE ENCRYPTING DEVICE (SED) OPAL DRIVER
|
||||
M: Scott Bauer <scott.bauer@intel.com>
|
||||
M: Jonathan Derrick <jonathan.derrick@intel.com>
|
||||
|
||||
@@ -682,8 +682,7 @@
|
||||
};
|
||||
|
||||
mmc0: mmc@11230000 {
|
||||
compatible = "mediatek,mt8173-mmc",
|
||||
"mediatek,mt8135-mmc";
|
||||
compatible = "mediatek,mt8173-mmc";
|
||||
reg = <0 0x11230000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&pericfg CLK_PERI_MSDC30_0>,
|
||||
@@ -693,8 +692,7 @@
|
||||
};
|
||||
|
||||
mmc1: mmc@11240000 {
|
||||
compatible = "mediatek,mt8173-mmc",
|
||||
"mediatek,mt8135-mmc";
|
||||
compatible = "mediatek,mt8173-mmc";
|
||||
reg = <0 0x11240000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&pericfg CLK_PERI_MSDC30_1>,
|
||||
@@ -704,8 +702,7 @@
|
||||
};
|
||||
|
||||
mmc2: mmc@11250000 {
|
||||
compatible = "mediatek,mt8173-mmc",
|
||||
"mediatek,mt8135-mmc";
|
||||
compatible = "mediatek,mt8173-mmc";
|
||||
reg = <0 0x11250000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&pericfg CLK_PERI_MSDC30_2>,
|
||||
@@ -715,8 +712,7 @@
|
||||
};
|
||||
|
||||
mmc3: mmc@11260000 {
|
||||
compatible = "mediatek,mt8173-mmc",
|
||||
"mediatek,mt8135-mmc";
|
||||
compatible = "mediatek,mt8173-mmc";
|
||||
reg = <0 0x11260000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_LOW>;
|
||||
clocks = <&pericfg CLK_PERI_MSDC30_3>,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -369,10 +369,17 @@ int mmc_add_card(struct mmc_card *card)
|
||||
*/
|
||||
void mmc_remove_card(struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
mmc_remove_card_debugfs(card);
|
||||
#endif
|
||||
|
||||
if (host->cqe_enabled) {
|
||||
host->cqe_ops->cqe_disable(host);
|
||||
host->cqe_enabled = false;
|
||||
}
|
||||
|
||||
if (mmc_card_present(card)) {
|
||||
if (mmc_host_is_spi(card->host)) {
|
||||
pr_info("%s: SPI card removed\n",
|
||||
|
||||
@@ -266,7 +266,8 @@ static void __mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||
host->ops->request(host, mrq);
|
||||
}
|
||||
|
||||
static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
|
||||
static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq,
|
||||
bool cqe)
|
||||
{
|
||||
if (mrq->sbc) {
|
||||
pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
|
||||
@@ -275,9 +276,12 @@ static void mmc_mrq_pr_debug(struct mmc_host *host, struct mmc_request *mrq)
|
||||
}
|
||||
|
||||
if (mrq->cmd) {
|
||||
pr_debug("%s: starting CMD%u arg %08x flags %08x\n",
|
||||
mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->arg,
|
||||
mrq->cmd->flags);
|
||||
pr_debug("%s: starting %sCMD%u arg %08x flags %08x\n",
|
||||
mmc_hostname(host), cqe ? "CQE direct " : "",
|
||||
mrq->cmd->opcode, mrq->cmd->arg, mrq->cmd->flags);
|
||||
} else if (cqe) {
|
||||
pr_debug("%s: starting CQE transfer for tag %d blkaddr %u\n",
|
||||
mmc_hostname(host), mrq->tag, mrq->data->blk_addr);
|
||||
}
|
||||
|
||||
if (mrq->data) {
|
||||
@@ -333,7 +337,7 @@ static int mmc_mrq_prep(struct mmc_host *host, struct mmc_request *mrq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||
int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -342,7 +346,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||
if (mmc_card_removed(host->card))
|
||||
return -ENOMEDIUM;
|
||||
|
||||
mmc_mrq_pr_debug(host, mrq);
|
||||
mmc_mrq_pr_debug(host, mrq, false);
|
||||
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
@@ -355,6 +359,7 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_start_request);
|
||||
|
||||
/*
|
||||
* mmc_wait_data_done() - done callback for data request
|
||||
@@ -482,6 +487,155 @@ void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_wait_for_req_done);
|
||||
|
||||
/*
|
||||
* mmc_cqe_start_req - Start a CQE request.
|
||||
* @host: MMC host to start the request
|
||||
* @mrq: request to start
|
||||
*
|
||||
* Start the request, re-tuning if needed and it is possible. Returns an error
|
||||
* code if the request fails to start or -EBUSY if CQE is busy.
|
||||
*/
|
||||
int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
int err;
|
||||
|
||||
/*
|
||||
* CQE cannot process re-tuning commands. Caller must hold retuning
|
||||
* while CQE is in use. Re-tuning can happen here only when CQE has no
|
||||
* active requests i.e. this is the first. Note, re-tuning will call
|
||||
* ->cqe_off().
|
||||
*/
|
||||
err = mmc_retune(host);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
mrq->host = host;
|
||||
|
||||
mmc_mrq_pr_debug(host, mrq, true);
|
||||
|
||||
err = mmc_mrq_prep(host, mrq);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
err = host->cqe_ops->cqe_request(host, mrq);
|
||||
if (err)
|
||||
goto out_err;
|
||||
|
||||
trace_mmc_request_start(host, mrq);
|
||||
|
||||
return 0;
|
||||
|
||||
out_err:
|
||||
if (mrq->cmd) {
|
||||
pr_debug("%s: failed to start CQE direct CMD%u, error %d\n",
|
||||
mmc_hostname(host), mrq->cmd->opcode, err);
|
||||
} else {
|
||||
pr_debug("%s: failed to start CQE transfer for tag %d, error %d\n",
|
||||
mmc_hostname(host), mrq->tag, err);
|
||||
}
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_cqe_start_req);
|
||||
|
||||
/**
|
||||
* mmc_cqe_request_done - CQE has finished processing an MMC request
|
||||
* @host: MMC host which completed request
|
||||
* @mrq: MMC request which completed
|
||||
*
|
||||
* CQE drivers should call this function when they have completed
|
||||
* their processing of a request.
|
||||
*/
|
||||
void mmc_cqe_request_done(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
mmc_should_fail_request(host, mrq);
|
||||
|
||||
/* Flag re-tuning needed on CRC errors */
|
||||
if ((mrq->cmd && mrq->cmd->error == -EILSEQ) ||
|
||||
(mrq->data && mrq->data->error == -EILSEQ))
|
||||
mmc_retune_needed(host);
|
||||
|
||||
trace_mmc_request_done(host, mrq);
|
||||
|
||||
if (mrq->cmd) {
|
||||
pr_debug("%s: CQE req done (direct CMD%u): %d\n",
|
||||
mmc_hostname(host), mrq->cmd->opcode, mrq->cmd->error);
|
||||
} else {
|
||||
pr_debug("%s: CQE transfer done tag %d\n",
|
||||
mmc_hostname(host), mrq->tag);
|
||||
}
|
||||
|
||||
if (mrq->data) {
|
||||
pr_debug("%s: %d bytes transferred: %d\n",
|
||||
mmc_hostname(host),
|
||||
mrq->data->bytes_xfered, mrq->data->error);
|
||||
}
|
||||
|
||||
mrq->done(mrq);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_cqe_request_done);
|
||||
|
||||
/**
|
||||
* mmc_cqe_post_req - CQE post process of a completed MMC request
|
||||
* @host: MMC host
|
||||
* @mrq: MMC request to be processed
|
||||
*/
|
||||
void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
if (host->cqe_ops->cqe_post_req)
|
||||
host->cqe_ops->cqe_post_req(host, mrq);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_cqe_post_req);
|
||||
|
||||
/* Arbitrary 1 second timeout */
|
||||
#define MMC_CQE_RECOVERY_TIMEOUT 1000
|
||||
|
||||
/*
|
||||
* mmc_cqe_recovery - Recover from CQE errors.
|
||||
* @host: MMC host to recover
|
||||
*
|
||||
* Recovery consists of stopping CQE, stopping eMMC, discarding the queue in
|
||||
* in eMMC, and discarding the queue in CQE. CQE must call
|
||||
* mmc_cqe_request_done() on all requests. An error is returned if the eMMC
|
||||
* fails to discard its queue.
|
||||
*/
|
||||
int mmc_cqe_recovery(struct mmc_host *host)
|
||||
{
|
||||
struct mmc_command cmd;
|
||||
int err;
|
||||
|
||||
mmc_retune_hold_now(host);
|
||||
|
||||
/*
|
||||
* Recovery is expected seldom, if at all, but it reduces performance,
|
||||
* so make sure it is not completely silent.
|
||||
*/
|
||||
pr_warn("%s: running CQE recovery\n", mmc_hostname(host));
|
||||
|
||||
host->cqe_ops->cqe_recovery_start(host);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.opcode = MMC_STOP_TRANSMISSION,
|
||||
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC,
|
||||
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
|
||||
cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
|
||||
mmc_wait_for_cmd(host, &cmd, 0);
|
||||
|
||||
memset(&cmd, 0, sizeof(cmd));
|
||||
cmd.opcode = MMC_CMDQ_TASK_MGMT;
|
||||
cmd.arg = 1; /* Discard entire queue */
|
||||
cmd.flags = MMC_RSP_R1B | MMC_CMD_AC;
|
||||
cmd.flags &= ~MMC_RSP_CRC; /* Ignore CRC */
|
||||
cmd.busy_timeout = MMC_CQE_RECOVERY_TIMEOUT,
|
||||
err = mmc_wait_for_cmd(host, &cmd, 0);
|
||||
|
||||
host->cqe_ops->cqe_recovery_finish(host);
|
||||
|
||||
mmc_retune_release(host);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_cqe_recovery);
|
||||
|
||||
/**
|
||||
* mmc_is_req_done - Determine if a 'cap_cmd_during_tfr' request is done
|
||||
* @host: MMC host
|
||||
@@ -832,9 +986,36 @@ unsigned int mmc_align_data_size(struct mmc_card *card, unsigned int sz)
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_align_data_size);
|
||||
|
||||
/*
|
||||
* Allow claiming an already claimed host if the context is the same or there is
|
||||
* no context but the task is the same.
|
||||
*/
|
||||
static inline bool mmc_ctx_matches(struct mmc_host *host, struct mmc_ctx *ctx,
|
||||
struct task_struct *task)
|
||||
{
|
||||
return host->claimer == ctx ||
|
||||
(!ctx && task && host->claimer->task == task);
|
||||
}
|
||||
|
||||
static inline void mmc_ctx_set_claimer(struct mmc_host *host,
|
||||
struct mmc_ctx *ctx,
|
||||
struct task_struct *task)
|
||||
{
|
||||
if (!host->claimer) {
|
||||
if (ctx)
|
||||
host->claimer = ctx;
|
||||
else
|
||||
host->claimer = &host->default_ctx;
|
||||
}
|
||||
if (task)
|
||||
host->claimer->task = task;
|
||||
}
|
||||
|
||||
/**
|
||||
* __mmc_claim_host - exclusively claim a host
|
||||
* @host: mmc host to claim
|
||||
* @ctx: context that claims the host or NULL in which case the default
|
||||
* context will be used
|
||||
* @abort: whether or not the operation should be aborted
|
||||
*
|
||||
* Claim a host for a set of operations. If @abort is non null and
|
||||
@@ -842,8 +1023,10 @@ EXPORT_SYMBOL(mmc_align_data_size);
|
||||
* that non-zero value without acquiring the lock. Returns zero
|
||||
* with the lock held otherwise.
|
||||
*/
|
||||
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
|
||||
int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
|
||||
atomic_t *abort)
|
||||
{
|
||||
struct task_struct *task = ctx ? NULL : current;
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
unsigned long flags;
|
||||
int stop;
|
||||
@@ -856,7 +1039,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
|
||||
while (1) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
stop = abort ? atomic_read(abort) : 0;
|
||||
if (stop || !host->claimed || host->claimer == current)
|
||||
if (stop || !host->claimed || mmc_ctx_matches(host, ctx, task))
|
||||
break;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
schedule();
|
||||
@@ -865,7 +1048,7 @@ int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
|
||||
set_current_state(TASK_RUNNING);
|
||||
if (!stop) {
|
||||
host->claimed = 1;
|
||||
host->claimer = current;
|
||||
mmc_ctx_set_claimer(host, ctx, task);
|
||||
host->claim_cnt += 1;
|
||||
if (host->claim_cnt == 1)
|
||||
pm = true;
|
||||
@@ -900,6 +1083,7 @@ void mmc_release_host(struct mmc_host *host)
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
} else {
|
||||
host->claimed = 0;
|
||||
host->claimer->task = NULL;
|
||||
host->claimer = NULL;
|
||||
spin_unlock_irqrestore(&host->lock, flags);
|
||||
wake_up(&host->wq);
|
||||
@@ -913,10 +1097,10 @@ EXPORT_SYMBOL(mmc_release_host);
|
||||
* This is a helper function, which fetches a runtime pm reference for the
|
||||
* card device and also claims the host.
|
||||
*/
|
||||
void mmc_get_card(struct mmc_card *card)
|
||||
void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx)
|
||||
{
|
||||
pm_runtime_get_sync(&card->dev);
|
||||
mmc_claim_host(card->host);
|
||||
__mmc_claim_host(card->host, ctx, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_get_card);
|
||||
|
||||
@@ -924,9 +1108,13 @@ EXPORT_SYMBOL(mmc_get_card);
|
||||
* This is a helper function, which releases the host and drops the runtime
|
||||
* pm reference for the card device.
|
||||
*/
|
||||
void mmc_put_card(struct mmc_card *card)
|
||||
void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx)
|
||||
{
|
||||
mmc_release_host(card->host);
|
||||
struct mmc_host *host = card->host;
|
||||
|
||||
WARN_ON(ctx && host->claimer != ctx);
|
||||
|
||||
mmc_release_host(host);
|
||||
pm_runtime_mark_last_busy(&card->dev);
|
||||
pm_runtime_put_autosuspend(&card->dev);
|
||||
}
|
||||
@@ -1400,6 +1588,16 @@ EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc);
|
||||
|
||||
#endif /* CONFIG_REGULATOR */
|
||||
|
||||
/**
|
||||
* mmc_regulator_get_supply - try to get VMMC and VQMMC regulators for a host
|
||||
* @mmc: the host to regulate
|
||||
*
|
||||
* Returns 0 or errno. errno should be handled, it is either a critical error
|
||||
* or -EPROBE_DEFER. 0 means no critical error but it does not mean all
|
||||
* regulators have been found because they all are optional. If you require
|
||||
* certain regulators, you need to check separately in your driver if they got
|
||||
* populated after calling this function.
|
||||
*/
|
||||
int mmc_regulator_get_supply(struct mmc_host *mmc)
|
||||
{
|
||||
struct device *dev = mmc_dev(mmc);
|
||||
@@ -1484,11 +1682,33 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage)
|
||||
|
||||
}
|
||||
|
||||
int mmc_host_set_uhs_voltage(struct mmc_host *host)
|
||||
{
|
||||
u32 clock;
|
||||
|
||||
/*
|
||||
* During a signal voltage level switch, the clock must be gated
|
||||
* for 5 ms according to the SD spec
|
||||
*/
|
||||
clock = host->ios.clock;
|
||||
host->ios.clock = 0;
|
||||
mmc_set_ios(host);
|
||||
|
||||
if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180))
|
||||
return -EAGAIN;
|
||||
|
||||
/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
|
||||
mmc_delay(10);
|
||||
host->ios.clock = clock;
|
||||
mmc_set_ios(host);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
|
||||
{
|
||||
struct mmc_command cmd = {};
|
||||
int err = 0;
|
||||
u32 clock;
|
||||
|
||||
/*
|
||||
* If we cannot switch voltages, return failure so the caller
|
||||
@@ -1520,15 +1740,8 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
|
||||
err = -EAGAIN;
|
||||
goto power_cycle;
|
||||
}
|
||||
/*
|
||||
* During a signal voltage level switch, the clock must be gated
|
||||
* for 5 ms according to the SD spec
|
||||
*/
|
||||
clock = host->ios.clock;
|
||||
host->ios.clock = 0;
|
||||
mmc_set_ios(host);
|
||||
|
||||
if (mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_180)) {
|
||||
if (mmc_host_set_uhs_voltage(host)) {
|
||||
/*
|
||||
* Voltages may not have been switched, but we've already
|
||||
* sent CMD11, so a power cycle is required anyway
|
||||
@@ -1537,11 +1750,6 @@ int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr)
|
||||
goto power_cycle;
|
||||
}
|
||||
|
||||
/* Keep clock gated for at least 10 ms, though spec only says 5 ms */
|
||||
mmc_delay(10);
|
||||
host->ios.clock = clock;
|
||||
mmc_set_ios(host);
|
||||
|
||||
/* Wait for at least 1 ms according to spec */
|
||||
mmc_delay(1);
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ void mmc_set_bus_mode(struct mmc_host *host, unsigned int mode);
|
||||
void mmc_set_bus_width(struct mmc_host *host, unsigned int width);
|
||||
u32 mmc_select_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_set_uhs_voltage(struct mmc_host *host, u32 ocr);
|
||||
int mmc_host_set_uhs_voltage(struct mmc_host *host);
|
||||
int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage);
|
||||
void mmc_set_timing(struct mmc_host *host, unsigned int timing);
|
||||
void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
|
||||
@@ -107,6 +108,8 @@ static inline void mmc_unregister_pm_notifier(struct mmc_host *host) { }
|
||||
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);
|
||||
|
||||
int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq);
|
||||
|
||||
struct mmc_async_req;
|
||||
|
||||
struct mmc_async_req *mmc_start_areq(struct mmc_host *host,
|
||||
@@ -128,10 +131,11 @@ int mmc_set_blocklen(struct mmc_card *card, unsigned int blocklen);
|
||||
int mmc_set_blockcount(struct mmc_card *card, unsigned int blockcount,
|
||||
bool is_rel_write);
|
||||
|
||||
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort);
|
||||
int __mmc_claim_host(struct mmc_host *host, struct mmc_ctx *ctx,
|
||||
atomic_t *abort);
|
||||
void mmc_release_host(struct mmc_host *host);
|
||||
void mmc_get_card(struct mmc_card *card);
|
||||
void mmc_put_card(struct mmc_card *card);
|
||||
void mmc_get_card(struct mmc_card *card, struct mmc_ctx *ctx);
|
||||
void mmc_put_card(struct mmc_card *card, struct mmc_ctx *ctx);
|
||||
|
||||
/**
|
||||
* mmc_claim_host - exclusively claim a host
|
||||
@@ -141,7 +145,11 @@ void mmc_put_card(struct mmc_card *card);
|
||||
*/
|
||||
static inline void mmc_claim_host(struct mmc_host *host)
|
||||
{
|
||||
__mmc_claim_host(host, NULL);
|
||||
__mmc_claim_host(host, NULL, NULL);
|
||||
}
|
||||
|
||||
int mmc_cqe_start_req(struct mmc_host *host, struct mmc_request *mrq);
|
||||
void mmc_cqe_post_req(struct mmc_host *host, struct mmc_request *mrq);
|
||||
int mmc_cqe_recovery(struct mmc_host *host);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -111,12 +111,6 @@ void mmc_retune_hold(struct mmc_host *host)
|
||||
host->hold_retune += 1;
|
||||
}
|
||||
|
||||
void mmc_retune_hold_now(struct mmc_host *host)
|
||||
{
|
||||
host->retune_now = 0;
|
||||
host->hold_retune += 1;
|
||||
}
|
||||
|
||||
void mmc_retune_release(struct mmc_host *host)
|
||||
{
|
||||
if (host->hold_retune)
|
||||
@@ -124,6 +118,7 @@ void mmc_retune_release(struct mmc_host *host)
|
||||
else
|
||||
WARN_ON(1);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_retune_release);
|
||||
|
||||
int mmc_retune(struct mmc_host *host)
|
||||
{
|
||||
@@ -184,7 +179,7 @@ static void mmc_retune_timer(unsigned long data)
|
||||
int mmc_of_parse(struct mmc_host *host)
|
||||
{
|
||||
struct device *dev = host->parent;
|
||||
u32 bus_width;
|
||||
u32 bus_width, drv_type;
|
||||
int ret;
|
||||
bool cd_cap_invert, cd_gpio_invert = false;
|
||||
bool ro_cap_invert, ro_gpio_invert = false;
|
||||
@@ -326,6 +321,15 @@ int mmc_of_parse(struct mmc_host *host)
|
||||
if (device_property_read_bool(dev, "no-mmc"))
|
||||
host->caps2 |= MMC_CAP2_NO_MMC;
|
||||
|
||||
/* Must be after "non-removable" check */
|
||||
if (device_property_read_u32(dev, "fixed-emmc-driver-type", &drv_type) == 0) {
|
||||
if (host->caps & MMC_CAP_NONREMOVABLE)
|
||||
host->fixed_drv_type = drv_type;
|
||||
else
|
||||
dev_err(host->parent,
|
||||
"can't use fixed driver type, media is removable\n");
|
||||
}
|
||||
|
||||
host->dsr_req = !device_property_read_u32(dev, "dsr", &host->dsr);
|
||||
if (host->dsr_req && (host->dsr & ~0xffff)) {
|
||||
dev_err(host->parent,
|
||||
@@ -398,6 +402,8 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
|
||||
host->max_blk_size = 512;
|
||||
host->max_blk_count = PAGE_SIZE / 512;
|
||||
|
||||
host->fixed_drv_type = -EINVAL;
|
||||
|
||||
return host;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,12 +19,17 @@ void mmc_unregister_host_class(void);
|
||||
void mmc_retune_enable(struct mmc_host *host);
|
||||
void mmc_retune_disable(struct mmc_host *host);
|
||||
void mmc_retune_hold(struct mmc_host *host);
|
||||
void mmc_retune_hold_now(struct mmc_host *host);
|
||||
void mmc_retune_release(struct mmc_host *host);
|
||||
int mmc_retune(struct mmc_host *host);
|
||||
void mmc_retune_pause(struct mmc_host *host);
|
||||
void mmc_retune_unpause(struct mmc_host *host);
|
||||
|
||||
static inline void mmc_retune_hold_now(struct mmc_host *host)
|
||||
{
|
||||
host->retune_now = 0;
|
||||
host->hold_retune += 1;
|
||||
}
|
||||
|
||||
static inline void mmc_retune_recheck(struct mmc_host *host)
|
||||
{
|
||||
if (host->hold_retune <= 1)
|
||||
|
||||
@@ -780,6 +780,7 @@ MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
|
||||
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
|
||||
MMC_DEV_ATTR(oemid, "0x%04x\n", card->cid.oemid);
|
||||
MMC_DEV_ATTR(prv, "0x%x\n", card->cid.prv);
|
||||
MMC_DEV_ATTR(rev, "0x%x\n", card->ext_csd.rev);
|
||||
MMC_DEV_ATTR(pre_eol_info, "%02x\n", card->ext_csd.pre_eol_info);
|
||||
MMC_DEV_ATTR(life_time, "0x%02x 0x%02x\n",
|
||||
card->ext_csd.device_life_time_est_typ_a,
|
||||
@@ -838,6 +839,7 @@ static struct attribute *mmc_std_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_oemid.attr,
|
||||
&dev_attr_prv.attr,
|
||||
&dev_attr_rev.attr,
|
||||
&dev_attr_pre_eol_info.attr,
|
||||
&dev_attr_life_time.attr,
|
||||
&dev_attr_serial.attr,
|
||||
@@ -1289,13 +1291,18 @@ out_err:
|
||||
static void mmc_select_driver_type(struct mmc_card *card)
|
||||
{
|
||||
int card_drv_type, drive_strength, drv_type;
|
||||
int fixed_drv_type = card->host->fixed_drv_type;
|
||||
|
||||
card_drv_type = card->ext_csd.raw_driver_strength |
|
||||
mmc_driver_type_mask(0);
|
||||
|
||||
drive_strength = mmc_select_drive_strength(card,
|
||||
card->ext_csd.hs200_max_dtr,
|
||||
card_drv_type, &drv_type);
|
||||
if (fixed_drv_type >= 0)
|
||||
drive_strength = card_drv_type & mmc_driver_type_mask(fixed_drv_type)
|
||||
? fixed_drv_type : 0;
|
||||
else
|
||||
drive_strength = mmc_select_drive_strength(card,
|
||||
card->ext_csd.hs200_max_dtr,
|
||||
card_drv_type, &drv_type);
|
||||
|
||||
card->drive_strength = drive_strength;
|
||||
|
||||
@@ -1785,6 +1792,23 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable Command Queue if supported. Note that Packed Commands cannot
|
||||
* be used with Command Queue.
|
||||
*/
|
||||
card->ext_csd.cmdq_en = false;
|
||||
if (card->ext_csd.cmdq_support && host->caps2 & MMC_CAP2_CQE) {
|
||||
err = mmc_cmdq_enable(card);
|
||||
if (err && err != -EBADMSG)
|
||||
goto free_card;
|
||||
if (err) {
|
||||
pr_warn("%s: Enabling CMDQ failed\n",
|
||||
mmc_hostname(card->host));
|
||||
card->ext_csd.cmdq_support = false;
|
||||
card->ext_csd.cmdq_depth = 0;
|
||||
err = 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* In some cases (e.g. RPMB or mmc_test), the Command Queue must be
|
||||
* disabled for a time, so a flag is needed to indicate to re-enable the
|
||||
@@ -1792,6 +1816,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
|
||||
*/
|
||||
card->reenable_cmdq = card->ext_csd.cmdq_en;
|
||||
|
||||
if (card->ext_csd.cmdq_en && !host->cqe_enabled) {
|
||||
err = host->cqe_ops->cqe_enable(host, card);
|
||||
if (err) {
|
||||
pr_err("%s: Failed to enable CQE, error %d\n",
|
||||
mmc_hostname(host), err);
|
||||
} else {
|
||||
host->cqe_enabled = true;
|
||||
pr_info("%s: Command Queue Engine enabled\n",
|
||||
mmc_hostname(host));
|
||||
}
|
||||
}
|
||||
|
||||
if (!oldcard)
|
||||
host->card = card;
|
||||
|
||||
@@ -1911,14 +1947,14 @@ static void mmc_detect(struct mmc_host *host)
|
||||
{
|
||||
int err;
|
||||
|
||||
mmc_get_card(host->card);
|
||||
mmc_get_card(host->card, NULL);
|
||||
|
||||
/*
|
||||
* Just check if our card has been removed.
|
||||
*/
|
||||
err = _mmc_detect_card_removed(host);
|
||||
|
||||
mmc_put_card(host->card);
|
||||
mmc_put_card(host->card, NULL);
|
||||
|
||||
if (err) {
|
||||
mmc_remove(host);
|
||||
|
||||
@@ -977,7 +977,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
|
||||
from_exception)
|
||||
return;
|
||||
|
||||
mmc_claim_host(card->host);
|
||||
if (card->ext_csd.raw_bkops_status >= EXT_CSD_BKOPS_LEVEL_2) {
|
||||
timeout = MMC_OPS_TIMEOUT_MS;
|
||||
use_busy_signal = true;
|
||||
@@ -995,7 +994,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
|
||||
pr_warn("%s: Error %d starting bkops\n",
|
||||
mmc_hostname(card->host), err);
|
||||
mmc_retune_release(card->host);
|
||||
goto out;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1007,9 +1006,8 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
|
||||
mmc_card_set_doing_bkops(card);
|
||||
else
|
||||
mmc_retune_release(card->host);
|
||||
out:
|
||||
mmc_release_host(card->host);
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_start_bkops);
|
||||
|
||||
/*
|
||||
* Flush the cache to the non-volatile storage.
|
||||
|
||||
@@ -30,7 +30,7 @@ static int mmc_prep_request(struct request_queue *q, struct request *req)
|
||||
{
|
||||
struct mmc_queue *mq = q->queuedata;
|
||||
|
||||
if (mq && (mmc_card_removed(mq->card) || mmc_access_rpmb(mq)))
|
||||
if (mq && mmc_card_removed(mq->card))
|
||||
return BLKPREP_KILL;
|
||||
|
||||
req->rq_flags |= RQF_DONTPREP;
|
||||
@@ -177,6 +177,29 @@ static void mmc_exit_request(struct request_queue *q, struct request *req)
|
||||
mq_rq->sg = NULL;
|
||||
}
|
||||
|
||||
static void mmc_setup_queue(struct mmc_queue *mq, struct mmc_card *card)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
u64 limit = BLK_BOUNCE_HIGH;
|
||||
|
||||
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
|
||||
limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
|
||||
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
|
||||
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
|
||||
if (mmc_can_erase(card))
|
||||
mmc_queue_setup_discard(mq->queue, card);
|
||||
|
||||
blk_queue_bounce_limit(mq->queue, limit);
|
||||
blk_queue_max_hw_sectors(mq->queue,
|
||||
min(host->max_blk_count, host->max_req_size / 512));
|
||||
blk_queue_max_segments(mq->queue, host->max_segs);
|
||||
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
|
||||
|
||||
/* Initialize thread_sem even if it is not used */
|
||||
sema_init(&mq->thread_sem, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_init_queue - initialise a queue structure.
|
||||
* @mq: mmc queue
|
||||
@@ -190,12 +213,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
|
||||
spinlock_t *lock, const char *subname)
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
u64 limit = BLK_BOUNCE_HIGH;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
|
||||
limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
|
||||
|
||||
mq->card = card;
|
||||
mq->queue = blk_alloc_queue(GFP_KERNEL);
|
||||
if (!mq->queue)
|
||||
@@ -214,18 +233,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
|
||||
}
|
||||
|
||||
blk_queue_prep_rq(mq->queue, mmc_prep_request);
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_NONROT, mq->queue);
|
||||
queue_flag_clear_unlocked(QUEUE_FLAG_ADD_RANDOM, mq->queue);
|
||||
if (mmc_can_erase(card))
|
||||
mmc_queue_setup_discard(mq->queue, card);
|
||||
|
||||
blk_queue_bounce_limit(mq->queue, limit);
|
||||
blk_queue_max_hw_sectors(mq->queue,
|
||||
min(host->max_blk_count, host->max_req_size / 512));
|
||||
blk_queue_max_segments(mq->queue, host->max_segs);
|
||||
blk_queue_max_segment_size(mq->queue, host->max_seg_size);
|
||||
|
||||
sema_init(&mq->thread_sem, 1);
|
||||
mmc_setup_queue(mq, card);
|
||||
|
||||
mq->thread = kthread_run(mmc_queue_thread, mq, "mmcqd/%d%s",
|
||||
host->index, subname ? subname : "");
|
||||
|
||||
@@ -36,12 +36,14 @@ struct mmc_blk_request {
|
||||
/**
|
||||
* enum mmc_drv_op - enumerates the operations in the mmc_queue_req
|
||||
* @MMC_DRV_OP_IOCTL: ioctl operation
|
||||
* @MMC_DRV_OP_IOCTL_RPMB: RPMB-oriented ioctl operation
|
||||
* @MMC_DRV_OP_BOOT_WP: write protect boot partitions
|
||||
* @MMC_DRV_OP_GET_CARD_STATUS: get card status
|
||||
* @MMC_DRV_OP_GET_EXT_CSD: get the EXT CSD from an eMMC card
|
||||
*/
|
||||
enum mmc_drv_op {
|
||||
MMC_DRV_OP_IOCTL,
|
||||
MMC_DRV_OP_IOCTL_RPMB,
|
||||
MMC_DRV_OP_BOOT_WP,
|
||||
MMC_DRV_OP_GET_CARD_STATUS,
|
||||
MMC_DRV_OP_GET_EXT_CSD,
|
||||
@@ -82,6 +84,4 @@ extern void mmc_queue_resume(struct mmc_queue *);
|
||||
extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
|
||||
struct mmc_queue_req *);
|
||||
|
||||
extern int mmc_access_rpmb(struct mmc_queue *);
|
||||
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user