mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Pierre Ossman <drzeus@drzeus.cx>
To: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
Cc: "??" <wux@landicorp.com>,
	Linux Kernel list <linux-kernel@vger.kernel.org>,
	ARM Linux Mailing List  <linux-arm-kernel@lists.arm.linux.org.uk>
Subject: Re: [PATCH] mmc: at91_mci: add multiwrite cap
Date: Wed, 8 Aug 2007 12:11:47 +0200	[thread overview]
Message-ID: <20070808121147.1433d055@poseidon.drzeus.cx> (raw)
In-Reply-To: <46B9926B.3090707@rfo.atmel.com>


[-- Attachment #1.1: Type: text/plain, Size: 492 bytes --]

On Wed, 08 Aug 2007 11:52:43 +0200
Nicolas Ferre <nicolas.ferre@rfo.atmel.com> wrote:

> From: Wu Xuan <wux@landicorp.com>
> 
> Add multiwrite support capability.
> 
> Signed-off-by: Nicolas Ferre <nicolas.ferre@rfo.atmel.com>
> ---

Just like that? :)

If I could just bother you with testing the included patch first. Just
load the module and insert a card. WARNING! It will eat your data, so
do it on a test card. And remember to remove it once you're done.

Rgds
Pierre

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: mmc-test.patch --]
[-- Type: text/x-patch; name=mmc-test.patch, Size: 12635 bytes --]

commit e966ae990cd2ef3be48ece8cde0f97f04a0d6024
Author: Pierre Ossman <drzeus@drzeus.cx>
Date:   Tue Aug 7 14:27:17 2007 +0200

    mmc: mmc host test driver
    
    A dummy driver that performs a series of requests that are often mis-
    handled by host drivers.
    
    Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>

diff --git a/drivers/mmc/card/Kconfig b/drivers/mmc/card/Kconfig
index aa8a4e4..28db50d 100644
--- a/drivers/mmc/card/Kconfig
+++ b/drivers/mmc/card/Kconfig
@@ -32,6 +32,12 @@ config MMC_BLOCK_BOUNCE
 
 	  If unsure, say Y here.
 
+config MMC_TEST
+	tristate "MMC host test driver"
+	default n
+	help
+	  Dummy driver that tests that a host performs as it should.
+
 config SDIO_UART
 	tristate "SDIO UART/GPS class support"
 	depends on MMC
diff --git a/drivers/mmc/card/Makefile b/drivers/mmc/card/Makefile
index fc5a784..944447d 100644
--- a/drivers/mmc/card/Makefile
+++ b/drivers/mmc/card/Makefile
@@ -9,5 +9,6 @@ endif
 obj-$(CONFIG_MMC_BLOCK)		+= mmc_block.o
 mmc_block-objs			:= block.o queue.o
 
+obj-$(CONFIG_MMC_TEST)		+= mmc_test.o
 obj-$(CONFIG_SDIO_UART)		+= sdio_uart.o
 
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
new file mode 100644
index 0000000..06c9ef2
--- /dev/null
+++ b/drivers/mmc/card/mmc_test.c
@@ -0,0 +1,520 @@
+/*
+ *  linux/drivers/mmc/card/mmc_test.c
+ *
+ *  Copyright 2007 Pierre Ossman
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/mmc/core.h>
+#include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+
+#include <linux/scatterlist.h>
+
+static int set_blksize(struct mmc_card *card, unsigned size)
+{
+	struct mmc_command cmd;
+	int ret;
+
+	cmd.opcode = MMC_SET_BLOCKLEN;
+	cmd.arg = size;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
+	ret = mmc_wait_for_cmd(card->host, &cmd, 5);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static int do_transfer(struct mmc_card *card, struct mmc_request *mrq,
+		int write, unsigned blocks, unsigned blksz)
+{
+	int ret, i;
+	u8 *buffer;
+
+	struct scatterlist sg;
+
+	buffer = kzalloc((blocks + 1) * blksz, GFP_KERNEL);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	if (!write)
+		memset(buffer, 0xDF, blocks * blksz);
+
+	memset(mrq->data, 0, sizeof(struct mmc_data));
+
+	mrq->data->blksz = blksz;
+	mrq->data->blocks = blocks;
+	mrq->data->flags = write ? MMC_DATA_WRITE : MMC_DATA_READ;
+	mrq->data->sg = &sg;
+	mrq->data->sg_len = 1;
+
+	sg_init_one(&sg, buffer, blocks * blksz);
+
+	mmc_set_data_timeout(mrq->data, card, write);
+
+	mmc_wait_for_req(card->host, mrq);
+
+	if (!write) {
+		for (i = 0;i < blocks * blksz;i++) {
+			if (buffer[i] == 0xDF) {
+				ret = -EIO;
+				break;
+			}
+		}
+
+		for (i = 0;i < blksz;i++) {
+			if (buffer[blocks * blksz + i] != 0x00) {
+				ret = -EIO;
+				break;
+			}
+		}
+	}
+
+	ret = 0;
+
+out:
+	kfree(buffer);
+	return ret;
+}
+
+static int do_valid_transfer(struct mmc_card *card, struct mmc_request *mrq,
+		int write, unsigned blocks, unsigned blksz)
+{
+	int ret;
+
+	ret = set_blksize(card, blksz);
+	if (ret)
+		return ret;
+
+	memset(mrq->cmd, 0, sizeof(struct mmc_command));
+
+	if (blocks > 1)
+		mrq->cmd->opcode = write ? MMC_WRITE_MULTIPLE_BLOCK : MMC_READ_MULTIPLE_BLOCK;
+	else
+		mrq->cmd->opcode = write ? MMC_WRITE_BLOCK : MMC_READ_SINGLE_BLOCK;
+
+	mrq->cmd->arg = 0;
+	mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	memset(mrq->stop, 0, sizeof(struct mmc_command));
+
+	if (blocks > 1) {
+		mrq->stop->opcode = MMC_STOP_TRANSMISSION;
+		mrq->stop->arg = 0;
+		mrq->stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
+	} else {
+		mrq->stop->opcode = MMC_SEND_STATUS;
+		mrq->stop->arg = card->rca << 16;
+		mrq->stop->flags = MMC_RSP_R1 | MMC_CMD_AC;
+	}
+
+	return do_transfer(card, mrq, write, blocks, blksz);
+}
+
+static int do_invalid_transfer(struct mmc_card *card, struct mmc_request *mrq,
+		int write, unsigned blocks, unsigned blksz)
+{
+	memset(mrq->cmd, 0, sizeof(struct mmc_command));
+
+	mrq->cmd->opcode = MMC_SEND_STATUS;
+	mrq->cmd->arg = card->rca << 16;
+	mrq->cmd->flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	memset(mrq->stop, 0, sizeof(struct mmc_command));
+
+	mrq->stop->opcode = MMC_SEND_STATUS;
+	mrq->stop->arg = card->rca << 16;
+	mrq->stop->flags = MMC_RSP_R1 | MMC_CMD_AC;
+
+	return do_transfer(card, mrq, write, blocks, blksz);
+}
+
+static int test_pow2_reads(struct mmc_card *card)
+{
+	int ret, i;
+
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_command stop;
+	struct mmc_data data;
+
+	printk(KERN_INFO "%s: Testing reading power of two block sizes...\n",
+		mmc_hostname(card->host));
+
+	for (i = 1;i <= 512;i <<= 1) {
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		mrq.cmd = &cmd;
+		mrq.data = &data;
+		mrq.stop = &stop;
+
+		ret = do_valid_transfer(card, &mrq, 0, 1, i);
+		if (ret)
+			goto out;
+
+		ret = 0;
+
+		if (!ret && cmd.error)
+			ret = cmd.error;
+		if (!ret && data.error)
+			ret = data.error;
+		if (!ret && stop.error)
+			ret = stop.error;
+		if (!ret && data.bytes_xfered != i)
+			ret = -EIO;
+
+		if (ret)
+			break;
+	}
+
+out:
+	printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host),
+		ret ? "FAIL" : "OK");
+
+	return ret;
+}
+
+static int test_pow2_writes(struct mmc_card *card)
+{
+	int ret, i;
+
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_command stop;
+	struct mmc_data data;
+
+	printk(KERN_INFO "%s: Testing writing power of two block sizes...\n",
+		mmc_hostname(card->host));
+
+	for (i = 1;i <= 512;i <<= 1) {
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		mrq.cmd = &cmd;
+		mrq.data = &data;
+		mrq.stop = &stop;
+
+		ret = do_valid_transfer(card, &mrq, 1, 1, i);
+		if (ret)
+			goto out;
+
+		ret = 0;
+
+		if (!ret && cmd.error)
+			ret = cmd.error;
+		if (!ret && data.error)
+			ret = data.error;
+		if (!ret && stop.error)
+			ret = stop.error;
+		if (!ret && data.bytes_xfered != i)
+			ret = -EIO;
+
+		if (ret)
+			break;
+	}
+
+out:
+	printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host),
+		ret ? "FAIL" : "OK");
+
+	return ret;
+}
+
+static int test_weird_reads(struct mmc_card *card)
+{
+	int ret, i;
+
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_command stop;
+	struct mmc_data data;
+
+	printk(KERN_INFO "%s: Testing reading unusual block sizes...\n",
+		mmc_hostname(card->host));
+
+	for (i = 3;i <= 512;i += 7) {
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		mrq.cmd = &cmd;
+		mrq.data = &data;
+		mrq.stop = &stop;
+
+		ret = do_valid_transfer(card, &mrq, 0, 1, i);
+		if (ret)
+			goto out;
+
+		ret = 0;
+
+		if (!ret && cmd.error)
+			ret = cmd.error;
+		if (!ret && data.error)
+			ret = data.error;
+		if (!ret && stop.error)
+			ret = stop.error;
+		if (!ret && data.bytes_xfered != i)
+			ret = -EIO;
+
+		if (ret)
+			break;
+	}
+
+out:
+	printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host),
+		ret ? "FAIL" : "OK");
+
+	return ret;
+}
+
+static int test_weird_writes(struct mmc_card *card)
+{
+	int ret, i;
+
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_command stop;
+	struct mmc_data data;
+
+	printk(KERN_INFO "%s: Testing writing unusual block sizes...\n",
+		mmc_hostname(card->host));
+
+	for (i = 3;i <= 512;i += 7) {
+		memset(&mrq, 0, sizeof(struct mmc_request));
+
+		mrq.cmd = &cmd;
+		mrq.data = &data;
+		mrq.stop = &stop;
+
+		ret = do_valid_transfer(card, &mrq, 1, 1, i);
+		if (ret)
+			goto out;
+
+		ret = 0;
+
+		if (!ret && cmd.error)
+			ret = cmd.error;
+		if (!ret && data.error)
+			ret = data.error;
+		if (!ret && stop.error)
+			ret = stop.error;
+		if (!ret && data.bytes_xfered != i)
+			ret = -EIO;
+
+		if (ret)
+			break;
+	}
+
+out:
+	printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host),
+		ret ? "FAIL" : "OK");
+
+	return ret;
+}
+
+static int test_bytes_xfer_single(struct mmc_card *card)
+{
+	int ret;
+
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_command stop;
+	struct mmc_data data;
+
+	printk(KERN_INFO "%s: Testing correct bytes_xfered for a single block...\n",
+		mmc_hostname(card->host));
+
+	if (!(card->host->caps & MMC_CAP_MULTIWRITE)) {
+		printk(KERN_INFO "%s: Result: UNSUPPORTED\n",
+			mmc_hostname(card->host));
+		return -EINVAL;
+	}
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+	mrq.stop = &stop;
+
+	ret = do_invalid_transfer(card, &mrq, 1, 1, 512);
+	if (ret)
+		goto out;
+
+	ret = 0;
+
+	if (!ret && cmd.error)
+		ret = cmd.error;
+	if (!ret && data.error != -ETIMEDOUT)
+		ret = data.error;
+	if (!ret && stop.error)
+		ret = stop.error;
+	if (!ret && data.bytes_xfered != 0)
+		ret = -EINVAL;
+
+out:
+	printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host),
+		ret ? "FAIL" : "OK");
+
+	return ret;
+}
+
+static int test_bytes_xfer_multi(struct mmc_card *card)
+{
+	int ret;
+
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_command stop;
+	struct mmc_data data;
+
+	printk(KERN_INFO "%s: Testing correct bytes_xfered for multiple blocks...\n",
+		mmc_hostname(card->host));
+
+	if (!(card->host->caps & MMC_CAP_MULTIWRITE) ||
+			(card->host->max_blk_count < 2) ||
+			(card->host->max_req_size < 1024) ||
+			(card->host->max_seg_size < 1024)) {
+		printk(KERN_INFO "%s: Result: UNSUPPORTED\n",
+			mmc_hostname(card->host));
+		return -EINVAL;
+	}
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+	mrq.stop = &stop;
+
+	ret = do_invalid_transfer(card, &mrq, 1, 2, 512);
+	if (ret)
+		goto out;
+
+	ret = 0;
+
+	if (!ret && cmd.error)
+		ret = cmd.error;
+	if (!ret && data.error != -ETIMEDOUT)
+		ret = data.error;
+	if (!ret && stop.error)
+		ret = stop.error;
+	if (!ret && data.bytes_xfered != 0)
+		ret = -EINVAL;
+
+out:
+	printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host),
+		ret ? "FAIL" : "OK");
+
+	return ret;
+}
+
+static int test_busy_wait(struct mmc_card *card)
+{
+	int ret;
+
+	struct mmc_request mrq;
+	struct mmc_command cmd;
+	struct mmc_command stop;
+	struct mmc_data data;
+
+	printk(KERN_INFO "%s: Testing that host waits for busy...\n",
+		mmc_hostname(card->host));
+
+	memset(&mrq, 0, sizeof(struct mmc_request));
+
+	mrq.cmd = &cmd;
+	mrq.data = &data;
+	mrq.stop = &stop;
+
+	ret = do_valid_transfer(card, &mrq, 1, 10, 512);
+	if (ret)
+		goto out;
+
+	ret = 0;
+
+	if (!ret && cmd.error)
+		ret = cmd.error;
+	if (!ret && data.error)
+		ret = data.error;
+	if (!ret && stop.error)
+		ret = stop.error;
+	if (!ret && data.bytes_xfered != 10 * 512)
+		ret = -EIO;
+
+	if (ret)
+		goto out;
+
+	memset(&cmd, 0, sizeof(struct mmc_command));
+
+	cmd.opcode = MMC_SEND_STATUS;
+	cmd.arg = card->rca << 16;
+	cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+	ret = mmc_wait_for_cmd(card->host, &cmd, 0);
+	if (ret)
+		goto out;
+
+	if (!(cmd.resp[0] & R1_READY_FOR_DATA))
+		ret = -EIO;
+
+out:
+	printk(KERN_INFO "%s: Result: %s\n", mmc_hostname(card->host),
+		ret ? "FAIL" : "OK (uncertain, test multiple cards)");
+
+	return ret;
+}
+
+static int mmc_test_probe(struct mmc_card *card)
+{
+	mmc_claim_host(card->host);
+
+	test_pow2_writes(card);
+	test_pow2_reads(card);
+
+	test_weird_writes(card);
+	test_weird_reads(card);
+
+	test_bytes_xfer_single(card);
+	test_bytes_xfer_multi(card);
+
+	test_busy_wait(card);
+
+	mmc_release_host(card->host);
+
+	return -ENODEV;
+}
+
+static void mmc_test_remove(struct mmc_card *card)
+{
+}
+
+static struct mmc_driver mmc_driver = {
+	.drv		= {
+		.name	= "mmc_test",
+	},
+	.probe		= mmc_test_probe,
+	.remove		= mmc_test_remove,
+};
+
+static int __init mmc_test_init(void)
+{
+	return mmc_register_driver(&mmc_driver);
+}
+
+static void __exit mmc_test_exit(void)
+{
+	mmc_unregister_driver(&mmc_driver);
+}
+
+module_init(mmc_test_init);
+module_exit(mmc_test_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Multimedia Card (MMC) host test driver");
+MODULE_AUTHOR("Pierre Ossman");
+
+

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 189 bytes --]

  reply	other threads:[~2007-08-08 10:12 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-08-08  9:52 Nicolas Ferre
2007-08-08 10:11 ` Pierre Ossman [this message]
2007-08-08 14:45   ` Nicolas Ferre
2007-08-08 15:01     ` Pierre Ossman
2007-08-09 14:09       ` Nicolas Ferre
2007-08-09 14:45         ` Pierre Ossman

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20070808121147.1433d055@poseidon.drzeus.cx \
    --to=drzeus@drzeus.cx \
    --cc=linux-arm-kernel@lists.arm.linux.org.uk \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nicolas.ferre@rfo.atmel.com \
    --cc=wux@landicorp.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®