return device_probe(*devp);
}
+struct blk_bounce_buffer {
+ struct udevice *dev;
+ struct bounce_buffer state;
+};
+
+static int blk_buffer_aligned(struct bounce_buffer *state)
+{
+#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
+ struct blk_bounce_buffer *bbstate =
+ container_of(state, struct blk_bounce_buffer, state);
+ struct udevice *dev = bbstate->dev;
+ const struct blk_ops *ops = blk_get_ops(dev);
+
+ if (ops->buffer_aligned)
+ return ops->buffer_aligned(dev, state);
+#endif /* CONFIG_BOUNCE_BUFFER */
+
+ return 1; /* Default, any buffer is OK */
+}
+
long blk_read(struct udevice *dev, lbaint_t start, lbaint_t blkcnt, void *buf)
{
struct blk_desc *desc = dev_get_uclass_plat(dev);
if (blkcache_read(desc->uclass_id, desc->devnum,
start, blkcnt, desc->blksz, buf))
return blkcnt;
- blks_read = ops->read(dev, start, blkcnt, buf);
+
+ if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
+ struct blk_bounce_buffer bbstate = { .dev = dev };
+ int ret;
+
+ ret = bounce_buffer_start_extalign(&bbstate.state, buf,
+ blkcnt * desc->blksz,
+ GEN_BB_WRITE, desc->blksz,
+ blk_buffer_aligned);
+ if (ret)
+ return ret;
+
+ blks_read = ops->read(dev, start, blkcnt, bbstate.state.bounce_buffer);
+
+ bounce_buffer_stop(&bbstate.state);
+ } else {
+ blks_read = ops->read(dev, start, blkcnt, buf);
+ }
+
if (blks_read == blkcnt)
blkcache_fill(desc->uclass_id, desc->devnum, start, blkcnt,
desc->blksz, buf);
{
struct blk_desc *desc = dev_get_uclass_plat(dev);
const struct blk_ops *ops = blk_get_ops(dev);
+ long blks_written;
if (!ops->write)
return -ENOSYS;
blkcache_invalidate(desc->uclass_id, desc->devnum);
- return ops->write(dev, start, blkcnt, buf);
+ if (IS_ENABLED(CONFIG_BOUNCE_BUFFER)) {
+ struct blk_bounce_buffer bbstate = { .dev = dev };
+ int ret;
+
+ ret = bounce_buffer_start_extalign(&bbstate.state, (void *)buf,
+ blkcnt * desc->blksz,
+ GEN_BB_READ, desc->blksz,
+ blk_buffer_aligned);
+ if (ret)
+ return ret;
+
+ blks_written = ops->write(dev, start, blkcnt,
+ bbstate.state.bounce_buffer);
+
+ bounce_buffer_stop(&bbstate.state);
+ } else {
+ blks_written = ops->write(dev, start, blkcnt, buf);
+ }
+
+ return blks_written;
}
long blk_erase(struct udevice *dev, lbaint_t start, lbaint_t blkcnt)
#ifndef BLK_H
#define BLK_H
+#include <bouncebuf.h>
#include <dm/uclass-id.h>
#include <efi.h>
* @return 0 if OK, -ve on error
*/
int (*select_hwpart)(struct udevice *dev, int hwpart);
+
+#if IS_ENABLED(CONFIG_BOUNCE_BUFFER)
+ /**
+ * buffer_aligned() - test memory alignment of block operation buffer
+ *
+ * Some devices have limited DMA capabilities and require that the
+ * buffers passed to them fit specific properties. This optional
+ * callback can be used to indicate whether a buffer alignment is
+ * suitable for the device DMA or not, and trigger use of generic
+ * bounce buffer implementation to help use of unsuitable buffers
+ * at the expense of performance degradation.
+ *
+ * @dev: Block device associated with the request
+ * @state: Bounce buffer state
+ * @return 1 if OK, 0 if unaligned
+ */
+ int (*buffer_aligned)(struct udevice *dev, struct bounce_buffer *state);
+#endif /* CONFIG_BOUNCE_BUFFER */
};
/*