Skip to content

Commit

Permalink
Merge tag 'mmc-v4.14-rc3' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/git/ulfh/mmc

Pull MMC fixes from Ulf Hansson:
 "MMC core:

   - Fix driver strength selection when selecting hs400es

   - Delete bounce buffer handling:

     This change fixes a problem related to how bounce buffers are being
     allocated. However, instead of trying to fix that, let's just
     remove the mmc bounce buffer code altogether, as it has practically
     no use.

  MMC host:

   - meson-gx: A couple of fixes related to clock/phase/tuning

   - sdhci-xenon: Fix clock resource by adding an optional bus clock"

* tag 'mmc-v4.14-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc:
  mmc: sdhci-xenon: Fix clock resource by adding an optional bus clock
  mmc: meson-gx: include tx phase in the tuning process
  mmc: meson-gx: fix rx phase reset
  mmc: meson-gx: make sure the clock is rounded down
  mmc: Delete bounce buffer handling
  mmc: core: add driver strength selection when selecting hs400es
  • Loading branch information
torvalds committed Oct 7, 2017
2 parents 1c86f2e + bb16ea1 commit 031b814
Show file tree
Hide file tree
Showing 11 changed files with 81 additions and 162 deletions.
12 changes: 7 additions & 5 deletions Documentation/devicetree/bindings/mmc/marvell,xenon-sdhci.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ Required Properties:

- clocks:
Array of clocks required for SDHC.
Require at least input clock for Xenon IP core.
Require at least input clock for Xenon IP core. For Armada AP806 and
CP110, the AXI clock is also mandatory.

- clock-names:
Array of names corresponding to clocks property.
The input clock for Xenon IP core should be named as "core".
The input clock for the AXI bus must be named as "axi".

- reg:
* For "marvell,armada-3700-sdhci", two register areas.
Expand Down Expand Up @@ -106,8 +108,8 @@ Example:
compatible = "marvell,armada-ap806-sdhci";
reg = <0xaa0000 0x1000>;
interrupts = <GIC_SPI 13 IRQ_TYPE_LEVEL_HIGH>
clocks = <&emmc_clk>;
clock-names = "core";
clocks = <&emmc_clk>,<&axi_clk>;
clock-names = "core", "axi";
bus-width = <4>;
marvell,xenon-phy-slow-mode;
marvell,xenon-tun-count = <11>;
Expand All @@ -126,8 +128,8 @@ Example:
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>
vqmmc-supply = <&sd_vqmmc_regulator>;
vmmc-supply = <&sd_vmmc_regulator>;
clocks = <&sdclk>;
clock-names = "core";
clocks = <&sdclk>, <&axi_clk>;
clock-names = "core", "axi";
bus-width = <4>;
marvell,xenon-tun-count = <9>;
};
Expand Down
3 changes: 0 additions & 3 deletions drivers/mmc/core/block.c
Original file line number Diff line number Diff line change
Expand Up @@ -1634,8 +1634,6 @@ static void mmc_blk_data_prep(struct mmc_queue *mq, struct mmc_queue_req *mqrq,
}

mqrq->areq.mrq = &brq->mrq;

mmc_queue_bounce_pre(mqrq);
}

static void mmc_blk_rw_rq_prep(struct mmc_queue_req *mqrq,
Expand Down Expand Up @@ -1829,7 +1827,6 @@ static void mmc_blk_issue_rw_rq(struct mmc_queue *mq, struct request *new_req)
brq = &mq_rq->brq;
old_req = mmc_queue_req_to_req(mq_rq);
type = rq_data_dir(old_req) == READ ? MMC_BLK_READ : MMC_BLK_WRITE;
mmc_queue_bounce_post(mq_rq);

switch (status) {
case MMC_BLK_SUCCESS:
Expand Down
36 changes: 19 additions & 17 deletions drivers/mmc/core/mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1286,6 +1286,23 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
return err;
}

static void mmc_select_driver_type(struct mmc_card *card)
{
int card_drv_type, drive_strength, 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);

card->drive_strength = drive_strength;

if (drv_type)
mmc_set_driver_type(card->host, drv_type);
}

static int mmc_select_hs400es(struct mmc_card *card)
{
struct mmc_host *host = card->host;
Expand Down Expand Up @@ -1341,6 +1358,8 @@ static int mmc_select_hs400es(struct mmc_card *card)
goto out_err;
}

mmc_select_driver_type(card);

/* Switch card to HS400 */
val = EXT_CSD_TIMING_HS400 |
card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
Expand Down Expand Up @@ -1374,23 +1393,6 @@ static int mmc_select_hs400es(struct mmc_card *card)
return err;
}

static void mmc_select_driver_type(struct mmc_card *card)
{
int card_drv_type, drive_strength, 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);

card->drive_strength = drive_strength;

if (drv_type)
mmc_set_driver_type(card->host, drv_type);
}

/*
* For device supporting HS200 mode, the following sequence
* should be done before executing the tuning process.
Expand Down
125 changes: 9 additions & 116 deletions drivers/mmc/core/queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@
#include "core.h"
#include "card.h"

#define MMC_QUEUE_BOUNCESZ 65536

/*
* Prepare a MMC request. This just filters out odd stuff.
*/
Expand Down Expand Up @@ -150,26 +148,6 @@ static void mmc_queue_setup_discard(struct request_queue *q,
queue_flag_set_unlocked(QUEUE_FLAG_SECERASE, q);
}

static unsigned int mmc_queue_calc_bouncesz(struct mmc_host *host)
{
unsigned int bouncesz = MMC_QUEUE_BOUNCESZ;

if (host->max_segs != 1 || (host->caps & MMC_CAP_NO_BOUNCE_BUFF))
return 0;

if (bouncesz > host->max_req_size)
bouncesz = host->max_req_size;
if (bouncesz > host->max_seg_size)
bouncesz = host->max_seg_size;
if (bouncesz > host->max_blk_count * 512)
bouncesz = host->max_blk_count * 512;

if (bouncesz <= 512)
return 0;

return bouncesz;
}

/**
* mmc_init_request() - initialize the MMC-specific per-request data
* @q: the request queue
Expand All @@ -184,26 +162,9 @@ static int mmc_init_request(struct request_queue *q, struct request *req,
struct mmc_card *card = mq->card;
struct mmc_host *host = card->host;

if (card->bouncesz) {
mq_rq->bounce_buf = kmalloc(card->bouncesz, gfp);
if (!mq_rq->bounce_buf)
return -ENOMEM;
if (card->bouncesz > 512) {
mq_rq->sg = mmc_alloc_sg(1, gfp);
if (!mq_rq->sg)
return -ENOMEM;
mq_rq->bounce_sg = mmc_alloc_sg(card->bouncesz / 512,
gfp);
if (!mq_rq->bounce_sg)
return -ENOMEM;
}
} else {
mq_rq->bounce_buf = NULL;
mq_rq->bounce_sg = NULL;
mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp);
if (!mq_rq->sg)
return -ENOMEM;
}
mq_rq->sg = mmc_alloc_sg(host->max_segs, gfp);
if (!mq_rq->sg)
return -ENOMEM;

return 0;
}
Expand All @@ -212,13 +173,6 @@ static void mmc_exit_request(struct request_queue *q, struct request *req)
{
struct mmc_queue_req *mq_rq = req_to_mmc_queue_req(req);

/* It is OK to kfree(NULL) so this will be smooth */
kfree(mq_rq->bounce_sg);
mq_rq->bounce_sg = NULL;

kfree(mq_rq->bounce_buf);
mq_rq->bounce_buf = NULL;

kfree(mq_rq->sg);
mq_rq->sg = NULL;
}
Expand All @@ -242,12 +196,6 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
if (mmc_dev(host)->dma_mask && *mmc_dev(host)->dma_mask)
limit = (u64)dma_max_pfn(mmc_dev(host)) << PAGE_SHIFT;

/*
* mmc_init_request() depends on card->bouncesz so it must be calculated
* before blk_init_allocated_queue() starts allocating requests.
*/
card->bouncesz = mmc_queue_calc_bouncesz(host);

mq->card = card;
mq->queue = blk_alloc_queue(GFP_KERNEL);
if (!mq->queue)
Expand All @@ -271,17 +219,11 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
if (mmc_can_erase(card))
mmc_queue_setup_discard(mq->queue, card);

if (card->bouncesz) {
blk_queue_max_hw_sectors(mq->queue, card->bouncesz / 512);
blk_queue_max_segments(mq->queue, card->bouncesz / 512);
blk_queue_max_segment_size(mq->queue, card->bouncesz);
} else {
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);
}
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);

Expand Down Expand Up @@ -370,56 +312,7 @@ void mmc_queue_resume(struct mmc_queue *mq)
*/
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;
struct request *req = mmc_queue_req_to_req(mqrq);
int i;

if (!mqrq->bounce_buf)
return blk_rq_map_sg(mq->queue, req, mqrq->sg);

sg_len = blk_rq_map_sg(mq->queue, req, mqrq->bounce_sg);

mqrq->bounce_sg_len = sg_len;

buflen = 0;
for_each_sg(mqrq->bounce_sg, sg, sg_len, i)
buflen += sg->length;

sg_init_one(mqrq->sg, mqrq->bounce_buf, buflen);

return 1;
}

/*
* If writing, bounce the data to the buffer before the request
* is sent to the host driver
*/
void mmc_queue_bounce_pre(struct mmc_queue_req *mqrq)
{
if (!mqrq->bounce_buf)
return;

if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != WRITE)
return;

sg_copy_to_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
mqrq->bounce_buf, mqrq->sg[0].length);
}

/*
* If reading, bounce the data from the buffer after the request
* has been handled by the host driver
*/
void mmc_queue_bounce_post(struct mmc_queue_req *mqrq)
{
if (!mqrq->bounce_buf)
return;

if (rq_data_dir(mmc_queue_req_to_req(mqrq)) != READ)
return;

sg_copy_from_buffer(mqrq->bounce_sg, mqrq->bounce_sg_len,
mqrq->bounce_buf, mqrq->sg[0].length);
return blk_rq_map_sg(mq->queue, req, mqrq->sg);
}
6 changes: 0 additions & 6 deletions drivers/mmc/core/queue.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,6 @@ enum mmc_drv_op {
struct mmc_queue_req {
struct mmc_blk_request brq;
struct scatterlist *sg;
char *bounce_buf;
struct scatterlist *bounce_sg;
unsigned int bounce_sg_len;
struct mmc_async_req areq;
enum mmc_drv_op drv_op;
int drv_op_result;
Expand Down Expand Up @@ -81,11 +78,8 @@ extern int mmc_init_queue(struct mmc_queue *, struct mmc_card *, spinlock_t *,
extern void mmc_cleanup_queue(struct mmc_queue *);
extern void mmc_queue_suspend(struct mmc_queue *);
extern void mmc_queue_resume(struct mmc_queue *);

extern unsigned int mmc_queue_map_sg(struct mmc_queue *,
struct mmc_queue_req *);
extern void mmc_queue_bounce_pre(struct mmc_queue_req *);
extern void mmc_queue_bounce_post(struct mmc_queue_req *);

extern int mmc_access_rpmb(struct mmc_queue *);

Expand Down
2 changes: 1 addition & 1 deletion drivers/mmc/host/cavium.c
Original file line number Diff line number Diff line change
Expand Up @@ -1038,7 +1038,7 @@ int cvm_mmc_of_slot_probe(struct device *dev, struct cvm_mmc_host *host)
*/
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_ERASE | MMC_CAP_CMD23 | MMC_CAP_POWER_OFF_CARD |
MMC_CAP_3_3V_DDR | MMC_CAP_NO_BOUNCE_BUFF;
MMC_CAP_3_3V_DDR;

if (host->use_sg)
mmc->max_segs = 16;
Expand Down
26 changes: 22 additions & 4 deletions drivers/mmc/host/meson-gx-mmc.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,8 +531,7 @@ static int meson_mmc_clk_init(struct meson_host *host)
div->shift = __ffs(CLK_DIV_MASK);
div->width = __builtin_popcountl(CLK_DIV_MASK);
div->hw.init = &init;
div->flags = (CLK_DIVIDER_ONE_BASED |
CLK_DIVIDER_ROUND_CLOSEST);
div->flags = CLK_DIVIDER_ONE_BASED;

clk = devm_clk_register(host->dev, &div->hw);
if (WARN_ON(IS_ERR(clk)))
Expand Down Expand Up @@ -717,6 +716,22 @@ static int meson_mmc_clk_phase_tuning(struct mmc_host *mmc, u32 opcode,
static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode)
{
struct meson_host *host = mmc_priv(mmc);
int ret;

/*
* If this is the initial tuning, try to get a sane Rx starting
* phase before doing the actual tuning.
*/
if (!mmc->doing_retune) {
ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk);

if (ret)
return ret;
}

ret = meson_mmc_clk_phase_tuning(mmc, opcode, host->tx_clk);
if (ret)
return ret;

return meson_mmc_clk_phase_tuning(mmc, opcode, host->rx_clk);
}
Expand Down Expand Up @@ -746,6 +761,11 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
case MMC_POWER_UP:
if (!IS_ERR(mmc->supply.vmmc))
mmc_regulator_set_ocr(mmc, mmc->supply.vmmc, ios->vdd);

/* Reset phases */
clk_set_phase(host->rx_clk, 0);
clk_set_phase(host->tx_clk, 270);

break;

case MMC_POWER_ON:
Expand All @@ -759,8 +779,6 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
host->vqmmc_enabled = true;
}

/* Reset rx phase */
clk_set_phase(host->rx_clk, 0);
break;
}

Expand Down
6 changes: 1 addition & 5 deletions drivers/mmc/host/pxamci.c
Original file line number Diff line number Diff line change
Expand Up @@ -702,11 +702,7 @@ static int pxamci_probe(struct platform_device *pdev)

pxamci_init_ocr(host);

/*
* This architecture used to disable bounce buffers through its
* defconfig, now it is done at runtime as a host property.
*/
mmc->caps = MMC_CAP_NO_BOUNCE_BUFF;
mmc->caps = 0;
host->cmdat = 0;
if (!cpu_is_pxa25x()) {
mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
Expand Down
Loading

0 comments on commit 031b814

Please sign in to comment.