From: Viresh Kumar <viresh.kumar-qxv4g6HH51o@public.gmane.org>
To: Linus WALLEIJ <linus.walleij-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org>
Cc: "spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org"
<spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org>,
Linus Walleij
<linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
"linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org"
<linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org>,
Virupax SADASHIVPETIMATH
<virupax.sadashivpetimath-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org>
Subject: Re: [PATCH 7/7] spi/pl022: make the chip deselect handling thread safe
Date: Tue, 22 Nov 2011 13:58:56 +0530 [thread overview]
Message-ID: <4ECB5D48.8040309@st.com> (raw)
In-Reply-To: <1321950328-4882-1-git-send-email-linus.walleij-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org>
On 11/22/2011 1:55 PM, Linus WALLEIJ wrote:
> From: Virupax Sadashivpetimath <virupax.sadashivpetimath-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org>
>
> There is a possibility that the pump_message and giveback
> run in parallel on a SMP system. Both the pump_message and
> giveback threads work on the same SPI message queue.
> Results will be in correct if the pump_message gets to
> work on the queue first.
>
> when the pump_message works with the queue, it reads the
> head of the queue and removes it from the queue. pump_message
> activates the chip select depending on this message read.
>
> This leads to giveback working on the modified queue or a
> emptied queue. If the queue is empty or if the next message on
> the queue (which is not the actual next message, as the pump
> message has removed the next message from the queue) is not for
> the same SPI device as that Of the previous one, giveback will
> de-activate the chip select activated by pump_message(),
> which is wrong.
>
> To solve this problem pump_message is made not to run and
> access the queue until the giveback is done handling the queue.
> I.e. by making the cur_msg NULL after the giveback has read the
> queue.
>
> Also a state variable has been introduced to keep track of when
> the CS for next message is already activated and avoid to
> double-activate it.
>
> Signed-off-by: Virupax Sadashivpetimath <virupax.sadashivpetimath-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org>
> Signed-off-by: Linus Walleij <linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> ---
> drivers/spi/spi-pl022.c | 72 ++++++++++++++++++++++++-----------------------
> 1 files changed, 37 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
> index 13988a3..1cff8ad 100644
> --- a/drivers/spi/spi-pl022.c
> +++ b/drivers/spi/spi-pl022.c
> @@ -340,6 +340,10 @@ struct vendor_data {
> * @cur_msg: Pointer to current spi_message being processed
> * @cur_transfer: Pointer to current spi_transfer
> * @cur_chip: pointer to current clients chip(assigned from controller_state)
> + * @next_msg_cs_active: the next message in the queue has been examined
> + * and it was found that it uses the same chip select as the previous
> + * message, so we left it active after the previous transfer, and it's
> + * active already.
> * @tx: current position in TX buffer to be read
> * @tx_end: end position in TX buffer to be read
> * @rx: current position in RX buffer to be written
> @@ -373,6 +377,7 @@ struct pl022 {
> struct spi_message *cur_msg;
> struct spi_transfer *cur_transfer;
> struct chip_data *cur_chip;
> + bool next_msg_cs_active;
> void *tx;
> void *tx_end;
> void *rx;
> @@ -445,23 +450,9 @@ static void giveback(struct pl022 *pl022)
> struct spi_transfer *last_transfer;
> unsigned long flags;
> struct spi_message *msg;
> - void (*curr_cs_control) (u32 command);
> + pl022->next_msg_cs_active = false;
>
> - /*
> - * This local reference to the chip select function
> - * is needed because we set curr_chip to NULL
> - * as a step toward termininating the message.
> - */
> - curr_cs_control = pl022->cur_chip->cs_control;
> - spin_lock_irqsave(&pl022->queue_lock, flags);
> - msg = pl022->cur_msg;
> - pl022->cur_msg = NULL;
> - pl022->cur_transfer = NULL;
> - pl022->cur_chip = NULL;
> - queue_work(pl022->workqueue, &pl022->pump_messages);
> - spin_unlock_irqrestore(&pl022->queue_lock, flags);
> -
> - last_transfer = list_entry(msg->transfers.prev,
> + last_transfer = list_entry(pl022->cur_msg->transfers.prev,
> struct spi_transfer,
> transfer_list);
>
> @@ -473,18 +464,13 @@ static void giveback(struct pl022 *pl022)
> */
> udelay(last_transfer->delay_usecs);
>
> - /*
> - * Drop chip select UNLESS cs_change is true or we are returning
> - * a message with an error, or next message is for another chip
> - */
> - if (!last_transfer->cs_change)
> - curr_cs_control(SSP_CHIP_DESELECT);
> - else {
> + if (!last_transfer->cs_change) {
> struct spi_message *next_msg;
>
> - /* Holding of cs was hinted, but we need to make sure
> - * the next message is for the same chip. Don't waste
> - * time with the following tests unless this was hinted.
> + /*
> + * cs_change was not set. We can keep the chip select
> + * enabled if there is message in the queue and it is
> + * for the same spi device.
> *
> * We cannot postpone this until pump_messages, because
> * after calling msg->complete (below) the driver that
> @@ -501,14 +487,26 @@ static void giveback(struct pl022 *pl022)
> struct spi_message, queue);
> spin_unlock_irqrestore(&pl022->queue_lock, flags);
>
> - /* see if the next and current messages point
> - * to the same chip
> + /*
> + * see if the next and current messages point
> + * to the same spi device.
> */
> - if (next_msg && next_msg->spi != msg->spi)
> + if (next_msg && next_msg->spi != pl022->cur_msg->spi)
> next_msg = NULL;
> - if (!next_msg || msg->state == STATE_ERROR)
> - curr_cs_control(SSP_CHIP_DESELECT);
> + if (!next_msg || pl022->cur_msg->state == STATE_ERROR)
> + pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
> + else
> + pl022->next_msg_cs_active = true;
> }
> +
> + spin_lock_irqsave(&pl022->queue_lock, flags);
> + msg = pl022->cur_msg;
> + pl022->cur_msg = NULL;
> + pl022->cur_transfer = NULL;
> + pl022->cur_chip = NULL;
> + queue_work(pl022->workqueue, &pl022->pump_messages);
> + spin_unlock_irqrestore(&pl022->queue_lock, flags);
> +
> msg->state = NULL;
> if (msg->complete)
> msg->complete(msg->context);
> @@ -1350,7 +1348,7 @@ static void pump_transfers(unsigned long data)
> */
> udelay(previous->delay_usecs);
>
> - /* Drop chip select only if cs_change is requested */
> + /* Reselect chip select only if cs_change was requested */
> if (previous->cs_change)
> pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> } else {
> @@ -1389,8 +1387,10 @@ static void do_interrupt_dma_transfer(struct pl022 *pl022)
> */
> u32 irqflags = ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM;
>
> - /* Enable target chip */
> - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> + /* Enable target chip, if not already active */
> + if (!pl022->next_msg_cs_active)
> + pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> +
> if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
> /* Error path */
> pl022->cur_msg->state = STATE_ERROR;
> @@ -1445,7 +1445,8 @@ static void do_polling_transfer(struct pl022 *pl022)
> } else {
> /* STATE_START */
> message->state = STATE_RUNNING;
> - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> + if (!pl022->next_msg_cs_active)
> + pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> }
>
> /* Configuration Changing Per Transfer */
> @@ -1604,6 +1605,7 @@ static int start_queue(struct pl022 *pl022)
> pl022->cur_msg = NULL;
> pl022->cur_transfer = NULL;
> pl022->cur_chip = NULL;
> + pl022->next_msg_cs_active = false;
> spin_unlock_irqrestore(&pl022->queue_lock, flags);
>
> queue_work(pl022->workqueue, &pl022->pump_messages);
Reviewed-by: Viresh Kumar <viresh.kumar-qxv4g6HH51o@public.gmane.org>
--
viresh
------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure
contains a definitive record of customers, application performance,
security threats, fraudulent activity, and more. Splunk takes this
data and makes sense of it. IT sense. And common sense.
http://p.sf.net/sfu/splunk-novd2d
WARNING: multiple messages have this Message-ID (diff)
From: viresh.kumar@st.com (Viresh Kumar)
To: linux-arm-kernel@lists.infradead.org
Subject: [PATCH 7/7] spi/pl022: make the chip deselect handling thread safe
Date: Tue, 22 Nov 2011 13:58:56 +0530 [thread overview]
Message-ID: <4ECB5D48.8040309@st.com> (raw)
In-Reply-To: <1321950328-4882-1-git-send-email-linus.walleij@stericsson.com>
On 11/22/2011 1:55 PM, Linus WALLEIJ wrote:
> From: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>
>
> There is a possibility that the pump_message and giveback
> run in parallel on a SMP system. Both the pump_message and
> giveback threads work on the same SPI message queue.
> Results will be in correct if the pump_message gets to
> work on the queue first.
>
> when the pump_message works with the queue, it reads the
> head of the queue and removes it from the queue. pump_message
> activates the chip select depending on this message read.
>
> This leads to giveback working on the modified queue or a
> emptied queue. If the queue is empty or if the next message on
> the queue (which is not the actual next message, as the pump
> message has removed the next message from the queue) is not for
> the same SPI device as that Of the previous one, giveback will
> de-activate the chip select activated by pump_message(),
> which is wrong.
>
> To solve this problem pump_message is made not to run and
> access the queue until the giveback is done handling the queue.
> I.e. by making the cur_msg NULL after the giveback has read the
> queue.
>
> Also a state variable has been introduced to keep track of when
> the CS for next message is already activated and avoid to
> double-activate it.
>
> Signed-off-by: Virupax Sadashivpetimath <virupax.sadashivpetimath@stericsson.com>
> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
> ---
> drivers/spi/spi-pl022.c | 72 ++++++++++++++++++++++++-----------------------
> 1 files changed, 37 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
> index 13988a3..1cff8ad 100644
> --- a/drivers/spi/spi-pl022.c
> +++ b/drivers/spi/spi-pl022.c
> @@ -340,6 +340,10 @@ struct vendor_data {
> * @cur_msg: Pointer to current spi_message being processed
> * @cur_transfer: Pointer to current spi_transfer
> * @cur_chip: pointer to current clients chip(assigned from controller_state)
> + * @next_msg_cs_active: the next message in the queue has been examined
> + * and it was found that it uses the same chip select as the previous
> + * message, so we left it active after the previous transfer, and it's
> + * active already.
> * @tx: current position in TX buffer to be read
> * @tx_end: end position in TX buffer to be read
> * @rx: current position in RX buffer to be written
> @@ -373,6 +377,7 @@ struct pl022 {
> struct spi_message *cur_msg;
> struct spi_transfer *cur_transfer;
> struct chip_data *cur_chip;
> + bool next_msg_cs_active;
> void *tx;
> void *tx_end;
> void *rx;
> @@ -445,23 +450,9 @@ static void giveback(struct pl022 *pl022)
> struct spi_transfer *last_transfer;
> unsigned long flags;
> struct spi_message *msg;
> - void (*curr_cs_control) (u32 command);
> + pl022->next_msg_cs_active = false;
>
> - /*
> - * This local reference to the chip select function
> - * is needed because we set curr_chip to NULL
> - * as a step toward termininating the message.
> - */
> - curr_cs_control = pl022->cur_chip->cs_control;
> - spin_lock_irqsave(&pl022->queue_lock, flags);
> - msg = pl022->cur_msg;
> - pl022->cur_msg = NULL;
> - pl022->cur_transfer = NULL;
> - pl022->cur_chip = NULL;
> - queue_work(pl022->workqueue, &pl022->pump_messages);
> - spin_unlock_irqrestore(&pl022->queue_lock, flags);
> -
> - last_transfer = list_entry(msg->transfers.prev,
> + last_transfer = list_entry(pl022->cur_msg->transfers.prev,
> struct spi_transfer,
> transfer_list);
>
> @@ -473,18 +464,13 @@ static void giveback(struct pl022 *pl022)
> */
> udelay(last_transfer->delay_usecs);
>
> - /*
> - * Drop chip select UNLESS cs_change is true or we are returning
> - * a message with an error, or next message is for another chip
> - */
> - if (!last_transfer->cs_change)
> - curr_cs_control(SSP_CHIP_DESELECT);
> - else {
> + if (!last_transfer->cs_change) {
> struct spi_message *next_msg;
>
> - /* Holding of cs was hinted, but we need to make sure
> - * the next message is for the same chip. Don't waste
> - * time with the following tests unless this was hinted.
> + /*
> + * cs_change was not set. We can keep the chip select
> + * enabled if there is message in the queue and it is
> + * for the same spi device.
> *
> * We cannot postpone this until pump_messages, because
> * after calling msg->complete (below) the driver that
> @@ -501,14 +487,26 @@ static void giveback(struct pl022 *pl022)
> struct spi_message, queue);
> spin_unlock_irqrestore(&pl022->queue_lock, flags);
>
> - /* see if the next and current messages point
> - * to the same chip
> + /*
> + * see if the next and current messages point
> + * to the same spi device.
> */
> - if (next_msg && next_msg->spi != msg->spi)
> + if (next_msg && next_msg->spi != pl022->cur_msg->spi)
> next_msg = NULL;
> - if (!next_msg || msg->state == STATE_ERROR)
> - curr_cs_control(SSP_CHIP_DESELECT);
> + if (!next_msg || pl022->cur_msg->state == STATE_ERROR)
> + pl022->cur_chip->cs_control(SSP_CHIP_DESELECT);
> + else
> + pl022->next_msg_cs_active = true;
> }
> +
> + spin_lock_irqsave(&pl022->queue_lock, flags);
> + msg = pl022->cur_msg;
> + pl022->cur_msg = NULL;
> + pl022->cur_transfer = NULL;
> + pl022->cur_chip = NULL;
> + queue_work(pl022->workqueue, &pl022->pump_messages);
> + spin_unlock_irqrestore(&pl022->queue_lock, flags);
> +
> msg->state = NULL;
> if (msg->complete)
> msg->complete(msg->context);
> @@ -1350,7 +1348,7 @@ static void pump_transfers(unsigned long data)
> */
> udelay(previous->delay_usecs);
>
> - /* Drop chip select only if cs_change is requested */
> + /* Reselect chip select only if cs_change was requested */
> if (previous->cs_change)
> pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> } else {
> @@ -1389,8 +1387,10 @@ static void do_interrupt_dma_transfer(struct pl022 *pl022)
> */
> u32 irqflags = ENABLE_ALL_INTERRUPTS & ~SSP_IMSC_MASK_RXIM;
>
> - /* Enable target chip */
> - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> + /* Enable target chip, if not already active */
> + if (!pl022->next_msg_cs_active)
> + pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> +
> if (set_up_next_transfer(pl022, pl022->cur_transfer)) {
> /* Error path */
> pl022->cur_msg->state = STATE_ERROR;
> @@ -1445,7 +1445,8 @@ static void do_polling_transfer(struct pl022 *pl022)
> } else {
> /* STATE_START */
> message->state = STATE_RUNNING;
> - pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> + if (!pl022->next_msg_cs_active)
> + pl022->cur_chip->cs_control(SSP_CHIP_SELECT);
> }
>
> /* Configuration Changing Per Transfer */
> @@ -1604,6 +1605,7 @@ static int start_queue(struct pl022 *pl022)
> pl022->cur_msg = NULL;
> pl022->cur_transfer = NULL;
> pl022->cur_chip = NULL;
> + pl022->next_msg_cs_active = false;
> spin_unlock_irqrestore(&pl022->queue_lock, flags);
>
> queue_work(pl022->workqueue, &pl022->pump_messages);
Reviewed-by: Viresh Kumar <viresh.kumar@st.com>
--
viresh
next prev parent reply other threads:[~2011-11-22 8:28 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-11-22 8:25 [PATCH 7/7] spi/pl022: make the chip deselect handling thread safe Linus Walleij
2011-11-22 8:25 ` Linus Walleij
[not found] ` <1321950328-4882-1-git-send-email-linus.walleij-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org>
2011-11-22 8:28 ` Viresh Kumar [this message]
2011-11-22 8:28 ` Viresh Kumar
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4ECB5D48.8040309@st.com \
--to=viresh.kumar-qxv4g6hh51o@public.gmane.org \
--cc=linus.walleij-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org \
--cc=linus.walleij-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org \
--cc=spi-devel-general-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org \
--cc=virupax.sadashivpetimath-0IS4wlFg1OjSUeElwK9/Pw@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.