diff options
author | Heiner Kallweit <hkallweit1@gmail.com> | 2016-09-07 16:50:22 -0400 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2016-09-12 14:58:45 -0400 |
commit | 1423877b73ed5f4982eaba8bed359605b9918a2b (patch) | |
tree | 19fe399436429fe4b6086f33300e619d1abb648e | |
parent | 71581a1507e642bbc6f698a3f43355552ee8056f (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.c | 41 | ||||
-rw-r--r-- | drivers/spi/spi-fsl-lib.h | 1 |
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, | |||
297 | static void fsl_espi_cmd_trans(struct spi_message *m, | 297 | static 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 | ||
326 | static void fsl_espi_rw_trans(struct spi_message *m, | 319 | static 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 | ||
364 | static int fsl_espi_do_one_msg(struct spi_master *master, | 349 | static 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; |