[PATCH linux dev-5.7 5/6] spi: fsi: Implement restricted size for certain controllers
Joel Stanley
joel at jms.id.au
Thu Jul 30 09:33:06 AEST 2020
On Wed, 29 Jul 2020 at 20:45, Eddie James <eajames at linux.ibm.com> wrote:
>
> Some of the FSI-attached SPI controllers cannot use the loop command in
> programming the sequencer due to security requirements. Add a boolean
> devicetree property that describes this condition and restrict the
> size for these controllers. Also, add more transfers directly in the
> sequence up to the length of the sequence register.
>
> Signed-off-by: Eddie James <eajames at linux.ibm.com>
Fixes: bbb6b2f9865b ("spi: Add FSI-attached SPI controller driver")
Reviewed-by: Joel Stanley <joel at jms.id.au>
> ---
> drivers/spi/spi-fsi.c | 65 +++++++++++++++++++++++++++++++++++--------
> 1 file changed, 53 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/spi/spi-fsi.c b/drivers/spi/spi-fsi.c
> index c31a852b6a3e..53cfa201e187 100644
> --- a/drivers/spi/spi-fsi.c
> +++ b/drivers/spi/spi-fsi.c
> @@ -24,7 +24,8 @@
>
> #define SPI_FSI_BASE 0x70000
> #define SPI_FSI_INIT_TIMEOUT_MS 1000
> -#define SPI_FSI_MAX_TRANSFER_SIZE 2048
> +#define SPI_FSI_MAX_XFR_SIZE 2048
> +#define SPI_FSI_MAX_XFR_SIZE_RESTRICTED 32
>
> #define SPI_FSI_ERROR 0x0
> #define SPI_FSI_COUNTER_CFG 0x1
> @@ -74,6 +75,8 @@ struct fsi_spi {
> struct device *dev; /* SPI controller device */
> struct fsi_device *fsi; /* FSI2SPI CFAM engine device */
> u32 base;
> + size_t max_xfr_size;
> + bool restricted;
> };
>
> struct fsi_spi_sequence {
> @@ -209,8 +212,12 @@ static int fsi_spi_reset(struct fsi_spi *ctx)
> if (rc)
> return rc;
>
> - return fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,
> - SPI_FSI_CLOCK_CFG_RESET2);
> + rc = fsi_spi_write_reg(ctx, SPI_FSI_CLOCK_CFG,
> + SPI_FSI_CLOCK_CFG_RESET2);
> + if (rc)
> + return rc;
> +
> + return fsi_spi_write_reg(ctx, SPI_FSI_STATUS, 0ULL);
> }
>
> static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val)
> @@ -218,8 +225,8 @@ static int fsi_spi_sequence_add(struct fsi_spi_sequence *seq, u8 val)
> /*
> * Add the next byte of instruction to the 8-byte sequence register.
> * Then decrement the counter so that the next instruction will go in
> - * the right place. Return the number of "slots" left in the sequence
> - * register.
> + * the right place. Return the index of the slot we just filled in the
> + * sequence register.
> */
> seq->data |= (u64)val << seq->bit;
> seq->bit -= 8;
> @@ -237,9 +244,11 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx,
> struct fsi_spi_sequence *seq,
> struct spi_transfer *transfer)
> {
> + bool docfg = false;
> int loops;
> int idx;
> int rc;
> + u8 val = 0;
> u8 len = min(transfer->len, 8U);
> u8 rem = transfer->len % len;
> u64 cfg = 0ULL;
> @@ -247,22 +256,42 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx,
> loops = transfer->len / len;
>
> if (transfer->tx_buf) {
> - idx = fsi_spi_sequence_add(seq,
> - SPI_FSI_SEQUENCE_SHIFT_OUT(len));
> + val = SPI_FSI_SEQUENCE_SHIFT_OUT(len);
> + idx = fsi_spi_sequence_add(seq, val);
> +
> if (rem)
> rem = SPI_FSI_SEQUENCE_SHIFT_OUT(rem);
> } else if (transfer->rx_buf) {
> - idx = fsi_spi_sequence_add(seq,
> - SPI_FSI_SEQUENCE_SHIFT_IN(len));
> + val = SPI_FSI_SEQUENCE_SHIFT_IN(len);
> + idx = fsi_spi_sequence_add(seq, val);
> +
> if (rem)
> rem = SPI_FSI_SEQUENCE_SHIFT_IN(rem);
> } else {
> return -EINVAL;
> }
>
> + if (ctx->restricted) {
> + const int eidx = rem ? 5 : 6;
> +
> + while (loops > 1 && idx <= eidx) {
> + idx = fsi_spi_sequence_add(seq, val);
> + loops--;
> + docfg = true;
> + }
> +
> + if (loops > 1) {
> + dev_warn(ctx->dev, "No sequencer slots; aborting.\n");
> + return -EINVAL;
> + }
> + }
> +
> if (loops > 1) {
> fsi_spi_sequence_add(seq, SPI_FSI_SEQUENCE_BRANCH(idx));
> + docfg = true;
> + }
>
> + if (docfg) {
> cfg = SPI_FSI_COUNTER_CFG_LOOPS(loops - 1);
> if (transfer->rx_buf)
> cfg |= SPI_FSI_COUNTER_CFG_N2_RX |
> @@ -273,6 +302,8 @@ static int fsi_spi_sequence_transfer(struct fsi_spi *ctx,
> rc = fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, cfg);
> if (rc)
> return rc;
> + } else {
> + fsi_spi_write_reg(ctx, SPI_FSI_COUNTER_CFG, 0ULL);
> }
>
> if (rem)
> @@ -429,7 +460,7 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,
>
> /* Sequencer must do shift out (tx) first. */
> if (!transfer->tx_buf ||
> - transfer->len > SPI_FSI_MAX_TRANSFER_SIZE) {
> + transfer->len > (ctx->max_xfr_size + 8)) {
> rc = -EINVAL;
> goto error;
> }
> @@ -453,7 +484,7 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,
>
> /* Sequencer can only do shift in (rx) after tx. */
> if (next->rx_buf) {
> - if (next->len > SPI_FSI_MAX_TRANSFER_SIZE) {
> + if (next->len > ctx->max_xfr_size) {
> rc = -EINVAL;
> goto error;
> }
> @@ -498,7 +529,9 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,
>
> static size_t fsi_spi_max_transfer_size(struct spi_device *spi)
> {
> - return SPI_FSI_MAX_TRANSFER_SIZE;
> + struct fsi_spi *ctx = spi_controller_get_devdata(spi->controller);
> +
> + return ctx->max_xfr_size;
> }
>
> static int fsi_spi_probe(struct device *dev)
> @@ -546,6 +579,14 @@ static int fsi_spi_probe(struct device *dev)
> ctx->fsi = fsi;
> ctx->base = base + SPI_FSI_BASE;
>
> + if (of_property_read_bool(np, "fsi2spi,restricted")) {
> + ctx->restricted = true;
> + ctx->max_xfr_size = SPI_FSI_MAX_XFR_SIZE_RESTRICTED;
> + } else {
> + ctx->restricted = false;
> + ctx->max_xfr_size = SPI_FSI_MAX_XFR_SIZE;
> + }
> +
> rc = devm_spi_register_controller(dev, ctlr);
> if (rc)
> spi_controller_put(ctlr);
> --
> 2.24.0
>
More information about the openbmc
mailing list