diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c index 488d7dd78a2f..c05adcd7fbfd 100644 --- a/drivers/staging/nvec/nvec.c +++ b/drivers/staging/nvec/nvec.c @@ -62,6 +62,16 @@ #define I2C_SL_ADDR2 0x30 #define I2C_SL_DELAY_COUNT 0x3c +/** + * enum nvec_msg_category - Message categories for nvec_msg_alloc() + * @NVEC_MSG_RX: The message is an incoming message (from EC) + * @NVEC_MSG_TX: The message is an outgoing message (to EC) + */ +enum nvec_msg_category { + NVEC_MSG_RX, + NVEC_MSG_TX, +}; + static const unsigned char EC_DISABLE_EVENT_REPORTING[3] = "\x04\x00\x00"; static const unsigned char EC_ENABLE_EVENT_REPORTING[3] = "\x04\x00\x01"; static const unsigned char EC_GET_FIRMWARE_VERSION[2] = "\x07\x15"; @@ -131,23 +141,31 @@ static int nvec_status_notifier(struct notifier_block *nb, /** * nvec_msg_alloc: * @nvec: A &struct nvec_chip + * @category: Pool category, see &enum nvec_msg_category * * Allocate a single &struct nvec_msg object from the message pool of * @nvec. The result shall be passed to nvec_msg_free() if no longer * used. + * + * Outgoing messages are placed in the upper 75% of the pool, keeping the + * lower 25% available for RX buffers only. The reason is to prevent a + * situation where all buffers are full and a message is thus endlessly + * retried because the response could never be processed. */ -static struct nvec_msg *nvec_msg_alloc(struct nvec_chip *nvec) +static struct nvec_msg *nvec_msg_alloc(struct nvec_chip *nvec, + enum nvec_msg_category category) { - int i; + int i = (category == NVEC_MSG_TX) ? (NVEC_POOL_SIZE / 4) : 0; - for (i = 0; i < NVEC_POOL_SIZE; i++) { + for (; i < NVEC_POOL_SIZE; i++) { if (atomic_xchg(&nvec->msg_pool[i].used, 1) == 0) { dev_vdbg(nvec->dev, "INFO: Allocate %i\n", i); return &nvec->msg_pool[i]; } } - dev_err(nvec->dev, "could not allocate buffer\n"); + dev_err(nvec->dev, "could not allocate %s buffer\n", + (category == NVEC_MSG_TX) ? "TX" : "RX"); return NULL; } @@ -230,7 +248,8 @@ int nvec_write_async(struct nvec_chip *nvec, const unsigned char *data, struct nvec_msg *msg; unsigned long flags; - msg = nvec_msg_alloc(nvec); + msg = nvec_msg_alloc(nvec, NVEC_MSG_TX); + if (msg == NULL) return -ENOMEM; @@ -534,7 +553,7 @@ static irqreturn_t nvec_interrupt(int irq, void *dev) if (status != I2C_SL_IRQ) { nvec_invalid_flags(nvec, status, true); } else { - nvec->rx = nvec_msg_alloc(nvec); + nvec->rx = nvec_msg_alloc(nvec, NVEC_MSG_RX); nvec->rx->data[0] = received; nvec->rx->pos = 1; nvec->state = 2;