From patchwork Tue Feb 16 19:57:28 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ernst Schwab X-Patchwork-Id: 79772 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 o1GJw2h3014265 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO) for ; Tue, 16 Feb 2010 19:58:38 GMT Received: from localhost ([127.0.0.1] helo=sfs-ml-1.v29.ch3.sourceforge.com) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1NhTYY-0004sA-Jt; Tue, 16 Feb 2010 19:58:02 +0000 Received: from sfi-mx-4.v28.ch3.sourceforge.com ([172.29.28.124] helo=mx.sourceforge.net) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.69) (envelope-from ) id 1NhTYX-0004rn-1u for spi-devel-general@lists.sourceforge.net; Tue, 16 Feb 2010 19:58:01 +0000 X-ACL-Warn: Received: from moutng.kundenserver.de ([212.227.17.8]) by sfi-mx-4.v28.ch3.sourceforge.com with esmtp (Exim 4.69) id 1NhTYW-0001Ne-3L; Tue, 16 Feb 2010 19:58:00 +0000 Received: from ip065 (koln-5d8135c9.pool.mediaWays.net [93.129.53.201]) by mrelayeu.kundenserver.de (node=mrbap1) with ESMTP (Nemesis) id 0LjdUG-1OEKKM2Fku-00bUdR; Tue, 16 Feb 2010 20:57:27 +0100 Date: Tue, 16 Feb 2010 20:57:28 +0100 From: Ernst Schwab To: Grant Likely , Kumar Gala , David Brownell , spi-devel-general@lists.sourceforge.net Message-Id: <20100216205728.86960a9e.eschwab@online.de> X-Mailer: Sylpheed 3.0.0beta8 (GTK+ 2.10.14; i686-pc-mingw32) Mime-Version: 1.0 X-Provags-ID: V01U2FsdGVkX18upYHuagSf/Rqj6R7sP+XAMiLkpRHpiYPxWv/ kSSZwvgwV2H1LFMZbDG/A5nxnUpYHiJWyy9F3/uwoydRsNJdrQ ehS9d2d9ezeI9/q8g0ArzM/s0WX7P9T 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: 1NhTYW-0001Ne-3L Cc: yi.li@analog.com, vapier@gentoo.org Subject: [spi-devel-general] [PATCH 2/5] spi: spi_register_lock_bus and spi_unregister_lock_bus 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:38 +0000 (UTC) diff -upr a/drivers/spi/spi.c b/drivers/spi/spi.c --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -285,6 +285,18 @@ int spi_add_device(struct spi_device *sp goto done; } + /* If exclusive SPI bus access was granted to an SPI client, all + * further spi_add_device calls are abandoned. + */ + if (spi->master->exclusive && + spi->chip_select!=spi->master->bus_lock_chip_select) { + dev_err(dev, "SPI bus is locked for exclusive use " + "by chipselect %d; chipselect %d cannot be used\n", + spi->master->bus_lock_chip_select, spi->chip_select); + status = -EBUSY; + goto done; + } + /* Drivers may modify this initial i/o setup, but will * normally rely on the device being setup. Devices * using SPI_CS_HIGH can't coexist well otherwise... @@ -524,6 +536,10 @@ int spi_register_master(struct spi_maste dynamic = 1; } + /* no device has registered the master for exclusive use yet */ + master->bus_lock_chip_select = SPI_MASTER_BUS_UNLOCKED; + master->exclusive = 0; + /* register the device, then userspace will see it. * registration fails if the bus ID is in use. */ @@ -783,6 +799,96 @@ int spi_unlock_bus(struct spi_device *sp } EXPORT_SYMBOL_GPL(spi_unlock_bus); +/* REVISIT: + * Temporary solution: + * Helper functions to check if exclusive access possible. + * If all masters support the spi_lock_bus callback, these can be removed. + */ +struct count_children { + unsigned n; + struct bus_type *bus; +}; + +static int maybe_count_child(struct device *dev, void *c) +{ + struct count_children *ccp = c; + + if (dev->bus == ccp->bus) { + if (ccp->n) + return -EBUSY; + ccp->n++; + } + return 0; +} + +static int spi_lock_bus_check (struct spi_device *spi) +{ + int status; + + if (spi->master->num_chipselect > 1) { + struct count_children cc; + + cc.n = 0; + cc.bus = spi->dev.bus; + status = device_for_each_child(spi->dev.parent, &cc, + maybe_count_child); + if (status < 0) { + return status; + } + } + return 0; +} + +/** + * spi_register_lock_bus - register SPI device for use of spi_lock_bus + */ +int spi_register_lock_bus(struct spi_device *spi) +{ + if (spi->master->bus_lock_chip_select != SPI_MASTER_BUS_UNLOCKED) { + /* currently, only one device can use bus locking */ + dev_err(&spi->dev, "only one SPI device can " + "get exclusive SPI bus access\n"); + return -EBUSY; + } + + if (!spi->master->lock_bus) { + /* REVISIT: + * If all masters support the spi_lock_bus entry, + * this can be removed. + * A check for exclusive SPI bus use is done if the SPI master + * does not support bus locking. + */ + if (spi_lock_bus_check(spi) < 0) { + return -EBUSY; + } + + /* lock out all future spi_add_device calls */ + spi->master->exclusive = 1; + dev_warn(&spi->dev, "ENFORCING SPI bus stays unshared!\n"); + } + + /* Remember the chip_select for which the bus is locked. */ + spi->master->bus_lock_chip_select = spi->chip_select; + + return 0; +} +EXPORT_SYMBOL_GPL(spi_register_lock_bus); + +/** + * spi_unregister_lock_bus - unregister SPI device for use of spi_lock_bus + */ +int spi_unregister_lock_bus(struct spi_device *spi) +{ + if (spi->master->bus_lock_chip_select != spi->chip_select) { + /* unregister without a matching register */ + return -EINVAL; + } + + spi->master->bus_lock_chip_select = SPI_MASTER_BUS_UNLOCKED; + return 0; +} +EXPORT_SYMBOL_GPL(spi_unregister_lock_bus); + /** * spi_sync - blocking/synchronous SPI data transfers * @spi: device with which data will be exchanged diff -upr a/include/linux/spi/spi.h b/include/linux/spi/spi.h --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -263,6 +263,14 @@ struct spi_master { #define SPI_MASTER_NO_RX BIT(1) /* can't do buffer read */ #define SPI_MASTER_NO_TX BIT(2) /* can't do buffer write */ + /* chipselect of the (one) spi device that may lock the bus for + * exclusive use */ + u8 bus_lock_chip_select; +#define SPI_MASTER_BUS_UNLOCKED 0xFF /* value to indicate unlocked */ + + /* enforce that the spi bus remains unshared */ + u8 exclusive; + /* Setup mode and clock, etc (spi driver may call many times). * * IMPORTANT: this may be called when transfers to another @@ -555,6 +563,10 @@ extern int spi_async(struct spi_device * */ extern int spi_sync(struct spi_device *spi, struct spi_message *message); + +/* Functions to ensure exclusive access to the spi bus */ +extern int spi_register_lock_bus(struct spi_device *spi); +extern int spi_unregister_lock_bus(struct spi_device *spi); extern int spi_lock_bus(struct spi_device *spi); extern int spi_unlock_bus(struct spi_device *spi);