aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHeiner Kallweit <hkallweit1@gmail.com>2016-09-07 16:50:22 -0400
committerMark Brown <broonie@kernel.org>2016-09-12 14:58:45 -0400
commit1423877b73ed5f4982eaba8bed359605b9918a2b (patch)
tree19fe399436429fe4b6086f33300e619d1abb648e
parent71581a1507e642bbc6f698a3f43355552ee8056f (diff)
spi: fsl-espi: pre-allocate message buffer
Currently the driver allocates a 64kb buffer for each single message. On systems with little and fragmented memory this can result in memory allocation errors. Solve this by pre-allocating a buffer. This patch was developed in OpenWRT long ago, however it never made it upstream. I slightly modified the original patch to re-initialize the buffer at the beginning of each transfer. Signed-off-by: Gabor Juhos <juhosg@openwrt.org> Signed-off-by: Felix Fietkau <nbd@nbd.name> Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/spi/spi-fsl-espi.c41
-rw-r--r--drivers/spi/spi-fsl-lib.h1
2 files changed, 19 insertions, 23 deletions
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index 16fff7237ab2..81d7416668b8 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -297,57 +297,44 @@ static void fsl_espi_do_trans(struct spi_message *m,
297static void fsl_espi_cmd_trans(struct spi_message *m, 297static void fsl_espi_cmd_trans(struct spi_message *m,
298 struct fsl_espi_transfer *trans, u8 *rx_buff) 298 struct fsl_espi_transfer *trans, u8 *rx_buff)
299{ 299{
300 struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master);
300 struct spi_transfer *t; 301 struct spi_transfer *t;
301 u8 *local_buf;
302 int i = 0; 302 int i = 0;
303 struct fsl_espi_transfer *espi_trans = trans; 303 struct fsl_espi_transfer *espi_trans = trans;
304 304
305 local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL);
306 if (!local_buf) {
307 espi_trans->status = -ENOMEM;
308 return;
309 }
310
311 list_for_each_entry(t, &m->transfers, transfer_list) { 305 list_for_each_entry(t, &m->transfers, transfer_list) {
312 if (t->tx_buf) { 306 if (t->tx_buf) {
313 memcpy(local_buf + i, t->tx_buf, t->len); 307 memcpy(mspi->local_buf + i, t->tx_buf, t->len);
314 i += t->len; 308 i += t->len;
315 } 309 }
316 } 310 }
317 311
318 espi_trans->tx_buf = local_buf; 312 espi_trans->tx_buf = mspi->local_buf;
319 espi_trans->rx_buf = local_buf; 313 espi_trans->rx_buf = mspi->local_buf;
320 fsl_espi_do_trans(m, espi_trans); 314 fsl_espi_do_trans(m, espi_trans);
321 315
322 espi_trans->actual_length = espi_trans->len; 316 espi_trans->actual_length = espi_trans->len;
323 kfree(local_buf);
324} 317}
325 318
326static void fsl_espi_rw_trans(struct spi_message *m, 319static void fsl_espi_rw_trans(struct spi_message *m,
327 struct fsl_espi_transfer *trans, u8 *rx_buff) 320 struct fsl_espi_transfer *trans, u8 *rx_buff)
328{ 321{
322 struct mpc8xxx_spi *mspi = spi_master_get_devdata(m->spi->master);
329 struct spi_transfer *t; 323 struct spi_transfer *t;
330 u8 *local_buf;
331 unsigned int tx_only = 0; 324 unsigned int tx_only = 0;
332 int i = 0; 325 int i = 0;
333 326
334 local_buf = kzalloc(SPCOM_TRANLEN_MAX, GFP_KERNEL);
335 if (!local_buf) {
336 trans->status = -ENOMEM;
337 return;
338 }
339
340 list_for_each_entry(t, &m->transfers, transfer_list) { 327 list_for_each_entry(t, &m->transfers, transfer_list) {
341 if (t->tx_buf) { 328 if (t->tx_buf) {
342 memcpy(local_buf + i, t->tx_buf, t->len); 329 memcpy(mspi->local_buf + i, t->tx_buf, t->len);
343 i += t->len; 330 i += t->len;
344 if (!t->rx_buf) 331 if (!t->rx_buf)
345 tx_only += t->len; 332 tx_only += t->len;
346 } 333 }
347 } 334 }
348 335
349 trans->tx_buf = local_buf; 336 trans->tx_buf = mspi->local_buf;
350 trans->rx_buf = local_buf; 337 trans->rx_buf = mspi->local_buf;
351 fsl_espi_do_trans(m, trans); 338 fsl_espi_do_trans(m, trans);
352 339
353 if (!trans->status) { 340 if (!trans->status) {
@@ -357,18 +344,19 @@ static void fsl_espi_rw_trans(struct spi_message *m,
357 trans->len - tx_only); 344 trans->len - tx_only);
358 trans->actual_length += trans->len; 345 trans->actual_length += trans->len;
359 } 346 }
360
361 kfree(local_buf);
362} 347}
363 348
364static int fsl_espi_do_one_msg(struct spi_master *master, 349static int fsl_espi_do_one_msg(struct spi_master *master,
365 struct spi_message *m) 350 struct spi_message *m)
366{ 351{
352 struct mpc8xxx_spi *mspi = spi_master_get_devdata(master);
367 struct spi_transfer *t; 353 struct spi_transfer *t;
368 u8 *rx_buf = NULL; 354 u8 *rx_buf = NULL;
369 unsigned int xfer_len = 0; 355 unsigned int xfer_len = 0;
370 struct fsl_espi_transfer espi_trans; 356 struct fsl_espi_transfer espi_trans;
371 357
358 memset(mspi->local_buf, 0, SPCOM_TRANLEN_MAX);
359
372 list_for_each_entry(t, &m->transfers, transfer_list) { 360 list_for_each_entry(t, &m->transfers, transfer_list) {
373 if (t->rx_buf) 361 if (t->rx_buf)
374 rx_buf = t->rx_buf; 362 rx_buf = t->rx_buf;
@@ -614,6 +602,13 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
614 602
615 mpc8xxx_spi = spi_master_get_devdata(master); 603 mpc8xxx_spi = spi_master_get_devdata(master);
616 604
605 mpc8xxx_spi->local_buf =
606 devm_kmalloc(dev, SPCOM_TRANLEN_MAX, GFP_KERNEL);
607 if (!mpc8xxx_spi->local_buf) {
608 ret = -ENOMEM;
609 goto err_probe;
610 }
611
617 mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem); 612 mpc8xxx_spi->reg_base = devm_ioremap_resource(dev, mem);
618 if (IS_ERR(mpc8xxx_spi->reg_base)) { 613 if (IS_ERR(mpc8xxx_spi->reg_base)) {
619 ret = PTR_ERR(mpc8xxx_spi->reg_base); 614 ret = PTR_ERR(mpc8xxx_spi->reg_base);
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 84f5dcb7a897..065b9db212cf 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -30,6 +30,7 @@ struct mpc8xxx_spi {
30 void *rx; 30 void *rx;
31#if IS_ENABLED(CONFIG_SPI_FSL_ESPI) 31#if IS_ENABLED(CONFIG_SPI_FSL_ESPI)
32 int len; 32 int len;
33 u8 *local_buf;
33#endif 34#endif
34 35
35 int subblock; 36 int subblock;