All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: u-boot@lists.denx.de
Subject: [U-Boot] [PATCH 22/30] dm: blk: Add a block-device uclass
Date: Sun, 14 Feb 2016 19:16:51 -0700	[thread overview]
Message-ID: <1455502619-16093-23-git-send-email-sjg@chromium.org> (raw)
In-Reply-To: <1455502619-16093-1-git-send-email-sjg@chromium.org>

Add a uclass for block devices. These provide block-oriented data access,
supporting reading, writing and erasing of whole blocks.

Signed-off-by: Simon Glass <sjg@chromium.org>
---

 drivers/block/Kconfig      |  11 +++
 drivers/block/Makefile     |   2 +
 drivers/block/blk-uclass.c | 175 +++++++++++++++++++++++++++++++++++++++++++++
 include/blk.h              | 145 +++++++++++++++++++++++++++++++++++++
 include/dm/uclass-id.h     |   1 +
 5 files changed, 334 insertions(+)
 create mode 100644 drivers/block/blk-uclass.c

diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 990f768..f35c4d4 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -1,3 +1,14 @@
+config BLK
+	bool "Support block devices"
+	depends on DM
+	help
+	  Enable support for block devices, such as SCSI, MMC and USB
+	  flash sticks. These provide a block-level interface which permits
+	  reading, writing and (in some cases) erasing blocks. Block
+	  devices often have a partition table which allows the device to
+	  be partitioned into several areas, called 'partitions' in U-Boot.
+	  A filesystem can be placed in each partition.
+
 config DISK
 	bool "Support disk controllers with driver model"
 	depends on DM
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
index 5eb87e0..b5c7ae1 100644
--- a/drivers/block/Makefile
+++ b/drivers/block/Makefile
@@ -5,6 +5,8 @@
 # SPDX-License-Identifier:	GPL-2.0+
 #
 
+obj-$(CONFIG_BLK) += blk-uclass.o
+
 obj-$(CONFIG_DISK) += disk-uclass.o
 obj-$(CONFIG_SCSI_AHCI) += ahci.o
 obj-$(CONFIG_DWC_AHSATA) += dwc_ahsata.o
diff --git a/drivers/block/blk-uclass.c b/drivers/block/blk-uclass.c
new file mode 100644
index 0000000..49df2a6
--- /dev/null
+++ b/drivers/block/blk-uclass.c
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2016 Google, Inc
+ * Written by Simon Glass <sjg@chromium.org>
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <blk.h>
+#include <dm.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+
+int blk_first_device(int if_type, struct udevice **devp)
+{
+	struct blk_desc *desc;
+	int ret;
+
+	ret = uclass_first_device(UCLASS_BLK, devp);
+	if (ret)
+		return ret;
+	if (!*devp)
+		return -ENODEV;
+	do {
+		desc = dev_get_uclass_platdata(*devp);
+		if (desc->if_type == if_type)
+			return 0;
+		ret = uclass_next_device(devp);
+		if (ret)
+			return ret;
+	} while (*devp);
+
+	return -ENODEV;
+}
+
+int blk_next_device(struct udevice **devp)
+{
+	struct blk_desc *desc;
+	int ret, if_type;
+
+	desc = dev_get_uclass_platdata(*devp);
+	if_type = desc->if_type;
+	do {
+		ret = uclass_next_device(devp);
+		if (ret)
+			return ret;
+		if (!*devp)
+			return -ENODEV;
+		desc = dev_get_uclass_platdata(*devp);
+		if (desc->if_type == if_type)
+			return 0;
+	} while (1);
+}
+
+int blk_get_device(int if_type, int devnum, struct udevice **devp)
+{
+	struct uclass *uc;
+	struct udevice *dev;
+	int ret;
+
+	ret = uclass_get(UCLASS_BLK, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev(dev, uc) {
+		struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+		debug("%s: if_type=%d, devnum=%d: %s, %d, %d\n", __func__,
+		      if_type, devnum, dev->name, desc->if_type, desc->devnum);
+		if (desc->if_type == if_type && desc->devnum == devnum) {
+			*devp = dev;
+			return device_probe(dev);
+		}
+	}
+
+	return -ENODEV;
+}
+
+unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
+			lbaint_t blkcnt, void *buffer)
+{
+	struct udevice *dev = block_dev->bdev;
+	const struct blk_ops *ops = blk_get_ops(dev);
+
+	if (!ops->read)
+		return -ENOSYS;
+
+	return ops->read(dev, start, blkcnt, buffer);
+}
+
+unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
+			 lbaint_t blkcnt, const void *buffer)
+{
+	struct udevice *dev = block_dev->bdev;
+	const struct blk_ops *ops = blk_get_ops(dev);
+
+	if (!ops->write)
+		return -ENOSYS;
+
+	return ops->write(dev, start, blkcnt, buffer);
+}
+
+unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
+			 lbaint_t blkcnt)
+{
+	struct udevice *dev = block_dev->bdev;
+	const struct blk_ops *ops = blk_get_ops(dev);
+
+	if (!ops->erase)
+		return -ENOSYS;
+
+	return ops->erase(dev, start, blkcnt);
+}
+
+int blk_prepare_device(struct udevice *dev)
+{
+	struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+	part_init(desc);
+
+	return 0;
+}
+
+int blk_create_device(struct udevice *parent, const char *drv_name,
+		      const char *name, int if_type, int devnum, int blksz,
+		      lbaint_t size, struct udevice **devp)
+{
+	struct blk_desc *desc;
+	struct udevice *dev;
+	int ret;
+
+	ret = device_bind_driver(parent, drv_name, name, &dev);
+	if (ret)
+		return ret;
+	desc = dev_get_uclass_platdata(dev);
+	desc->if_type = if_type;
+	desc->blksz = blksz;
+	desc->lba = size / blksz;
+	desc->part_type = PART_TYPE_UNKNOWN;
+	desc->bdev = dev;
+	desc->devnum = devnum;
+	*devp = dev;
+
+	return 0;
+}
+
+int blk_unbind_all(int if_type)
+{
+	struct uclass *uc;
+	struct udevice *dev, *next;
+	int ret;
+
+	ret = uclass_get(UCLASS_BLK, &uc);
+	if (ret)
+		return ret;
+	uclass_foreach_dev_safe(dev, next, uc) {
+		struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+		if (desc->if_type == if_type) {
+			ret = device_remove(dev);
+			if (ret)
+				return ret;
+			ret = device_unbind(dev);
+			if (ret)
+				return ret;
+		}
+	}
+
+	return 0;
+}
+
+UCLASS_DRIVER(blk) = {
+	.id		= UCLASS_BLK,
+	.name		= "blk",
+	.per_device_platdata_auto_alloc_size = sizeof(struct blk_desc),
+};
diff --git a/include/blk.h b/include/blk.h
index 8b4861b..9d6918b 100644
--- a/include/blk.h
+++ b/include/blk.h
@@ -34,7 +34,15 @@ enum if_type_t {
 	IF_TYPE_COUNT,			/* Number of interface types */
 };
 
+/*
+ * With driver model (CONFIG_BLK) this is uclass platform data, accessible
+ * with dev_get_uclass_platdata(dev)
+ */
 struct blk_desc {
+	/*
+	 * TODO: With driver model we should be able to use the parent
+	 * device's uclass instead.
+	 */
 	enum if_type_t	if_type;	/* type of the interface */
 	int		devnum;		/* device number */
 	unsigned char	part_type;	/* partition type */
@@ -53,6 +61,9 @@ struct blk_desc {
 	char		vendor[40+1];	/* IDE model, SCSI Vendor */
 	char		product[20+1];	/* IDE Serial no, SCSI product */
 	char		revision[8+1];	/* firmware revision */
+#ifdef CONFIG_BLK
+	struct udevice *bdev;
+#else
 	unsigned long	(*block_read)(struct blk_desc *block_dev,
 				      lbaint_t start,
 				      lbaint_t blkcnt,
@@ -65,12 +76,145 @@ struct blk_desc {
 				       lbaint_t start,
 				       lbaint_t blkcnt);
 	void		*priv;		/* driver private struct pointer */
+#endif
 };
 
 #define BLOCK_CNT(size, blk_desc) (PAD_COUNT(size, blk_desc->blksz))
 #define PAD_TO_BLOCKSIZE(size, blk_desc) \
 	(PAD_SIZE(size, blk_desc->blksz))
 
+#ifdef CONFIG_BLK
+struct udevice;
+
+/* Operations on block devices */
+struct blk_ops {
+	/**
+	 * read() - read from a block device
+	 *
+	 * @dev:	Device to read from
+	 * @start:	Start block number to read (0=first)
+	 * @blkcnt:	Number of blocks to read
+	 * @buffer:	Destination buffer for data read
+	 * @return number of blocks read, or -ve error number (see the
+	 * IS_ERR_VALUE() macro
+	 */
+	unsigned long (*read)(struct udevice *dev, lbaint_t start,
+			      lbaint_t blkcnt, void *buffer);
+
+	/**
+	 * write() - write to a block device
+	 *
+	 * @dev:	Device to write to
+	 * @start:	Start block number to write (0=first)
+	 * @blkcnt:	Number of blocks to write
+	 * @buffer:	Source buffer for data to write
+	 * @return number of blocks written, or -ve error number (see the
+	 * IS_ERR_VALUE() macro
+	 */
+	unsigned long (*write)(struct udevice *dev, lbaint_t start,
+			       lbaint_t blkcnt, const void *buffer);
+
+	/**
+	 * erase() - erase a section of a block device
+	 *
+	 * @dev:	Device to (partially) erase
+	 * @start:	Start block number to erase (0=first)
+	 * @blkcnt:	Number of blocks to erase
+	 * @return number of blocks erased, or -ve error number (see the
+	 * IS_ERR_VALUE() macro
+	 */
+	unsigned long (*erase)(struct udevice *dev, lbaint_t start,
+			       lbaint_t blkcnt);
+};
+
+#define blk_get_ops(dev)	((struct blk_ops *)(dev)->driver->ops)
+
+/*
+ * These functions should take struct udevice instead of struct blk_desc,
+ * but this is convenient for migration to driver model. Add a 'd' prefix
+ * to the function operations, so that blk_read(), etc. can be reserved for
+ * functions with the correct arguments.
+ */
+unsigned long blk_dread(struct blk_desc *block_dev, lbaint_t start,
+			lbaint_t blkcnt, void *buffer);
+unsigned long blk_dwrite(struct blk_desc *block_dev, lbaint_t start,
+			 lbaint_t blkcnt, const void *buffer);
+unsigned long blk_derase(struct blk_desc *block_dev, lbaint_t start,
+			 lbaint_t blkcnt);
+
+/**
+ * blk_get_device() - Find and probe a block device ready for use
+ *
+ * @if_type:	Interface type (enum if_type_t)
+ * @devnum:	Device number (specific to each interface type)
+ * @devp:	the device, if found
+ * @return - if found, -ENODEV if no device found, or other -ve error value
+ */
+int blk_get_device(int if_type, int devnum, struct udevice **devp);
+
+/**
+ * blk_first_device() - Find the first device for a given interface
+ *
+ * The device is probed ready for use
+ *
+ * @devnum:	Device number (specific to each interface type)
+ * @devp:	the device, if found
+ * @return 0 if found, -ENODEV if no device, or other -ve error value
+ */
+int blk_first_device(int if_type, struct udevice **devp);
+
+/**
+ * blk_next_device() - Find the next device for a given interface
+ *
+ * This can be called repeatedly after blk_first_device() to iterate through
+ * all devices of the given interface type.
+ *
+ * The device is probed ready for use
+ *
+ * @devp:	On entry, the previous device returned. On exit, the next
+ *		device, if found
+ * @return 0 if found, -ENODEV if no device, or other -ve error value
+ */
+int blk_next_device(struct udevice **devp);
+
+/**
+ * blk_create_device() - Create a new block device
+ *
+ * @parent:	Parent of the new device
+ * @drv_name:	Driver name to use for the block device
+ * @name:	Name for the device
+ * @if_type:	Interface type (enum if_type_t)
+ * @devnum:	Device number, specific to the interface type
+ * @blksz:	Block size of the device in bytes (typically 512)
+ * @size:	Total size of the device in bytes
+ * @devp:	the new device (which has not been probed)
+ */
+int blk_create_device(struct udevice *parent, const char *drv_name,
+		      const char *name, int if_type, int devnum, int blksz,
+		      lbaint_t size, struct udevice **devp);
+
+/**
+ * blk_prepare_device() - Prepare a block device for use
+ *
+ * This reads partition information from the device if supported.
+ *
+ * @dev:	Device to prepare
+ * @return 0 if ok, -ve on error
+ */
+int blk_prepare_device(struct udevice *dev);
+
+/**
+ * blk_unbind_all() - Unbind all device of the given interface type
+ *
+ * The devices are removed and then unbound.
+ *
+ * @if_type:	Interface type to unbind
+ * @return 0 if OK, -ve on error
+ */
+int blk_unbind_all(int if_type);
+
+#else
+#include <errno.h>
 /*
  * These functions should take struct udevice instead of struct blk_desc,
  * but this is convenient for migration to driver model. Add a 'd' prefix
@@ -99,5 +243,6 @@ static inline ulong blk_derase(struct blk_desc *block_dev, lbaint_t start,
 {
 	return block_dev->block_erase(block_dev, start, blkcnt);
 }
+#endif /* !CONFIG_BLK */
 
 #endif
diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h
index 73cd3ac..096fd38 100644
--- a/include/dm/uclass-id.h
+++ b/include/dm/uclass-id.h
@@ -26,6 +26,7 @@ enum uclass_id {
 
 	/* U-Boot uclasses start here - in alphabetical order */
 	UCLASS_ADC,		/* Analog-to-digital converter */
+	UCLASS_BLK,		/* Block device */
 	UCLASS_CLK,		/* Clock source, e.g. used by peripherals */
 	UCLASS_CPU,		/* CPU, typically part of an SoC */
 	UCLASS_CROS_EC,		/* Chrome OS EC */
-- 
2.7.0.rc3.207.g0ac5344

  parent reply	other threads:[~2016-02-15  2:16 UTC|newest]

Thread overview: 69+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-02-15  2:16 [U-Boot] [PATCH 00/30] dm: Add driver-model support for block drivers Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 01/30] dm: Drop the block_dev_desc_t typedef Simon Glass
2016-02-16 10:09   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 02/30] dm: pci: Break out the common region display code Simon Glass
2016-02-16 10:09   ` Bin Meng
2016-02-29  4:18     ` Simon Glass
2016-02-17  0:19   ` Stephen Warren
2016-02-15  2:16 ` [U-Boot] [PATCH 03/30] dm: part: Correct a sandbox build warning Simon Glass
2016-02-16 10:09   ` Bin Meng
2016-02-29  4:18     ` Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 04/30] dm: fdtdec: " Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 05/30] dm: part: Drop the common.h header Simon Glass
2016-02-16 10:09   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 06/30] dm: Add a new header for block devices Simon Glass
2016-02-16 10:10   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 07/30] dm: blk: Convert interface type to an enum Simon Glass
2016-02-16 10:10   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 08/30] dm: blk: Add comments to a few functions Simon Glass
2016-02-16 10:10   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 09/30] dm: blk: Rename get_dev() to blk_get_dev() Simon Glass
2016-02-16 10:10   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 10/30] dm: blk: Rename get_device() to blk_get_device_str() Simon Glass
2016-02-16 14:02   ` Bin Meng
2016-02-16 23:14   ` Stephen Warren
2016-02-15  2:16 ` [U-Boot] [PATCH 11/30] dm: blk: Rename get_device_and_partition() Simon Glass
2016-02-16 14:02   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 12/30] dm: part: Add a cast to avoid a compiler warning Simon Glass
2016-02-16 14:02   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 13/30] dm: sandbox: Enable all partition types Simon Glass
2016-02-15 22:37   ` Tom Rini
2016-02-16 14:02   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 14/30] dm: part: Convert partition API use to linker lists Simon Glass
2016-02-15 22:37   ` Tom Rini
2016-02-16 14:25   ` Bin Meng
2016-02-29  4:18     ` Simon Glass
2016-02-17  6:41   ` Stephen Warren
2016-02-29  4:48     ` Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 15/30] dm: part: Rename some partition functions Simon Glass
2016-02-16 14:25   ` Bin Meng
2016-02-29  4:19     ` Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 16/30] dm: cbfs: Fix handling of invalid type Simon Glass
2016-02-16 14:51   ` Bin Meng
2016-02-29  4:19     ` Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 17/30] dm: sandbox: Enable cbfs and cramfs Simon Glass
2016-02-16 14:51   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 18/30] dm: block: Rename device number member dev to devnum Simon Glass
2016-02-16 14:51   ` Bin Meng
2016-02-16 23:23   ` Stephen Warren
2016-02-29  4:19     ` Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 19/30] dm: block: Adjust device calls to go through helpers function Simon Glass
2016-02-16 14:51   ` Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 20/30] dm: usb: Avoid exceeding available array size for storage devices Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 21/30] dm: usb: Tidy up storage code ready for driver model conversion Simon Glass
2016-02-15  2:16 ` Simon Glass [this message]
2016-02-17  4:49   ` [U-Boot] [PATCH 22/30] dm: blk: Add a block-device uclass Bin Meng
2016-02-15  2:16 ` [U-Boot] [PATCH 23/30] dm: sandbox: Prepare block driver for driver-model conversion Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 24/30] dm: sandbox: Add driver-model block-device support for sandbox Simon Glass
2016-02-16 23:34   ` Stephen Warren
2016-02-29  4:19     ` Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 25/30] dm: usb: Convert USB storage to use driver-model for block devs Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 26/30] dm: usb: Unbind old block devices when shutting down USB Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 27/30] dm: sandbox: Switch over to use DM for block devices Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 28/30] dm: sandbox: Drop the pre-DM host implementation Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 29/30] dm: usb: Clean up USB after each test Simon Glass
2016-02-15  2:16 ` [U-Boot] [PATCH 30/30] dm: blk: Add tests for block devices Simon Glass
2016-02-15 22:37 ` [U-Boot] [PATCH 00/30] dm: Add driver-model support for block drivers Tom Rini
2016-02-29  4:19   ` Simon Glass
2016-02-16 23:43 ` Stephen Warren
2016-02-29  4:19   ` Simon Glass

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=1455502619-16093-23-git-send-email-sjg@chromium.org \
    --to=sjg@chromium.org \
    --cc=u-boot@lists.denx.de \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.