From f89412ac45c68ff28b83f88c3789bc5d6cf97c8e Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Tue, 30 Sep 2014 15:31:16 +0200 Subject: CRISv32: Drop obsolete file for SPI driver File was already deleted. Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/drivers/Makefile | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/cris/arch-v32/drivers/Makefile b/arch/cris/arch-v32/drivers/Makefile index 39aa3c117a86..15fbfefced2c 100644 --- a/arch/cris/arch-v32/drivers/Makefile +++ b/arch/cris/arch-v32/drivers/Makefile @@ -10,4 +10,3 @@ obj-$(CONFIG_ETRAX_IOP_FW_LOAD) += iop_fw_load.o obj-$(CONFIG_ETRAX_I2C) += i2c.o obj-$(CONFIG_ETRAX_SYNCHRONOUS_SERIAL) += sync_serial.o obj-$(CONFIG_PCI) += pci/ -obj-$(CONFIG_ETRAX_SPI_MMC_BOARD) += board_mmcspi.o -- cgit v1.2.3-59-g8ed1b From eeda0084419741016d32019bf535a94dbd5628e7 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Tue, 30 Sep 2014 15:34:10 +0200 Subject: CRISv32: Add missing include for mm.h Fixes the following compile error. arch/cris/arch-v32/kernel/time.c: In function 'reset_watchdog': arch/cris/arch-v32/kernel/time.c:121:2: error: implicit declaration of function 'global_page_state' Signed-off-by: Guenter Roeck Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/kernel/time.c | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index ee66866538f8..73745ce79f6c 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include -- cgit v1.2.3-59-g8ed1b From 6eb64b8c64f7177b160b4bdbabd317d523bf4bfc Mon Sep 17 00:00:00 2001 From: Sam Ravnborg Date: Mon, 14 Jul 2014 17:08:29 +0200 Subject: CRIS: Fix headers_install Fix headers_install by adjusting the path to arch files. And delete unused Kbuild file. Drop special handling of cris in the headers.sh script as a nice side-effect. Signed-off-by: Sam Ravnborg Cc: Mikael Starvik Cc: David Howells Signed-off-by: Jesper Nilsson --- arch/cris/include/asm/Kbuild | 4 ---- arch/cris/include/uapi/asm/Kbuild | 4 ++-- scripts/headers.sh | 2 -- 3 files changed, 2 insertions(+), 8 deletions(-) (limited to 'arch') diff --git a/arch/cris/include/asm/Kbuild b/arch/cris/include/asm/Kbuild index d5f124832fd1..889f2de050a3 100644 --- a/arch/cris/include/asm/Kbuild +++ b/arch/cris/include/asm/Kbuild @@ -1,8 +1,4 @@ -header-y += arch-v10/ -header-y += arch-v32/ - - generic-y += barrier.h generic-y += clkdev.h generic-y += cputime.h diff --git a/arch/cris/include/uapi/asm/Kbuild b/arch/cris/include/uapi/asm/Kbuild index 7d47b366ad82..01f66b8f15e5 100644 --- a/arch/cris/include/uapi/asm/Kbuild +++ b/arch/cris/include/uapi/asm/Kbuild @@ -1,8 +1,8 @@ # UAPI Header export list include include/uapi/asm-generic/Kbuild.asm -header-y += arch-v10/ -header-y += arch-v32/ +header-y += ../arch-v10/arch/ +header-y += ../arch-v32/arch/ header-y += auxvec.h header-y += bitsperlong.h header-y += byteorder.h diff --git a/scripts/headers.sh b/scripts/headers.sh index 95ece06599a5..d4dc4de5cea1 100755 --- a/scripts/headers.sh +++ b/scripts/headers.sh @@ -19,8 +19,6 @@ for arch in ${archs}; do case ${arch} in um) # no userspace export ;; - cris) # headers export are known broken - ;; *) if [ -d ${srctree}/arch/${arch} ]; then do_command $1 ${arch} -- cgit v1.2.3-59-g8ed1b From 82e6df1e86e5c09d610df3da7524ea951b2ad458 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Wed, 1 Oct 2014 15:38:38 +0200 Subject: CRIS: Export ioremap_nocache Signed-off-by: Jesper Nilsson --- arch/cris/mm/ioremap.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'arch') diff --git a/arch/cris/mm/ioremap.c b/arch/cris/mm/ioremap.c index f9ca44bdea20..80fdb995a8ce 100644 --- a/arch/cris/mm/ioremap.c +++ b/arch/cris/mm/ioremap.c @@ -76,10 +76,11 @@ void __iomem * __ioremap(unsigned long phys_addr, unsigned long size, unsigned l * Must be freed with iounmap. */ -void __iomem *ioremap_nocache (unsigned long phys_addr, unsigned long size) +void __iomem *ioremap_nocache(unsigned long phys_addr, unsigned long size) { return __ioremap(phys_addr | MEM_NON_CACHEABLE, size, 0); } +EXPORT_SYMBOL(ioremap_nocache); void iounmap(volatile void __iomem *addr) { -- cgit v1.2.3-59-g8ed1b From dbd3c7e1bfb1e4319402eda23e04cc08dd26c50e Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Tue, 7 Oct 2014 12:20:47 +0200 Subject: CRIS: Export missing function symbols strcmp was lost when all other string functions were removed, but we still have an optimized version for this on CRISv32, so any driver built as a module would not have access to this symbol. In a similar manner, we had optimized versions of csum_partial_copy_from_user and __do_clear_user but no exported symbols for them, breaking bunch of other drivers when built as a module. At the same time, move EXPORT_SYMBOL(__copy_user) and EXPORT_SYMBOL(__copy_user_zeroing) C-files so it's located together with the function definition. Signed-off-by: Jesper Nilsson --- arch/cris/arch-v10/lib/usercopy.c | 14 +++++++------- arch/cris/arch-v32/lib/usercopy.c | 15 +++++++-------- arch/cris/kernel/crisksyms.c | 9 +++++---- 3 files changed, 19 insertions(+), 19 deletions(-) (limited to 'arch') diff --git a/arch/cris/arch-v10/lib/usercopy.c b/arch/cris/arch-v10/lib/usercopy.c index b0a608da7bd1..b964c667aced 100644 --- a/arch/cris/arch-v10/lib/usercopy.c +++ b/arch/cris/arch-v10/lib/usercopy.c @@ -30,8 +30,7 @@ /* Copy to userspace. This is based on the memcpy used for kernel-to-kernel copying; see "string.c". */ -unsigned long -__copy_user (void __user *pdst, const void *psrc, unsigned long pn) +unsigned long __copy_user(void __user *pdst, const void *psrc, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -187,13 +186,14 @@ __copy_user (void __user *pdst, const void *psrc, unsigned long pn) return retn; } +EXPORT_SYMBOL(__copy_user); /* Copy from user to kernel, zeroing the bytes that were inaccessible in userland. The return-value is the number of bytes that were inaccessible. */ -unsigned long -__copy_user_zeroing(void *pdst, const void __user *psrc, unsigned long pn) +unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc, + unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -369,11 +369,10 @@ copy_exception_bytes: return retn + n; } +EXPORT_SYMBOL(__copy_user_zeroing); /* Zero userspace. */ - -unsigned long -__do_clear_user (void __user *pto, unsigned long pn) +unsigned long __do_clear_user(void __user *pto, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -521,3 +520,4 @@ __do_clear_user (void __user *pto, unsigned long pn) return retn; } +EXPORT_SYMBOL(__do_clear_user); diff --git a/arch/cris/arch-v32/lib/usercopy.c b/arch/cris/arch-v32/lib/usercopy.c index 0b5b70d5f58a..f0f335d8aa79 100644 --- a/arch/cris/arch-v32/lib/usercopy.c +++ b/arch/cris/arch-v32/lib/usercopy.c @@ -26,8 +26,7 @@ /* Copy to userspace. This is based on the memcpy used for kernel-to-kernel copying; see "string.c". */ -unsigned long -__copy_user (void __user *pdst, const void *psrc, unsigned long pn) +unsigned long __copy_user(void __user *pdst, const void *psrc, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -155,13 +154,13 @@ __copy_user (void __user *pdst, const void *psrc, unsigned long pn) return retn; } +EXPORT_SYMBOL(__copy_user); /* Copy from user to kernel, zeroing the bytes that were inaccessible in userland. The return-value is the number of bytes that were inaccessible. */ - -unsigned long -__copy_user_zeroing(void *pdst, const void __user *psrc, unsigned long pn) +unsigned long __copy_user_zeroing(void *pdst, const void __user *psrc, + unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -321,11 +320,10 @@ copy_exception_bytes: return retn + n; } +EXPORT_SYMBOL(__copy_user_zeroing); /* Zero userspace. */ - -unsigned long -__do_clear_user (void __user *pto, unsigned long pn) +unsigned long __do_clear_user(void __user *pto, unsigned long pn) { /* We want the parameters put in special registers. Make sure the compiler is able to make something useful of this. @@ -468,3 +466,4 @@ __do_clear_user (void __user *pto, unsigned long pn) return retn; } +EXPORT_SYMBOL(__do_clear_user); diff --git a/arch/cris/kernel/crisksyms.c b/arch/cris/kernel/crisksyms.c index 5868cee20ebd..3908b942fd4c 100644 --- a/arch/cris/kernel/crisksyms.c +++ b/arch/cris/kernel/crisksyms.c @@ -47,16 +47,16 @@ EXPORT_SYMBOL(__negdi2); EXPORT_SYMBOL(__ioremap); EXPORT_SYMBOL(iounmap); -/* Userspace access functions */ -EXPORT_SYMBOL(__copy_user_zeroing); -EXPORT_SYMBOL(__copy_user); - #undef memcpy #undef memset extern void * memset(void *, int, __kernel_size_t); extern void * memcpy(void *, const void *, __kernel_size_t); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memset); +#ifdef CONFIG_ETRAX_ARCH_V32 +#undef strcmp +EXPORT_SYMBOL(strcmp); +#endif #ifdef CONFIG_ETRAX_FAST_TIMER /* Fast timer functions */ @@ -66,3 +66,4 @@ EXPORT_SYMBOL(del_fast_timer); EXPORT_SYMBOL(schedule_usleep); #endif EXPORT_SYMBOL(csum_partial); +EXPORT_SYMBOL(csum_partial_copy_from_user); -- cgit v1.2.3-59-g8ed1b From d6517c4c192b04016e2fbf12322bc6bd00f23835 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Tue, 7 Oct 2014 12:59:24 +0200 Subject: CRISv32: Better handling of watchdog bite Don't enter watchdog handling if we're already in watchdog handling. Also some minor formatting tweaks. Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/kernel/time.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) (limited to 'arch') diff --git a/arch/cris/arch-v32/kernel/time.c b/arch/cris/arch-v32/kernel/time.c index 73745ce79f6c..eb74dabbeb96 100644 --- a/arch/cris/arch-v32/kernel/time.c +++ b/arch/cris/arch-v32/kernel/time.c @@ -57,7 +57,6 @@ static int __init etrax_init_cont_rotime(void) } arch_initcall(etrax_init_cont_rotime); - unsigned long timer_regs[NR_CPUS] = { regi_timer0, @@ -69,9 +68,8 @@ unsigned long timer_regs[NR_CPUS] = extern int set_rtc_mmss(unsigned long nowtime); #ifdef CONFIG_CPU_FREQ -static int -cris_time_freq_notifier(struct notifier_block *nb, unsigned long val, - void *data); +static int cris_time_freq_notifier(struct notifier_block *nb, + unsigned long val, void *data); static struct notifier_block cris_time_freq_notifier_block = { .notifier_call = cris_time_freq_notifier, @@ -88,7 +86,6 @@ unsigned long get_ns_in_jiffie(void) return ns; } - /* From timer MDS describing the hardware watchdog: * 4.3.1 Watchdog Operation * The watchdog timer is an 8-bit timer with a configurable start value. @@ -110,11 +107,18 @@ static short int watchdog_key = 42; /* arbitrary 7 bit number */ * is used though, so set this really low. */ #define WATCHDOG_MIN_FREE_PAGES 8 +/* for reliable NICE_DOGGY behaviour */ +static int bite_in_progress; + void reset_watchdog(void) { #if defined(CONFIG_ETRAX_WATCHDOG) reg_timer_rw_wd_ctrl wd_ctrl = { 0 }; +#if defined(CONFIG_ETRAX_WATCHDOG_NICE_DOGGY) + if (unlikely(bite_in_progress)) + return; +#endif /* Only keep watchdog happy as long as we have memory left! */ if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) { /* Reset the watchdog with the inverse of the old key */ @@ -149,7 +153,9 @@ void handle_watchdog_bite(struct pt_regs *regs) #if defined(CONFIG_ETRAX_WATCHDOG) extern int cause_of_death; + nmi_enter(); oops_in_progress = 1; + bite_in_progress = 1; printk(KERN_WARNING "Watchdog bite\n"); /* Check if forced restart or unexpected watchdog */ @@ -171,6 +177,7 @@ void handle_watchdog_bite(struct pt_regs *regs) printk(KERN_WARNING "Oops: bitten by watchdog\n"); show_registers(regs); oops_in_progress = 0; + printk("\n"); /* Flush mtdoops. */ #ifndef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY reset_watchdog(); #endif @@ -203,7 +210,7 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id) /* Reset watchdog otherwise it resets us! */ reset_watchdog(); - /* Update statistics. */ + /* Update statistics. */ update_process_times(user_mode(regs)); cris_do_profile(regs); /* Save profiling information */ @@ -214,7 +221,7 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id) /* Call the real timer interrupt handler */ xtime_update(1); - return IRQ_HANDLED; + return IRQ_HANDLED; } /* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */ @@ -294,14 +301,13 @@ void __init time_init(void) #ifdef CONFIG_CPU_FREQ cpufreq_register_notifier(&cris_time_freq_notifier_block, - CPUFREQ_TRANSITION_NOTIFIER); + CPUFREQ_TRANSITION_NOTIFIER); #endif } #ifdef CONFIG_CPU_FREQ -static int -cris_time_freq_notifier(struct notifier_block *nb, unsigned long val, - void *data) +static int cris_time_freq_notifier(struct notifier_block *nb, + unsigned long val, void *data) { struct cpufreq_freqs *freqs = data; if (val == CPUFREQ_POSTCHANGE) { -- cgit v1.2.3-59-g8ed1b From 80d6170a289a1201480242d3570c5d7606ea1de9 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Tue, 7 Oct 2014 13:03:17 +0200 Subject: CRIS: Update init memory handling - Add free_initrd_mem as found by Guenter Roeck - Add free_init_pages - Export empty_zero_page symbol Signed-off-by: Jesper Nilsson --- arch/cris/mm/init.c | 38 +++++++++++++++++++++++++++++++++----- 1 file changed, 33 insertions(+), 5 deletions(-) (limited to 'arch') diff --git a/arch/cris/mm/init.c b/arch/cris/mm/init.c index c81af5bd9167..1e7fd45b60f8 100644 --- a/arch/cris/mm/init.c +++ b/arch/cris/mm/init.c @@ -11,13 +11,15 @@ #include #include #include +#include +#include #include #include unsigned long empty_zero_page; +EXPORT_SYMBOL(empty_zero_page); -void __init -mem_init(void) +void __init mem_init(void) { BUG_ON(!mem_map); @@ -31,10 +33,36 @@ mem_init(void) mem_init_print_info(NULL); } -/* free the pages occupied by initialization code */ +/* Free a range of init pages. Virtual addresses. */ -void -free_initmem(void) +void free_init_pages(const char *what, unsigned long begin, unsigned long end) +{ + unsigned long addr; + + for (addr = begin; addr < end; addr += PAGE_SIZE) { + ClearPageReserved(virt_to_page(addr)); + init_page_count(virt_to_page(addr)); + free_page(addr); + totalram_pages++; + } + + printk(KERN_INFO "Freeing %s: %ldk freed\n", what, (end - begin) >> 10); +} + +/* Free the pages occupied by initialization code. */ + +void free_initmem(void) { free_initmem_default(-1); } + +/* Free the pages occupied by initrd code. */ + +#ifdef CONFIG_BLK_DEV_INITRD +void free_initrd_mem(unsigned long start, unsigned long end) +{ + free_init_pages("initrd memory", + start, + end); +} +#endif -- cgit v1.2.3-59-g8ed1b From 3f10462f292e5d8f3bb2a19fa62f442bd8c4df5a Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Tue, 7 Oct 2014 13:40:08 +0200 Subject: CRISv32: Rewrite of synchronous serial port driver Make driver possible to load as a module and try to handle locking better. Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/drivers/sync_serial.c | 1430 +++++++++++++++++------------- 1 file changed, 791 insertions(+), 639 deletions(-) (limited to 'arch') diff --git a/arch/cris/arch-v32/drivers/sync_serial.c b/arch/cris/arch-v32/drivers/sync_serial.c index 5a149134cfb5..08a313fc2241 100644 --- a/arch/cris/arch-v32/drivers/sync_serial.c +++ b/arch/cris/arch-v32/drivers/sync_serial.c @@ -1,8 +1,7 @@ /* - * Simple synchronous serial port driver for ETRAX FS and Artpec-3. - * - * Copyright (c) 2005 Axis Communications AB + * Simple synchronous serial port driver for ETRAX FS and ARTPEC-3. * + * Copyright (c) 2005, 2008 Axis Communications AB * Author: Mikael Starvik * */ @@ -16,16 +15,17 @@ #include #include #include -#include -#include -#include +#include +#include +#include #include #include -#include +#include #include #include #include +#include #include #include #include @@ -59,22 +59,23 @@ /* the rest of the data pointed out by Descr1 and set readp to the start */ /* of Descr2 */ -#define SYNC_SERIAL_MAJOR 125 - /* IN_BUFFER_SIZE should be a multiple of 6 to make sure that 24 bit */ /* words can be handled */ -#define IN_BUFFER_SIZE 12288 -#define IN_DESCR_SIZE 256 -#define NBR_IN_DESCR (IN_BUFFER_SIZE/IN_DESCR_SIZE) +#define IN_DESCR_SIZE SSP_INPUT_CHUNK_SIZE +#define NBR_IN_DESCR (8*6) +#define IN_BUFFER_SIZE (IN_DESCR_SIZE * NBR_IN_DESCR) -#define OUT_BUFFER_SIZE 1024*8 #define NBR_OUT_DESCR 8 +#define OUT_BUFFER_SIZE (1024 * NBR_OUT_DESCR) #define DEFAULT_FRAME_RATE 0 #define DEFAULT_WORD_RATE 7 +/* To be removed when we move to pure udev. */ +#define SYNC_SERIAL_MAJOR 125 + /* NOTE: Enabling some debug will likely cause overrun or underrun, - * especially if manual mode is use. + * especially if manual mode is used. */ #define DEBUG(x) #define DEBUGREAD(x) @@ -85,11 +86,28 @@ #define DEBUGTRDMA(x) #define DEBUGOUTBUF(x) -typedef struct sync_port -{ - reg_scope_instances regi_sser; - reg_scope_instances regi_dmain; - reg_scope_instances regi_dmaout; +enum syncser_irq_setup { + no_irq_setup = 0, + dma_irq_setup = 1, + manual_irq_setup = 2, +}; + +struct sync_port { + unsigned long regi_sser; + unsigned long regi_dmain; + unsigned long regi_dmaout; + + /* Interrupt vectors. */ + unsigned long dma_in_intr_vect; /* Used for DMA in. */ + unsigned long dma_out_intr_vect; /* Used for DMA out. */ + unsigned long syncser_intr_vect; /* Used when no DMA. */ + + /* DMA number for in and out. */ + unsigned int dma_in_nbr; + unsigned int dma_out_nbr; + + /* DMA owner. */ + enum dma_owner req_dma; char started; /* 1 if port has been started */ char port_nbr; /* Port 0 or 1 */ @@ -99,22 +117,29 @@ typedef struct sync_port char use_dma; /* 1 if port uses dma */ char tr_running; - char init_irqs; + enum syncser_irq_setup init_irqs; int output; int input; /* Next byte to be read by application */ - volatile unsigned char *volatile readp; + unsigned char *readp; /* Next byte to be written by etrax */ - volatile unsigned char *volatile writep; + unsigned char *writep; unsigned int in_buffer_size; + unsigned int in_buffer_len; unsigned int inbufchunk; - unsigned char out_buffer[OUT_BUFFER_SIZE] __attribute__ ((aligned(32))); - unsigned char in_buffer[IN_BUFFER_SIZE]__attribute__ ((aligned(32))); - unsigned char flip[IN_BUFFER_SIZE] __attribute__ ((aligned(32))); - struct dma_descr_data* next_rx_desc; - struct dma_descr_data* prev_rx_desc; + /* Data buffers for in and output. */ + unsigned char out_buffer[OUT_BUFFER_SIZE] __aligned(32); + unsigned char in_buffer[IN_BUFFER_SIZE] __aligned(32); + unsigned char flip[IN_BUFFER_SIZE] __aligned(32); + struct timespec timestamp[NBR_IN_DESCR]; + struct dma_descr_data *next_rx_desc; + struct dma_descr_data *prev_rx_desc; + + struct timeval last_timestamp; + int read_ts_idx; + int write_ts_idx; /* Pointer to the first available descriptor in the ring, * unless active_tr_descr == catch_tr_descr and a dma @@ -135,114 +160,138 @@ typedef struct sync_port /* Number of bytes currently locked for being read by DMA */ int out_buf_count; - dma_descr_data in_descr[NBR_IN_DESCR] __attribute__ ((__aligned__(16))); - dma_descr_context in_context __attribute__ ((__aligned__(32))); - dma_descr_data out_descr[NBR_OUT_DESCR] - __attribute__ ((__aligned__(16))); - dma_descr_context out_context __attribute__ ((__aligned__(32))); + dma_descr_context in_context __aligned(32); + dma_descr_context out_context __aligned(32); + dma_descr_data in_descr[NBR_IN_DESCR] __aligned(16); + dma_descr_data out_descr[NBR_OUT_DESCR] __aligned(16); + wait_queue_head_t out_wait_q; wait_queue_head_t in_wait_q; spinlock_t lock; -} sync_port; +}; static DEFINE_MUTEX(sync_serial_mutex); static int etrax_sync_serial_init(void); static void initialize_port(int portnbr); static inline int sync_data_avail(struct sync_port *port); -static int sync_serial_open(struct inode *, struct file*); -static int sync_serial_release(struct inode*, struct file*); +static int sync_serial_open(struct inode *, struct file *); +static int sync_serial_release(struct inode *, struct file *); static unsigned int sync_serial_poll(struct file *filp, poll_table *wait); -static int sync_serial_ioctl(struct file *, - unsigned int cmd, unsigned long arg); -static ssize_t sync_serial_write(struct file * file, const char * buf, +static long sync_serial_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); +static int sync_serial_ioctl_unlocked(struct file *file, + unsigned int cmd, unsigned long arg); +static ssize_t sync_serial_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos); -static ssize_t sync_serial_read(struct file *file, char *buf, +static ssize_t sync_serial_read(struct file *file, char __user *buf, size_t count, loff_t *ppos); -#if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \ - defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \ - (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \ - defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)) +#if ((defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \ + defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \ + (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \ + defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA))) #define SYNC_SER_DMA +#else +#define SYNC_SER_MANUAL #endif -static void send_word(sync_port* port); -static void start_dma_out(struct sync_port *port, const char *data, int count); -static void start_dma_in(sync_port* port); #ifdef SYNC_SER_DMA +static void start_dma_out(struct sync_port *port, const char *data, int count); +static void start_dma_in(struct sync_port *port); static irqreturn_t tr_interrupt(int irq, void *dev_id); static irqreturn_t rx_interrupt(int irq, void *dev_id); #endif - -#if (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) && \ - !defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA)) || \ - (defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) && \ - !defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA)) -#define SYNC_SER_MANUAL -#endif #ifdef SYNC_SER_MANUAL +static void send_word(struct sync_port *port); static irqreturn_t manual_interrupt(int irq, void *dev_id); #endif -#ifdef CONFIG_ETRAXFS /* ETRAX FS */ -#define OUT_DMA_NBR 4 -#define IN_DMA_NBR 5 -#define PINMUX_SSER pinmux_sser0 -#define SYNCSER_INST regi_sser0 -#define SYNCSER_INTR_VECT SSER0_INTR_VECT -#define OUT_DMA_INST regi_dma4 -#define IN_DMA_INST regi_dma5 -#define DMA_OUT_INTR_VECT DMA4_INTR_VECT -#define DMA_IN_INTR_VECT DMA5_INTR_VECT -#define REQ_DMA_SYNCSER dma_sser0 -#else /* Artpec-3 */ -#define OUT_DMA_NBR 6 -#define IN_DMA_NBR 7 -#define PINMUX_SSER pinmux_sser -#define SYNCSER_INST regi_sser -#define SYNCSER_INTR_VECT SSER_INTR_VECT -#define OUT_DMA_INST regi_dma6 -#define IN_DMA_INST regi_dma7 -#define DMA_OUT_INTR_VECT DMA6_INTR_VECT -#define DMA_IN_INTR_VECT DMA7_INTR_VECT -#define REQ_DMA_SYNCSER dma_sser +#define artpec_pinmux_alloc_fixed crisv32_pinmux_alloc_fixed +#define artpec_request_dma crisv32_request_dma +#define artpec_free_dma crisv32_free_dma + +#ifdef CONFIG_ETRAXFS +/* ETRAX FS */ +#define DMA_OUT_NBR0 SYNC_SER0_TX_DMA_NBR +#define DMA_IN_NBR0 SYNC_SER0_RX_DMA_NBR +#define DMA_OUT_NBR1 SYNC_SER1_TX_DMA_NBR +#define DMA_IN_NBR1 SYNC_SER1_RX_DMA_NBR +#define PINMUX_SSER0 pinmux_sser0 +#define PINMUX_SSER1 pinmux_sser1 +#define SYNCSER_INST0 regi_sser0 +#define SYNCSER_INST1 regi_sser1 +#define SYNCSER_INTR_VECT0 SSER0_INTR_VECT +#define SYNCSER_INTR_VECT1 SSER1_INTR_VECT +#define OUT_DMA_INST0 regi_dma4 +#define IN_DMA_INST0 regi_dma5 +#define DMA_OUT_INTR_VECT0 DMA4_INTR_VECT +#define DMA_OUT_INTR_VECT1 DMA7_INTR_VECT +#define DMA_IN_INTR_VECT0 DMA5_INTR_VECT +#define DMA_IN_INTR_VECT1 DMA6_INTR_VECT +#define REQ_DMA_SYNCSER0 dma_sser0 +#define REQ_DMA_SYNCSER1 dma_sser1 +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) +#define PORT1_DMA 1 +#else +#define PORT1_DMA 0 +#endif +#elif defined(CONFIG_CRIS_MACH_ARTPEC3) +/* ARTPEC-3 */ +#define DMA_OUT_NBR0 SYNC_SER_TX_DMA_NBR +#define DMA_IN_NBR0 SYNC_SER_RX_DMA_NBR +#define PINMUX_SSER0 pinmux_sser +#define SYNCSER_INST0 regi_sser +#define SYNCSER_INTR_VECT0 SSER_INTR_VECT +#define OUT_DMA_INST0 regi_dma6 +#define IN_DMA_INST0 regi_dma7 +#define DMA_OUT_INTR_VECT0 DMA6_INTR_VECT +#define DMA_IN_INTR_VECT0 DMA7_INTR_VECT +#define REQ_DMA_SYNCSER0 dma_sser +#define REQ_DMA_SYNCSER1 dma_sser #endif -/* The ports */ -static struct sync_port ports[]= -{ - { - .regi_sser = SYNCSER_INST, - .regi_dmaout = OUT_DMA_INST, - .regi_dmain = IN_DMA_INST, #if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL0_DMA) - .use_dma = 1, +#define PORT0_DMA 1 #else - .use_dma = 0, +#define PORT0_DMA 0 #endif - } -#ifdef CONFIG_ETRAXFS - , +/* The ports */ +static struct sync_port ports[] = { { - .regi_sser = regi_sser1, - .regi_dmaout = regi_dma6, - .regi_dmain = regi_dma7, -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL1_DMA) - .use_dma = 1, -#else - .use_dma = 0, -#endif - } + .regi_sser = SYNCSER_INST0, + .regi_dmaout = OUT_DMA_INST0, + .regi_dmain = IN_DMA_INST0, + .use_dma = PORT0_DMA, + .dma_in_intr_vect = DMA_IN_INTR_VECT0, + .dma_out_intr_vect = DMA_OUT_INTR_VECT0, + .dma_in_nbr = DMA_IN_NBR0, + .dma_out_nbr = DMA_OUT_NBR0, + .req_dma = REQ_DMA_SYNCSER0, + .syncser_intr_vect = SYNCSER_INTR_VECT0, + }, +#ifdef CONFIG_ETRAXFS + { + .regi_sser = SYNCSER_INST1, + .regi_dmaout = regi_dma6, + .regi_dmain = regi_dma7, + .use_dma = PORT1_DMA, + .dma_in_intr_vect = DMA_IN_INTR_VECT1, + .dma_out_intr_vect = DMA_OUT_INTR_VECT1, + .dma_in_nbr = DMA_IN_NBR1, + .dma_out_nbr = DMA_OUT_NBR1, + .req_dma = REQ_DMA_SYNCSER1, + .syncser_intr_vect = SYNCSER_INTR_VECT1, + }, #endif }; #define NBR_PORTS ARRAY_SIZE(ports) -static const struct file_operations sync_serial_fops = { +static const struct file_operations syncser_fops = { .owner = THIS_MODULE, .write = sync_serial_write, .read = sync_serial_read, @@ -253,61 +302,40 @@ static const struct file_operations sync_serial_fops = { .llseek = noop_llseek, }; -static int __init etrax_sync_serial_init(void) -{ - ports[0].enabled = 0; -#ifdef CONFIG_ETRAXFS - ports[1].enabled = 0; -#endif - if (register_chrdev(SYNC_SERIAL_MAJOR, "sync serial", - &sync_serial_fops) < 0) { - printk(KERN_WARNING - "Unable to get major for synchronous serial port\n"); - return -EBUSY; - } - - /* Initialize Ports */ -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) - if (crisv32_pinmux_alloc_fixed(PINMUX_SSER)) { - printk(KERN_WARNING - "Unable to alloc pins for synchronous serial port 0\n"); - return -EIO; - } - ports[0].enabled = 1; - initialize_port(0); -#endif - -#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) - if (crisv32_pinmux_alloc_fixed(pinmux_sser1)) { - printk(KERN_WARNING - "Unable to alloc pins for synchronous serial port 0\n"); - return -EIO; - } - ports[1].enabled = 1; - initialize_port(1); -#endif +static dev_t syncser_first; +static int minor_count = NBR_PORTS; +#define SYNCSER_NAME "syncser" +static struct cdev *syncser_cdev; +static struct class *syncser_class; -#ifdef CONFIG_ETRAXFS - printk(KERN_INFO "ETRAX FS synchronous serial port driver\n"); -#else - printk(KERN_INFO "Artpec-3 synchronous serial port driver\n"); -#endif - return 0; +static void sync_serial_start_port(struct sync_port *port) +{ + reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); + reg_sser_rw_tr_cfg tr_cfg = + REG_RD(sser, port->regi_sser, rw_tr_cfg); + reg_sser_rw_rec_cfg rec_cfg = + REG_RD(sser, port->regi_sser, rw_rec_cfg); + cfg.en = regk_sser_yes; + tr_cfg.tr_en = regk_sser_yes; + rec_cfg.rec_en = regk_sser_yes; + REG_WR(sser, port->regi_sser, rw_cfg, cfg); + REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); + REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); + port->started = 1; } static void __init initialize_port(int portnbr) { - int __attribute__((unused)) i; struct sync_port *port = &ports[portnbr]; - reg_sser_rw_cfg cfg = {0}; - reg_sser_rw_frm_cfg frm_cfg = {0}; - reg_sser_rw_tr_cfg tr_cfg = {0}; - reg_sser_rw_rec_cfg rec_cfg = {0}; + reg_sser_rw_cfg cfg = { 0 }; + reg_sser_rw_frm_cfg frm_cfg = { 0 }; + reg_sser_rw_tr_cfg tr_cfg = { 0 }; + reg_sser_rw_rec_cfg rec_cfg = { 0 }; - DEBUG(printk(KERN_DEBUG "Init sync serial port %d\n", portnbr)); + DEBUG(pr_info("Init sync serial port %d\n", portnbr)); port->port_nbr = portnbr; - port->init_irqs = 1; + port->init_irqs = no_irq_setup; port->out_rd_ptr = port->out_buffer; port->out_buf_count = 0; @@ -318,10 +346,11 @@ static void __init initialize_port(int portnbr) port->readp = port->flip; port->writep = port->flip; port->in_buffer_size = IN_BUFFER_SIZE; + port->in_buffer_len = 0; port->inbufchunk = IN_DESCR_SIZE; - port->next_rx_desc = &port->in_descr[0]; - port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR-1]; - port->prev_rx_desc->eol = 1; + + port->read_ts_idx = 0; + port->write_ts_idx = 0; init_waitqueue_head(&port->out_wait_q); init_waitqueue_head(&port->in_wait_q); @@ -368,14 +397,18 @@ static void __init initialize_port(int portnbr) REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); #ifdef SYNC_SER_DMA - /* Setup the descriptor ring for dma out/transmit. */ - for (i = 0; i < NBR_OUT_DESCR; i++) { - port->out_descr[i].wait = 0; - port->out_descr[i].intr = 1; - port->out_descr[i].eol = 0; - port->out_descr[i].out_eop = 0; - port->out_descr[i].next = - (dma_descr_data *)virt_to_phys(&port->out_descr[i+1]); + { + int i; + /* Setup the descriptor ring for dma out/transmit. */ + for (i = 0; i < NBR_OUT_DESCR; i++) { + dma_descr_data *descr = &port->out_descr[i]; + descr->wait = 0; + descr->intr = 1; + descr->eol = 0; + descr->out_eop = 0; + descr->next = + (dma_descr_data *)virt_to_phys(&descr[i+1]); + } } /* Create a ring from the list. */ @@ -391,201 +424,116 @@ static void __init initialize_port(int portnbr) static inline int sync_data_avail(struct sync_port *port) { - int avail; - unsigned char *start; - unsigned char *end; - - start = (unsigned char*)port->readp; /* cast away volatile */ - end = (unsigned char*)port->writep; /* cast away volatile */ - /* 0123456789 0123456789 - * ----- - ----- - * ^rp ^wp ^wp ^rp - */ - - if (end >= start) - avail = end - start; - else - avail = port->in_buffer_size - (start - end); - return avail; -} - -static inline int sync_data_avail_to_end(struct sync_port *port) -{ - int avail; - unsigned char *start; - unsigned char *end; - - start = (unsigned char*)port->readp; /* cast away volatile */ - end = (unsigned char*)port->writep; /* cast away volatile */ - /* 0123456789 0123456789 - * ----- ----- - * ^rp ^wp ^wp ^rp - */ - - if (end >= start) - avail = end - start; - else - avail = port->flip + port->in_buffer_size - start; - return avail; + return port->in_buffer_len; } static int sync_serial_open(struct inode *inode, struct file *file) { + int ret = 0; int dev = iminor(inode); - int ret = -EBUSY; - sync_port *port; - reg_dma_rw_cfg cfg = {.en = regk_dma_yes}; - reg_dma_rw_intr_mask intr_mask = {.data = regk_dma_yes}; + struct sync_port *port; +#ifdef SYNC_SER_DMA + reg_dma_rw_cfg cfg = { .en = regk_dma_yes }; + reg_dma_rw_intr_mask intr_mask = { .data = regk_dma_yes }; +#endif - mutex_lock(&sync_serial_mutex); - DEBUG(printk(KERN_DEBUG "Open sync serial port %d\n", dev)); + DEBUG(pr_debug("Open sync serial port %d\n", dev)); - if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) - { - DEBUG(printk(KERN_DEBUG "Invalid minor %d\n", dev)); - ret = -ENODEV; - goto out; + if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { + DEBUG(pr_info("Invalid minor %d\n", dev)); + return -ENODEV; } port = &ports[dev]; /* Allow open this device twice (assuming one reader and one writer) */ - if (port->busy == 2) - { - DEBUG(printk(KERN_DEBUG "Device is busy.. \n")); - goto out; + if (port->busy == 2) { + DEBUG(pr_info("syncser%d is busy\n", dev)); + return -EBUSY; } + mutex_lock(&sync_serial_mutex); - if (port->init_irqs) { - if (port->use_dma) { - if (port == &ports[0]) { -#ifdef SYNC_SER_DMA - if (request_irq(DMA_OUT_INTR_VECT, - tr_interrupt, - 0, - "synchronous serial 0 dma tr", - &ports[0])) { - printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); - goto out; - } else if (request_irq(DMA_IN_INTR_VECT, - rx_interrupt, - 0, - "synchronous serial 1 dma rx", - &ports[0])) { - free_irq(DMA_OUT_INTR_VECT, &port[0]); - printk(KERN_CRIT "Can't allocate sync serial port 0 IRQ"); - goto out; - } else if (crisv32_request_dma(OUT_DMA_NBR, - "synchronous serial 0 dma tr", - DMA_VERBOSE_ON_ERROR, - 0, - REQ_DMA_SYNCSER)) { - free_irq(DMA_OUT_INTR_VECT, &port[0]); - free_irq(DMA_IN_INTR_VECT, &port[0]); - printk(KERN_CRIT "Can't allocate sync serial port 0 TX DMA channel"); - goto out; - } else if (crisv32_request_dma(IN_DMA_NBR, - "synchronous serial 0 dma rec", - DMA_VERBOSE_ON_ERROR, - 0, - REQ_DMA_SYNCSER)) { - crisv32_free_dma(OUT_DMA_NBR); - free_irq(DMA_OUT_INTR_VECT, &port[0]); - free_irq(DMA_IN_INTR_VECT, &port[0]); - printk(KERN_CRIT "Can't allocate sync serial port 1 RX DMA channel"); - goto out; - } -#endif - } -#ifdef CONFIG_ETRAXFS - else if (port == &ports[1]) { + /* Clear any stale date left in the flip buffer */ + port->readp = port->writep = port->flip; + port->in_buffer_len = 0; + port->read_ts_idx = 0; + port->write_ts_idx = 0; + + if (port->init_irqs != no_irq_setup) { + /* Init only on first call. */ + port->busy++; + mutex_unlock(&sync_serial_mutex); + return 0; + } + if (port->use_dma) { #ifdef SYNC_SER_DMA - if (request_irq(DMA6_INTR_VECT, - tr_interrupt, - 0, - "synchronous serial 1 dma tr", - &ports[1])) { - printk(KERN_CRIT "Can't allocate sync serial port 1 IRQ"); - goto out; - } else if (request_irq(DMA7_INTR_VECT, - rx_interrupt, - 0, - "synchronous serial 1 dma rx", - &ports[1])) { - free_irq(DMA6_INTR_VECT, &ports[1]); - printk(KERN_CRIT "Can't allocate sync serial port 3 IRQ"); - goto out; - } else if (crisv32_request_dma( - SYNC_SER1_TX_DMA_NBR, - "synchronous serial 1 dma tr", - DMA_VERBOSE_ON_ERROR, - 0, - dma_sser1)) { - free_irq(DMA6_INTR_VECT, &ports[1]); - free_irq(DMA7_INTR_VECT, &ports[1]); - printk(KERN_CRIT "Can't allocate sync serial port 3 TX DMA channel"); - goto out; - } else if (crisv32_request_dma( - SYNC_SER1_RX_DMA_NBR, - "synchronous serial 3 dma rec", - DMA_VERBOSE_ON_ERROR, - 0, - dma_sser1)) { - crisv32_free_dma(SYNC_SER1_TX_DMA_NBR); - free_irq(DMA6_INTR_VECT, &ports[1]); - free_irq(DMA7_INTR_VECT, &ports[1]); - printk(KERN_CRIT "Can't allocate sync serial port 3 RX DMA channel"); - goto out; - } -#endif - } + const char *tmp; + DEBUG(pr_info("Using DMA for syncser%d\n", dev)); + + tmp = dev == 0 ? "syncser0 tx" : "syncser1 tx"; + if (request_irq(port->dma_out_intr_vect, tr_interrupt, 0, + tmp, port)) { + pr_err("Can't alloc syncser%d TX IRQ", dev); + ret = -EBUSY; + goto unlock_and_exit; + } + if (artpec_request_dma(port->dma_out_nbr, tmp, + DMA_VERBOSE_ON_ERROR, 0, port->req_dma)) { + free_irq(port->dma_out_intr_vect, port); + pr_err("Can't alloc syncser%d TX DMA", dev); + ret = -EBUSY; + goto unlock_and_exit; + } + tmp = dev == 0 ? "syncser0 rx" : "syncser1 rx"; + if (request_irq(port->dma_in_intr_vect, rx_interrupt, 0, + tmp, port)) { + artpec_free_dma(port->dma_out_nbr); + free_irq(port->dma_out_intr_vect, port); + pr_err("Can't alloc syncser%d RX IRQ", dev); + ret = -EBUSY; + goto unlock_and_exit; + } + if (artpec_request_dma(port->dma_in_nbr, tmp, + DMA_VERBOSE_ON_ERROR, 0, port->req_dma)) { + artpec_free_dma(port->dma_out_nbr); + free_irq(port->dma_out_intr_vect, port); + free_irq(port->dma_in_intr_vect, port); + pr_err("Can't alloc syncser%d RX DMA", dev); + ret = -EBUSY; + goto unlock_and_exit; + } + /* Enable DMAs */ + REG_WR(dma, port->regi_dmain, rw_cfg, cfg); + REG_WR(dma, port->regi_dmaout, rw_cfg, cfg); + /* Enable DMA IRQs */ + REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask); + REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask); + /* Set up wordsize = 1 for DMAs. */ + DMA_WR_CMD(port->regi_dmain, regk_dma_set_w_size1); + DMA_WR_CMD(port->regi_dmaout, regk_dma_set_w_size1); + + start_dma_in(port); + port->init_irqs = dma_irq_setup; #endif - /* Enable DMAs */ - REG_WR(dma, port->regi_dmain, rw_cfg, cfg); - REG_WR(dma, port->regi_dmaout, rw_cfg, cfg); - /* Enable DMA IRQs */ - REG_WR(dma, port->regi_dmain, rw_intr_mask, intr_mask); - REG_WR(dma, port->regi_dmaout, rw_intr_mask, intr_mask); - /* Set up wordsize = 1 for DMAs. */ - DMA_WR_CMD (port->regi_dmain, regk_dma_set_w_size1); - DMA_WR_CMD (port->regi_dmaout, regk_dma_set_w_size1); - - start_dma_in(port); - port->init_irqs = 0; - } else { /* !port->use_dma */ + } else { /* !port->use_dma */ #ifdef SYNC_SER_MANUAL - if (port == &ports[0]) { - if (request_irq(SYNCSER_INTR_VECT, - manual_interrupt, - 0, - "synchronous serial manual irq", - &ports[0])) { - printk("Can't allocate sync serial manual irq"); - goto out; - } - } -#ifdef CONFIG_ETRAXFS - else if (port == &ports[1]) { - if (request_irq(SSER1_INTR_VECT, - manual_interrupt, - 0, - "synchronous serial manual irq", - &ports[1])) { - printk(KERN_CRIT "Can't allocate sync serial manual irq"); - goto out; - } - } -#endif - port->init_irqs = 0; + const char *tmp = dev == 0 ? "syncser0 manual irq" : + "syncser1 manual irq"; + if (request_irq(port->syncser_intr_vect, manual_interrupt, + 0, tmp, port)) { + pr_err("Can't alloc syncser%d manual irq", + dev); + ret = -EBUSY; + goto unlock_and_exit; + } + port->init_irqs = manual_irq_setup; #else - panic("sync_serial: Manual mode not supported.\n"); + panic("sync_serial: Manual mode not supported\n"); #endif /* SYNC_SER_MANUAL */ - } - - } /* port->init_irqs */ - + } port->busy++; ret = 0; -out: + +unlock_and_exit: mutex_unlock(&sync_serial_mutex); return ret; } @@ -593,18 +541,17 @@ out: static int sync_serial_release(struct inode *inode, struct file *file) { int dev = iminor(inode); - sync_port *port; + struct sync_port *port; - if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); + if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { + DEBUG(pr_info("Invalid minor %d\n", dev)); return -ENODEV; } port = &ports[dev]; if (port->busy) port->busy--; if (!port->busy) - /* XXX */ ; + /* XXX */; return 0; } @@ -612,21 +559,15 @@ static unsigned int sync_serial_poll(struct file *file, poll_table *wait) { int dev = iminor(file_inode(file)); unsigned int mask = 0; - sync_port *port; - DEBUGPOLL( static unsigned int prev_mask = 0; ); + struct sync_port *port; + DEBUGPOLL( + static unsigned int prev_mask; + ); port = &ports[dev]; - if (!port->started) { - reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); - reg_sser_rw_rec_cfg rec_cfg = - REG_RD(sser, port->regi_sser, rw_rec_cfg); - cfg.en = regk_sser_yes; - rec_cfg.rec_en = port->input; - REG_WR(sser, port->regi_sser, rw_cfg, cfg); - REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); - port->started = 1; - } + if (!port->started) + sync_serial_start_port(port); poll_wait(file, &port->out_wait_q, wait); poll_wait(file, &port->in_wait_q, wait); @@ -645,33 +586,175 @@ static unsigned int sync_serial_poll(struct file *file, poll_table *wait) if (port->input && sync_data_avail(port) >= port->inbufchunk) mask |= POLLIN | POLLRDNORM; - DEBUGPOLL(if (mask != prev_mask) - printk("sync_serial_poll: mask 0x%08X %s %s\n", mask, - mask&POLLOUT?"POLLOUT":"", mask&POLLIN?"POLLIN":""); - prev_mask = mask; - ); + DEBUGPOLL( + if (mask != prev_mask) + pr_info("sync_serial_poll: mask 0x%08X %s %s\n", + mask, + mask & POLLOUT ? "POLLOUT" : "", + mask & POLLIN ? "POLLIN" : ""); + prev_mask = mask; + ); return mask; } -static int sync_serial_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) +static ssize_t __sync_serial_read(struct file *file, + char __user *buf, + size_t count, + loff_t *ppos, + struct timespec *ts) +{ + unsigned long flags; + int dev = MINOR(file->f_dentry->d_inode->i_rdev); + int avail; + struct sync_port *port; + unsigned char *start; + unsigned char *end; + + if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { + DEBUG(pr_info("Invalid minor %d\n", dev)); + return -ENODEV; + } + port = &ports[dev]; + + if (!port->started) + sync_serial_start_port(port); + + /* Calculate number of available bytes */ + /* Save pointers to avoid that they are modified by interrupt */ + spin_lock_irqsave(&port->lock, flags); + start = port->readp; + end = port->writep; + spin_unlock_irqrestore(&port->lock, flags); + + while ((start == end) && !port->in_buffer_len) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + + wait_event_interruptible(port->in_wait_q, + !(start == end && !port->full)); + + if (signal_pending(current)) + return -EINTR; + + spin_lock_irqsave(&port->lock, flags); + start = port->readp; + end = port->writep; + spin_unlock_irqrestore(&port->lock, flags); + } + + DEBUGREAD(pr_info("R%d c %d ri %u wi %u /%u\n", + dev, count, + start - port->flip, end - port->flip, + port->in_buffer_size)); + + /* Lazy read, never return wrapped data. */ + if (end > start) + avail = end - start; + else + avail = port->flip + port->in_buffer_size - start; + + count = count > avail ? avail : count; + if (copy_to_user(buf, start, count)) + return -EFAULT; + + /* If timestamp requested, find timestamp of first returned byte + * and copy it. + * N.B: Applications that request timstamps MUST read data in + * chunks that are multiples of IN_DESCR_SIZE. + * Otherwise the timestamps will not be aligned to the data read. + */ + if (ts != NULL) { + int idx = port->read_ts_idx; + memcpy(ts, &port->timestamp[idx], sizeof(struct timespec)); + port->read_ts_idx += count / IN_DESCR_SIZE; + if (port->read_ts_idx >= NBR_IN_DESCR) + port->read_ts_idx = 0; + } + + spin_lock_irqsave(&port->lock, flags); + port->readp += count; + /* Check for wrap */ + if (port->readp >= port->flip + port->in_buffer_size) + port->readp = port->flip; + port->in_buffer_len -= count; + port->full = 0; + spin_unlock_irqrestore(&port->lock, flags); + + DEBUGREAD(pr_info("r %d\n", count)); + + return count; +} + +static ssize_t sync_serial_input(struct file *file, unsigned long arg) +{ + struct ssp_request req; + int count; + int ret; + + /* Copy the request structure from user-mode. */ + ret = copy_from_user(&req, (struct ssp_request __user *)arg, + sizeof(struct ssp_request)); + + if (ret) { + DEBUG(pr_info("sync_serial_input copy from user failed\n")); + return -EFAULT; + } + + /* To get the timestamps aligned, make sure that 'len' + * is a multiple of IN_DESCR_SIZE. + */ + if ((req.len % IN_DESCR_SIZE) != 0) { + DEBUG(pr_info("sync_serial: req.len %x, IN_DESCR_SIZE %x\n", + req.len, IN_DESCR_SIZE)); + return -EFAULT; + } + + /* Do the actual read. */ + /* Note that req.buf is actually a pointer to user space. */ + count = __sync_serial_read(file, req.buf, req.len, + NULL, &req.ts); + + if (count < 0) { + DEBUG(pr_info("sync_serial_input read failed\n")); + return count; + } + + /* Copy the request back to user-mode. */ + ret = copy_to_user((struct ssp_request __user *)arg, &req, + sizeof(struct ssp_request)); + + if (ret) { + DEBUG(pr_info("syncser input copy2user failed\n")); + return -EFAULT; + } + + /* Return the number of bytes read. */ + return count; +} + + +static int sync_serial_ioctl_unlocked(struct file *file, + unsigned int cmd, unsigned long arg) { int return_val = 0; int dma_w_size = regk_dma_set_w_size1; int dev = iminor(file_inode(file)); - sync_port *port; + struct sync_port *port; reg_sser_rw_tr_cfg tr_cfg; reg_sser_rw_rec_cfg rec_cfg; reg_sser_rw_frm_cfg frm_cfg; reg_sser_rw_cfg gen_cfg; reg_sser_rw_intr_mask intr_mask; - if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); + if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { + DEBUG(pr_info("Invalid minor %d\n", dev)); return -1; } - port = &ports[dev]; + + if (cmd == SSP_INPUT) + return sync_serial_input(file, arg); + + port = &ports[dev]; spin_lock_irq(&port->lock); tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); @@ -680,11 +763,9 @@ static int sync_serial_ioctl(struct file *file, gen_cfg = REG_RD(sser, port->regi_sser, rw_cfg); intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); - switch(cmd) - { + switch (cmd) { case SSP_SPEED: - if (GET_SPEED(arg) == CODEC) - { + if (GET_SPEED(arg) == CODEC) { unsigned int freq; gen_cfg.base_freq = regk_sser_f32; @@ -701,15 +782,25 @@ static int sync_serial_ioctl(struct file *file, case FREQ_256kHz: gen_cfg.clk_div = 125 * (1 << (freq - FREQ_256kHz)) - 1; - break; + break; case FREQ_512kHz: gen_cfg.clk_div = 62; - break; + break; case FREQ_1MHz: case FREQ_2MHz: case FREQ_4MHz: gen_cfg.clk_div = 8 * (1 << freq) - 1; - break; + break; + } + } else if (GET_SPEED(arg) == CODEC_f32768) { + gen_cfg.base_freq = regk_sser_f32_768; + switch (GET_FREQ(arg)) { + case FREQ_4096kHz: + gen_cfg.clk_div = 7; + break; + default: + spin_unlock_irq(&port->lock); + return -EINVAL; } } else { gen_cfg.base_freq = regk_sser_f29_493; @@ -767,62 +858,64 @@ static int sync_serial_ioctl(struct file *file, break; case SSP_MODE: - switch(arg) - { - case MASTER_OUTPUT: - port->output = 1; - port->input = 0; - frm_cfg.out_on = regk_sser_tr; - frm_cfg.frame_pin_dir = regk_sser_out; - gen_cfg.clk_dir = regk_sser_out; - break; - case SLAVE_OUTPUT: - port->output = 1; - port->input = 0; - frm_cfg.frame_pin_dir = regk_sser_in; - gen_cfg.clk_dir = regk_sser_in; - break; - case MASTER_INPUT: - port->output = 0; - port->input = 1; - frm_cfg.frame_pin_dir = regk_sser_out; - frm_cfg.out_on = regk_sser_intern_tb; - gen_cfg.clk_dir = regk_sser_out; - break; - case SLAVE_INPUT: - port->output = 0; - port->input = 1; - frm_cfg.frame_pin_dir = regk_sser_in; - gen_cfg.clk_dir = regk_sser_in; - break; - case MASTER_BIDIR: - port->output = 1; - port->input = 1; - frm_cfg.frame_pin_dir = regk_sser_out; - frm_cfg.out_on = regk_sser_intern_tb; - gen_cfg.clk_dir = regk_sser_out; - break; - case SLAVE_BIDIR: - port->output = 1; - port->input = 1; - frm_cfg.frame_pin_dir = regk_sser_in; - gen_cfg.clk_dir = regk_sser_in; - break; - default: - spin_unlock_irq(&port->lock); - return -EINVAL; + switch (arg) { + case MASTER_OUTPUT: + port->output = 1; + port->input = 0; + frm_cfg.out_on = regk_sser_tr; + frm_cfg.frame_pin_dir = regk_sser_out; + gen_cfg.clk_dir = regk_sser_out; + break; + case SLAVE_OUTPUT: + port->output = 1; + port->input = 0; + frm_cfg.frame_pin_dir = regk_sser_in; + gen_cfg.clk_dir = regk_sser_in; + break; + case MASTER_INPUT: + port->output = 0; + port->input = 1; + frm_cfg.frame_pin_dir = regk_sser_out; + frm_cfg.out_on = regk_sser_intern_tb; + gen_cfg.clk_dir = regk_sser_out; + break; + case SLAVE_INPUT: + port->output = 0; + port->input = 1; + frm_cfg.frame_pin_dir = regk_sser_in; + gen_cfg.clk_dir = regk_sser_in; + break; + case MASTER_BIDIR: + port->output = 1; + port->input = 1; + frm_cfg.frame_pin_dir = regk_sser_out; + frm_cfg.out_on = regk_sser_intern_tb; + gen_cfg.clk_dir = regk_sser_out; + break; + case SLAVE_BIDIR: + port->output = 1; + port->input = 1; + frm_cfg.frame_pin_dir = regk_sser_in; + gen_cfg.clk_dir = regk_sser_in; + break; + default: + spin_unlock_irq(&port->lock); + return -EINVAL; } - if (!port->use_dma || (arg == MASTER_OUTPUT || arg == SLAVE_OUTPUT)) + if (!port->use_dma || arg == MASTER_OUTPUT || + arg == SLAVE_OUTPUT) intr_mask.rdav = regk_sser_yes; break; case SSP_FRAME_SYNC: if (arg & NORMAL_SYNC) { frm_cfg.rec_delay = 1; frm_cfg.tr_delay = 1; - } - else if (arg & EARLY_SYNC) + } else if (arg & EARLY_SYNC) frm_cfg.rec_delay = frm_cfg.tr_delay = 0; - else if (arg & SECOND_WORD_SYNC) { + else if (arg & LATE_SYNC) { + frm_cfg.tr_delay = 2; + frm_cfg.rec_delay = 2; + } else if (arg & SECOND_WORD_SYNC) { frm_cfg.rec_delay = 7; frm_cfg.tr_delay = 1; } @@ -914,15 +1007,12 @@ static int sync_serial_ioctl(struct file *file, frm_cfg.type = regk_sser_level; frm_cfg.tr_delay = 1; frm_cfg.level = regk_sser_neg_lo; - if (arg & SPI_SLAVE) - { + if (arg & SPI_SLAVE) { rec_cfg.clk_pol = regk_sser_neg; gen_cfg.clk_dir = regk_sser_in; port->input = 1; port->output = 0; - } - else - { + } else { gen_cfg.out_clk_pol = regk_sser_pos; port->input = 0; port->output = 1; @@ -965,19 +1055,19 @@ static int sync_serial_ioctl(struct file *file, } static long sync_serial_ioctl(struct file *file, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - long ret; + long ret; - mutex_lock(&sync_serial_mutex); - ret = sync_serial_ioctl_unlocked(file, cmd, arg); - mutex_unlock(&sync_serial_mutex); + mutex_lock(&sync_serial_mutex); + ret = sync_serial_ioctl_unlocked(file, cmd, arg); + mutex_unlock(&sync_serial_mutex); - return ret; + return ret; } /* NOTE: sync_serial_write does not support concurrency */ -static ssize_t sync_serial_write(struct file *file, const char *buf, +static ssize_t sync_serial_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { int dev = iminor(file_inode(file)); @@ -993,7 +1083,7 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, unsigned char *buf_stop_ptr; /* Last byte + 1 */ if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) { - DEBUG(printk("Invalid minor %d\n", dev)); + DEBUG(pr_info("Invalid minor %d\n", dev)); return -ENODEV; } port = &ports[dev]; @@ -1006,9 +1096,9 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, * |_________|___________________|________________________| * ^ rd_ptr ^ wr_ptr */ - DEBUGWRITE(printk(KERN_DEBUG "W d%d c %lu a: %p c: %p\n", - port->port_nbr, count, port->active_tr_descr, - port->catch_tr_descr)); + DEBUGWRITE(pr_info("W d%d c %u a: %p c: %p\n", + port->port_nbr, count, port->active_tr_descr, + port->catch_tr_descr)); /* Read variables that may be updated by interrupts */ spin_lock_irqsave(&port->lock, flags); @@ -1020,7 +1110,7 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, if (port->tr_running && ((port->use_dma && port->active_tr_descr == port->catch_tr_descr) || out_buf_count >= OUT_BUFFER_SIZE)) { - DEBUGWRITE(printk(KERN_DEBUG "sser%d full\n", dev)); + DEBUGWRITE(pr_info("sser%d full\n", dev)); return -EAGAIN; } @@ -1043,15 +1133,16 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, if (copy_from_user(wr_ptr, buf, trunc_count)) return -EFAULT; - DEBUGOUTBUF(printk(KERN_DEBUG "%-4d + %-4d = %-4d %p %p %p\n", - out_buf_count, trunc_count, - port->out_buf_count, port->out_buffer, - wr_ptr, buf_stop_ptr)); + DEBUGOUTBUF(pr_info("%-4d + %-4d = %-4d %p %p %p\n", + out_buf_count, trunc_count, + port->out_buf_count, port->out_buffer, + wr_ptr, buf_stop_ptr)); /* Make sure transmitter/receiver is running */ if (!port->started) { reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); - reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); + reg_sser_rw_rec_cfg rec_cfg = + REG_RD(sser, port->regi_sser, rw_rec_cfg); cfg.en = regk_sser_yes; rec_cfg.rec_en = port->input; REG_WR(sser, port->regi_sser, rw_cfg, cfg); @@ -1068,8 +1159,11 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, spin_lock_irqsave(&port->lock, flags); port->out_buf_count += trunc_count; if (port->use_dma) { +#ifdef SYNC_SER_DMA start_dma_out(port, wr_ptr, trunc_count); +#endif } else if (!port->tr_running) { +#ifdef SYNC_SER_MANUAL reg_sser_rw_intr_mask intr_mask; intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); /* Start sender by writing data */ @@ -1077,14 +1171,15 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, /* and enable transmitter ready IRQ */ intr_mask.trdy = 1; REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); +#endif } spin_unlock_irqrestore(&port->lock, flags); /* Exit if non blocking */ if (file->f_flags & O_NONBLOCK) { - DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu %08x\n", - port->port_nbr, trunc_count, - REG_RD_INT(dma, port->regi_dmaout, r_intr))); + DEBUGWRITE(pr_info("w d%d c %u %08x\n", + port->port_nbr, trunc_count, + REG_RD_INT(dma, port->regi_dmaout, r_intr))); return trunc_count; } @@ -1094,105 +1189,32 @@ static ssize_t sync_serial_write(struct file *file, const char *buf, if (signal_pending(current)) return -EINTR; - DEBUGWRITE(printk(KERN_DEBUG "w d%d c %lu\n", - port->port_nbr, trunc_count)); + DEBUGWRITE(pr_info("w d%d c %u\n", port->port_nbr, trunc_count)); return trunc_count; } -static ssize_t sync_serial_read(struct file * file, char * buf, +static ssize_t sync_serial_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) { - int dev = iminor(file_inode(file)); - int avail; - sync_port *port; - unsigned char* start; - unsigned char* end; - unsigned long flags; - - if (dev < 0 || dev >= NBR_PORTS || !ports[dev].enabled) - { - DEBUG(printk("Invalid minor %d\n", dev)); - return -ENODEV; - } - port = &ports[dev]; - - DEBUGREAD(printk("R%d c %d ri %lu wi %lu /%lu\n", dev, count, port->readp - port->flip, port->writep - port->flip, port->in_buffer_size)); - - if (!port->started) - { - reg_sser_rw_cfg cfg = REG_RD(sser, port->regi_sser, rw_cfg); - reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); - reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); - cfg.en = regk_sser_yes; - tr_cfg.tr_en = regk_sser_yes; - rec_cfg.rec_en = regk_sser_yes; - REG_WR(sser, port->regi_sser, rw_cfg, cfg); - REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); - REG_WR(sser, port->regi_sser, rw_rec_cfg, rec_cfg); - port->started = 1; - } - - /* Calculate number of available bytes */ - /* Save pointers to avoid that they are modified by interrupt */ - spin_lock_irqsave(&port->lock, flags); - start = (unsigned char*)port->readp; /* cast away volatile */ - end = (unsigned char*)port->writep; /* cast away volatile */ - spin_unlock_irqrestore(&port->lock, flags); - while ((start == end) && !port->full) /* No data */ - { - DEBUGREAD(printk(KERN_DEBUG "&")); - if (file->f_flags & O_NONBLOCK) - return -EAGAIN; - - wait_event_interruptible(port->in_wait_q, - !(start == end && !port->full)); - if (signal_pending(current)) - return -EINTR; - - spin_lock_irqsave(&port->lock, flags); - start = (unsigned char*)port->readp; /* cast away volatile */ - end = (unsigned char*)port->writep; /* cast away volatile */ - spin_unlock_irqrestore(&port->lock, flags); - } - - /* Lazy read, never return wrapped data. */ - if (port->full) - avail = port->in_buffer_size; - else if (end > start) - avail = end - start; - else - avail = port->flip + port->in_buffer_size - start; - - count = count > avail ? avail : count; - if (copy_to_user(buf, start, count)) - return -EFAULT; - /* Disable interrupts while updating readp */ - spin_lock_irqsave(&port->lock, flags); - port->readp += count; - if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */ - port->readp = port->flip; - port->full = 0; - spin_unlock_irqrestore(&port->lock, flags); - DEBUGREAD(printk("r %d\n", count)); - return count; + return __sync_serial_read(file, buf, count, ppos, NULL); } -static void send_word(sync_port* port) +#ifdef SYNC_SER_MANUAL +static void send_word(struct sync_port *port) { reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); reg_sser_rw_tr_data tr_data = {0}; - switch(tr_cfg.sample_size) + switch (tr_cfg.sample_size) { + case 8: + port->out_buf_count--; + tr_data.data = *port->out_rd_ptr++; + REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); + if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) + port->out_rd_ptr = port->out_buffer; + break; + case 12: { - case 8: - port->out_buf_count--; - tr_data.data = *port->out_rd_ptr++; - REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); - if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) - port->out_rd_ptr = port->out_buffer; - break; - case 12: - { int data = (*port->out_rd_ptr++) << 8; data |= *port->out_rd_ptr++; port->out_buf_count -= 2; @@ -1200,8 +1222,8 @@ static void send_word(sync_port* port) REG_WR(sser, port->regi_sser, rw_tr_data, tr_data); if (port->out_rd_ptr >= port->out_buffer + OUT_BUFFER_SIZE) port->out_rd_ptr = port->out_buffer; + break; } - break; case 16: port->out_buf_count -= 2; tr_data.data = *(unsigned short *)port->out_rd_ptr; @@ -1233,27 +1255,28 @@ static void send_word(sync_port* port) break; } } +#endif -static void start_dma_out(struct sync_port *port, - const char *data, int count) +#ifdef SYNC_SER_DMA +static void start_dma_out(struct sync_port *port, const char *data, int count) { - port->active_tr_descr->buf = (char *) virt_to_phys((char *) data); + port->active_tr_descr->buf = (char *)virt_to_phys((char *)data); port->active_tr_descr->after = port->active_tr_descr->buf + count; port->active_tr_descr->intr = 1; port->active_tr_descr->eol = 1; port->prev_tr_descr->eol = 0; - DEBUGTRDMA(printk(KERN_DEBUG "Inserting eolr:%p eol@:%p\n", + DEBUGTRDMA(pr_info("Inserting eolr:%p eol@:%p\n", port->prev_tr_descr, port->active_tr_descr)); port->prev_tr_descr = port->active_tr_descr; - port->active_tr_descr = phys_to_virt((int) port->active_tr_descr->next); + port->active_tr_descr = phys_to_virt((int)port->active_tr_descr->next); if (!port->tr_running) { reg_sser_rw_tr_cfg tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); - port->out_context.next = 0; + port->out_context.next = NULL; port->out_context.saved_data = (dma_descr_data *)virt_to_phys(port->prev_tr_descr); port->out_context.saved_data_buf = port->prev_tr_descr->buf; @@ -1263,57 +1286,58 @@ static void start_dma_out(struct sync_port *port, tr_cfg.tr_en = regk_sser_yes; REG_WR(sser, port->regi_sser, rw_tr_cfg, tr_cfg); - DEBUGTRDMA(printk(KERN_DEBUG "dma s\n");); + DEBUGTRDMA(pr_info(KERN_INFO "dma s\n");); } else { DMA_CONTINUE_DATA(port->regi_dmaout); - DEBUGTRDMA(printk(KERN_DEBUG "dma c\n");); + DEBUGTRDMA(pr_info("dma c\n");); } port->tr_running = 1; } -static void start_dma_in(sync_port *port) +static void start_dma_in(struct sync_port *port) { int i; char *buf; + unsigned long flags; + spin_lock_irqsave(&port->lock, flags); port->writep = port->flip; + spin_unlock_irqrestore(&port->lock, flags); - if (port->writep > port->flip + port->in_buffer_size) { - panic("Offset too large in sync serial driver\n"); - return; - } - buf = (char*)virt_to_phys(port->in_buffer); + buf = (char *)virt_to_phys(port->in_buffer); for (i = 0; i < NBR_IN_DESCR; i++) { port->in_descr[i].buf = buf; port->in_descr[i].after = buf + port->inbufchunk; port->in_descr[i].intr = 1; - port->in_descr[i].next = (dma_descr_data*)virt_to_phys(&port->in_descr[i+1]); + port->in_descr[i].next = + (dma_descr_data *)virt_to_phys(&port->in_descr[i+1]); port->in_descr[i].buf = buf; buf += port->inbufchunk; } /* Link the last descriptor to the first */ - port->in_descr[i-1].next = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); + port->in_descr[i-1].next = + (dma_descr_data *)virt_to_phys(&port->in_descr[0]); port->in_descr[i-1].eol = regk_sser_yes; port->next_rx_desc = &port->in_descr[0]; port->prev_rx_desc = &port->in_descr[NBR_IN_DESCR - 1]; - port->in_context.saved_data = (dma_descr_data*)virt_to_phys(&port->in_descr[0]); + port->in_context.saved_data = + (dma_descr_data *)virt_to_phys(&port->in_descr[0]); port->in_context.saved_data_buf = port->in_descr[0].buf; DMA_START_CONTEXT(port->regi_dmain, virt_to_phys(&port->in_context)); } -#ifdef SYNC_SER_DMA static irqreturn_t tr_interrupt(int irq, void *dev_id) { reg_dma_r_masked_intr masked; - reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes}; + reg_dma_rw_ack_intr ack_intr = { .data = regk_dma_yes }; reg_dma_rw_stat stat; int i; int found = 0; int stop_sser = 0; for (i = 0; i < NBR_PORTS; i++) { - sync_port *port = &ports[i]; - if (!port->enabled || !port->use_dma) + struct sync_port *port = &ports[i]; + if (!port->enabled || !port->use_dma) continue; /* IRQ active for the port? */ @@ -1338,19 +1362,20 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) int sent; sent = port->catch_tr_descr->after - port->catch_tr_descr->buf; - DEBUGTXINT(printk(KERN_DEBUG "%-4d - %-4d = %-4d\t" - "in descr %p (ac: %p)\n", - port->out_buf_count, sent, - port->out_buf_count - sent, - port->catch_tr_descr, - port->active_tr_descr);); + DEBUGTXINT(pr_info("%-4d - %-4d = %-4d\t" + "in descr %p (ac: %p)\n", + port->out_buf_count, sent, + port->out_buf_count - sent, + port->catch_tr_descr, + port->active_tr_descr);); port->out_buf_count -= sent; port->catch_tr_descr = phys_to_virt((int) port->catch_tr_descr->next); port->out_rd_ptr = phys_to_virt((int) port->catch_tr_descr->buf); } else { - int i, sent; + reg_sser_rw_tr_cfg tr_cfg; + int j, sent; /* EOL handler. * Note that if an EOL was encountered during the irq * locked section of sync_ser_write the DMA will be @@ -1358,11 +1383,11 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) * The remaining descriptors will be traversed by * the descriptor interrupts as usual. */ - i = 0; + j = 0; while (!port->catch_tr_descr->eol) { sent = port->catch_tr_descr->after - port->catch_tr_descr->buf; - DEBUGOUTBUF(printk(KERN_DEBUG + DEBUGOUTBUF(pr_info( "traversing descr %p -%d (%d)\n", port->catch_tr_descr, sent, @@ -1370,16 +1395,15 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) port->out_buf_count -= sent; port->catch_tr_descr = phys_to_virt( (int)port->catch_tr_descr->next); - i++; - if (i >= NBR_OUT_DESCR) { + j++; + if (j >= NBR_OUT_DESCR) { /* TODO: Reset and recover */ panic("sync_serial: missing eol"); } } sent = port->catch_tr_descr->after - port->catch_tr_descr->buf; - DEBUGOUTBUF(printk(KERN_DEBUG - "eol at descr %p -%d (%d)\n", + DEBUGOUTBUF(pr_info("eol at descr %p -%d (%d)\n", port->catch_tr_descr, sent, port->out_buf_count)); @@ -1394,15 +1418,13 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) OUT_BUFFER_SIZE) port->out_rd_ptr = port->out_buffer; - reg_sser_rw_tr_cfg tr_cfg = - REG_RD(sser, port->regi_sser, rw_tr_cfg); - DEBUGTXINT(printk(KERN_DEBUG + tr_cfg = REG_RD(sser, port->regi_sser, rw_tr_cfg); + DEBUGTXINT(pr_info( "tr_int DMA stop %d, set catch @ %p\n", port->out_buf_count, port->active_tr_descr)); if (port->out_buf_count != 0) - printk(KERN_CRIT "sync_ser: buffer not " - "empty after eol.\n"); + pr_err("sync_ser: buf not empty after eol\n"); port->catch_tr_descr = port->active_tr_descr; port->tr_running = 0; tr_cfg.tr_en = regk_sser_no; @@ -1414,62 +1436,79 @@ static irqreturn_t tr_interrupt(int irq, void *dev_id) return IRQ_RETVAL(found); } /* tr_interrupt */ + +static inline void handle_rx_packet(struct sync_port *port) +{ + int idx; + reg_dma_rw_ack_intr ack_intr = { .data = regk_dma_yes }; + unsigned long flags; + + DEBUGRXINT(pr_info(KERN_INFO "!")); + spin_lock_irqsave(&port->lock, flags); + + /* If we overrun the user experience is crap regardless if we + * drop new or old data. Its much easier to get it right when + * dropping new data so lets do that. + */ + if ((port->writep + port->inbufchunk <= + port->flip + port->in_buffer_size) && + (port->in_buffer_len + port->inbufchunk < IN_BUFFER_SIZE)) { + memcpy(port->writep, + phys_to_virt((unsigned)port->next_rx_desc->buf), + port->inbufchunk); + port->writep += port->inbufchunk; + if (port->writep >= port->flip + port->in_buffer_size) + port->writep = port->flip; + + /* Timestamp the new data chunk. */ + if (port->write_ts_idx == NBR_IN_DESCR) + port->write_ts_idx = 0; + idx = port->write_ts_idx++; + do_posix_clock_monotonic_gettime(&port->timestamp[idx]); + port->in_buffer_len += port->inbufchunk; + } + spin_unlock_irqrestore(&port->lock, flags); + + port->next_rx_desc->eol = 1; + port->prev_rx_desc->eol = 0; + /* Cache bug workaround */ + flush_dma_descr(port->prev_rx_desc, 0); + port->prev_rx_desc = port->next_rx_desc; + port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next); + /* Cache bug workaround */ + flush_dma_descr(port->prev_rx_desc, 1); + /* wake up the waiting process */ + wake_up_interruptible(&port->in_wait_q); + DMA_CONTINUE(port->regi_dmain); + REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr); + +} + static irqreturn_t rx_interrupt(int irq, void *dev_id) { reg_dma_r_masked_intr masked; - reg_dma_rw_ack_intr ack_intr = {.data = regk_dma_yes}; int i; int found = 0; - for (i = 0; i < NBR_PORTS; i++) - { - sync_port *port = &ports[i]; + DEBUG(pr_info("rx_interrupt\n")); + + for (i = 0; i < NBR_PORTS; i++) { + struct sync_port *port = &ports[i]; - if (!port->enabled || !port->use_dma ) + if (!port->enabled || !port->use_dma) continue; masked = REG_RD(dma, port->regi_dmain, r_masked_intr); - if (masked.data) /* Descriptor interrupt */ - { - found = 1; - while (REG_RD(dma, port->regi_dmain, rw_data) != - virt_to_phys(port->next_rx_desc)) { - DEBUGRXINT(printk(KERN_DEBUG "!")); - if (port->writep + port->inbufchunk > port->flip + port->in_buffer_size) { - int first_size = port->flip + port->in_buffer_size - port->writep; - memcpy((char*)port->writep, phys_to_virt((unsigned)port->next_rx_desc->buf), first_size); - memcpy(port->flip, phys_to_virt((unsigned)port->next_rx_desc->buf+first_size), port->inbufchunk - first_size); - port->writep = port->flip + port->inbufchunk - first_size; - } else { - memcpy((char*)port->writep, - phys_to_virt((unsigned)port->next_rx_desc->buf), - port->inbufchunk); - port->writep += port->inbufchunk; - if (port->writep >= port->flip + port->in_buffer_size) - port->writep = port->flip; - } - if (port->writep == port->readp) - { - port->full = 1; - } - - port->next_rx_desc->eol = 1; - port->prev_rx_desc->eol = 0; - /* Cache bug workaround */ - flush_dma_descr(port->prev_rx_desc, 0); - port->prev_rx_desc = port->next_rx_desc; - port->next_rx_desc = phys_to_virt((unsigned)port->next_rx_desc->next); - /* Cache bug workaround */ - flush_dma_descr(port->prev_rx_desc, 1); - /* wake up the waiting process */ - wake_up_interruptible(&port->in_wait_q); - DMA_CONTINUE(port->regi_dmain); - REG_WR(dma, port->regi_dmain, rw_ack_intr, ack_intr); + if (!masked.data) + continue; - } - } + /* Descriptor interrupt */ + found = 1; + while (REG_RD(dma, port->regi_dmain, rw_data) != + virt_to_phys(port->next_rx_desc)) + handle_rx_packet(port); } return IRQ_RETVAL(found); } /* rx_interrupt */ @@ -1478,75 +1517,83 @@ static irqreturn_t rx_interrupt(int irq, void *dev_id) #ifdef SYNC_SER_MANUAL static irqreturn_t manual_interrupt(int irq, void *dev_id) { + unsigned long flags; int i; int found = 0; reg_sser_r_masked_intr masked; - for (i = 0; i < NBR_PORTS; i++) - { - sync_port *port = &ports[i]; + for (i = 0; i < NBR_PORTS; i++) { + struct sync_port *port = &ports[i]; if (!port->enabled || port->use_dma) - { continue; - } masked = REG_RD(sser, port->regi_sser, r_masked_intr); - if (masked.rdav) /* Data received? */ - { - reg_sser_rw_rec_cfg rec_cfg = REG_RD(sser, port->regi_sser, rw_rec_cfg); - reg_sser_r_rec_data data = REG_RD(sser, port->regi_sser, r_rec_data); + /* Data received? */ + if (masked.rdav) { + reg_sser_rw_rec_cfg rec_cfg = + REG_RD(sser, port->regi_sser, rw_rec_cfg); + reg_sser_r_rec_data data = REG_RD(sser, + port->regi_sser, r_rec_data); found = 1; /* Read data */ - switch(rec_cfg.sample_size) - { + spin_lock_irqsave(&port->lock, flags); + switch (rec_cfg.sample_size) { case 8: *port->writep++ = data.data & 0xff; break; case 12: *port->writep = (data.data & 0x0ff0) >> 4; *(port->writep + 1) = data.data & 0x0f; - port->writep+=2; + port->writep += 2; break; case 16: - *(unsigned short*)port->writep = data.data; - port->writep+=2; + *(unsigned short *)port->writep = data.data; + port->writep += 2; break; case 24: - *(unsigned int*)port->writep = data.data; - port->writep+=3; + *(unsigned int *)port->writep = data.data; + port->writep += 3; break; case 32: - *(unsigned int*)port->writep = data.data; - port->writep+=4; + *(unsigned int *)port->writep = data.data; + port->writep += 4; break; } - if (port->writep >= port->flip + port->in_buffer_size) /* Wrap? */ + /* Wrap? */ + if (port->writep >= port->flip + port->in_buffer_size) port->writep = port->flip; if (port->writep == port->readp) { - /* receive buffer overrun, discard oldest data - */ + /* Receive buf overrun, discard oldest data */ port->readp++; - if (port->readp >= port->flip + port->in_buffer_size) /* Wrap? */ + /* Wrap? */ + if (port->readp >= port->flip + + port->in_buffer_size) port->readp = port->flip; } + spin_unlock_irqrestore(&port->lock, flags); if (sync_data_avail(port) >= port->inbufchunk) - wake_up_interruptible(&port->in_wait_q); /* Wake up application */ + /* Wake up application */ + wake_up_interruptible(&port->in_wait_q); } - if (masked.trdy) /* Transmitter ready? */ - { + /* Transmitter ready? */ + if (masked.trdy) { found = 1; - if (port->out_buf_count > 0) /* More data to send */ + /* More data to send */ + if (port->out_buf_count > 0) send_word(port); - else /* transmission finished */ - { + else { + /* Transmission finished */ reg_sser_rw_intr_mask intr_mask; - intr_mask = REG_RD(sser, port->regi_sser, rw_intr_mask); + intr_mask = REG_RD(sser, port->regi_sser, + rw_intr_mask); intr_mask.trdy = 0; - REG_WR(sser, port->regi_sser, rw_intr_mask, intr_mask); - wake_up_interruptible(&port->out_wait_q); /* Wake up application */ + REG_WR(sser, port->regi_sser, + rw_intr_mask, intr_mask); + /* Wake up application */ + wake_up_interruptible(&port->out_wait_q); } } } @@ -1554,4 +1601,109 @@ static irqreturn_t manual_interrupt(int irq, void *dev_id) } #endif +static int __init etrax_sync_serial_init(void) +{ +#if 1 + /* This code will be removed when we move to udev for all devices. */ + syncser_first = MKDEV(SYNC_SERIAL_MAJOR, 0); + if (register_chrdev_region(syncser_first, minor_count, SYNCSER_NAME)) { + pr_err("Failed to register major %d\n", SYNC_SERIAL_MAJOR); + return -1; + } +#else + /* Allocate dynamic major number. */ + if (alloc_chrdev_region(&syncser_first, 0, minor_count, SYNCSER_NAME)) { + pr_err("Failed to allocate character device region\n"); + return -1; + } +#endif + syncser_cdev = cdev_alloc(); + if (!syncser_cdev) { + pr_err("Failed to allocate cdev for syncser\n"); + unregister_chrdev_region(syncser_first, minor_count); + return -1; + } + cdev_init(syncser_cdev, &syncser_fops); + + /* Create a sysfs class for syncser */ + syncser_class = class_create(THIS_MODULE, "syncser_class"); + + /* Initialize Ports */ +#if defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT0) + if (artpec_pinmux_alloc_fixed(PINMUX_SSER0)) { + pr_warn("Unable to alloc pins for synchronous serial port 0\n"); + unregister_chrdev_region(syncser_first, minor_count); + return -EIO; + } + initialize_port(0); + ports[0].enabled = 1; + /* Register with sysfs so udev can pick it up. */ + device_create(syncser_class, NULL, syncser_first, NULL, + "%s%d", SYNCSER_NAME, 0); +#endif + +#if defined(CONFIG_ETRAXFS) && defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1) + if (artpec_pinmux_alloc_fixed(PINMUX_SSER1)) { + pr_warn("Unable to alloc pins for synchronous serial port 1\n"); + unregister_chrdev_region(syncser_first, minor_count); + class_destroy(syncser_class); + return -EIO; + } + initialize_port(1); + ports[1].enabled = 1; + /* Register with sysfs so udev can pick it up. */ + device_create(syncser_class, NULL, syncser_first, NULL, + "%s%d", SYNCSER_NAME, 0); +#endif + + /* Add it to system */ + if (cdev_add(syncser_cdev, syncser_first, minor_count) < 0) { + pr_err("Failed to add syncser as char device\n"); + device_destroy(syncser_class, syncser_first); + class_destroy(syncser_class); + cdev_del(syncser_cdev); + unregister_chrdev_region(syncser_first, minor_count); + return -1; + } + + + pr_info("ARTPEC synchronous serial port (%s: %d, %d)\n", + SYNCSER_NAME, MAJOR(syncser_first), MINOR(syncser_first)); + + return 0; +} + +static void __exit etrax_sync_serial_exit(void) +{ + int i; + device_destroy(syncser_class, syncser_first); + class_destroy(syncser_class); + + if (syncser_cdev) { + cdev_del(syncser_cdev); + unregister_chrdev_region(syncser_first, minor_count); + } + for (i = 0; i < NBR_PORTS; i++) { + struct sync_port *port = &ports[i]; + if (port->init_irqs == dma_irq_setup) { + /* Free dma irqs and dma channels. */ +#ifdef SYNC_SER_DMA + artpec_free_dma(port->dma_in_nbr); + artpec_free_dma(port->dma_out_nbr); + free_irq(port->dma_out_intr_vect, port); + free_irq(port->dma_in_intr_vect, port); +#endif + } else if (port->init_irqs == manual_irq_setup) { + /* Free manual irq. */ + free_irq(port->syncser_intr_vect, port); + } + } + + pr_info("ARTPEC synchronous serial port unregistered\n"); +} + module_init(etrax_sync_serial_init); +module_exit(etrax_sync_serial_exit); + +MODULE_LICENSE("GPL"); + -- cgit v1.2.3-59-g8ed1b From ca36c1faddb48c478f7f8944b9b900fc72629310 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Tue, 7 Oct 2014 13:42:35 +0200 Subject: CRISv32: Fix declaration mismatch Drop i2c_init from this header, it was declared non-static here, but static in the C-file. Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/drivers/i2c.h | 1 - 1 file changed, 1 deletion(-) (limited to 'arch') diff --git a/arch/cris/arch-v32/drivers/i2c.h b/arch/cris/arch-v32/drivers/i2c.h index c073cf4ba016..d9cc856f89fb 100644 --- a/arch/cris/arch-v32/drivers/i2c.h +++ b/arch/cris/arch-v32/drivers/i2c.h @@ -2,7 +2,6 @@ #include /* High level I2C actions */ -int __init i2c_init(void); int i2c_write(unsigned char theSlave, void *data, size_t nbytes); int i2c_read(unsigned char theSlave, void *data, size_t nbytes); int i2c_writereg(unsigned char theSlave, unsigned char theReg, unsigned char theValue); -- cgit v1.2.3-59-g8ed1b From 421d085252613c4caf9c4f2fda3c722a9f5bc554 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Wed, 8 Oct 2014 14:57:35 +0200 Subject: CRIS: Use KALLSYMs if available in call stack dump Also, print kernel version on oops. Signed-off-by: Jesper Nilsson --- arch/cris/kernel/traps.c | 61 +++++++++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 27 deletions(-) (limited to 'arch') diff --git a/arch/cris/kernel/traps.c b/arch/cris/kernel/traps.c index 0ffda73734f5..da4c72401e27 100644 --- a/arch/cris/kernel/traps.c +++ b/arch/cris/kernel/traps.c @@ -14,6 +14,10 @@ #include #include +#include +#ifdef CONFIG_KALLSYMS +#include +#endif #include #include @@ -34,25 +38,24 @@ static int kstack_depth_to_print = 24; void (*nmi_handler)(struct pt_regs *); -void -show_trace(unsigned long *stack) +void show_trace(unsigned long *stack) { unsigned long addr, module_start, module_end; extern char _stext, _etext; int i; - printk("\nCall Trace: "); + pr_err("\nCall Trace: "); i = 1; module_start = VMALLOC_START; module_end = VMALLOC_END; - while (((long)stack & (THREAD_SIZE-1)) != 0) { + while (((long)stack & (THREAD_SIZE - 1)) != 0) { if (__get_user(addr, stack)) { /* This message matches "failing address" marked s390 in ksymoops, so lines containing it will not be filtered out by ksymoops. */ - printk("Failing address 0x%lx\n", (unsigned long)stack); + pr_err("Failing address 0x%lx\n", (unsigned long)stack); break; } stack++; @@ -68,10 +71,14 @@ show_trace(unsigned long *stack) if (((addr >= (unsigned long)&_stext) && (addr <= (unsigned long)&_etext)) || ((addr >= module_start) && (addr <= module_end))) { +#ifdef CONFIG_KALLSYMS + print_ip_sym(addr); +#else if (i && ((i % 8) == 0)) - printk("\n "); - printk("[<%08lx>] ", addr); + pr_err("\n "); + pr_err("[<%08lx>] ", addr); i++; +#endif } } } @@ -111,21 +118,21 @@ show_stack(struct task_struct *task, unsigned long *sp) stack = sp; - printk("\nStack from %08lx:\n ", (unsigned long)stack); + pr_err("\nStack from %08lx:\n ", (unsigned long)stack); for (i = 0; i < kstack_depth_to_print; i++) { if (((long)stack & (THREAD_SIZE-1)) == 0) break; if (i && ((i % 8) == 0)) - printk("\n "); + pr_err("\n "); if (__get_user(addr, stack)) { /* This message matches "failing address" marked s390 in ksymoops, so lines containing it will not be filtered out by ksymoops. */ - printk("Failing address 0x%lx\n", (unsigned long)stack); + pr_err("Failing address 0x%lx\n", (unsigned long)stack); break; } stack++; - printk("%08lx ", addr); + pr_err("%08lx ", addr); } show_trace(sp); } @@ -139,33 +146,32 @@ show_stack(void) unsigned long *sp = (unsigned long *)rdusp(); int i; - printk("Stack dump [0x%08lx]:\n", (unsigned long)sp); + pr_err("Stack dump [0x%08lx]:\n", (unsigned long)sp); for (i = 0; i < 16; i++) - printk("sp + %d: 0x%08lx\n", i*4, sp[i]); + pr_err("sp + %d: 0x%08lx\n", i*4, sp[i]); return 0; } #endif -void -set_nmi_handler(void (*handler)(struct pt_regs *)) +void set_nmi_handler(void (*handler)(struct pt_regs *)) { nmi_handler = handler; arch_enable_nmi(); } #ifdef CONFIG_DEBUG_NMI_OOPS -void -oops_nmi_handler(struct pt_regs *regs) +void oops_nmi_handler(struct pt_regs *regs) { stop_watchdog(); oops_in_progress = 1; - printk("NMI!\n"); + pr_err("NMI!\n"); show_registers(regs); oops_in_progress = 0; + oops_exit(); + pr_err("\n"); /* Flush mtdoops. */ } -static int __init -oops_nmi_register(void) +static int __init oops_nmi_register(void) { set_nmi_handler(oops_nmi_handler); return 0; @@ -180,8 +186,7 @@ __initcall(oops_nmi_register); * similar to an Oops dump, and if the kernel is configured to be a nice * doggy, then halt instead of reboot. */ -void -watchdog_bite_hook(struct pt_regs *regs) +void watchdog_bite_hook(struct pt_regs *regs) { #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY local_irq_disable(); @@ -196,8 +201,7 @@ watchdog_bite_hook(struct pt_regs *regs) } /* This is normally the Oops function. */ -void -die_if_kernel(const char *str, struct pt_regs *regs, long err) +void die_if_kernel(const char *str, struct pt_regs *regs, long err) { if (user_mode(regs)) return; @@ -211,13 +215,17 @@ die_if_kernel(const char *str, struct pt_regs *regs, long err) stop_watchdog(); #endif + oops_enter(); handle_BUG(regs); - printk("%s: %04lx\n", str, err & 0xffff); + pr_err("Linux %s %s\n", utsname()->release, utsname()->version); + pr_err("%s: %04lx\n", str, err & 0xffff); show_registers(regs); + oops_exit(); oops_in_progress = 0; + pr_err("\n"); /* Flush mtdoops. */ #ifdef CONFIG_ETRAX_WATCHDOG_NICE_DOGGY reset_watchdog(); @@ -225,8 +233,7 @@ die_if_kernel(const char *str, struct pt_regs *regs, long err) do_exit(SIGSEGV); } -void __init -trap_init(void) +void __init trap_init(void) { /* Nothing needs to be done */ } -- cgit v1.2.3-59-g8ed1b From 4729d77332a4383770c780b7709d5e14f12a4d1e Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Wed, 8 Oct 2014 15:52:49 +0200 Subject: CRISv32: Implement early console Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/kernel/debugport.c | 82 ++++++++++++++++++++++++----------- 1 file changed, 56 insertions(+), 26 deletions(-) (limited to 'arch') diff --git a/arch/cris/arch-v32/kernel/debugport.c b/arch/cris/arch-v32/kernel/debugport.c index 610909b003f6..02e33ebe51ec 100644 --- a/arch/cris/arch-v32/kernel/debugport.c +++ b/arch/cris/arch-v32/kernel/debugport.c @@ -3,7 +3,9 @@ */ #include +#include #include +#include #include #include #include @@ -65,6 +67,7 @@ struct dbg_port ports[] = }, #endif }; + static struct dbg_port *port = #if defined(CONFIG_ETRAX_DEBUG_PORT0) &ports[0]; @@ -97,14 +100,19 @@ static struct dbg_port *kgdb_port = #endif #endif -static void -start_port(struct dbg_port* p) +static void start_port(struct dbg_port *p) { - if (!p) - return; + /* Set up serial port registers */ + reg_ser_rw_tr_ctrl tr_ctrl = {0}; + reg_ser_rw_tr_dma_en tr_dma_en = {0}; - if (p->started) + reg_ser_rw_rec_ctrl rec_ctrl = {0}; + reg_ser_rw_tr_baud_div tr_baud_div = {0}; + reg_ser_rw_rec_baud_div rec_baud_div = {0}; + + if (!p || p->started) return; + p->started = 1; if (p->nbr == 1) @@ -118,36 +126,24 @@ start_port(struct dbg_port* p) crisv32_pinmux_alloc_fixed(pinmux_ser4); #endif - /* Set up serial port registers */ - reg_ser_rw_tr_ctrl tr_ctrl = {0}; - reg_ser_rw_tr_dma_en tr_dma_en = {0}; - - reg_ser_rw_rec_ctrl rec_ctrl = {0}; - reg_ser_rw_tr_baud_div tr_baud_div = {0}; - reg_ser_rw_rec_baud_div rec_baud_div = {0}; - tr_ctrl.base_freq = rec_ctrl.base_freq = regk_ser_f29_493; tr_dma_en.en = rec_ctrl.dma_mode = regk_ser_no; tr_baud_div.div = rec_baud_div.div = 29493000 / p->baudrate / 8; tr_ctrl.en = rec_ctrl.en = 1; - if (p->parity == 'O') - { + if (p->parity == 'O') { tr_ctrl.par_en = regk_ser_yes; tr_ctrl.par = regk_ser_odd; rec_ctrl.par_en = regk_ser_yes; rec_ctrl.par = regk_ser_odd; - } - else if (p->parity == 'E') - { + } else if (p->parity == 'E') { tr_ctrl.par_en = regk_ser_yes; tr_ctrl.par = regk_ser_even; rec_ctrl.par_en = regk_ser_yes; rec_ctrl.par = regk_ser_odd; } - if (p->bits == 7) - { + if (p->bits == 7) { tr_ctrl.data_bits = regk_ser_bits7; rec_ctrl.data_bits = regk_ser_bits7; } @@ -161,8 +157,7 @@ start_port(struct dbg_port* p) #ifdef CONFIG_ETRAX_KGDB /* Use polling to get a single character from the kernel debug port */ -int -getDebugChar(void) +int getDebugChar(void) { reg_ser_rs_stat_din stat; reg_ser_rw_ack_intr ack_intr = { 0 }; @@ -179,8 +174,7 @@ getDebugChar(void) } /* Use polling to put a single character to the kernel debug port */ -void -putDebugChar(int val) +void putDebugChar(int val) { reg_ser_r_stat_din stat; do { @@ -190,12 +184,48 @@ putDebugChar(int val) } #endif /* CONFIG_ETRAX_KGDB */ +static void __init early_putch(int c) +{ + reg_ser_r_stat_din stat; + /* Wait until transmitter is ready and send. */ + do + stat = REG_RD(ser, port->instance, r_stat_din); + while (!stat.tr_rdy); + REG_WR_INT(ser, port->instance, rw_dout, c); +} + +static void __init +early_console_write(struct console *con, const char *s, unsigned n) +{ + extern void reset_watchdog(void); + int i; + + /* Send data. */ + for (i = 0; i < n; i++) { + /* TODO: the '\n' -> '\n\r' translation should be done at the + receiver. Remove it when the serial driver removes it. */ + if (s[i] == '\n') + early_putch('\r'); + early_putch(s[i]); + reset_watchdog(); + } +} + +static struct console early_console_dev __initdata = { + .name = "early", + .write = early_console_write, + .flags = CON_PRINTBUFFER | CON_BOOT, + .index = -1 +}; + /* Register console for printk's, etc. */ -int __init -init_etrax_debug(void) +int __init init_etrax_debug(void) { start_port(port); + /* Register an early console if a debug port was chosen. */ + register_console(&early_console_dev); + #ifdef CONFIG_ETRAX_KGDB start_port(kgdb_port); #endif /* CONFIG_ETRAX_KGDB */ -- cgit v1.2.3-59-g8ed1b From 9f1ad51b32173a2da3c4fab58bc4f87d6094868f Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Mon, 27 Oct 2014 09:09:14 +0100 Subject: CRISv32: Select MTDRAM for axisflashmap Fixes compile error on allmodconfig. Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/drivers/Kconfig | 1 + 1 file changed, 1 insertion(+) (limited to 'arch') diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index 15a9ed1d579c..28e259de9df9 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig @@ -108,6 +108,7 @@ config ETRAX_AXISFLASHMAP select MTD_JEDECPROBE select MTD_BLOCK select MTD_COMPLEX_MAPPINGS + select MTD_MTDRAM help This option enables MTD mapping of flash devices. Needed to use flash memories. If unsure, say Y. -- cgit v1.2.3-59-g8ed1b From a3199ad90ac33c1afae0fa3dbf2e0fe4ee827fa7 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Mon, 27 Oct 2014 09:11:31 +0100 Subject: CRISv32: ETRAXFS: Fix recursive spinlock Move pinmux alloc/dealloc code into functions that don't take the spinlock so we can use from code that has the spinlock already. CRISv32 has no working SMP, so spinlocks becomes a NOP, so deadlock was never seen. Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/mach-fs/pinmux.c | 152 +++++++++++++---------- arch/cris/include/arch-v32/mach-fs/mach/pinmux.h | 2 - 2 files changed, 83 insertions(+), 71 deletions(-) (limited to 'arch') diff --git a/arch/cris/arch-v32/mach-fs/pinmux.c b/arch/cris/arch-v32/mach-fs/pinmux.c index 38f29eec14a6..05a04708b8eb 100644 --- a/arch/cris/arch-v32/mach-fs/pinmux.c +++ b/arch/cris/arch-v32/mach-fs/pinmux.c @@ -26,7 +26,29 @@ static DEFINE_SPINLOCK(pinmux_lock); static void crisv32_pinmux_set(int port); -int crisv32_pinmux_init(void) +static int __crisv32_pinmux_alloc(int port, int first_pin, int last_pin, + enum pin_mode mode) +{ + int i; + + for (i = first_pin; i <= last_pin; i++) { + if ((pins[port][i] != pinmux_none) + && (pins[port][i] != pinmux_gpio) + && (pins[port][i] != mode)) { +#ifdef DEBUG + panic("Pinmux alloc failed!\n"); +#endif + return -EPERM; + } + } + + for (i = first_pin; i <= last_pin; i++) + pins[port][i] = mode; + + crisv32_pinmux_set(port); +} + +static int crisv32_pinmux_init(void) { static int initialized; @@ -37,20 +59,20 @@ int crisv32_pinmux_init(void) pa.pa0 = pa.pa1 = pa.pa2 = pa.pa3 = pa.pa4 = pa.pa5 = pa.pa6 = pa.pa7 = regk_pinmux_yes; REG_WR(pinmux, regi_pinmux, rw_pa, pa); - crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio); - crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio); - crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio); - crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio); + __crisv32_pinmux_alloc(PORT_B, 0, PORT_PINS - 1, pinmux_gpio); + __crisv32_pinmux_alloc(PORT_C, 0, PORT_PINS - 1, pinmux_gpio); + __crisv32_pinmux_alloc(PORT_D, 0, PORT_PINS - 1, pinmux_gpio); + __crisv32_pinmux_alloc(PORT_E, 0, PORT_PINS - 1, pinmux_gpio); } return 0; } -int -crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) +int crisv32_pinmux_alloc(int port, int first_pin, int last_pin, + enum pin_mode mode) { - int i; unsigned long flags; + int ret; crisv32_pinmux_init(); @@ -59,26 +81,11 @@ crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode mode) spin_lock_irqsave(&pinmux_lock, flags); - for (i = first_pin; i <= last_pin; i++) { - if ((pins[port][i] != pinmux_none) - && (pins[port][i] != pinmux_gpio) - && (pins[port][i] != mode)) { - spin_unlock_irqrestore(&pinmux_lock, flags); -#ifdef DEBUG - panic("Pinmux alloc failed!\n"); -#endif - return -EPERM; - } - } - - for (i = first_pin; i <= last_pin; i++) - pins[port][i] = mode; - - crisv32_pinmux_set(port); + ret = __crisv32_pinmux_alloc(port, first_pin, last_pin, mode); spin_unlock_irqrestore(&pinmux_lock, flags); - return 0; + return ret; } int crisv32_pinmux_alloc_fixed(enum fixed_function function) @@ -98,58 +105,58 @@ int crisv32_pinmux_alloc_fixed(enum fixed_function function) switch (function) { case pinmux_ser1: - ret = crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_C, 4, 7, pinmux_fixed); hwprot.ser1 = regk_pinmux_yes; break; case pinmux_ser2: - ret = crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_C, 8, 11, pinmux_fixed); hwprot.ser2 = regk_pinmux_yes; break; case pinmux_ser3: - ret = crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_C, 12, 15, pinmux_fixed); hwprot.ser3 = regk_pinmux_yes; break; case pinmux_sser0: - ret = crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_C, 0, 3, pinmux_fixed); + ret |= __crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); hwprot.sser0 = regk_pinmux_yes; break; case pinmux_sser1: - ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); hwprot.sser1 = regk_pinmux_yes; break; case pinmux_ata0: - ret = crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_D, 5, 7, pinmux_fixed); + ret |= __crisv32_pinmux_alloc(PORT_D, 15, 17, pinmux_fixed); hwprot.ata0 = regk_pinmux_yes; break; case pinmux_ata1: - ret = crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_D, 0, 4, pinmux_fixed); + ret |= __crisv32_pinmux_alloc(PORT_E, 17, 17, pinmux_fixed); hwprot.ata1 = regk_pinmux_yes; break; case pinmux_ata2: - ret = crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_C, 11, 15, pinmux_fixed); + ret |= __crisv32_pinmux_alloc(PORT_E, 3, 3, pinmux_fixed); hwprot.ata2 = regk_pinmux_yes; break; case pinmux_ata3: - ret = crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_C, 8, 10, pinmux_fixed); + ret |= __crisv32_pinmux_alloc(PORT_C, 0, 2, pinmux_fixed); hwprot.ata2 = regk_pinmux_yes; break; case pinmux_ata: - ret = crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed); - ret |= crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_B, 0, 15, pinmux_fixed); + ret |= __crisv32_pinmux_alloc(PORT_D, 8, 15, pinmux_fixed); hwprot.ata = regk_pinmux_yes; break; case pinmux_eth1: - ret = crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_E, 0, 17, pinmux_fixed); hwprot.eth1 = regk_pinmux_yes; hwprot.eth1_mgm = regk_pinmux_yes; break; case pinmux_timer: - ret = crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); + ret = __crisv32_pinmux_alloc(PORT_C, 16, 16, pinmux_fixed); hwprot.timer = regk_pinmux_yes; spin_unlock_irqrestore(&pinmux_lock, flags); return ret; @@ -188,9 +195,19 @@ void crisv32_pinmux_set(int port) #endif } -int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) +static int __crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) { int i; + + for (i = first_pin; i <= last_pin; i++) + pins[port][i] = pinmux_none; + + crisv32_pinmux_set(port); + return 0; +} + +int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) +{ unsigned long flags; crisv32_pinmux_init(); @@ -199,11 +216,7 @@ int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin) return -EINVAL; spin_lock_irqsave(&pinmux_lock, flags); - - for (i = first_pin; i <= last_pin; i++) - pins[port][i] = pinmux_none; - - crisv32_pinmux_set(port); + __crisv32_pinmux_dealloc(port, first_pin, last_pin); spin_unlock_irqrestore(&pinmux_lock, flags); return 0; @@ -226,58 +239,58 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function) switch (function) { case pinmux_ser1: - ret = crisv32_pinmux_dealloc(PORT_C, 4, 7); + ret = __crisv32_pinmux_dealloc(PORT_C, 4, 7); hwprot.ser1 = regk_pinmux_no; break; case pinmux_ser2: - ret = crisv32_pinmux_dealloc(PORT_C, 8, 11); + ret = __crisv32_pinmux_dealloc(PORT_C, 8, 11); hwprot.ser2 = regk_pinmux_no; break; case pinmux_ser3: - ret = crisv32_pinmux_dealloc(PORT_C, 12, 15); + ret = __crisv32_pinmux_dealloc(PORT_C, 12, 15); hwprot.ser3 = regk_pinmux_no; break; case pinmux_sser0: - ret = crisv32_pinmux_dealloc(PORT_C, 0, 3); - ret |= crisv32_pinmux_dealloc(PORT_C, 16, 16); + ret = __crisv32_pinmux_dealloc(PORT_C, 0, 3); + ret |= __crisv32_pinmux_dealloc(PORT_C, 16, 16); hwprot.sser0 = regk_pinmux_no; break; case pinmux_sser1: - ret = crisv32_pinmux_dealloc(PORT_D, 0, 4); + ret = __crisv32_pinmux_dealloc(PORT_D, 0, 4); hwprot.sser1 = regk_pinmux_no; break; case pinmux_ata0: - ret = crisv32_pinmux_dealloc(PORT_D, 5, 7); - ret |= crisv32_pinmux_dealloc(PORT_D, 15, 17); + ret = __crisv32_pinmux_dealloc(PORT_D, 5, 7); + ret |= __crisv32_pinmux_dealloc(PORT_D, 15, 17); hwprot.ata0 = regk_pinmux_no; break; case pinmux_ata1: - ret = crisv32_pinmux_dealloc(PORT_D, 0, 4); - ret |= crisv32_pinmux_dealloc(PORT_E, 17, 17); + ret = __crisv32_pinmux_dealloc(PORT_D, 0, 4); + ret |= __crisv32_pinmux_dealloc(PORT_E, 17, 17); hwprot.ata1 = regk_pinmux_no; break; case pinmux_ata2: - ret = crisv32_pinmux_dealloc(PORT_C, 11, 15); - ret |= crisv32_pinmux_dealloc(PORT_E, 3, 3); + ret = __crisv32_pinmux_dealloc(PORT_C, 11, 15); + ret |= __crisv32_pinmux_dealloc(PORT_E, 3, 3); hwprot.ata2 = regk_pinmux_no; break; case pinmux_ata3: - ret = crisv32_pinmux_dealloc(PORT_C, 8, 10); - ret |= crisv32_pinmux_dealloc(PORT_C, 0, 2); + ret = __crisv32_pinmux_dealloc(PORT_C, 8, 10); + ret |= __crisv32_pinmux_dealloc(PORT_C, 0, 2); hwprot.ata2 = regk_pinmux_no; break; case pinmux_ata: - ret = crisv32_pinmux_dealloc(PORT_B, 0, 15); - ret |= crisv32_pinmux_dealloc(PORT_D, 8, 15); + ret = __crisv32_pinmux_dealloc(PORT_B, 0, 15); + ret |= __crisv32_pinmux_dealloc(PORT_D, 8, 15); hwprot.ata = regk_pinmux_no; break; case pinmux_eth1: - ret = crisv32_pinmux_dealloc(PORT_E, 0, 17); + ret = __crisv32_pinmux_dealloc(PORT_E, 0, 17); hwprot.eth1 = regk_pinmux_no; hwprot.eth1_mgm = regk_pinmux_no; break; case pinmux_timer: - ret = crisv32_pinmux_dealloc(PORT_C, 16, 16); + ret = __crisv32_pinmux_dealloc(PORT_C, 16, 16); hwprot.timer = regk_pinmux_no; spin_unlock_irqrestore(&pinmux_lock, flags); return ret; @@ -293,7 +306,8 @@ int crisv32_pinmux_dealloc_fixed(enum fixed_function function) return ret; } -void crisv32_pinmux_dump(void) +#ifdef DEBUG +static void crisv32_pinmux_dump(void) { int i, j; @@ -305,5 +319,5 @@ void crisv32_pinmux_dump(void) printk(KERN_DEBUG " Pin %d = %d\n", j, pins[i][j]); } } - +#endif __initcall(crisv32_pinmux_init); diff --git a/arch/cris/include/arch-v32/mach-fs/mach/pinmux.h b/arch/cris/include/arch-v32/mach-fs/mach/pinmux.h index c2b3036779df..09bf0c90d2d3 100644 --- a/arch/cris/include/arch-v32/mach-fs/mach/pinmux.h +++ b/arch/cris/include/arch-v32/mach-fs/mach/pinmux.h @@ -28,11 +28,9 @@ enum fixed_function { pinmux_timer }; -int crisv32_pinmux_init(void); int crisv32_pinmux_alloc(int port, int first_pin, int last_pin, enum pin_mode); int crisv32_pinmux_alloc_fixed(enum fixed_function function); int crisv32_pinmux_dealloc(int port, int first_pin, int last_pin); int crisv32_pinmux_dealloc_fixed(enum fixed_function function); -void crisv32_pinmux_dump(void); #endif -- cgit v1.2.3-59-g8ed1b From 8bcabff0589c1ef8fec9f98d525943217ae10971 Mon Sep 17 00:00:00 2001 From: Jesper Nilsson Date: Wed, 29 Oct 2014 10:15:35 +0100 Subject: CRISv32: Remove last remnants of ETRAX_SPI_MMC_BOARD There are no users of this symbol left. Reported-by: Paul Bolle Signed-off-by: Jesper Nilsson --- arch/cris/arch-v32/drivers/Kconfig | 7 ------- 1 file changed, 7 deletions(-) (limited to 'arch') diff --git a/arch/cris/arch-v32/drivers/Kconfig b/arch/cris/arch-v32/drivers/Kconfig index 28e259de9df9..4fc16b44fff2 100644 --- a/arch/cris/arch-v32/drivers/Kconfig +++ b/arch/cris/arch-v32/drivers/Kconfig @@ -359,13 +359,6 @@ config ETRAX_SPI_MMC default MMC select SPI select MMC_SPI - select ETRAX_SPI_MMC_BOARD - -# For the parts that can't be a module (due to restrictions in -# framework elsewhere). -config ETRAX_SPI_MMC_BOARD - boolean - default n # While the board info is MMC_SPI only, the drivers are written to be # independent of MMC_SPI, so we'll keep SPI non-dependent on the -- cgit v1.2.3-59-g8ed1b