From patchwork Tue Feb 16 19:57:43 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ernst Schwab X-Patchwork-Id: 79770 Received: from lists.sourceforge.net (lists.sourceforge.net [216.34.181.88]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o1GJvqKg014128 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 16 Feb 2010 19:58:28 GMT Received: from localhost ([127.0.0.1] helo=sfs-ml-2.v29.ch3.sourceforge.com) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1NhTYO-0004ok-5I; Tue, 16 Feb 2010 19:57:52 +0000 Received: from sfi-mx-2.v28.ch3.sourceforge.com ([172.29.28.122] helo=mx.sourceforge.net) by sfs-ml-2.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1NhTYN-0004of-BM for spi-devel-general@lists.sourceforge.net; Tue, 16 Feb 2010 19:57:51 +0000 X-ACL-Warn: Received: from moutng.kundenserver.de ([212.227.17.10]) by sfi-mx-2.v28.ch3.sourceforge.com with esmtp (Exim 4.69) id 1NhTYM-0007Xx-8X; Tue, 16 Feb 2010 19:57:51 +0000 Received: from ip065 (koln-5d8135c9.pool.mediaWays.net [93.129.53.201]) by mrelayeu.kundenserver.de (node=mrbap1) with ESMTP (Nemesis) id 0M2nhO-1NzQNH1lKw-00sSwd; Tue, 16 Feb 2010 20:57:41 +0100 Date: Tue, 16 Feb 2010 20:57:43 +0100 From: Ernst Schwab To: Grant Likely , Kumar Gala , David Brownell , spi-devel-general@lists.sourceforge.net Message-Id: <20100216205743.c4d736d1.eschwab@online.de> X-Mailer: Sylpheed 3.0.0beta8 (GTK+ 2.10.14; i686-pc-mingw32) Mime-Version: 1.0 X-Provags-ID: V01U2FsdGVkX1+XPXqFl8TvHLRyhsdoUGmy//yj1r0hPPCK0TF U8ZcnGSH+psRLMHUqvKf6unluf3CPxYJrkCUbd+ftEIYmgDc1g g+C9xOz5liXiReYuUQ6EXezSZS1pSJA X-Spam-Score: -0.0 (/) X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 SPF_HELO_PASS SPF: HELO matches SPF record X-Headers-End: 1NhTYM-0007Xx-8X Cc: yi.li@analog.com, vapier@gentoo.org Subject: [spi-devel-general] [PATCH 5/5] spi: added SPI bus locking to mpc8xxx_spi X-BeenThere: spi-devel-general@lists.sourceforge.net X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux SPI core/device drivers discussion List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: spi-devel-general-bounces@lists.sourceforge.net X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Tue, 16 Feb 2010 19:58:28 +0000 (UTC) diff -upr a/drivers/spi/spi_mpc8xxx.c b/drivers/spi/spi_mpc8xxx.c --- a/drivers/spi/spi_mpc8xxx.c +++ b/drivers/spi/spi_mpc8xxx.c @@ -124,6 +124,9 @@ struct spi_pram { #define SPI_PRAM_SIZE 0x100 #define SPI_MRBLR ((unsigned int)PAGE_SIZE) +/* value for 'locked' variable to indicate that the bus is unlocked */ +#define SPIBUS_UNLOCKED 0xFF + /* SPI Controller driver's private data. */ struct mpc8xxx_spi { struct device *dev; @@ -171,6 +174,8 @@ struct mpc8xxx_spi { spinlock_t lock; struct completion done; + + u8 locked; /* chipselect number if bus is locked */ }; static void *mpc8xxx_dummy_rx; @@ -605,11 +610,39 @@ static void mpc8xxx_spi_work(struct work { struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi, work); + u8 locked_cs; + u8 next_cs; spin_lock_irq(&mpc8xxx_spi->lock); while (!list_empty(&mpc8xxx_spi->queue)) { struct spi_message *m = container_of(mpc8xxx_spi->queue.next, struct spi_message, queue); + struct spi_message *msg = NULL; + + if (mpc8xxx_spi->locked != SPIBUS_UNLOCKED) { + locked_cs = mpc8xxx_spi->locked; + next_cs = m->spi->chip_select; + + if (next_cs != locked_cs) { + list_for_each_entry(msg, &mpc8xxx_spi->queue, + queue) { + next_cs = msg->spi->chip_select; + if (next_cs == locked_cs) { + m = msg; + break; + } + } + + /* + * Do nothing even if there are messages + * for other devices + */ + if (next_cs != locked_cs) { + spin_unlock_irq(&mpc8xxx_spi->lock); + return; + } + } + } list_del_init(&m->queue); spin_unlock_irq(&mpc8xxx_spi->lock); @@ -736,6 +769,50 @@ static irqreturn_t mpc8xxx_spi_irq(s32 i return ret; } +/* + * lock the spi bus for exclusive access + */ +static int mpc8xxx_spi_lock_bus(struct spi_device *spi) +{ + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_spi->lock, flags); + if (mpc8xxx_spi->locked != SPIBUS_UNLOCKED) { + spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags); + return -ENOLCK; + } + mpc8xxx_spi->locked = spi->chip_select; + + spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags); + + return 0; +} + +/* + * unlock the spi bus from exclusive access + */ +static int mpc8xxx_spi_unlock_bus(struct spi_device *spi) +{ + struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master); + unsigned long flags; + + spin_lock_irqsave(&mpc8xxx_spi->lock, flags); + + /* remove the spi bus lock */ + mpc8xxx_spi->locked = SPIBUS_UNLOCKED; + + /* + * process all deferred messages for all chipselects + * other than the locked after the bus became unlocked + */ + queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work); + + spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags); + + return 0; +} + static int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m) { @@ -992,6 +1069,8 @@ mpc8xxx_spi_probe(struct device *dev, st master->setup = mpc8xxx_spi_setup; master->transfer = mpc8xxx_spi_transfer; master->cleanup = mpc8xxx_spi_cleanup; + master->lock_bus = mpc8xxx_spi_lock_bus; + master->unlock_bus = mpc8xxx_spi_unlock_bus; mpc8xxx_spi = spi_master_get_devdata(master); mpc8xxx_spi->dev = dev; @@ -999,6 +1078,7 @@ mpc8xxx_spi_probe(struct device *dev, st mpc8xxx_spi->get_tx = mpc8xxx_spi_tx_buf_u8; mpc8xxx_spi->flags = pdata->flags; mpc8xxx_spi->spibrg = pdata->sysclk; + mpc8xxx_spi->locked = SPIBUS_UNLOCKED; ret = mpc8xxx_spi_cpm_init(mpc8xxx_spi); if (ret)