You've already forked linux-rockchip
mirror of
https://github.com/armbian/linux-rockchip.git
synced 2026-01-06 11:08:10 -08:00
Merge tag 'mmc-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc
Pull MMC updates from Ulf Hansson:
"It's been an busy period for mmc. Quite some changes in the mmc core,
two new mmc host drivers, some existing drivers being extended to
support new IP versions and lots of other updates.
MMC core:
- Delete eMMC packed command support
- Introduce mmc_abort_tuning() to enable eMMC tuning to fail
gracefully
- Introduce mmc_can_retune() to see if a host can be retuned
- Re-work and improve the sequence when sending a CMD6 for mmc
- Enable CDM13 polling when switching to HS and HS DDR mode for mmc
- Relax checking for CMD6 errors after switch to HS200
- Re-factoring the code dealing with the mmc block queue
- Recognize whether the eMMC card supports CMDQ
- Fix 4K native sector check
- Don't power off the card when starting the host
- Increase MMC_IOC_MAX_BYTES to support bigger firmware binaries
- Improve error handling and drop meaningless BUG_ONs()
- Lots of clean-ups and changes to improve the quality of the code
MMC host:
- sdhci: Fix tuning sequence and clean-up the related code
- sdhci: Add support to via DT override broken SDHCI cap register
bits
- sdhci-cadence: Add new driver for Cadence SD4HC SDHCI variant
- sdhci-msm: Update clock management
- sdhci-msm: Add support for eMMC HS400 mode
- sdhci-msm: Deploy runtime/system PM support
- sdhci-iproc: Extend driver support to newer IP versions
- sdhci-pci: Add support for Intel GLK
- sdhci-pci: Add support for Intel NI byt sdio
- sdhci-acpi: Add support for 80860F14 UID 2 SDIO bus
- sdhci: Lots of various small improvements and clean-ups
- tmio: Add support for tuning
- sh_mobile_sdhi: Add support for tuning
- sh_mobile_sdhi: Extend driver to support SDHI IP on R7S72100 SoC
- sh_mobile_sdhi: remove support for sh7372
- davinci: Use mmc_of_parse() to enable generic mmc DT bindings
- meson: Add new driver to support GX platforms
- dw_mmc: Deploy generic runtime/system PM support
- dw_mmc: Lots of various small improvements
As a part of the mmc changes this time, I have also pulled in an
immutable branch/tag (soc-device-match-tag1) hosted by Geert
Uytterhoeven, to share the implementation of the new
soc_device_match() interface. This is needed by these mmc related
changes:
- mmc: sdhci-of-esdhc: Get correct IP version for T4240-R1.0-R2.0
- soc: fsl: add GUTS driver for QorIQ platforms"
* tag 'mmc-v4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc: (136 commits)
mmc: sdhci-cadence: add Cadence SD4HC support
mmc: sdhci: export sdhci_execute_tuning()
mmc: sdhci: Tidy tuning loop
mmc: sdhci: Simplify tuning block size logic
mmc: sdhci: Factor out tuning helper functions
mmc: sdhci: Use mmc_abort_tuning()
mmc: mmc: Introduce mmc_abort_tuning()
mmc: sdhci: Always allow tuning to fall back to fixed sampling
mmc: sdhci: Fix tuning reset after exhausting the maximum number of loops
mmc: sdhci: Fix recovery from tuning timeout
Revert "mmc: sdhci: Reset cmd and data circuits after tuning failure"
mmc: mmc: Relax checking for switch errors after HS200 switch
mmc: sdhci-acpi: support 80860F14 UID 2 SDIO bus
mmc: sdhci-of-at91: remove bogus MMC_SDHCI_IO_ACCESSORS select
mmc: sdhci-pci: Use ACPI to get max frequency for Intel NI byt sdio
mmc: sdhci-pci: Add PCI ID for Intel NI byt sdio
mmc: sdhci-s3c: add spin_unlock_irq() before calling clk_round_rate
mmc: dw_mmc: display the clock message only one time when card is polling
mmc: dw_mmc: add the debug message for polling and non-removable
mmc: dw_mmc: check the "present" variable before checking flags
...
This commit is contained in:
32
Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt
Normal file
32
Documentation/devicetree/bindings/mmc/amlogic,meson-gx.txt
Normal file
@@ -0,0 +1,32 @@
|
||||
Amlogic SD / eMMC controller for S905/GXBB family SoCs
|
||||
|
||||
The MMC 5.1 compliant host controller on Amlogic provides the
|
||||
interface for SD, eMMC and SDIO devices.
|
||||
|
||||
This file documents the properties in addition to those available in
|
||||
the MMC core bindings, documented by mmc.txt.
|
||||
|
||||
Required properties:
|
||||
- compatible : contains one of:
|
||||
- "amlogic,meson-gx-mmc"
|
||||
- "amlogic,meson-gxbb-mmc"
|
||||
- "amlogic,meson-gxl-mmc"
|
||||
- "amlogic,meson-gxm-mmc"
|
||||
- clocks : A list of phandle + clock-specifier pairs for the clocks listed in clock-names.
|
||||
- clock-names: Should contain the following:
|
||||
"core" - Main peripheral bus clock
|
||||
"clkin0" - Parent clock of internal mux
|
||||
"clkin1" - Other parent clock of internal mux
|
||||
The driver has an interal mux clock which switches between clkin0 and clkin1 depending on the
|
||||
clock rate requested by the MMC core.
|
||||
|
||||
Example:
|
||||
|
||||
sd_emmc_a: mmc@70000 {
|
||||
compatible = "amlogic,meson-gxbb-mmc";
|
||||
reg = <0x0 0x70000 0x0 0x2000>;
|
||||
interrupts = < GIC_SPI 216 IRQ_TYPE_EDGE_RISING>;
|
||||
clocks = <&clkc CLKID_SD_EMMC_A>, <&xtal>, <&clkc CLKID_FCLK_DIV2>;
|
||||
clock-names = "core", "clkin0", "clkin1";
|
||||
pinctrl-0 = <&emmc_pins>;
|
||||
};
|
||||
@@ -7,6 +7,15 @@ Required properties:
|
||||
- compatible : Should be one of the following
|
||||
"brcm,bcm2835-sdhci"
|
||||
"brcm,sdhci-iproc-cygnus"
|
||||
"brcm,sdhci-iproc"
|
||||
|
||||
Use brcm2835-sdhci for Rasperry PI.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -8,11 +8,14 @@ Required properties:
|
||||
|
||||
- compatible: should be "renesas,mmcif-<soctype>", "renesas,sh-mmcif" as a
|
||||
fallback. Examples with <soctype> are:
|
||||
- "renesas,mmcif-r8a73a4" for the MMCIF found in r8a73a4 SoCs
|
||||
- "renesas,mmcif-r8a7740" for the MMCIF found in r8a7740 SoCs
|
||||
- "renesas,mmcif-r8a7778" for the MMCIF found in r8a7778 SoCs
|
||||
- "renesas,mmcif-r8a7790" for the MMCIF found in r8a7790 SoCs
|
||||
- "renesas,mmcif-r8a7791" for the MMCIF found in r8a7791 SoCs
|
||||
- "renesas,mmcif-r8a7793" for the MMCIF found in r8a7793 SoCs
|
||||
- "renesas,mmcif-r8a7794" for the MMCIF found in r8a7794 SoCs
|
||||
- "renesas,mmcif-sh73a0" for the MMCIF found in sh73a0 SoCs
|
||||
|
||||
- clocks: reference to the functional clock
|
||||
|
||||
|
||||
30
Documentation/devicetree/bindings/mmc/sdhci-cadence.txt
Normal file
30
Documentation/devicetree/bindings/mmc/sdhci-cadence.txt
Normal file
@@ -0,0 +1,30 @@
|
||||
* Cadence SD/SDIO/eMMC Host Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "cdns,sd4hc".
|
||||
- reg: offset and length of the register set for the device.
|
||||
- interrupts: a single interrupt specifier.
|
||||
- clocks: phandle to the input clock.
|
||||
|
||||
Optional properties:
|
||||
For eMMC configuration, supported speed modes are not indicated by the SDHCI
|
||||
Capabilities Register. Instead, the following properties should be specified
|
||||
if supported. See mmc.txt for details.
|
||||
- mmc-ddr-1_8v
|
||||
- mmc-ddr-1_2v
|
||||
- mmc-hs200-1_8v
|
||||
- mmc-hs200-1_2v
|
||||
- mmc-hs400-1_8v
|
||||
- mmc-hs400-1_2v
|
||||
|
||||
Example:
|
||||
emmc: sdhci@5a000000 {
|
||||
compatible = "cdns,sd4hc";
|
||||
reg = <0x5a000000 0x400>;
|
||||
interrupts = <0 78 4>;
|
||||
clocks = <&clk 4>;
|
||||
bus-width = <8>;
|
||||
mmc-ddr-1_8v;
|
||||
mmc-hs200-1_8v;
|
||||
mmc-hs400-1_8v;
|
||||
};
|
||||
@@ -17,6 +17,7 @@ Required properties:
|
||||
"iface" - Main peripheral bus clock (PCLK/HCLK - AHB Bus clock) (required)
|
||||
"core" - SDC MMC clock (MCLK) (required)
|
||||
"bus" - SDCC bus voter clock (optional)
|
||||
"xo" - TCXO clock (optional)
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
13
Documentation/devicetree/bindings/mmc/sdhci.txt
Normal file
13
Documentation/devicetree/bindings/mmc/sdhci.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
The properties specific for SD host controllers. For properties shared by MMC
|
||||
host controllers refer to the mmc[1] bindings.
|
||||
|
||||
[1] Documentation/devicetree/bindings/mmc/mmc.txt
|
||||
|
||||
Optional properties:
|
||||
- sdhci-caps-mask: The sdhci capabilities register is incorrect. This 64bit
|
||||
property corresponds to the bits in the sdhci capabilty register. If the bit
|
||||
is on in the mask then the bit is incorrect in the register and should be
|
||||
turned off, before applying sdhci-caps.
|
||||
- sdhci-caps: The sdhci capabilities register is incorrect. This 64bit
|
||||
property corresponds to the bits in the sdhci capability register. If the
|
||||
bit is on in the property then the bit should be turned on.
|
||||
@@ -59,8 +59,9 @@ Optional properties:
|
||||
is specified and the ciu clock is specified then we'll try to set the ciu
|
||||
clock to this at probe time.
|
||||
|
||||
* clock-freq-min-max: Minimum and Maximum clock frequency for card output
|
||||
* clock-freq-min-max (DEPRECATED): Minimum and Maximum clock frequency for card output
|
||||
clock(cclk_out). If it's not specified, max is 200MHZ and min is 400KHz by default.
|
||||
(Use the "max-frequency" instead of "clock-freq-min-max".)
|
||||
|
||||
* num-slots: specifies the number of slots supported by the controller.
|
||||
The number of physical slots actually used could be equal or less than the
|
||||
@@ -74,11 +75,6 @@ Optional properties:
|
||||
* card-detect-delay: Delay in milli-seconds before detecting card after card
|
||||
insert event. The default value is 0.
|
||||
|
||||
* supports-highspeed (DEPRECATED): Enables support for high speed cards (up to 50MHz)
|
||||
(use "cap-mmc-highspeed" or "cap-sd-highspeed" instead)
|
||||
|
||||
* broken-cd: as documented in mmc core bindings.
|
||||
|
||||
* vmmc-supply: The phandle to the regulator to use for vmmc. If this is
|
||||
specified we'll defer probe until we can find this regulator.
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ optional bindings can be used.
|
||||
|
||||
Required properties:
|
||||
- compatible: "renesas,sdhi-shmobile" - a generic sh-mobile SDHI unit
|
||||
"renesas,sdhi-sh7372" - SDHI IP on SH7372 SoC
|
||||
"renesas,sdhi-sh73a0" - SDHI IP on SH73A0 SoC
|
||||
"renesas,sdhi-r7s72100" - SDHI IP on R7S72100 SoC
|
||||
"renesas,sdhi-r8a73a4" - SDHI IP on R8A73A4 SoC
|
||||
"renesas,sdhi-r8a7740" - SDHI IP on R8A7740 SoC
|
||||
"renesas,sdhi-r8a7778" - SDHI IP on R8A7778 SoC
|
||||
|
||||
@@ -25,6 +25,9 @@ Recommended properties:
|
||||
- fsl,liodn-bits : Indicates the number of defined bits in the LIODN
|
||||
registers, for those SOCs that have a PAMU device.
|
||||
|
||||
- little-endian : Indicates that the global utilities block is little
|
||||
endian. The default is big endian.
|
||||
|
||||
Examples:
|
||||
global-utilities@e0000 { /* global utilities block */
|
||||
compatible = "fsl,mpc8548-guts";
|
||||
14
MAINTAINERS
14
MAINTAINERS
@@ -1052,6 +1052,7 @@ F: arch/arm/mach-meson/
|
||||
F: arch/arm/boot/dts/meson*
|
||||
F: arch/arm64/boot/dts/amlogic/
|
||||
F: drivers/pinctrl/meson/
|
||||
F: drivers/mmc/host/meson*
|
||||
N: meson
|
||||
|
||||
ARM/Annapurna Labs ALPINE ARCHITECTURE
|
||||
@@ -5068,9 +5069,18 @@ S: Maintained
|
||||
F: drivers/net/ethernet/freescale/fman
|
||||
F: Documentation/devicetree/bindings/powerpc/fsl/fman.txt
|
||||
|
||||
FREESCALE QUICC ENGINE LIBRARY
|
||||
FREESCALE SOC DRIVERS
|
||||
M: Scott Wood <oss@buserror.net>
|
||||
L: linuxppc-dev@lists.ozlabs.org
|
||||
S: Orphan
|
||||
L: linux-arm-kernel@lists.infradead.org
|
||||
S: Maintained
|
||||
F: drivers/soc/fsl/
|
||||
F: include/linux/fsl/
|
||||
|
||||
FREESCALE QUICC ENGINE LIBRARY
|
||||
M: Qiang Zhao <qiang.zhao@nxp.com>
|
||||
L: linuxppc-dev@lists.ozlabs.org
|
||||
S: Maintained
|
||||
F: drivers/soc/fsl/qe/
|
||||
F: include/soc/fsl/*qe*.h
|
||||
F: include/soc/fsl/*ucc*.h
|
||||
|
||||
@@ -216,6 +216,12 @@
|
||||
clocks = <&sysclk>;
|
||||
};
|
||||
|
||||
dcfg: dcfg@1e00000 {
|
||||
compatible = "fsl,ls2080a-dcfg", "syscon";
|
||||
reg = <0x0 0x1e00000 0x0 0x10000>;
|
||||
little-endian;
|
||||
};
|
||||
|
||||
serial0: serial@21c0500 {
|
||||
compatible = "fsl,ns16550", "ns16550a";
|
||||
reg = <0x0 0x21c0500 0x0 0x100>;
|
||||
|
||||
@@ -237,6 +237,7 @@ config GENERIC_CPU_AUTOPROBE
|
||||
|
||||
config SOC_BUS
|
||||
bool
|
||||
select GLOB
|
||||
|
||||
source "drivers/base/regmap/Kconfig"
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/sys_soc.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/glob.h>
|
||||
|
||||
static DEFINE_IDA(soc_ida);
|
||||
|
||||
@@ -113,6 +114,12 @@ struct soc_device *soc_device_register(struct soc_device_attribute *soc_dev_attr
|
||||
struct soc_device *soc_dev;
|
||||
int ret;
|
||||
|
||||
if (!soc_bus_type.p) {
|
||||
ret = bus_register(&soc_bus_type);
|
||||
if (ret)
|
||||
goto out1;
|
||||
}
|
||||
|
||||
soc_dev = kzalloc(sizeof(*soc_dev), GFP_KERNEL);
|
||||
if (!soc_dev) {
|
||||
ret = -ENOMEM;
|
||||
@@ -156,6 +163,78 @@ void soc_device_unregister(struct soc_device *soc_dev)
|
||||
|
||||
static int __init soc_bus_register(void)
|
||||
{
|
||||
if (soc_bus_type.p)
|
||||
return 0;
|
||||
|
||||
return bus_register(&soc_bus_type);
|
||||
}
|
||||
core_initcall(soc_bus_register);
|
||||
|
||||
static int soc_device_match_one(struct device *dev, void *arg)
|
||||
{
|
||||
struct soc_device *soc_dev = container_of(dev, struct soc_device, dev);
|
||||
const struct soc_device_attribute *match = arg;
|
||||
|
||||
if (match->machine &&
|
||||
(!soc_dev->attr->machine ||
|
||||
!glob_match(match->machine, soc_dev->attr->machine)))
|
||||
return 0;
|
||||
|
||||
if (match->family &&
|
||||
(!soc_dev->attr->family ||
|
||||
!glob_match(match->family, soc_dev->attr->family)))
|
||||
return 0;
|
||||
|
||||
if (match->revision &&
|
||||
(!soc_dev->attr->revision ||
|
||||
!glob_match(match->revision, soc_dev->attr->revision)))
|
||||
return 0;
|
||||
|
||||
if (match->soc_id &&
|
||||
(!soc_dev->attr->soc_id ||
|
||||
!glob_match(match->soc_id, soc_dev->attr->soc_id)))
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* soc_device_match - identify the SoC in the machine
|
||||
* @matches: zero-terminated array of possible matches
|
||||
*
|
||||
* returns the first matching entry of the argument array, or NULL
|
||||
* if none of them match.
|
||||
*
|
||||
* This function is meant as a helper in place of of_match_node()
|
||||
* in cases where either no device tree is available or the information
|
||||
* in a device node is insufficient to identify a particular variant
|
||||
* by its compatible strings or other properties. For new devices,
|
||||
* the DT binding should always provide unique compatible strings
|
||||
* that allow the use of of_match_node() instead.
|
||||
*
|
||||
* The calling function can use the .data entry of the
|
||||
* soc_device_attribute to pass a structure or function pointer for
|
||||
* each entry.
|
||||
*/
|
||||
const struct soc_device_attribute *soc_device_match(
|
||||
const struct soc_device_attribute *matches)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (!matches)
|
||||
return NULL;
|
||||
|
||||
while (!ret) {
|
||||
if (!(matches->machine || matches->family ||
|
||||
matches->revision || matches->soc_id))
|
||||
break;
|
||||
ret = bus_for_each_dev(&soc_bus_type, NULL, (void *)matches,
|
||||
soc_device_match_one);
|
||||
if (!ret)
|
||||
matches++;
|
||||
else
|
||||
return matches;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(soc_device_match);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -214,7 +214,8 @@ static void mmc_test_prepare_mrq(struct mmc_test_card *test,
|
||||
struct mmc_request *mrq, struct scatterlist *sg, unsigned sg_len,
|
||||
unsigned dev_addr, unsigned blocks, unsigned blksz, int write)
|
||||
{
|
||||
BUG_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop);
|
||||
if (WARN_ON(!mrq || !mrq->cmd || !mrq->data || !mrq->stop))
|
||||
return;
|
||||
|
||||
if (blocks > 1) {
|
||||
mrq->cmd->opcode = write ?
|
||||
@@ -694,7 +695,8 @@ static int mmc_test_cleanup(struct mmc_test_card *test)
|
||||
static void mmc_test_prepare_broken_mrq(struct mmc_test_card *test,
|
||||
struct mmc_request *mrq, int write)
|
||||
{
|
||||
BUG_ON(!mrq || !mrq->cmd || !mrq->data);
|
||||
if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
|
||||
return;
|
||||
|
||||
if (mrq->data->blocks > 1) {
|
||||
mrq->cmd->opcode = write ?
|
||||
@@ -714,7 +716,8 @@ static int mmc_test_check_result(struct mmc_test_card *test,
|
||||
{
|
||||
int ret;
|
||||
|
||||
BUG_ON(!mrq || !mrq->cmd || !mrq->data);
|
||||
if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
|
||||
return -EINVAL;
|
||||
|
||||
ret = 0;
|
||||
|
||||
@@ -736,15 +739,28 @@ static int mmc_test_check_result(struct mmc_test_card *test,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mmc_test_check_result_async(struct mmc_card *card,
|
||||
static enum mmc_blk_status mmc_test_check_result_async(struct mmc_card *card,
|
||||
struct mmc_async_req *areq)
|
||||
{
|
||||
struct mmc_test_async_req *test_async =
|
||||
container_of(areq, struct mmc_test_async_req, areq);
|
||||
int ret;
|
||||
|
||||
mmc_test_wait_busy(test_async->test);
|
||||
|
||||
return mmc_test_check_result(test_async->test, areq->mrq);
|
||||
/*
|
||||
* FIXME: this would earlier just casts a regular error code,
|
||||
* either of the kernel type -ERRORCODE or the local test framework
|
||||
* RESULT_* errorcode, into an enum mmc_blk_status and return as
|
||||
* result check. Instead, convert it to some reasonable type by just
|
||||
* returning either MMC_BLK_SUCCESS or MMC_BLK_CMD_ERR.
|
||||
* If possible, a reasonable error code should be returned.
|
||||
*/
|
||||
ret = mmc_test_check_result(test_async->test, areq->mrq);
|
||||
if (ret)
|
||||
return MMC_BLK_CMD_ERR;
|
||||
|
||||
return MMC_BLK_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -755,7 +771,8 @@ static int mmc_test_check_broken_result(struct mmc_test_card *test,
|
||||
{
|
||||
int ret;
|
||||
|
||||
BUG_ON(!mrq || !mrq->cmd || !mrq->data);
|
||||
if (WARN_ON(!mrq || !mrq->cmd || !mrq->data))
|
||||
return -EINVAL;
|
||||
|
||||
ret = 0;
|
||||
|
||||
@@ -817,8 +834,9 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
|
||||
struct mmc_async_req *done_areq;
|
||||
struct mmc_async_req *cur_areq = &test_areq[0].areq;
|
||||
struct mmc_async_req *other_areq = &test_areq[1].areq;
|
||||
enum mmc_blk_status status;
|
||||
int i;
|
||||
int ret;
|
||||
int ret = RESULT_OK;
|
||||
|
||||
test_areq[0].test = test;
|
||||
test_areq[1].test = test;
|
||||
@@ -834,10 +852,12 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
|
||||
for (i = 0; i < count; i++) {
|
||||
mmc_test_prepare_mrq(test, cur_areq->mrq, sg, sg_len, dev_addr,
|
||||
blocks, blksz, write);
|
||||
done_areq = mmc_start_req(test->card->host, cur_areq, &ret);
|
||||
done_areq = mmc_start_req(test->card->host, cur_areq, &status);
|
||||
|
||||
if (ret || (!done_areq && i > 0))
|
||||
if (status != MMC_BLK_SUCCESS || (!done_areq && i > 0)) {
|
||||
ret = RESULT_FAIL;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (done_areq) {
|
||||
if (done_areq->mrq == &mrq2)
|
||||
@@ -851,7 +871,9 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
|
||||
dev_addr += blocks;
|
||||
}
|
||||
|
||||
done_areq = mmc_start_req(test->card->host, NULL, &ret);
|
||||
done_areq = mmc_start_req(test->card->host, NULL, &status);
|
||||
if (status != MMC_BLK_SUCCESS)
|
||||
ret = RESULT_FAIL;
|
||||
|
||||
return ret;
|
||||
err:
|
||||
@@ -2351,6 +2373,7 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
|
||||
struct mmc_request *mrq;
|
||||
unsigned long timeout;
|
||||
bool expired = false;
|
||||
enum mmc_blk_status blkstat = MMC_BLK_SUCCESS;
|
||||
int ret = 0, cmd_ret;
|
||||
u32 status = 0;
|
||||
int count = 0;
|
||||
@@ -2378,9 +2401,11 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
|
||||
|
||||
/* Start ongoing data request */
|
||||
if (use_areq) {
|
||||
mmc_start_req(host, &test_areq.areq, &ret);
|
||||
if (ret)
|
||||
mmc_start_req(host, &test_areq.areq, &blkstat);
|
||||
if (blkstat != MMC_BLK_SUCCESS) {
|
||||
ret = RESULT_FAIL;
|
||||
goto out_free;
|
||||
}
|
||||
} else {
|
||||
mmc_wait_for_req(host, mrq);
|
||||
}
|
||||
@@ -2413,10 +2438,13 @@ static int mmc_test_ongoing_transfer(struct mmc_test_card *test,
|
||||
} while (repeat_cmd && R1_CURRENT_STATE(status) != R1_STATE_TRAN);
|
||||
|
||||
/* Wait for data request to complete */
|
||||
if (use_areq)
|
||||
mmc_start_req(host, NULL, &ret);
|
||||
else
|
||||
if (use_areq) {
|
||||
mmc_start_req(host, NULL, &blkstat);
|
||||
if (blkstat != MMC_BLK_SUCCESS)
|
||||
ret = RESULT_FAIL;
|
||||
} else {
|
||||
mmc_wait_for_req_done(test->card->host, mrq);
|
||||
}
|
||||
|
||||
/*
|
||||
* For cap_cmd_during_tfr request, upper layer must send stop if
|
||||
|
||||
@@ -53,6 +53,7 @@ static int mmc_queue_thread(void *d)
|
||||
{
|
||||
struct mmc_queue *mq = d;
|
||||
struct request_queue *q = mq->queue;
|
||||
struct mmc_context_info *cntx = &mq->card->host->context_info;
|
||||
|
||||
current->flags |= PF_MEMALLOC;
|
||||
|
||||
@@ -63,6 +64,19 @@ static int mmc_queue_thread(void *d)
|
||||
spin_lock_irq(q->queue_lock);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
req = blk_fetch_request(q);
|
||||
mq->asleep = false;
|
||||
cntx->is_waiting_last_req = false;
|
||||
cntx->is_new_req = false;
|
||||
if (!req) {
|
||||
/*
|
||||
* Dispatch queue is empty so set flags for
|
||||
* mmc_request_fn() to wake us up.
|
||||
*/
|
||||
if (mq->mqrq_prev->req)
|
||||
cntx->is_waiting_last_req = true;
|
||||
else
|
||||
mq->asleep = true;
|
||||
}
|
||||
mq->mqrq_cur->req = req;
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
|
||||
@@ -115,7 +129,6 @@ static void mmc_request_fn(struct request_queue *q)
|
||||
{
|
||||
struct mmc_queue *mq = q->queuedata;
|
||||
struct request *req;
|
||||
unsigned long flags;
|
||||
struct mmc_context_info *cntx;
|
||||
|
||||
if (!mq) {
|
||||
@@ -127,19 +140,13 @@ static void mmc_request_fn(struct request_queue *q)
|
||||
}
|
||||
|
||||
cntx = &mq->card->host->context_info;
|
||||
if (!mq->mqrq_cur->req && mq->mqrq_prev->req) {
|
||||
/*
|
||||
* New MMC request arrived when MMC thread may be
|
||||
* blocked on the previous request to be complete
|
||||
* with no current request fetched
|
||||
*/
|
||||
spin_lock_irqsave(&cntx->lock, flags);
|
||||
if (cntx->is_waiting_last_req) {
|
||||
cntx->is_new_req = true;
|
||||
wake_up_interruptible(&cntx->wait);
|
||||
}
|
||||
spin_unlock_irqrestore(&cntx->lock, flags);
|
||||
} else if (!mq->mqrq_cur->req && !mq->mqrq_prev->req)
|
||||
|
||||
if (cntx->is_waiting_last_req) {
|
||||
cntx->is_new_req = true;
|
||||
wake_up_interruptible(&cntx->wait);
|
||||
}
|
||||
|
||||
if (mq->asleep)
|
||||
wake_up_process(mq->thread);
|
||||
}
|
||||
|
||||
@@ -179,6 +186,82 @@ static void mmc_queue_setup_discard(struct request_queue *q,
|
||||
queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_MMC_BLOCK_BOUNCE
|
||||
static bool mmc_queue_alloc_bounce_bufs(struct mmc_queue *mq,
|
||||
unsigned int bouncesz)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mq->qdepth; i++) {
|
||||
mq->mqrq[i].bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
|
||||
if (!mq->mqrq[i].bounce_buf)
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
out_err:
|
||||
while (--i >= 0) {
|
||||
kfree(mq->mqrq[i].bounce_buf);
|
||||
mq->mqrq[i].bounce_buf = NULL;
|
||||
}
|
||||
pr_warn("%s: unable to allocate bounce buffers\n",
|
||||
mmc_card_name(mq->card));
|
||||
return false;
|
||||
}
|
||||
|
||||
static int mmc_queue_alloc_bounce_sgs(struct mmc_queue *mq,
|
||||
unsigned int bouncesz)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < mq->qdepth; i++) {
|
||||
mq->mqrq[i].sg = mmc_alloc_sg(1, &ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mq->mqrq[i].bounce_sg = mmc_alloc_sg(bouncesz / 512, &ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int mmc_queue_alloc_sgs(struct mmc_queue *mq, int max_segs)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
for (i = 0; i < mq->qdepth; i++) {
|
||||
mq->mqrq[i].sg = mmc_alloc_sg(max_segs, &ret);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mmc_queue_req_free_bufs(struct mmc_queue_req *mqrq)
|
||||
{
|
||||
kfree(mqrq->bounce_sg);
|
||||
mqrq->bounce_sg = NULL;
|
||||
|
||||
kfree(mqrq->sg);
|
||||
mqrq->sg = NULL;
|
||||
|
||||
kfree(mqrq->bounce_buf);
|
||||
mqrq->bounce_buf = NULL;
|
||||
}
|
||||
|
||||
static void mmc_queue_reqs_free_bufs(struct mmc_queue *mq)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < mq->qdepth; i++)
|
||||
mmc_queue_req_free_bufs(&mq->mqrq[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_init_queue - initialise a queue structure.
|
||||
* @mq: mmc queue
|
||||
@@ -193,9 +276,8 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
|
||||
{
|
||||
struct mmc_host *host = card->host;
|
||||
u64 limit = BLK_BOUNCE_HIGH;
|
||||
int ret;
|
||||
struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
|
||||
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
|
||||
bool bounce = false;
|
||||
int ret = -ENOMEM;
|
||||
|
||||
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
|
||||
limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;
|
||||
@@ -205,8 +287,13 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
|
||||
if (!mq->queue)
|
||||
return -ENOMEM;
|
||||
|
||||
mq->mqrq_cur = mqrq_cur;
|
||||
mq->mqrq_prev = mqrq_prev;
|
||||
mq->qdepth = 2;
|
||||
mq->mqrq = kcalloc(mq->qdepth, sizeof(struct mmc_queue_req),
|
||||
GFP_KERNEL);
|
||||
if (!mq->mqrq)
|
||||
goto blk_cleanup;
|
||||
mq->mqrq_cur = &mq->mqrq[0];
|
||||
mq->mqrq_prev = &mq->mqrq[1];
|
||||
mq->queue->queuedata = mq;
|
||||
|
||||
blk_queue_prep_rq(mq->queue, mmc_prep_request);
|
||||
@@ -228,63 +315,29 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
|
||||
if (bouncesz > (host->max_blk_count * 512))
|
||||
bouncesz = host->max_blk_count * 512;
|
||||
|
||||
if (bouncesz > 512) {
|
||||
mqrq_cur->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
|
||||
if (!mqrq_cur->bounce_buf) {
|
||||
pr_warn("%s: unable to allocate bounce cur buffer\n",
|
||||
mmc_card_name(card));
|
||||
} else {
|
||||
mqrq_prev->bounce_buf =
|
||||
kmalloc(bouncesz, GFP_KERNEL);
|
||||
if (!mqrq_prev->bounce_buf) {
|
||||
pr_warn("%s: unable to allocate bounce prev buffer\n",
|
||||
mmc_card_name(card));
|
||||
kfree(mqrq_cur->bounce_buf);
|
||||
mqrq_cur->bounce_buf = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mqrq_cur->bounce_buf && mqrq_prev->bounce_buf) {
|
||||
if (bouncesz > 512 &&
|
||||
mmc_queue_alloc_bounce_bufs(mq, bouncesz)) {
|
||||
blk_queue_bounce_limit(mq->queue, BLK_BOUNCE_ANY);
|
||||
blk_queue_max_hw_sectors(mq->queue, bouncesz / 512);
|
||||
blk_queue_max_segments(mq->queue, bouncesz / 512);
|
||||
blk_queue_max_segment_size(mq->queue, bouncesz);
|
||||
|
||||
mqrq_cur->sg = mmc_alloc_sg(1, &ret);
|
||||
if (ret)
|
||||
goto cleanup_queue;
|
||||
|
||||
mqrq_cur->bounce_sg =
|
||||
mmc_alloc_sg(bouncesz / 512, &ret);
|
||||
if (ret)
|
||||
goto cleanup_queue;
|
||||
|
||||
mqrq_prev->sg = mmc_alloc_sg(1, &ret);
|
||||
if (ret)
|
||||
goto cleanup_queue;
|
||||
|
||||
mqrq_prev->bounce_sg =
|
||||
mmc_alloc_sg(bouncesz / 512, &ret);
|
||||
ret = mmc_queue_alloc_bounce_sgs(mq, bouncesz);
|
||||
if (ret)
|
||||
goto cleanup_queue;
|
||||
bounce = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!mqrq_cur->bounce_buf && !mqrq_prev->bounce_buf) {
|
||||
if (!bounce) {
|
||||
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);
|
||||
|
||||
mqrq_cur->sg = mmc_alloc_sg(host->max_segs, &ret);
|
||||
if (ret)
|
||||
goto cleanup_queue;
|
||||
|
||||
|
||||
mqrq_prev->sg = mmc_alloc_sg(host->max_segs, &ret);
|
||||
ret = mmc_queue_alloc_sgs(mq, host->max_segs);
|
||||
if (ret)
|
||||
goto cleanup_queue;
|
||||
}
|
||||
@@ -296,27 +349,16 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
|
||||
|
||||
if (IS_ERR(mq->thread)) {
|
||||
ret = PTR_ERR(mq->thread);
|
||||
goto free_bounce_sg;
|
||||
goto cleanup_queue;
|
||||
}
|
||||
|
||||
return 0;
|
||||
free_bounce_sg:
|
||||
kfree(mqrq_cur->bounce_sg);
|
||||
mqrq_cur->bounce_sg = NULL;
|
||||
kfree(mqrq_prev->bounce_sg);
|
||||
mqrq_prev->bounce_sg = NULL;
|
||||
|
||||
cleanup_queue:
|
||||
kfree(mqrq_cur->sg);
|
||||
mqrq_cur->sg = NULL;
|
||||
kfree(mqrq_cur->bounce_buf);
|
||||
mqrq_cur->bounce_buf = NULL;
|
||||
|
||||
kfree(mqrq_prev->sg);
|
||||
mqrq_prev->sg = NULL;
|
||||
kfree(mqrq_prev->bounce_buf);
|
||||
mqrq_prev->bounce_buf = NULL;
|
||||
|
||||
mmc_queue_reqs_free_bufs(mq);
|
||||
kfree(mq->mqrq);
|
||||
mq->mqrq = NULL;
|
||||
blk_cleanup:
|
||||
blk_cleanup_queue(mq->queue);
|
||||
return ret;
|
||||
}
|
||||
@@ -325,8 +367,6 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
|
||||
{
|
||||
struct request_queue *q = mq->queue;
|
||||
unsigned long flags;
|
||||
struct mmc_queue_req *mqrq_cur = mq->mqrq_cur;
|
||||
struct mmc_queue_req *mqrq_prev = mq->mqrq_prev;
|
||||
|
||||
/* Make sure the queue isn't suspended, as that will deadlock */
|
||||
mmc_queue_resume(mq);
|
||||
@@ -340,71 +380,14 @@ void mmc_cleanup_queue(struct mmc_queue *mq)
|
||||
blk_start_queue(q);
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
|
||||
kfree(mqrq_cur->bounce_sg);
|
||||
mqrq_cur->bounce_sg = NULL;
|
||||
|
||||
kfree(mqrq_cur->sg);
|
||||
mqrq_cur->sg = NULL;
|
||||
|
||||
kfree(mqrq_cur->bounce_buf);
|
||||
mqrq_cur->bounce_buf = NULL;
|
||||
|
||||
kfree(mqrq_prev->bounce_sg);
|
||||
mqrq_prev->bounce_sg = NULL;
|
||||
|
||||
kfree(mqrq_prev->sg);
|
||||
mqrq_prev->sg = NULL;
|
||||
|
||||
kfree(mqrq_prev->bounce_buf);
|
||||
mqrq_prev->bounce_buf = NULL;
|
||||
mmc_queue_reqs_free_bufs(mq);
|
||||
kfree(mq->mqrq);
|
||||
mq->mqrq = NULL;
|
||||
|
||||
mq->card = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_cleanup_queue);
|
||||
|
||||
int mmc_packed_init(struct mmc_queue *mq, struct mmc_card *card)
|
||||
{
|
||||
struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
|
||||
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
|
||||
int ret = 0;
|
||||
|
||||
|
||||
mqrq_cur->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
|
||||
if (!mqrq_cur->packed) {
|
||||
pr_warn("%s: unable to allocate packed cmd for mqrq_cur\n",
|
||||
mmc_card_name(card));
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
mqrq_prev->packed = kzalloc(sizeof(struct mmc_packed), GFP_KERNEL);
|
||||
if (!mqrq_prev->packed) {
|
||||
pr_warn("%s: unable to allocate packed cmd for mqrq_prev\n",
|
||||
mmc_card_name(card));
|
||||
kfree(mqrq_cur->packed);
|
||||
mqrq_cur->packed = NULL;
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&mqrq_cur->packed->list);
|
||||
INIT_LIST_HEAD(&mqrq_prev->packed->list);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void mmc_packed_clean(struct mmc_queue *mq)
|
||||
{
|
||||
struct mmc_queue_req *mqrq_cur = &mq->mqrq[0];
|
||||
struct mmc_queue_req *mqrq_prev = &mq->mqrq[1];
|
||||
|
||||
kfree(mqrq_cur->packed);
|
||||
mqrq_cur->packed = NULL;
|
||||
kfree(mqrq_prev->packed);
|
||||
mqrq_prev->packed = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* mmc_queue_suspend - suspend a MMC request queue
|
||||
* @mq: MMC queue to suspend
|
||||
@@ -449,41 +432,6 @@ void mmc_queue_resume(struct mmc_queue *mq)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int mmc_queue_packed_map_sg(struct mmc_queue *mq,
|
||||
struct mmc_packed *packed,
|
||||
struct scatterlist *sg,
|
||||
enum mmc_packed_type cmd_type)
|
||||
{
|
||||
struct scatterlist *__sg = sg;
|
||||
unsigned int sg_len = 0;
|
||||
struct request *req;
|
||||
|
||||
if (mmc_packed_wr(cmd_type)) {
|
||||
unsigned int hdr_sz = mmc_large_sector(mq->card) ? 4096 : 512;
|
||||
unsigned int max_seg_sz = queue_max_segment_size(mq->queue);
|
||||
unsigned int len, remain, offset = 0;
|
||||
u8 *buf = (u8 *)packed->cmd_hdr;
|
||||
|
||||
remain = hdr_sz;
|
||||
do {
|
||||
len = min(remain, max_seg_sz);
|
||||
sg_set_buf(__sg, buf + offset, len);
|
||||
offset += len;
|
||||
remain -= len;
|
||||
sg_unmark_end(__sg++);
|
||||
sg_len++;
|
||||
} while (remain);
|
||||
}
|
||||
|
||||
list_for_each_entry(req, &packed->list, queuelist) {
|
||||
sg_len += blk_rq_map_sg(mq->queue, req, __sg);
|
||||
__sg = sg + (sg_len - 1);
|
||||
sg_unmark_end(__sg++);
|
||||
}
|
||||
sg_mark_end(sg + (sg_len - 1));
|
||||
return sg_len;
|
||||
}
|
||||
|
||||
/*
|
||||
* Prepare the sg list(s) to be handed of to the host driver
|
||||
*/
|
||||
@@ -492,26 +440,12 @@ unsigned int mmc_queue_map_sg(struct mmc_queue *mq, struct mmc_queue_req *mqrq)
|
||||
unsigned int sg_len;
|
||||
size_t buflen;
|
||||
struct scatterlist *sg;
|
||||
enum mmc_packed_type cmd_type;
|
||||
int i;
|
||||
|
||||
cmd_type = mqrq->cmd_type;
|
||||
if (!mqrq->bounce_buf)
|
||||
return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
|
||||
|
||||
if (!mqrq->bounce_buf) {
|
||||
if (mmc_packed_cmd(cmd_type))
|
||||
return mmc_queue_packed_map_sg(mq, mqrq->packed,
|
||||
mqrq->sg, cmd_type);
|
||||
else
|
||||
return blk_rq_map_sg(mq->queue, mqrq->req, mqrq->sg);
|
||||
}
|
||||
|
||||
BUG_ON(!mqrq->bounce_sg);
|
||||
|
||||
if (mmc_packed_cmd(cmd_type))
|
||||
sg_len = mmc_queue_packed_map_sg(mq, mqrq->packed,
|
||||
mqrq->bounce_sg, cmd_type);
|
||||
else
|
||||
sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
|
||||
sg_len = blk_rq_map_sg(mq->queue, mqrq->req, mqrq->bounce_sg);
|
||||
|
||||
mqrq->bounce_sg_len = sg_len;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ static inline bool mmc_req_is_special(struct request *req)
|
||||
|
||||
struct request;
|
||||
struct task_struct;
|
||||
struct mmc_blk_data;
|
||||
|
||||
struct mmc_blk_request {
|
||||
struct mmc_request mrq;
|
||||
@@ -21,23 +22,6 @@ struct mmc_blk_request {
|
||||
int retune_retry_done;
|
||||
};
|
||||
|
||||
enum mmc_packed_type {
|
||||
MMC_PACKED_NONE = 0,
|
||||
MMC_PACKED_WRITE,
|
||||
};
|
||||
|
||||
#define mmc_packed_cmd(type) ((type) != MMC_PACKED_NONE)
|
||||
#define mmc_packed_wr(type) ((type) == MMC_PACKED_WRITE)
|
||||
|
||||
struct mmc_packed {
|
||||
struct list_head list;
|
||||
__le32 cmd_hdr[1024];
|
||||
unsigned int blocks;
|
||||
u8 nr_entries;
|
||||
u8 retries;
|
||||
s16 idx_failure;
|
||||
};
|
||||
|
||||
struct mmc_queue_req {
|
||||
struct request *req;
|
||||
struct mmc_blk_request brq;
|
||||
@@ -46,8 +30,6 @@ struct mmc_queue_req {
|
||||
struct scatterlist *bounce_sg;
|
||||
unsigned int bounce_sg_len;
|
||||
struct mmc_async_req mmc_active;
|
||||
enum mmc_packed_type cmd_type;
|
||||
struct mmc_packed *packed;
|
||||
};
|
||||
|
||||
struct mmc_queue {
|
||||
@@ -57,11 +39,13 @@ struct mmc_queue {
|
||||
unsigned int flags;
|
||||
#define MMC_QUEUE_SUSPENDED (1 << 0)
|
||||
#define MMC_QUEUE_NEW_REQUEST (1 << 1)
|
||||
void *data;
|
||||
bool asleep;
|
||||
struct mmc_blk_data *blkdata;
|
||||
struct request_queue *queue;
|
||||
struct mmc_queue_req mqrq[2];
|
||||
struct mmc_queue_req *mqrq;
|
||||
struct mmc_queue_req *mqrq_cur;
|
||||
struct mmc_queue_req *mqrq_prev;
|
||||
int qdepth;
|
||||
};
|
||||
|
||||
extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
|
||||
@@ -75,9 +59,6 @@ extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
|
||||
extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
|
||||
extern void mmc_queue_bounce_post(struct mmc_queue_req *);
|
||||
|
||||
extern int mmc_packed_init(struct mmc_queue *, struct mmc_card *);
|
||||
extern void mmc_packed_clean(struct mmc_queue *);
|
||||
|
||||
extern int mmc_access_rpmb(struct mmc_queue *);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -135,8 +135,6 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port)
|
||||
{
|
||||
struct sdio_func *func;
|
||||
|
||||
BUG_ON(sdio_uart_table[port->index] != port);
|
||||
|
||||
spin_lock(&sdio_uart_table_lock);
|
||||
sdio_uart_table[port->index] = NULL;
|
||||
spin_unlock(&sdio_uart_table_lock);
|
||||
|
||||
@@ -306,16 +306,16 @@ static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
|
||||
mrq->sbc->mrq = mrq;
|
||||
}
|
||||
if (mrq->data) {
|
||||
BUG_ON(mrq->data->blksz > host->max_blk_size);
|
||||
BUG_ON(mrq->data->blocks > host->max_blk_count);
|
||||
BUG_ON(mrq->data->blocks * mrq->data->blksz >
|
||||
host->max_req_size);
|
||||
|
||||
if (mrq->data->blksz > host->max_blk_size ||
|
||||
mrq->data->blocks > host->max_blk_count ||
|
||||
mrq->data->blocks * mrq->data->blksz > host->max_req_size)
|
||||
return -EINVAL;
|
||||
#ifdef CONFIG_MMC_DEBUG
|
||||
sz = 0;
|
||||
for_each_sg(mrq->data->sg, sg, mrq->data->sg_len, i)
|
||||
sz += sg->length;
|
||||
BUG_ON(sz != mrq->data->blocks * mrq->data->blksz);
|
||||
if (sz != mrq->data->blocks * mrq->data->blksz)
|
||||
return -EINVAL;
|
||||
#endif
|
||||
|
||||
mrq->cmd->data = mrq->data;
|
||||
@@ -349,8 +349,6 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
|
||||
int timeout;
|
||||
bool use_busy_signal;
|
||||
|
||||
BUG_ON(!card);
|
||||
|
||||
if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card))
|
||||
return;
|
||||
|
||||
@@ -380,7 +378,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
|
||||
mmc_retune_hold(card->host);
|
||||
|
||||
err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
|
||||
EXT_CSD_BKOPS_START, 1, timeout,
|
||||
EXT_CSD_BKOPS_START, 1, timeout, 0,
|
||||
use_busy_signal, true, false);
|
||||
if (err) {
|
||||
pr_warn("%s: Error %d starting bkops\n",
|
||||
@@ -497,32 +495,28 @@ static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
*
|
||||
* Returns enum mmc_blk_status after checking errors.
|
||||
*/
|
||||
static int mmc_wait_for_data_req_done(struct mmc_host *host,
|
||||
static enum mmc_blk_status mmc_wait_for_data_req_done(struct mmc_host *host,
|
||||
struct mmc_request *mrq,
|
||||
struct mmc_async_req *next_req)
|
||||
{
|
||||
struct mmc_command *cmd;
|
||||
struct mmc_context_info *context_info = &host->context_info;
|
||||
int err;
|
||||
unsigned long flags;
|
||||
enum mmc_blk_status status;
|
||||
|
||||
while (1) {
|
||||
wait_event_interruptible(context_info->wait,
|
||||
(context_info->is_done_rcv ||
|
||||
context_info->is_new_req));
|
||||
spin_lock_irqsave(&context_info->lock, flags);
|
||||
context_info->is_waiting_last_req = false;
|
||||
spin_unlock_irqrestore(&context_info->lock, flags);
|
||||
if (context_info->is_done_rcv) {
|
||||
context_info->is_done_rcv = false;
|
||||
context_info->is_new_req = false;
|
||||
cmd = mrq->cmd;
|
||||
|
||||
if (!cmd->error || !cmd->retries ||
|
||||
mmc_card_removed(host->card)) {
|
||||
err = host->areq->err_check(host->card,
|
||||
host->areq);
|
||||
break; /* return err */
|
||||
status = host->areq->err_check(host->card,
|
||||
host->areq);
|
||||
break; /* return status */
|
||||
} else {
|
||||
mmc_retune_recheck(host);
|
||||
pr_info("%s: req failed (CMD%u): %d, retrying...\n",
|
||||
@@ -534,13 +528,12 @@ static int mmc_wait_for_data_req_done(struct mmc_host *host,
|
||||
continue; /* wait for done/new event again */
|
||||
}
|
||||
} else if (context_info->is_new_req) {
|
||||
context_info->is_new_req = false;
|
||||
if (!next_req)
|
||||
return MMC_BLK_NEW_REQUEST;
|
||||
}
|
||||
}
|
||||
mmc_retune_release(host);
|
||||
return err;
|
||||
return status;
|
||||
}
|
||||
|
||||
void mmc_wait_for_req_done(struct mmc_host *host, struct mmc_request *mrq)
|
||||
@@ -611,18 +604,15 @@ EXPORT_SYMBOL(mmc_is_req_done);
|
||||
* mmc_pre_req - Prepare for a new request
|
||||
* @host: MMC host to prepare command
|
||||
* @mrq: MMC request to prepare for
|
||||
* @is_first_req: true if there is no previous started request
|
||||
* that may run in parellel to this call, otherwise false
|
||||
*
|
||||
* mmc_pre_req() is called in prior to mmc_start_req() to let
|
||||
* host prepare for the new request. Preparation of a request may be
|
||||
* performed while another request is running on the host.
|
||||
*/
|
||||
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq,
|
||||
bool is_first_req)
|
||||
static void mmc_pre_req(struct mmc_host *host, struct mmc_request *mrq)
|
||||
{
|
||||
if (host->ops->pre_req)
|
||||
host->ops->pre_req(host, mrq, is_first_req);
|
||||
host->ops->pre_req(host, mrq);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -658,21 +648,22 @@ static void mmc_post_req(struct mmc_host *host, struct mmc_request *mrq,
|
||||
* is returned without waiting. NULL is not an error condition.
|
||||
*/
|
||||
struct mmc_async_req *mmc_start_req(struct mmc_host *host,
|
||||
struct mmc_async_req *areq, int *error)
|
||||
struct mmc_async_req *areq,
|
||||
enum mmc_blk_status *ret_stat)
|
||||
{
|
||||
int err = 0;
|
||||
enum mmc_blk_status status = MMC_BLK_SUCCESS;
|
||||
int start_err = 0;
|
||||
struct mmc_async_req *data = host->areq;
|
||||
|
||||
/* Prepare a new request */
|
||||
if (areq)
|
||||
mmc_pre_req(host, areq->mrq, !host->areq);
|
||||
mmc_pre_req(host, areq->mrq);
|
||||
|
||||
if (host->areq) {
|
||||
err = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
|
||||
if (err == MMC_BLK_NEW_REQUEST) {
|
||||
if (error)
|
||||
*error = err;
|
||||
status = mmc_wait_for_data_req_done(host, host->areq->mrq, areq);
|
||||
if (status == MMC_BLK_NEW_REQUEST) {
|
||||
if (ret_stat)
|
||||
*ret_stat = status;
|
||||
/*
|
||||
* The previous request was not completed,
|
||||
* nothing to return
|
||||
@@ -695,27 +686,27 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
|
||||
|
||||
/* prepare the request again */
|
||||
if (areq)
|
||||
mmc_pre_req(host, areq->mrq, !host->areq);
|
||||
mmc_pre_req(host, areq->mrq);
|
||||
}
|
||||
}
|
||||
|
||||
if (!err && areq)
|
||||
if (status == MMC_BLK_SUCCESS && areq)
|
||||
start_err = __mmc_start_data_req(host, areq->mrq);
|
||||
|
||||
if (host->areq)
|
||||
mmc_post_req(host, host->areq->mrq, 0);
|
||||
|
||||
/* Cancel a prepared request if it was not started. */
|
||||
if ((err || start_err) && areq)
|
||||
if ((status != MMC_BLK_SUCCESS || start_err) && areq)
|
||||
mmc_post_req(host, areq->mrq, -EINVAL);
|
||||
|
||||
if (err)
|
||||
if (status != MMC_BLK_SUCCESS)
|
||||
host->areq = NULL;
|
||||
else
|
||||
host->areq = areq;
|
||||
|
||||
if (error)
|
||||
*error = err;
|
||||
if (ret_stat)
|
||||
*ret_stat = status;
|
||||
return data;
|
||||
}
|
||||
EXPORT_SYMBOL(mmc_start_req);
|
||||
@@ -754,8 +745,6 @@ int mmc_interrupt_hpi(struct mmc_card *card)
|
||||
u32 status;
|
||||
unsigned long prg_wait;
|
||||
|
||||
BUG_ON(!card);
|
||||
|
||||
if (!card->ext_csd.hpi_en) {
|
||||
pr_info("%s: HPI enable bit unset\n", mmc_hostname(card->host));
|
||||
return 1;
|
||||
@@ -850,7 +839,6 @@ int mmc_stop_bkops(struct mmc_card *card)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
BUG_ON(!card);
|
||||
err = mmc_interrupt_hpi(card);
|
||||
|
||||
/*
|
||||
@@ -1666,8 +1654,6 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
|
||||
int err = 0;
|
||||
u32 clock;
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
/*
|
||||
* Send CMD11 only if the request is to switch the card to
|
||||
* 1.8V signalling.
|
||||
@@ -1884,9 +1870,7 @@ void mmc_power_cycle(struct mmc_host *host, u32 ocr)
|
||||
*/
|
||||
static void __mmc_release_bus(struct mmc_host *host)
|
||||
{
|
||||
BUG_ON(!host);
|
||||
BUG_ON(host->bus_refs);
|
||||
BUG_ON(!host->bus_dead);
|
||||
WARN_ON(!host->bus_dead);
|
||||
|
||||
host->bus_ops = NULL;
|
||||
}
|
||||
@@ -1926,15 +1910,12 @@ void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(!host);
|
||||
BUG_ON(!ops);
|
||||
|
||||
WARN_ON(!host->claimed);
|
||||
|
||||
spin_lock_irqsave(&host->lock, flags);
|
||||
|
||||
BUG_ON(host->bus_ops);
|
||||
BUG_ON(host->bus_refs);
|
||||
WARN_ON(host->bus_ops);
|
||||
WARN_ON(host->bus_refs);
|
||||
|
||||
host->bus_ops = ops;
|
||||
host->bus_refs = 1;
|
||||
@@ -1950,8 +1931,6 @@ void mmc_detach_bus(struct mmc_host *host)
|
||||
{
|
||||
unsigned long flags;
|
||||
|
||||
BUG_ON(!host);
|
||||
|
||||
WARN_ON(!host->claimed);
|
||||
WARN_ON(!host->bus_ops);
|
||||
|
||||
@@ -2824,12 +2803,11 @@ void mmc_start_host(struct mmc_host *host)
|
||||
host->rescan_disable = 0;
|
||||
host->ios.power_mode = MMC_POWER_UNDEFINED;
|
||||
|
||||
mmc_claim_host(host);
|
||||
if (host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)
|
||||
mmc_power_off(host);
|
||||
else
|
||||
if (!(host->caps2 & MMC_CAP2_NO_PRESCAN_POWERUP)) {
|
||||
mmc_claim_host(host);
|
||||
mmc_power_up(host, host->ocr_avail);
|
||||
mmc_release_host(host);
|
||||
mmc_release_host(host);
|
||||
}
|
||||
|
||||
mmc_gpiod_request_cd_irq(host);
|
||||
_mmc_detect_change(host, 0, false);
|
||||
@@ -2865,8 +2843,6 @@ void mmc_stop_host(struct mmc_host *host)
|
||||
}
|
||||
mmc_bus_put(host);
|
||||
|
||||
BUG_ON(host->card);
|
||||
|
||||
mmc_claim_host(host);
|
||||
mmc_power_off(host);
|
||||
mmc_release_host(host);
|
||||
@@ -3019,7 +2995,6 @@ void mmc_unregister_pm_notifier(struct mmc_host *host)
|
||||
*/
|
||||
void mmc_init_context_info(struct mmc_host *host)
|
||||
{
|
||||
spin_lock_init(&host->context_info.lock);
|
||||
host->context_info.is_new_req = false;
|
||||
host->context_info.is_done_rcv = false;
|
||||
host->context_info.is_waiting_last_req = false;
|
||||
|
||||
@@ -321,7 +321,11 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
|
||||
for (i = 0; i < 512; i++)
|
||||
n += sprintf(buf + n, "%02x", ext_csd[i]);
|
||||
n += sprintf(buf + n, "\n");
|
||||
BUG_ON(n != EXT_CSD_STR_LEN);
|
||||
|
||||
if (n != EXT_CSD_STR_LEN) {
|
||||
err = -EINVAL;
|
||||
goto out_free;
|
||||
}
|
||||
|
||||
filp->private_data = buf;
|
||||
kfree(ext_csd);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user