From 986733e01d258c26107f1da9d8d47c718349ad2f Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Mon, 15 May 2006 09:43:58 -0700 Subject: [PATCH] RCU: introduce rcu_needs_cpu() interface With "Paul E. McKenney" Introduce rcu_needs_cpu() interface. This can be used to tell if there will be a new rcu batch on a cpu soon by looking at the curlist pointer. This can be used to avoid to enter a tickless idle state where the cpu would miss that a new batch is ready when rcu_start_batch would be called on a different cpu. Signed-off-by: Heiko Carstens Cc: "Paul E. McKenney" Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/rcupdate.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/linux') diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h index 5673008b61e1..970284f571a6 100644 --- a/include/linux/rcupdate.h +++ b/include/linux/rcupdate.h @@ -132,6 +132,7 @@ static inline void rcu_bh_qsctr_inc(int cpu) } extern int rcu_pending(int cpu); +extern int rcu_needs_cpu(int cpu); /** * rcu_read_lock - mark the beginning of an RCU read-side critical section. -- cgit v1.3-8-gc7d7 From 5e376613899076396d0c97de67ad072587267370 Mon Sep 17 00:00:00 2001 From: Trent Piepho Date: Mon, 15 May 2006 09:44:06 -0700 Subject: [PATCH] symbol_put_addr() locks kernel Even since a previous patch: Fix race between CONFIG_DEBUG_SLABALLOC and modules Sun, 27 Jun 2004 17:55:19 +0000 (17:55 +0000) http://www.kernel.org/git/?p=linux/kernel/git/torvalds/old-2.6-bkcvs.git;a=commit;h=92b3db26d31cf21b70e3c1eadc56c179506d8fbe The function symbol_put_addr() will deadlock the kernel. symbol_put_addr() would acquire modlist_lock, then while holding the lock call two functions kernel_text_address() and module_text_address() which also try to acquire the same lock. This deadlocks the kernel of course. This patch changes symbol_put_addr() to not acquire the modlist_lock, it doesn't need it since it never looks at the module list directly. Also, it now uses core_kernel_text() instead of kernel_text_address(). The latter has an additional check for addr inside a module, but we don't need to do that since we call module_text_address() (the same function kernel_text_address uses) ourselves. Signed-off-by: Trent Piepho Cc: Zwane Mwaikambo Acked-by: Rusty Russell Cc: Johannes Stezenbach Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/kernel.h | 1 + kernel/extable.c | 2 +- kernel/module.c | 12 ++++++------ 3 files changed, 8 insertions(+), 7 deletions(-) (limited to 'include/linux') diff --git a/include/linux/kernel.h b/include/linux/kernel.h index e1bd0842f6a1..f4fc576ed4c4 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -124,6 +124,7 @@ extern int get_option(char **str, int *pint); extern char *get_options(const char *str, int nints, int *ints); extern unsigned long long memparse(char *ptr, char **retptr); +extern int core_kernel_text(unsigned long addr); extern int __kernel_text_address(unsigned long addr); extern int kernel_text_address(unsigned long addr); extern int session_of_pgrp(int pgrp); diff --git a/kernel/extable.c b/kernel/extable.c index 7501b531ceed..7fe262855317 100644 --- a/kernel/extable.c +++ b/kernel/extable.c @@ -40,7 +40,7 @@ const struct exception_table_entry *search_exception_tables(unsigned long addr) return e; } -static int core_kernel_text(unsigned long addr) +int core_kernel_text(unsigned long addr) { if (addr >= (unsigned long)_stext && addr <= (unsigned long)_etext) diff --git a/kernel/module.c b/kernel/module.c index d24deb0dbbc9..bbe04862e1b0 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -705,14 +705,14 @@ EXPORT_SYMBOL(__symbol_put); void symbol_put_addr(void *addr) { - unsigned long flags; + struct module *modaddr; - spin_lock_irqsave(&modlist_lock, flags); - if (!kernel_text_address((unsigned long)addr)) - BUG(); + if (core_kernel_text((unsigned long)addr)) + return; - module_put(module_text_address((unsigned long)addr)); - spin_unlock_irqrestore(&modlist_lock, flags); + if (!(modaddr = module_text_address((unsigned long)addr))) + BUG(); + module_put(modaddr); } EXPORT_SYMBOL_GPL(symbol_put_addr); -- cgit v1.3-8-gc7d7 From 39d24e64263cd3211705d3b61ea4171c65030921 Mon Sep 17 00:00:00 2001 From: Mike Kravetz Date: Mon, 15 May 2006 09:44:13 -0700 Subject: [PATCH] add slab_is_available() routine for boot code slab_is_available() indicates slab based allocators are available for use. SPARSEMEM code needs to know this as it can be called at various times during the boot process. Signed-off-by: Mike Kravetz Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/slab.h | 1 + mm/slab.c | 8 ++++++++ mm/sparse.c | 2 +- 3 files changed, 10 insertions(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/slab.h b/include/linux/slab.h index 3af03b19c983..2d985d59c7b8 100644 --- a/include/linux/slab.h +++ b/include/linux/slab.h @@ -150,6 +150,7 @@ static inline void *kcalloc(size_t n, size_t size, gfp_t flags) extern void kfree(const void *); extern unsigned int ksize(const void *); +extern int slab_is_available(void); #ifdef CONFIG_NUMA extern void *kmem_cache_alloc_node(kmem_cache_t *, gfp_t flags, int node); diff --git a/mm/slab.c b/mm/slab.c index c32af7e7581e..b1d643b5238d 100644 --- a/mm/slab.c +++ b/mm/slab.c @@ -700,6 +700,14 @@ static enum { FULL } g_cpucache_up; +/* + * used by boot code to determine if it can use slab based allocator + */ +int slab_is_available(void) +{ + return g_cpucache_up == FULL; +} + static DEFINE_PER_CPU(struct work_struct, reap_work); static void free_block(struct kmem_cache *cachep, void **objpp, int len, diff --git a/mm/sparse.c b/mm/sparse.c index d7c32de99ee8..c5e89eb9ac8f 100644 --- a/mm/sparse.c +++ b/mm/sparse.c @@ -32,7 +32,7 @@ static struct mem_section *sparse_index_alloc(int nid) unsigned long array_size = SECTIONS_PER_ROOT * sizeof(struct mem_section); - if (system_state == SYSTEM_RUNNING) + if (slab_is_available()) section = kmalloc_node(array_size, GFP_KERNEL, nid); else section = alloc_bootmem_node(NODE_DATA(nid), array_size); -- cgit v1.3-8-gc7d7 From e6333fd4ddf7a583480017f535b9ea53c116ab81 Mon Sep 17 00:00:00 2001 From: Hua Zhong Date: Mon, 15 May 2006 09:44:22 -0700 Subject: [PATCH] fix can_share_swap_page() when !CONFIG_SWAP can_share_swap_page() is used to check if the page has the last reference. This avoids allocating a new page for COW if it's the last page. However, if CONFIG_SWAP is not set, can_share_swap_page() is defined as 0, thus always causes a copy for the last COW page. The below simple patch fixes it. Signed-off-by: Hua Zhong Cc: David Howells Cc: Hugh Dickins Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- include/linux/swap.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'include/linux') diff --git a/include/linux/swap.h b/include/linux/swap.h index 5b1fdf1cff4f..f03c24719302 100644 --- a/include/linux/swap.h +++ b/include/linux/swap.h @@ -296,7 +296,7 @@ static inline void disable_swap_token(void) #define read_swap_cache_async(swp,vma,addr) NULL #define lookup_swap_cache(swp) NULL #define valid_swaphandles(swp, off) 0 -#define can_share_swap_page(p) 0 +#define can_share_swap_page(p) (page_mapcount(p) == 1) #define move_to_swap_cache(p, swp) 1 #define move_from_swap_cache(p, i, m) 1 #define __delete_from_swap_cache(p) /*NOTHING*/ -- cgit v1.3-8-gc7d7 From 4cff33f94fefcce1b3c01a9d1da6bb85fe3cbdfa Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Fri, 17 Feb 2006 10:02:18 -0800 Subject: [PATCH] SPI: per-transfer overrides for wordsize and clocking Some protocols (like one for some bitmap displays) require different clock speed or word size settings for each transfer in an SPI message. This adds those parameters to struct spi_transfer. They are to be used when they are nonzero; otherwise the defaults from spi_device are to be used. The patch also adds a setup_transfer callback to spi_bitbang, uses it for messages that use those overrides, and implements it so that the pure bitbanging code can help resolve any questions about how it should work. Signed-off-by: Imre Deak Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi_bitbang.c | 77 +++++++++++++++++++++++++++++++++-------- include/linux/spi/spi.h | 8 +++++ include/linux/spi/spi_bitbang.h | 6 ++++ 3 files changed, 77 insertions(+), 14 deletions(-) (limited to 'include/linux') diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index f037e5593269..0525c99118c3 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -138,6 +138,43 @@ static unsigned bitbang_txrx_32( return t->len - count; } +static int +bitbang_transfer_setup(struct spi_device *spi, struct spi_transfer *t) +{ + struct spi_bitbang_cs *cs = spi->controller_state; + u8 bits_per_word; + u32 hz; + + if (t) { + bits_per_word = t->bits_per_word; + hz = t->speed_hz; + } else { + bits_per_word = 0; + hz = 0; + } + + /* spi_transfer level calls that work per-word */ + if (!bits_per_word) + bits_per_word = spi->bits_per_word; + if (bits_per_word <= 8) + cs->txrx_bufs = bitbang_txrx_8; + else if (bits_per_word <= 16) + cs->txrx_bufs = bitbang_txrx_16; + else if (bits_per_word <= 32) + cs->txrx_bufs = bitbang_txrx_32; + else + return -EINVAL; + + /* nsecs = (clock period)/2 */ + if (!hz) + hz = spi->max_speed_hz; + cs->nsecs = (1000000000/2) / hz; + if (cs->nsecs > MAX_UDELAY_MS * 1000) + return -EINVAL; + + return 0; +} + /** * spi_bitbang_setup - default setup for per-word I/O loops */ @@ -145,6 +182,7 @@ int spi_bitbang_setup(struct spi_device *spi) { struct spi_bitbang_cs *cs = spi->controller_state; struct spi_bitbang *bitbang; + int retval; if (!spi->max_speed_hz) return -EINVAL; @@ -160,25 +198,14 @@ int spi_bitbang_setup(struct spi_device *spi) if (!spi->bits_per_word) spi->bits_per_word = 8; - /* spi_transfer level calls that work per-word */ - if (spi->bits_per_word <= 8) - cs->txrx_bufs = bitbang_txrx_8; - else if (spi->bits_per_word <= 16) - cs->txrx_bufs = bitbang_txrx_16; - else if (spi->bits_per_word <= 32) - cs->txrx_bufs = bitbang_txrx_32; - else - return -EINVAL; - /* per-word shift register access, in hardware or bitbanging */ cs->txrx_word = bitbang->txrx_word[spi->mode & (SPI_CPOL|SPI_CPHA)]; if (!cs->txrx_word) return -EINVAL; - /* nsecs = (clock period)/2 */ - cs->nsecs = (1000000000/2) / (spi->max_speed_hz); - if (cs->nsecs > MAX_UDELAY_MS * 1000) - return -EINVAL; + retval = bitbang_transfer_setup(spi, NULL); + if (retval < 0) + return retval; dev_dbg(&spi->dev, "%s, mode %d, %u bits/w, %u nsec\n", __FUNCTION__, spi->mode & (SPI_CPOL | SPI_CPHA), @@ -246,6 +273,8 @@ static void bitbang_work(void *_bitbang) unsigned tmp; unsigned cs_change; int status; + int (*setup_transfer)(struct spi_device *, + struct spi_transfer *); m = container_of(bitbang->queue.next, struct spi_message, queue); @@ -262,6 +291,7 @@ static void bitbang_work(void *_bitbang) tmp = 0; cs_change = 1; status = 0; + setup_transfer = NULL; list_for_each_entry (t, &m->transfers, transfer_list) { if (bitbang->shutdown) { @@ -269,6 +299,20 @@ static void bitbang_work(void *_bitbang) break; } + /* override or restore speed and wordsize */ + if (t->speed_hz || t->bits_per_word) { + setup_transfer = bitbang->setup_transfer; + if (!setup_transfer) { + status = -ENOPROTOOPT; + break; + } + } + if (setup_transfer) { + status = setup_transfer(spi, t); + if (status < 0) + break; + } + /* set up default clock polarity, and activate chip; * this implicitly updates clock and spi modes as * previously recorded for this device via setup(). @@ -325,6 +369,10 @@ static void bitbang_work(void *_bitbang) m->status = status; m->complete(m->context); + /* restore speed and wordsize */ + if (setup_transfer) + setup_transfer(spi, NULL); + /* normally deactivate chipselect ... unless no error and * cs_change has hinted that the next message will probably * be for this chip too. @@ -406,6 +454,7 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) bitbang->use_dma = 0; bitbang->txrx_bufs = spi_bitbang_bufs; if (!bitbang->master->setup) { + bitbang->setup_transfer = bitbang_transfer_setup; bitbang->master->setup = spi_bitbang_setup; bitbang->master->cleanup = spi_bitbang_cleanup; } diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index b05f1463a267..caa4665e3fa2 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -31,6 +31,7 @@ extern struct bus_type spi_bus_type; * @master: SPI controller used with the device. * @max_speed_hz: Maximum clock rate to be used with this chip * (on this board); may be changed by the device's driver. + * The spi_transfer.speed_hz can override this for each transfer. * @chip-select: Chipselect, distinguishing chips handled by "master". * @mode: The spi mode defines how data is clocked out and in. * This may be changed by the device's driver. @@ -38,6 +39,7 @@ extern struct bus_type spi_bus_type; * like eight or 12 bits are common. In-memory wordsizes are * powers of two bytes (e.g. 20 bit samples use 32 bits). * This may be changed by the device's driver. + * The spi_transfer.bits_per_word can override this for each transfer. * @irq: Negative, or the number passed to request_irq() to receive * interrupts from this device. * @controller_state: Controller's runtime state @@ -268,6 +270,10 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum); * @tx_dma: DMA address of tx_buf, if spi_message.is_dma_mapped * @rx_dma: DMA address of rx_buf, if spi_message.is_dma_mapped * @len: size of rx and tx buffers (in bytes) + * @speed_hz: Select a speed other then the device default for this + * transfer. If 0 the default (from spi_device) is used. + * @bits_per_word: select a bits_per_word other then the device default + * for this transfer. If 0 the default (from spi_device) is used. * @cs_change: affects chipselect after this transfer completes * @delay_usecs: microseconds to delay after this transfer before * (optionally) changing the chipselect status, then starting @@ -322,7 +328,9 @@ struct spi_transfer { dma_addr_t rx_dma; unsigned cs_change:1; + u8 bits_per_word; u16 delay_usecs; + u32 speed_hz; struct list_head transfer_list; }; diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index c961fe9bf3eb..c954557b757c 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -30,6 +30,12 @@ struct spi_bitbang { struct spi_master *master; + /* setup_transfer() changes clock and/or wordsize to match settings + * for this transfer; zeroes restore defaults from spi_device. + */ + int (*setup_transfer)(struct spi_device *spi, + struct spi_transfer *t); + void (*chipselect)(struct spi_device *spi, int is_on); #define BITBANG_CS_ACTIVE 1 /* normally nCS, active low */ #define BITBANG_CS_INACTIVE 0 -- cgit v1.3-8-gc7d7 From 747d844ee9a183ff3067bb1181f2a25c50649538 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Sun, 2 Apr 2006 10:33:37 -0800 Subject: [PATCH] SPI: spi whitespace fixes This removes superfluous whitespace in the header. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- include/linux/spi/spi.h | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) (limited to 'include/linux') diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index caa4665e3fa2..082006714b85 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -36,15 +36,15 @@ extern struct bus_type spi_bus_type; * @mode: The spi mode defines how data is clocked out and in. * This may be changed by the device's driver. * @bits_per_word: Data transfers involve one or more words; word sizes - * like eight or 12 bits are common. In-memory wordsizes are + * like eight or 12 bits are common. In-memory wordsizes are * powers of two bytes (e.g. 20 bit samples use 32 bits). * This may be changed by the device's driver. * The spi_transfer.bits_per_word can override this for each transfer. * @irq: Negative, or the number passed to request_irq() to receive - * interrupts from this device. + * interrupts from this device. * @controller_state: Controller's runtime state * @controller_data: Board-specific definitions for controller, such as - * FIFO initialization parameters; from board_info.controller_data + * FIFO initialization parameters; from board_info.controller_data * * An spi_device is used to interchange data between an SPI slave * (usually a discrete chip) and CPU memory. @@ -145,13 +145,13 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) * struct spi_master - interface to SPI master controller * @cdev: class interface to this driver * @bus_num: board-specific (and often SOC-specific) identifier for a - * given SPI controller. + * given SPI controller. * @num_chipselect: chipselects are used to distinguish individual - * SPI slaves, and are numbered from zero to num_chipselects. - * each slave has a chipselect signal, but it's common that not - * every chipselect is connected to a slave. + * SPI slaves, and are numbered from zero to num_chipselects. + * each slave has a chipselect signal, but it's common that not + * every chipselect is connected to a slave. * @setup: updates the device mode and clocking records used by a - * device's SPI controller; protocol code may call this. + * device's SPI controller; protocol code may call this. * @transfer: adds a message to the controller's transfer queue. * @cleanup: frees controller-specific state * @@ -276,8 +276,8 @@ extern struct spi_master *spi_busnum_to_master(u16 busnum); * for this transfer. If 0 the default (from spi_device) is used. * @cs_change: affects chipselect after this transfer completes * @delay_usecs: microseconds to delay after this transfer before - * (optionally) changing the chipselect status, then starting - * the next transfer or completing this spi_message. + * (optionally) changing the chipselect status, then starting + * the next transfer or completing this spi_message. * @transfer_list: transfers are sequenced through spi_message.transfers * * SPI transfers always write the same number of bytes as they read. @@ -364,7 +364,7 @@ struct spi_transfer { * and its transfers, ignore them until its completion callback. */ struct spi_message { - struct list_head transfers; + struct list_head transfers; struct spi_device *spi; @@ -382,7 +382,7 @@ struct spi_message { */ /* completion is reported through a callback */ - void (*complete)(void *context); + void (*complete)(void *context); void *context; unsigned actual_length; int status; -- cgit v1.3-8-gc7d7 From ff9f4771b5f017ee0f57629488b6cd7a6ef3d19b Mon Sep 17 00:00:00 2001 From: Kumar Gala Date: Sun, 2 Apr 2006 16:06:35 -0500 Subject: [PATCH] SPI: Renamed bitbang_transfer_setup to spi_bitbang_setup_transfer and export it Renamed bitbang_transfer_setup to follow convention of other exported symbols from spi-bitbang. Exported spi_bitbang_setup_transfer to allow users of spi-bitbang to use the function in their own setup_transfer. Signed-off-by: Kumar Gala Cc: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi_bitbang.c | 10 ++++++---- include/linux/spi/spi_bitbang.h | 2 ++ 2 files changed, 8 insertions(+), 4 deletions(-) (limited to 'include/linux') diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 0525c99118c3..6c3da64d609a 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -138,8 +138,7 @@ static unsigned bitbang_txrx_32( return t->len - count; } -static int -bitbang_transfer_setup(struct spi_device *spi, struct spi_transfer *t) +int spi_bitbang_setup_transfer(struct spi_device *spi, struct spi_transfer *t) { struct spi_bitbang_cs *cs = spi->controller_state; u8 bits_per_word; @@ -174,6 +173,7 @@ bitbang_transfer_setup(struct spi_device *spi, struct spi_transfer *t) return 0; } +EXPORT_SYMBOL_GPL(spi_bitbang_setup_transfer); /** * spi_bitbang_setup - default setup for per-word I/O loops @@ -203,7 +203,7 @@ int spi_bitbang_setup(struct spi_device *spi) if (!cs->txrx_word) return -EINVAL; - retval = bitbang_transfer_setup(spi, NULL); + retval = spi_bitbang_setup_transfer(spi, NULL); if (retval < 0) return retval; @@ -454,7 +454,9 @@ int spi_bitbang_start(struct spi_bitbang *bitbang) bitbang->use_dma = 0; bitbang->txrx_bufs = spi_bitbang_bufs; if (!bitbang->master->setup) { - bitbang->setup_transfer = bitbang_transfer_setup; + if (!bitbang->setup_transfer) + bitbang->setup_transfer = + spi_bitbang_setup_transfer; bitbang->master->setup = spi_bitbang_setup; bitbang->master->cleanup = spi_bitbang_cleanup; } diff --git a/include/linux/spi/spi_bitbang.h b/include/linux/spi/spi_bitbang.h index c954557b757c..16ce178f54d7 100644 --- a/include/linux/spi/spi_bitbang.h +++ b/include/linux/spi/spi_bitbang.h @@ -57,6 +57,8 @@ struct spi_bitbang { extern int spi_bitbang_setup(struct spi_device *spi); extern void spi_bitbang_cleanup(const struct spi_device *spi); extern int spi_bitbang_transfer(struct spi_device *spi, struct spi_message *m); +extern int spi_bitbang_setup_transfer(struct spi_device *spi, + struct spi_transfer *t); /* start or stop queue processing */ extern int spi_bitbang_start(struct spi_bitbang *spi); -- cgit v1.3-8-gc7d7 From ccf77cc4af5b048e20cfd9327fcc286cb69c34cc Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 3 Apr 2006 15:46:22 -0700 Subject: [PATCH] SPI: devices can require LSB-first encodings Add spi_device hook for LSB-first word encoding, and update all the (in-tree) controller drivers to reject such devices. Eventually, some controller drivers will be updated to support lsb-first encodings on the wire; no current drivers need this. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- drivers/spi/spi_bitbang.c | 11 ++++++++++- include/linux/spi/spi.h | 7 +++++-- 2 files changed, 15 insertions(+), 3 deletions(-) (limited to 'include/linux') diff --git a/drivers/spi/spi_bitbang.c b/drivers/spi/spi_bitbang.c index 6c3da64d609a..0f7f5c64391c 100644 --- a/drivers/spi/spi_bitbang.c +++ b/drivers/spi/spi_bitbang.c @@ -187,13 +187,22 @@ int spi_bitbang_setup(struct spi_device *spi) if (!spi->max_speed_hz) return -EINVAL; + bitbang = spi_master_get_devdata(spi->master); + + /* REVISIT: some systems will want to support devices using lsb-first + * bit encodings on the wire. In pure software that would be trivial, + * just bitbang_txrx_le_cphaX() routines shifting the other way, and + * some hardware controllers also have this support. + */ + if ((spi->mode & SPI_LSB_FIRST) != 0) + return -EINVAL; + if (!cs) { cs = kzalloc(sizeof *cs, SLAB_KERNEL); if (!cs) return -ENOMEM; spi->controller_state = cs; } - bitbang = spi_master_get_devdata(spi->master); if (!spi->bits_per_word) spi->bits_per_word = 8; diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 082006714b85..77add901691d 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -35,10 +35,13 @@ extern struct bus_type spi_bus_type; * @chip-select: Chipselect, distinguishing chips handled by "master". * @mode: The spi mode defines how data is clocked out and in. * This may be changed by the device's driver. + * The "active low" default for chipselect mode can be overridden, + * as can the "MSB first" default for each word in a transfer. * @bits_per_word: Data transfers involve one or more words; word sizes * like eight or 12 bits are common. In-memory wordsizes are * powers of two bytes (e.g. 20 bit samples use 32 bits). - * This may be changed by the device's driver. + * This may be changed by the device's driver, or left at the + * default (0) indicating protocol words are eight bit bytes. * The spi_transfer.bits_per_word can override this for each transfer. * @irq: Negative, or the number passed to request_irq() to receive * interrupts from this device. @@ -67,6 +70,7 @@ struct spi_device { #define SPI_MODE_2 (SPI_CPOL|0) #define SPI_MODE_3 (SPI_CPOL|SPI_CPHA) #define SPI_CS_HIGH 0x04 /* chipselect active high? */ +#define SPI_LSB_FIRST 0x08 /* per-word bits-on-wire */ u8 bits_per_word; int irq; void *controller_state; @@ -75,7 +79,6 @@ struct spi_device { // likely need more hooks for more protocol options affecting how // the controller talks to each chip, like: - // - bit order (default is wordwise msb-first) // - memory packing (12 bit samples into low bits, others zeroed) // - priority // - drop chipselect after each word -- cgit v1.3-8-gc7d7 From a020ed7521a9737bcf3e34eb880867c60c3c68d0 Mon Sep 17 00:00:00 2001 From: David Brownell Date: Mon, 3 Apr 2006 15:49:04 -0700 Subject: [PATCH] SPI: busnum == 0 needs to work We need to be able to have a "SPI bus 0" matching chip numbering; but that number was wrongly used to flag dynamic allocation of a bus number. This patch resolves that issue; now negative numbers trigger dynamic alloc. It also updates the how-to-write-a-controller-driver overview to mention this stuff. Signed-off-by: David Brownell Signed-off-by: Greg Kroah-Hartman --- Documentation/spi/spi-summary | 34 +++++++++++++++++++++++++++++++++- drivers/spi/spi.c | 4 ++-- include/linux/spi/spi.h | 6 +++--- 3 files changed, 38 insertions(+), 6 deletions(-) (limited to 'include/linux') diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary index a5ffba33a351..068732d32276 100644 --- a/Documentation/spi/spi-summary +++ b/Documentation/spi/spi-summary @@ -414,7 +414,33 @@ to get the driver-private data allocated for that device. The driver will initialize the fields of that spi_master, including the bus number (maybe the same as the platform device ID) and three methods used to interact with the SPI core and SPI protocol drivers. It will -also initialize its own internal state. +also initialize its own internal state. (See below about bus numbering +and those methods.) + +After you initialize the spi_master, then use spi_register_master() to +publish it to the rest of the system. At that time, device nodes for +the controller and any predeclared spi devices will be made available, +and the driver model core will take care of binding them to drivers. + +If you need to remove your SPI controller driver, spi_unregister_master() +will reverse the effect of spi_register_master(). + + +BUS NUMBERING + +Bus numbering is important, since that's how Linux identifies a given +SPI bus (shared SCK, MOSI, MISO). Valid bus numbers start at zero. On +SOC systems, the bus numbers should match the numbers defined by the chip +manufacturer. For example, hardware controller SPI2 would be bus number 2, +and spi_board_info for devices connected to it would use that number. + +If you don't have such hardware-assigned bus number, and for some reason +you can't just assign them, then provide a negative bus number. That will +then be replaced by a dynamically assigned number. You'd then need to treat +this as a non-static configuration (see above). + + +SPI MASTER METHODS master->setup(struct spi_device *spi) This sets up the device clock rate, SPI mode, and word sizes. @@ -431,6 +457,9 @@ also initialize its own internal state. state it dynamically associates with that device. If you do that, be sure to provide the cleanup() method to free that state. + +SPI MESSAGE QUEUE + The bulk of the driver will be managing the I/O queue fed by transfer(). That queue could be purely conceptual. For example, a driver used only @@ -440,6 +469,9 @@ But the queue will probably be very real, using message->queue, PIO, often DMA (especially if the root filesystem is in SPI flash), and execution contexts like IRQ handlers, tasklets, or workqueues (such as keventd). Your driver can be as fancy, or as simple, as you need. +Such a transfer() method would normally just add the message to a +queue, and then start some asynchronous transfer engine (unless it's +already running). THANKS TO diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c index 1168ef015887..7a3f733051e9 100644 --- a/drivers/spi/spi.c +++ b/drivers/spi/spi.c @@ -395,7 +395,7 @@ EXPORT_SYMBOL_GPL(spi_alloc_master); int __init_or_module spi_register_master(struct spi_master *master) { - static atomic_t dyn_bus_id = ATOMIC_INIT(0); + static atomic_t dyn_bus_id = ATOMIC_INIT((1<<16) - 1); struct device *dev = master->cdev.dev; int status = -ENODEV; int dynamic = 0; @@ -404,7 +404,7 @@ spi_register_master(struct spi_master *master) return -ENODEV; /* convention: dynamically assigned bus IDs count down from the max */ - if (master->bus_num == 0) { + if (master->bus_num < 0) { master->bus_num = atomic_dec_return(&dyn_bus_id); dynamic = 1; } diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h index 77add901691d..e928c0dcc297 100644 --- a/include/linux/spi/spi.h +++ b/include/linux/spi/spi.h @@ -172,13 +172,13 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv) struct spi_master { struct class_device cdev; - /* other than zero (== assign one dynamically), bus_num is fully + /* other than negative (== assign one dynamically), bus_num is fully * board-specific. usually that simplifies to being SOC-specific. - * example: one SOC has three SPI controllers, numbered 1..3, + * example: one SOC has three SPI controllers, numbered 0..2, * and one board's schematics might show it using SPI-2. software * would normally use bus_num=2 for that controller. */ - u16 bus_num; + s16 bus_num; /* chipselects will be integral to many controllers; some others * might use board-specific GPIOs. -- cgit v1.3-8-gc7d7 From 2c171bf13423dc5293188cea7f6c2da1720926e2 Mon Sep 17 00:00:00 2001 From: Pavel Pisa Date: Fri, 19 May 2006 21:48:03 +0100 Subject: [ARM] 3531/1: i.MX/MX1 SD/MMC ensure, that clock are stopped before new command and cleanups Patch from Pavel Pisa There has been problems that for some paths that clock are not stopped during new command programming and initiation. Result is issuing of incorrect command to the card. Some other problems are cleaned too. Noisy report of known ERRATUM #4 has been suppressed. Signed-off-by: Pavel Pisa Signed-off-by: Russell King --- drivers/mmc/au1xmmc.c | 6 +++--- drivers/mmc/imxmmc.c | 24 ++++++++++++++---------- drivers/mmc/mmc.c | 1 + drivers/mmc/mmc_block.c | 1 + drivers/mmc/pxamci.c | 4 ++-- drivers/mmc/wbsd.c | 8 ++++---- include/linux/mmc/mmc.h | 1 + 7 files changed, 26 insertions(+), 19 deletions(-) (limited to 'include/linux') diff --git a/drivers/mmc/au1xmmc.c b/drivers/mmc/au1xmmc.c index 914d62b24064..5dc4bee7abeb 100644 --- a/drivers/mmc/au1xmmc.c +++ b/drivers/mmc/au1xmmc.c @@ -310,7 +310,7 @@ static void au1xmmc_data_complete(struct au1xmmc_host *host, u32 status) } else data->bytes_xfered = - (data->blocks * (1 << data->blksz_bits)) - + (data->blocks * data->blksz) - host->pio.len; } @@ -575,7 +575,7 @@ static int au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) { - int datalen = data->blocks * (1 << data->blksz_bits); + int datalen = data->blocks * data->blksz; if (dma != 0) host->flags |= HOST_F_DMA; @@ -596,7 +596,7 @@ au1xmmc_prepare_data(struct au1xmmc_host *host, struct mmc_data *data) if (host->dma.len == 0) return MMC_ERR_TIMEOUT; - au_writel((1 << data->blksz_bits) - 1, HOST_BLKSIZE(host)); + au_writel(data->blksz - 1, HOST_BLKSIZE(host)); if (host->flags & HOST_F_DMA) { int i; diff --git a/drivers/mmc/imxmmc.c b/drivers/mmc/imxmmc.c index 79358e223f57..a4eb1d0e7a71 100644 --- a/drivers/mmc/imxmmc.c +++ b/drivers/mmc/imxmmc.c @@ -218,8 +218,10 @@ static int imxmci_busy_wait_for_status(struct imxmci_host *host, if(!loops) return 0; - dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n", - loops, where, *pstat, stat_mask); + /* The busy-wait is expected there for clock <8MHz due to SDHC hardware flaws */ + if(!(stat_mask & STATUS_END_CMD_RESP) || (host->mmc->ios.clock>=8000000)) + dev_info(mmc_dev(host->mmc), "busy wait for %d usec in %s, STATUS = 0x%x (0x%x)\n", + loops, where, *pstat, stat_mask); return loops; } @@ -333,6 +335,9 @@ static void imxmci_start_cmd(struct imxmci_host *host, struct mmc_command *cmd, WARN_ON(host->cmd != NULL); host->cmd = cmd; + /* Ensure, that clock are stopped else command programming and start fails */ + imxmci_stop_clock(host); + if (cmd->flags & MMC_RSP_BUSY) cmdat |= CMD_DAT_CONT_BUSY; @@ -553,7 +558,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat) int trans_done = 0; unsigned int stat = *pstat; - if(host->actual_bus_width == MMC_BUS_WIDTH_4) + if(host->actual_bus_width != MMC_BUS_WIDTH_4) burst_len = 16; else burst_len = 64; @@ -591,8 +596,7 @@ static int imxmci_cpu_driven_data(struct imxmci_host *host, unsigned int *pstat) stat = MMC_STATUS; /* Flush extra bytes from FIFO */ - while(flush_len >= 2){ - flush_len -= 2; + while(flush_len && !(stat & STATUS_DATA_TRANS_DONE)){ i = MMC_BUFFER_ACCESS; stat = MMC_STATUS; stat &= ~STATUS_CRC_READ_ERR; /* Stupid but required there */ @@ -746,10 +750,6 @@ static void imxmci_tasklet_fnc(unsigned long data) data_dir_mask = STATUS_DATA_TRANS_DONE; } - imxmci_busy_wait_for_status(host, &stat, - data_dir_mask, - 50, "imxmci_tasklet_fnc data"); - if(stat & data_dir_mask) { clear_bit(IMXMCI_PEND_DMA_END_b, &host->pending_events); imxmci_data_done(host, stat); @@ -865,7 +865,11 @@ static void imxmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) imxmci_stop_clock(host); MMC_CLK_RATE = (prescaler<<3) | clk; - imxmci_start_clock(host); + /* + * Under my understanding, clock should not be started there, because it would + * initiate SDHC sequencer and send last or random command into card + */ + /*imxmci_start_clock(host);*/ dev_dbg(mmc_dev(host->mmc), "MMC_CLK_RATE: 0x%08x\n", MMC_CLK_RATE); } else { diff --git a/drivers/mmc/mmc.c b/drivers/mmc/mmc.c index 1ca2c8b9c9b5..6201f3086a02 100644 --- a/drivers/mmc/mmc.c +++ b/drivers/mmc/mmc.c @@ -951,6 +951,7 @@ static void mmc_read_scrs(struct mmc_host *host) data.timeout_ns = card->csd.tacc_ns * 10; data.timeout_clks = card->csd.tacc_clks * 10; data.blksz_bits = 3; + data.blksz = 1 << 3; data.blocks = 1; data.flags = MMC_DATA_READ; data.sg = &sg; diff --git a/drivers/mmc/mmc_block.c b/drivers/mmc/mmc_block.c index 06bd1f4cb9b1..e39cc05c64c2 100644 --- a/drivers/mmc/mmc_block.c +++ b/drivers/mmc/mmc_block.c @@ -175,6 +175,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req) brq.data.timeout_ns = card->csd.tacc_ns * 10; brq.data.timeout_clks = card->csd.tacc_clks * 10; brq.data.blksz_bits = md->block_bits; + brq.data.blksz = 1 << md->block_bits; brq.data.blocks = req->nr_sectors >> (md->block_bits - 9); brq.stop.opcode = MMC_STOP_TRANSMISSION; brq.stop.arg = 0; diff --git a/drivers/mmc/pxamci.c b/drivers/mmc/pxamci.c index f97b472085cb..b49368fd96b8 100644 --- a/drivers/mmc/pxamci.c +++ b/drivers/mmc/pxamci.c @@ -119,7 +119,7 @@ static void pxamci_setup_data(struct pxamci_host *host, struct mmc_data *data) nob = 0xffff; writel(nob, host->base + MMC_NOB); - writel(1 << data->blksz_bits, host->base + MMC_BLKLEN); + writel(data->blksz, host->base + MMC_BLKLEN); clks = (unsigned long long)data->timeout_ns * CLOCKRATE; do_div(clks, 1000000000UL); @@ -283,7 +283,7 @@ static int pxamci_data_done(struct pxamci_host *host, unsigned int stat) * data blocks as being in error. */ if (data->error == MMC_ERR_NONE) - data->bytes_xfered = data->blocks << data->blksz_bits; + data->bytes_xfered = data->blocks * data->blksz; else data->bytes_xfered = 0; diff --git a/drivers/mmc/wbsd.c b/drivers/mmc/wbsd.c index 39b3d97f891e..8167332d4013 100644 --- a/drivers/mmc/wbsd.c +++ b/drivers/mmc/wbsd.c @@ -662,14 +662,14 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) unsigned long dmaflags; DBGF("blksz %04x blks %04x flags %08x\n", - 1 << data->blksz_bits, data->blocks, data->flags); + data->blksz, data->blocks, data->flags); DBGF("tsac %d ms nsac %d clk\n", data->timeout_ns / 1000000, data->timeout_clks); /* * Calculate size. */ - host->size = data->blocks << data->blksz_bits; + host->size = data->blocks * data->blksz; /* * Check timeout values for overflow. @@ -696,12 +696,12 @@ static void wbsd_prepare_data(struct wbsd_host *host, struct mmc_data *data) * Two bytes are needed for each data line. */ if (host->bus_width == MMC_BUS_WIDTH_1) { - blksize = (1 << data->blksz_bits) + 2; + blksize = data->blksz + 2; wbsd_write_index(host, WBSD_IDX_PBSMSB, (blksize >> 4) & 0xF0); wbsd_write_index(host, WBSD_IDX_PBSLSB, blksize & 0xFF); } else if (host->bus_width == MMC_BUS_WIDTH_4) { - blksize = (1 << data->blksz_bits) + 2 * 4; + blksize = data->blksz + 2 * 4; wbsd_write_index(host, WBSD_IDX_PBSMSB, ((blksize >> 4) & 0xF0) | WBSD_DATA_WIDTH); diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h index bdc556d88498..03a14a30c46a 100644 --- a/include/linux/mmc/mmc.h +++ b/include/linux/mmc/mmc.h @@ -69,6 +69,7 @@ struct mmc_data { unsigned int timeout_ns; /* data timeout (in ns, max 80ms) */ unsigned int timeout_clks; /* data timeout (in clocks) */ unsigned int blksz_bits; /* data block size */ + unsigned int blksz; /* data block size */ unsigned int blocks; /* number of blocks */ unsigned int error; /* data error */ unsigned int flags; -- cgit v1.3-8-gc7d7