Skip to content

Commit e954af1

Browse files
Eddie Jamesbroonie
authored andcommitted
spi: fsi: Fix contention in the FSI2SPI engine
There was nothing to protect multiple SPI controllers on the same FSI2SPI device from being accessed through the FSI2SPI device at the same time. For example, multiple writes to the command and data registers might occur for different SPI controllers, resulting in complete chaos in the SPI engine. To prevent this, add a FSI2SPI device level mutex and lock it in the SPI register read and write functions. Fixes: bbb6b2f ("spi: Add FSI-attached SPI controller driver") Signed-off-by: Eddie James <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Mark Brown <[email protected]>
1 parent 0b0a281 commit e954af1

File tree

1 file changed

+53
-22
lines changed

1 file changed

+53
-22
lines changed

drivers/spi/spi-fsi.c

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,14 @@
6767
SPI_FSI_STATUS_RDR_OVERRUN)
6868
#define SPI_FSI_PORT_CTRL 0x9
6969

70+
struct fsi2spi {
71+
struct fsi_device *fsi; /* FSI2SPI CFAM engine device */
72+
struct mutex lock; /* lock access to the device */
73+
};
74+
7075
struct fsi_spi {
7176
struct device *dev; /* SPI controller device */
72-
struct fsi_device *fsi; /* FSI2SPI CFAM engine device */
77+
struct fsi2spi *bridge; /* FSI2SPI device */
7378
u32 base;
7479
};
7580

@@ -104,7 +109,7 @@ static int fsi_spi_check_status(struct fsi_spi *ctx)
104109
u32 sts;
105110
__be32 sts_be;
106111

107-
rc = fsi_device_read(ctx->fsi, FSI2SPI_STATUS, &sts_be,
112+
rc = fsi_device_read(ctx->bridge->fsi, FSI2SPI_STATUS, &sts_be,
108113
sizeof(sts_be));
109114
if (rc)
110115
return rc;
@@ -120,73 +125,91 @@ static int fsi_spi_check_status(struct fsi_spi *ctx)
120125

121126
static int fsi_spi_read_reg(struct fsi_spi *ctx, u32 offset, u64 *value)
122127
{
123-
int rc;
128+
int rc = 0;
124129
__be32 cmd_be;
125130
__be32 data_be;
126131
u32 cmd = offset + ctx->base;
132+
struct fsi2spi *bridge = ctx->bridge;
127133

128134
*value = 0ULL;
129135

130136
if (cmd & FSI2SPI_CMD_WRITE)
131137
return -EINVAL;
132138

133-
cmd_be = cpu_to_be32(cmd);
134-
rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be));
139+
rc = mutex_lock_interruptible(&bridge->lock);
135140
if (rc)
136141
return rc;
137142

143+
cmd_be = cpu_to_be32(cmd);
144+
rc = fsi_device_write(bridge->fsi, FSI2SPI_CMD, &cmd_be,
145+
sizeof(cmd_be));
146+
if (rc)
147+
goto unlock;
148+
138149
rc = fsi_spi_check_status(ctx);
139150
if (rc)
140-
return rc;
151+
goto unlock;
141152

142-
rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA0, &data_be,
153+
rc = fsi_device_read(bridge->fsi, FSI2SPI_DATA0, &data_be,
143154
sizeof(data_be));
144155
if (rc)
145-
return rc;
156+
goto unlock;
146157

147158
*value |= (u64)be32_to_cpu(data_be) << 32;
148159

149-
rc = fsi_device_read(ctx->fsi, FSI2SPI_DATA1, &data_be,
160+
rc = fsi_device_read(bridge->fsi, FSI2SPI_DATA1, &data_be,
150161
sizeof(data_be));
151162
if (rc)
152-
return rc;
163+
goto unlock;
153164

154165
*value |= (u64)be32_to_cpu(data_be);
155166
dev_dbg(ctx->dev, "Read %02x[%016llx].\n", offset, *value);
156167

157-
return 0;
168+
unlock:
169+
mutex_unlock(&bridge->lock);
170+
return rc;
158171
}
159172

160173
static int fsi_spi_write_reg(struct fsi_spi *ctx, u32 offset, u64 value)
161174
{
162-
int rc;
175+
int rc = 0;
163176
__be32 cmd_be;
164177
__be32 data_be;
165178
u32 cmd = offset + ctx->base;
179+
struct fsi2spi *bridge = ctx->bridge;
166180

167181
if (cmd & FSI2SPI_CMD_WRITE)
168182
return -EINVAL;
169183

184+
rc = mutex_lock_interruptible(&bridge->lock);
185+
if (rc)
186+
return rc;
187+
170188
dev_dbg(ctx->dev, "Write %02x[%016llx].\n", offset, value);
171189

172190
data_be = cpu_to_be32(upper_32_bits(value));
173-
rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA0, &data_be,
191+
rc = fsi_device_write(bridge->fsi, FSI2SPI_DATA0, &data_be,
174192
sizeof(data_be));
175193
if (rc)
176-
return rc;
194+
goto unlock;
177195

178196
data_be = cpu_to_be32(lower_32_bits(value));
179-
rc = fsi_device_write(ctx->fsi, FSI2SPI_DATA1, &data_be,
197+
rc = fsi_device_write(bridge->fsi, FSI2SPI_DATA1, &data_be,
180198
sizeof(data_be));
181199
if (rc)
182-
return rc;
200+
goto unlock;
183201

184202
cmd_be = cpu_to_be32(cmd | FSI2SPI_CMD_WRITE);
185-
rc = fsi_device_write(ctx->fsi, FSI2SPI_CMD, &cmd_be, sizeof(cmd_be));
203+
rc = fsi_device_write(bridge->fsi, FSI2SPI_CMD, &cmd_be,
204+
sizeof(cmd_be));
186205
if (rc)
187-
return rc;
206+
goto unlock;
207+
208+
rc = fsi_spi_check_status(ctx);
188209

189-
return fsi_spi_check_status(ctx);
210+
unlock:
211+
mutex_unlock(&bridge->lock);
212+
return rc;
190213
}
191214

192215
static int fsi_spi_data_in(u64 in, u8 *rx, int len)
@@ -242,7 +265,7 @@ static int fsi_spi_status(struct fsi_spi *ctx, u64 *status, const char *dir)
242265
return rc;
243266

244267
if (*status & SPI_FSI_STATUS_ANY_ERROR) {
245-
dev_err(ctx->dev, "%s error: %08llx\n", dir, *status);
268+
dev_err(ctx->dev, "%s error: %016llx\n", dir, *status);
246269

247270
rc = fsi_spi_reset(ctx);
248271
if (rc)
@@ -394,7 +417,7 @@ static int fsi_spi_transfer_one_message(struct spi_controller *ctlr,
394417
struct spi_transfer *transfer;
395418
struct fsi_spi *ctx = spi_controller_get_devdata(ctlr);
396419

397-
rc = fsi_spi_check_mux(ctx->fsi, ctx->dev);
420+
rc = fsi_spi_check_mux(ctx->bridge->fsi, ctx->dev);
398421
if (rc)
399422
goto error;
400423

@@ -484,12 +507,20 @@ static int fsi_spi_probe(struct device *dev)
484507
int rc;
485508
struct device_node *np;
486509
int num_controllers_registered = 0;
510+
struct fsi2spi *bridge;
487511
struct fsi_device *fsi = to_fsi_dev(dev);
488512

489513
rc = fsi_spi_check_mux(fsi, dev);
490514
if (rc)
491515
return -ENODEV;
492516

517+
bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
518+
if (!bridge)
519+
return -ENOMEM;
520+
521+
bridge->fsi = fsi;
522+
mutex_init(&bridge->lock);
523+
493524
for_each_available_child_of_node(dev->of_node, np) {
494525
u32 base;
495526
struct fsi_spi *ctx;
@@ -512,7 +543,7 @@ static int fsi_spi_probe(struct device *dev)
512543

513544
ctx = spi_controller_get_devdata(ctlr);
514545
ctx->dev = &ctlr->dev;
515-
ctx->fsi = fsi;
546+
ctx->bridge = bridge;
516547
ctx->base = base + SPI_FSI_BASE;
517548

518549
rc = devm_spi_register_controller(dev, ctlr);

0 commit comments

Comments
 (0)