io_block_ops_t *ops;
size_t aligned_length, skip, count, left, padding, block_size;
int lba;
+ int buffer_not_aligned;
assert(entity->info != (uintptr_t)NULL);
cur = (block_dev_state_t *)entity->info;
(length > 0) &&
(ops->read != 0));
+ if ((buffer & (block_size - 1)) != 0) {
+ /*
+ * buffer isn't aligned with block size.
+ * Block device always relies on DMA operation.
+ * It's better to make the buffer as block size aligned.
+ */
+ buffer_not_aligned = 1;
+ } else {
+ buffer_not_aligned = 0;
+ }
+
skip = cur->file_pos % block_size;
aligned_length = ((skip + length) + (block_size - 1)) &
~(block_size - 1);
do {
lba = (cur->file_pos + cur->base) / block_size;
if (left >= buf->length) {
- /* Since left is larger, it's impossible to padding. */
- if (skip) {
+ /*
+ * Since left is larger, it's impossible to padding.
+ *
+ * If buffer isn't aligned, we need to use aligned
+ * buffer instead.
+ */
+ if (skip || buffer_not_aligned) {
/*
* The beginning address (file_pos) isn't
* aligned with block size, we need to use
}
assert(count == buf->length);
cur->file_pos += count - skip;
- if (skip) {
+ if (skip || buffer_not_aligned) {
/*
- * Since it's not aligned with block size,
- * block buffer is used to store data.
+ * Since there's not aligned block size caused
+ * by skip or not aligned buffer, block buffer
+ * is used to store data.
*/
memcpy((void *)buffer,
(void *)(buf->offset + skip),
}
left = left - (count - skip);
} else {
- if (skip || padding) {
+ if (skip || padding || buffer_not_aligned) {
/*
* The beginning address (file_pos) isn't
* aligned with block size, we have to read
* full block by block buffer instead.
* The size isn't aligned with block size.
* Use block buffer to avoid overflow.
+ *
+ * If buffer isn't aligned, use block buffer
+ * to avoid DMA error.
*/
count = ops->read(lba, buf->offset, left);
} else
assert(count == left);
left = left - (skip + padding);
cur->file_pos += left;
- if (skip || padding) {
+ if (skip || padding || buffer_not_aligned) {
/*
- * Since it's not aligned with block size,
- * block buffer is used to store data.
+ * Since there's not aligned block size or
+ * buffer, block buffer is used to store data.
*/
memcpy((void *)buffer,
(void *)(buf->offset + skip),
io_block_ops_t *ops;
size_t aligned_length, skip, count, left, padding, block_size;
int lba;
+ int buffer_not_aligned;
assert(entity->info != (uintptr_t)NULL);
cur = (block_dev_state_t *)entity->info;
(ops->read != 0) &&
(ops->write != 0));
+ if ((buffer & (block_size - 1)) != 0) {
+ /*
+ * buffer isn't aligned with block size.
+ * Block device always relies on DMA operation.
+ * It's better to make the buffer as block size aligned.
+ */
+ buffer_not_aligned = 1;
+ } else {
+ buffer_not_aligned = 0;
+ }
+
skip = cur->file_pos % block_size;
aligned_length = ((skip + length) + (block_size - 1)) &
~(block_size - 1);
lba = (cur->file_pos + cur->base) / block_size;
if (left >= buf->length) {
/* Since left is larger, it's impossible to padding. */
- if (skip) {
+ if (skip || buffer_not_aligned) {
/*
* The beginning address (file_pos) isn't
- * aligned with block size, we need to use
- * block buffer to write block. Since block
- * device is always relied on DMA operation.
+ * aligned with block size or buffer isn't
+ * aligned, we need to use block buffer to
+ * write block.
*/
count = ops->read(lba, buf->offset,
buf->length);
cur->file_pos += count - skip;
left = left - (count - skip);
} else {
- if (skip || padding) {
+ if (skip || padding || buffer_not_aligned) {
/*
* The beginning address (file_pos) isn't
* aligned with block size, we need to avoid
* skipping the beginning is the only way.
* The size isn't aligned with block size.
* Use block buffer to avoid overflow.
+ *
+ * If buffer isn't aligned, use block buffer
+ * to avoid DMA error.
*/
count = ops->read(lba, buf->offset, left);
assert(count == left);