summaryrefslogtreecommitdiff
path: root/disk/disk-uclass.c
blob: ee3cc4407d76bee65bb5b5ef48209ed8ce5c3f89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// SPDX-License-Identifier: GPL-2.0+
/*
 *  Software partition device (UCLASS_PARTITION)
 *
 *  Copyright (c) 2021 Linaro Limited
 *			Author: AKASHI Takahiro
 */

#define LOG_CATEGORY UCLASS_PARTITION

#include <blk.h>
#include <dm.h>
#include <log.h>
#include <part.h>
#include <vsprintf.h>
#include <dm/device-internal.h>
#include <dm/lists.h>

/**
 * disk_blk_part_validate() - Check whether access to partition is within limits
 *
 * @dev: Device (partition udevice)
 * @start: Start block for the access(from start of partition)
 * @blkcnt: Number of blocks to access (within the partition)
 * @return 0 on valid block range, or -ve on error.
 */
static int disk_blk_part_validate(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
{
	struct disk_part *part = dev_get_uclass_plat(dev);

	if (device_get_uclass_id(dev) != UCLASS_PARTITION)
		return -ENOSYS;

	if (start >= part->gpt_part_info.size)
		return -E2BIG;

	if ((start + blkcnt) > part->gpt_part_info.size)
		return -ERANGE;

	return 0;
}

/**
 * disk_blk_part_offset() - Compute offset from start of block device
 *
 * @dev: Device (partition udevice)
 * @start: Start block for the access (from start of partition)
 * @return Start block for the access (from start of block device)
 */
static lbaint_t disk_blk_part_offset(struct udevice *dev, lbaint_t start)
{
	struct disk_part *part = dev_get_uclass_plat(dev);

	return start + part->gpt_part_info.start;
}

/*
 * BLOCK IO APIs
 */
/**
 * disk_blk_read() - Read from a block device partition
 *
 * @dev: Device to read from (partition udevice)
 * @start: Start block for the read (from start of partition)
 * @blkcnt: Number of blocks to read (within the partition)
 * @buffer: Place to put the data
 * @return number of blocks read (which may be less than @blkcnt),
 * or -ve on error. This never returns 0 unless @blkcnt is 0
 */
unsigned long disk_blk_read(struct udevice *dev, lbaint_t start,
			    lbaint_t blkcnt, void *buffer)
{
	int ret = disk_blk_part_validate(dev, start, blkcnt);

	if (ret)
		return ret;

	return blk_read(dev_get_parent(dev), disk_blk_part_offset(dev, start),
			blkcnt, buffer);
}

/**
 * disk_blk_write() - Write to a block device
 *
 * @dev: Device to write to (partition udevice)
 * @start: Start block for the write (from start of partition)
 * @blkcnt: Number of blocks to write (within the partition)
 * @buffer: Data to write
 * @return number of blocks written (which may be less than @blkcnt),
 * or -ve on error. This never returns 0 unless @blkcnt is 0
 */
unsigned long disk_blk_write(struct udevice *dev, lbaint_t start,
			     lbaint_t blkcnt, const void *buffer)
{
	int ret = disk_blk_part_validate(dev, start, blkcnt);

	if (ret)
		return ret;

	return blk_write(dev_get_parent(dev), disk_blk_part_offset(dev, start),
			 blkcnt, buffer);
}

/**
 * disk_blk_erase() - Erase part of a block device
 *
 * @dev: Device to erase (partition udevice)
 * @start: Start block for the erase (from start of partition)
 * @blkcnt: Number of blocks to erase (within the partition)
 * @return number of blocks erased (which may be less than @blkcnt),
 * or -ve on error. This never returns 0 unless @blkcnt is 0
 */
unsigned long disk_blk_erase(struct udevice *dev, lbaint_t start,
			     lbaint_t blkcnt)
{
	int ret = disk_blk_part_validate(dev, start, blkcnt);

	if (ret)
		return ret;

	return blk_erase(dev_get_parent(dev), disk_blk_part_offset(dev, start),
			 blkcnt);
}

UCLASS_DRIVER(partition) = {
	.id		= UCLASS_PARTITION,
	.per_device_plat_auto	= sizeof(struct disk_part),
	.name		= "partition",
};

static const struct blk_ops blk_part_ops = {
	.read	= disk_blk_read,
	.write	= disk_blk_write,
	.erase	= disk_blk_erase,
};

U_BOOT_DRIVER(blk_partition) = {
	.name		= "blk_partition",
	.id		= UCLASS_PARTITION,
	.ops		= &blk_part_ops,
};