staging: nvec: Allow TX buffers only in the upper 75% of the pool
authorJulian Andres Klode <jak@jak-linux.org>
Tue, 27 Sep 2011 17:00:59 +0000 (19:00 +0200)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 30 Sep 2011 00:41:36 +0000 (17:41 -0700)
Allow TX buffers to be allocated only in the upper 75% of the pool
to avoid a completely filled buffer preventing the driver from
processing responses. This also improves performance, as RX
allocations do not require checking buffers allocated for TX
unless there are more than 16 incoming messages -- which is
highly unlikely.

An earlier version used the lower 75% for TX messages, but
that was considered to be not that effective due to the
overlaps of RX and TX buffers mentioned above.

Signed-off-by: Julian Andres Klode <jak@jak-linux.org>
Acked-by: Marc Dietrich <marvin24@gmx.de>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/staging/nvec/nvec.c

index 488d7dd..c05adcd 100644 (file)
 #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;