From cd82ceb1fda11f12accce81db7dac059fbe42772 Mon Sep 17 00:00:00 2001 From: Ben Shelton Date: Tue, 1 Apr 2014 11:31:31 -0500 Subject: [PATCH 01/83] shared: Adding mcopy syscall for x64 Signed-off-by: Ben Shelton Acked-by: Scot Salmon Acked-by: Terry Wilcox Natinst-ReviewBoard-ID: 69848 [gratian: convert to new syscall table format for arm] Signed-off-by: Gratian Crisan [bstreiff: update the number for this painful out-of-tree syscall] Signed-off-by: Brandon Streiff [gratian: update due to new syscall introduced by ecb8ac8b1f14 ("mm/madvise: introduce process_madvise() syscall: an external memory hinting AP")] Signed-off-by: Gratian Crisan [gratian: update syscall numbers to account for upstream additions; dropped arm bits] Signed-off-by: Gratian Crisan [gratian: bump syscall number to account for upstream process_mrelease addition] Signed-off-by: Gratian Crisan [gratian: bump syscall number to account for upstream 'futex_waitv' and 'set_mempolicy_home_node' additions] Signed-off-by: Gratian Crisan [mpeterse: bump syscall number to account for upstream 'cachestat', 'fchmodat2', and 'map_shadow_stack' additions] [mpeterse: remove comments in syscalls.h referring to the function's source file] Signed-off-by: Mike Petersen [cvadrevu: bump syscall number to account for upstream additions] Signed-off-by: Chaitanya Vadrevu --- arch/x86/entry/syscalls/syscall_64.tbl | 1 + include/linux/syscalls.h | 2 ++ include/uapi/asm-generic/unistd.h | 5 +++- kernel/ksysfs.c | 14 +++++++++++ mm/maccess.c | 32 ++++++++++++++++++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 7093ee21c0d1c..746010ecfb6ac 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -386,6 +386,7 @@ 460 common lsm_set_self_attr sys_lsm_set_self_attr 461 common lsm_list_modules sys_lsm_list_modules 462 common mseal sys_mseal +463 common mcopy sys_mcopy # # Due to a historical design error, certain syscalls are numbered differently diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 5758104921e66..40268ceeb9f83 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -802,6 +802,8 @@ asmlinkage long sys_execve(const char __user *filename, const char __user *const __user *envp); asmlinkage long sys_fadvise64_64(int fd, loff_t offset, loff_t len, int advice); +asmlinkage long sys_mcopy(void * __user dest, void * __user src, size_t len); + /* CONFIG_MMU only */ asmlinkage long sys_swapon(const char __user *specialfile, int swap_flags); asmlinkage long sys_swapoff(const char __user *specialfile); diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 5bf6148cac2b9..e0b08caffc866 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -841,8 +841,11 @@ __SYSCALL(__NR_lsm_list_modules, sys_lsm_list_modules) #define __NR_mseal 462 __SYSCALL(__NR_mseal, sys_mseal) +#define __NR_mcopy 463 +__SYSCALL(__NR_mcopy, sys_mcopy) + #undef __NR_syscalls -#define __NR_syscalls 463 +#define __NR_syscalls 464 /* * 32 bit systems traditionally used different diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 8d3bee77cacc6..8eb16dc4dd7cd 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -18,6 +18,7 @@ #include #include #include +#include #include /* rcu_expedited and rcu_normal */ @@ -205,6 +206,16 @@ static ssize_t fscaps_show(struct kobject *kobj, } KERNEL_ATTR_RO(fscaps); +#ifdef __NR_mcopy +static ssize_t ni_syscall_mcopy_show(struct kobject *kobj, + struct kobj_attribute *attr, + char *buf) +{ + return sprintf(buf, "%d\n", __NR_mcopy); +} +KERNEL_ATTR_RO(ni_syscall_mcopy); +#endif + #ifndef CONFIG_TINY_RCU int rcu_expedited; static ssize_t rcu_expedited_show(struct kobject *kobj, @@ -297,6 +308,9 @@ static struct attribute * kernel_attrs[] = { #endif #ifdef CONFIG_PREEMPT_RT &realtime_attr.attr, +#endif +#ifdef __NR_mcopy + &ni_syscall_mcopy_attr.attr, #endif NULL }; diff --git a/mm/maccess.c b/mm/maccess.c index 518a25667323e..6410af8f476fa 100644 --- a/mm/maccess.c +++ b/mm/maccess.c @@ -5,6 +5,7 @@ #include #include #include +#include #include bool __weak copy_from_kernel_nofault_allowed(const void *unsafe_src, @@ -228,3 +229,34 @@ void __copy_overflow(int size, unsigned long count) WARN(1, "Buffer overflow detected (%d < %lu)!\n", size, count); } EXPORT_SYMBOL(__copy_overflow); + +/* + * Safely copy 'len' bytes from user space 'src' to user space 'dst'. + * 'len' must be less than or equal to 64. In particular, safely here + * means that if we are trying to copy memory that has been freed and + * unmapped we don't crash. + * + * Returns + * 0 copy completed successfully + * + * EFAULT if either the source or destination blocks are not + * valid + * + * EINVAL len is greater than 64 + * + */ +SYSCALL_DEFINE3(mcopy, void*, dst, void*, src, size_t, len) +{ + char buf[64]; + + if (len > 64) + return -EINVAL; + + if (copy_from_user(buf, src, len)) + return -EFAULT; + + if (copy_to_user(dst, buf, len)) + return -EFAULT; + + return 0; +} From 87534e4e95400a9c6f4c0353602fb0bf9c285105 Mon Sep 17 00:00:00 2001 From: Terry Wilcox Date: Mon, 19 May 2014 15:28:03 -0500 Subject: [PATCH 02/83] kernel: Providing API to allow userland programs to request a cold or warm reboot Another group is requesting that we provide an API to allow them to signal that the next reboot should be "cold". They need this to guarantee that the FPGA will not be running and cause the system to reboot at a bad time. This change creates a RW file at /sys/kernel/ni_requested_reboot_type. The default value is 0. - If when we reboot the value is 0 then we do the normal reset behavior. - If the value is 1 we attempt to do a PCI reboot (using the CF9 register) and fall back to the normal reboot method if that fails. - If the value is 2 we attempt to do an ACPI reboot and fall back to the normal reboot method if that fails. We selected a reboot using the CF9 register over attempting to do an EFI reboot because we don't have much time to test this feature and we've found EFI features to be fairly buggy. For next release the plan is to do an EFI cold reboot, but put it in early enough to properly test it. Rebooting using the CF9 register should work on all x64 hardware that we will support for 2014 (smasher and hammerhead). Signed-off-by: Terry Wilcox Acked-by: Brad Mouring Natinst-ReviewBoard-ID: 68018 --- arch/x86/kernel/reboot.c | 49 ++++++++++++++++++++++++++++++++-------- kernel/ksysfs.c | 18 +++++++++++++++ 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index dc1dd3f3e67fc..631ee3a99739c 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c @@ -39,6 +39,14 @@ void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); +enum requested_reboot_type { + REQUEST_DEFAULT_REBOOT, + REQUEST_COLD_REBOOT, + REQUEST_WARM_REBOOT +}; + +enum requested_reboot_type requested_reboot_type = REQUEST_DEFAULT_REBOOT; + /* * This is set if we need to go through the 'emergency' path. * When machine_emergency_restart() is called, we may be on @@ -606,6 +614,21 @@ void __attribute__((weak)) mach_reboot_fixups(void) { } +static void native_machine_restart_cf9(void) +{ + if (port_cf9_safe) { + u8 reboot_code = reboot_mode == REBOOT_WARM ? 0x06 : 0x0E; + u8 cf9 = inb(0xcf9) & ~reboot_code; + + outb(cf9|2, 0xcf9); /* Request hard reset */ + udelay(50); + /* Actually do the reset */ + outb(cf9|reboot_code, 0xcf9); + udelay(50); + } +} + + /* * To the best of our knowledge Windows compatible x86 hardware expects * the following on reboot: @@ -637,6 +660,22 @@ static void native_machine_emergency_restart(void) tboot_shutdown(TB_SHUTDOWN_REBOOT); + + switch (requested_reboot_type) { + case REQUEST_COLD_REBOOT: + port_cf9_safe = true; + native_machine_restart_cf9(); + break; + + case REQUEST_WARM_REBOOT: + acpi_reboot(); + break; + + case REQUEST_DEFAULT_REBOOT: + default: + break; + } + /* Tell the BIOS if we want cold or warm reboot */ mode = reboot_mode == REBOOT_WARM ? 0x1234 : 0; *((unsigned short *)__va(0x472)) = mode; @@ -692,15 +731,7 @@ static void native_machine_emergency_restart(void) fallthrough; case BOOT_CF9_SAFE: - if (port_cf9_safe) { - u8 reboot_code = reboot_mode == REBOOT_WARM ? 0x06 : 0x0E; - u8 cf9 = inb(0xcf9) & ~reboot_code; - outb(cf9|2, 0xcf9); /* Request hard reset */ - udelay(50); - /* Actually do the reset */ - outb(cf9|reboot_code, 0xcf9); - udelay(50); - } + native_machine_restart_cf9(); reboot_type = BOOT_TRIPLE; break; diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index 8eb16dc4dd7cd..a12d04e20fb9d 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -252,6 +252,23 @@ static ssize_t rcu_normal_store(struct kobject *kobj, KERNEL_ATTR_RW(rcu_normal); #endif /* #ifndef CONFIG_TINY_RCU */ +extern int requested_reboot_type; +static ssize_t ni_requested_reboot_type_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", requested_reboot_type); +} +static ssize_t ni_requested_reboot_type_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count) +{ + if (kstrtoint(buf, 0, &requested_reboot_type)) + return -EINVAL; + + return count; +} +KERNEL_ATTR_RW(ni_requested_reboot_type); + /* * Make /sys/kernel/notes give the raw contents of our kernel .notes section. */ @@ -312,6 +329,7 @@ static struct attribute * kernel_attrs[] = { #ifdef __NR_mcopy &ni_syscall_mcopy_attr.attr, #endif + &ni_requested_reboot_type_attr.attr, NULL }; From ef924dd1b07a1eb2f758760404d6d00a5ad78a18 Mon Sep 17 00:00:00 2001 From: Ben Shelton Date: Tue, 10 Jun 2014 15:04:11 -0500 Subject: [PATCH 03/83] kernel: Add config option to specify NI cold boot support Currently, we provide NI cold boot support on x64 targets. However, at some future point, we may wish to provide this support on other targets as well. Adding a config option to specify that a target supports NI cold boot functionality; this fixes the build for Zynq targets and doesn't paint us into a corner later. Signed-off-by: Ben Shelton [gratian: fix trivial conflict with ceea991a019c ("bpf: Move bpf_dispatcher function out of ftrace locations")] Signed-off-by: Gratian Crisan --- arch/x86/Kconfig | 4 ++++ kernel/ksysfs.c | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index e9245082ff151..ffbf8fbfb56c2 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -319,6 +319,10 @@ config X86 select FUNCTION_ALIGNMENT_4B imply IMA_SECURE_AND_OR_TRUSTED_BOOT if EFI select HAVE_DYNAMIC_FTRACE_NO_PATCHABLE + select NI_COLD_BOOT_SUPPORT + +config NI_COLD_BOOT_SUPPORT + def_bool n config INSTRUCTION_DECODER def_bool y diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index a12d04e20fb9d..865872c60f367 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c @@ -252,6 +252,7 @@ static ssize_t rcu_normal_store(struct kobject *kobj, KERNEL_ATTR_RW(rcu_normal); #endif /* #ifndef CONFIG_TINY_RCU */ +#ifdef CONFIG_NI_COLD_BOOT_SUPPORT extern int requested_reboot_type; static ssize_t ni_requested_reboot_type_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf) @@ -268,6 +269,7 @@ static ssize_t ni_requested_reboot_type_store(struct kobject *kobj, return count; } KERNEL_ATTR_RW(ni_requested_reboot_type); +#endif /* * Make /sys/kernel/notes give the raw contents of our kernel .notes section. @@ -329,7 +331,9 @@ static struct attribute * kernel_attrs[] = { #ifdef __NR_mcopy &ni_syscall_mcopy_attr.attr, #endif +#ifdef CONFIG_NI_COLD_BOOT_SUPPORT &ni_requested_reboot_type_attr.attr, +#endif NULL }; From 11938e770b3750c2820e789fc68ddd7cdcf67c35 Mon Sep 17 00:00:00 2001 From: Haris Okanovic Date: Fri, 25 Sep 2015 11:34:42 -0500 Subject: [PATCH 04/83] proc/interrupts: Add polling Implement polling on procfs' "interrupts" file which observes changes to IRQ action handlers. The poll fires each time an action handler is registered or unregistered. This change enables daemons to watch for changes and apply certain system policies relating to IRQ processing. For example, modify execution priority of dedicated IRQ tasks after they're created. include/linux/interrupt.h kernel/irq/manage.c Add change counter for handler registrations and a wait queue to notify tasks on updates. fs/proc/interrupts.c Add polling callback on aforementioned counter and wait queue. Signed-off-by: Haris Okanovic Signed-off-by: Ovidiu-Adrian Vancea Signed-off-by: Brad Mouring Natinst-ReviewBoard-ID: 111860, 163902 [gratian: fixed small rebase conflict] Signed-off-by: Gratian Crisan [bstreiff: un-trivialize from changes in fddda2b7b521 ("proc: introduce proc_create_seq{,_data}") and convert file_operations to proc_ops] Signed-off-by: Brandon Streiff --- fs/proc/interrupts.c | 74 ++++++++++++++++++++++++++++++++++++++- include/linux/interrupt.h | 3 ++ kernel/irq/manage.c | 18 ++++++++++ 3 files changed, 94 insertions(+), 1 deletion(-) diff --git a/fs/proc/interrupts.c b/fs/proc/interrupts.c index cb0edc7cbf092..624eb74af1e3c 100644 --- a/fs/proc/interrupts.c +++ b/fs/proc/interrupts.c @@ -1,10 +1,12 @@ // SPDX-License-Identifier: GPL-2.0 #include +#include #include #include #include #include #include +#include /* * /proc/interrupts @@ -34,9 +36,79 @@ static const struct seq_operations int_seq_ops = { .show = show_interrupts }; +struct interrupts_fd_state { + atomic_long_t last_irq_change_count; +}; + +static int interrupts_open(struct inode *inode, struct file *filp) +{ + int res; + struct interrupts_fd_state *privdata; + struct seq_file *sf; + + privdata = kzalloc(sizeof(struct interrupts_fd_state), GFP_KERNEL); + if (!privdata) { + res = -ENOMEM; + goto exit; + } + + res = seq_open(filp, &int_seq_ops); + if (res) { + kfree(privdata); + goto exit; + } + + sf = filp->private_data; + sf->private = privdata; + + atomic_long_set(&(privdata->last_irq_change_count), + get_irq_handler_change_count()); + +exit: + return res; +} + +static int interrupts_release(struct inode *inode, struct file *filp) +{ + struct seq_file *sf = filp->private_data; + + kfree(sf->private); + return seq_release(inode, filp); +} + +static unsigned int interrupts_poll(struct file *filp, + struct poll_table_struct *pt) +{ + unsigned int mask = POLLIN | POLLRDNORM; + long newcount, oldcount; + struct seq_file *sf = filp->private_data; + struct interrupts_fd_state *fds = sf->private; + + /* Register for changes to IRQ handlers */ + poll_wait(filp, &irq_handler_change_wq, pt); + + /* Store new change count in priv data */ + newcount = get_irq_handler_change_count(); + oldcount = atomic_long_xchg( + &(fds->last_irq_change_count), newcount); + + if (newcount != oldcount) + mask |= POLLERR | POLLPRI; + + return mask; +} + +static const struct proc_ops interrupts_proc_ops = { + .proc_open = interrupts_open, + .proc_read = seq_read, + .proc_poll = interrupts_poll, + .proc_lseek = seq_lseek, + .proc_release = interrupts_release, +}; + static int __init proc_interrupts_init(void) { - proc_create_seq("interrupts", 0, NULL, &int_seq_ops); + proc_create("interrupts", 0, NULL, &interrupts_proc_ops); return 0; } fs_initcall(proc_interrupts_init); diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 9637af78087f3..171d82ecf656f 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -877,6 +877,9 @@ extern int early_irq_init(void); extern int arch_probe_nr_irqs(void); extern int arch_early_irq_init(void); +extern long get_irq_handler_change_count(void); +extern wait_queue_head_t irq_handler_change_wq; + /* * We want to know which function is an entrypoint of a hardirq or a softirq. */ diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index f0803d6bd2969..f5a6ffcbb6535 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -35,6 +35,22 @@ static int __init setup_forced_irqthreads(char *arg) early_param("threadirqs", setup_forced_irqthreads); #endif +static atomic_long_t irq_handler_change_count = ATOMIC_LONG_INIT(0); +DECLARE_WAIT_QUEUE_HEAD(irq_handler_change_wq); + +/* Bump change count and wake up anything waiting on changes to + * IRQ handlers */ +static void __irq_handler_change_event(void) +{ + atomic_long_inc(&irq_handler_change_count); + wake_up(&irq_handler_change_wq); +} + +long get_irq_handler_change_count(void) +{ + return atomic_long_read(&irq_handler_change_count); +} + static void __synchronize_hardirq(struct irq_desc *desc, bool sync_chip) { struct irq_data *irqd = irq_desc_get_irq_data(desc); @@ -1833,6 +1849,7 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new) register_irq_proc(irq, desc); new->dir = NULL; register_handler_proc(irq, new); + __irq_handler_change_event(); return 0; mismatch: @@ -2006,6 +2023,7 @@ static struct irqaction *__free_irq(struct irq_desc *desc, void *dev_id) irq_chip_pm_put(&desc->irq_data); module_put(desc->owner); kfree(action->secondary); + __irq_handler_change_event(); return action; } From 8785c1572e7736ec09d0fbfa6c2d5f7b49dce5ae Mon Sep 17 00:00:00 2001 From: Richard Tollerton Date: Wed, 4 Apr 2012 20:13:05 -0400 Subject: [PATCH 05/83] ftrace: ni: add raw marker support for trace tool Signed-off-by: Richard Tollerton [gratian: fix conflict with fa32e8557b47 ("tracing: Add new trace_marker_raw"); rename NI specific implementation until we can replace it] Signed-off-by: Gratian Crisan [bstreiff: fixups due to struct member renames in 13292494379f ("tracing: Make struct ring_buffer less ambiguous")] Signed-off-by: Brandon Streiff [gratian: update for 22c36b182634 ("tracing: make tracing_init_dentry() returns an integer instead of a d_entry pointer")] Signed-off-by: Gratian Crisan [gratian: fixups due to tracing contex introduction in edbaaa13a660 ("tracing: Merge irqflags + preemt counter, add RT bits")] Signed-off-by: Gratian Crisan [gratian: fixups due to tracing_gen_ctx_flags() API change in 8cac5dbf18c7 ("tracing: Merge irqflags + preemt counter, add RT bits")] Signed-off-by: Gratian Crisan [gratian: use always_inlined __trace_buffer_lock_reserve() introduced by 3e9a8aadca48 ("tracing: Create a always_inlined __trace_buffer_lock_reserve()")] Signed-off-by: Gratian Crisan --- kernel/trace/trace.c | 92 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 1443eb33ff21d..2229d6a5b117a 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -7095,6 +7095,89 @@ tracing_mark_raw_write(struct file *filp, const char __user *ubuf, return written; } +/* + * rtollert: tracing_ni_ett_raw_write exists as part of LabVIEW RT's support of + * the Execution Trace Toolkit. LabVIEW RT logs its own events through this + * interface, so that they are stored in ftrace's ring buffers. Basically + * tracing_ni_ett_raw_write is the same as tracing_mark_write, except all the + * text processing code is ripped out for improved performance. + * + * These events will show up as BPRINT ftrace events, with ip and fmt set to + * the fourcc 'lvrt'. The event data is generally a binary blob that is + * processed later by LabVIEW RT (and ultimately the ETT). That data is not + * meant to be parsed by third parties and is not documented (sorry). + * + * I'm a little embarrassed of this implementation, so this code goes out of + * its way to scream "HACK!": The hardcoded settings for ip and fmt; the + * name of the marker file (trace_ni_ett_marker), etc. + * + * Eventually I'd like to see a solution which would allow multiple programs + * to each write to their own marker files, with dynamically allocated IDs, + * without overloading BPRINT events, etc. However a lot of that is contingent + * on if it's even a good idea to allow binary blobs to be logged to ftrace. + * (a worthwhile discussion!) + */ +static ssize_t +tracing_ni_ett_raw_write(struct file *filp, const char __user *ubuf, + size_t cnt, loff_t *fpos) +{ + struct trace_event_call *call = &event_bprint; + struct ring_buffer_event *event; + struct trace_array *tr = &global_trace; + struct trace_buffer *buffer = tr->array_buffer.buffer; + struct trace_array_cpu *data; + int cpu, size; + unsigned int trace_ctx; + struct bprint_entry *entry; + unsigned long irq_flags; + int disable; + + const unsigned int ip = 0x6c767274; /* "lvrt" */ + const char *fmt = "lvrt"; /* to avoid dereferencing NULL */ + + if (tracing_disabled || tracing_selftest_running) + return -EINVAL; + + preempt_disable_notrace(); + cpu = raw_smp_processor_id(); + data = per_cpu_ptr(tr->array_buffer.data, cpu); + disable = atomic_inc_return(&data->disabled); + if (unlikely(disable != 1)) + goto out; + pause_graph_tracing(); + raw_local_irq_save(irq_flags); + + trace_ctx = tracing_gen_ctx_flags(irq_flags); + size = sizeof(*entry) + cnt; + event = __trace_buffer_lock_reserve(buffer, TRACE_BPRINT, size, + trace_ctx); + if (!event) + goto out_unlock; + entry = ring_buffer_event_data(event); + entry->ip = ip; + entry->fmt = fmt; + + if (cnt) { + if (copy_from_user(&(entry->buf[0]), ubuf, cnt)) { + cnt = -EFAULT; + goto error_and_trace; + } + } + if (call_filter_check_discard(call, entry, buffer, event)) + goto out_unlock; + error_and_trace: + __buffer_unlock_commit(buffer, event); + ftrace_trace_stack(&global_trace, buffer, trace_ctx, 6, NULL); + out_unlock: + raw_local_irq_restore(irq_flags); + unpause_graph_tracing(); + out: + atomic_dec_return(&data->disabled); + preempt_enable_notrace(); + + return cnt; +} + static int tracing_clock_show(struct seq_file *m, void *v) { struct trace_array *tr = m->private; @@ -7522,6 +7605,12 @@ static const struct file_operations tracing_mark_raw_fops = { .release = tracing_release_generic_tr, }; +static const struct file_operations tracing_ni_ett_raw_fops = { + .open = tracing_open_generic, + .write = tracing_ni_ett_raw_write, + .llseek = generic_file_llseek, +}; + static const struct file_operations trace_clock_fops = { .open = tracing_clock_open, .read = seq_read, @@ -10008,6 +10097,9 @@ static __init void tracer_init_tracefs_work_func(struct work_struct *work) trace_create_file("README", TRACE_MODE_READ, NULL, NULL, &tracing_readme_fops); + trace_create_file("trace_ni_ett_marker", 0220, NULL, + NULL, &tracing_ni_ett_raw_fops); + trace_create_file("saved_cmdlines", TRACE_MODE_READ, NULL, NULL, &tracing_saved_cmdlines_fops); From 483b642b012f9a802cfbf833a201de45de1d5cec Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Thu, 24 Mar 2016 13:52:00 -0500 Subject: [PATCH 06/83] time: Make the clocksource watchdog user configurable The clocksource watchdog is used to detect instabilities in the current clocksource. This is a beneficial feature on new/unknown hardware however it can create problems by falsely triggering when the watchdog wraps. The reason is that an interrupt storm and/or high priority (FIFO/RR) tasks can preempt the timer softirq long enough for the watchdog to wrap if it has a limited number of bits available by comparison with the main clocksource. One observed example is on a Intel Baytrail platform where TSC is the main clocksource, HPET is disabled due to a hardware bug and acpi_pm gets selected as the watchdog clocksource. Provide the option to disable the clocksource watchdog for hardware where the clocksource stability has been validated. Signed-off-by: Gratian Crisan [gratian: fix trivial conflict with fc153c1c58cb ("clocksource: Add a Kconfig option for WATCHDOG_MAX_SKEW")] Signed-off-by: Gratian Crisan [gratian: fix trivial conflict with 7cf8f44a5a1c ("x86: fs: kmsan: disable CONFIG_DCACHE_WORD_ACCESS")] Signed-off-by: Gratian Crisan [cvadrevu: fix trivial conflict with e26cbab9821a ("timekeeping: Always check for negative motion")] Signed-off-by: Chaitanya Vadrevu --- arch/x86/Kconfig | 2 +- kernel/time/Kconfig | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index ffbf8fbfb56c2..95744a4165589 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -146,7 +146,7 @@ config X86 select ARCH_HAS_PARANOID_L1D_FLUSH select BUILDTIME_TABLE_SORT select CLKEVT_I8253 - select CLOCKSOURCE_WATCHDOG + select HAVE_CLOCKSOURCE_WATCHDOG # Word-size accesses may read uninitialized data past the trailing \0 # in strings and cause false KMSAN reports. select DCACHE_WORD_ACCESS if !KMSAN diff --git a/kernel/time/Kconfig b/kernel/time/Kconfig index b0b97a60aaa6f..ae1df5e8c8d57 100644 --- a/kernel/time/Kconfig +++ b/kernel/time/Kconfig @@ -6,7 +6,7 @@ # Options selectable by arch Kconfig # Watchdog function for clocksources to detect instabilities -config CLOCKSOURCE_WATCHDOG +config HAVE_CLOCKSOURCE_WATCHDOG bool # Architecture has extra clocksource data @@ -209,5 +209,15 @@ config CLOCKSOURCE_WATCHDOG_MAX_SKEW_US per million. If the clocksource is good enough for NTP, it is good enough for the clocksource watchdog! +config CLOCKSOURCE_WATCHDOG + bool "Clocksource watchdog" + depends on HAVE_CLOCKSOURCE_WATCHDOG + default y + help + This option enables the watchdog function for clocksources. It is + used to detect instabilities in the currently selected clocksource. + + Say Y if you are unsure. + endmenu endif From 2e7e62b460e5a42e332915323e074ff83f9399c2 Mon Sep 17 00:00:00 2001 From: Brad Mouring Date: Wed, 1 Mar 2017 13:43:12 -0600 Subject: [PATCH 07/83] Revert "time: Always make sure wall_to_monotonic isn't positive" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit e1d7ba8735551ed79c7a0463a042353574b96da3. NI has a use case that involves distributed networked Linux devices that need to share the same concept of time using a mechanism like IEEE-1588 or 802.1AS. The “master” device (ie. the device with the time all other devices will be synchronized to) is often a device that boots up set to the Posix Epoch, mainly because it lacks a battery-backed RTC. (note: the existence of an RTC does not prevent a device from booting up at or very near the Posix Epoch, it just greatly reduces the likelihood). If a slave device attempted to synchronize its CLOCK_REALTIME to that of the master – and the master’s time was < Epoch+slave uptime, that slave would not be able to synchronize. This use case is believed to be very common among embedded devices, especially those without RTCs. Long term: We (NI Timing & Sync) are planning on engaging with the upstream community to educate them on our use case and hopefully put a different solution in place which solves the original problem (preventing a negative boot time representation) while also allowing our use case to continue working as it did prior to the change we’re reverting. Once that happens, we can drop this revert. Signed-off-by: Brad Mouring Reported-by: Vineeth Acharya Tested-by: Rick Ratzel Natinst-CAR-ID: 629499 [bstreiff: reduced control flow in do_settimeofday64 due to unassigned 'ret'] Signed-off-by: Brandon Streiff [gratian: fix conflict with b8ac29b40183 ("timekeeping: contribute wall clock to rng on time change")] Signed-off-by: Gratian Crisan --- kernel/time/timekeeping.c | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index 96933082431fe..fecc292594b4b 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -1345,7 +1345,6 @@ int do_settimeofday64(const struct timespec64 *ts) struct timekeeper *tk = &tk_core.timekeeper; struct timespec64 ts_delta, xt; unsigned long flags; - int ret = 0; if (!timespec64_valid_settod(ts)) return -EINVAL; @@ -1358,15 +1357,10 @@ int do_settimeofday64(const struct timespec64 *ts) xt = tk_xtime(tk); ts_delta = timespec64_sub(*ts, xt); - if (timespec64_compare(&tk->wall_to_monotonic, &ts_delta) > 0) { - ret = -EINVAL; - goto out; - } - tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta)); tk_set_xtime(tk, ts); -out: + timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); write_seqcount_end(&tk_core.seq); @@ -1375,12 +1369,10 @@ int do_settimeofday64(const struct timespec64 *ts) /* Signal hrtimers about time change */ clock_was_set(CLOCK_SET_WALL); - if (!ret) { - audit_tk_injoffset(ts_delta); - add_device_randomness(ts, sizeof(*ts)); - } + audit_tk_injoffset(ts_delta); + add_device_randomness(ts, sizeof(*ts)); - return ret; + return 0; } EXPORT_SYMBOL(do_settimeofday64); @@ -1407,8 +1399,7 @@ static int timekeeping_inject_offset(const struct timespec64 *ts) /* Make sure the proposed value is valid */ tmp = timespec64_add(tk_xtime(tk), *ts); - if (timespec64_compare(&tk->wall_to_monotonic, ts) > 0 || - !timespec64_valid_settod(&tmp)) { + if (!timespec64_valid_settod(&tmp)) { ret = -EINVAL; goto error; } From 1998d968ecefb0581d1652d24e6800817ffc3e67 Mon Sep 17 00:00:00 2001 From: Bill Pittman Date: Mon, 30 Aug 2021 13:34:07 -0500 Subject: [PATCH 08/83] i2c-i801.c: Skip SPD initialization on cRIO-903x The cRIO-903x architecture is sort of special, we do not connect a dimm to the SPD because we use flash instead, but the SPD is still present because the processor expects it. However, enumerating and registering the SPD i2c bus is causing interrupt storms, so for now we skip the registration on all 903x devices. Fixes: 01590f3 ("i2c: i801: Instantiate SPD EEPROMs automatically") Signed-off-by: Bill Pittman Natinst-AZDO-ID: 1573148 (cherry picked from commit 4de019e72df37f49e08f352a835cf5779d57fac2) [cvadrevu: fix trivial conflict with d08cac0a6378c ("i2c: i801: reword according to newest specification")] [cvadrevu: fix minor conflict with 80e56b86b59e7 ("i2c: i801: Simplify class-based client device instantiation")] Signed-off-by: Chaitanya Vadrevu --- drivers/i2c/busses/i2c-i801.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/i2c/busses/i2c-i801.c b/drivers/i2c/busses/i2c-i801.c index 75dab01d43a75..c84a4fd22305b 100644 --- a/drivers/i2c/busses/i2c-i801.c +++ b/drivers/i2c/busses/i2c-i801.c @@ -1286,6 +1286,8 @@ static void register_dell_lis3lv02d_i2c_device(struct i801_priv *priv) /* Register optional targets */ static void i801_probe_optional_targets(struct i801_priv *priv) { + const char *product; + /* Only register targets on main SMBus channel */ if (priv->features & FEATURE_IDF) return; @@ -1305,11 +1307,17 @@ static void i801_probe_optional_targets(struct i801_priv *priv) if (is_dell_system_with_lis3lv02d()) register_dell_lis3lv02d_i2c_device(priv); - /* Instantiate SPD EEPROMs unless the SMBus is multiplexed */ + /* Instantiate SPD EEPROMs unless the SMBus is multiplexed or it's a cRIO-903x */ + product = dmi_get_system_info(DMI_PRODUCT_NAME); + if(strncmp(product, "NI cRIO-903", 11)) { #ifdef CONFIG_I2C_I801_MUX - if (!priv->mux_pdev) + if (!priv->mux_pdev) #endif - i2c_register_spd(&priv->adapter); + i2c_register_spd(&priv->adapter); + } + else { + dev_info(&priv->adapter.dev, "Found %s, skipping SPD registration.", product); + } } #else static void __init input_apanel_init(void) {} From acc8c992a94718cc694c8ced0e28d8eb3a0cd922 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Mon, 16 Dec 2013 10:33:02 -0600 Subject: [PATCH 09/83] nirtfeatures: Added NI RT features driver Added an NI RT features driver. This is an ACPI device that exposes LEDs, switches, and other hardware features of the Smasher controllers. Not all of the proposed features of the device work as expected, and some features may be removed in the future. Development work on this device by the hardware team is currently not a high priority. These issues will be addressed once the hardware team gets back to this device. Signed-off-by: Jeff Westfahl [gratian: fix conflict with 7a6ff4c4cbc3 ("misc: hisi_hikey_usb: Driver to support onboard USB gpio hub on Hikey960")] Signed-off-by: Gratian Crisan [gratian: fix conflict with bb3b6552a5b0 ("staging: hikey9xx: split hi6421v600 irq into a separate driver")] Signed-off-by: Gratian Crisan [gratian: fix conflict with f396ededbd8b ("misc: open-dice: Add driver to expose DICE data to userspace")] Signed-off-by: Gratian Crisan [gratian: fix trivial conflict with 6c93c6f3bad4 ("misc: Add a mechanism to detect stalls on guest vCPUs")] Signed-off-by: Gratian Crisan [gratian: fix trivial conflict with 393fc2f5948f ("misc: microchip: pci1xxxx: load auxiliary bus driver for the PIO function in the multi-function endpoint of pci1xxxx device.")] Signed-off-by: Gratian Crisan [mpeterse: fix trivial conflicts with new config flags] [mpeterse: change return type of nirtfeatures_acpi_remove due to 6c0eb5ba3500] Signed-off-by: Mike Petersen [cvadrevu: fix trivial conflict with b9873755a6c8c ("misc: Add Nitro Secure Module driver")] [cvadrevu: fix trivial conflict with 5f67eef6dff39 ("misc: mrvl-cn10k-dpi: add Octeon CN10K DPI administrative driver")] Signed-off-by: Chaitanya Vadrevu --- drivers/misc/Kconfig | 31 ++ drivers/misc/Makefile | 1 + drivers/misc/nirtfeatures.c | 886 ++++++++++++++++++++++++++++++++++++ 3 files changed, 918 insertions(+) create mode 100644 drivers/misc/nirtfeatures.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 3fe7e2a9bd294..0c80df0fbebb3 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -610,6 +610,37 @@ config MARVELL_CN10K_DPI To compile this driver as a module, choose M here: the module will be called mrvl_cn10k_dpi. +config NI_RT_FEATURES + bool "NI 903x/913x support" + depends on X86 && ACPI + help + This driver exposes LEDs and other features of NI 903x/913x Real-Time + controllers. + + If unsure, say N (but it's safe to say "Y"). + +config NI_LED_PREFIX + string "NI 903x/913x LED prefix" + depends on NI_RT_FEATURES + default "nizynqcpld" + help + This option defines the base name of LEDs exposed by NI_RT_FEATURES. + The default value maintains backwards compatibility with user-space + software that was originally written for ARM (Zynq) hardware. + + If unsure, use the default. + +config NI_HW_REBOOT + bool "Hardware reboot for NI 903x/913x" + depends on NI_RT_FEATURES && X86_64 + default n + help + If enabled, when rebooting an NI 903x/913x, on-board hardware will + be used to reset the system. If not enabled, the controller will do + a normal ACPI reset. + + If unsure, say N. + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index a9f94525e1819..8221e1b6c496b 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -72,3 +72,4 @@ obj-$(CONFIG_TPS6594_PFSM) += tps6594-pfsm.o obj-$(CONFIG_NSM) += nsm.o obj-$(CONFIG_MARVELL_CN10K_DPI) += mrvl_cn10k_dpi.o obj-y += keba/ +obj-$(CONFIG_NI_RT_FEATURES) += nirtfeatures.o diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c new file mode 100644 index 0000000000000..40fb9893642e5 --- /dev/null +++ b/drivers/misc/nirtfeatures.c @@ -0,0 +1,886 @@ +/* + * Copyright (C) 2013 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include +#include +#include + +#ifdef CONFIG_NI_HW_REBOOT +#include +#endif + +#define MODULE_NAME "nirtfeatures" + +/* Register addresses */ + +#define NIRTF_SIGNATURE 0x00 +#define NIRTF_YEAR 0x01 +#define NIRTF_MONTH 0x02 +#define NIRTF_DAY 0x03 +#define NIRTF_HOUR 0x04 +#define NIRTF_MINUTE 0x05 +#define NIRTF_SCRATCH 0x06 +#define NIRTF_BPINFO 0x07 +#define NIRTF_RAIL_STATUS1 0x08 +#define NIRTF_RAIL_STATUS2 0x09 +#define NIRTF_RESET 0x10 +#define NIRTF_RESET_SOURCE 0x11 +#define NIRTF_PROCESSOR_MODE 0x12 +#define NIRTF_SYSTEM_LEDS 0x20 +#define NIRTF_STATUS_LED_SHIFT1 0x21 +#define NIRTF_STATUS_LED_SHIFT0 0x22 +#define NIRTF_RT_LEDS 0x23 + +#define NIRTF_IO_SIZE 0x40 + +/* Register values */ + +#define NIRTF_BPINFO_ID_MASK 0x07 + +#define NIRTF_BPINFO_ID_MANHATTAN 0 +#define NIRTF_BPINFO_ID_HAMMERHEAD 1 + +#define NIRTF_RESET_RESET_PROCESSOR 0x80 + +#define NIRTF_RESET_SOURCE_SOFT_OFF 0x20 +#define NIRTF_RESET_SOURCE_SOFTWARE 0x10 +#define NIRTF_RESET_SOURCE_WATCHDOG 0x08 +#define NIRTF_RESET_SOURCE_FPGA 0x04 +#define NIRTF_RESET_SOURCE_PROCESSOR 0x02 +#define NIRTF_RESET_SOURCE_BUTTON 0x01 + +#define NIRTF_PROCESSOR_MODE_HARD_BOOT_N 0x20 +#define NIRTF_PROCESSOR_MODE_NO_FPGA 0x10 +#define NIRTF_PROCESSOR_MODE_RECOVERY 0x08 +#define NIRTF_PROCESSOR_MODE_CONSOLE_OUT 0x04 +#define NIRTF_PROCESSOR_MODE_IP_RESET 0x02 +#define NIRTF_PROCESSOR_MODE_SAFE 0x01 + +#define NIRTF_SYSTEM_LEDS_STATUS_RED 0x08 +#define NIRTF_SYSTEM_LEDS_STATUS_YELLOW 0x04 +#define NIRTF_SYSTEM_LEDS_POWER_GREEN 0x02 +#define NIRTF_SYSTEM_LEDS_POWER_YELLOW 0x01 + +#define NIRTF_RT_LEDS_USER2_GREEN 0x08 +#define NIRTF_RT_LEDS_USER2_YELLOW 0x04 +#define NIRTF_RT_LEDS_USER1_GREEN 0x02 +#define NIRTF_RT_LEDS_USER1_YELLOW 0x01 + +/* Structures */ + +struct nirtfeatures { + struct acpi_device *acpi_device; + u16 io_base; + u16 io_size; + spinlock_t lock; + u8 revision[5]; + const char *bpstring; + struct nirtfeatures_led *extra_leds; + unsigned num_extra_leds; +}; + +struct nirtfeatures_led { + struct led_classdev cdev; + struct nirtfeatures *nirtfeatures; + u8 address; + u8 mask; + u8 pattern_hi_addr; + u8 pattern_lo_addr; +}; + +/* sysfs files */ + +static ssize_t nirtfeatures_revision_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + + return sprintf(buf, "20%02X/%02X/%02X %02X:%02X\n", + nirtfeatures->revision[0], nirtfeatures->revision[1], + nirtfeatures->revision[2], nirtfeatures->revision[3], + nirtfeatures->revision[4]); +} + +static DEVICE_ATTR(revision, S_IRUGO, nirtfeatures_revision_get, NULL); + +static ssize_t nirtfeatures_scratch_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + data = inb(nirtfeatures->io_base + NIRTF_SCRATCH); + + return sprintf(buf, "%02x\n", data); +} + +static ssize_t nirtfeatures_scratch_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + unsigned long tmp; + u8 data; + + if (kstrtoul(buf, 0, &tmp) || (tmp > 0xFF)) + return -EINVAL; + + data = (u8)tmp; + + outb(data, nirtfeatures->io_base + NIRTF_SCRATCH); + + return count; +} + +static DEVICE_ATTR(scratch, S_IRUGO|S_IWUSR, nirtfeatures_scratch_get, + nirtfeatures_scratch_set); + +static ssize_t nirtfeatures_backplane_id_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + + return sprintf(buf, "%s\n", nirtfeatures->bpstring); +} + +static DEVICE_ATTR(backplane_id, S_IRUGO, nirtfeatures_backplane_id_get, NULL); + +static ssize_t nirtfeatures_railstatus1_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + data = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS1); + + return sprintf(buf, "%02x\n", data); +} + +static DEVICE_ATTR(railstatus1, S_IRUGO, nirtfeatures_railstatus1_get, NULL); + +static ssize_t nirtfeatures_railstatus2_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + data = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS2); + + return sprintf(buf, "%02x\n", data); +} + +static DEVICE_ATTR(railstatus2, S_IRUGO, nirtfeatures_railstatus2_get, NULL); + +static ssize_t nirtfeatures_reset_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + + if (strcmp(buf, "1")) + return -EINVAL; + + outb(NIRTF_RESET_RESET_PROCESSOR, nirtfeatures->io_base + NIRTF_RESET); + + return count; +} + +static DEVICE_ATTR(reset, S_IWUSR, NULL, nirtfeatures_reset_set); + +static ssize_t nirtfeatures_reset_source_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + const char *reset_source; + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + data &= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; + + /* Power-on reset status is in a different register from the other reset + sources, we must check it first. */ + if (!data) { + reset_source = "power-on reset"; + } else { + data = inb(nirtfeatures->io_base + NIRTF_RESET_SOURCE); + + switch (data) { + case NIRTF_RESET_SOURCE_SOFT_OFF: + reset_source = "soft off button"; + break; + case NIRTF_RESET_SOURCE_SOFTWARE: + reset_source = "software"; + break; + case NIRTF_RESET_SOURCE_WATCHDOG: + reset_source = "watchdog"; + break; + case NIRTF_RESET_SOURCE_FPGA: + reset_source = "FPGA"; + break; + case NIRTF_RESET_SOURCE_PROCESSOR: + reset_source = "processor"; + break; + case NIRTF_RESET_SOURCE_BUTTON: + reset_source = "reset button"; + break; + default: + dev_err(&nirtfeatures->acpi_device->dev, + "Unrecognized reset source 0x%02X\n", + data); + reset_source = "unknown"; + break; + } + } + + return sprintf(buf, "%s\n", reset_source); +} + +static DEVICE_ATTR(reset_source, S_IRUGO, nirtfeatures_reset_source_get, NULL); + +static ssize_t nirtfeatures_hard_boot_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + data &= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; + + return sprintf(buf, "%s\n", data ? "soft reset" : "power-on reset"); +} + +static ssize_t nirtfeatures_hard_boot_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + if (strcmp(buf, "1")) + return -EINVAL; + + spin_lock(&nirtfeatures->lock); + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + data |= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; + + outb(data, nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + spin_unlock(&nirtfeatures->lock); + + return count; +} + +static DEVICE_ATTR(hard_boot, S_IRUGO|S_IWUSR, nirtfeatures_hard_boot_get, + nirtfeatures_hard_boot_set); + +static ssize_t nirtfeatures_no_fpga_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + data &= NIRTF_PROCESSOR_MODE_NO_FPGA; + + return sprintf(buf, "%u\n", !!data); +} + +static ssize_t nirtfeatures_no_fpga_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + unsigned long tmp; + u8 data; + + if (kstrtoul(buf, 0, &tmp) || (tmp > 1)) + return -EINVAL; + + spin_lock(&nirtfeatures->lock); + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + if (tmp) + data |= NIRTF_PROCESSOR_MODE_NO_FPGA; + else + data &= ~NIRTF_PROCESSOR_MODE_NO_FPGA; + + outb(data, nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + spin_unlock(&nirtfeatures->lock); + + return count; +} + +static DEVICE_ATTR(no_fpga, S_IRUGO|S_IWUSR, nirtfeatures_no_fpga_get, + nirtfeatures_no_fpga_set); + +static ssize_t nirtfeatures_recovery_mode_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + data &= NIRTF_PROCESSOR_MODE_RECOVERY; + + return sprintf(buf, "%u\n", !!data); +} + +static ssize_t nirtfeatures_recovery_mode_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + unsigned long tmp; + u8 data; + + if (kstrtoul(buf, 0, &tmp) || (tmp > 1)) + return -EINVAL; + + spin_lock(&nirtfeatures->lock); + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + if (tmp) + data |= NIRTF_PROCESSOR_MODE_RECOVERY; + else + data &= ~NIRTF_PROCESSOR_MODE_RECOVERY; + + outb(data, nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + spin_unlock(&nirtfeatures->lock); + + return count; +} + +static DEVICE_ATTR(recovery_mode, S_IRUGO|S_IWUSR, + nirtfeatures_recovery_mode_get, nirtfeatures_recovery_mode_set); + +static ssize_t nirtfeatures_console_out_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + data &= NIRTF_PROCESSOR_MODE_CONSOLE_OUT; + + return sprintf(buf, "%u\n", !!data); +} + +static DEVICE_ATTR(console_out, S_IRUGO, nirtfeatures_console_out_get, NULL); + +static ssize_t nirtfeatures_ip_reset_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + data &= NIRTF_PROCESSOR_MODE_IP_RESET; + + return sprintf(buf, "%u\n", !!data); +} + +static DEVICE_ATTR(ip_reset, S_IRUGO, nirtfeatures_ip_reset_get, NULL); + +static ssize_t nirtfeatures_safe_mode_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; + + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + + data &= NIRTF_PROCESSOR_MODE_SAFE; + + return sprintf(buf, "%u\n", !!data); +} + +static DEVICE_ATTR(safe_mode, S_IRUGO, nirtfeatures_safe_mode_get, NULL); + +static ssize_t nirtfeatures_register_dump_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 signature, year, month, day, hour, minute, scratch, bpinfo; + u8 railstatus1, railstatus2, reset, reset_source, processor_mode; + u8 system_leds, status_led_shift1, status_led_shift0, rt_leds; + + signature = inb(nirtfeatures->io_base + NIRTF_SIGNATURE); + year = inb(nirtfeatures->io_base + NIRTF_YEAR); + month = inb(nirtfeatures->io_base + NIRTF_MONTH); + day = inb(nirtfeatures->io_base + NIRTF_DAY); + hour = inb(nirtfeatures->io_base + NIRTF_HOUR); + minute = inb(nirtfeatures->io_base + NIRTF_MINUTE); + scratch = inb(nirtfeatures->io_base + NIRTF_SCRATCH); + bpinfo = inb(nirtfeatures->io_base + NIRTF_BPINFO); + railstatus1 = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS1); + railstatus2 = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS2); + reset = inb(nirtfeatures->io_base + NIRTF_RESET); + reset_source = inb(nirtfeatures->io_base + NIRTF_RESET_SOURCE); + processor_mode = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + system_leds = inb(nirtfeatures->io_base + NIRTF_SYSTEM_LEDS); + status_led_shift1 = + inb(nirtfeatures->io_base + NIRTF_STATUS_LED_SHIFT1); + status_led_shift0 = + inb(nirtfeatures->io_base + NIRTF_STATUS_LED_SHIFT0); + rt_leds = inb(nirtfeatures->io_base + NIRTF_RT_LEDS); + + return sprintf(buf, + "Signature: 0x%02X\n" + "Year: 0x%02X\n" + "Month: 0x%02X\n" + "Day: 0x%02X\n" + "Hour: 0x%02X\n" + "Minute: 0x%02X\n" + "Scratch: 0x%02X\n" + "BPInfo: 0x%02X\n" + "Rail status 1: 0x%02X\n" + "Rail status 2: 0x%02X\n" + "Reset: 0x%02X\n" + "Reset source: 0x%02X\n" + "Processor mode: 0x%02X\n" + "System LEDs: 0x%02X\n" + "Status LED shift 1: 0x%02X\n" + "Status LED shift 0: 0x%02X\n" + "RT LEDs: 0x%02X\n", + signature, year, month, day, hour, minute, scratch, + bpinfo, railstatus1, railstatus2, reset, reset_source, + processor_mode, system_leds, status_led_shift1, + status_led_shift0, rt_leds); +} + +static DEVICE_ATTR(register_dump, S_IRUGO, nirtfeatures_register_dump_get, + NULL); + +static const struct attribute *nirtfeatures_attrs[] = { + &dev_attr_revision.attr, + &dev_attr_scratch.attr, + &dev_attr_backplane_id.attr, + &dev_attr_railstatus1.attr, + &dev_attr_railstatus2.attr, + &dev_attr_reset.attr, + &dev_attr_reset_source.attr, + &dev_attr_hard_boot.attr, + &dev_attr_no_fpga.attr, + &dev_attr_recovery_mode.attr, + &dev_attr_console_out.attr, + &dev_attr_ip_reset.attr, + &dev_attr_safe_mode.attr, + &dev_attr_register_dump.attr, + NULL +}; + +/* LEDs */ + +static void nirtfeatures_led_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct nirtfeatures_led *led = (struct nirtfeatures_led *)led_cdev; + u8 data; + bool on; + u16 pattern; + + on = !!brightness; + pattern = brightness; + + spin_lock(&led->nirtfeatures->lock); + + data = inb(led->nirtfeatures->io_base + led->address); + + data &= ~led->mask; + + if (on) + data |= led->mask; + + outb(data, led->nirtfeatures->io_base + led->address); + + if (led->pattern_hi_addr && led->pattern_lo_addr) { + /* Write the high byte first. */ + outb(pattern >> 8, + led->nirtfeatures->io_base + led->pattern_hi_addr); + outb(pattern & 0xFF, + led->nirtfeatures->io_base + led->pattern_lo_addr); + } + + spin_unlock(&led->nirtfeatures->lock); +} + +static enum led_brightness +nirtfeatures_led_brightness_get(struct led_classdev *led_cdev) +{ + struct nirtfeatures_led *led = (struct nirtfeatures_led *)led_cdev; + u8 data; + + data = inb(led->nirtfeatures->io_base + led->address); + + /* For the yellow status LED, the blink pattern used for brightness + on write is write-only, so we just return on/off for all LEDs. */ + return (data & led->mask) ? LED_FULL : LED_OFF; +} + +static struct nirtfeatures_led nirtfeatures_leds_common[] = { + { + { + .name = CONFIG_NI_LED_PREFIX ":user1:green", + }, + .address = NIRTF_RT_LEDS, + .mask = NIRTF_RT_LEDS_USER1_GREEN, + }, + { + { + .name = CONFIG_NI_LED_PREFIX ":user1:yellow", + }, + .address = NIRTF_RT_LEDS, + .mask = NIRTF_RT_LEDS_USER1_YELLOW, + }, + { + { + .name = CONFIG_NI_LED_PREFIX ":status:red", + }, + .address = NIRTF_SYSTEM_LEDS, + .mask = NIRTF_SYSTEM_LEDS_STATUS_RED, + }, + { + { + .name = CONFIG_NI_LED_PREFIX ":status:yellow", + .max_brightness = 0xFFFF, + }, + .address = NIRTF_SYSTEM_LEDS, + .mask = NIRTF_SYSTEM_LEDS_STATUS_YELLOW, + .pattern_hi_addr = NIRTF_STATUS_LED_SHIFT1, + .pattern_lo_addr = NIRTF_STATUS_LED_SHIFT0, + }, + { + { + .name = CONFIG_NI_LED_PREFIX ":power:green", + }, + .address = NIRTF_SYSTEM_LEDS, + .mask = NIRTF_SYSTEM_LEDS_POWER_GREEN, + }, + { + { + .name = CONFIG_NI_LED_PREFIX ":power:yellow", + }, + .address = NIRTF_SYSTEM_LEDS, + .mask = NIRTF_SYSTEM_LEDS_POWER_YELLOW, + }, +}; + +static struct nirtfeatures_led nirtfeatures_leds_cdaq[] = { + { + { + .name = CONFIG_NI_LED_PREFIX ":user2:green", + }, + .address = NIRTF_RT_LEDS, + .mask = NIRTF_RT_LEDS_USER2_GREEN, + }, + { + { + .name = CONFIG_NI_LED_PREFIX ":user2:yellow", + }, + .address = NIRTF_RT_LEDS, + .mask = NIRTF_RT_LEDS_USER2_YELLOW, + }, +}; + +static int nirtfeatures_create_leds(struct nirtfeatures *nirtfeatures) +{ + int i; + int err; + + for (i = 0; i < ARRAY_SIZE(nirtfeatures_leds_common); ++i) { + + nirtfeatures_leds_common[i].nirtfeatures = nirtfeatures; + + if (0 == nirtfeatures_leds_common[i].cdev.max_brightness) + nirtfeatures_leds_common[i].cdev.max_brightness = 1; + + nirtfeatures_leds_common[i].cdev.brightness_set = + nirtfeatures_led_brightness_set; + + nirtfeatures_leds_common[i].cdev.brightness_get = + nirtfeatures_led_brightness_get; + + err = led_classdev_register(&nirtfeatures->acpi_device->dev, + &nirtfeatures_leds_common[i].cdev); + if (err) + return err; + } + + for (i = 0; i < nirtfeatures->num_extra_leds; ++i) { + + nirtfeatures->extra_leds[i].nirtfeatures = nirtfeatures; + + if (0 == nirtfeatures->extra_leds[i].cdev.max_brightness) + nirtfeatures->extra_leds[i].cdev.max_brightness = 1; + + nirtfeatures->extra_leds[i].cdev.brightness_set = + nirtfeatures_led_brightness_set; + + nirtfeatures->extra_leds[i].cdev.brightness_get = + nirtfeatures_led_brightness_get; + + err = led_classdev_register(&nirtfeatures->acpi_device->dev, + &nirtfeatures->extra_leds[i].cdev); + if (err) + return err; + } + + return 0; +} + +static void nirtfeatures_remove_leds(struct nirtfeatures *nirtfeatures) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(nirtfeatures_leds_common); ++i) + led_classdev_unregister(&nirtfeatures_leds_common[i].cdev); + + for (i = 0; i < nirtfeatures->num_extra_leds; ++i) + led_classdev_unregister(&nirtfeatures->extra_leds[i].cdev); +} + +/* Board specific reboot fixup */ + +#ifdef CONFIG_NI_HW_REBOOT + +static u16 mach_reboot_fixup_io_base; + +void mach_reboot_fixups(void) +{ + int i; + + if (mach_reboot_fixup_io_base) + for (i = 0; i < 10; ++i) { + outb(NIRTF_RESET_RESET_PROCESSOR, + mach_reboot_fixup_io_base + NIRTF_RESET); + udelay(100); + } +} + +#endif + +/* ACPI driver */ + +static acpi_status nirtfeatures_resources(struct acpi_resource *res, void *data) +{ + struct nirtfeatures *nirtfeatures = data; + + switch (res->type) { + case ACPI_RESOURCE_TYPE_IO: + if ((nirtfeatures->io_base != 0) || + (nirtfeatures->io_size != 0)) { + dev_err(&nirtfeatures->acpi_device->dev, + "too many IO resources\n"); + return AE_ERROR; + } + + nirtfeatures->io_base = res->data.io.minimum; + nirtfeatures->io_size = res->data.io.address_length; + + return AE_OK; + + case ACPI_RESOURCE_TYPE_END_TAG: + return AE_OK; + + default: + dev_err(&nirtfeatures->acpi_device->dev, + "unsupported resource type %u\n", + res->type); + return AE_ERROR; + } + + return AE_OK; +} + +static void nirtfeatures_acpi_remove(struct acpi_device *device) +{ + struct nirtfeatures *nirtfeatures = device->driver_data; + + nirtfeatures_remove_leds(nirtfeatures); + + sysfs_remove_files(&nirtfeatures->acpi_device->dev.kobj, + nirtfeatures_attrs); + + if ((nirtfeatures->io_base != 0) && + (nirtfeatures->io_size == NIRTF_IO_SIZE)) + release_region(nirtfeatures->io_base, nirtfeatures->io_size); + + device->driver_data = NULL; + + kfree(nirtfeatures); +} + +static int nirtfeatures_acpi_add(struct acpi_device *device) +{ + struct nirtfeatures *nirtfeatures; + acpi_status acpi_ret; + u8 bpinfo; + int err; + + nirtfeatures = kzalloc(sizeof(*nirtfeatures), GFP_KERNEL); + + if (!nirtfeatures) + return -ENOMEM; + + device->driver_data = nirtfeatures; + + nirtfeatures->acpi_device = device; + + acpi_ret = acpi_walk_resources(device->handle, METHOD_NAME__CRS, + nirtfeatures_resources, nirtfeatures); + + if (ACPI_FAILURE(acpi_ret) || + (nirtfeatures->io_base == 0) || + (nirtfeatures->io_size != NIRTF_IO_SIZE)) { + nirtfeatures_acpi_remove(device); + return -ENODEV; + } + + if (!request_region(nirtfeatures->io_base, nirtfeatures->io_size, + MODULE_NAME)) { + nirtfeatures_acpi_remove(device); + return -EBUSY; + } + +#ifdef CONFIG_NI_HW_REBOOT + mach_reboot_fixup_io_base = nirtfeatures->io_base; + reboot_type = BOOT_KBD; +#endif + + bpinfo = inb(nirtfeatures->io_base + NIRTF_BPINFO); + + bpinfo &= NIRTF_BPINFO_ID_MASK; + + switch (bpinfo) { + case NIRTF_BPINFO_ID_MANHATTAN: + nirtfeatures->bpstring = "Manhattan"; + break; + case NIRTF_BPINFO_ID_HAMMERHEAD: + nirtfeatures->bpstring = "Hammerhead"; + nirtfeatures->extra_leds = nirtfeatures_leds_cdaq; + nirtfeatures->num_extra_leds = + ARRAY_SIZE(nirtfeatures_leds_cdaq); + break; + default: + dev_err(&nirtfeatures->acpi_device->dev, + "Unrecognized backplane type %u\n", + bpinfo); + nirtfeatures_acpi_remove(device); + return -ENODEV; + } + + err = sysfs_create_files(&nirtfeatures->acpi_device->dev.kobj, + nirtfeatures_attrs); + if (0 != err) { + nirtfeatures_acpi_remove(device); + return err; + } + + err = nirtfeatures_create_leds(nirtfeatures); + if (0 != err) { + nirtfeatures_acpi_remove(device); + return err; + } + + spin_lock_init(&nirtfeatures->lock); + + nirtfeatures->revision[0] = inb(nirtfeatures->io_base + NIRTF_YEAR); + nirtfeatures->revision[1] = inb(nirtfeatures->io_base + NIRTF_MONTH); + nirtfeatures->revision[2] = inb(nirtfeatures->io_base + NIRTF_DAY); + nirtfeatures->revision[3] = inb(nirtfeatures->io_base + NIRTF_HOUR); + nirtfeatures->revision[4] = inb(nirtfeatures->io_base + NIRTF_MINUTE); + + dev_info(&nirtfeatures->acpi_device->dev, + "IO range 0x%04X-0x%04X\n", + nirtfeatures->io_base, + nirtfeatures->io_base + nirtfeatures->io_size - 1); + + return 0; +} + +static const struct acpi_device_id nirtfeatures_device_ids[] = { + {"NIC775D", 0}, + {"", 0}, +}; + +static struct acpi_driver nirtfeatures_acpi_driver = { + .name = MODULE_NAME, + .ids = nirtfeatures_device_ids, + .ops = { + .add = nirtfeatures_acpi_add, + .remove = nirtfeatures_acpi_remove, + }, +}; + +static int __init nirtfeatures_init(void) +{ + return acpi_bus_register_driver(&nirtfeatures_acpi_driver); +} + +static void __exit nirtfeatures_exit(void) +{ + acpi_bus_unregister_driver(&nirtfeatures_acpi_driver); +} + +module_init(nirtfeatures_init); +module_exit(nirtfeatures_exit); + +MODULE_DEVICE_TABLE(acpi, nirtfeatures_device_ids); +MODULE_DESCRIPTION("NI RT Features"); +MODULE_AUTHOR("Jeff Westfahl "); +MODULE_LICENSE("GPL"); From aa736b83faf84fc73c7124cbb9b32236303678c5 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 14 Mar 2014 17:24:18 -0500 Subject: [PATCH 10/83] nirtfeatures: change hard_boot to soft_reset to match our Zynq targets On our Zynq targets, we expose the power-on reset status of the controller via a soft_reset sysfs file. The same underlying bit in the CPLD is exposed as hard_boot on our Smasher targets. In this commit we change the Smasher implementation to match Zynq. Signed-off-by: Jeff Westfahl --- drivers/misc/nirtfeatures.c | 37 ++++++------------------------------- 1 file changed, 6 insertions(+), 31 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 40fb9893642e5..3fb9ed5d248b0 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -264,9 +264,9 @@ static ssize_t nirtfeatures_reset_source_get(struct device *dev, static DEVICE_ATTR(reset_source, S_IRUGO, nirtfeatures_reset_source_get, NULL); -static ssize_t nirtfeatures_hard_boot_get(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t nirtfeatures_soft_reset_get(struct device *dev, + struct device_attribute *attr, + char *buf) { struct acpi_device *acpi_device = to_acpi_device(dev); struct nirtfeatures *nirtfeatures = acpi_device->driver_data; @@ -276,35 +276,10 @@ static ssize_t nirtfeatures_hard_boot_get(struct device *dev, data &= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; - return sprintf(buf, "%s\n", data ? "soft reset" : "power-on reset"); -} - -static ssize_t nirtfeatures_hard_boot_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct acpi_device *acpi_device = to_acpi_device(dev); - struct nirtfeatures *nirtfeatures = acpi_device->driver_data; - u8 data; - - if (strcmp(buf, "1")) - return -EINVAL; - - spin_lock(&nirtfeatures->lock); - - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - - data |= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; - - outb(data, nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - - spin_unlock(&nirtfeatures->lock); - - return count; + return sprintf(buf, "%u\n", !!data); } -static DEVICE_ATTR(hard_boot, S_IRUGO|S_IWUSR, nirtfeatures_hard_boot_get, - nirtfeatures_hard_boot_set); +static DEVICE_ATTR(soft_reset, S_IRUGO, nirtfeatures_soft_reset_get, NULL); static ssize_t nirtfeatures_no_fpga_get(struct device *dev, struct device_attribute *attr, @@ -514,7 +489,7 @@ static const struct attribute *nirtfeatures_attrs[] = { &dev_attr_railstatus2.attr, &dev_attr_reset.attr, &dev_attr_reset_source.attr, - &dev_attr_hard_boot.attr, + &dev_attr_soft_reset.attr, &dev_attr_no_fpga.attr, &dev_attr_recovery_mode.attr, &dev_attr_console_out.attr, From fa90ba27cd21d2de3338bb1d83fc5fb4a4dcc78b Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 14 Mar 2014 17:00:58 -0500 Subject: [PATCH 11/83] nirtfeatures: modify reset_source to match Zynq Changed the strings returned by the reset_source sysfs file to match those returned on Zynq. Changed the algorithm used to determine the reset source to match Zynq. Signed-off-by: Jeff Westfahl (Note that the Smasher CPLD currently returns incorrect values for the reset source in some cases. See CARs 458093 and 458094.) --- drivers/misc/nirtfeatures.c | 50 ++++++++----------------------------- 1 file changed, 11 insertions(+), 39 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 3fb9ed5d248b0..c373b79650fdb 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -211,6 +211,10 @@ static ssize_t nirtfeatures_reset_set(struct device *dev, static DEVICE_ATTR(reset, S_IWUSR, NULL, nirtfeatures_reset_set); +static const char * const nirtfeatures_reset_source_strings[] = { + "button", "processor", "fpga", "watchdog", "software", "softoff", +}; + static ssize_t nirtfeatures_reset_source_get(struct device *dev, struct device_attribute *attr, char *buf) @@ -218,48 +222,16 @@ static ssize_t nirtfeatures_reset_source_get(struct device *dev, struct acpi_device *acpi_device = to_acpi_device(dev); struct nirtfeatures *nirtfeatures = acpi_device->driver_data; u8 data; - const char *reset_source; + int i; - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + data = inb(nirtfeatures->io_base + NIRTF_RESET_SOURCE); - data &= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; - - /* Power-on reset status is in a different register from the other reset - sources, we must check it first. */ - if (!data) { - reset_source = "power-on reset"; - } else { - data = inb(nirtfeatures->io_base + NIRTF_RESET_SOURCE); - - switch (data) { - case NIRTF_RESET_SOURCE_SOFT_OFF: - reset_source = "soft off button"; - break; - case NIRTF_RESET_SOURCE_SOFTWARE: - reset_source = "software"; - break; - case NIRTF_RESET_SOURCE_WATCHDOG: - reset_source = "watchdog"; - break; - case NIRTF_RESET_SOURCE_FPGA: - reset_source = "FPGA"; - break; - case NIRTF_RESET_SOURCE_PROCESSOR: - reset_source = "processor"; - break; - case NIRTF_RESET_SOURCE_BUTTON: - reset_source = "reset button"; - break; - default: - dev_err(&nirtfeatures->acpi_device->dev, - "Unrecognized reset source 0x%02X\n", - data); - reset_source = "unknown"; - break; - } - } + for (i = 0; i < ARRAY_SIZE(nirtfeatures_reset_source_strings); i++) + if ((1 << i) & data) + return sprintf(buf, "%s\n", + nirtfeatures_reset_source_strings[i]); - return sprintf(buf, "%s\n", reset_source); + return sprintf(buf, "poweron\n"); } static DEVICE_ATTR(reset_source, S_IRUGO, nirtfeatures_reset_source_get, NULL); From b7e170fbc070330cd959509ac8de19e7357a11e5 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 14 Mar 2014 17:12:01 -0500 Subject: [PATCH 12/83] nirtfeatures: restructure init function to close holes In nirtfeatures_acpi_add, we create several sysfs files. As currently implemented, there is a window where access to a sysfs file may cause our spinlock to be used before it's been initialized, or may cause us to write an incorrect value to an I/O port. We can close this window by moving the creation of the sysfs files closer to the end of the function. Signed-off-by: Jeff Westfahl [cvadrevu: fixed trivial conflict due to dropping 9cbd2f25fe01 ("nirtfeatures: set HARD_BOOT_N if necessary when the driver loads")] Signed-off-by: Chaitanya Vadrevu --- drivers/misc/nirtfeatures.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index c373b79650fdb..89bf4516579bc 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -771,6 +771,14 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) return -ENODEV; } + spin_lock_init(&nirtfeatures->lock); + + nirtfeatures->revision[0] = inb(nirtfeatures->io_base + NIRTF_YEAR); + nirtfeatures->revision[1] = inb(nirtfeatures->io_base + NIRTF_MONTH); + nirtfeatures->revision[2] = inb(nirtfeatures->io_base + NIRTF_DAY); + nirtfeatures->revision[3] = inb(nirtfeatures->io_base + NIRTF_HOUR); + nirtfeatures->revision[4] = inb(nirtfeatures->io_base + NIRTF_MINUTE); + err = sysfs_create_files(&nirtfeatures->acpi_device->dev.kobj, nirtfeatures_attrs); if (0 != err) { @@ -784,14 +792,6 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) return err; } - spin_lock_init(&nirtfeatures->lock); - - nirtfeatures->revision[0] = inb(nirtfeatures->io_base + NIRTF_YEAR); - nirtfeatures->revision[1] = inb(nirtfeatures->io_base + NIRTF_MONTH); - nirtfeatures->revision[2] = inb(nirtfeatures->io_base + NIRTF_DAY); - nirtfeatures->revision[3] = inb(nirtfeatures->io_base + NIRTF_HOUR); - nirtfeatures->revision[4] = inb(nirtfeatures->io_base + NIRTF_MINUTE); - dev_info(&nirtfeatures->acpi_device->dev, "IO range 0x%04X-0x%04X\n", nirtfeatures->io_base, From 63f7b54377e753d3f2a055f5d83995d792657780 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 14 Mar 2014 17:14:42 -0500 Subject: [PATCH 13/83] nirtfeatures: add LOCK, DEBUG_SWITCH, and GP_BUTTON registers The Smasher CPLD has recently exposed some new registers. In this commit we display the values of these registers in the output of the register_dump sysfs file. Signed-off-by: Jeff Westfahl --- drivers/misc/nirtfeatures.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 89bf4516579bc..d5ba6c8baec4e 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -35,6 +35,7 @@ #define NIRTF_BPINFO 0x07 #define NIRTF_RAIL_STATUS1 0x08 #define NIRTF_RAIL_STATUS2 0x09 +#define NIRTF_LOCK 0x0F #define NIRTF_RESET 0x10 #define NIRTF_RESET_SOURCE 0x11 #define NIRTF_PROCESSOR_MODE 0x12 @@ -42,6 +43,8 @@ #define NIRTF_STATUS_LED_SHIFT1 0x21 #define NIRTF_STATUS_LED_SHIFT0 0x22 #define NIRTF_RT_LEDS 0x23 +#define NIRTF_DEBUG_SWITCH 0x30 +#define NIRTF_GP_BUTTON 0x31 #define NIRTF_IO_SIZE 0x40 @@ -403,8 +406,9 @@ static ssize_t nirtfeatures_register_dump_get(struct device *dev, struct acpi_device *acpi_device = to_acpi_device(dev); struct nirtfeatures *nirtfeatures = acpi_device->driver_data; u8 signature, year, month, day, hour, minute, scratch, bpinfo; - u8 railstatus1, railstatus2, reset, reset_source, processor_mode; + u8 railstatus1, railstatus2, lock, reset, reset_source, processor_mode; u8 system_leds, status_led_shift1, status_led_shift0, rt_leds; + u8 debug_switch, gp_button; signature = inb(nirtfeatures->io_base + NIRTF_SIGNATURE); year = inb(nirtfeatures->io_base + NIRTF_YEAR); @@ -416,6 +420,7 @@ static ssize_t nirtfeatures_register_dump_get(struct device *dev, bpinfo = inb(nirtfeatures->io_base + NIRTF_BPINFO); railstatus1 = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS1); railstatus2 = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS2); + lock = inb(nirtfeatures->io_base + NIRTF_LOCK); reset = inb(nirtfeatures->io_base + NIRTF_RESET); reset_source = inb(nirtfeatures->io_base + NIRTF_RESET_SOURCE); processor_mode = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); @@ -425,6 +430,8 @@ static ssize_t nirtfeatures_register_dump_get(struct device *dev, status_led_shift0 = inb(nirtfeatures->io_base + NIRTF_STATUS_LED_SHIFT0); rt_leds = inb(nirtfeatures->io_base + NIRTF_RT_LEDS); + debug_switch = inb(nirtfeatures->io_base + NIRTF_DEBUG_SWITCH); + gp_button = inb(nirtfeatures->io_base + NIRTF_GP_BUTTON); return sprintf(buf, "Signature: 0x%02X\n" @@ -437,17 +444,21 @@ static ssize_t nirtfeatures_register_dump_get(struct device *dev, "BPInfo: 0x%02X\n" "Rail status 1: 0x%02X\n" "Rail status 2: 0x%02X\n" + "Lock: 0x%02X\n" "Reset: 0x%02X\n" "Reset source: 0x%02X\n" "Processor mode: 0x%02X\n" "System LEDs: 0x%02X\n" "Status LED shift 1: 0x%02X\n" "Status LED shift 0: 0x%02X\n" - "RT LEDs: 0x%02X\n", + "RT LEDs: 0x%02X\n" + "Debug switch: 0x%02X\n" + "GP button: 0x%02X\n", signature, year, month, day, hour, minute, scratch, - bpinfo, railstatus1, railstatus2, reset, reset_source, - processor_mode, system_leds, status_led_shift1, - status_led_shift0, rt_leds); + bpinfo, railstatus1, railstatus2, lock, reset, + reset_source, processor_mode, system_leds, + status_led_shift1, status_led_shift0, rt_leds, + debug_switch, gp_button); } static DEVICE_ATTR(register_dump, S_IRUGO, nirtfeatures_register_dump_get, From 7b34548f10202bd7604fb523d66d640b90181305 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 21 Mar 2014 15:42:17 -0500 Subject: [PATCH 14/83] nirtfeatures: Change Hammerhead ID to match hardware When we built Hammerhead, we used ID 4 instead of 1. We don't want to rework all of the boards to match the documentation, so we're just changing the documentation and driver to match what we built. Signed-off-by: Jeff Westfahl --- drivers/misc/nirtfeatures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index d5ba6c8baec4e..74e0b67f875c5 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -53,7 +53,7 @@ #define NIRTF_BPINFO_ID_MASK 0x07 #define NIRTF_BPINFO_ID_MANHATTAN 0 -#define NIRTF_BPINFO_ID_HAMMERHEAD 1 +#define NIRTF_BPINFO_ID_HAMMERHEAD 4 #define NIRTF_RESET_RESET_PROCESSOR 0x80 From a30c3a7a123586a00d3f6acc6c7ed7a78fbfc88e Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Tue, 1 Apr 2014 13:37:37 -0500 Subject: [PATCH 15/83] nirtfeatures: support for Winghead variant Signed-off-by: Jeff Westfahl --- drivers/misc/nirtfeatures.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 74e0b67f875c5..df3a40b29f79f 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -54,6 +54,7 @@ #define NIRTF_BPINFO_ID_MANHATTAN 0 #define NIRTF_BPINFO_ID_HAMMERHEAD 4 +#define NIRTF_BPINFO_ID_WINGHEAD 5 #define NIRTF_RESET_RESET_PROCESSOR 0x80 @@ -774,6 +775,12 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) nirtfeatures->num_extra_leds = ARRAY_SIZE(nirtfeatures_leds_cdaq); break; + case NIRTF_BPINFO_ID_WINGHEAD: + nirtfeatures->bpstring = "Winghead"; + nirtfeatures->extra_leds = nirtfeatures_leds_cdaq; + nirtfeatures->num_extra_leds = + ARRAY_SIZE(nirtfeatures_leds_cdaq); + break; default: dev_err(&nirtfeatures->acpi_device->dev, "Unrecognized backplane type %u\n", From c4d2ef76b18dc54097e0731998b5a5f3d4a1b3f9 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Tue, 1 Apr 2014 13:58:01 -0500 Subject: [PATCH 16/83] nirtfeatures: support latest CPLD The existing recovery_mode and no_fpga bits are now read only. A new bit, no_fpga_sw, exists for software to tell the CPLD to assert NO_FPGA at the next reset. Signed-off-by: Jeff Westfahl --- drivers/misc/nirtfeatures.c | 85 +++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 47 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index df3a40b29f79f..e31caacaf8e4a 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -65,6 +65,7 @@ #define NIRTF_RESET_SOURCE_PROCESSOR 0x02 #define NIRTF_RESET_SOURCE_BUTTON 0x01 +#define NIRTF_PROCESSOR_MODE_NO_FPGA_SW 0x40 #define NIRTF_PROCESSOR_MODE_HARD_BOOT_N 0x20 #define NIRTF_PROCESSOR_MODE_NO_FPGA 0x10 #define NIRTF_PROCESSOR_MODE_RECOVERY 0x08 @@ -240,7 +241,7 @@ static ssize_t nirtfeatures_reset_source_get(struct device *dev, static DEVICE_ATTR(reset_source, S_IRUGO, nirtfeatures_reset_source_get, NULL); -static ssize_t nirtfeatures_soft_reset_get(struct device *dev, +static ssize_t nirtfeatures_no_fpga_sw_get(struct device *dev, struct device_attribute *attr, char *buf) { @@ -250,31 +251,14 @@ static ssize_t nirtfeatures_soft_reset_get(struct device *dev, data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - data &= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; + data &= NIRTF_PROCESSOR_MODE_NO_FPGA_SW; return sprintf(buf, "%u\n", !!data); } -static DEVICE_ATTR(soft_reset, S_IRUGO, nirtfeatures_soft_reset_get, NULL); - -static ssize_t nirtfeatures_no_fpga_get(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct acpi_device *acpi_device = to_acpi_device(dev); - struct nirtfeatures *nirtfeatures = acpi_device->driver_data; - u8 data; - - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - - data &= NIRTF_PROCESSOR_MODE_NO_FPGA; - - return sprintf(buf, "%u\n", !!data); -} - -static ssize_t nirtfeatures_no_fpga_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t nirtfeatures_no_fpga_sw_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) { struct acpi_device *acpi_device = to_acpi_device(dev); struct nirtfeatures *nirtfeatures = acpi_device->driver_data; @@ -289,9 +273,9 @@ static ssize_t nirtfeatures_no_fpga_set(struct device *dev, data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); if (tmp) - data |= NIRTF_PROCESSOR_MODE_NO_FPGA; + data |= NIRTF_PROCESSOR_MODE_NO_FPGA_SW; else - data &= ~NIRTF_PROCESSOR_MODE_NO_FPGA; + data &= ~NIRTF_PROCESSOR_MODE_NO_FPGA_SW; outb(data, nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); @@ -300,12 +284,12 @@ static ssize_t nirtfeatures_no_fpga_set(struct device *dev, return count; } -static DEVICE_ATTR(no_fpga, S_IRUGO|S_IWUSR, nirtfeatures_no_fpga_get, - nirtfeatures_no_fpga_set); +static DEVICE_ATTR(no_fpga_sw, S_IRUGO|S_IWUSR, nirtfeatures_no_fpga_sw_get, + nirtfeatures_no_fpga_sw_set); -static ssize_t nirtfeatures_recovery_mode_get(struct device *dev, - struct device_attribute *attr, - char *buf) +static ssize_t nirtfeatures_soft_reset_get(struct device *dev, + struct device_attribute *attr, + char *buf) { struct acpi_device *acpi_device = to_acpi_device(dev); struct nirtfeatures *nirtfeatures = acpi_device->driver_data; @@ -313,41 +297,47 @@ static ssize_t nirtfeatures_recovery_mode_get(struct device *dev, data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - data &= NIRTF_PROCESSOR_MODE_RECOVERY; + data &= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; return sprintf(buf, "%u\n", !!data); } -static ssize_t nirtfeatures_recovery_mode_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) +static DEVICE_ATTR(soft_reset, S_IRUGO, nirtfeatures_soft_reset_get, NULL); + +static ssize_t nirtfeatures_no_fpga_get(struct device *dev, + struct device_attribute *attr, + char *buf) { struct acpi_device *acpi_device = to_acpi_device(dev); struct nirtfeatures *nirtfeatures = acpi_device->driver_data; - unsigned long tmp; u8 data; - if (kstrtoul(buf, 0, &tmp) || (tmp > 1)) - return -EINVAL; + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - spin_lock(&nirtfeatures->lock); + data &= NIRTF_PROCESSOR_MODE_NO_FPGA; - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + return sprintf(buf, "%u\n", !!data); +} - if (tmp) - data |= NIRTF_PROCESSOR_MODE_RECOVERY; - else - data &= ~NIRTF_PROCESSOR_MODE_RECOVERY; +static DEVICE_ATTR(no_fpga, S_IRUGO, nirtfeatures_no_fpga_get, NULL); - outb(data, nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); +static ssize_t nirtfeatures_recovery_mode_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct nirtfeatures *nirtfeatures = acpi_device->driver_data; + u8 data; - spin_unlock(&nirtfeatures->lock); + data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - return count; + data &= NIRTF_PROCESSOR_MODE_RECOVERY; + + return sprintf(buf, "%u\n", !!data); } -static DEVICE_ATTR(recovery_mode, S_IRUGO|S_IWUSR, - nirtfeatures_recovery_mode_get, nirtfeatures_recovery_mode_set); +static DEVICE_ATTR(recovery_mode, S_IRUGO, + nirtfeatures_recovery_mode_get, NULL); static ssize_t nirtfeatures_console_out_get(struct device *dev, struct device_attribute *attr, @@ -473,6 +463,7 @@ static const struct attribute *nirtfeatures_attrs[] = { &dev_attr_railstatus2.attr, &dev_attr_reset.attr, &dev_attr_reset_source.attr, + &dev_attr_no_fpga_sw.attr, &dev_attr_soft_reset.attr, &dev_attr_no_fpga.attr, &dev_attr_recovery_mode.attr, From 3797d63178c300ee2216c1eebe4eaa1277171fb3 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Thu, 10 Apr 2014 16:56:04 -0500 Subject: [PATCH 17/83] nirtfeatures: don't bail out on unrecognized ID The driver currently returns an error from init if it doesn't recognize the backplane ID. This causes the kernel to hang on boot. Although this is probably a bug somewhere else in the kernel, there's no real benefit to returning an error in this case. It's sufficient to print an error message to the console and return "Unknown" as the backplane ID. Signed-off-by: Jeff Westfahl --- drivers/misc/nirtfeatures.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index e31caacaf8e4a..dbfd065a15ac7 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -776,8 +776,8 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) dev_err(&nirtfeatures->acpi_device->dev, "Unrecognized backplane type %u\n", bpinfo); - nirtfeatures_acpi_remove(device); - return -ENODEV; + nirtfeatures->bpstring = "Unknown"; + break; } spin_lock_init(&nirtfeatures->lock); From b2243075fb6e9e59bbaf8e71993a22f99085bacb Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 11 Apr 2014 09:01:06 -0500 Subject: [PATCH 18/83] nirtfeatures: remove unused NI_HW_REBOOT config option Remove the unused NI_HW_REBOOT config option. We're not going to use this. Signed-off-by: Jeff Westfahl --- drivers/misc/Kconfig | 11 ----------- drivers/misc/nirtfeatures.c | 29 ----------------------------- 2 files changed, 40 deletions(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 0c80df0fbebb3..87b245bfa213b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -630,17 +630,6 @@ config NI_LED_PREFIX If unsure, use the default. -config NI_HW_REBOOT - bool "Hardware reboot for NI 903x/913x" - depends on NI_RT_FEATURES && X86_64 - default n - help - If enabled, when rebooting an NI 903x/913x, on-board hardware will - be used to reset the system. If not enabled, the controller will do - a normal ACPI reset. - - If unsure, say N. - source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index dbfd065a15ac7..9b1e3232d4a58 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -17,10 +17,6 @@ #include #include -#ifdef CONFIG_NI_HW_REBOOT -#include -#endif - #define MODULE_NAME "nirtfeatures" /* Register addresses */ @@ -644,26 +640,6 @@ static void nirtfeatures_remove_leds(struct nirtfeatures *nirtfeatures) led_classdev_unregister(&nirtfeatures->extra_leds[i].cdev); } -/* Board specific reboot fixup */ - -#ifdef CONFIG_NI_HW_REBOOT - -static u16 mach_reboot_fixup_io_base; - -void mach_reboot_fixups(void) -{ - int i; - - if (mach_reboot_fixup_io_base) - for (i = 0; i < 10; ++i) { - outb(NIRTF_RESET_RESET_PROCESSOR, - mach_reboot_fixup_io_base + NIRTF_RESET); - udelay(100); - } -} - -#endif - /* ACPI driver */ static acpi_status nirtfeatures_resources(struct acpi_resource *res, void *data) @@ -747,11 +723,6 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) return -EBUSY; } -#ifdef CONFIG_NI_HW_REBOOT - mach_reboot_fixup_io_base = nirtfeatures->io_base; - reboot_type = BOOT_KBD; -#endif - bpinfo = inb(nirtfeatures->io_base + NIRTF_BPINFO); bpinfo &= NIRTF_BPINFO_ID_MASK; From 36d99588eb71c39a127e1e82a5f85149440b13f1 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 11 Apr 2014 10:09:59 -0500 Subject: [PATCH 19/83] nirtfeatures: update to latest CPLD and remove debugging features Updated registers to match the latest CPLD documentation, removed several sysfs files that were only used for development debugging, and removed several now unused constants. Signed-off-by: Jeff Westfahl --- drivers/misc/nirtfeatures.c | 211 +++++++----------------------------- 1 file changed, 39 insertions(+), 172 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 9b1e3232d4a58..def78a22cf403 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -21,53 +21,36 @@ /* Register addresses */ -#define NIRTF_SIGNATURE 0x00 #define NIRTF_YEAR 0x01 #define NIRTF_MONTH 0x02 #define NIRTF_DAY 0x03 #define NIRTF_HOUR 0x04 #define NIRTF_MINUTE 0x05 #define NIRTF_SCRATCH 0x06 -#define NIRTF_BPINFO 0x07 -#define NIRTF_RAIL_STATUS1 0x08 -#define NIRTF_RAIL_STATUS2 0x09 -#define NIRTF_LOCK 0x0F -#define NIRTF_RESET 0x10 -#define NIRTF_RESET_SOURCE 0x11 -#define NIRTF_PROCESSOR_MODE 0x12 +#define NIRTF_PLATFORM_MISC 0x07 +#define NIRTF_PROC_RESET_SOURCE 0x11 +#define NIRTF_CONTROLLER_MODE 0x12 #define NIRTF_SYSTEM_LEDS 0x20 #define NIRTF_STATUS_LED_SHIFT1 0x21 #define NIRTF_STATUS_LED_SHIFT0 0x22 #define NIRTF_RT_LEDS 0x23 -#define NIRTF_DEBUG_SWITCH 0x30 -#define NIRTF_GP_BUTTON 0x31 #define NIRTF_IO_SIZE 0x40 /* Register values */ -#define NIRTF_BPINFO_ID_MASK 0x07 +#define NIRTF_PLATFORM_MISC_ID_MASK 0x07 +#define NIRTF_PLATFORM_MISC_ID_MANHATTAN 0 +#define NIRTF_PLATFORM_MISC_ID_HAMMERHEAD 4 +#define NIRTF_PLATFORM_MISC_ID_WINGHEAD 5 -#define NIRTF_BPINFO_ID_MANHATTAN 0 -#define NIRTF_BPINFO_ID_HAMMERHEAD 4 -#define NIRTF_BPINFO_ID_WINGHEAD 5 - -#define NIRTF_RESET_RESET_PROCESSOR 0x80 - -#define NIRTF_RESET_SOURCE_SOFT_OFF 0x20 -#define NIRTF_RESET_SOURCE_SOFTWARE 0x10 -#define NIRTF_RESET_SOURCE_WATCHDOG 0x08 -#define NIRTF_RESET_SOURCE_FPGA 0x04 -#define NIRTF_RESET_SOURCE_PROCESSOR 0x02 -#define NIRTF_RESET_SOURCE_BUTTON 0x01 - -#define NIRTF_PROCESSOR_MODE_NO_FPGA_SW 0x40 -#define NIRTF_PROCESSOR_MODE_HARD_BOOT_N 0x20 -#define NIRTF_PROCESSOR_MODE_NO_FPGA 0x10 -#define NIRTF_PROCESSOR_MODE_RECOVERY 0x08 -#define NIRTF_PROCESSOR_MODE_CONSOLE_OUT 0x04 -#define NIRTF_PROCESSOR_MODE_IP_RESET 0x02 -#define NIRTF_PROCESSOR_MODE_SAFE 0x01 +#define NIRTF_CONTROLLER_MODE_NO_FPGA_SW 0x40 +#define NIRTF_CONTROLLER_MODE_HARD_BOOT_N 0x20 +#define NIRTF_CONTROLLER_MODE_NO_FPGA 0x10 +#define NIRTF_CONTROLLER_MODE_RECOVERY 0x08 +#define NIRTF_CONTROLLER_MODE_CONSOLE_OUT 0x04 +#define NIRTF_CONTROLLER_MODE_IP_RESET 0x02 +#define NIRTF_CONTROLLER_MODE_SAFE 0x01 #define NIRTF_SYSTEM_LEDS_STATUS_RED 0x08 #define NIRTF_SYSTEM_LEDS_STATUS_YELLOW 0x04 @@ -165,55 +148,8 @@ static ssize_t nirtfeatures_backplane_id_get(struct device *dev, static DEVICE_ATTR(backplane_id, S_IRUGO, nirtfeatures_backplane_id_get, NULL); -static ssize_t nirtfeatures_railstatus1_get(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct acpi_device *acpi_device = to_acpi_device(dev); - struct nirtfeatures *nirtfeatures = acpi_device->driver_data; - u8 data; - - data = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS1); - - return sprintf(buf, "%02x\n", data); -} - -static DEVICE_ATTR(railstatus1, S_IRUGO, nirtfeatures_railstatus1_get, NULL); - -static ssize_t nirtfeatures_railstatus2_get(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct acpi_device *acpi_device = to_acpi_device(dev); - struct nirtfeatures *nirtfeatures = acpi_device->driver_data; - u8 data; - - data = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS2); - - return sprintf(buf, "%02x\n", data); -} - -static DEVICE_ATTR(railstatus2, S_IRUGO, nirtfeatures_railstatus2_get, NULL); - -static ssize_t nirtfeatures_reset_set(struct device *dev, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct acpi_device *acpi_device = to_acpi_device(dev); - struct nirtfeatures *nirtfeatures = acpi_device->driver_data; - - if (strcmp(buf, "1")) - return -EINVAL; - - outb(NIRTF_RESET_RESET_PROCESSOR, nirtfeatures->io_base + NIRTF_RESET); - - return count; -} - -static DEVICE_ATTR(reset, S_IWUSR, NULL, nirtfeatures_reset_set); - static const char * const nirtfeatures_reset_source_strings[] = { - "button", "processor", "fpga", "watchdog", "software", "softoff", + "button", "processor", "fpga", "watchdog", "software", }; static ssize_t nirtfeatures_reset_source_get(struct device *dev, @@ -225,7 +161,7 @@ static ssize_t nirtfeatures_reset_source_get(struct device *dev, u8 data; int i; - data = inb(nirtfeatures->io_base + NIRTF_RESET_SOURCE); + data = inb(nirtfeatures->io_base + NIRTF_PROC_RESET_SOURCE); for (i = 0; i < ARRAY_SIZE(nirtfeatures_reset_source_strings); i++) if ((1 << i) & data) @@ -245,9 +181,9 @@ static ssize_t nirtfeatures_no_fpga_sw_get(struct device *dev, struct nirtfeatures *nirtfeatures = acpi_device->driver_data; u8 data; - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + data = inb(nirtfeatures->io_base + NIRTF_CONTROLLER_MODE); - data &= NIRTF_PROCESSOR_MODE_NO_FPGA_SW; + data &= NIRTF_CONTROLLER_MODE_NO_FPGA_SW; return sprintf(buf, "%u\n", !!data); } @@ -266,14 +202,14 @@ static ssize_t nirtfeatures_no_fpga_sw_set(struct device *dev, spin_lock(&nirtfeatures->lock); - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + data = inb(nirtfeatures->io_base + NIRTF_CONTROLLER_MODE); if (tmp) - data |= NIRTF_PROCESSOR_MODE_NO_FPGA_SW; + data |= NIRTF_CONTROLLER_MODE_NO_FPGA_SW; else - data &= ~NIRTF_PROCESSOR_MODE_NO_FPGA_SW; + data &= ~NIRTF_CONTROLLER_MODE_NO_FPGA_SW; - outb(data, nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + outb(data, nirtfeatures->io_base + NIRTF_CONTROLLER_MODE); spin_unlock(&nirtfeatures->lock); @@ -291,9 +227,9 @@ static ssize_t nirtfeatures_soft_reset_get(struct device *dev, struct nirtfeatures *nirtfeatures = acpi_device->driver_data; u8 data; - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + data = inb(nirtfeatures->io_base + NIRTF_CONTROLLER_MODE); - data &= NIRTF_PROCESSOR_MODE_HARD_BOOT_N; + data &= NIRTF_CONTROLLER_MODE_HARD_BOOT_N; return sprintf(buf, "%u\n", !!data); } @@ -308,9 +244,9 @@ static ssize_t nirtfeatures_no_fpga_get(struct device *dev, struct nirtfeatures *nirtfeatures = acpi_device->driver_data; u8 data; - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + data = inb(nirtfeatures->io_base + NIRTF_CONTROLLER_MODE); - data &= NIRTF_PROCESSOR_MODE_NO_FPGA; + data &= NIRTF_CONTROLLER_MODE_NO_FPGA; return sprintf(buf, "%u\n", !!data); } @@ -325,9 +261,9 @@ static ssize_t nirtfeatures_recovery_mode_get(struct device *dev, struct nirtfeatures *nirtfeatures = acpi_device->driver_data; u8 data; - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + data = inb(nirtfeatures->io_base + NIRTF_CONTROLLER_MODE); - data &= NIRTF_PROCESSOR_MODE_RECOVERY; + data &= NIRTF_CONTROLLER_MODE_RECOVERY; return sprintf(buf, "%u\n", !!data); } @@ -343,9 +279,9 @@ static ssize_t nirtfeatures_console_out_get(struct device *dev, struct nirtfeatures *nirtfeatures = acpi_device->driver_data; u8 data; - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + data = inb(nirtfeatures->io_base + NIRTF_CONTROLLER_MODE); - data &= NIRTF_PROCESSOR_MODE_CONSOLE_OUT; + data &= NIRTF_CONTROLLER_MODE_CONSOLE_OUT; return sprintf(buf, "%u\n", !!data); } @@ -360,9 +296,9 @@ static ssize_t nirtfeatures_ip_reset_get(struct device *dev, struct nirtfeatures *nirtfeatures = acpi_device->driver_data; u8 data; - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + data = inb(nirtfeatures->io_base + NIRTF_CONTROLLER_MODE); - data &= NIRTF_PROCESSOR_MODE_IP_RESET; + data &= NIRTF_CONTROLLER_MODE_IP_RESET; return sprintf(buf, "%u\n", !!data); } @@ -377,87 +313,19 @@ static ssize_t nirtfeatures_safe_mode_get(struct device *dev, struct nirtfeatures *nirtfeatures = acpi_device->driver_data; u8 data; - data = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); + data = inb(nirtfeatures->io_base + NIRTF_CONTROLLER_MODE); - data &= NIRTF_PROCESSOR_MODE_SAFE; + data &= NIRTF_CONTROLLER_MODE_SAFE; return sprintf(buf, "%u\n", !!data); } static DEVICE_ATTR(safe_mode, S_IRUGO, nirtfeatures_safe_mode_get, NULL); -static ssize_t nirtfeatures_register_dump_get(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct acpi_device *acpi_device = to_acpi_device(dev); - struct nirtfeatures *nirtfeatures = acpi_device->driver_data; - u8 signature, year, month, day, hour, minute, scratch, bpinfo; - u8 railstatus1, railstatus2, lock, reset, reset_source, processor_mode; - u8 system_leds, status_led_shift1, status_led_shift0, rt_leds; - u8 debug_switch, gp_button; - - signature = inb(nirtfeatures->io_base + NIRTF_SIGNATURE); - year = inb(nirtfeatures->io_base + NIRTF_YEAR); - month = inb(nirtfeatures->io_base + NIRTF_MONTH); - day = inb(nirtfeatures->io_base + NIRTF_DAY); - hour = inb(nirtfeatures->io_base + NIRTF_HOUR); - minute = inb(nirtfeatures->io_base + NIRTF_MINUTE); - scratch = inb(nirtfeatures->io_base + NIRTF_SCRATCH); - bpinfo = inb(nirtfeatures->io_base + NIRTF_BPINFO); - railstatus1 = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS1); - railstatus2 = inb(nirtfeatures->io_base + NIRTF_RAIL_STATUS2); - lock = inb(nirtfeatures->io_base + NIRTF_LOCK); - reset = inb(nirtfeatures->io_base + NIRTF_RESET); - reset_source = inb(nirtfeatures->io_base + NIRTF_RESET_SOURCE); - processor_mode = inb(nirtfeatures->io_base + NIRTF_PROCESSOR_MODE); - system_leds = inb(nirtfeatures->io_base + NIRTF_SYSTEM_LEDS); - status_led_shift1 = - inb(nirtfeatures->io_base + NIRTF_STATUS_LED_SHIFT1); - status_led_shift0 = - inb(nirtfeatures->io_base + NIRTF_STATUS_LED_SHIFT0); - rt_leds = inb(nirtfeatures->io_base + NIRTF_RT_LEDS); - debug_switch = inb(nirtfeatures->io_base + NIRTF_DEBUG_SWITCH); - gp_button = inb(nirtfeatures->io_base + NIRTF_GP_BUTTON); - - return sprintf(buf, - "Signature: 0x%02X\n" - "Year: 0x%02X\n" - "Month: 0x%02X\n" - "Day: 0x%02X\n" - "Hour: 0x%02X\n" - "Minute: 0x%02X\n" - "Scratch: 0x%02X\n" - "BPInfo: 0x%02X\n" - "Rail status 1: 0x%02X\n" - "Rail status 2: 0x%02X\n" - "Lock: 0x%02X\n" - "Reset: 0x%02X\n" - "Reset source: 0x%02X\n" - "Processor mode: 0x%02X\n" - "System LEDs: 0x%02X\n" - "Status LED shift 1: 0x%02X\n" - "Status LED shift 0: 0x%02X\n" - "RT LEDs: 0x%02X\n" - "Debug switch: 0x%02X\n" - "GP button: 0x%02X\n", - signature, year, month, day, hour, minute, scratch, - bpinfo, railstatus1, railstatus2, lock, reset, - reset_source, processor_mode, system_leds, - status_led_shift1, status_led_shift0, rt_leds, - debug_switch, gp_button); -} - -static DEVICE_ATTR(register_dump, S_IRUGO, nirtfeatures_register_dump_get, - NULL); - static const struct attribute *nirtfeatures_attrs[] = { &dev_attr_revision.attr, &dev_attr_scratch.attr, &dev_attr_backplane_id.attr, - &dev_attr_railstatus1.attr, - &dev_attr_railstatus2.attr, - &dev_attr_reset.attr, &dev_attr_reset_source.attr, &dev_attr_no_fpga_sw.attr, &dev_attr_soft_reset.attr, @@ -466,7 +334,6 @@ static const struct attribute *nirtfeatures_attrs[] = { &dev_attr_console_out.attr, &dev_attr_ip_reset.attr, &dev_attr_safe_mode.attr, - &dev_attr_register_dump.attr, NULL }; @@ -723,21 +590,21 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) return -EBUSY; } - bpinfo = inb(nirtfeatures->io_base + NIRTF_BPINFO); + bpinfo = inb(nirtfeatures->io_base + NIRTF_PLATFORM_MISC); - bpinfo &= NIRTF_BPINFO_ID_MASK; + bpinfo &= NIRTF_PLATFORM_MISC_ID_MASK; switch (bpinfo) { - case NIRTF_BPINFO_ID_MANHATTAN: + case NIRTF_PLATFORM_MISC_ID_MANHATTAN: nirtfeatures->bpstring = "Manhattan"; break; - case NIRTF_BPINFO_ID_HAMMERHEAD: + case NIRTF_PLATFORM_MISC_ID_HAMMERHEAD: nirtfeatures->bpstring = "Hammerhead"; nirtfeatures->extra_leds = nirtfeatures_leds_cdaq; nirtfeatures->num_extra_leds = ARRAY_SIZE(nirtfeatures_leds_cdaq); break; - case NIRTF_BPINFO_ID_WINGHEAD: + case NIRTF_PLATFORM_MISC_ID_WINGHEAD: nirtfeatures->bpstring = "Winghead"; nirtfeatures->extra_leds = nirtfeatures_leds_cdaq; nirtfeatures->num_extra_leds = From 87e7c1276ba526c051a9108daab9124af0db46fb Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Tue, 13 May 2014 16:12:02 -0500 Subject: [PATCH 20/83] nirtfeatures: Physical interface element support These changes add support for PIEs (physical interface elements), which are defined as physical elements fixed to a controller/chassis with which a user can interact (e.g. LEDs and switches) and whose meaning is user-defined and implementation-specific. The support for these elements, in terms of enumerating and interacting with them (i.e. retrieving the list of elements, getting/setting their current state, enabling notifications, etc.) is embedded within the BIOS as a set of ACPI methods. The changes to the CPLD driver act as a bridge between these methods and existing Linux kernel facilities as described below to expose the elements and any applicable metadata to user mode. The metadata or knowledge needed for the interpretation thereof is not a prerequisite to interacting with the elements--it is there for upper-level value add software to use to improve the user experience. In other words, Linux users familiar with the class drivers by which the elements are surfaced should not have any issues interfacing with them without knowing the meaning of the attached metadata. Output elements, which consist currently of LEDs, are surfaced via the LED class driver. Each LED and color becomes its own LED class device with the naming convention 'nilrt:{name}:{color}'. Any additional attributes/metadata intended for upper-level software are appended to the name, each separated by colons, as suggested by the LED class driver documentation in the Linux kernel proper, except where there is already a standard way to communicate a specific piece of metadata (e.g., maximum brightness, which is exposed via the /sys/class/leds/.../ max_brightness attribute node). Input elements as surfaced via the input class driver. As with output elements, each input element registers its own separate driver whose name and associated metadata are transmitted via the name attribute attached to the input device, retrievable via the EVIOCGNAME ioctl, using the same convention as described above for output elements. The input class driver model is that events are pushed (i.e. reported) to indicate state changes, so to facilitate this, the CPLD driver has an ACPI notify callback that is invoked when an input element changes state and its BIOS support generates a general purpose event per the ACPI GPE model. The notify callback checks the instantaneous state of the input element and reports a keyboard event on its particular device with a scan code of 256 (BTN_0), where a key down event means that the input element is in the '1' state (down, engaged, on, pressed, etc.) and a key up event means that the input element is in the '0' state (off, disengaged, released, etc.). User mode software can then monitor for these specific events to determine when the state of the element has changed, or can use the EVIOCGKEY ioctl on the appropriate input device to retrieve the instantaneous state of the element. Signed-off-by: Aaron Rossetto (joshc: fixed up strnicmp -> strncasecmp for 4.0) Signed-off-by: Josh Cartwright [mpeterse: change return type of nirtfeatures_acpi_remove due to 6c0eb5ba3500] Signed-off-by: Mike Petersen --- drivers/misc/nirtfeatures.c | 812 +++++++++++++++++++++++++++++++++--- 1 file changed, 751 insertions(+), 61 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index def78a22cf403..1ae01b7a4ad2a 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -15,7 +15,9 @@ #include #include #include +#include #include +#include #define MODULE_NAME "nirtfeatures" @@ -57,10 +59,49 @@ #define NIRTF_SYSTEM_LEDS_POWER_GREEN 0x02 #define NIRTF_SYSTEM_LEDS_POWER_YELLOW 0x01 -#define NIRTF_RT_LEDS_USER2_GREEN 0x08 -#define NIRTF_RT_LEDS_USER2_YELLOW 0x04 -#define NIRTF_RT_LEDS_USER1_GREEN 0x02 -#define NIRTF_RT_LEDS_USER1_YELLOW 0x01 +/*===================================================================== + * ACPI NI physical interface element support + *===================================================================*/ +#define MAX_NAMELEN 64 +#define MAX_NODELEN 128 +#define MIN_PIE_CAPS_VERSION 2 +#define MAX_PIE_CAPS_VERSION 2 + +enum nirtfeatures_pie_class { + PIE_CLASS_INPUT = 0, + PIE_CLASS_OUTPUT = 1 +}; + +enum nirtfeatures_pie_type { + PIE_TYPE_UNKNOWN = 0, + PIE_TYPE_SWITCH = 1, + PIE_TYPE_LED = 2 +}; + +struct nirtfeatures_pie_descriptor { + char name[MAX_NAMELEN]; + enum nirtfeatures_pie_class pie_class; + enum nirtfeatures_pie_type pie_type; + bool is_user_visible; + unsigned int notification_value; +}; + +struct nirtfeatures_pie_descriptor_led_color { + char name[MAX_NAMELEN]; + int brightness_range_low; + int brightness_range_high; +}; + +struct nirtfeatures_pie_descriptor_switch { + unsigned int num_states; + unsigned int state_value[1]; +}; + +struct nirtfeatures_pie_location { + unsigned int element; + unsigned int subelement; +}; + /* Structures */ @@ -71,18 +112,31 @@ struct nirtfeatures { spinlock_t lock; u8 revision[5]; const char *bpstring; - struct nirtfeatures_led *extra_leds; - unsigned num_extra_leds; }; struct nirtfeatures_led { struct led_classdev cdev; struct nirtfeatures *nirtfeatures; + struct nirtfeatures_pie_location pie_location; + char name_string[MAX_NODELEN]; u8 address; u8 mask; u8 pattern_hi_addr; u8 pattern_lo_addr; + struct list_head node; +}; +LIST_HEAD(nirtfeatures_led_pie_list); + +struct nirtfeatures_switch { + struct input_dev *cdev; + struct nirtfeatures *nirtfeatures; + struct nirtfeatures_pie_descriptor pie_descriptor; + struct nirtfeatures_pie_location pie_location; + char name_string[MAX_NODELEN]; + char phys_location_string[MAX_NODELEN]; + struct list_head node; }; +LIST_HEAD(nirtfeatures_switch_pie_list); /* sysfs files */ @@ -386,20 +440,6 @@ nirtfeatures_led_brightness_get(struct led_classdev *led_cdev) } static struct nirtfeatures_led nirtfeatures_leds_common[] = { - { - { - .name = CONFIG_NI_LED_PREFIX ":user1:green", - }, - .address = NIRTF_RT_LEDS, - .mask = NIRTF_RT_LEDS_USER1_GREEN, - }, - { - { - .name = CONFIG_NI_LED_PREFIX ":user1:yellow", - }, - .address = NIRTF_RT_LEDS, - .mask = NIRTF_RT_LEDS_USER1_YELLOW, - }, { { .name = CONFIG_NI_LED_PREFIX ":status:red", @@ -433,22 +473,610 @@ static struct nirtfeatures_led nirtfeatures_leds_common[] = { }, }; -static struct nirtfeatures_led nirtfeatures_leds_cdaq[] = { - { - { - .name = CONFIG_NI_LED_PREFIX ":user2:green", - }, - .address = NIRTF_RT_LEDS, - .mask = NIRTF_RT_LEDS_USER2_GREEN, - }, - { - { - .name = CONFIG_NI_LED_PREFIX ":user2:yellow", - }, - .address = NIRTF_RT_LEDS, - .mask = NIRTF_RT_LEDS_USER2_YELLOW, - }, -}; +/*===================================================================== + * ACPI NI physical interface element support + *===================================================================*/ + +/* Note that callers of this function are responsible for deallocating + * the buffer allocated by acpi_evaluate_object() by calling + * kfree() on the pointer passed back in result_buffer. + */ +static int nirtfeatures_call_acpi_method(struct nirtfeatures *nirtfeatures, + const char *method_name, + int argc, + union acpi_object *argv, + acpi_size *result_size, + void **result_buffer) +{ + acpi_status acpi_ret; + acpi_handle acpi_hdl; + struct acpi_object_list acpi_params; + struct acpi_buffer acpi_result = { ACPI_ALLOCATE_BUFFER, NULL }; + + if (NULL == nirtfeatures || NULL == result_size || + NULL == result_buffer) + return -EINVAL; + + acpi_ret = acpi_get_handle(nirtfeatures->acpi_device->handle, + (acpi_string) method_name, &acpi_hdl); + if (ACPI_FAILURE(acpi_ret)) { + dev_err(&nirtfeatures->acpi_device->dev, + "nirtfeatures: ACPI get handle for %s failed (%d)\n", + method_name, acpi_ret); + return -1; + } + + acpi_params.count = argc; + acpi_params.pointer = argv; + + acpi_ret = acpi_evaluate_object(acpi_hdl, NULL, + &acpi_params, &acpi_result); + if (ACPI_FAILURE(acpi_ret)) { + dev_err(&nirtfeatures->acpi_device->dev, + "nirtfeatures: ACPI evaluate for %s failed (%d)\n", + method_name, acpi_ret); + return -1; + } + + *result_size = acpi_result.length; + *result_buffer = acpi_result.pointer; + return 0; +} + +/* This is the generic PIE set state wrapper. It invokes the PIES + * ACPI method to modify the state of the given PIE. + */ +static int nirtfeatures_pie_set_state(struct nirtfeatures *nirtfeatures, + unsigned int element, unsigned int subelement, int state) +{ + union acpi_object pies_args[3]; + acpi_size result_size; + void *result_buffer; + union acpi_object *acpi_buffer; + int err = 0; + + if (NULL == nirtfeatures) + return -EINVAL; + + pies_args[0].type = ACPI_TYPE_INTEGER; + pies_args[0].integer.value = element; + pies_args[1].type = ACPI_TYPE_INTEGER; + pies_args[1].integer.value = subelement; + pies_args[2].type = ACPI_TYPE_INTEGER; + pies_args[2].integer.value = state; + + /* evaluate PIES(element, subelement, value) ACPI method */ + err = nirtfeatures_call_acpi_method(nirtfeatures, "PIES", + 3, &pies_args[0], &result_size, &result_buffer); + + if (err == 0) { + acpi_buffer = (union acpi_object *) result_buffer; + if (ACPI_TYPE_INTEGER == acpi_buffer->type) + err = (int) acpi_buffer->integer.value; + kfree(result_buffer); + } + + return err; +} + +/* This is the generic PIE get state wrapper. It invokes the PIEG + * ACPI method to query the state of the given PIE. + */ +static int nirtfeatures_pie_get_state(struct nirtfeatures *nirtfeatures, + unsigned int element, unsigned int subelement, int *result) +{ + union acpi_object pies_args[2]; + acpi_size result_size; + void *result_buffer; + union acpi_object *acpi_buffer; + int err = 0; + + if (NULL == nirtfeatures || NULL == result) + return -EINVAL; + + pies_args[0].type = ACPI_TYPE_INTEGER; + pies_args[0].integer.value = element; + pies_args[1].type = ACPI_TYPE_INTEGER; + pies_args[1].integer.value = subelement; + + /* evaluate PIEG(element, subelement) ACPI method */ + err = nirtfeatures_call_acpi_method(nirtfeatures, "PIEG", + 2, &pies_args[0], &result_size, &result_buffer); + + if (err == 0) { + acpi_buffer = (union acpi_object *) result_buffer; + if (ACPI_TYPE_INTEGER == acpi_buffer->type) + *result = (int) acpi_buffer->integer.value; + kfree(result_buffer); + } + + return err; +} + +/* This function enables or disables notifications for a particular + * input class PIE. + */ +static int nirtfeatures_pie_enable_notifications( + struct nirtfeatures *nirtfeatures, + unsigned int element, unsigned int subelement, int enable) +{ + union acpi_object pies_args[3]; + acpi_size result_size; + void *result_buffer; + union acpi_object *acpi_buffer; + int err = 0; + + if (NULL == nirtfeatures) + return -EINVAL; + + pies_args[0].type = ACPI_TYPE_INTEGER; + pies_args[0].integer.value = element; + pies_args[1].type = ACPI_TYPE_INTEGER; + pies_args[1].integer.value = subelement; + pies_args[2].type = ACPI_TYPE_INTEGER; + pies_args[2].integer.value = enable; + + /* evaluate PIEF(element, subelement, enable) ACPI method */ + err = nirtfeatures_call_acpi_method(nirtfeatures, "PIEF", + 3, &pies_args[0], &result_size, &result_buffer); + + if (err == 0) { + acpi_buffer = (union acpi_object *) result_buffer; + if (ACPI_TYPE_INTEGER == acpi_buffer->type) + err = (int) acpi_buffer->integer.value; + kfree(result_buffer); + } + + return err; +} + +/* This is the set_brightness callback for a PIE-enumerated LED. + */ +static void nirtfeatures_led_pie_brightness_set( + struct led_classdev *led_cdev, enum led_brightness brightness) +{ + struct nirtfeatures_led *led = (struct nirtfeatures_led *)led_cdev; + + spin_lock(&led->nirtfeatures->lock); + + /* Delegate the control of the PIE to the ACPI method. */ + if (nirtfeatures_pie_set_state(led->nirtfeatures, + led->pie_location.element, led->pie_location.subelement, + brightness)) { + dev_err(&led->nirtfeatures->acpi_device->dev, + "nirtfeatures: set brightness failed for %s\n", + led->name_string); + } + + spin_unlock(&led->nirtfeatures->lock); +} + +/* This is the get_brightness callback for a PIE-enumerated LED. + */ +static enum led_brightness nirtfeatures_led_pie_brightness_get( + struct led_classdev *led_cdev) +{ + struct nirtfeatures_led *led = (struct nirtfeatures_led *)led_cdev; + int state = 0; + + spin_lock(&led->nirtfeatures->lock); + + if (nirtfeatures_pie_get_state(led->nirtfeatures, + led->pie_location.element, led->pie_location.subelement, &state)) { + dev_err(&led->nirtfeatures->acpi_device->dev, + "nirtfeatures: get brightness failed for %s\n", + led->name_string); + } + + spin_unlock(&led->nirtfeatures->lock); + return state; +} + +/* Parse a PIE LED color caps package and populate the + * corresponding nirtfeatures_pie_descriptor_led_color structure. + */ +static int nirtfeatures_parse_led_pie_color(struct nirtfeatures *nirtfeatures, + unsigned int pie_caps_version, + struct nirtfeatures_pie_descriptor_led_color *led_color_descriptor, + union acpi_object *acpi_buffer) +{ + unsigned int i; + + if (NULL == nirtfeatures || NULL == led_color_descriptor || + NULL == acpi_buffer) + return -EINVAL; + + /* element 0 of a PIE LED color caps package is the name */ + if (ACPI_TYPE_BUFFER == acpi_buffer->package.elements[0].type) { + for (i = 0; + i < acpi_buffer->package.elements[0].buffer.length; i++) { + /* get pointer to Nth Unicode character in name */ + unsigned short *unicode_char = (unsigned short *) + (acpi_buffer->package.elements[0].buffer.pointer + + (2 * i)); + /* naive convert to ASCII */ + led_color_descriptor->name[i] = + (char) *unicode_char & 0xff; + } + } else + return -EINVAL; + + /* element 1 is the brightness min value */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[1].type) + led_color_descriptor->brightness_range_low = + (int) acpi_buffer->package.elements[1].integer.value; + else + return -EINVAL; + + /* element 2 is the brightness max value */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[2].type) + led_color_descriptor->brightness_range_high = + (int) acpi_buffer->package.elements[2].integer.value; + else + return -EINVAL; + + return 0; +} + +/* Parse a PIE LED caps package and create an LED class device + * with the appropriate metadata. + */ +static int nirtfeatures_parse_led_pie( + struct nirtfeatures *nirtfeatures, + unsigned int pie_caps_version, + unsigned int pie_element, + struct nirtfeatures_pie_descriptor *pie, + union acpi_object *acpi_buffer) +{ + unsigned int num_colors; + unsigned int i; + struct nirtfeatures_pie_descriptor_led_color led_descriptor; + struct nirtfeatures_led *led_dev; + int err; + + if (NULL == nirtfeatures || NULL == pie || + NULL == acpi_buffer) + return -EINVAL; + + if (ACPI_TYPE_PACKAGE != acpi_buffer->type) + return -EINVAL; + + /* element 0 is the number of colors */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[0].type) { + num_colors = (unsigned int) + acpi_buffer->package.elements[0].integer.value; + } else { + return -EINVAL; + } + + /* parse color caps and create LED class device */ + for (i = 0; i < num_colors; i++) { + if (nirtfeatures_parse_led_pie_color(nirtfeatures, + pie_caps_version, &led_descriptor, + &(acpi_buffer->package.elements[i + 1]))) + return -EINVAL; + + /* create an LED class device for this LED */ + led_dev = kzalloc(sizeof(struct nirtfeatures_led), GFP_KERNEL); + if (NULL == led_dev) + return -ENOMEM; + + /* for compatibility with existing LVRT support, PIEs beginning + * with 'user' should not affix the uservisible attribute to + * their name */ + if (strncasecmp(pie->name, "user", strlen("user")) != 0) { + snprintf(led_dev->name_string, MAX_NODELEN, + "%s:%s:%s:uservisible=%d", + CONFIG_NI_LED_PREFIX, + pie->name, led_descriptor.name, + pie->is_user_visible); + } else { + snprintf(led_dev->name_string, MAX_NODELEN, + "%s:%s:%s", + CONFIG_NI_LED_PREFIX, + pie->name, led_descriptor.name); + } + + led_dev->cdev.name = led_dev->name_string; + led_dev->cdev.brightness = + led_descriptor.brightness_range_low; + led_dev->cdev.max_brightness = + led_descriptor.brightness_range_high; + led_dev->cdev.brightness_set = + nirtfeatures_led_pie_brightness_set; + led_dev->cdev.brightness_get = + nirtfeatures_led_pie_brightness_get; + led_dev->nirtfeatures = nirtfeatures; + led_dev->pie_location.element = pie_element; + led_dev->pie_location.subelement = i; + + err = led_classdev_register(&nirtfeatures->acpi_device->dev, + &led_dev->cdev); + if (0 != err) { + kfree(led_dev); + return err; + } + + list_add_tail(&led_dev->node, &nirtfeatures_led_pie_list); + } + + return 0; +} + +/* Parse a PIE switch caps package and create an input class device + * with the appropriate metadata. + */ +static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, + unsigned int pie_caps_version, + unsigned int pie_element, + struct nirtfeatures_pie_descriptor *pie, + union acpi_object *acpi_buffer) +{ + unsigned int num_states; + unsigned int i; + struct nirtfeatures_pie_descriptor_switch *switch_descriptor = NULL; + struct nirtfeatures_switch *switch_dev = NULL; + int err = 0; + + if (NULL == nirtfeatures || NULL == pie || NULL == acpi_buffer) + return -EINVAL; + + if (ACPI_TYPE_PACKAGE != acpi_buffer->type) + return -EINVAL; + + /* element 0 is the number of states */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[0].type) + num_states = (unsigned int) + acpi_buffer->package.elements[0].integer.value; + else + return -EINVAL; + + /* allocate storage for switch descriptor */ + switch_descriptor = kzalloc( + sizeof(struct nirtfeatures_pie_descriptor_switch) + + sizeof(int) * (num_states - 1), GFP_KERNEL); + if (NULL == switch_descriptor) + return -ENOMEM; + + switch_descriptor->num_states = num_states; + + /* parse individual states in elements 1..N-1 */ + for (i = 0; i < num_states; i++) { + if (ACPI_TYPE_INTEGER != + acpi_buffer->package.elements[i + 1].type) { + err = -EINVAL; + goto exit; + } + + switch_descriptor->state_value[i] = + (int) acpi_buffer->package.elements[i + 1].integer.value; + } + + /* create an input class device for this switch */ + switch_dev = kzalloc(sizeof(struct nirtfeatures_switch), GFP_KERNEL); + if (NULL == switch_dev) { + err = -ENOMEM; + goto exit; + } + + switch_dev->cdev = input_allocate_device(); + if (NULL == switch_dev->cdev) { + err = -ENOMEM; + goto exit_dealloc_switch_dev; + } + + switch_dev->nirtfeatures = nirtfeatures; + switch_dev->pie_location.element = pie_element; + switch_dev->pie_location.subelement = 0; + memcpy(&switch_dev->pie_descriptor, pie, + sizeof(struct nirtfeatures_pie_descriptor)); + + snprintf(switch_dev->name_string, MAX_NODELEN, + "%s:%s:uservisible=%d:states=(", + CONFIG_NI_LED_PREFIX, pie->name, pie->is_user_visible); + for (i = 0; i < switch_descriptor->num_states; i++) { + char temp[4] = { '\0' }; + + sprintf(temp, "%d%c", switch_descriptor->state_value[i], + (i < switch_descriptor->num_states - 1) ? ',' : ')'); + strncat(switch_dev->name_string, temp, MAX_NODELEN); + } + + snprintf(switch_dev->phys_location_string, MAX_NODELEN, "%s/%s/%s", + CONFIG_NI_LED_PREFIX, nirtfeatures->bpstring, pie->name); + + switch_dev->cdev->name = switch_dev->name_string; + switch_dev->cdev->phys = switch_dev->phys_location_string; + switch_dev->cdev->id.bustype = BUS_HOST; + switch_dev->cdev->id.vendor = 0x3923; + switch_dev->cdev->id.product = pie->pie_type; + switch_dev->cdev->id.version = pie_caps_version; + switch_dev->cdev->dev.parent = &nirtfeatures->acpi_device->dev; + + switch_dev->cdev->evbit[0] = BIT_MASK(EV_KEY); + set_bit(BTN_0, switch_dev->cdev->keybit); + + err = input_register_device(switch_dev->cdev); + if (0 != err) { + input_free_device(switch_dev->cdev); + goto exit_dealloc_switch_dev; + } + + /* if this PIE supports notifications, enable them now */ + if (pie->notification_value != 0) { + err = nirtfeatures_pie_enable_notifications(nirtfeatures, + pie_element, 0, 1); + if (0 != err) { + input_unregister_device(switch_dev->cdev); + input_free_device(switch_dev->cdev); + goto exit_dealloc_switch_dev; + } + } + + /* add the new device to our list of switch PIEs */ + list_add_tail(&switch_dev->node, &nirtfeatures_switch_pie_list); + goto exit; + +exit_dealloc_switch_dev: + kfree(switch_dev); + +exit: + kfree(switch_descriptor); + return err; +} + + +/* Parse a single PIE caps package from the PIEC buffer, determine the + * type of PIE it is, then dispatch to the appropriate parsing routine. + */ +static int nirtfeatures_parse_one_pie(struct nirtfeatures *nirtfeatures, + unsigned int pie_caps_version, + unsigned int pie_element, + union acpi_object *acpi_buffer) +{ + struct nirtfeatures_pie_descriptor pie; + unsigned int i; + + if (NULL == nirtfeatures || NULL == acpi_buffer) + return -EINVAL; + + /* check for proper type and number of elements */ + if (ACPI_TYPE_PACKAGE != acpi_buffer->type || + 6 != acpi_buffer->package.count) + return -EINVAL; + + /* element 0 of the package is the name */ + if (ACPI_TYPE_BUFFER == acpi_buffer->package.elements[0].type) { + for (i = 0; + i < acpi_buffer->package.elements[0].buffer.length && + i < MAX_NAMELEN; i++) { + /* get pointer to Nth Unicode character in name */ + unsigned short *unicode_char = (unsigned short *) + (acpi_buffer->package.elements[0].buffer.pointer + + (2 * i)); + /* naive convert to ASCII */ + pie.name[i] = (char) *unicode_char & 0xff; + } + } else + return -EINVAL; + + /* element 1 of the package is the PIE class */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[1].type) + pie.pie_class = (enum nirtfeatures_pie_class) + acpi_buffer->package.elements[1].integer.value; + else + return -EINVAL; + + /* element 2 of the package is the PIE type */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[2].type) + pie.pie_type = (enum nirtfeatures_pie_type) + acpi_buffer->package.elements[2].integer.value; + else + return -EINVAL; + + /* element 4 of an package is the visible flag */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[4].type) + pie.is_user_visible = + (acpi_buffer->package.elements[4].integer.value != 0); + else + return -EINVAL; + + /* element 5 of the package is the notification value */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[5].type) + pie.notification_value = + acpi_buffer->package.elements[5].integer.value; + else + return -EINVAL; + + /* parse the type-specific descriptor in element 3 */ + switch (pie.pie_type) { + case PIE_TYPE_LED: + if (nirtfeatures_parse_led_pie(nirtfeatures, + pie_caps_version, pie_element, &pie, + &(acpi_buffer->package.elements[3]))) + return -EINVAL; + break; + case PIE_TYPE_SWITCH: + if (nirtfeatures_parse_switch_pie(nirtfeatures, + pie_caps_version, pie_element, &pie, + &(acpi_buffer->package.elements[3]))) + return -EINVAL; + break; + + default: + return -EINVAL; + break; + } + + return 0; +} + +/* Populate the list of physical interface elements from the table in + * the DSDT and then generate the appropriate class devices. + */ +static int nirtfeatures_populate_pies(struct nirtfeatures *nirtfeatures) +{ + acpi_size result_size; + void *result_buffer; + union acpi_object *acpi_buffer; + unsigned int num_elements = 0; + unsigned int pie_caps_version; + unsigned int i; + unsigned int err = 0; + + if (NULL == nirtfeatures) + return -EINVAL; + + /* get the PIE descriptor buffer from DSDT */ + if (nirtfeatures_call_acpi_method(nirtfeatures, + "PIEC", 0, NULL, &result_size, &result_buffer)) + return -1; + + acpi_buffer = (union acpi_object *) result_buffer; + if (ACPI_TYPE_PACKAGE != acpi_buffer->type) { + err = -1; + goto exit; + } + + /* the first element of the package is the caps version */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[0].type) + pie_caps_version = (unsigned int) + acpi_buffer->package.elements[0].integer.value; + else { + err = -1; + goto exit; + } + + if (pie_caps_version < MIN_PIE_CAPS_VERSION || + pie_caps_version > MAX_PIE_CAPS_VERSION) { + dev_err(&nirtfeatures->acpi_device->dev, + "nirtfeatures: invalid PIE caps version\n"); + err = -1; + goto exit; + } + + /* the second element of the package is the number of PIEs */ + if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[1].type) + num_elements = (unsigned int) + acpi_buffer->package.elements[1].integer.value; + else { + err = -1; + goto exit; + } + + /* parse elements 2..N as PIE descriptors */ + for (i = 2; i < acpi_buffer->package.count; i++) { + err = nirtfeatures_parse_one_pie(nirtfeatures, + pie_caps_version, i - 2, + &(acpi_buffer->package.elements[i])); + if (0 != err) + break; + } + +exit: + kfree(result_buffer); + return err; +} static int nirtfeatures_create_leds(struct nirtfeatures *nirtfeatures) { @@ -474,37 +1102,57 @@ static int nirtfeatures_create_leds(struct nirtfeatures *nirtfeatures) return err; } - for (i = 0; i < nirtfeatures->num_extra_leds; ++i) { + return 0; +} - nirtfeatures->extra_leds[i].nirtfeatures = nirtfeatures; +static void nirtfeatures_remove_leds(struct nirtfeatures *nirtfeatures) +{ + int i; - if (0 == nirtfeatures->extra_leds[i].cdev.max_brightness) - nirtfeatures->extra_leds[i].cdev.max_brightness = 1; + for (i = 0; i < ARRAY_SIZE(nirtfeatures_leds_common); ++i) + led_classdev_unregister(&nirtfeatures_leds_common[i].cdev); +} - nirtfeatures->extra_leds[i].cdev.brightness_set = - nirtfeatures_led_brightness_set; +static void nirtfeatures_remove_led_pies(struct nirtfeatures *nirtfeatures) +{ + struct nirtfeatures_led *cdev_iter; + struct nirtfeatures_led *temp; - nirtfeatures->extra_leds[i].cdev.brightness_get = - nirtfeatures_led_brightness_get; + spin_lock(&nirtfeatures->lock); - err = led_classdev_register(&nirtfeatures->acpi_device->dev, - &nirtfeatures->extra_leds[i].cdev); - if (err) - return err; + /* walk the list of non-fixed LEDs and unregister/free their devices */ + list_for_each_entry_safe( + cdev_iter, temp, &nirtfeatures_led_pie_list, node) { + led_classdev_unregister(&cdev_iter->cdev); + kfree(cdev_iter); } - return 0; + spin_unlock(&nirtfeatures->lock); } -static void nirtfeatures_remove_leds(struct nirtfeatures *nirtfeatures) +static void nirtfeatures_remove_switch_pies(struct nirtfeatures *nirtfeatures) { - int i; + struct nirtfeatures_switch *cdev_iter; + struct nirtfeatures_switch *temp; - for (i = 0; i < ARRAY_SIZE(nirtfeatures_leds_common); ++i) - led_classdev_unregister(&nirtfeatures_leds_common[i].cdev); + spin_lock(&nirtfeatures->lock); + + /* walk the list of switch devices and unregister/free each one */ + list_for_each_entry_safe( + cdev_iter, temp, &nirtfeatures_switch_pie_list, node) { + /* disable notifications for this PIE if supported */ + if (cdev_iter->pie_descriptor.notification_value != 0) { + nirtfeatures_pie_enable_notifications(nirtfeatures, + cdev_iter->pie_location.element, + cdev_iter->pie_location.subelement, + 0); + } + input_unregister_device(cdev_iter->cdev); + input_free_device(cdev_iter->cdev); + kfree(cdev_iter); + } - for (i = 0; i < nirtfeatures->num_extra_leds; ++i) - led_classdev_unregister(&nirtfeatures->extra_leds[i].cdev); + spin_unlock(&nirtfeatures->lock); } /* ACPI driver */ @@ -540,12 +1188,53 @@ static acpi_status nirtfeatures_resources(struct acpi_resource *res, void *data) return AE_OK; } +/* Process a notification from ACPI, which typically occurs when a switch + * PIE is signalling a change of state via its GPE. + */ +static void nirtfeatures_acpi_notify(struct acpi_device *device, u32 event) +{ + /* find the switch PIE for which this notification was generated, + * and push an event into its associated input subsystem node + */ + struct nirtfeatures_switch *iter; + int state = 0; + struct nirtfeatures *nirtfeatures = + (struct nirtfeatures *)device->driver_data; + + spin_lock(&nirtfeatures->lock); + + list_for_each_entry(iter, &nirtfeatures_switch_pie_list, node) { + if (event == iter->pie_descriptor.notification_value) { + + /* query instantaneous switch state */ + if (!nirtfeatures_pie_get_state(iter->nirtfeatures, + iter->pie_location.element, + iter->pie_location.subelement, + &state)) { + /* push current state of switch */ + input_report_key(iter->cdev, BTN_0, !!state); + input_sync(iter->cdev); + } + spin_unlock(&nirtfeatures->lock); + return; + } + } + + spin_unlock(&nirtfeatures->lock); + + dev_err(&device->dev, "no input found for notification (event %02X)\n", + event); +} + static void nirtfeatures_acpi_remove(struct acpi_device *device) { struct nirtfeatures *nirtfeatures = device->driver_data; nirtfeatures_remove_leds(nirtfeatures); + nirtfeatures_remove_led_pies(nirtfeatures); + nirtfeatures_remove_switch_pies(nirtfeatures); + sysfs_remove_files(&nirtfeatures->acpi_device->dev.kobj, nirtfeatures_attrs); @@ -600,15 +1289,9 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) break; case NIRTF_PLATFORM_MISC_ID_HAMMERHEAD: nirtfeatures->bpstring = "Hammerhead"; - nirtfeatures->extra_leds = nirtfeatures_leds_cdaq; - nirtfeatures->num_extra_leds = - ARRAY_SIZE(nirtfeatures_leds_cdaq); break; case NIRTF_PLATFORM_MISC_ID_WINGHEAD: nirtfeatures->bpstring = "Winghead"; - nirtfeatures->extra_leds = nirtfeatures_leds_cdaq; - nirtfeatures->num_extra_leds = - ARRAY_SIZE(nirtfeatures_leds_cdaq); break; default: dev_err(&nirtfeatures->acpi_device->dev, @@ -620,6 +1303,12 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) spin_lock_init(&nirtfeatures->lock); + err = nirtfeatures_populate_pies(nirtfeatures); + if (0 != err) { + nirtfeatures_acpi_remove(device); + return err; + } + nirtfeatures->revision[0] = inb(nirtfeatures->io_base + NIRTF_YEAR); nirtfeatures->revision[1] = inb(nirtfeatures->io_base + NIRTF_MONTH); nirtfeatures->revision[2] = inb(nirtfeatures->io_base + NIRTF_DAY); @@ -658,6 +1347,7 @@ static struct acpi_driver nirtfeatures_acpi_driver = { .ops = { .add = nirtfeatures_acpi_add, .remove = nirtfeatures_acpi_remove, + .notify = nirtfeatures_acpi_notify, }, }; From 53f897c95a25c101a14e9fd8920d6f1260c0d7ef Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Tue, 29 Sep 2015 12:45:12 -0500 Subject: [PATCH 21/83] nirtfeatures: Don't rename wifi LEDs For compatibility with myRIO, don't change the name of the wireless PIE LEDs. Signed-off-by: Nathan Sullivan Reviewed-by: Jaeden Amero Reviewed-by: Josh Cartwright Natinst-ReviewBoard-ID: 107067 Natinst-CAR-ID: 540272 --- drivers/misc/nirtfeatures.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 1ae01b7a4ad2a..9a7d438c05416 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -762,9 +762,10 @@ static int nirtfeatures_parse_led_pie( return -ENOMEM; /* for compatibility with existing LVRT support, PIEs beginning - * with 'user' should not affix the uservisible attribute to - * their name */ - if (strncasecmp(pie->name, "user", strlen("user")) != 0) { + * with 'user' or 'wifi' should not affix the uservisible + * attribute to their name */ + if (strncasecmp(pie->name, "user", strlen("user")) != 0 && + strncasecmp(pie->name, "wifi", strlen("wifi")) != 0) { snprintf(led_dev->name_string, MAX_NODELEN, "%s:%s:%s:uservisible=%d", CONFIG_NI_LED_PREFIX, From 989ef26812949cea956169efe9e0c781d8f351dd Mon Sep 17 00:00:00 2001 From: James Minor Date: Tue, 9 Aug 2016 13:50:02 -0500 Subject: [PATCH 22/83] nirtfeatures: Add control for WiFi reset as a vmmc regulator The MMC driver will enable/disable external regulators as part of enabling/disabling the SD Host Controller. The WLAN_PWD_L line (controlled from the CPLD) must be enabled/disabled at the same time that the controller is enabled/disabled. Allow the MMC driver to just control that pin directly via the regulator framework. Signed-off-by: James Minor --- drivers/misc/Kconfig | 1 + drivers/misc/nirtfeatures.c | 127 +++++++++++++++++++++++++++++++++++- 2 files changed, 126 insertions(+), 2 deletions(-) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 87b245bfa213b..2fb4788c7c92b 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -613,6 +613,7 @@ config MARVELL_CN10K_DPI config NI_RT_FEATURES bool "NI 903x/913x support" depends on X86 && ACPI + select REGULATOR help This driver exposes LEDs and other features of NI 903x/913x Real-Time controllers. diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 9a7d438c05416..ea2978c4692f5 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -18,6 +18,8 @@ #include #include #include +#include +#include #define MODULE_NAME "nirtfeatures" @@ -36,6 +38,7 @@ #define NIRTF_STATUS_LED_SHIFT1 0x21 #define NIRTF_STATUS_LED_SHIFT0 0x22 #define NIRTF_RT_LEDS 0x23 +#define NIRTF_WLAN_CONTROLREG 0x32 #define NIRTF_IO_SIZE 0x40 @@ -59,6 +62,9 @@ #define NIRTF_SYSTEM_LEDS_POWER_GREEN 0x02 #define NIRTF_SYSTEM_LEDS_POWER_YELLOW 0x01 +#define NIRTF_WLAN_RESET_N 0x02 +#define NIRTF_WLAN_RESETENABLE 0x01 + /*===================================================================== * ACPI NI physical interface element support *===================================================================*/ @@ -112,6 +118,8 @@ struct nirtfeatures { spinlock_t lock; u8 revision[5]; const char *bpstring; + bool has_wifi; + struct regulator_dev *reg_dev; }; struct nirtfeatures_led { @@ -733,6 +741,7 @@ static int nirtfeatures_parse_led_pie( struct nirtfeatures_pie_descriptor_led_color led_descriptor; struct nirtfeatures_led *led_dev; int err; + int is_wifi, is_user; if (NULL == nirtfeatures || NULL == pie || NULL == acpi_buffer) @@ -764,8 +773,10 @@ static int nirtfeatures_parse_led_pie( /* for compatibility with existing LVRT support, PIEs beginning * with 'user' or 'wifi' should not affix the uservisible * attribute to their name */ - if (strncasecmp(pie->name, "user", strlen("user")) != 0 && - strncasecmp(pie->name, "wifi", strlen("wifi")) != 0) { + is_user = strncasecmp(pie->name, "user", strlen("user")); + is_wifi = strncasecmp(pie->name, "wifi", strlen("wifi")); + if (is_user != 0 && + is_wifi != 0) { snprintf(led_dev->name_string, MAX_NODELEN, "%s:%s:%s:uservisible=%d", CONFIG_NI_LED_PREFIX, @@ -778,6 +789,10 @@ static int nirtfeatures_parse_led_pie( pie->name, led_descriptor.name); } + /* The presence of any WiFi LED means this target has wifi */ + if (is_wifi == 0) + nirtfeatures->has_wifi = true; + led_dev->cdev.name = led_dev->name_string; led_dev->cdev.brightness = led_descriptor.brightness_range_low; @@ -1239,6 +1254,9 @@ static void nirtfeatures_acpi_remove(struct acpi_device *device) sysfs_remove_files(&nirtfeatures->acpi_device->dev.kobj, nirtfeatures_attrs); + if (nirtfeatures->reg_dev) + regulator_unregister(nirtfeatures->reg_dev); + if ((nirtfeatures->io_base != 0) && (nirtfeatures->io_size == NIRTF_IO_SIZE)) release_region(nirtfeatures->io_base, nirtfeatures->io_size); @@ -1248,6 +1266,102 @@ static void nirtfeatures_acpi_remove(struct acpi_device *device) kfree(nirtfeatures); } +static int nirtfeatures_wifi_regulator_list_voltage(struct regulator_dev *dev, + unsigned selector) +{ + return 3300000; +} + +static int nirtfeatures_wifi_regulator_enable(struct regulator_dev *dev) +{ + struct nirtfeatures *nirtfeatures; + + nirtfeatures = rdev_get_drvdata(dev); + + /* WiFi out of Reset */ + outb(NIRTF_WLAN_RESET_N | NIRTF_WLAN_RESETENABLE, + nirtfeatures->io_base + NIRTF_WLAN_CONTROLREG); + /* WiFi Reset Disable */ + outb(NIRTF_WLAN_RESET_N, + nirtfeatures->io_base + NIRTF_WLAN_CONTROLREG); + + return 0; +} + +static int nirtfeatures_wifi_regulator_disable(struct regulator_dev *dev) +{ + struct nirtfeatures *nirtfeatures; + + nirtfeatures = rdev_get_drvdata(dev); + + /* WiFi Reset Enable */ + outb(NIRTF_WLAN_RESET_N | NIRTF_WLAN_RESETENABLE, + nirtfeatures->io_base + NIRTF_WLAN_CONTROLREG); + /* WiFi into Reset */ + outb(NIRTF_WLAN_RESETENABLE, + nirtfeatures->io_base + NIRTF_WLAN_CONTROLREG); + + /* Silex specs say to assert reset for 5 us, make it 10 to be sure */ + usleep_range(10, 1000); + + return 0; +} + +static int nirtfeatures_wifi_regulator_is_enabled(struct regulator_dev *dev) +{ + struct nirtfeatures *nirtfeatures; + u8 data; + + nirtfeatures = rdev_get_drvdata(dev); + + data = inb(nirtfeatures->io_base + NIRTF_WLAN_CONTROLREG); + + return !!(data & NIRTF_WLAN_RESET_N); +} + +static struct regulator_ops nirtfeatures_wifi_regulator_voltage_ops = { + .list_voltage = nirtfeatures_wifi_regulator_list_voltage, + .enable = nirtfeatures_wifi_regulator_enable, + .disable = nirtfeatures_wifi_regulator_disable, + .is_enabled = nirtfeatures_wifi_regulator_is_enabled +}; + +static const struct regulator_desc nirtfeatures_wifi_regulator_desc = { + .name = "vmmc", + .id = -1, + .n_voltages = 1, + .ops = &nirtfeatures_wifi_regulator_voltage_ops, + .type = REGULATOR_VOLTAGE, + .owner = THIS_MODULE +}; + +static const struct regulator_init_data wifi_reset_init_data = { + .constraints = { + .min_uV = 3300000, + .max_uV = 3300000, + .valid_ops_mask = REGULATOR_CHANGE_STATUS, + } +}; + +static int nirtfeatures_wifi_regulator_init(struct device *dev, + struct nirtfeatures *nirtfeatures) +{ + struct regulator_config cfg = { }; + struct regulator_dev *reg_dev; + + cfg.dev = dev; + cfg.init_data = &wifi_reset_init_data; + cfg.driver_data = nirtfeatures; + reg_dev = regulator_register(&nirtfeatures_wifi_regulator_desc, + &cfg); + if (IS_ERR(reg_dev)) { + pr_err("Failed to register vmmc regulator for wifi\n"); + return -ENODEV; + } + nirtfeatures->reg_dev = reg_dev; + return 0; +} + static int nirtfeatures_acpi_add(struct acpi_device *device) { struct nirtfeatures *nirtfeatures; @@ -1334,6 +1448,15 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) nirtfeatures->io_base, nirtfeatures->io_base + nirtfeatures->io_size - 1); + if (nirtfeatures->has_wifi) { + err = nirtfeatures_wifi_regulator_init(&device->dev, + nirtfeatures); + if (0 != err) { + nirtfeatures_acpi_remove(device); + return err; + } + } + return 0; } From b76473e0d0e6872f879e21fddf6f06e3c0b71351 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Fri, 9 Sep 2016 13:07:35 -0500 Subject: [PATCH 23/83] nirtfeatures: Add Fire Eagle backplane ID Add the new Fire Eagle backplane ID so we stop complaining on boot. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Xander Huff Natinst-ReviewBoard-ID: 152156 --- drivers/misc/nirtfeatures.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index ea2978c4692f5..6d43c89b7ce4c 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -46,6 +46,7 @@ #define NIRTF_PLATFORM_MISC_ID_MASK 0x07 #define NIRTF_PLATFORM_MISC_ID_MANHATTAN 0 +#define NIRTF_PLATFORM_MISC_ID_FIRE_EAGLE 2 #define NIRTF_PLATFORM_MISC_ID_HAMMERHEAD 4 #define NIRTF_PLATFORM_MISC_ID_WINGHEAD 5 @@ -1402,6 +1403,9 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) case NIRTF_PLATFORM_MISC_ID_MANHATTAN: nirtfeatures->bpstring = "Manhattan"; break; + case NIRTF_PLATFORM_MISC_ID_FIRE_EAGLE: + nirtfeatures->bpstring = "Fire Eagle"; + break; case NIRTF_PLATFORM_MISC_ID_HAMMERHEAD: nirtfeatures->bpstring = "Hammerhead"; break; From 7c91729c294ae7c88e0054a67791121c26037be4 Mon Sep 17 00:00:00 2001 From: Xander Huff Date: Fri, 14 Oct 2016 13:54:00 -0500 Subject: [PATCH 24/83] nirtfeatures: Housecleaning of comments, comparisons, etc. Fix checkpatch warnings: Block comments use * on subsequent lines Block comments use a trailing */ on a separate line Comparisons should place the constant on the right side of the test break is not useful after a goto or return Signed-off-by: Xander Huff Natinst-ReviewBoard-ID: 157395 --- drivers/misc/nirtfeatures.c | 107 ++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 52 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 6d43c89b7ce4c..01c6af81caaae 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -68,7 +68,8 @@ /*===================================================================== * ACPI NI physical interface element support - *===================================================================*/ + *===================================================================== + */ #define MAX_NAMELEN 64 #define MAX_NODELEN 128 #define MIN_PIE_CAPS_VERSION 2 @@ -444,7 +445,8 @@ nirtfeatures_led_brightness_get(struct led_classdev *led_cdev) data = inb(led->nirtfeatures->io_base + led->address); /* For the yellow status LED, the blink pattern used for brightness - on write is write-only, so we just return on/off for all LEDs. */ + * on write is write-only, so we just return on/off for all LEDs. + */ return (data & led->mask) ? LED_FULL : LED_OFF; } @@ -484,7 +486,8 @@ static struct nirtfeatures_led nirtfeatures_leds_common[] = { /*===================================================================== * ACPI NI physical interface element support - *===================================================================*/ + *===================================================================== + */ /* Note that callers of this function are responsible for deallocating * the buffer allocated by acpi_evaluate_object() by calling @@ -502,8 +505,8 @@ static int nirtfeatures_call_acpi_method(struct nirtfeatures *nirtfeatures, struct acpi_object_list acpi_params; struct acpi_buffer acpi_result = { ACPI_ALLOCATE_BUFFER, NULL }; - if (NULL == nirtfeatures || NULL == result_size || - NULL == result_buffer) + if (nirtfeatures == NULL || result_size == NULL || + result_buffer == NULL) return -EINVAL; acpi_ret = acpi_get_handle(nirtfeatures->acpi_device->handle, @@ -544,7 +547,7 @@ static int nirtfeatures_pie_set_state(struct nirtfeatures *nirtfeatures, union acpi_object *acpi_buffer; int err = 0; - if (NULL == nirtfeatures) + if (nirtfeatures == NULL) return -EINVAL; pies_args[0].type = ACPI_TYPE_INTEGER; @@ -560,7 +563,7 @@ static int nirtfeatures_pie_set_state(struct nirtfeatures *nirtfeatures, if (err == 0) { acpi_buffer = (union acpi_object *) result_buffer; - if (ACPI_TYPE_INTEGER == acpi_buffer->type) + if (acpi_buffer->type == ACPI_TYPE_INTEGER) err = (int) acpi_buffer->integer.value; kfree(result_buffer); } @@ -580,7 +583,7 @@ static int nirtfeatures_pie_get_state(struct nirtfeatures *nirtfeatures, union acpi_object *acpi_buffer; int err = 0; - if (NULL == nirtfeatures || NULL == result) + if (nirtfeatures == NULL || result == NULL) return -EINVAL; pies_args[0].type = ACPI_TYPE_INTEGER; @@ -594,7 +597,7 @@ static int nirtfeatures_pie_get_state(struct nirtfeatures *nirtfeatures, if (err == 0) { acpi_buffer = (union acpi_object *) result_buffer; - if (ACPI_TYPE_INTEGER == acpi_buffer->type) + if (acpi_buffer->type == ACPI_TYPE_INTEGER) *result = (int) acpi_buffer->integer.value; kfree(result_buffer); } @@ -615,7 +618,7 @@ static int nirtfeatures_pie_enable_notifications( union acpi_object *acpi_buffer; int err = 0; - if (NULL == nirtfeatures) + if (nirtfeatures == NULL) return -EINVAL; pies_args[0].type = ACPI_TYPE_INTEGER; @@ -631,7 +634,7 @@ static int nirtfeatures_pie_enable_notifications( if (err == 0) { acpi_buffer = (union acpi_object *) result_buffer; - if (ACPI_TYPE_INTEGER == acpi_buffer->type) + if (acpi_buffer->type == ACPI_TYPE_INTEGER) err = (int) acpi_buffer->integer.value; kfree(result_buffer); } @@ -691,12 +694,12 @@ static int nirtfeatures_parse_led_pie_color(struct nirtfeatures *nirtfeatures, { unsigned int i; - if (NULL == nirtfeatures || NULL == led_color_descriptor || - NULL == acpi_buffer) + if (nirtfeatures == NULL || led_color_descriptor == NULL || + acpi_buffer == NULL) return -EINVAL; /* element 0 of a PIE LED color caps package is the name */ - if (ACPI_TYPE_BUFFER == acpi_buffer->package.elements[0].type) { + if (acpi_buffer->package.elements[0].type == ACPI_TYPE_BUFFER) { for (i = 0; i < acpi_buffer->package.elements[0].buffer.length; i++) { /* get pointer to Nth Unicode character in name */ @@ -711,14 +714,14 @@ static int nirtfeatures_parse_led_pie_color(struct nirtfeatures *nirtfeatures, return -EINVAL; /* element 1 is the brightness min value */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[1].type) + if (acpi_buffer->package.elements[1].type == ACPI_TYPE_INTEGER) led_color_descriptor->brightness_range_low = (int) acpi_buffer->package.elements[1].integer.value; else return -EINVAL; /* element 2 is the brightness max value */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[2].type) + if (acpi_buffer->package.elements[2].type == ACPI_TYPE_INTEGER) led_color_descriptor->brightness_range_high = (int) acpi_buffer->package.elements[2].integer.value; else @@ -744,15 +747,15 @@ static int nirtfeatures_parse_led_pie( int err; int is_wifi, is_user; - if (NULL == nirtfeatures || NULL == pie || - NULL == acpi_buffer) + if (nirtfeatures == NULL || pie == NULL || + acpi_buffer == NULL) return -EINVAL; - if (ACPI_TYPE_PACKAGE != acpi_buffer->type) + if (acpi_buffer->type != ACPI_TYPE_PACKAGE) return -EINVAL; /* element 0 is the number of colors */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[0].type) { + if (acpi_buffer->package.elements[0].type == ACPI_TYPE_INTEGER) { num_colors = (unsigned int) acpi_buffer->package.elements[0].integer.value; } else { @@ -768,12 +771,13 @@ static int nirtfeatures_parse_led_pie( /* create an LED class device for this LED */ led_dev = kzalloc(sizeof(struct nirtfeatures_led), GFP_KERNEL); - if (NULL == led_dev) + if (led_dev == NULL) return -ENOMEM; /* for compatibility with existing LVRT support, PIEs beginning * with 'user' or 'wifi' should not affix the uservisible - * attribute to their name */ + * attribute to their name + */ is_user = strncasecmp(pie->name, "user", strlen("user")); is_wifi = strncasecmp(pie->name, "wifi", strlen("wifi")); if (is_user != 0 && @@ -809,7 +813,7 @@ static int nirtfeatures_parse_led_pie( err = led_classdev_register(&nirtfeatures->acpi_device->dev, &led_dev->cdev); - if (0 != err) { + if (err != 0) { kfree(led_dev); return err; } @@ -835,14 +839,14 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, struct nirtfeatures_switch *switch_dev = NULL; int err = 0; - if (NULL == nirtfeatures || NULL == pie || NULL == acpi_buffer) + if (nirtfeatures == NULL || pie == NULL || acpi_buffer == NULL) return -EINVAL; - if (ACPI_TYPE_PACKAGE != acpi_buffer->type) + if (acpi_buffer->type != ACPI_TYPE_PACKAGE) return -EINVAL; /* element 0 is the number of states */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[0].type) + if (acpi_buffer->package.elements[0].type == ACPI_TYPE_INTEGER) num_states = (unsigned int) acpi_buffer->package.elements[0].integer.value; else @@ -852,15 +856,15 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, switch_descriptor = kzalloc( sizeof(struct nirtfeatures_pie_descriptor_switch) + sizeof(int) * (num_states - 1), GFP_KERNEL); - if (NULL == switch_descriptor) + if (switch_descriptor == NULL) return -ENOMEM; switch_descriptor->num_states = num_states; /* parse individual states in elements 1..N-1 */ for (i = 0; i < num_states; i++) { - if (ACPI_TYPE_INTEGER != - acpi_buffer->package.elements[i + 1].type) { + if (acpi_buffer->package.elements[i + 1].type + != ACPI_TYPE_INTEGER) { err = -EINVAL; goto exit; } @@ -871,13 +875,13 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, /* create an input class device for this switch */ switch_dev = kzalloc(sizeof(struct nirtfeatures_switch), GFP_KERNEL); - if (NULL == switch_dev) { + if (switch_dev == NULL) { err = -ENOMEM; goto exit; } switch_dev->cdev = input_allocate_device(); - if (NULL == switch_dev->cdev) { + if (switch_dev->cdev == NULL) { err = -ENOMEM; goto exit_dealloc_switch_dev; } @@ -914,7 +918,7 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, set_bit(BTN_0, switch_dev->cdev->keybit); err = input_register_device(switch_dev->cdev); - if (0 != err) { + if (err != 0) { input_free_device(switch_dev->cdev); goto exit_dealloc_switch_dev; } @@ -923,7 +927,7 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, if (pie->notification_value != 0) { err = nirtfeatures_pie_enable_notifications(nirtfeatures, pie_element, 0, 1); - if (0 != err) { + if (err != 0) { input_unregister_device(switch_dev->cdev); input_free_device(switch_dev->cdev); goto exit_dealloc_switch_dev; @@ -954,16 +958,16 @@ static int nirtfeatures_parse_one_pie(struct nirtfeatures *nirtfeatures, struct nirtfeatures_pie_descriptor pie; unsigned int i; - if (NULL == nirtfeatures || NULL == acpi_buffer) + if (nirtfeatures == NULL || acpi_buffer == NULL) return -EINVAL; /* check for proper type and number of elements */ - if (ACPI_TYPE_PACKAGE != acpi_buffer->type || - 6 != acpi_buffer->package.count) + if (acpi_buffer->type != ACPI_TYPE_PACKAGE || + acpi_buffer->package.count != 6) return -EINVAL; /* element 0 of the package is the name */ - if (ACPI_TYPE_BUFFER == acpi_buffer->package.elements[0].type) { + if (acpi_buffer->package.elements[0].type == ACPI_TYPE_BUFFER) { for (i = 0; i < acpi_buffer->package.elements[0].buffer.length && i < MAX_NAMELEN; i++) { @@ -978,28 +982,28 @@ static int nirtfeatures_parse_one_pie(struct nirtfeatures *nirtfeatures, return -EINVAL; /* element 1 of the package is the PIE class */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[1].type) + if (acpi_buffer->package.elements[1].type == ACPI_TYPE_INTEGER) pie.pie_class = (enum nirtfeatures_pie_class) acpi_buffer->package.elements[1].integer.value; else return -EINVAL; /* element 2 of the package is the PIE type */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[2].type) + if (acpi_buffer->package.elements[2].type == ACPI_TYPE_INTEGER) pie.pie_type = (enum nirtfeatures_pie_type) acpi_buffer->package.elements[2].integer.value; else return -EINVAL; /* element 4 of an package is the visible flag */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[4].type) + if (acpi_buffer->package.elements[4].type == ACPI_TYPE_INTEGER) pie.is_user_visible = (acpi_buffer->package.elements[4].integer.value != 0); else return -EINVAL; /* element 5 of the package is the notification value */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[5].type) + if (acpi_buffer->package.elements[5].type == ACPI_TYPE_INTEGER) pie.notification_value = acpi_buffer->package.elements[5].integer.value; else @@ -1022,7 +1026,6 @@ static int nirtfeatures_parse_one_pie(struct nirtfeatures *nirtfeatures, default: return -EINVAL; - break; } return 0; @@ -1041,7 +1044,7 @@ static int nirtfeatures_populate_pies(struct nirtfeatures *nirtfeatures) unsigned int i; unsigned int err = 0; - if (NULL == nirtfeatures) + if (nirtfeatures == NULL) return -EINVAL; /* get the PIE descriptor buffer from DSDT */ @@ -1050,13 +1053,13 @@ static int nirtfeatures_populate_pies(struct nirtfeatures *nirtfeatures) return -1; acpi_buffer = (union acpi_object *) result_buffer; - if (ACPI_TYPE_PACKAGE != acpi_buffer->type) { + if (acpi_buffer->type != ACPI_TYPE_PACKAGE) { err = -1; goto exit; } /* the first element of the package is the caps version */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[0].type) + if (acpi_buffer->package.elements[0].type == ACPI_TYPE_INTEGER) pie_caps_version = (unsigned int) acpi_buffer->package.elements[0].integer.value; else { @@ -1073,7 +1076,7 @@ static int nirtfeatures_populate_pies(struct nirtfeatures *nirtfeatures) } /* the second element of the package is the number of PIEs */ - if (ACPI_TYPE_INTEGER == acpi_buffer->package.elements[1].type) + if (acpi_buffer->package.elements[1].type == ACPI_TYPE_INTEGER) num_elements = (unsigned int) acpi_buffer->package.elements[1].integer.value; else { @@ -1086,7 +1089,7 @@ static int nirtfeatures_populate_pies(struct nirtfeatures *nirtfeatures) err = nirtfeatures_parse_one_pie(nirtfeatures, pie_caps_version, i - 2, &(acpi_buffer->package.elements[i])); - if (0 != err) + if (err != 0) break; } @@ -1104,7 +1107,7 @@ static int nirtfeatures_create_leds(struct nirtfeatures *nirtfeatures) nirtfeatures_leds_common[i].nirtfeatures = nirtfeatures; - if (0 == nirtfeatures_leds_common[i].cdev.max_brightness) + if (nirtfeatures_leds_common[i].cdev.max_brightness == 0) nirtfeatures_leds_common[i].cdev.max_brightness = 1; nirtfeatures_leds_common[i].cdev.brightness_set = @@ -1423,7 +1426,7 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) spin_lock_init(&nirtfeatures->lock); err = nirtfeatures_populate_pies(nirtfeatures); - if (0 != err) { + if (err != 0) { nirtfeatures_acpi_remove(device); return err; } @@ -1436,13 +1439,13 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) err = sysfs_create_files(&nirtfeatures->acpi_device->dev.kobj, nirtfeatures_attrs); - if (0 != err) { + if (err != 0) { nirtfeatures_acpi_remove(device); return err; } err = nirtfeatures_create_leds(nirtfeatures); - if (0 != err) { + if (err != 0) { nirtfeatures_acpi_remove(device); return err; } @@ -1455,7 +1458,7 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) if (nirtfeatures->has_wifi) { err = nirtfeatures_wifi_regulator_init(&device->dev, nirtfeatures); - if (0 != err) { + if (err != 0) { nirtfeatures_acpi_remove(device); return err; } From ccb98808438993e143fe012a7b3becb6d1724515 Mon Sep 17 00:00:00 2001 From: Akash Mankar Date: Fri, 17 Feb 2017 16:52:58 -0600 Subject: [PATCH 25/83] nirtfeatures: Implement serial IRQ mechanism for user push button. This commit assumes that BIOS will implement a change to add a new field to PIEC capability structure. Also bumping the capabilities version by 1. Adding IRQ mechanism for user Push button instead of GPIO This change registers and requests an IRQ for User push button.Adds a new handler pushbutton_interrupt_handler() to handle the interrupt when the button is pressed or released. Adds a new field to struct nirtfeatures_pie_descriptor called notification_method. If this field is 1, it indicates interrupt mechanism. We check this field only for caps version=3 and pie_type=switch. Also bumps the MAX_PIE_CAPS_VERSION to 3. The kernel and BIOS have to be updated at the same time in order for this change to be successful. If kernel is updated first on a controller, user button will simply not function but will have no other side effects. If BIOS is updated first, then system will end in kernel panic and reboot constantly. Signed-off-by: Akash Mankar Signed-off-by: Brad Mouring Acked-by: Zach Hindes Acked-by: Aaron Rossetto Natinst-ReviewBoard-ID: 174593 --- drivers/misc/nirtfeatures.c | 85 ++++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 5 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 01c6af81caaae..3458cd44efed7 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -13,6 +13,7 @@ */ #include +#include #include #include #include @@ -73,7 +74,9 @@ #define MAX_NAMELEN 64 #define MAX_NODELEN 128 #define MIN_PIE_CAPS_VERSION 2 -#define MAX_PIE_CAPS_VERSION 2 +#define MAX_PIE_CAPS_VERSION 3 +#define NOTIFY_METHOD_INTERRUPT 1 +#define NOTIFY_METHOD_GPIO 0 enum nirtfeatures_pie_class { PIE_CLASS_INPUT = 0, @@ -92,6 +95,8 @@ struct nirtfeatures_pie_descriptor { enum nirtfeatures_pie_type pie_type; bool is_user_visible; unsigned int notification_value; + /* notification_method applicable only for caps version 3 & above */ + unsigned int notification_method; }; struct nirtfeatures_pie_descriptor_led_color { @@ -122,6 +127,7 @@ struct nirtfeatures { const char *bpstring; bool has_wifi; struct regulator_dev *reg_dev; + unsigned int irq; }; struct nirtfeatures_led { @@ -961,9 +967,14 @@ static int nirtfeatures_parse_one_pie(struct nirtfeatures *nirtfeatures, if (nirtfeatures == NULL || acpi_buffer == NULL) return -EINVAL; - /* check for proper type and number of elements */ + /* + * check for proper type and number of elements + * caps_version 2 or less, support only 6 elements in package + * caps_version 3 or more, support only up to 7 elements in package + */ if (acpi_buffer->type != ACPI_TYPE_PACKAGE || - acpi_buffer->package.count != 6) + (acpi_buffer->package.count != 6 && pie_caps_version < 3) || + (acpi_buffer->package.count > 7 && pie_caps_version >= 3)) return -EINVAL; /* element 0 of the package is the name */ @@ -1005,10 +1016,23 @@ static int nirtfeatures_parse_one_pie(struct nirtfeatures *nirtfeatures, /* element 5 of the package is the notification value */ if (acpi_buffer->package.elements[5].type == ACPI_TYPE_INTEGER) pie.notification_value = - acpi_buffer->package.elements[5].integer.value; + acpi_buffer->package.elements[5].integer.value; else return -EINVAL; + /* + * element 6 of the package is notification method + * used only for pie type switch and caps_Version >= 3 + * don't worry about it for lower caps versions. + */ + if (pie_caps_version >= 3 && pie.pie_type == PIE_TYPE_SWITCH) { + if (acpi_buffer->package.elements[6].type == ACPI_TYPE_INTEGER) + pie.notification_method = + acpi_buffer->package.elements[6].integer.value; + else + return -EINVAL; + } + /* parse the type-specific descriptor in element 3 */ switch (pie.pie_type) { case PIE_TYPE_LED: @@ -1175,13 +1199,64 @@ static void nirtfeatures_remove_switch_pies(struct nirtfeatures *nirtfeatures) spin_unlock(&nirtfeatures->lock); } +/* IRQ Handler for User push button */ +static irqreturn_t pushbutton_interrupt_handler(int irq, void *data) +{ + /* find the switch PIE for which this interrupt was generated */ + struct nirtfeatures_switch *iter; + struct nirtfeatures *nirtfeatures = (struct nirtfeatures *)data; + int state = 0; + + spin_lock(&nirtfeatures->lock); + list_for_each_entry(iter, &nirtfeatures_switch_pie_list, node) { + if (iter->pie_descriptor.notification_method == NOTIFY_METHOD_INTERRUPT && + iter->pie_descriptor.notification_value == irq) { + /* query instantaneous switch state */ + if (!nirtfeatures_pie_get_state(iter->nirtfeatures, + iter->pie_location.element, + iter->pie_location.subelement, + &state)) { + /* push current state of switch */ + input_report_key(iter->cdev, BTN_0, !!state); + input_sync(iter->cdev); + } + spin_unlock(&nirtfeatures->lock); + return IRQ_HANDLED; + } + } + spin_unlock(&nirtfeatures->lock); + return IRQ_NONE; +} + /* ACPI driver */ static acpi_status nirtfeatures_resources(struct acpi_resource *res, void *data) { struct nirtfeatures *nirtfeatures = data; + int err; switch (res->type) { + case ACPI_RESOURCE_TYPE_IRQ: + if (nirtfeatures->irq != 0) { + dev_err(&nirtfeatures->acpi_device->dev, + "too many IRQ resources\n"); + return AE_ERROR; + } + + nirtfeatures->irq = res->data.irq.interrupts[0]; + + err = devm_request_irq(&nirtfeatures->acpi_device->dev, + nirtfeatures->irq, + pushbutton_interrupt_handler, + 0 /*irq_flags*/, MODULE_NAME, + nirtfeatures); + if (err) { + dev_err(&nirtfeatures->acpi_device->dev, + "failed to request IRQ (err %d)\n", err); + return AE_ERROR; + } + return AE_OK; + case ACPI_RESOURCE_TYPE_IO: if ((nirtfeatures->io_base != 0) || (nirtfeatures->io_size != 0)) { @@ -1383,7 +1458,7 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) nirtfeatures->acpi_device = device; acpi_ret = acpi_walk_resources(device->handle, METHOD_NAME__CRS, - nirtfeatures_resources, nirtfeatures); + nirtfeatures_resources, nirtfeatures); if (ACPI_FAILURE(acpi_ret) || (nirtfeatures->io_base == 0) || From 9b6a5e79cf08116579caca37003fba3ca821c135 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Wed, 15 Feb 2017 09:12:38 -0600 Subject: [PATCH 26/83] nirtfeatures: Add Ironclad reset source string On Fire Eagle, the Ironclad ASIC has an internal watchdog which will reset the chip if the its firmware hangs. Unless we're in button- directed safemode, this will also reset the whole system. Add this reset reason to our strings so we can tell when this happens. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: James Minor Acked-by: Zach Brown Acked-by: Akash Mankar Natinst-ReviewBoard-ID: 176049 --- drivers/misc/nirtfeatures.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 3458cd44efed7..3077a5dca82fe 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -219,7 +219,7 @@ static ssize_t nirtfeatures_backplane_id_get(struct device *dev, static DEVICE_ATTR(backplane_id, S_IRUGO, nirtfeatures_backplane_id_get, NULL); static const char * const nirtfeatures_reset_source_strings[] = { - "button", "processor", "fpga", "watchdog", "software", + "button", "processor", "fpga", "watchdog", "software", "ironclad", }; static ssize_t nirtfeatures_reset_source_get(struct device *dev, From b882ca82c5475edfa22754c909e295ad999f2d15 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Thu, 16 Mar 2017 14:13:38 -0500 Subject: [PATCH 27/83] nirtfeatures: Use managed resource allocation Adding a new ACPI resource to device BIOS exposed the fact that our error handling on a failed device probe is very broken. To fix this, use managed allocation (devm_*) for all resources which support it. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: James Minor Acked-by: Zach Brown Acked-by: Akash Mankar Natinst-ReviewBoard-ID: 176049 [mpeterse: change return type of nirtfeatures_acpi_remove due to 6c0eb5ba3500] Signed-off-by: Mike Petersen --- drivers/misc/nirtfeatures.c | 191 +++++++++--------------------------- 1 file changed, 48 insertions(+), 143 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index 3077a5dca82fe..fcb6bcdf2ffab 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -776,7 +776,9 @@ static int nirtfeatures_parse_led_pie( return -EINVAL; /* create an LED class device for this LED */ - led_dev = kzalloc(sizeof(struct nirtfeatures_led), GFP_KERNEL); + led_dev = devm_kzalloc(&nirtfeatures->acpi_device->dev, + sizeof(struct nirtfeatures_led), + GFP_KERNEL); if (led_dev == NULL) return -ENOMEM; @@ -817,12 +819,10 @@ static int nirtfeatures_parse_led_pie( led_dev->pie_location.element = pie_element; led_dev->pie_location.subelement = i; - err = led_classdev_register(&nirtfeatures->acpi_device->dev, - &led_dev->cdev); - if (err != 0) { - kfree(led_dev); + err = devm_led_classdev_register(&nirtfeatures->acpi_device->dev, + &led_dev->cdev); + if (err) return err; - } list_add_tail(&led_dev->node, &nirtfeatures_led_pie_list); } @@ -844,6 +844,7 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, struct nirtfeatures_pie_descriptor_switch *switch_descriptor = NULL; struct nirtfeatures_switch *switch_dev = NULL; int err = 0; + struct device *dev = &nirtfeatures->acpi_device->dev; if (nirtfeatures == NULL || pie == NULL || acpi_buffer == NULL) return -EINVAL; @@ -859,9 +860,9 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, return -EINVAL; /* allocate storage for switch descriptor */ - switch_descriptor = kzalloc( - sizeof(struct nirtfeatures_pie_descriptor_switch) + - sizeof(int) * (num_states - 1), GFP_KERNEL); + switch_descriptor = devm_kzalloc(dev, sizeof(*switch_descriptor) + + sizeof(int) * (num_states - 1), + GFP_KERNEL); if (switch_descriptor == NULL) return -ENOMEM; @@ -869,28 +870,23 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, /* parse individual states in elements 1..N-1 */ for (i = 0; i < num_states; i++) { - if (acpi_buffer->package.elements[i + 1].type - != ACPI_TYPE_INTEGER) { - err = -EINVAL; - goto exit; - } + if (acpi_buffer->package.elements[i + 1].type != + ACPI_TYPE_INTEGER) + return -EINVAL; switch_descriptor->state_value[i] = (int) acpi_buffer->package.elements[i + 1].integer.value; } /* create an input class device for this switch */ - switch_dev = kzalloc(sizeof(struct nirtfeatures_switch), GFP_KERNEL); - if (switch_dev == NULL) { - err = -ENOMEM; - goto exit; - } + switch_dev = devm_kzalloc(dev, sizeof(struct nirtfeatures_switch), + GFP_KERNEL); + if (switch_dev == NULL) + return -ENOMEM; - switch_dev->cdev = input_allocate_device(); - if (switch_dev->cdev == NULL) { - err = -ENOMEM; - goto exit_dealloc_switch_dev; - } + switch_dev->cdev = devm_input_allocate_device(dev); + if (switch_dev->cdev == NULL) + return -ENOMEM; switch_dev->nirtfeatures = nirtfeatures; switch_dev->pie_location.element = pie_element; @@ -924,32 +920,21 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, set_bit(BTN_0, switch_dev->cdev->keybit); err = input_register_device(switch_dev->cdev); - if (err != 0) { - input_free_device(switch_dev->cdev); - goto exit_dealloc_switch_dev; - } + if (err) + return err; /* if this PIE supports notifications, enable them now */ if (pie->notification_value != 0) { err = nirtfeatures_pie_enable_notifications(nirtfeatures, - pie_element, 0, 1); - if (err != 0) { - input_unregister_device(switch_dev->cdev); - input_free_device(switch_dev->cdev); - goto exit_dealloc_switch_dev; - } + pie_element, 0, 1); + if (err) + return err; } /* add the new device to our list of switch PIEs */ list_add_tail(&switch_dev->node, &nirtfeatures_switch_pie_list); - goto exit; - -exit_dealloc_switch_dev: - kfree(switch_dev); -exit: - kfree(switch_descriptor); - return err; + return 0; } @@ -1140,8 +1125,8 @@ static int nirtfeatures_create_leds(struct nirtfeatures *nirtfeatures) nirtfeatures_leds_common[i].cdev.brightness_get = nirtfeatures_led_brightness_get; - err = led_classdev_register(&nirtfeatures->acpi_device->dev, - &nirtfeatures_leds_common[i].cdev); + err = devm_led_classdev_register(&nirtfeatures->acpi_device->dev, + &nirtfeatures_leds_common[i].cdev); if (err) return err; } @@ -1149,56 +1134,6 @@ static int nirtfeatures_create_leds(struct nirtfeatures *nirtfeatures) return 0; } -static void nirtfeatures_remove_leds(struct nirtfeatures *nirtfeatures) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(nirtfeatures_leds_common); ++i) - led_classdev_unregister(&nirtfeatures_leds_common[i].cdev); -} - -static void nirtfeatures_remove_led_pies(struct nirtfeatures *nirtfeatures) -{ - struct nirtfeatures_led *cdev_iter; - struct nirtfeatures_led *temp; - - spin_lock(&nirtfeatures->lock); - - /* walk the list of non-fixed LEDs and unregister/free their devices */ - list_for_each_entry_safe( - cdev_iter, temp, &nirtfeatures_led_pie_list, node) { - led_classdev_unregister(&cdev_iter->cdev); - kfree(cdev_iter); - } - - spin_unlock(&nirtfeatures->lock); -} - -static void nirtfeatures_remove_switch_pies(struct nirtfeatures *nirtfeatures) -{ - struct nirtfeatures_switch *cdev_iter; - struct nirtfeatures_switch *temp; - - spin_lock(&nirtfeatures->lock); - - /* walk the list of switch devices and unregister/free each one */ - list_for_each_entry_safe( - cdev_iter, temp, &nirtfeatures_switch_pie_list, node) { - /* disable notifications for this PIE if supported */ - if (cdev_iter->pie_descriptor.notification_value != 0) { - nirtfeatures_pie_enable_notifications(nirtfeatures, - cdev_iter->pie_location.element, - cdev_iter->pie_location.subelement, - 0); - } - input_unregister_device(cdev_iter->cdev); - input_free_device(cdev_iter->cdev); - kfree(cdev_iter); - } - - spin_unlock(&nirtfeatures->lock); -} - /* IRQ Handler for User push button */ static irqreturn_t pushbutton_interrupt_handler(int irq, void *data) { @@ -1323,26 +1258,7 @@ static void nirtfeatures_acpi_notify(struct acpi_device *device, u32 event) static void nirtfeatures_acpi_remove(struct acpi_device *device) { - struct nirtfeatures *nirtfeatures = device->driver_data; - - nirtfeatures_remove_leds(nirtfeatures); - - nirtfeatures_remove_led_pies(nirtfeatures); - nirtfeatures_remove_switch_pies(nirtfeatures); - - sysfs_remove_files(&nirtfeatures->acpi_device->dev.kobj, - nirtfeatures_attrs); - - if (nirtfeatures->reg_dev) - regulator_unregister(nirtfeatures->reg_dev); - - if ((nirtfeatures->io_base != 0) && - (nirtfeatures->io_size == NIRTF_IO_SIZE)) - release_region(nirtfeatures->io_base, nirtfeatures->io_size); - - device->driver_data = NULL; - - kfree(nirtfeatures); + sysfs_remove_files(&device->dev.kobj, nirtfeatures_attrs); } static int nirtfeatures_wifi_regulator_list_voltage(struct regulator_dev *dev, @@ -1431,8 +1347,9 @@ static int nirtfeatures_wifi_regulator_init(struct device *dev, cfg.dev = dev; cfg.init_data = &wifi_reset_init_data; cfg.driver_data = nirtfeatures; - reg_dev = regulator_register(&nirtfeatures_wifi_regulator_desc, - &cfg); + reg_dev = devm_regulator_register(dev, + &nirtfeatures_wifi_regulator_desc, + &cfg); if (IS_ERR(reg_dev)) { pr_err("Failed to register vmmc regulator for wifi\n"); return -ENODEV; @@ -1448,7 +1365,8 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) u8 bpinfo; int err; - nirtfeatures = kzalloc(sizeof(*nirtfeatures), GFP_KERNEL); + nirtfeatures = devm_kzalloc(&device->dev, sizeof(*nirtfeatures), + GFP_KERNEL); if (!nirtfeatures) return -ENOMEM; @@ -1462,16 +1380,12 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) if (ACPI_FAILURE(acpi_ret) || (nirtfeatures->io_base == 0) || - (nirtfeatures->io_size != NIRTF_IO_SIZE)) { - nirtfeatures_acpi_remove(device); + (nirtfeatures->io_size != NIRTF_IO_SIZE)) return -ENODEV; - } - if (!request_region(nirtfeatures->io_base, nirtfeatures->io_size, - MODULE_NAME)) { - nirtfeatures_acpi_remove(device); + if (!devm_request_region(&device->dev, nirtfeatures->io_base, + nirtfeatures->io_size, MODULE_NAME)) return -EBUSY; - } bpinfo = inb(nirtfeatures->io_base + NIRTF_PLATFORM_MISC); @@ -1501,10 +1415,8 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) spin_lock_init(&nirtfeatures->lock); err = nirtfeatures_populate_pies(nirtfeatures); - if (err != 0) { - nirtfeatures_acpi_remove(device); + if (err) return err; - } nirtfeatures->revision[0] = inb(nirtfeatures->io_base + NIRTF_YEAR); nirtfeatures->revision[1] = inb(nirtfeatures->io_base + NIRTF_MONTH); @@ -1512,33 +1424,26 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) nirtfeatures->revision[3] = inb(nirtfeatures->io_base + NIRTF_HOUR); nirtfeatures->revision[4] = inb(nirtfeatures->io_base + NIRTF_MINUTE); - err = sysfs_create_files(&nirtfeatures->acpi_device->dev.kobj, - nirtfeatures_attrs); - if (err != 0) { - nirtfeatures_acpi_remove(device); + err = nirtfeatures_create_leds(nirtfeatures); + if (err) return err; + + if (nirtfeatures->has_wifi) { + err = nirtfeatures_wifi_regulator_init(&device->dev, + nirtfeatures); + if (err) + return err; } - err = nirtfeatures_create_leds(nirtfeatures); - if (err != 0) { - nirtfeatures_acpi_remove(device); + err = sysfs_create_files(&device->dev.kobj, nirtfeatures_attrs); + if (err) return err; - } dev_info(&nirtfeatures->acpi_device->dev, "IO range 0x%04X-0x%04X\n", nirtfeatures->io_base, nirtfeatures->io_base + nirtfeatures->io_size - 1); - if (nirtfeatures->has_wifi) { - err = nirtfeatures_wifi_regulator_init(&device->dev, - nirtfeatures); - if (err != 0) { - nirtfeatures_acpi_remove(device); - return err; - } - } - return 0; } From 4978a32ca17ad4c016f6509e618f62aa7d0101fc Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Wed, 14 Mar 2018 18:22:42 -0500 Subject: [PATCH 28/83] nirtfeatures: Add Swordfish backplane ID Add the new Swordfish backplane ID to stop errors on boot. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Zach Brown Acked-by: Nathan Sullivan Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 227200 --- drivers/misc/nirtfeatures.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index fcb6bcdf2ffab..ce35381af5754 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -47,6 +47,7 @@ #define NIRTF_PLATFORM_MISC_ID_MASK 0x07 #define NIRTF_PLATFORM_MISC_ID_MANHATTAN 0 +#define NIRTF_PLATFORM_MISC_ID_SWORDFISH 1 #define NIRTF_PLATFORM_MISC_ID_FIRE_EAGLE 2 #define NIRTF_PLATFORM_MISC_ID_HAMMERHEAD 4 #define NIRTF_PLATFORM_MISC_ID_WINGHEAD 5 @@ -1398,6 +1399,9 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) case NIRTF_PLATFORM_MISC_ID_FIRE_EAGLE: nirtfeatures->bpstring = "Fire Eagle"; break; + case NIRTF_PLATFORM_MISC_ID_SWORDFISH: + nirtfeatures->bpstring = "Swordfish"; + break; case NIRTF_PLATFORM_MISC_ID_HAMMERHEAD: nirtfeatures->bpstring = "Hammerhead"; break; From 585973b9cacb062d62b4f9e7fb953f34425191ea Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Wed, 14 Mar 2018 18:23:30 -0500 Subject: [PATCH 29/83] nirtfeatures: Only register bi-color LEDs on supported targets Unlike all previous controllers, Swordfish targets do not have bi-color power and status LEDs. Check our backplane ID and don't register the second color if we're on a Swordfish. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Zach Brown Acked-by: Nathan Sullivan Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 227200 Natinst-CAR-ID: 691081 --- drivers/misc/nirtfeatures.c | 130 +++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 39 deletions(-) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index ce35381af5754..e3496e2bc405e 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -125,10 +125,17 @@ struct nirtfeatures { u16 io_size; spinlock_t lock; u8 revision[5]; - const char *bpstring; bool has_wifi; struct regulator_dev *reg_dev; unsigned int irq; + struct nirtfeatures_desc *desc; +}; + +struct nirtfeatures_desc { + unsigned int backplane_id; + const char *name; + struct nirtfeatures_led *leds; + unsigned int num_leds; }; struct nirtfeatures_led { @@ -214,7 +221,7 @@ static ssize_t nirtfeatures_backplane_id_get(struct device *dev, struct acpi_device *acpi_device = to_acpi_device(dev); struct nirtfeatures *nirtfeatures = acpi_device->driver_data; - return sprintf(buf, "%s\n", nirtfeatures->bpstring); + return sprintf(buf, "%s\n", nirtfeatures->desc->name); } static DEVICE_ATTR(backplane_id, S_IRUGO, nirtfeatures_backplane_id_get, NULL); @@ -457,7 +464,7 @@ nirtfeatures_led_brightness_get(struct led_classdev *led_cdev) return (data & led->mask) ? LED_FULL : LED_OFF; } -static struct nirtfeatures_led nirtfeatures_leds_common[] = { +static struct nirtfeatures_led nirtfeatures_leds[] = { { { .name = CONFIG_NI_LED_PREFIX ":status:red", @@ -488,7 +495,67 @@ static struct nirtfeatures_led nirtfeatures_leds_common[] = { }, .address = NIRTF_SYSTEM_LEDS, .mask = NIRTF_SYSTEM_LEDS_POWER_YELLOW, + } +}; + +static struct nirtfeatures_led nirtfeatures_leds_monochrome[] = { + { + { + .name = CONFIG_NI_LED_PREFIX ":status:yellow", + .max_brightness = 0xFFFF, + }, + .address = NIRTF_SYSTEM_LEDS, + .mask = NIRTF_SYSTEM_LEDS_STATUS_YELLOW, + .pattern_hi_addr = NIRTF_STATUS_LED_SHIFT1, + .pattern_lo_addr = NIRTF_STATUS_LED_SHIFT0, }, + { + { + .name = CONFIG_NI_LED_PREFIX ":power:green", + }, + .address = NIRTF_SYSTEM_LEDS, + .mask = NIRTF_SYSTEM_LEDS_POWER_GREEN, + } +}; + +static struct nirtfeatures_desc nirtfeatures_descs[] = { + { + .backplane_id = NIRTF_PLATFORM_MISC_ID_MANHATTAN, + .name = "Manhattan", + .leds = nirtfeatures_leds, + .num_leds = ARRAY_SIZE(nirtfeatures_leds), + }, + { + .backplane_id = NIRTF_PLATFORM_MISC_ID_FIRE_EAGLE, + .name = "Fire Eagle", + .leds = nirtfeatures_leds, + .num_leds = ARRAY_SIZE(nirtfeatures_leds), + }, + { + .backplane_id = NIRTF_PLATFORM_MISC_ID_SWORDFISH, + .name = "Swordfish", + .leds = nirtfeatures_leds_monochrome, + .num_leds = ARRAY_SIZE(nirtfeatures_leds_monochrome), + }, + { + .backplane_id = NIRTF_PLATFORM_MISC_ID_HAMMERHEAD, + .name = "Hammerhead", + .leds = nirtfeatures_leds, + .num_leds = ARRAY_SIZE(nirtfeatures_leds), + }, + { + .backplane_id = NIRTF_PLATFORM_MISC_ID_WINGHEAD, + .name = "Winghead", + .leds = nirtfeatures_leds, + .num_leds = ARRAY_SIZE(nirtfeatures_leds), + } +}; + +static struct nirtfeatures_desc nirtfeatures_desc_unknown = { + .backplane_id = 0xf, + .name = "Unknown", + .leds = nirtfeatures_leds, + .num_leds = ARRAY_SIZE(nirtfeatures_leds), }; /*===================================================================== @@ -907,7 +974,7 @@ static int nirtfeatures_parse_switch_pie(struct nirtfeatures *nirtfeatures, } snprintf(switch_dev->phys_location_string, MAX_NODELEN, "%s/%s/%s", - CONFIG_NI_LED_PREFIX, nirtfeatures->bpstring, pie->name); + CONFIG_NI_LED_PREFIX, nirtfeatures->desc->name, pie->name); switch_dev->cdev->name = switch_dev->name_string; switch_dev->cdev->phys = switch_dev->phys_location_string; @@ -1110,24 +1177,20 @@ static int nirtfeatures_populate_pies(struct nirtfeatures *nirtfeatures) static int nirtfeatures_create_leds(struct nirtfeatures *nirtfeatures) { - int i; - int err; - - for (i = 0; i < ARRAY_SIZE(nirtfeatures_leds_common); ++i) { - - nirtfeatures_leds_common[i].nirtfeatures = nirtfeatures; + struct nirtfeatures_led *leds = nirtfeatures->desc->leds; + int i, err; - if (nirtfeatures_leds_common[i].cdev.max_brightness == 0) - nirtfeatures_leds_common[i].cdev.max_brightness = 1; + for (i = 0; i < nirtfeatures->desc->num_leds; i++) { + leds[i].nirtfeatures = nirtfeatures; - nirtfeatures_leds_common[i].cdev.brightness_set = - nirtfeatures_led_brightness_set; + if (leds[i].cdev.max_brightness == 0) + leds[i].cdev.max_brightness = 1; - nirtfeatures_leds_common[i].cdev.brightness_get = - nirtfeatures_led_brightness_get; + leds[i].cdev.brightness_set = nirtfeatures_led_brightness_set; + leds[i].cdev.brightness_get = nirtfeatures_led_brightness_get; err = devm_led_classdev_register(&nirtfeatures->acpi_device->dev, - &nirtfeatures_leds_common[i].cdev); + &leds[i].cdev); if (err) return err; } @@ -1364,7 +1427,7 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) struct nirtfeatures *nirtfeatures; acpi_status acpi_ret; u8 bpinfo; - int err; + int err, i; nirtfeatures = devm_kzalloc(&device->dev, sizeof(*nirtfeatures), GFP_KERNEL); @@ -1392,28 +1455,17 @@ static int nirtfeatures_acpi_add(struct acpi_device *device) bpinfo &= NIRTF_PLATFORM_MISC_ID_MASK; - switch (bpinfo) { - case NIRTF_PLATFORM_MISC_ID_MANHATTAN: - nirtfeatures->bpstring = "Manhattan"; - break; - case NIRTF_PLATFORM_MISC_ID_FIRE_EAGLE: - nirtfeatures->bpstring = "Fire Eagle"; - break; - case NIRTF_PLATFORM_MISC_ID_SWORDFISH: - nirtfeatures->bpstring = "Swordfish"; - break; - case NIRTF_PLATFORM_MISC_ID_HAMMERHEAD: - nirtfeatures->bpstring = "Hammerhead"; - break; - case NIRTF_PLATFORM_MISC_ID_WINGHEAD: - nirtfeatures->bpstring = "Winghead"; - break; - default: + for (i = 0; i < ARRAY_SIZE(nirtfeatures_descs); i++) { + if (bpinfo == nirtfeatures_descs[i].backplane_id) { + nirtfeatures->desc = &nirtfeatures_descs[i]; + break; + } + } + + if (!nirtfeatures->desc) { dev_err(&nirtfeatures->acpi_device->dev, - "Unrecognized backplane type %u\n", - bpinfo); - nirtfeatures->bpstring = "Unknown"; - break; + "Unrecognized backplane ID %u\n", bpinfo); + nirtfeatures->desc = &nirtfeatures_desc_unknown; } spin_lock_init(&nirtfeatures->lock); From 55b76e481ee8147bc44a6bd2dfad9c5a694a868a Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Fri, 20 Aug 2021 15:47:31 -0500 Subject: [PATCH 30/83] nirtfeatures: Automatically select support for NEW_LEDS Prior to commit 7142f92412c1 ("wireless: carl9170: fix LEDS build errors & warnings") support for MAC80211_LEDS, NEW_LEDS and LEDS_CLASS config options was automatically enabled by having CONFIG_CARL9170=m in nati_x86_64_defconfig. The aforementioned commit removed the automatic selection in favor of CARL9170_LEDS config option declaring a dependency on MAC80211_LEDS. This results in linker errors if the nirtfeatures driver is enabled via CONFIG_NI_RT_FEATURES since this driver makes use of functionality provided by the NEW_LEDS and LEDS_CLASS configuration options: LD .tmp_vmlinux.kallsyms1 ld: drivers/misc/nirtfeatures.o: in function `nirtfeatures_parse_led_pie.isra.0': nirtfeatures.c:(.text+0x103b): undefined reference to `devm_led_classdev_register_ext' ld: drivers/misc/nirtfeatures.o: in function `nirtfeatures_acpi_add': nirtfeatures.c:(.text+0x14ad): undefined reference to `devm_led_classdev_register_ext' make: *** [Makefile:1179: vmlinux] Error 1 Automatically select support for NEW_LEDS and by extension LEDS_CLASS if NI_RT_FEATURES is enabled. Signed-off-by: Gratian Crisan --- drivers/misc/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index 2fb4788c7c92b..fe4149ddf7360 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -614,6 +614,7 @@ config NI_RT_FEATURES bool "NI 903x/913x support" depends on X86 && ACPI select REGULATOR + select NEW_LEDS help This driver exposes LEDs and other features of NI 903x/913x Real-Time controllers. From 2e434ceb32056bb79fa443f63a70b8c73634cc8b Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Fri, 30 Nov 2018 14:34:02 -0600 Subject: [PATCH 31/83] nirtfeatures: Add Dogfish backplane ID and LED info This family uses the same monochrome LEDs as Swordfish. Signed-off-by: Kyle Roeschley Acked-by: Brandon Streiff Acked-by: Gratian Crisan Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 273119 --- drivers/misc/nirtfeatures.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/misc/nirtfeatures.c b/drivers/misc/nirtfeatures.c index e3496e2bc405e..449efb186f910 100644 --- a/drivers/misc/nirtfeatures.c +++ b/drivers/misc/nirtfeatures.c @@ -49,6 +49,7 @@ #define NIRTF_PLATFORM_MISC_ID_MANHATTAN 0 #define NIRTF_PLATFORM_MISC_ID_SWORDFISH 1 #define NIRTF_PLATFORM_MISC_ID_FIRE_EAGLE 2 +#define NIRTF_PLATFORM_MISC_ID_DOGFISH 3 #define NIRTF_PLATFORM_MISC_ID_HAMMERHEAD 4 #define NIRTF_PLATFORM_MISC_ID_WINGHEAD 5 @@ -537,6 +538,12 @@ static struct nirtfeatures_desc nirtfeatures_descs[] = { .leds = nirtfeatures_leds_monochrome, .num_leds = ARRAY_SIZE(nirtfeatures_leds_monochrome), }, + { + .backplane_id = NIRTF_PLATFORM_MISC_ID_DOGFISH, + .name = "Dogfish", + .leds = nirtfeatures_leds_monochrome, + .num_leds = ARRAY_SIZE(nirtfeatures_leds_monochrome), + }, { .backplane_id = NIRTF_PLATFORM_MISC_ID_HAMMERHEAD, .name = "Hammerhead", From e5c38afbdafd9ee7240170f687c988b282cc774f Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Mon, 16 Dec 2013 10:44:59 -0600 Subject: [PATCH 32/83] niwatchdog: Added NI Watchdog driver Added an NI Watchdog driver. This is an ACPI device that exposes the NI Watchdog hardware interface. Not all of the proposed features of the device work as expected. Development work on this device by the hardware team is currently not a high priority. These issues will be addressed once the hardware team gets back to this device. Signed-off-by: Jeff Westfahl [mpeterse: change return type of niwatchdog_acpi_remove due to 6c0eb5ba3500] Signed-off-by: Mike Petersen --- drivers/misc/Kconfig | 9 ++ drivers/misc/Makefile | 1 + drivers/misc/niwatchdog.c | 252 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 262 insertions(+) create mode 100644 drivers/misc/niwatchdog.c diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig index fe4149ddf7360..c0c615c917d39 100644 --- a/drivers/misc/Kconfig +++ b/drivers/misc/Kconfig @@ -632,6 +632,15 @@ config NI_LED_PREFIX If unsure, use the default. +config NI_WATCHDOG + bool "NI Watchdog support for NI 903x/913x" + depends on X86 && ACPI + help + This driver exposes the NI Watchdog feature of NI 903x/913x Real-Time + controllers. + + If unsure, say N (but it's safe to say "Y"). + source "drivers/misc/c2port/Kconfig" source "drivers/misc/eeprom/Kconfig" source "drivers/misc/cb710/Kconfig" diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile index 8221e1b6c496b..d2cac39aa5de9 100644 --- a/drivers/misc/Makefile +++ b/drivers/misc/Makefile @@ -73,3 +73,4 @@ obj-$(CONFIG_NSM) += nsm.o obj-$(CONFIG_MARVELL_CN10K_DPI) += mrvl_cn10k_dpi.o obj-y += keba/ obj-$(CONFIG_NI_RT_FEATURES) += nirtfeatures.o +obj-$(CONFIG_NI_WATCHDOG) += niwatchdog.o diff --git a/drivers/misc/niwatchdog.c b/drivers/misc/niwatchdog.c new file mode 100644 index 0000000000000..bdd9417311604 --- /dev/null +++ b/drivers/misc/niwatchdog.c @@ -0,0 +1,252 @@ +/* + * Copyright (C) 2013 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include + +#define MODULE_NAME "niwatchdog" + +#define NIWD_CONTROL 0x01 +#define NIWD_COUNTER2 0x02 +#define NIWD_COUNTER1 0x03 +#define NIWD_COUNTER0 0x04 +#define NIWD_SEED2 0x05 +#define NIWD_SEED1 0x06 +#define NIWD_SEED0 0x07 + +#define NIWD_IO_SIZE 0x08 + +#define NIWD_CONTROL_MODE 0x80 +#define NIWD_CONTROL_RESET 0x02 + +struct niwatchdog { + struct acpi_device *acpi_device; + u16 io_base; + u16 io_size; + u32 irq; + spinlock_t lock; +}; + +static ssize_t niwatchdog_wdmode_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct niwatchdog *niwatchdog = acpi_device->driver_data; + u8 data; + + data = inb(niwatchdog->io_base + NIWD_CONTROL); + + data &= NIWD_CONTROL_MODE; + + return sprintf(buf, "%s\n", data ? "boot" : "user"); +} + +static ssize_t niwatchdog_wdmode_set(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct niwatchdog *niwatchdog = acpi_device->driver_data; + u8 data; + + /* you can only switch boot->user */ + if (strcmp(buf, "user")) + return -EINVAL; + + data = NIWD_CONTROL_MODE | NIWD_CONTROL_RESET; + + outb(data, niwatchdog->io_base + NIWD_CONTROL); + + return count; +} + +static DEVICE_ATTR(watchdog_mode, S_IRUSR|S_IWUSR, niwatchdog_wdmode_get, + niwatchdog_wdmode_set); + +static ssize_t niwatchdog_register_dump_get(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct acpi_device *acpi_device = to_acpi_device(dev); + struct niwatchdog *niwatchdog = acpi_device->driver_data; + u8 control, counter2, counter1, counter0; + u8 seed2, seed1, seed0; + + control = inb(niwatchdog->io_base + NIWD_CONTROL); + counter2 = inb(niwatchdog->io_base + NIWD_COUNTER2); + counter1 = inb(niwatchdog->io_base + NIWD_COUNTER1); + counter0 = inb(niwatchdog->io_base + NIWD_COUNTER0); + seed2 = inb(niwatchdog->io_base + NIWD_SEED2); + seed1 = inb(niwatchdog->io_base + NIWD_SEED1); + seed0 = inb(niwatchdog->io_base + NIWD_SEED0); + + return sprintf(buf, + "Control: 0x%02X\n" + "Counter 2: 0x%02X\n" + "Counter 1: 0x%02X\n" + "Counter 0: 0x%02X\n" + "Seed 2: 0x%02X\n" + "Seed 1: 0x%02X\n" + "Seed 0: 0x%02X\n", + control, counter2, counter1, counter0, + seed2, seed1, seed0); +} + +static DEVICE_ATTR(register_dump, S_IRUGO, niwatchdog_register_dump_get, NULL); + +static const struct attribute *niwatchdog_attrs[] = { + &dev_attr_watchdog_mode.attr, + &dev_attr_register_dump.attr, + NULL +}; + +static acpi_status niwatchdog_resources(struct acpi_resource *res, void *data) +{ + struct niwatchdog *niwatchdog = data; + + switch (res->type) { + case ACPI_RESOURCE_TYPE_IO: + if ((niwatchdog->io_base != 0) || + (niwatchdog->io_size != 0)) { + dev_err(&niwatchdog->acpi_device->dev, + "too many IO resources\n"); + return AE_ERROR; + } + + niwatchdog->io_base = res->data.io.minimum; + niwatchdog->io_size = res->data.io.address_length; + + return AE_OK; + + case ACPI_RESOURCE_TYPE_IRQ: + if (niwatchdog->irq != 0) { + dev_err(&niwatchdog->acpi_device->dev, + "too many IRQ resources\n"); + return AE_ERROR; + } + + niwatchdog->irq = res->data.irq.interrupts[0]; + + return AE_OK; + + case ACPI_RESOURCE_TYPE_END_TAG: + return AE_OK; + + default: + dev_err(&niwatchdog->acpi_device->dev, + "unsupported resource type %d\n", + res->type); + return AE_ERROR; + } + + return AE_OK; +} + +static void niwatchdog_acpi_remove(struct acpi_device *device) +{ + struct niwatchdog *niwatchdog = device->driver_data; + + sysfs_remove_files(&niwatchdog->acpi_device->dev.kobj, + niwatchdog_attrs); + + if ((niwatchdog->io_base != 0) && + (niwatchdog->io_size == NIWD_IO_SIZE)) + release_region(niwatchdog->io_base, niwatchdog->io_size); + + device->driver_data = NULL; + + kfree(niwatchdog); +} + +static int niwatchdog_acpi_add(struct acpi_device *device) +{ + struct niwatchdog *niwatchdog; + acpi_status acpi_ret; + int err; + + niwatchdog = kzalloc(sizeof(*niwatchdog), GFP_KERNEL); + + if (!niwatchdog) + return -ENOMEM; + + device->driver_data = niwatchdog; + + niwatchdog->acpi_device = device; + + acpi_ret = acpi_walk_resources(device->handle, METHOD_NAME__CRS, + niwatchdog_resources, niwatchdog); + + if (ACPI_FAILURE(acpi_ret) || + (niwatchdog->io_base == 0) || + (niwatchdog->io_size != NIWD_IO_SIZE) || + (niwatchdog->irq == 0)) { + niwatchdog_acpi_remove(device); + return -ENODEV; + } + + if (!request_region(niwatchdog->io_base, niwatchdog->io_size, + MODULE_NAME)) { + niwatchdog_acpi_remove(device); + return -EBUSY; + } + + err = sysfs_create_files(&niwatchdog->acpi_device->dev.kobj, + niwatchdog_attrs); + if (err) { + niwatchdog_acpi_remove(device); + return err; + } + + spin_lock_init(&niwatchdog->lock); + + dev_info(&niwatchdog->acpi_device->dev, + "IO range 0x%04X-0x%04X, IRQ %d\n", + niwatchdog->io_base, + niwatchdog->io_base + niwatchdog->io_size - 1, niwatchdog->irq); + + return 0; +} + +static const struct acpi_device_id niwatchdog_device_ids[] = { + {"NIC775C", 0}, + {"", 0}, +}; + +static struct acpi_driver niwatchdog_acpi_driver = { + .name = MODULE_NAME, + .ids = niwatchdog_device_ids, + .ops = { + .add = niwatchdog_acpi_add, + .remove = niwatchdog_acpi_remove, + }, +}; + +static int __init niwatchdog_init(void) +{ + return acpi_bus_register_driver(&niwatchdog_acpi_driver); +} + +static void __exit niwatchdog_exit(void) +{ + acpi_bus_unregister_driver(&niwatchdog_acpi_driver); +} + +module_init(niwatchdog_init); +module_exit(niwatchdog_exit); + +MODULE_DEVICE_TABLE(acpi, niwatchdog_device_ids); +MODULE_DESCRIPTION("NI Watchdog"); +MODULE_AUTHOR("Jeff Westfahl "); +MODULE_LICENSE("GPL"); From 70d2b05e66995eb65b6b8e4d2ac803a837f0a357 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Wed, 5 Mar 2014 09:50:05 -0600 Subject: [PATCH 33/83] niwatchdog: Added ioctl interface for NI Watchdog Added a new header file with an ioctl interface for NI Watchdog. This file is installed as part of 'make headers_install'. Signed-off-by: Jeff Westfahl [gratian: fix Kbuild conflict, no need to explicitly list headers anymore] Signed-off-by: Gratian Crisan --- include/uapi/linux/niwatchdog.h | 39 +++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 include/uapi/linux/niwatchdog.h diff --git a/include/uapi/linux/niwatchdog.h b/include/uapi/linux/niwatchdog.h new file mode 100644 index 0000000000000..804d45f0243fa --- /dev/null +++ b/include/uapi/linux/niwatchdog.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2012 National Instruments Corp. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_NIWATCHDOG_H_ +#define _LINUX_NIWATCHDOG_H_ + +#include +#include + +#define NIWATCHDOG_ACTION_INTERRUPT 0 +#define NIWATCHDOG_ACTION_RESET 1 + +#define NIWATCHDOG_STATE_RUNNING 0 +#define NIWATCHDOG_STATE_EXPIRED 1 + +#define NIWATCHDOG_IOCTL_PERIOD_NS _IOR('W', 0, __u32) +#define NIWATCHDOG_IOCTL_MAX_COUNTER _IOR('W', 1, __u32) +#define NIWATCHDOG_IOCTL_COUNTER_SET _IOW('W', 2, __u32) +#define NIWATCHDOG_IOCTL_CHECK_ACTION _IOW('W', 3, __u32) +#define NIWATCHDOG_IOCTL_ADD_ACTION _IOW('W', 4, __u32) +#define NIWATCHDOG_IOCTL_START _IO('W', 5) +#define NIWATCHDOG_IOCTL_PET _IOR('W', 6, __u32) +#define NIWATCHDOG_IOCTL_RESET _IO('W', 7) +#define NIWATCHDOG_IOCTL_COUNTER_GET _IOR('W', 8, __u32) + +#define NIWATCHDOG_NAME "niwatchdog" + +#endif /* _LINUX_NIWATCHDOG_H_ */ From 699f547dd34be1f6765e6de01899485c82c4c37c Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Thu, 6 Mar 2014 11:07:15 -0600 Subject: [PATCH 34/83] niwatchdog: Added NIWATCHDOG_STATE_DISABLED Signed-off-by: Jeff Westfahl --- include/uapi/linux/niwatchdog.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/uapi/linux/niwatchdog.h b/include/uapi/linux/niwatchdog.h index 804d45f0243fa..a5931a4c8a277 100644 --- a/include/uapi/linux/niwatchdog.h +++ b/include/uapi/linux/niwatchdog.h @@ -23,6 +23,7 @@ #define NIWATCHDOG_STATE_RUNNING 0 #define NIWATCHDOG_STATE_EXPIRED 1 +#define NIWATCHDOG_STATE_DISABLED 2 #define NIWATCHDOG_IOCTL_PERIOD_NS _IOR('W', 0, __u32) #define NIWATCHDOG_IOCTL_MAX_COUNTER _IOR('W', 1, __u32) From f5ce7e54d0d8050e03428a531c6ac5021ffe35ea Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Thu, 6 Mar 2014 11:17:36 -0600 Subject: [PATCH 35/83] niwatchdog: Implemented NI Watchdog for NI Linux x64 targets. Signed-off-by: Jeff Westfahl --- drivers/misc/niwatchdog.c | 363 +++++++++++++++++++++++++++++++++++++- 1 file changed, 361 insertions(+), 2 deletions(-) diff --git a/drivers/misc/niwatchdog.c b/drivers/misc/niwatchdog.c index bdd9417311604..0e67f87463aee 100644 --- a/drivers/misc/niwatchdog.c +++ b/drivers/misc/niwatchdog.c @@ -14,6 +14,10 @@ #include #include +#include +#include +#include +#include #define MODULE_NAME "niwatchdog" @@ -27,8 +31,18 @@ #define NIWD_IO_SIZE 0x08 -#define NIWD_CONTROL_MODE 0x80 -#define NIWD_CONTROL_RESET 0x02 +#define NIWD_CONTROL_MODE 0x80 +#define NIWD_CONTROL_PROC_INTERRUPT 0x40 +#define NIWD_CONTROL_PROC_RESET 0x20 +#define NIWD_CONTROL_PET 0x10 +#define NIWD_CONTROL_RUNNING 0x08 +#define NIWD_CONTROL_CAPTURECOUNTER 0x04 +#define NIWD_CONTROL_RESET 0x02 +#define NIWD_CONTROL_ALARM 0x01 + +#define NIWD_PERIOD_NS 30720 +#define NIWD_MAX_COUNTER 0x00FFFFFF + struct niwatchdog { struct acpi_device *acpi_device; @@ -36,6 +50,11 @@ struct niwatchdog { u16 io_size; u32 irq; spinlock_t lock; + struct miscdevice misc_dev; + atomic_t available; + wait_queue_head_t irq_event; + u32 running:1; + u32 expired:1; }; static ssize_t niwatchdog_wdmode_get(struct device *dev, @@ -65,6 +84,12 @@ static ssize_t niwatchdog_wdmode_set(struct device *dev, if (strcmp(buf, "user")) return -EINVAL; + data = inb(niwatchdog->io_base + NIWD_CONTROL); + + /* Check if we're already in user mode. */ + if (!(data & NIWD_CONTROL_MODE)) + return count; + data = NIWD_CONTROL_MODE | NIWD_CONTROL_RESET; outb(data, niwatchdog->io_base + NIWD_CONTROL); @@ -112,6 +137,323 @@ static const struct attribute *niwatchdog_attrs[] = { NULL }; +static int niwatchdog_counter_set(struct niwatchdog *niwatchdog, u32 counter) +{ + int ret; + unsigned long flags; + + spin_lock_irqsave(&niwatchdog->lock, flags); + + /* Prevent changing the counter while the watchdog is running. */ + if (niwatchdog->running) { + ret = -EBUSY; + goto out_unlock; + } + + outb(((0x00FF0000 & counter) >> 16), niwatchdog->io_base + NIWD_SEED2); + outb(((0x0000FF00 & counter) >> 8), niwatchdog->io_base + NIWD_SEED1); + outb((0x000000FF & counter), niwatchdog->io_base + NIWD_SEED0); + + ret = 0; + +out_unlock: + spin_unlock_irqrestore(&niwatchdog->lock, flags); + + return ret; +} + +static int niwatchdog_check_action(u32 action) +{ + int err = 0; + + switch (action) { + case NIWD_CONTROL_PROC_INTERRUPT: + case NIWD_CONTROL_PROC_RESET: + break; + default: + err = -ENOTSUPP; + } + + return err; +} + +static int niwatchdog_add_action(struct niwatchdog *niwatchdog, u32 action) +{ + u8 action_mask; + u8 control; + unsigned long flags; + + if (action == NIWATCHDOG_ACTION_INTERRUPT) + action_mask = NIWD_CONTROL_PROC_INTERRUPT; + else if (action == NIWATCHDOG_ACTION_RESET) + action_mask = NIWD_CONTROL_PROC_RESET; + else + return -ENOTSUPP; + + spin_lock_irqsave(&niwatchdog->lock, flags); + + control = inb(niwatchdog->io_base + NIWD_CONTROL); + control |= action_mask; + outb(control, niwatchdog->io_base + NIWD_CONTROL); + + spin_unlock_irqrestore(&niwatchdog->lock, flags); + + return 0; +} + +static int niwatchdog_start(struct niwatchdog *niwatchdog) +{ + u8 control; + unsigned long flags; + + spin_lock_irqsave(&niwatchdog->lock, flags); + + niwatchdog->running = true; + niwatchdog->expired = false; + + control = inb(niwatchdog->io_base + NIWD_CONTROL); + outb(control | NIWD_CONTROL_RESET, niwatchdog->io_base + NIWD_CONTROL); + outb(control | NIWD_CONTROL_PET, niwatchdog->io_base + NIWD_CONTROL); + + spin_unlock_irqrestore(&niwatchdog->lock, flags); + + return 0; +} + +static int niwatchdog_pet(struct niwatchdog *niwatchdog, u32 *state) +{ + u8 control; + unsigned long flags; + + spin_lock_irqsave(&niwatchdog->lock, flags); + + if (niwatchdog->expired) { + *state = NIWATCHDOG_STATE_EXPIRED; + } else if (!niwatchdog->running) { + *state = NIWATCHDOG_STATE_DISABLED; + } else { + control = inb(niwatchdog->io_base + NIWD_CONTROL); + control |= NIWD_CONTROL_PET; + outb(control, niwatchdog->io_base + NIWD_CONTROL); + + *state = NIWATCHDOG_STATE_RUNNING; + } + + spin_unlock_irqrestore(&niwatchdog->lock, flags); + + return 0; +} + +static int niwatchdog_reset(struct niwatchdog *niwatchdog) +{ + unsigned long flags; + + spin_lock_irqsave(&niwatchdog->lock, flags); + + niwatchdog->running = false; + niwatchdog->expired = false; + + outb(NIWD_CONTROL_RESET, niwatchdog->io_base + NIWD_CONTROL); + + spin_unlock_irqrestore(&niwatchdog->lock, flags); + + return 0; +} + +static int niwatchdog_counter_get(struct niwatchdog *niwatchdog, + u32 *counter) +{ + u8 control; + u8 counter2, counter1, counter0; + unsigned long flags; + + spin_lock_irqsave(&niwatchdog->lock, flags); + + control = inb(niwatchdog->io_base + NIWD_CONTROL); + control |= NIWD_CONTROL_CAPTURECOUNTER; + outb(control, niwatchdog->io_base + NIWD_CONTROL); + + counter2 = inb(niwatchdog->io_base + NIWD_COUNTER2); + counter1 = inb(niwatchdog->io_base + NIWD_COUNTER1); + counter0 = inb(niwatchdog->io_base + NIWD_COUNTER0); + + *counter = (counter2 << 16) | (counter1 << 8) | counter0; + + spin_unlock_irqrestore(&niwatchdog->lock, flags); + + return 0; +} + +static irqreturn_t niwatchdog_irq(int irq, void *data) +{ + struct niwatchdog *niwatchdog = data; + irqreturn_t ret = IRQ_NONE; + u8 control; + unsigned long flags; + + spin_lock_irqsave(&niwatchdog->lock, flags); + + control = inb(niwatchdog->io_base + NIWD_CONTROL); + + if (!(NIWD_CONTROL_ALARM & control)) { + dev_err(&niwatchdog->acpi_device->dev, + "Spurious watchdog interrupt, 0x%02X\n", control); + goto out_unlock; + } + + niwatchdog->running = false; + niwatchdog->expired = true; + + /* Acknowledge the interrupt. */ + control |= NIWD_CONTROL_RESET; + outb(control, niwatchdog->io_base + NIWD_CONTROL); + + /* Signal the watchdog event. */ + wake_up_all(&niwatchdog->irq_event); + + ret = IRQ_HANDLED; + +out_unlock: + spin_unlock_irqrestore(&niwatchdog->lock, flags); + + return ret; +} + +static int niwatchdog_misc_open(struct inode *inode, struct file *file) +{ + struct miscdevice *misc_dev = file->private_data; + struct niwatchdog *niwatchdog = container_of( + misc_dev, struct niwatchdog, misc_dev); + + file->private_data = niwatchdog; + + if (!atomic_dec_and_test(&niwatchdog->available)) { + atomic_inc(&niwatchdog->available); + return -EBUSY; + } + + return request_irq(niwatchdog->irq, niwatchdog_irq, 0, + NIWATCHDOG_NAME, niwatchdog); +} + +static int niwatchdog_misc_release(struct inode *inode, struct file *file) +{ + struct niwatchdog *niwatchdog = file->private_data; + + free_irq(niwatchdog->irq, niwatchdog); + atomic_inc(&niwatchdog->available); + return 0; +} + +static long niwatchdog_misc_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct niwatchdog *niwatchdog = file->private_data; + int err; + + switch (cmd) { + case NIWATCHDOG_IOCTL_PERIOD_NS: { + __u32 period = NIWD_PERIOD_NS; + + err = copy_to_user((__u32 *)arg, &period, + sizeof(__u32)); + break; + } + case NIWATCHDOG_IOCTL_MAX_COUNTER: { + __u32 counter = NIWD_MAX_COUNTER; + + err = copy_to_user((__u32 *)arg, &counter, + sizeof(__u32)); + break; + } + case NIWATCHDOG_IOCTL_COUNTER_SET: { + __u32 counter; + + err = copy_from_user(&counter, (__u32 *)arg, + sizeof(__u32)); + if (!err) + err = niwatchdog_counter_set(niwatchdog, counter); + break; + } + case NIWATCHDOG_IOCTL_CHECK_ACTION: { + __u32 action; + + err = copy_from_user(&action, (__u32 *)arg, + sizeof(__u32)); + if (!err) + err = niwatchdog_check_action(action); + break; + } + case NIWATCHDOG_IOCTL_ADD_ACTION: { + __u32 action; + err = copy_from_user(&action, (__u32 *)arg, + sizeof(__u32)); + if (!err) + err = niwatchdog_add_action(niwatchdog, action); + break; + } + case NIWATCHDOG_IOCTL_START: { + err = niwatchdog_start(niwatchdog); + break; + } + case NIWATCHDOG_IOCTL_PET: { + __u32 state; + + err = niwatchdog_pet(niwatchdog, &state); + if (!err) + err = copy_to_user((__u32 *)arg, &state, + sizeof(__u32)); + break; + } + case NIWATCHDOG_IOCTL_RESET: { + err = niwatchdog_reset(niwatchdog); + break; + } + case NIWATCHDOG_IOCTL_COUNTER_GET: { + __u32 counter; + + err = niwatchdog_counter_get(niwatchdog, &counter); + if (!err) { + err = copy_to_user((__u32 *)arg, &counter, + sizeof(__u32)); + } + break; + } + default: + err = -EINVAL; + break; + }; + + return err; +} + +unsigned int niwatchdog_misc_poll(struct file *file, + struct poll_table_struct *wait) +{ + struct niwatchdog *niwatchdog = file->private_data; + unsigned int mask = 0; + unsigned long flags; + + poll_wait(file, &niwatchdog->irq_event, wait); + + spin_lock_irqsave(&niwatchdog->lock, flags); + + if (niwatchdog->expired) + mask = POLLIN; + + spin_unlock_irqrestore(&niwatchdog->lock, flags); + + return mask; +} + +static const struct file_operations niwatchdog_misc_fops = { + .owner = THIS_MODULE, + .open = niwatchdog_misc_open, + .release = niwatchdog_misc_release, + .unlocked_ioctl = niwatchdog_misc_ioctl, + .poll = niwatchdog_misc_poll, +}; + static acpi_status niwatchdog_resources(struct acpi_resource *res, void *data) { struct niwatchdog *niwatchdog = data; @@ -158,6 +500,8 @@ static void niwatchdog_acpi_remove(struct acpi_device *device) { struct niwatchdog *niwatchdog = device->driver_data; + misc_deregister(&niwatchdog->misc_dev); + sysfs_remove_files(&niwatchdog->acpi_device->dev.kobj, niwatchdog_attrs); @@ -211,6 +555,21 @@ static int niwatchdog_acpi_add(struct acpi_device *device) spin_lock_init(&niwatchdog->lock); + atomic_set(&niwatchdog->available, 1); + init_waitqueue_head(&niwatchdog->irq_event); + niwatchdog->expired = false; + + niwatchdog->misc_dev.minor = MISC_DYNAMIC_MINOR; + niwatchdog->misc_dev.name = NIWATCHDOG_NAME; + niwatchdog->misc_dev.fops = &niwatchdog_misc_fops; + + err = misc_register(&niwatchdog->misc_dev); + + if (err) { + niwatchdog_acpi_remove(device); + return err; + } + dev_info(&niwatchdog->acpi_device->dev, "IO range 0x%04X-0x%04X, IRQ %d\n", niwatchdog->io_base, From f33464170284f1f829c0334f1f5f6faca30fff87 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Thu, 10 Apr 2014 16:40:22 -0500 Subject: [PATCH 36/83] niwatchdog: remove register_dump Removed the register_dump sysfs file. The watchdog works well, there's no longer a need for this debugging file. Signed-off-by: Jeff Westfahl --- drivers/misc/niwatchdog.c | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/drivers/misc/niwatchdog.c b/drivers/misc/niwatchdog.c index 0e67f87463aee..b591d5fbe493b 100644 --- a/drivers/misc/niwatchdog.c +++ b/drivers/misc/niwatchdog.c @@ -100,40 +100,8 @@ static ssize_t niwatchdog_wdmode_set(struct device *dev, static DEVICE_ATTR(watchdog_mode, S_IRUSR|S_IWUSR, niwatchdog_wdmode_get, niwatchdog_wdmode_set); -static ssize_t niwatchdog_register_dump_get(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - struct acpi_device *acpi_device = to_acpi_device(dev); - struct niwatchdog *niwatchdog = acpi_device->driver_data; - u8 control, counter2, counter1, counter0; - u8 seed2, seed1, seed0; - - control = inb(niwatchdog->io_base + NIWD_CONTROL); - counter2 = inb(niwatchdog->io_base + NIWD_COUNTER2); - counter1 = inb(niwatchdog->io_base + NIWD_COUNTER1); - counter0 = inb(niwatchdog->io_base + NIWD_COUNTER0); - seed2 = inb(niwatchdog->io_base + NIWD_SEED2); - seed1 = inb(niwatchdog->io_base + NIWD_SEED1); - seed0 = inb(niwatchdog->io_base + NIWD_SEED0); - - return sprintf(buf, - "Control: 0x%02X\n" - "Counter 2: 0x%02X\n" - "Counter 1: 0x%02X\n" - "Counter 0: 0x%02X\n" - "Seed 2: 0x%02X\n" - "Seed 1: 0x%02X\n" - "Seed 0: 0x%02X\n", - control, counter2, counter1, counter0, - seed2, seed1, seed0); -} - -static DEVICE_ATTR(register_dump, S_IRUGO, niwatchdog_register_dump_get, NULL); - static const struct attribute *niwatchdog_attrs[] = { &dev_attr_watchdog_mode.attr, - &dev_attr_register_dump.attr, NULL }; From 53a819f7f7e92e8ebb36c7bacc5fef317b07cc39 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Fri, 19 Feb 2016 14:27:22 -0600 Subject: [PATCH 37/83] niwatchdog: Explicitly request threaded interrupt Requesting a threaded interrupt explicity and doing so with a NULL handler/non-NULL thread_fn avoids disabling softirqs while the handler executes. This does require setting IRQF_ONESHOT, which was set automatically when using request_irq before. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Josh Cartwright Natinst-ReviewBoard-ID: 127047 --- drivers/misc/niwatchdog.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/misc/niwatchdog.c b/drivers/misc/niwatchdog.c index b591d5fbe493b..25114df5c19db 100644 --- a/drivers/misc/niwatchdog.c +++ b/drivers/misc/niwatchdog.c @@ -300,8 +300,8 @@ static int niwatchdog_misc_open(struct inode *inode, struct file *file) return -EBUSY; } - return request_irq(niwatchdog->irq, niwatchdog_irq, 0, - NIWATCHDOG_NAME, niwatchdog); + return request_threaded_irq(niwatchdog->irq, NULL, niwatchdog_irq, + IRQF_ONESHOT, NIWATCHDOG_NAME, niwatchdog); } static int niwatchdog_misc_release(struct inode *inode, struct file *file) From c11809954f4c8b2063fc1f95f2a6e952319c2559 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Mon, 7 Aug 2017 15:17:44 -0500 Subject: [PATCH 38/83] niwatchdog: Fix error path in ACPI add Use device-managed resource allocation where possible and clean up correctly in the event of an error during ACPI add. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Zach Brown Acked-by: James Minor Acked-by: Ovidiu Vancea Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 196333 [mpeterse: change return type of niwatchdog_acpi_remove due to 6c0eb5ba3500] Signed-off-by: Mike Petersen --- drivers/misc/niwatchdog.c | 94 +++++++++++++-------------------------- 1 file changed, 32 insertions(+), 62 deletions(-) diff --git a/drivers/misc/niwatchdog.c b/drivers/misc/niwatchdog.c index 25114df5c19db..c3e0eeae24c85 100644 --- a/drivers/misc/niwatchdog.c +++ b/drivers/misc/niwatchdog.c @@ -47,7 +47,6 @@ struct niwatchdog { struct acpi_device *acpi_device; u16 io_base; - u16 io_size; u32 irq; spinlock_t lock; struct miscdevice misc_dev; @@ -425,25 +424,35 @@ static const struct file_operations niwatchdog_misc_fops = { static acpi_status niwatchdog_resources(struct acpi_resource *res, void *data) { struct niwatchdog *niwatchdog = data; + struct device *dev = &niwatchdog->acpi_device->dev; + u16 io_size; switch (res->type) { case ACPI_RESOURCE_TYPE_IO: - if ((niwatchdog->io_base != 0) || - (niwatchdog->io_size != 0)) { - dev_err(&niwatchdog->acpi_device->dev, - "too many IO resources\n"); + if (niwatchdog->io_base != 0) { + dev_err(dev, "too many IO resources\n"); return AE_ERROR; } niwatchdog->io_base = res->data.io.minimum; - niwatchdog->io_size = res->data.io.address_length; + io_size = res->data.io.address_length; + + if (io_size < NIWD_IO_SIZE) { + dev_err(dev, "memory region too small\n"); + return AE_ERROR; + } + + if (!devm_request_region(dev, niwatchdog->io_base, io_size, + MODULE_NAME)) { + dev_err(dev, "failed to get memory region\n"); + return AE_ERROR; + } return AE_OK; case ACPI_RESOURCE_TYPE_IRQ: if (niwatchdog->irq != 0) { - dev_err(&niwatchdog->acpi_device->dev, - "too many IRQ resources\n"); + dev_err(dev, "too many IRQ resources\n"); return AE_ERROR; } @@ -455,13 +464,9 @@ static acpi_status niwatchdog_resources(struct acpi_resource *res, void *data) return AE_OK; default: - dev_err(&niwatchdog->acpi_device->dev, - "unsupported resource type %d\n", - res->type); + dev_err(dev, "unsupported resource type %d\n", res->type); return AE_ERROR; } - - return AE_OK; } static void niwatchdog_acpi_remove(struct acpi_device *device) @@ -472,77 +477,53 @@ static void niwatchdog_acpi_remove(struct acpi_device *device) sysfs_remove_files(&niwatchdog->acpi_device->dev.kobj, niwatchdog_attrs); - - if ((niwatchdog->io_base != 0) && - (niwatchdog->io_size == NIWD_IO_SIZE)) - release_region(niwatchdog->io_base, niwatchdog->io_size); - - device->driver_data = NULL; - - kfree(niwatchdog); } static int niwatchdog_acpi_add(struct acpi_device *device) { + struct device *dev = &device->dev; struct niwatchdog *niwatchdog; acpi_status acpi_ret; int err; - niwatchdog = kzalloc(sizeof(*niwatchdog), GFP_KERNEL); - + niwatchdog = devm_kzalloc(dev, sizeof(*niwatchdog), GFP_KERNEL); if (!niwatchdog) return -ENOMEM; device->driver_data = niwatchdog; - niwatchdog->acpi_device = device; acpi_ret = acpi_walk_resources(device->handle, METHOD_NAME__CRS, niwatchdog_resources, niwatchdog); - - if (ACPI_FAILURE(acpi_ret) || - (niwatchdog->io_base == 0) || - (niwatchdog->io_size != NIWD_IO_SIZE) || - (niwatchdog->irq == 0)) { - niwatchdog_acpi_remove(device); + if (ACPI_FAILURE(acpi_ret) || niwatchdog->io_base == 0 || + niwatchdog->irq == 0) { + dev_err(dev, "failed to get resources\n"); return -ENODEV; } - if (!request_region(niwatchdog->io_base, niwatchdog->io_size, - MODULE_NAME)) { - niwatchdog_acpi_remove(device); - return -EBUSY; - } - - err = sysfs_create_files(&niwatchdog->acpi_device->dev.kobj, - niwatchdog_attrs); - if (err) { - niwatchdog_acpi_remove(device); - return err; - } - spin_lock_init(&niwatchdog->lock); atomic_set(&niwatchdog->available, 1); init_waitqueue_head(&niwatchdog->irq_event); niwatchdog->expired = false; + err = sysfs_create_files(&dev->kobj, niwatchdog_attrs); + if (err) { + dev_err(dev, "failed to create sysfs attributes\n"); + return err; + } + niwatchdog->misc_dev.minor = MISC_DYNAMIC_MINOR; niwatchdog->misc_dev.name = NIWATCHDOG_NAME; niwatchdog->misc_dev.fops = &niwatchdog_misc_fops; err = misc_register(&niwatchdog->misc_dev); - if (err) { - niwatchdog_acpi_remove(device); + dev_err(dev, "failed to register misc device\n"); + sysfs_remove_files(&dev->kobj, niwatchdog_attrs); return err; } - dev_info(&niwatchdog->acpi_device->dev, - "IO range 0x%04X-0x%04X, IRQ %d\n", - niwatchdog->io_base, - niwatchdog->io_base + niwatchdog->io_size - 1, niwatchdog->irq); - return 0; } @@ -560,18 +541,7 @@ static struct acpi_driver niwatchdog_acpi_driver = { }, }; -static int __init niwatchdog_init(void) -{ - return acpi_bus_register_driver(&niwatchdog_acpi_driver); -} - -static void __exit niwatchdog_exit(void) -{ - acpi_bus_unregister_driver(&niwatchdog_acpi_driver); -} - -module_init(niwatchdog_init); -module_exit(niwatchdog_exit); +module_acpi_driver(niwatchdog_acpi_driver); MODULE_DEVICE_TABLE(acpi, niwatchdog_device_ids); MODULE_DESCRIPTION("NI Watchdog"); From 54752b6e69bf161c645062152809866f706b1048 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Wed, 2 Aug 2017 13:08:03 -0500 Subject: [PATCH 39/83] niwatchdog: Request IRQ on ACPI add instead of miscdevice open Do what most sane drivers do and request our IRQ on ACPI add rather than doing it every time someone opens our char device. This ensures that our thread exists at boot time, which means priority changes can be done in user mode. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Zach Brown Acked-by: James Minor Acked-by: Ovidiu Vancea Acked-by: Julia Cartwright Natinst-CAR-ID: 648185 Natinst-ReviewBoard-ID: 196333 --- drivers/misc/niwatchdog.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/misc/niwatchdog.c b/drivers/misc/niwatchdog.c index c3e0eeae24c85..02aad34a04de9 100644 --- a/drivers/misc/niwatchdog.c +++ b/drivers/misc/niwatchdog.c @@ -299,15 +299,13 @@ static int niwatchdog_misc_open(struct inode *inode, struct file *file) return -EBUSY; } - return request_threaded_irq(niwatchdog->irq, NULL, niwatchdog_irq, - IRQF_ONESHOT, NIWATCHDOG_NAME, niwatchdog); + return 0; } static int niwatchdog_misc_release(struct inode *inode, struct file *file) { struct niwatchdog *niwatchdog = file->private_data; - free_irq(niwatchdog->irq, niwatchdog); atomic_inc(&niwatchdog->available); return 0; } @@ -458,6 +456,13 @@ static acpi_status niwatchdog_resources(struct acpi_resource *res, void *data) niwatchdog->irq = res->data.irq.interrupts[0]; + if (devm_request_threaded_irq(dev, niwatchdog->irq, NULL, + niwatchdog_irq, IRQF_ONESHOT, + NIWATCHDOG_NAME, niwatchdog)) { + dev_err(dev, "failed to get interrupt\n"); + return AE_ERROR; + } + return AE_OK; case ACPI_RESOURCE_TYPE_END_TAG: From ca976149c0c29419a07e16af620c7e283cb6d253 Mon Sep 17 00:00:00 2001 From: Hui Chun Ong Date: Mon, 6 Feb 2017 23:49:09 +0800 Subject: [PATCH 40/83] watchdog: nic7018_wdt: Add support for trigger pet and trigger assert Add capabilities to use trigger line to reset timer and to assert trigger line upon timeout. The trigger line control and selection is done through sysfs attributes. Signed-off-by: Hui Chun Ong Signed-off-by: Brad Mouring Acked-by: Gratian Crisan Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 192326 (cherry picked from commit d6351b1a5530fb532e948fec6a8e947cca384880) (cherry picked from commit be8a29797de3c2fc60a44993edc24071da2c7f5f) --- drivers/watchdog/nic7018_wdt.c | 168 +++++++++++++++++++++++++++++++++ 1 file changed, 168 insertions(+) diff --git a/drivers/watchdog/nic7018_wdt.c b/drivers/watchdog/nic7018_wdt.c index c3f0a4926667e..8e640ae76d16c 100644 --- a/drivers/watchdog/nic7018_wdt.c +++ b/drivers/watchdog/nic7018_wdt.c @@ -8,7 +8,9 @@ #include #include #include +#include #include +#include #include #define LOCK 0xA5 @@ -16,6 +18,8 @@ #define WDT_CTRL_RESET_EN BIT(7) #define WDT_RELOAD_PORT_EN BIT(7) +#define WDT_CTRL_TRIG_POL BIT(4) +#define WDT_RELOAD_TRIG_POL BIT(6) #define WDT_CTRL 1 #define WDT_RELOAD_CTRL 2 @@ -46,6 +50,7 @@ struct nic7018_wdt { u16 io_base; u32 period; struct watchdog_device wdd; + struct mutex lock; }; struct nic7018_config { @@ -165,6 +170,166 @@ static const struct watchdog_ops nic7018_wdd_ops = { .get_timeleft = nic7018_get_timeleft, }; +struct nic7018_attr { + struct device_attribute dev_attr; + u8 offset; + u8 bit; +}; +#define to_nic7018_attr(_attr) \ + container_of((_attr), struct nic7018_attr, dev_attr) + +static ssize_t wdt_attr_show(struct device *dev, + struct device_attribute *da, + char *buf) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); + struct nic7018_attr *attr = to_nic7018_attr(da); + u8 control; + + mutex_lock(&wdt->lock); + + control = inb(wdt->io_base + attr->offset); + + mutex_unlock(&wdt->lock); + return sprintf(buf, "%u\n", !!(control & attr->bit)); +} + +static ssize_t wdt_attr_store(struct device *dev, + struct device_attribute *da, + const char *buf, + size_t size) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); + struct nic7018_attr *attr = to_nic7018_attr(da); + unsigned long val; + u8 control; + + int ret = kstrtoul(buf, 10, &val); + + if (ret) + return ret; + + if (val > 1) + return -EINVAL; + + mutex_lock(&wdt->lock); + + control = inb(wdt->io_base + attr->offset); + if (val) + outb(control | attr->bit, wdt->io_base + attr->offset); + else + outb(control & ~attr->bit, wdt->io_base + attr->offset); + + mutex_unlock(&wdt->lock); + return size; +} + +#define WDT_ATTR(_name, _offset, _bit) \ + struct nic7018_attr dev_attr_##_name = { \ + .offset = _offset, \ + .bit = _bit, \ + .dev_attr = \ + __ATTR(_name, S_IWUSR | S_IRUGO, \ + wdt_attr_show, wdt_attr_store), \ + } + +static WDT_ATTR(enable_reset, WDT_CTRL, WDT_CTRL_RESET_EN); +static WDT_ATTR(enable_soft_ping, WDT_RELOAD_CTRL, WDT_RELOAD_PORT_EN); +static WDT_ATTR(trigger_polarity, WDT_CTRL, WDT_CTRL_TRIG_POL); +static WDT_ATTR(keepalive_trigger_polarity, WDT_RELOAD_CTRL, + WDT_RELOAD_TRIG_POL); + +static ssize_t wdt_trig_show(struct device *dev, + struct device_attribute *da, + char *buf) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); + struct nic7018_attr *attr = to_nic7018_attr(da); + u8 control; + + mutex_lock(&wdt->lock); + + control = inb(wdt->io_base + attr->offset); + + mutex_unlock(&wdt->lock); + + if (control & 0x0F) + return sprintf(buf, "trig%u\n", (control & 0x0F) - 1); + else + return sprintf(buf, "none\n"); +} + +static ssize_t wdt_trig_store(struct device *dev, + struct device_attribute *da, + const char *buf, + size_t size) +{ + struct watchdog_device *wdd = dev_get_drvdata(dev); + struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); + struct nic7018_attr *attr = to_nic7018_attr(da); + u8 control; + + char *p = memchr(buf, '\n', size); + size_t count = p ? p - buf : size; + + if (count == 5 && !strncmp(buf, "trig", 4)) { + unsigned long val; + int ret; + + ret = kstrtoul(buf + 4, 10, &val); + if (ret) + return ret; + + if (val > 8) + return -EINVAL; + + mutex_lock(&wdt->lock); + + control = inb(wdt->io_base + attr->offset); + outb((control & 0xF0) | (val + 1), + wdt->io_base + attr->offset); + + mutex_unlock(&wdt->lock); + + } else if (count == 4 && !strncmp(buf, "none", 4)) { + mutex_lock(&wdt->lock); + + control = inb(wdt->io_base + attr->offset); + outb(control & 0xF0, wdt->io_base + attr->offset); + + mutex_unlock(&wdt->lock); + } else { + return -EINVAL; + } + + return size; +} + +#define WDT_TRIG_ATTR(_name, _offset) \ + struct nic7018_attr dev_attr_##_name = { \ + .offset = _offset, \ + .dev_attr = \ + __ATTR(_name, S_IWUSR | S_IRUGO, \ + wdt_trig_show, wdt_trig_store), \ + } + +static WDT_TRIG_ATTR(trigger, WDT_CTRL); +static WDT_TRIG_ATTR(keepalive_trigger, WDT_RELOAD_CTRL); + +static struct attribute *nic7018_wdt_attrs[] = { + &dev_attr_enable_reset.dev_attr.attr, + &dev_attr_enable_soft_ping.dev_attr.attr, + &dev_attr_trigger_polarity.dev_attr.attr, + &dev_attr_keepalive_trigger_polarity.dev_attr.attr, + &dev_attr_trigger.dev_attr.attr, + &dev_attr_keepalive_trigger.dev_attr.attr, + NULL +}; +ATTRIBUTE_GROUPS(nic7018_wdt); + static int nic7018_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -191,6 +356,8 @@ static int nic7018_probe(struct platform_device *pdev) return -EBUSY; } + mutex_init(&wdt->lock); + wdt->io_base = io_rc->start; wdd = &wdt->wdd; wdd->info = &nic7018_wdd_info; @@ -199,6 +366,7 @@ static int nic7018_probe(struct platform_device *pdev) wdd->max_timeout = WDT_MAX_TIMEOUT; wdd->timeout = WDT_DEFAULT_TIMEOUT; wdd->parent = dev; + wdd->groups = nic7018_wdt_groups; watchdog_set_drvdata(wdd, wdt); watchdog_set_nowayout(wdd, nowayout); From eb87e230cbced272c058de713725ba01ddc7cd1b Mon Sep 17 00:00:00 2001 From: Hui Chun Ong Date: Sat, 8 Jul 2017 12:33:34 +0800 Subject: [PATCH 41/83] watchdog: nic7018_wdt: Add support for timeout interrupt Add interrupt handling for watchdog timeout. Interrupt control is done through sysfs "enable_interrupt" attribute. uevent is used to signal userspace when interrupt occurred as oppose to using poll due to no support in watchdog core. Signed-off-by: Hui Chun Ong Signed-off-by: Brad Mouring Acked-by: Julia Cartwright Natinst-ReviewBoard-ID: 195479 --- drivers/watchdog/nic7018_wdt.c | 45 +++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/drivers/watchdog/nic7018_wdt.c b/drivers/watchdog/nic7018_wdt.c index 8e640ae76d16c..a85f1d3280de2 100644 --- a/drivers/watchdog/nic7018_wdt.c +++ b/drivers/watchdog/nic7018_wdt.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,9 @@ #define WDT_RELOAD_PORT_EN BIT(7) #define WDT_CTRL_TRIG_POL BIT(4) #define WDT_RELOAD_TRIG_POL BIT(6) +#define WDT_CTRL_INTERRUPT_EN BIT(5) +#define WDT_STATUS 0 #define WDT_CTRL 1 #define WDT_RELOAD_CTRL 2 #define WDT_PRESET_PRESCALE 4 @@ -106,6 +109,31 @@ static int nic7018_set_timeout(struct watchdog_device *wdd, return 0; } +static irqreturn_t nic7018_thread_isr(int irq, void *wdt_arg) +{ + struct nic7018_wdt *wdt = wdt_arg; + struct watchdog_device *wdd = &wdt->wdd; + u8 status, control; + + status = inb(wdt->io_base + WDT_STATUS); + + /* IRQ line asserted */ + if (status & 0x20) { + + mutex_lock(&wdt->lock); + + control = inb(wdt->io_base + WDT_CTRL); + /* Disable IRQ line */ + outb(control & ~WDT_CTRL_INTERRUPT_EN, + wdt->io_base + WDT_CTRL); + + mutex_unlock(&wdt->lock); + + kobject_uevent(&wdd->parent->kobj, KOBJ_CHANGE); + } + return IRQ_HANDLED; +} + static int nic7018_start(struct watchdog_device *wdd) { struct nic7018_wdt *wdt = watchdog_get_drvdata(wdd); @@ -240,6 +268,7 @@ static WDT_ATTR(enable_soft_ping, WDT_RELOAD_CTRL, WDT_RELOAD_PORT_EN); static WDT_ATTR(trigger_polarity, WDT_CTRL, WDT_CTRL_TRIG_POL); static WDT_ATTR(keepalive_trigger_polarity, WDT_RELOAD_CTRL, WDT_RELOAD_TRIG_POL); +static WDT_ATTR(enable_interrupt, WDT_CTRL, WDT_CTRL_INTERRUPT_EN); static ssize_t wdt_trig_show(struct device *dev, struct device_attribute *da, @@ -324,6 +353,7 @@ static struct attribute *nic7018_wdt_attrs[] = { &dev_attr_enable_soft_ping.dev_attr.attr, &dev_attr_trigger_polarity.dev_attr.attr, &dev_attr_keepalive_trigger_polarity.dev_attr.attr, + &dev_attr_enable_interrupt.dev_attr.attr, &dev_attr_trigger.dev_attr.attr, &dev_attr_keepalive_trigger.dev_attr.attr, NULL @@ -336,7 +366,7 @@ static int nic7018_probe(struct platform_device *pdev) struct watchdog_device *wdd; struct nic7018_wdt *wdt; struct resource *io_rc; - int ret; + int ret, irq; wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL); if (!wdt) @@ -356,6 +386,10 @@ static int nic7018_probe(struct platform_device *pdev) return -EBUSY; } + irq = platform_get_irq(pdev, 0); + if (!irq) + return -EINVAL; + mutex_init(&wdt->lock); wdt->io_base = io_rc->start; @@ -372,6 +406,15 @@ static int nic7018_probe(struct platform_device *pdev) watchdog_set_nowayout(wdd, nowayout); watchdog_init_timeout(wdd, timeout, dev); + ret = devm_request_threaded_irq(dev, irq, NULL, + nic7018_thread_isr, + IRQF_ONESHOT, + KBUILD_MODNAME, wdt); + if (ret) { + dev_err(dev, "failed to register interrupt handler\n"); + return ret; + } + /* Unlock WDT register */ outb(UNLOCK, wdt->io_base + WDT_REG_LOCK); From 6a965c1e16d84dd7c9da6644859e79cb9238cfab Mon Sep 17 00:00:00 2001 From: James Minor Date: Mon, 16 Mar 2015 17:22:51 -0500 Subject: [PATCH 42/83] cfg80211: wext: Force scans to occur in AP mode When in AP mode, we should force scans to happen from the wext compatibility layer. This won't hurt when in station mode, and only affects the wl12xx driver. This change is to retain parity with NI's shipped 3.2 kernel. It can be dropped when we switch away from using the WEXT interface, and should not be upstreamed. Signed-off-by: James Minor Reviewed-by: Ben Shelton Reviewed-by: Jaeden Amero Natinst-ReviewBoard-ID: 92027 --- net/wireless/scan.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/net/wireless/scan.c b/net/wireless/scan.c index 18e132cdea72a..6356ea8699a4e 100644 --- a/net/wireless/scan.c +++ b/net/wireless/scan.c @@ -3555,6 +3555,9 @@ int cfg80211_wext_siwscan(struct net_device *dev, /* Set real number of channels specified in creq->channels[] */ creq->n_channels = i; + /* Force the scan if we are in AP mode */ + creq->flags |= NL80211_SCAN_FLAG_AP; + /* translate "Scan for SSID" request */ if (wreq) { if (wrqu->data.flags & IW_SCAN_THIS_ESSID) { From b8382fbb1b137dd17651d4c436b007fe1d430ea5 Mon Sep 17 00:00:00 2001 From: Sundar Subbiah Date: Tue, 2 Apr 2013 15:19:22 -0500 Subject: [PATCH 43/83] wlcore: Depend on WIRELESS_EXT for nitargetcfg This is a hack to get CONFIG_WIRELESS_EXT enabled, since if it is turned on in the defconfig it will not propogate to the .config (as it is not user selectable). Even though the driver does not need it, the current NI user-mode software stacks require this support for scanning and interface enumeration. With this change, it will propogate to the wl12xx driver build (from compat-wireless) and thus include WEXT support in that driver and wireless networking modules. Signed-off-by: Sundar Subbiah Acked-by: James Minor Acked-by: Josh Cartwright Acked-by: Jeff Westfahl Acked-by: Ken Sharp Natinst-ReviewBoard-ID: 37925 --- drivers/net/wireless/ti/wlcore/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/net/wireless/ti/wlcore/Kconfig b/drivers/net/wireless/ti/wlcore/Kconfig index 8094323256fb9..3f652e66e2553 100644 --- a/drivers/net/wireless/ti/wlcore/Kconfig +++ b/drivers/net/wireless/ti/wlcore/Kconfig @@ -3,6 +3,7 @@ config WLCORE tristate "TI wlcore support" depends on MAC80211 select FW_LOADER + select WIRELESS_EXT help This module contains the main code for TI WLAN chips. It abstracts hardware-specific differences among different chipset families. From 0a8f30de4098855b70ba5a5d054308f40db14bd8 Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Thu, 5 Nov 2015 14:53:58 -0600 Subject: [PATCH 44/83] ath6kl: set initial region using DMI info Use the BIOS DMI tables to select an initial region for regulatory info. The region in BIOS will be set in manufacturing based on where the product is to be used. This is intended to facilitate channel and power level selection based on the product's SKU. Signed-off-by: Nathan Sullivan Signed-off-by: James Minor Signed-off-by: Brad Mouring Natinst-CAR-ID: 578408 Natinst-ReviewBoard-ID: 120508 Natinst-ReviewBoard-ID: 130950 Natinst-Trello-ID: https://trello.com/c/xCpOlFJt [bstreiff: remove elvisiii dts changes as part of zynq removal] Signed-off-by: Brandon Streiff [gratian: update Kconfig '---help---' to 'help'] Signed-off-by: Gratian Crisan --- drivers/net/wireless/ath/ath6kl/Kconfig | 9 +++++ drivers/net/wireless/ath/ath6kl/core.c | 50 +++++++++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.c | 6 +++ drivers/net/wireless/ath/ath6kl/wmi.h | 3 ++ 4 files changed, 68 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index cd96cf8d99409..a9ac19f2c3727 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -64,3 +64,12 @@ config ATH6KL_REGDOMAIN are taken into account. If unsure, say N. + +config ATH6KL_NI_BIOS_DOMAIN + bool "Atheros ath6kl DMI regdomain support" + depends on ATH6KL + help + Enabling this will cause the ath6kl driver to load the initial + regdomain from BIOS DMI tables. + + If unsure, say N. diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 4f0a7a185fc91..411b92c7229de 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include "debug.h" #include "hif-ops.h" @@ -51,6 +53,31 @@ MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic polling in msecs - Also set recovery_enable for this to be effective"); +#define WLAN_REGION_ID 161 +#ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN +struct region_table { + struct dmi_header header; + char padding[3]; + char alpha2[2]; +}; + +static char region[2]; +static void find_region_type(const struct dmi_header *dm, void *private_data) +{ + int *found = (int *)private_data; + + if (dm->type == WLAN_REGION_ID) { + struct region_table *table = + container_of(dm, struct region_table, header); + + ath6kl_dbg(ATH6KL_DBG_TRC, "Region code from BIOS: %c%c\n", + table->alpha2[0], table->alpha2[1]); + memcpy(region, table->alpha2, 2); + *found = 1; + } +} +#endif + void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) { ath6kl_htc_tx_complete(ar, skb); @@ -69,6 +96,20 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) struct wireless_dev *wdev; int ret = 0, i; +#ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN + /* get region code from DMI */ + dmi_walk(find_region_type, &ret); + if (!ret) + return -ENODEV; + + if (!isascii(region[0]) || !isascii(region[1])) + return -EINVAL; + + ath6kl_info("Using region: %c%c\n", + region[0], + region[1]); +#endif + switch (htc_type) { case ATH6KL_HTC_TYPE_MBOX: ath6kl_htc_mbox_attach(ar); @@ -194,6 +235,15 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) goto err_rxbuf_cleanup; } +#ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN + /* set region from DMI if it is US */ + if (region[0] == 'U' && region[1] == 'S') { + ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, region); + if (ret) + goto err_rxbuf_cleanup; + } +#endif + /* give our connected endpoints some buffers */ ath6kl_rx_refill(ar->htc_target, ar->ctrl_ep); ath6kl_rx_refill(ar->htc_target, ar->ac2ep_map[WMM_AC_BE]); diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 3787b9fb00755..795df241ba504 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -3294,9 +3294,15 @@ int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2) cmd = (struct wmi_set_regdomain_cmd *) skb->data; memcpy(cmd->iso_name, alpha2, 2); +#ifdef CONFIG_ATH6KL_SILEX_FIRMWARE + return ath6kl_wmi_cmd_send(wmi, 0, skb, + WMI_SET_REGDOMAIN_SILEX_CMDID, + NO_SYNC_WMIFLAG); +#else return ath6kl_wmi_cmd_send(wmi, 0, skb, WMI_SET_REGDOMAIN_CMDID, NO_SYNC_WMIFLAG); +#endif } s32 ath6kl_wmi_get_rate(struct wmi *wmi, s8 rate_index) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index b4fcfb72991c1..7cb21de2911c1 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -644,6 +644,9 @@ enum wmi_cmd_id { WMI_ENABLE_SCHED_SCAN_CMDID, }; +/* Silex has this command at a different ID */ +#define WMI_SET_REGDOMAIN_SILEX_CMDID 0xf0b0 + enum wmi_mgmt_frame_type { WMI_FRAME_BEACON = 0, WMI_FRAME_PROBE_REQ, From 487a975beebf81a7f457325bdde929ae86171df2 Mon Sep 17 00:00:00 2001 From: James Minor Date: Wed, 28 Oct 2015 12:16:56 -0500 Subject: [PATCH 45/83] ath6kl: Add Silex firmware capabilities Signed-off-by: James Minor [gratian: update Kconfig '---help---' to 'help'] Signed-off-by: Gratian Crisan --- drivers/net/wireless/ath/ath6kl/Kconfig | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/Kconfig b/drivers/net/wireless/ath/ath6kl/Kconfig index a9ac19f2c3727..89eddce784310 100644 --- a/drivers/net/wireless/ath/ath6kl/Kconfig +++ b/drivers/net/wireless/ath/ath6kl/Kconfig @@ -73,3 +73,12 @@ config ATH6KL_NI_BIOS_DOMAIN regdomain from BIOS DMI tables. If unsure, say N. + +config ATH6KL_SILEX_FIRMWARE + bool "Atheros ath6kl Silex firmware support" + depends on ATH6KL + help + Enabling this will cause the ath6kl driver to use customizations + required by the firmware from Silex. + + If unsure, say N. From 931345165b2a344d8fd8141ffd4ad221999eedec Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Wed, 16 Mar 2016 09:01:15 -0500 Subject: [PATCH 46/83] ath6kl: select board file using DMI info In addition to setting the region on the device, switch board files based on the selected region from BIOS. This allows different boards to load files with different power levels for regulatory purposes. Signed-off-by: Nathan Sullivan Signed-off-by: Brad Mouring Acked-by: Xander Huff Acked-by: James Minor Natinst-CAR-ID: 578408 Natinst-ReviewBoard-ID: 130950 --- drivers/net/wireless/ath/ath6kl/core.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 411b92c7229de..af953f2329ff2 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -97,6 +97,7 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) int ret = 0, i; #ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN + char *region_board_file = NULL; /* get region code from DMI */ dmi_walk(find_region_type, &ret); if (!ret) @@ -160,6 +161,17 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) ar->testmode = testmode; +#ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN + /* ath6kl_init_hw_params() will set the board file name, but we want + * to override it with a region specific board file here. + */ + region_board_file = devm_kzalloc(ar->dev, 64, GFP_KERNEL); + + snprintf(region_board_file, 64, AR6004_HW_3_0_FW_DIR "/bdata%c%c.bin", + region[0], region[1]); + + ar->hw.fw_board = region_board_file; +#endif ret = ath6kl_init_fetch_firmwares(ar); if (ret) goto err_htc_cleanup; From 58e98fb7db808724fd88c08454df0808c03a2ce3 Mon Sep 17 00:00:00 2001 From: James Minor Date: Mon, 4 Apr 2016 12:15:18 -0500 Subject: [PATCH 47/83] ath6kl: Add ATH6KL_FW_CAPABILITY_SET_RSN_CAP capabilities Some firmwares offer the ability to directly set the RSN with WMI_SET_RSN_CAP_CMDID instead of using WMI_SET_IE_CMDID. Add the flags and functions to make that work. Signed-off-by: James Minor Signed-off-by: Brad Mouring Natinst-ReviewBoard-ID: 133028 Natinst-CAR-ID: 577496 --- drivers/net/wireless/ath/ath6kl/cfg80211.c | 22 +++++++++++++++------- drivers/net/wireless/ath/ath6kl/core.h | 3 +++ drivers/net/wireless/ath/ath6kl/init.c | 1 + drivers/net/wireless/ath/ath6kl/wmi.c | 18 ++++++++++++++++++ drivers/net/wireless/ath/ath6kl/wmi.h | 6 ++++++ 5 files changed, 43 insertions(+), 7 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c index 61b2e3f15f0e9..189b3e16a605d 100644 --- a/drivers/net/wireless/ath/ath6kl/cfg80211.c +++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c @@ -2933,14 +2933,22 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev, * advertise the same in beacon/probe response. Send * the complete RSN IE capability field to firmware */ - if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *) &rsn_capab) && - test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, - ar->fw_capabilities)) { - res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, - WLAN_EID_RSN, WMI_RSN_IE_CAPB, - (const u8 *) &rsn_capab, - sizeof(rsn_capab)); + if (!ath6kl_get_rsn_capab(&info->beacon, (u8 *)&rsn_capab)) { vif->rsn_capab = rsn_capab; + res = -EIO; + if (test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE, + ar->fw_capabilities)) { + res = ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx, + WLAN_EID_RSN, + WMI_RSN_IE_CAPB, + (const u8 *)&rsn_capab, + sizeof(rsn_capab)); + } + if (test_bit(ATH6KL_FW_CAPABILITY_SET_RSN_CAP, + ar->fw_capabilities)) { + res = ath6kl_wmi_set_rsn_cmd(ar->wmi, vif->fw_vif_idx, + rsn_capab); + } if (res < 0) return res; } diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 77e052336eb5b..96c8ab6f096f7 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -151,6 +151,9 @@ enum ath6kl_fw_capability { /* firmware doesn't support IP checksumming */ ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, + /* firmware supports setting RSN CAP directly */ + ATH6KL_FW_CAPABILITY_SET_RSN_CAP, + /* this needs to be last */ ATH6KL_FW_CAPABILITY_MAX, }; diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 15f455adb8609..1794f4f120837 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1644,6 +1644,7 @@ static const struct fw_capa_str_map { { ATH6KL_FW_CAPABILITY_MAP_LP_ENDPOINT, "map-lp-endpoint" }, { ATH6KL_FW_CAPABILITY_RATETABLE_MCS15, "ratetable-mcs15" }, { ATH6KL_FW_CAPABILITY_NO_IP_CHECKSUM, "no-ip-checksum" }, + { ATH6KL_FW_CAPABILITY_SET_RSN_CAP, "set-rsn-cap" }, }; static const char *ath6kl_init_get_fw_capa_name(unsigned int id) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index 795df241ba504..f1bf7a17bf1e4 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -3569,6 +3569,24 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, NO_SYNC_WMIFLAG); } +int ath6kl_wmi_set_rsn_cmd(struct wmi *wmi, u8 if_idx, u16 rsn_capab) +{ + struct sk_buff *skb; + struct wmi_set_rsn_cmd *p; + + skb = ath6kl_wmi_get_new_buf(sizeof(*p)); + if (!skb) + return -ENOMEM; + + ath6kl_info("set_rsn_cmd: rsn_capab=0x%4.4x\n", + rsn_capab); + p = (struct wmi_set_rsn_cmd *)skb->data; + p->rsn_capab = rsn_capab; + + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSN_CAP_CMDID, + NO_SYNC_WMIFLAG); +} + int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field, const u8 *ie_info, u8 ie_len) { diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 7cb21de2911c1..448be1dc0499e 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -2057,6 +2057,10 @@ struct wmi_set_appie_cmd { u8 ie_info[]; } __packed; +struct wmi_set_rsn_cmd { + u16 rsn_capab; +} __packed; + struct wmi_set_ie_cmd { u8 ie_id; u8 ie_field; /* enum wmi_ie_field_type */ @@ -2691,6 +2695,8 @@ int ath6kl_wmi_set_rx_frame_format_cmd(struct wmi *wmi, u8 if_idx, u8 rx_meta_version, bool rx_dot11_hdr, bool defrag_on_host); +int ath6kl_wmi_set_rsn_cmd(struct wmi *wmi, u8 if_idx, u16 rsn_capab); + int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, const u8 *ie, u8 ie_len); From b0f5ee6acc67f3e7ead8ebad784abd7ba9156b4a Mon Sep 17 00:00:00 2001 From: James Minor Date: Mon, 4 Apr 2016 12:17:46 -0500 Subject: [PATCH 48/83] ath6kl: Add Silex enums to set APPIE and RSN CAP Silex uses different command IDs for the commands WMI_SET_APPIE_CMDID and WMI_SET_RSN_CAP_SILEX_CMDID. In case of the Silex firmware, remap them to the correct command ID. Signed-off-by: James Minor Signed-off-by: Brad Mouring Natinst-ReviewBoard-ID: 133028 Natinst-CAR-ID: 577496 --- drivers/net/wireless/ath/ath6kl/wmi.c | 18 +++++++++++++++--- drivers/net/wireless/ath/ath6kl/wmi.h | 2 ++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/wmi.c b/drivers/net/wireless/ath/ath6kl/wmi.c index f1bf7a17bf1e4..dc00f07223d41 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.c +++ b/drivers/net/wireless/ath/ath6kl/wmi.c @@ -3565,8 +3565,13 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type, if (ie != NULL && ie_len > 0) memcpy(p->ie_info, ie, ie_len); - return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_APPIE_CMDID, - NO_SYNC_WMIFLAG); +#ifdef CONFIG_ATH6KL_SILEX_FIRMWARE + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_SET_APPIE_SILEX_CMDID, NO_SYNC_WMIFLAG); +#else + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_SET_APPIE_CMDID, NO_SYNC_WMIFLAG); +#endif } int ath6kl_wmi_set_rsn_cmd(struct wmi *wmi, u8 if_idx, u16 rsn_capab) @@ -3583,8 +3588,15 @@ int ath6kl_wmi_set_rsn_cmd(struct wmi *wmi, u8 if_idx, u16 rsn_capab) p = (struct wmi_set_rsn_cmd *)skb->data; p->rsn_capab = rsn_capab; - return ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSN_CAP_CMDID, +#ifdef CONFIG_ATH6KL_SILEX_FIRMWARE + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_SET_RSN_CAP_SILEX_CMDID, + NO_SYNC_WMIFLAG); +#else + return ath6kl_wmi_cmd_send(wmi, if_idx, skb, + WMI_SET_RSN_CAP_CMDID, NO_SYNC_WMIFLAG); +#endif } int ath6kl_wmi_set_ie_cmd(struct wmi *wmi, u8 if_idx, u8 ie_id, u8 ie_field, diff --git a/drivers/net/wireless/ath/ath6kl/wmi.h b/drivers/net/wireless/ath/ath6kl/wmi.h index 448be1dc0499e..c6d6dbdf0c338 100644 --- a/drivers/net/wireless/ath/ath6kl/wmi.h +++ b/drivers/net/wireless/ath/ath6kl/wmi.h @@ -646,6 +646,8 @@ enum wmi_cmd_id { /* Silex has this command at a different ID */ #define WMI_SET_REGDOMAIN_SILEX_CMDID 0xf0b0 +#define WMI_SET_APPIE_SILEX_CMDID 0x3f +#define WMI_SET_RSN_CAP_SILEX_CMDID 0xf082 enum wmi_mgmt_frame_type { WMI_FRAME_BEACON = 0, From 3c3bdf0e7796dfd3d928b700a2b5652eede40f20 Mon Sep 17 00:00:00 2001 From: James Minor Date: Thu, 25 Feb 2016 10:18:02 -0600 Subject: [PATCH 49/83] ath6kl: fix firmware race condition by retrying initialization Sometimes the devices will fail to boot the first time, but will work fine when retried. Retry the initialization a few times before failing (and reset the hardware properly when it fails). Signed-off-by: James Minor Signed-off-by: Brad Mouring Natinst-ReviewBoard-ID: 130170 Natinst-CAR-ID: 566029 --- drivers/net/wireless/ath/ath6kl/core.c | 18 +++++++++++++++--- drivers/net/wireless/ath/ath6kl/core.h | 3 +++ drivers/net/wireless/ath/ath6kl/init.c | 2 ++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index af953f2329ff2..90379b73fb04e 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -38,6 +38,7 @@ static unsigned int ath6kl_p2p; static unsigned int testmode; static unsigned int recovery_enable; static unsigned int heart_beat_poll; +static unsigned int boot_attempts; module_param(debug_mask, uint, 0644); module_param(suspend_mode, uint, 0644); @@ -48,9 +49,11 @@ module_param(ath6kl_p2p, uint, 0644); module_param(testmode, uint, 0644); module_param(recovery_enable, uint, 0644); module_param(heart_beat_poll, uint, 0644); +module_param(boot_attempts, uint, 0644); MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error"); MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic polling in msecs - Also set recovery_enable for this to be effective"); +MODULE_PARM_DESC(boot_attempts, "Number of times to retry booting the firmware"); #define WLAN_REGION_ID 161 @@ -111,6 +114,8 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) region[1]); #endif + ar->boot_attempts = boot_attempts; + switch (htc_type) { case ATH6KL_HTC_TYPE_MBOX: ath6kl_htc_mbox_attach(ar); @@ -242,11 +247,18 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) ath6kl_debug_init(ar); ret = ath6kl_init_hw_start(ar); - if (ret) { - ath6kl_err("Failed to start hardware: %d\n", ret); - goto err_rxbuf_cleanup; + while (ret && ar->boot_attempts) { + ath6kl_err("Failed to start hardware: %d (retry %d)\n", + ret, + ar->boot_attempts); + ar->boot_attempts--; + ret = ath6kl_init_hw_start(ar); } + if (ret) + /* Did not boot after several attempts */ + goto err_rxbuf_cleanup; + #ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN /* set region from DMI if it is US */ if (region[0] == 'U' && region[1] == 'S') { diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 96c8ab6f096f7..2c9c0cac314eb 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -874,6 +874,9 @@ struct ath6kl { u8 disc_timeout; } debug; #endif /* CONFIG_ATH6KL_DEBUG */ + + /* Number of times we have attempted to boot the radio */ + unsigned int boot_attempts; }; static inline struct ath6kl *ath6kl_priv(struct net_device *dev) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index 1794f4f120837..a77827d787184 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -1775,6 +1775,8 @@ static int __ath6kl_init_hw_start(struct ath6kl *ar) WMI_TIMEOUT); if (timeleft <= 0) { clear_bit(WMI_READY, &ar->flag); + ath6kl_init_hw_reset(ar); + ath6kl_bmi_reset(ar); ath6kl_err("wmi is not ready or wait was interrupted: %ld\n", timeleft); ret = -EIO; From 79fffef158db289a718a023650ca189469739cc6 Mon Sep 17 00:00:00 2001 From: James Minor Date: Mon, 25 Apr 2016 12:18:10 -0500 Subject: [PATCH 50/83] ath6kl: Retry SDIO function initialization on failure Sometimes the AR6234 gives us a error "ath6kl: Unable to enable sdio func: -62". This indicates that the enable bit for the function did not result in the function's status bit in the SDIO_CCCR_IORx register getting set within a reasonable period of time (like 400ms). The guess at this point is that the radio is coming up in some strange state and the power-on reset did not clean things up as it should have. This occurs about once every thousand or so reboots. Experimentation has shown that resetting the device after this has happened allows the function enable to correctly set the function's bit in the SDIO_CCCR_IORx. This change will reset the AR6234 and try the function enable again if the module parameter boot_attempts is set to >0. This has been tested over several thousand reboots, and the driver will recover correctly when it would have otherwise failed to initialize. Signed-off-by: James Minor Signed-off-by: Brad Mouring Acked-by: Nathan Sullivan Acked-by: Xander Huff Natinst-ReviewBoard-ID: 135864 Natinst-CAR-ID: 579000 --- drivers/net/wireless/ath/ath6kl/core.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 90379b73fb04e..a53ab66bc562b 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -142,6 +142,15 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) * seconds. */ ret = ath6kl_hif_power_on(ar); + while (ret && ar->boot_attempts) { + ath6kl_err("Failed to turn on hardware: %d (retry %d)\n", + ret, + ar->boot_attempts); + ar->boot_attempts--; + ret = ath6kl_hif_power_off(ar); + ret = ath6kl_hif_power_on(ar); + } + if (ret) goto err_bmi_cleanup; From 80a66168b13f03b0d7a6cc26203ccd9b8d2acf91 Mon Sep 17 00:00:00 2001 From: Wilson Lee Date: Mon, 5 Jun 2017 11:00:51 +0800 Subject: [PATCH 51/83] ni: wifi: ath6kl: Enable BIOS code to load "bdata.XX.bin" board file. Linux upstream had accepted the load of different board file using DTS method with board file name format of "bdata.XX.bin". Hence, we need to modify BIOS code to use same board file name format to match with the upstream code. Signed-off-by: Wilson Lee Signed-off-by: Brad Mouring Acked-by: Keng Soon Cheah Acked-by: Joseph Hershberger Acked-by: Chen Yee Chew Natinst-ReviewBoard-ID: 203623 Perforce-ReviewBoard-ID: 203621 --- drivers/net/wireless/ath/ath6kl/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index a53ab66bc562b..5084562978069 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -181,7 +181,7 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) */ region_board_file = devm_kzalloc(ar->dev, 64, GFP_KERNEL); - snprintf(region_board_file, 64, AR6004_HW_3_0_FW_DIR "/bdata%c%c.bin", + snprintf(region_board_file, 64, AR6004_HW_3_0_FW_DIR "/bdata.%c%c.bin", region[0], region[1]); ar->hw.fw_board = region_board_file; From b88feb11f063116b537783d1d6e70d34483518d3 Mon Sep 17 00:00:00 2001 From: James Minor Date: Tue, 27 Feb 2018 16:08:49 -0600 Subject: [PATCH 52/83] net: ath6kl: silex: Separate region and board file selection To support the single antenna board files for products with 1 antenna, separate out the selection of the region from the selection of the board file. On OF platforms, there will now be 2 device tree entries: atheros,region-code - The region code (like US) atheros,board-id - The board file code (like 00, 10, etc) In the process, do a small refactor of the CONFIG_ATH6KL_NI_BIOS_DOMAIN case to be more consistent with the device tree case. Signed-off-by: James Minor Signed-off-by: Brad Mouring Acked-by: Nathan Sullivan Acked-by: Kyle Roeschley Natinst-ReviewBoard-ID: 223288 Natinst-CAR-ID: 686866 --- drivers/net/wireless/ath/ath6kl/core.c | 61 ++--------------- drivers/net/wireless/ath/ath6kl/core.h | 4 ++ drivers/net/wireless/ath/ath6kl/init.c | 90 ++++++++++++++++++++++++++ 3 files changed, 98 insertions(+), 57 deletions(-) diff --git a/drivers/net/wireless/ath/ath6kl/core.c b/drivers/net/wireless/ath/ath6kl/core.c index 5084562978069..16873b7b578f3 100644 --- a/drivers/net/wireless/ath/ath6kl/core.c +++ b/drivers/net/wireless/ath/ath6kl/core.c @@ -21,8 +21,6 @@ #include #include #include -#include -#include #include "debug.h" #include "hif-ops.h" @@ -56,31 +54,6 @@ MODULE_PARM_DESC(heart_beat_poll, MODULE_PARM_DESC(boot_attempts, "Number of times to retry booting the firmware"); -#define WLAN_REGION_ID 161 -#ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN -struct region_table { - struct dmi_header header; - char padding[3]; - char alpha2[2]; -}; - -static char region[2]; -static void find_region_type(const struct dmi_header *dm, void *private_data) -{ - int *found = (int *)private_data; - - if (dm->type == WLAN_REGION_ID) { - struct region_table *table = - container_of(dm, struct region_table, header); - - ath6kl_dbg(ATH6KL_DBG_TRC, "Region code from BIOS: %c%c\n", - table->alpha2[0], table->alpha2[1]); - memcpy(region, table->alpha2, 2); - *found = 1; - } -} -#endif - void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb) { ath6kl_htc_tx_complete(ar, skb); @@ -99,21 +72,6 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) struct wireless_dev *wdev; int ret = 0, i; -#ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN - char *region_board_file = NULL; - /* get region code from DMI */ - dmi_walk(find_region_type, &ret); - if (!ret) - return -ENODEV; - - if (!isascii(region[0]) || !isascii(region[1])) - return -EINVAL; - - ath6kl_info("Using region: %c%c\n", - region[0], - region[1]); -#endif - ar->boot_attempts = boot_attempts; switch (htc_type) { @@ -175,17 +133,6 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) ar->testmode = testmode; -#ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN - /* ath6kl_init_hw_params() will set the board file name, but we want - * to override it with a region specific board file here. - */ - region_board_file = devm_kzalloc(ar->dev, 64, GFP_KERNEL); - - snprintf(region_board_file, 64, AR6004_HW_3_0_FW_DIR "/bdata.%c%c.bin", - region[0], region[1]); - - ar->hw.fw_board = region_board_file; -#endif ret = ath6kl_init_fetch_firmwares(ar); if (ret) goto err_htc_cleanup; @@ -268,10 +215,10 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type) /* Did not boot after several attempts */ goto err_rxbuf_cleanup; -#ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN - /* set region from DMI if it is US */ - if (region[0] == 'U' && region[1] == 'S') { - ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, region); +#ifdef CONFIG_ATH6KL_SILEX_FIRMWARE + /* set US region if this device is a US device (US or 1S) */ + if (ar->region[0] == 'U' && ar->region[1] == 'S') { + ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, ar->region); if (ret) goto err_rxbuf_cleanup; } diff --git a/drivers/net/wireless/ath/ath6kl/core.h b/drivers/net/wireless/ath/ath6kl/core.h index 2c9c0cac314eb..6fdbaf977154d 100644 --- a/drivers/net/wireless/ath/ath6kl/core.h +++ b/drivers/net/wireless/ath/ath6kl/core.h @@ -877,6 +877,10 @@ struct ath6kl { /* Number of times we have attempted to boot the radio */ unsigned int boot_attempts; + +#ifdef CONFIG_ATH6KL_SILEX_FIRMWARE + unsigned char region[2]; +#endif }; static inline struct ath6kl *ath6kl_priv(struct net_device *dev) diff --git a/drivers/net/wireless/ath/ath6kl/init.c b/drivers/net/wireless/ath/ath6kl/init.c index a77827d787184..3d154b6bae378 100644 --- a/drivers/net/wireless/ath/ath6kl/init.c +++ b/drivers/net/wireless/ath/ath6kl/init.c @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include "core.h" #include "cfg80211.h" @@ -32,6 +34,8 @@ #include "hif-ops.h" #include "htc-ops.h" +#define WLAN_REGION_ID 161 + static const struct ath6kl_hw hw_list[] = { { .id = AR6003_HW_2_0_VERSION, @@ -706,6 +710,10 @@ static bool check_device_tree(struct ath6kl *ar) char board_filename[64]; const char *board_id; int ret; +#ifdef CONFIG_ATH6KL_SILEX_FIRMWARE + static const char *region_code_prop = "atheros,region-code"; + const char *region_code; +#endif for_each_compatible_node(node, NULL, "atheros,ath6kl") { board_id = of_get_property(node, board_id_prop, NULL); @@ -724,6 +732,16 @@ static bool check_device_tree(struct ath6kl *ar) board_filename, ret); continue; } +#ifdef CONFIG_ATH6KL_SILEX_FIRMWARE + region_code = of_get_property(node, region_code_prop, NULL); + if (region_code == NULL) { + ath6kl_warn("No \"%s\" property on %s node.\n", + region_code_prop, node->name); + continue; + } + /* Silex firmware needs a region command in some cases */ + memcpy(&ar->region, region_code, 2); +#endif of_node_put(node); return true; } @@ -736,6 +754,73 @@ static bool check_device_tree(struct ath6kl *ar) } #endif /* CONFIG_OF */ +#ifdef CONFIG_ATH6KL_NI_BIOS_DOMAIN +struct region_table { + struct dmi_header header; + char padding[3]; + char alpha2[2]; +}; + +static char region[2]; +static void find_region_type(const struct dmi_header *dm, void *private_data) +{ + int *found = (int *)private_data; + + if (dm->type == WLAN_REGION_ID) { + struct region_table *table = + container_of(dm, struct region_table, header); + + memcpy(region, table->alpha2, 2); + *found = 1; + } +} + +static bool check_ni_bios(struct ath6kl *ar) +{ + char *region_board_file = NULL; + int ret = 0; + + /* get region code from DMI */ + dmi_walk(find_region_type, &ret); + if (!ret) + return -ENODEV; + + if (!isascii(region[0]) || !isascii(region[1])) + return -EINVAL; + + ath6kl_info("Using BIOS region: %c%c\n", + region[0], + region[1]); + +#ifdef CONFIG_ATH6KL_SILEX_FIRMWARE + /* Silex firmware needs a region command in some cases */ + memcpy(&ar->region, region, 2); +#endif + + /* ath6kl_init_hw_params() will set the board file name, but we want + * to override it with a region specific board file here. + */ + region_board_file = devm_kzalloc(ar->dev, 64, GFP_KERNEL); + + snprintf(region_board_file, 64, AR6004_HW_3_0_FW_DIR "/bdata.%c%c.bin", + region[0], region[1]); + + ret = ath6kl_get_fw(ar, region_board_file, &ar->fw_board, + &ar->fw_board_len); + if (ret) { + ath6kl_err("Failed to get BIOS board file %s: %d\n", + region_board_file, ret); + return false; + } + return true; +} +#else +static bool check_ni_bios(struct ath6kl *ar) +{ + return false; +} +#endif /* CONFIG_ATH6KL_NI_BIOS_DOMAIN */ + static int ath6kl_fetch_board_file(struct ath6kl *ar) { const char *filename; @@ -761,6 +846,11 @@ static int ath6kl_fetch_board_file(struct ath6kl *ar) return 0; } + if (check_ni_bios(ar)) { + /* got board file from BIOS */ + return 0; + } + /* there was no proper board file, try to use default instead */ ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n", filename, ret); From be1835769aeac322c0dab2e0c7f3233bb7727383 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Thu, 31 Aug 2017 19:58:11 -0500 Subject: [PATCH 53/83] mmc: core: Wait for Vdd to settle on card power off The SD spec version 6.0 section 6.4.1.5 requires that Vdd must be lowered to less than 0.5V for a minimum of 1 ms when powering off a card. Increase our wait to 15 ms so that voltage has time to drain down to 0.5V. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: James Minor Acked-by: Brandon Streiff Natinst-ReviewBoard-ID: 203804 --- drivers/mmc/host/sdhci.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 4b91c9e966357..4b311420788e4 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2372,6 +2372,9 @@ void sdhci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) else sdhci_set_power(host, ios->power_mode, ios->vdd); + if (ios->power_mode == MMC_POWER_OFF) + mdelay(15); + if (host->ops->platform_send_init_74_clocks) host->ops->platform_send_init_74_clocks(host, ios->power_mode); From b7a7efc78d2f300097bb5b56e606504a61d06c21 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Tue, 24 Apr 2018 08:27:03 -0500 Subject: [PATCH 54/83] mmc: sdhci: Disable SD card clock before changing parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the SD Host Controller Simplified Specification v4.20 §3.2.3, change the SD card clock parameters only after first disabling the external card clock. Doing this fixes a spurious clock pulse on Baytrail and Apollo Lake SD controllers which otherwise breaks voltage switching with a specific Swissbit SD card. Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Tony Liechty Acked-by: Nathan Sullivan Natinst-ReviewBoard-ID: 236135 Natinst-CAR-ID: 694815 --- drivers/mmc/host/sdhci.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 4b311420788e4..8b90f107acd40 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -2035,10 +2035,15 @@ void sdhci_set_clock(struct sdhci_host *host, unsigned int clock) host->mmc->actual_clock = 0; - sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); + clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL); + if (clk & SDHCI_CLOCK_CARD_EN) + sdhci_writew(host, clk & ~SDHCI_CLOCK_CARD_EN, + SDHCI_CLOCK_CONTROL); - if (clock == 0) + if (clock == 0) { + sdhci_writew(host, 0, SDHCI_CLOCK_CONTROL); return; + } clk = sdhci_calc_clk(host, clock, &host->mmc->actual_clock); sdhci_enable_clk(host, clk); From 43808477f3a027ee808bc6674cab0867d5905a87 Mon Sep 17 00:00:00 2001 From: Kyle Roeschley Date: Tue, 15 May 2018 13:56:50 -0500 Subject: [PATCH 55/83] mmc: sdhci: Handle tuning error interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the §2.2.19 of the SD Host Controller Simplified Specification Version 4.20, the Tuning Error interrupt is set when an unrecoverable error is detected by the host controller in the tuning circuit when not executing the tuning procedure. Handle this interrupt by printing a useful error message and re-tuning (also per the spec). Signed-off-by: Kyle Roeschley Signed-off-by: Brad Mouring Acked-by: Tony Liechty Acked-by: Nathan Sullivan Natinst-ReviewBoard-ID: 236135 Natinst-CAR-ID: 696866 [gratian: adjust includes for 5857b29b96dc ("mmc: core: Move public functions from host.h to private headers")] Signed-off-by: Gratian Crisan [cvadrevu: resolve conflict with d9ae0aa8ff8fd ("mmc: sdhci: Add support for "Tuning Error" interrupts")] Signed-off-by: Chaitanya Vadrevu --- drivers/mmc/host/sdhci.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 8b90f107acd40..811bba7007e96 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -32,6 +32,7 @@ #include #include +#include "../core/host.h" #include "sdhci.h" #define DRIVER_NAME "sdhci" @@ -304,7 +305,7 @@ static void sdhci_set_default_irqs(struct sdhci_host *host) if (host->tuning_mode == SDHCI_TUNING_MODE_2 || host->tuning_mode == SDHCI_TUNING_MODE_3) - host->ier |= SDHCI_INT_RETUNE; + host->ier |= SDHCI_INT_RETUNE | SDHCI_INT_TUNING_ERROR; sdhci_writel(host, host->ier, SDHCI_INT_ENABLE); sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE); @@ -3589,6 +3590,24 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) if (intmask & SDHCI_INT_RETUNE) mmc_retune_needed(host->mmc); + if (intmask & SDHCI_INT_TUNING_ERROR) { + u16 ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); + /* + * Only complain and retune if we're actually using the + * host's tuning circuits. + */ + if (ctrl2 & SDHCI_CTRL_TUNED_CLK) { + sdhci_writew(host, + ctrl2 & ~SDHCI_CTRL_TUNED_CLK, + SDHCI_HOST_CONTROL2); + mmc_retune_recheck(host->mmc); + pr_err("%s: Unrecoverable error in tuning circuit\n", + mmc_hostname(host->mmc)); + } + sdhci_writel(host, SDHCI_INT_TUNING_ERROR, + SDHCI_INT_STATUS); + } + if ((intmask & SDHCI_INT_CARD_INT) && (host->ier & SDHCI_INT_CARD_INT)) { sdhci_enable_sdio_irq_nolock(host, false); @@ -3598,7 +3617,8 @@ static irqreturn_t sdhci_irq(int irq, void *dev_id) intmask &= ~(SDHCI_INT_CARD_INSERT | SDHCI_INT_CARD_REMOVE | SDHCI_INT_CMD_MASK | SDHCI_INT_DATA_MASK | SDHCI_INT_ERROR | SDHCI_INT_BUS_POWER | - SDHCI_INT_RETUNE | SDHCI_INT_CARD_INT); + SDHCI_INT_RETUNE | SDHCI_INT_TUNING_ERROR | + SDHCI_INT_CARD_INT); if (intmask) { unexpected |= intmask; From 05521a6d17116b27aebf2c7a3104a6db3dd1b637 Mon Sep 17 00:00:00 2001 From: Karthik Manamcheri Date: Fri, 14 Mar 2014 13:15:59 -0500 Subject: [PATCH 56/83] 8250: Do not create ttyS* nodes for nonexistant devices This commit is a merge of two upstream-unfriendly commits: commit ba93f2d13b34 ("8250: Make SERIAL_8250_RUNTIME_UARTS work correctly") commit 0d1ed2d7adc1 ("Revert "serial: 8250: Do nothing if nr_uarts=0"") This was an attempt to resolve an architectural oddity in the 8250 core code, which was that, by design, it will create a static (build- or cmdline-specified) number of ttyS* devices, which is at odds with how most other Linux kernel drivers work. The original commit messages did not accurately describe the problem, so this is a merge-and-replace in order to get a better commit description. So, without further ado: The current state of affairs is as follows: There exists two build-time constants. - CONFIG_SERIAL_8250_NR_UARTS: the build-time max number of 8250 UARTs. - CONFIG_SERIAL_8250_RUNTIME_UARTS: the boot-time number of 8250 UARTs. (confusingly, this is also the default setting of 8250.nr_uarts) The way that the 8250 driver handles creation of ttyS* device is that, at initialize time, we create min(8250.nr_uarts, NR_UARTS) ttyS* devices up-front, and when a UART is registered, serial8250_find_match_or_unused will either merge it in under an existing ttyS* or find an unused one. There also exists code in the 8250 driver to automatically enumerate the UARTs specified in the SERIAL_PORT_DFNS table; these are the "well-known" ports at 0x3F8/0x2F8/0x3E8/0x2E8 from the IBM PC platform, and they are added this way because they predate the use of ACPI tables for enumeration. (Oh, and also you can point the ttyS* devices to completely different addresses from userspace via TIOCSSERIAL.) This has two ramifications for NI devices: 1) There is a limit on number of UARTs with 8250_core; this is a noteworthy problem when you are also a vendor of multiport serial cards, such as the PXIe-8430/16. However, the user experience of increasing the limit with a generic platform kernel is also bad; if, as a distro, we release a kernel with a default limit of 128, then users that have PXI systems that don't have any multiport serial cards will still be presented with devices named ttyS0 through ttyS127, even though most of them are just "empty" slots that are not backed by real devices. 2) ttyS0 through ttyS3 will always be given the addresses for the "legacy" serial ports, even if on-board controller ports are at different addresses. This is the case on several NI controllers; for example, on some sbRIO products [1] the UARTs are at 0x3F8, 0x350, 0x360, etc. However, because the legacy ports get first-dibs, those ports will be ttyS0, ttyS4, ttyS5, ... because the legacy 0x2f8/0x3E8/0x2E8 get S1-S3. Our initial attempt at resolving this was to redefine 8250.nr_uarts to mean "the number of automatically-created UART entries" and define it to be 0 (because we neither want the legacy ports nor the extra "empty" ports). On NI platforms, all serial ports are described in the ACPI table, so legacy enumeration is neither necessary nor desirable. However, this approach got soundly rejected upstream because it "caused existing kernel configurations to act differently from before" [2]. We're not alone in finding the upstream behavior to be counterintuitive; I have found at least two other attempts [3, 4] to resolve it with similar pushback of the form "this breaks existing users". A "proper" upstreamable solution probably needs two parts, with the default settings such that the current behavior is retained but can be opted-out (via Kconfig and/or kernel cmdline). - a config token for "don't create a bunch of empty devices" (1) - a config token for "don't add legacy ports, let ACPI handle it" (2) Until that arrives, we're stuck keeping this around, because we're _also_ stuck with not wanting to renumber ttyS* devices from the way we've shipped them. [1] https://github.com/ni/meta-nilrt/blob/8106f31da6980ee4ee94fa0e03b991479d9aa43e/recipes-kernel/kernel-tests/kernel-tests-files/test_kernel_serial_devices.sh#L127 [2] https://lore.kernel.org/lkml/20130603213754.GA15479@kroah.com/ [3] https://lore.kernel.org/linux-serial/1420513785-23660-1-git-send-email-peter@hurleysoftware.com/ [4] https://lore.kernel.org/linux-serial/20221025073944.102437-1-martin@geanix.com/ [SBOs from initial patches] Natinst-CAR-ID: 634278 Signed-off-by: Karthik Manamcheri Signed-off-by: Richard Tollerton Signed-off-by: Brad Mouring Natinst-ReviewBoard-ID: 183619 Upstream-Status: Denied [rejected upstream] Natinst-AzDO-ID: 2133864 Signed-off-by: Brenda Streiff [mpeterse: resolved trivial conflict with refactoring loop body to a function] Signed-off-by: Mike Petersen [cvadrevu: resolved conflict with ffd8e8bd26e94 ("serial: 8250: Extract platform driver")] Signed-off-by: Chaitanya Vadrevu --- drivers/tty/serial/8250/8250_core.c | 13 +++++-------- drivers/tty/serial/8250/8250_platform.c | 7 ++----- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c index 82f8aa0ffc068..3d130b304fc9a 100644 --- a/drivers/tty/serial/8250/8250_core.c +++ b/drivers/tty/serial/8250/8250_core.c @@ -504,7 +504,7 @@ static int univ8250_console_match(struct console *co, char *name, int idx, return -ENODEV; /* try to match the port specified on the command line */ - for (i = 0; i < nr_uarts; i++) { + for (i = 0; i < UART_NR; i++) { struct uart_port *port = &serial8250_ports[i].port; if (port->iotype != iotype) @@ -546,9 +546,6 @@ static struct console univ8250_console = { static int __init univ8250_console_init(void) { - if (nr_uarts == 0) - return -ENODEV; - serial8250_isa_init_ports(); register_console(&univ8250_console); return 0; @@ -579,7 +576,7 @@ int __init early_serial_setup(struct uart_port *port) { struct uart_port *p; - if (port->line >= ARRAY_SIZE(serial8250_ports) || nr_uarts == 0) + if (port->line >= ARRAY_SIZE(serial8250_ports)) return -ENODEV; serial8250_isa_init_ports(); @@ -675,7 +672,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_ /* * First, find a port entry which matches. */ - for (i = 0; i < nr_uarts; i++) + for (i = 0; i < UART_NR; i++) if (uart_match_port(&serial8250_ports[i].port, port)) return &serial8250_ports[i]; @@ -689,7 +686,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_ * free entry. We look for one which hasn't been previously * used (indicated by zero iobase). */ - for (i = 0; i < nr_uarts; i++) + for (i = 0; i < UART_NR; i++) if (serial8250_ports[i].port.type == PORT_UNKNOWN && serial8250_ports[i].port.iobase == 0) return &serial8250_ports[i]; @@ -698,7 +695,7 @@ static struct uart_8250_port *serial8250_find_match_or_unused(const struct uart_ * That also failed. Last resort is to find any entry which * doesn't have a real port associated with it. */ - for (i = 0; i < nr_uarts; i++) + for (i = 0; i < UART_NR; i++) if (serial8250_ports[i].port.type == PORT_UNKNOWN) return &serial8250_ports[i]; diff --git a/drivers/tty/serial/8250/8250_platform.c b/drivers/tty/serial/8250/8250_platform.c index be7ff07cbdd00..92983a45207df 100644 --- a/drivers/tty/serial/8250/8250_platform.c +++ b/drivers/tty/serial/8250/8250_platform.c @@ -69,7 +69,7 @@ static void __init __serial8250_isa_init_ports(void) * default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not * need to increase nr_uarts when setting up the initial ISA ports. */ - for (i = 0; i < nr_uarts; i++) + for (i = 0; i < UART_NR; i++) serial8250_setup_port(i); /* chain base port ops to support Remote Supervisor Adapter */ @@ -241,7 +241,7 @@ static void serial8250_remove(struct platform_device *dev) { int i; - for (i = 0; i < nr_uarts; i++) { + for (i = 0; i < UART_NR; i++) { struct uart_8250_port *up = serial8250_get_port(i); if (up->port.dev == &dev->dev) @@ -304,9 +304,6 @@ static int __init serial8250_init(void) { int ret; - if (nr_uarts == 0) - return -ENODEV; - serial8250_isa_init_ports(); pr_info("Serial: 8250/16550 driver, %d ports, IRQ sharing %s\n", From 2529e942e7ea834459c4df05fac3118df74803ed Mon Sep 17 00:00:00 2001 From: Brenda Streiff Date: Thu, 19 Jan 2023 14:42:02 -0600 Subject: [PATCH 57/83] dt-bindings: serial: ni,ni16650: add bindings Add bindings for the NI 16550 UART. Signed-off-by: Brenda Streiff Cc: Gratian Crisan Cc: Jason Smith --- .../bindings/serial/ni,ni16550.yaml | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 Documentation/devicetree/bindings/serial/ni,ni16550.yaml diff --git a/Documentation/devicetree/bindings/serial/ni,ni16550.yaml b/Documentation/devicetree/bindings/serial/ni,ni16550.yaml new file mode 100644 index 0000000000000..72ab125dd8922 --- /dev/null +++ b/Documentation/devicetree/bindings/serial/ni,ni16550.yaml @@ -0,0 +1,51 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/serial/ni,ni16550.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: NI 16550 asynchronous serial interface (UART) + +maintainers: + - Brenda Streiff + +allOf: + - $ref: serial.yaml# + +properties: + compatible: + const: ni,ni16550 + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 1 + + ni,serial-port-mode: + description: Indicates whether this is an RS-232 or RS-485 serial port. + $ref: /schemas/types.yaml#/definitions/string + enum: [ RS-232, RS-485 ] + default: RS-485 + +required: + - compatible + - reg + - interrupts + +unevaluatedProperties: false + +examples: + - | + #include + serial@80000000 { + compatible = "ni,ni16550"; + reg = <0x80000000 0x8>; + interrupts = <0 30 IRQ_TYPE_LEVEL_HIGH>; + clocks = <&clk_uart>; + ni,serial-port-mode = "RS-232"; + }; +... From ca2a9f22e8e3c8a7908576d10f039712274e8b69 Mon Sep 17 00:00:00 2001 From: Charlie Johnston Date: Tue, 5 Sep 2023 15:14:30 -0500 Subject: [PATCH 58/83] include/uapi pps.h: increase PPS_MAX_SOURCES value For consistency with what others use for minors, this change sets PPS_MAX_SOURCES to MINORMASK. The PPS_MAX_SOURCES value is currently set to 16. In some cases this was not sufficient for a system. For example, a system with multiple (4+) PCIe cards each with 4 PTP-capable ethernet interfaces could run out of the available PPS major:minors if each interface registers a PPS source. Signed-off-by: Charlie Johnston Acked-by: Rodolfo Giometti --- include/uapi/linux/pps.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/uapi/linux/pps.h b/include/uapi/linux/pps.h index 009ebcd8ced5e..90f2e86020ba9 100644 --- a/include/uapi/linux/pps.h +++ b/include/uapi/linux/pps.h @@ -26,7 +26,7 @@ #include #define PPS_VERSION "5.3.6" -#define PPS_MAX_SOURCES 16 /* should be enough... */ +#define PPS_MAX_SOURCES MINORMASK /* Implementation note: the logical states ``assert'' and ``clear'' * are implemented in terms of the chip register, i.e. ``assert'' From dca8306ea4d2d5c508830f70c77a12d676b6fde6 Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Tue, 19 May 2015 19:24:43 -0500 Subject: [PATCH 59/83] nati_x86_64_defconfig: defconfig for NI x86_64-based targets [gratian: squash all defconfig commits accumulated up to 6.0.19-rt14 and regenerate for 6.1.12-rt7] Signed-off-by: Gratian Crisan [mpeterse: squash all defconfig commits accumulated up to 6.1.54-rt15 and regenerate for 6.6-rc6-rt10] Signed-off-by: Mike Petersen [cvadrevu: squash all defconfig commits accumulated up to 6.6.77-rt50 and regenerate for 6.12.16-rt9] Signed-off-by: Chaitanya Vadrevu --- arch/x86/configs/nati_x86_64_defconfig | 624 +++++++++++++++++++++++++ 1 file changed, 624 insertions(+) create mode 100644 arch/x86/configs/nati_x86_64_defconfig diff --git a/arch/x86/configs/nati_x86_64_defconfig b/arch/x86/configs/nati_x86_64_defconfig new file mode 100644 index 0000000000000..ff7ef826c65fa --- /dev/null +++ b/arch/x86/configs/nati_x86_64_defconfig @@ -0,0 +1,624 @@ +CONFIG_SYSVIPC=y +CONFIG_POSIX_MQUEUE=y +CONFIG_AUDIT=y +# CONFIG_CONTEXT_TRACKING_USER_FORCE is not set +CONFIG_HIGH_RES_TIMERS=y +# CONFIG_CLOCKSOURCE_WATCHDOG is not set +CONFIG_BPF_SYSCALL=y +CONFIG_BPF_JIT=y +CONFIG_PREEMPT_RT=y +CONFIG_VIRT_CPU_ACCOUNTING_GEN=y +CONFIG_BSD_PROCESS_ACCT=y +CONFIG_BSD_PROCESS_ACCT_V3=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_RCU_NOCB_CPU_DEFAULT_ALL=y +# CONFIG_RCU_NOCB_CPU_CB_BOOST is not set +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=18 +CONFIG_CGROUPS=y +CONFIG_CGROUP_FAVOR_DYNMODS=y +CONFIG_MEMCG=y +CONFIG_CGROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_DEVICE=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_NAMESPACES=y +# CONFIG_TIME_NS is not set +CONFIG_USER_NS=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_EXPERT=y +# CONFIG_PCSPKR_PLATFORM is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_SMP=y +CONFIG_X86_X2APIC=y +# CONFIG_X86_EXTENDED_PLATFORM is not set +CONFIG_X86_INTEL_LPSS=y +# CONFIG_SCHED_OMIT_FRAME_POINTER is not set +CONFIG_HYPERVISOR_GUEST=y +CONFIG_PROCESSOR_SELECT=y +# CONFIG_CPU_SUP_CENTAUR is not set +# CONFIG_SCHED_MC is not set +CONFIG_X86_REROUTE_FOR_BROKEN_BOOT_IRQS=y +CONFIG_X86_MSR=m +CONFIG_X86_CPUID=m +# CONFIG_X86_5LEVEL is not set +CONFIG_NUMA=y +# CONFIG_AMD_NUMA is not set +CONFIG_MTRR_SANITIZER_ENABLE_DEFAULT=1 +CONFIG_EFI=y +CONFIG_HZ_100=y +# CONFIG_MODIFY_LDT_SYSCALL is not set +# CONFIG_SUSPEND is not set +# CONFIG_ACPI_AC is not set +# CONFIG_ACPI_BATTERY is not set +CONFIG_ACPI_BUTTON=m +# CONFIG_ACPI_FAN is not set +# CONFIG_ACPI_THERMAL is not set +CONFIG_ACPI_APEI=y +CONFIG_ACPI_APEI_GHES=y +CONFIG_ACPI_APEI_MEMORY_FAILURE=y +CONFIG_INTEL_IDLE=y +CONFIG_IA32_EMULATION=y +# CONFIG_VIRTUALIZATION is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_BLK_DEV_INTEGRITY=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_SLUB_CPU_PARTIAL is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTREMOVE=y +CONFIG_KSM=y +CONFIG_DEFAULT_MMAP_MIN_ADDR=65536 +CONFIG_MEMORY_FAILURE=y +CONFIG_ZONE_DEVICE=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_TLS=m +CONFIG_TLS_DEVICE=y +CONFIG_XFRM_USER=m +CONFIG_NET_KEY=m +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_ESP_OFFLOAD=m +CONFIG_INET_IPCOMP=m +CONFIG_INET_DIAG=m +CONFIG_IPV6=m +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_ESP_OFFLOAD=m +CONFIG_INET6_IPCOMP=m +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=m +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_ZONES=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMEOUT=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_LABELS=y +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NF_CT_NETLINK_TIMEOUT=m +CONFIG_NF_TABLES=m +CONFIG_NF_TABLES_INET=y +CONFIG_NF_TABLES_NETDEV=y +CONFIG_NFT_NUMGEN=m +CONFIG_NFT_CT=m +CONFIG_NFT_CONNLIMIT=m +CONFIG_NFT_LOG=m +CONFIG_NFT_LIMIT=m +CONFIG_NFT_MASQ=m +CONFIG_NFT_REDIR=m +CONFIG_NFT_NAT=m +CONFIG_NFT_TUNNEL=m +CONFIG_NFT_QUEUE=m +CONFIG_NFT_QUOTA=m +CONFIG_NFT_REJECT=m +CONFIG_NFT_COMPAT=m +CONFIG_NFT_HASH=m +CONFIG_NFT_FIB_INET=m +CONFIG_NFT_XFRM=m +CONFIG_NFT_SOCKET=m +CONFIG_NFT_OSF=m +CONFIG_NFT_TPROXY=m +CONFIG_NFT_SYNPROXY=m +CONFIG_NFT_DUP_NETDEV=m +CONFIG_NFT_FWD_NETDEV=m +CONFIG_NFT_FIB_NETDEV=m +CONFIG_NFT_REJECT_NETDEV=m +CONFIG_NF_FLOW_TABLE_INET=m +CONFIG_NF_FLOW_TABLE=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_DSCP=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_LOG=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_IPVS=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_VS=m +CONFIG_NFT_DUP_IPV4=m +CONFIG_NFT_FIB_IPV4=m +CONFIG_NF_TABLES_ARP=y +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_NAT=m +CONFIG_IP_NF_TARGET_MASQUERADE=m +CONFIG_IP_NF_TARGET_NETMAP=m +CONFIG_IP_NF_TARGET_REDIRECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_SECURITY=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_NFT_DUP_IPV6=m +CONFIG_NFT_FIB_IPV6=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_IP6_NF_SECURITY=m +CONFIG_IP_SCTP=m +CONFIG_SCTP_DBG_OBJCNT=y +CONFIG_SCTP_COOKIE_HMAC_SHA1=y +CONFIG_L2TP=m +CONFIG_L2TP_DEBUGFS=m +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_MULTIQ=m +CONFIG_NET_SCH_NETEM=m +CONFIG_NET_CLS_BASIC=m +CONFIG_NET_CLS_U32=m +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=m +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_SKBEDIT=m +CONFIG_DCB=y +CONFIG_DNS_RESOLVER=y +CONFIG_BT=m +CONFIG_BT_HCIBTUSB=m +CONFIG_CFG80211=m +CONFIG_NL80211_TESTMODE=y +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=m +CONFIG_MAC80211_LEDS=y +CONFIG_RFKILL=y +CONFIG_PCI=y +CONFIG_PCI_MSI=y +CONFIG_PCI_IOV=y +CONFIG_PCI_P2PDMA=y +CONFIG_HOTPLUG_PCI_ACPI=y +CONFIG_UEVENT_HELPER=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CONNECTOR=y +CONFIG_EDD=y +CONFIG_EDD_OFF=y +CONFIG_DMI_SYSFS=m +# CONFIG_EFI_DISABLE_RUNTIME is not set +CONFIG_MTD=m +CONFIG_MTD_SPI_NOR=m +CONFIG_MTD_UBI=m +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_VIRTIO_BLK=m +CONFIG_BLK_DEV_NVME=y +CONFIG_NVME_RDMA=m +CONFIG_NI_RT_FEATURES=y +CONFIG_NI_LED_PREFIX="nilrt" +CONFIG_NI_WATCHDOG=y +CONFIG_BLK_DEV_SD=y +CONFIG_BLK_DEV_SR=y +CONFIG_SCSI_SAS_ATA=y +CONFIG_SCSI_AACRAID=m +CONFIG_SCSI_MVSAS=m +CONFIG_SCSI_ARCMSR=m +CONFIG_SCSI_SYM53C8XX_2=m +CONFIG_SCSI_VIRTIO=m +CONFIG_ATA=y +CONFIG_SATA_AHCI=y +CONFIG_ATA_PIIX=y +CONFIG_SATA_MV=m +CONFIG_SATA_SIL=m +CONFIG_MD=y +CONFIG_BLK_DEV_DM=m +CONFIG_DM_CRYPT=m +CONFIG_DM_RAID=m +CONFIG_FIREWIRE=m +CONFIG_FIREWIRE_OHCI=m +CONFIG_FIREWIRE_SBP2=m +CONFIG_FIREWIRE_NET=m +CONFIG_NETDEVICES=y +CONFIG_BONDING=m +CONFIG_WIREGUARD=m +CONFIG_NETCONSOLE=m +CONFIG_NETCONSOLE_DYNAMIC=y +CONFIG_TUN=y +CONFIG_VETH=m +CONFIG_VIRTIO_NET=m +CONFIG_NLMON=m +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_NET_VENDOR_ADAPTEC is not set +# CONFIG_NET_VENDOR_ALTEON is not set +# CONFIG_NET_VENDOR_AMD is not set +# CONFIG_NET_VENDOR_ATHEROS is not set +CONFIG_TIGON3=m +# CONFIG_NET_VENDOR_CHELSIO is not set +# CONFIG_NET_VENDOR_CISCO is not set +CONFIG_NET_TULIP=y +CONFIG_TULIP=m +# CONFIG_NET_VENDOR_DLINK is not set +# CONFIG_NET_VENDOR_EMULEX is not set +# CONFIG_NET_VENDOR_I825XX is not set +CONFIG_E100=m +CONFIG_E1000=m +CONFIG_E1000E=m +CONFIG_IGB=m +CONFIG_IGBVF=m +CONFIG_IXGBE=m +# CONFIG_IXGBE_HWMON is not set +CONFIG_I40E=m +CONFIG_IGC=m +# CONFIG_NET_VENDOR_MARVELL is not set +CONFIG_MLX5_CORE=m +CONFIG_MLX5_CORE_EN=y +CONFIG_MLX5_EN_IPSEC=y +CONFIG_MLX5_EN_TLS=y +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_MYRI is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_NVIDIA is not set +# CONFIG_NET_VENDOR_OKI is not set +# CONFIG_NET_VENDOR_QLOGIC is not set +# CONFIG_NET_VENDOR_BROCADE is not set +# CONFIG_NET_VENDOR_RDC is not set +# CONFIG_NET_VENDOR_REALTEK is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SILAN is not set +# CONFIG_NET_VENDOR_SIS is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_SUN is not set +# CONFIG_NET_VENDOR_TEHUTI is not set +# CONFIG_NET_VENDOR_TI is not set +# CONFIG_NET_VENDOR_VIA is not set +# CONFIG_NET_VENDOR_WIZNET is not set +CONFIG_PHYLIB=y +CONFIG_MICROCHIP_PHY=m +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_USB_CATC=m +CONFIG_USB_KAWETH=m +CONFIG_USB_PEGASUS=m +CONFIG_USB_RTL8150=m +CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_IPHETH=m +CONFIG_USB_SIERRA_NET=m +CONFIG_USB_VL600=m +CONFIG_USB_NET_CH9200=m +CONFIG_CARL9170=m +CONFIG_ATH6KL=m +CONFIG_ATH6KL_SDIO=m +CONFIG_ATH6KL_USB=m +CONFIG_ATH6KL_NI_BIOS_DOMAIN=y +CONFIG_ATH6KL_SILEX_FIRMWARE=y +CONFIG_AR5523=m +CONFIG_AT76C50X_USB=m +CONFIG_MT7601U=m +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +CONFIG_RT2800USB=m +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RTL8187=m +CONFIG_RTL8192CU=m +CONFIG_ZD1211RW=m +CONFIG_HYPERV_NET=y +CONFIG_INPUT_MOUSEDEV=m +CONFIG_INPUT_MOUSEDEV_PSAUX=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_ATKBD=m +CONFIG_MOUSE_PS2=m +CONFIG_INPUT_TABLET=y +CONFIG_TABLET_SERIAL_WACOM4=m +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_USB_COMPOSITE=m +CONFIG_SERIO=m +# CONFIG_LEGACY_PTYS is not set +# CONFIG_LEGACY_TIOCSTI is not set +CONFIG_SERIAL_8250=y +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=32 +CONFIG_SERIAL_8250_RUNTIME_UARTS=0 +CONFIG_SERIAL_8250_EXTENDED=y +CONFIG_SERIAL_8250_SHARE_IRQ=y +CONFIG_SERIAL_8250_DETECT_IRQ=y +CONFIG_SERIAL_8250_RSA=y +CONFIG_SERIAL_8250_DW=y +# CONFIG_SERIAL_8250_PERICOM is not set +CONFIG_SERIAL_8250_NI=y +CONFIG_VIRTIO_CONSOLE=m +# CONFIG_HW_RANDOM_AMD is not set +# CONFIG_HW_RANDOM_VIA is not set +CONFIG_HW_RANDOM_VIRTIO=m +CONFIG_HPET=y +CONFIG_TCG_TPM=m +CONFIG_TCG_TIS=m +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=m +CONFIG_I2C_I801=m +CONFIG_SPI=y +CONFIG_SPI_PXA2XX=m +CONFIG_SPI_SPIDEV=m +CONFIG_PINCTRL_BAYTRAIL=y +CONFIG_PINCTRL_BROXTON=y +CONFIG_SENSORS_CORETEMP=m +CONFIG_SENSORS_TMP421=m +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_CORE=y +CONFIG_SOFT_WATCHDOG=m +CONFIG_NIC7018_WDT=m +CONFIG_LPC_ICH=m +CONFIG_MEDIA_SUPPORT=m +CONFIG_MEDIA_SUBDRV_AUTOSELECT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m +CONFIG_AGP=m +CONFIG_DRM=m +CONFIG_DRM_RADEON=m +CONFIG_DRM_I915=m +CONFIG_DRM_VMWGFX=m +CONFIG_DRM_VIRTIO_GPU=m +CONFIG_DRM_BOCHS=m +CONFIG_FB=y +CONFIG_FB_EFI=y +CONFIG_FB_MODE_HELPERS=y +CONFIG_LCD_CLASS_DEVICE=m +CONFIG_HIDRAW=y +CONFIG_HID_LOGITECH=m +CONFIG_HID_LOGITECH_DJ=m +CONFIG_LOGITECH_FF=y +CONFIG_LOGIRUMBLEPAD2_FF=y +CONFIG_LOGIG940_FF=y +CONFIG_HID_MICROSOFT=m +CONFIG_HID_MULTITOUCH=m +CONFIG_HID_PENMOUNT=m +CONFIG_USB_HIDDEV=y +CONFIG_USB=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_XHCI_PLATFORM=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_ROOT_HUB_TT=y +CONFIG_USB_UHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=m +CONFIG_USB_DWC3_GADGET=y +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_CH341=m +CONFIG_USB_SERIAL_WHITEHEAT=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_MOS7720=m +CONFIG_USB_SERIAL_MOS7840=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_USB_SERIAL_QUALCOMM=m +CONFIG_USB_SERIAL_SIERRAWIRELESS=m +CONFIG_NOP_USB_XCEIV=m +CONFIG_USB_GADGET=m +CONFIG_USB_ETH=m +# CONFIG_USB_ETH_RNDIS is not set +CONFIG_USB_ETH_EEM=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PCI=y +CONFIG_MMC_SDHCI_ACPI=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_NIC78BX=m +CONFIG_INFINIBAND=m +CONFIG_INFINIBAND_USER_ACCESS=m +CONFIG_MLX5_INFINIBAND=m +CONFIG_RTC_CLASS=y +CONFIG_DMADEVICES=y +CONFIG_UIO=m +CONFIG_UIO_PCI_GENERIC=m +CONFIG_VIRTIO_PCI=m +CONFIG_VIRTIO_BALLOON=m +CONFIG_VIRTIO_INPUT=m +CONFIG_VIRTIO_MMIO=m +CONFIG_HYPERV=y +CONFIG_HYPERV_UTILS=y +CONFIG_HYPERV_BALLOON=y +CONFIG_INTEL_IOMMU=y +# CONFIG_INTEL_IOMMU_DEFAULT_ON is not set +CONFIG_IRQ_REMAP=y +CONFIG_NTB=y +CONFIG_NTB_SWITCHTEC=y +CONFIG_USB4=m +CONFIG_DAX=m +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_POSIX_ACL=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +CONFIG_EXT3_FS_POSIX_ACL=y +CONFIG_EXT3_FS_SECURITY=y +# CONFIG_DNOTIFY is not set +CONFIG_FUSE_FS=m +CONFIG_CUSE=m +CONFIG_OVERLAY_FS=y +CONFIG_ISO9660_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_NTFS3_LZX_XPRESS=y +CONFIG_NTFS3_FS_POSIX_ACL=y +CONFIG_NTFS_FS=m +CONFIG_PROC_KCORE=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_HUGETLBFS=y +CONFIG_CONFIGFS_FS=y +CONFIG_EFIVAR_FS=y +CONFIG_UBIFS_FS=m +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_NFS_FS=m +CONFIG_NFS_V4=m +CONFIG_NFS_V4_1=y +CONFIG_CIFS=m +CONFIG_CIFS_XATTR=y +CONFIG_CIFS_POSIX=y +CONFIG_CIFS_DFS_UPCALL=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_NLS_UTF8=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_CRYPTO_PCRYPT=m +CONFIG_CRYPTO_CRYPTD=y +CONFIG_CRYPTO_AES=y +CONFIG_CRYPTO_ARC4=m +CONFIG_CRYPTO_CBC=y +CONFIG_CRYPTO_LRW=y +CONFIG_CRYPTO_XTS=y +CONFIG_CRYPTO_HMAC=y +CONFIG_CRYPTO_MD5=y +CONFIG_CRYPTO_SHA1=y +CONFIG_CRYPTO_SHA256=y +CONFIG_CRYPTO_USER_API_SKCIPHER=m +CONFIG_CRYPTO_AES_NI_INTEL=m +CONFIG_CRYPTO_CRC32C_INTEL=y +CONFIG_CRC7=m +CONFIG_LIBCRC32C=y +CONFIG_CRC8=m +CONFIG_PRINTK_TIME=y +CONFIG_FRAME_WARN=1024 +CONFIG_MAGIC_SYSRQ=y +CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x0 +CONFIG_DEBUG_FS=y +# CONFIG_SLUB_DEBUG is not set +CONFIG_PANIC_ON_OOPS=y +CONFIG_PANIC_TIMEOUT=30 +# CONFIG_SCHED_DEBUG is not set +CONFIG_RCU_CPU_STALL_TIMEOUT=60 +# CONFIG_RCU_TRACE is not set +CONFIG_FUNCTION_TRACER=y +CONFIG_FUNCTION_GRAPH_RETVAL=y +CONFIG_FUNCTION_PROFILER=y +CONFIG_FTRACE_SYSCALLS=y +CONFIG_TRACER_SNAPSHOT=y +CONFIG_TRACER_SNAPSHOT_PER_CPU_SWAP=y +# CONFIG_STRICT_DEVMEM is not set +# CONFIG_X86_VERBOSE_BOOTUP is not set +# CONFIG_EARLY_PRINTK is not set +CONFIG_IO_DELAY_0XED=y +CONFIG_UNWINDER_GUESS=y From 426f4a958948621e2ad29e5028cbe58ecbc6d173 Mon Sep 17 00:00:00 2001 From: Wan Ahmad Zainie Date: Tue, 14 Mar 2017 15:45:21 -0500 Subject: [PATCH 60/83] usb: dwc3: call _DSM for core soft reset The issue is, if core soft reset is issued while Intel Apollo Lake USB mux is in Host role mode, it takes close to 7 minutes before we are able to switch USB mux from Host mode to Device mode. This is due to RTL bug. The workaround is to let BIOS issue the core soft reset via _DSM method. It will ensure that USB mux is in Device role mode before issuing core soft reset, and will inform the driver whether the reset is success within the timeout value, or the timeout is exceeded. commit cd78b8067c6e ("usb: dwc3: call _DSM for core soft reset") originated from http://git.yoctoproject.org/cgit/cgit.cgi/linux-yocto-4.1/ Signed-off-by: Wan Ahmad Zainie [akash.mankar@ni.com: changed the way has_dsm_for_softreset property is set in dwc3-pci.c and read in core.c] Signed-off-by: Akash Mankar Signed-off-by: Brad Mouring Acked-by: Gratian Crisan Acked-by: Brandon Streiff Natinst-ReviewBoard-ID: 178124 [gratian: fixed merge conflicts, mainly due to dwc3_soft_reset removal] Signed-off-by: Gratian Crisan [bstreiff: fixed merge conflicts due to property refactor by 1a7b12f69a94 ("usb: dwc3: pci: Supply device properties via driver data")] [gratian: fix merge conflict with f580170f135a ("usb: dwc3: Add splitdisable quirk for Hisilicon Kirin Soc")] Signed-off-by: Gratian Crisan [gratian: fix conflict with 582ab24e096f ("usb: dwc3: pci: Set "linux,phy_charger_detect" property on some Bay Trail boards")] Signed-off-by: Gratian Crisan [cvadrevu: fix trivial conflict with 047161686b813 ("usb: dwc3: Add remote wakeup handling")] [cvadrevu: fix trivial conflict with 4e8ef34e36f28 ("usb: dwc3: fix gadget mode suspend interrupt handler issue")] [cvadrevu: fix conflict with 8bea147dfdf82 ("usb: dwc3: Soft reset phy on probe for host")] [cvadrevu: fix conflict with 917dc99b65911 ("usb: dwc3: pci: Change PCI device macros")] Signed-off-by: Chaitanya Vadrevu [cvadrevu: fix conflict with 4fad737008679 ("usb: dwc3: core: Fix system suspend on TI AM62 platforms")] [cvadrevu: fix conflict with e8d48c2282a91 ("Revert "usb: dwc3: Soft reset phy on probe for host"")] Signed-off-by: Chaitanya Vadrevu --- drivers/usb/dwc3/core.c | 40 +++++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/core.h | 3 +++ drivers/usb/dwc3/dwc3-pci.c | 17 +++++++++++++--- 3 files changed, 57 insertions(+), 3 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 244e3e04e1ad7..5658517715238 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -297,6 +297,38 @@ u32 dwc3_core_fifo_space(struct dwc3_ep *dep, u8 type) return DWC3_GDBGFIFOSPACE_SPACE_AVAILABLE(reg); } +/** + * WORKAROUND: We let BIOS issues the core soft reset to Device + * controller for Intel Apollo Lake, via _DSM method. + * + * The issue is, if core soft reset is issued while Intel Apollo Lake + * USB mux is in Host role mode, it takes close to 7 minutes before + * we are able to switch USB mux from Host mode to Device mode. + */ +static int dwc3_pci_dsm_soft_reset(struct device *dev) +{ + int ret = -ETIMEDOUT; + union acpi_object *obj; + guid_t guid; + + WARN_ON(guid_parse("732b85d5-b7a7-4a1b-9ba0-4bbd00ffd511", &guid)); + + obj = acpi_evaluate_dsm(ACPI_HANDLE(dev), + &guid, + 1, 6, NULL); + if (!obj) { + dev_err(dev, "failed to evaluate _DSM\n"); + return -EIO; + } + + if (obj->type == ACPI_TYPE_INTEGER) + ret = (obj->integer.value == 0) ? 0 : -ETIMEDOUT; + dev_dbg(dev, "dwc3_pci_dsm_soft_reset() ret= %d\n", ret); + + ACPI_FREE(obj); + return ret; +} + /** * dwc3_core_soft_reset - Issues core soft reset and PHY reset * @dwc: pointer to our context structure @@ -314,6 +346,11 @@ int dwc3_core_soft_reset(struct dwc3 *dwc) if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) return 0; + if (dwc->has_dsm_for_softreset) { + dev_dbg(dwc->dev, "calling dwc3_pci_dsm_soft_reset()"); + return dwc3_pci_dsm_soft_reset(dwc->dev); + } + reg = dwc3_readl(dwc->regs, DWC3_DCTL); reg |= DWC3_DCTL_CSFTRST; reg &= ~DWC3_DCTL_RUN_STOP; @@ -1794,6 +1831,9 @@ static void dwc3_get_properties(struct dwc3 *dwc) dwc->dis_split_quirk = device_property_read_bool(dev, "snps,dis-split-quirk"); + dwc->has_dsm_for_softreset = device_property_read_bool(dev, + "snps,has_dsm_for_softreset"); + dwc->lpm_nyet_threshold = lpm_nyet_threshold; dwc->tx_de_emphasis = tx_de_emphasis; diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 0e91a227507ff..01e55828de2d7 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1157,6 +1157,7 @@ struct dwc3_scratchpad_array { * @suspended: set to track suspend event due to U3/L2. * @susphy_state: state of DWC3_GUSB2PHYCFG_SUSPHY + DWC3_GUSB3PIPECTL_SUSPHY * before PM suspend. + * @has_dsm_for_softreset: set if we want to use BIOS to do core soft reset * @imod_interval: set the interrupt moderation interval in 250ns * increments or 0 to disable. * @max_cfg_eps: current max number of IN eps used across all USB configs. @@ -1391,6 +1392,8 @@ struct dwc3 { unsigned suspended:1; unsigned susphy_state:1; + unsigned has_dsm_for_softreset:1; + u16 imod_interval; int max_cfg_eps; diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c index 052852f801467..62df09e54be5c 100644 --- a/drivers/usb/dwc3/dwc3-pci.c +++ b/drivers/usb/dwc3/dwc3-pci.c @@ -141,6 +141,13 @@ static const struct property_entry dwc3_pci_intel_phy_charger_detect_properties[ {} }; +static const struct property_entry dwc3_pci_intel_bxt_properties[] = { + PROPERTY_ENTRY_STRING("dr_mode", "peripheral"), + PROPERTY_ENTRY_BOOL("snps,has_dsm_for_softreset"), + PROPERTY_ENTRY_BOOL("linux,sysdev_is_parent"), + {} +}; + static const struct property_entry dwc3_pci_intel_byt_properties[] = { PROPERTY_ENTRY_STRING("dr_mode", "peripheral"), PROPERTY_ENTRY_BOOL("snps,dis_u2_susphy_quirk"), @@ -194,6 +201,10 @@ static const struct software_node dwc3_pci_intel_phy_charger_detect_swnode = { .properties = dwc3_pci_intel_phy_charger_detect_properties, }; +static const struct software_node dwc3_pci_intel_bxt_swnode = { + .properties = dwc3_pci_intel_bxt_properties, +}; + static const struct software_node dwc3_pci_intel_byt_swnode = { .properties = dwc3_pci_intel_byt_properties, }; @@ -408,9 +419,9 @@ static const struct pci_device_id dwc3_pci_id_table[] = { { PCI_DEVICE_DATA(INTEL, CMLH, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, SPTLP, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, SPTH, &dwc3_pci_intel_swnode) }, - { PCI_DEVICE_DATA(INTEL, BXT, &dwc3_pci_intel_swnode) }, - { PCI_DEVICE_DATA(INTEL, BXT_M, &dwc3_pci_intel_swnode) }, - { PCI_DEVICE_DATA(INTEL, APL, &dwc3_pci_intel_swnode) }, + { PCI_DEVICE_DATA(INTEL, BXT, &dwc3_pci_intel_bxt_swnode) }, + { PCI_DEVICE_DATA(INTEL, BXT_M, &dwc3_pci_intel_bxt_swnode) }, + { PCI_DEVICE_DATA(INTEL, APL, &dwc3_pci_intel_bxt_swnode) }, { PCI_DEVICE_DATA(INTEL, KBP, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, GLK, &dwc3_pci_intel_swnode) }, { PCI_DEVICE_DATA(INTEL, CNPLP, &dwc3_pci_intel_swnode) }, From d7a368ebf8f963ebe3ebd35521335b78bf0f34d7 Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Mon, 18 Mar 2024 16:41:28 -0500 Subject: [PATCH 61/83] efivarfs: skip efivar_query_variable_info on PREEMPT_RT Commit d86ff3333cb1 ("efivarfs: expose used and total size") introduced the ability to query the efivars file system size with utilities like 'df'. Unfortunately this introduces large latency spikes in real-time tasks on PREEMPT_RT configured kernels. Skip the EFI run-time services query for EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO if on PREEMPT_RT. The 'df' functionality is lost but the rest of the efivars run-time services continue to work. Upstream status: Inappropriate (configuration) - upstream sets EFI_DISABLE_RUNTIME to 'default y if PREEMPT_RT' thus avoiding the problem entirely. - NILRT sets EFI_DISABLE_RUNTIME to 'n' and uses EFI run-time services to access EFI vars at run-time.[1][2] [1] https://review-board.natinst.com/r/271066 [2] https://review-board.natinst.com/r/303906 Signed-off-by: Gratian Crisan --- fs/efivarfs/super.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index beba15673be8d..e77798163ba6d 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -70,7 +70,8 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf) /* Some UEFI firmware does not implement QueryVariableInfo() */ storage_space = remaining_space = 0; - if (efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO)) { + if (efi_rt_services_supported(EFI_RT_SUPPORTED_QUERY_VARIABLE_INFO) && + !IS_ENABLED(CONFIG_PREEMPT_RT)) { status = efivar_query_variable_info(attr, &storage_space, &remaining_space, &max_variable_size); From c7627a21177329c86cdd37c7f938fe13b71bfd10 Mon Sep 17 00:00:00 2001 From: Erick Shepherd Date: Wed, 21 Aug 2024 14:33:53 -0500 Subject: [PATCH 62/83] Revert "mmc: sdhci: Add support for "Tuning Error" interrupts" This reverts commit d9ae0aa8ff8fd26c7b7fa3cad04ec54bb3b4b920. It provides similar functionality to our out-of-tree commit 13dc7b7 ("mmc: sdhci: Handle tuning error interrupts"). However it doesn't cover the cases where the "Tuning Error" interrupt is received during sdhci operations that don't have a data transfer associated with them. On our systems this results in a kernel splat: mmc0: Got data interrupt 0x04000000 even though no data operation was in progress. mmc0: sdhci: ============ SDHCI REGISTER DUMP =========== mmc0: sdhci: Sys addr: 0x12a65200 | Version: 0x0000b502 mmc0: sdhci: Blk size: 0x00007040 | Blk cnt: 0x00000001 mmc0: sdhci: Argument: 0x00010000 | Trn mode: 0x00000010 mmc0: sdhci: Present: 0x01ff0000 | Host ctl: 0x00000016 mmc0: sdhci: Power: 0x0000000f | Blk gap: 0x00000000 mmc0: sdhci: Wake-up: 0x00000000 | Clock: 0x00000107 mmc0: sdhci: Timeout: 0x0000000a | Int stat: 0x00000000 mmc0: sdhci: Int enab: 0x03ff008b | Sig enab: 0x03ff008b mmc0: sdhci: ACmd stat: 0x00000000 | Slot int: 0x00000000 mmc0: sdhci: Caps: 0x076864b2 | Caps_1: 0x00000004 mmc0: sdhci: Cmd: 0x00000d1a | Max curr: 0x00000000 mmc0: sdhci: Resp[0]: 0x00400900 | Resp[1]: 0x00000000 mmc0: sdhci: Resp[2]: 0x00000000 | Resp[3]: 0x00000000 mmc0: sdhci: Host ctl2: 0x0000000c mmc0: sdhci: ADMA Err: 0x00000003 | ADMA Ptr: 0x12a65200 mmc0: sdhci: ============================================ I/O error, dev mmcblk0, sector 0 op 0x0:(READ) flags 0x0 phys_seg 1 prio class 2 Buffer I/O error on dev mmcblk0, logical block 0, async page read Revert the upstream commit in favor of our out-of-tree commit until a proper upstream fix is found. See link to ongoing upstream conversation. Natinst-AzDo-ID: 2805437 Link: https://lore.kernel.org/linux-mmc/87jzgur32p.fsf@ni.com [erick: fix conflict when reverting d9ae0aa ("mmc: sdhci.h: Add support for "Tuning Error" interrupts") in favor of our 2c7cba1 ("mmc: sdhci: Handle tuning error interrupts")] Signed-off-by: Erick Shepherd --- drivers/mmc/host/sdhci.c | 10 ++-------- drivers/mmc/host/sdhci.h | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c index 811bba7007e96..ed5ff7090424e 100644 --- a/drivers/mmc/host/sdhci.c +++ b/drivers/mmc/host/sdhci.c @@ -3432,18 +3432,12 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask) host->data->error = -EILSEQ; if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) sdhci_err_stats_inc(host, DAT_CRC); - } else if ((intmask & (SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) && + } else if ((intmask & SDHCI_INT_DATA_CRC) && SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)) != MMC_BUS_TEST_R) { host->data->error = -EILSEQ; if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) sdhci_err_stats_inc(host, DAT_CRC); - if (intmask & SDHCI_INT_TUNING_ERROR) { - u16 ctrl2 = sdhci_readw(host, SDHCI_HOST_CONTROL2); - - ctrl2 &= ~SDHCI_CTRL_TUNED_CLK; - sdhci_writew(host, ctrl2, SDHCI_HOST_CONTROL2); - } } else if (intmask & SDHCI_INT_ADMA_ERROR) { pr_err("%s: ADMA error: 0x%08x\n", mmc_hostname(host->mmc), intmask); @@ -3997,7 +3991,7 @@ bool sdhci_cqe_irq(struct sdhci_host *host, u32 intmask, int *cmd_error, } else *cmd_error = 0; - if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC | SDHCI_INT_TUNING_ERROR)) { + if (intmask & (SDHCI_INT_DATA_END_BIT | SDHCI_INT_DATA_CRC)) { *data_error = -EILSEQ; if (!mmc_op_tuning(SDHCI_GET_CMD(sdhci_readw(host, SDHCI_COMMAND)))) sdhci_err_stats_inc(host, DAT_CRC); diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h index f531b617f28d7..edfd981dc3945 100644 --- a/drivers/mmc/host/sdhci.h +++ b/drivers/mmc/host/sdhci.h @@ -170,7 +170,7 @@ SDHCI_INT_DATA_AVAIL | SDHCI_INT_SPACE_AVAIL | \ SDHCI_INT_DATA_TIMEOUT | SDHCI_INT_DATA_CRC | \ SDHCI_INT_DATA_END_BIT | SDHCI_INT_ADMA_ERROR | \ - SDHCI_INT_BLK_GAP | SDHCI_INT_TUNING_ERROR) + SDHCI_INT_BLK_GAP) #define SDHCI_INT_ALL_MASK ((unsigned int)-1) #define SDHCI_CQE_INT_ERR_MASK ( \ From 160f55c276b0f30d4822c9e7ccca34222c74a507 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Thu, 6 Mar 2025 17:55:45 -0600 Subject: [PATCH 63/83] nati_bluefin_defconfig: defconfig for bluefin targets [cvadrevu: squash all defconfig commits accumulated up to 6.6.77-rt50 and regenerate for 6.12.16-rt9] Signed-off-by: Chaitanya Vadrevu --- arch/arm/configs/nati_bluefin_defconfig | 207 ++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 arch/arm/configs/nati_bluefin_defconfig diff --git a/arch/arm/configs/nati_bluefin_defconfig b/arch/arm/configs/nati_bluefin_defconfig new file mode 100644 index 0000000000000..887096c71fd58 --- /dev/null +++ b/arch/arm/configs/nati_bluefin_defconfig @@ -0,0 +1,207 @@ +CONFIG_LOCALVERSION="-ni" +CONFIG_SYSVIPC=y +CONFIG_AUDIT=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CGROUPS=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PERF_EVENTS=y +CONFIG_ARCH_ZYNQ=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_ERRATA_775420=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_HIGHMEM=y +CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)" +CONFIG_VFP=y +CONFIG_NEON=y +# CONFIG_SUSPEND is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPACTION is not set +CONFIG_CMA=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +# CONFIG_IPV6_SIT is not set +CONFIG_NETFILTER=y +CONFIG_BRIDGE_NETFILTER=y +CONFIG_NETFILTER_XT_MARK=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_FILTER=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_T_FILTER=y +CONFIG_BRIDGE_EBT_MARK_T=y +CONFIG_BRIDGE=y +CONFIG_BRIDGE_VLAN_FILTERING=y +CONFIG_NET_DSA=y +CONFIG_NET_DSA_MV88E6XXX_ONLY_8021AS=y +CONFIG_VLAN_8021Q=y +CONFIG_NET_SCHED=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_NAND_PL35X=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_SRAM=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_TUN=y +CONFIG_MACB=y +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_LED_TRIGGER_PHY=y +CONFIG_MARVELL_PHY=y +CONFIG_MICREL_PHY=y +CONFIG_SMSC_PHY=y +CONFIG_VITESSE_PHY=y +CONFIG_MDIO_BITBANG=y +CONFIG_INPUT_SPARSEKMAP=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=9 +CONFIG_SERIAL_8250_NI=y +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_CADENCE=y +CONFIG_I2C_XILINX=y +CONFIG_SPI=y +CONFIG_SPI_CADENCE=y +CONFIG_SPI_SPIDEV=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_ZYNQ=y +CONFIG_POWER_RESET=y +CONFIG_POWER_RESET_GPIO_RESTART=y +CONFIG_POWER_SUPPLY=y +CONFIG_SENSORS_LM90=y +CONFIG_WATCHDOG=y +CONFIG_WATCHDOG_NOWAYOUT=y +CONFIG_CADENCE_WATCHDOG=y +CONFIG_FB=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_USB=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_STORAGE=y +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_ULPI=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_GPIO=y +CONFIG_LEDS_TRIGGERS=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_LEDS_TRIGGER_ONESHOT=y +CONFIG_LEDS_TRIGGER_HEARTBEAT=y +CONFIG_LEDS_TRIGGER_DEFAULT_ON=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_PCF8563=y +CONFIG_RTC_DRV_DS3232=y +CONFIG_DMADEVICES=y +CONFIG_PL330_DMA=y +CONFIG_COMMON_CLK_SI5351=y +CONFIG_COMMON_CLK_SI570=y +CONFIG_MEMORY=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_SQUASHFS=y +CONFIG_SQUASHFS_XATTR=y +CONFIG_SQUASHFS_LZ4=y +CONFIG_SQUASHFS_LZO=y +CONFIG_SQUASHFS_XZ=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_CIFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +# CONFIG_INTEGRITY is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_SHA1_ARM=y +CONFIG_CRYPTO_SHA256_ARM=y +CONFIG_CRYPTO_AES_ARM=y +CONFIG_CRC7=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_RCU_CPU_STALL_TIMEOUT=60 From 7c914ae2ad47c156faf6912d1836afc73616da0b Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Thu, 6 Mar 2025 18:06:50 -0600 Subject: [PATCH 64/83] nati_zynq_defconfig: defconfig for NI Zynq-based targets [cvadrevu: squash all defconfig commits accumulated up to 6.6.77-rt50 and regenerate for 6.12.16-rt9] Signed-off-by: Chaitanya Vadrevu --- arch/arm/configs/nati_zynq_defconfig | 319 +++++++++++++++++++++++++++ 1 file changed, 319 insertions(+) create mode 100644 arch/arm/configs/nati_zynq_defconfig diff --git a/arch/arm/configs/nati_zynq_defconfig b/arch/arm/configs/nati_zynq_defconfig new file mode 100644 index 0000000000000..ef2eed950e4b4 --- /dev/null +++ b/arch/arm/configs/nati_zynq_defconfig @@ -0,0 +1,319 @@ +CONFIG_LOCALVERSION="-ni" +CONFIG_SYSVIPC=y +CONFIG_AUDIT=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_BUF_SHIFT=14 +CONFIG_CGROUPS=y +CONFIG_CPUSETS=y +# CONFIG_PROC_PID_CPUSET is not set +CONFIG_CGROUP_CPUACCT=y +CONFIG_BLK_DEV_INITRD=y +CONFIG_CC_OPTIMIZE_FOR_SIZE=y +CONFIG_PERF_EVENTS=y +CONFIG_ARCH_ZYNQ=y +CONFIG_ARM_ERRATA_754322=y +CONFIG_ARM_ERRATA_764369=y +CONFIG_ARM_ERRATA_775420=y +CONFIG_SMP=y +CONFIG_SCHED_MC=y +CONFIG_SCHED_SMT=y +CONFIG_HIGHMEM=y +CONFIG_CMDLINE="console=ttyPS0,115200n8 root=/dev/ram rw initrd=0x00800000,16M earlyprintk mtdparts=physmap-flash.0:512K(nor-fsbl),512K(nor-u-boot),5M(nor-linux),9M(nor-user),1M(nor-scratch),-(nor-rootfs)" +CONFIG_VFP=y +CONFIG_NEON=y +# CONFIG_SUSPEND is not set +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +# CONFIG_COMPACTION is not set +CONFIG_CMA=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_MULTIPATH=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_IP_PNP_BOOTP=y +CONFIG_IP_PNP_RARP=y +CONFIG_NET_IPIP=m +CONFIG_NET_IPGRE_DEMUX=m +CONFIG_NET_IPGRE=m +CONFIG_NET_IPGRE_BROADCAST=y +CONFIG_IP_MROUTE=y +CONFIG_IP_MROUTE_MULTIPLE_TABLES=y +CONFIG_IP_PIMSM_V1=y +CONFIG_IP_PIMSM_V2=y +CONFIG_INET_AH=m +CONFIG_INET_ESP=m +CONFIG_INET_IPCOMP=m +CONFIG_INET6_AH=m +CONFIG_INET6_ESP=m +CONFIG_INET6_IPCOMP=m +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=m +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_TIMESTAMP=y +CONFIG_NF_CONNTRACK_AMANDA=m +CONFIG_NF_CONNTRACK_FTP=m +CONFIG_NF_CONNTRACK_H323=m +CONFIG_NF_CONNTRACK_IRC=m +CONFIG_NF_CONNTRACK_NETBIOS_NS=m +CONFIG_NF_CONNTRACK_SNMP=m +CONFIG_NF_CONNTRACK_PPTP=m +CONFIG_NF_CONNTRACK_SANE=m +CONFIG_NF_CONNTRACK_SIP=m +CONFIG_NF_CONNTRACK_TFTP=m +CONFIG_NF_CT_NETLINK=m +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m +CONFIG_NETFILTER_XT_TARGET_CONNMARK=m +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=m +CONFIG_NETFILTER_XT_TARGET_MARK=m +CONFIG_NETFILTER_XT_TARGET_NFLOG=m +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m +CONFIG_NETFILTER_XT_TARGET_TEE=m +CONFIG_NETFILTER_XT_TARGET_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_ADDRTYPE=m +CONFIG_NETFILTER_XT_MATCH_CLUSTER=m +CONFIG_NETFILTER_XT_MATCH_COMMENT=m +CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m +CONFIG_NETFILTER_XT_MATCH_CONNMARK=m +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m +CONFIG_NETFILTER_XT_MATCH_CPU=m +CONFIG_NETFILTER_XT_MATCH_DCCP=m +CONFIG_NETFILTER_XT_MATCH_DEVGROUP=m +CONFIG_NETFILTER_XT_MATCH_DSCP=m +CONFIG_NETFILTER_XT_MATCH_ESP=m +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m +CONFIG_NETFILTER_XT_MATCH_HELPER=m +CONFIG_NETFILTER_XT_MATCH_IPRANGE=m +CONFIG_NETFILTER_XT_MATCH_LENGTH=m +CONFIG_NETFILTER_XT_MATCH_LIMIT=m +CONFIG_NETFILTER_XT_MATCH_MAC=m +CONFIG_NETFILTER_XT_MATCH_MARK=m +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m +CONFIG_NETFILTER_XT_MATCH_OSF=m +CONFIG_NETFILTER_XT_MATCH_OWNER=m +CONFIG_NETFILTER_XT_MATCH_POLICY=m +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m +CONFIG_NETFILTER_XT_MATCH_QUOTA=m +CONFIG_NETFILTER_XT_MATCH_RATEEST=m +CONFIG_NETFILTER_XT_MATCH_REALM=m +CONFIG_NETFILTER_XT_MATCH_RECENT=m +CONFIG_NETFILTER_XT_MATCH_SCTP=m +CONFIG_NETFILTER_XT_MATCH_STATE=m +CONFIG_NETFILTER_XT_MATCH_STATISTIC=m +CONFIG_NETFILTER_XT_MATCH_STRING=m +CONFIG_NETFILTER_XT_MATCH_TCPMSS=m +CONFIG_NETFILTER_XT_MATCH_TIME=m +CONFIG_NETFILTER_XT_MATCH_U32=m +CONFIG_IP_NF_IPTABLES=m +CONFIG_IP_NF_MATCH_AH=m +CONFIG_IP_NF_MATCH_ECN=m +CONFIG_IP_NF_MATCH_TTL=m +CONFIG_IP_NF_FILTER=m +CONFIG_IP_NF_TARGET_REJECT=m +CONFIG_IP_NF_MANGLE=m +CONFIG_IP_NF_TARGET_ECN=m +CONFIG_IP_NF_TARGET_TTL=m +CONFIG_IP_NF_RAW=m +CONFIG_IP_NF_ARPFILTER=m +CONFIG_IP_NF_ARP_MANGLE=m +CONFIG_IP6_NF_IPTABLES=m +CONFIG_IP6_NF_MATCH_AH=m +CONFIG_IP6_NF_MATCH_EUI64=m +CONFIG_IP6_NF_MATCH_FRAG=m +CONFIG_IP6_NF_MATCH_OPTS=m +CONFIG_IP6_NF_MATCH_HL=m +CONFIG_IP6_NF_MATCH_IPV6HEADER=m +CONFIG_IP6_NF_MATCH_MH=m +CONFIG_IP6_NF_MATCH_RT=m +CONFIG_IP6_NF_TARGET_HL=m +CONFIG_IP6_NF_FILTER=m +CONFIG_IP6_NF_TARGET_REJECT=m +CONFIG_IP6_NF_MANGLE=m +CONFIG_IP6_NF_RAW=m +CONFIG_L2TP=m +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=m +CONFIG_L2TP_ETH=m +CONFIG_BRIDGE=m +CONFIG_VLAN_8021Q=m +CONFIG_NET_SCHED=y +CONFIG_CAN=y +CONFIG_BT=m +CONFIG_BT_HCIBTUSB=m +CONFIG_CFG80211=m +CONFIG_NL80211_TESTMODE=y +CONFIG_CFG80211_WEXT=y +CONFIG_MAC80211=m +CONFIG_RFKILL=y +CONFIG_DEVTMPFS=y +CONFIG_DEVTMPFS_MOUNT=y +CONFIG_CONNECTOR=y +CONFIG_MTD=y +CONFIG_MTD_CMDLINE_PARTS=y +CONFIG_MTD_BLOCK=y +CONFIG_MTD_CFI=y +CONFIG_MTD_CFI_AMDSTD=y +CONFIG_MTD_PHYSMAP=y +CONFIG_MTD_PHYSMAP_OF=y +CONFIG_MTD_RAW_NAND=y +CONFIG_MTD_NAND_PL35X=y +CONFIG_MTD_UBI=y +CONFIG_MTD_UBI_GLUEBI=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=16384 +CONFIG_SRAM=y +CONFIG_EEPROM_AT24=y +CONFIG_EEPROM_AT25=y +CONFIG_EEPROM_93CX6=m +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +# CONFIG_BLK_DEV_BSG is not set +CONFIG_NETDEVICES=y +CONFIG_TUN=y +CONFIG_MACB=y +# CONFIG_NET_VENDOR_CIRRUS is not set +# CONFIG_NET_VENDOR_FARADAY is not set +# CONFIG_NET_VENDOR_HISILICON is not set +# CONFIG_NET_VENDOR_MARVELL is not set +# CONFIG_NET_VENDOR_MICREL is not set +# CONFIG_NET_VENDOR_MICROCHIP is not set +# CONFIG_NET_VENDOR_NATSEMI is not set +# CONFIG_NET_VENDOR_QUALCOMM is not set +# CONFIG_NET_VENDOR_SAMSUNG is not set +# CONFIG_NET_VENDOR_SEEQ is not set +# CONFIG_NET_VENDOR_SMSC is not set +# CONFIG_NET_VENDOR_STMICRO is not set +# CONFIG_NET_VENDOR_WIZNET is not set +# CONFIG_NET_VENDOR_XILINX is not set +CONFIG_MARVELL_PHY=y +CONFIG_MICREL_PHY=y +CONFIG_SMSC_PHY=y +CONFIG_VITESSE_PHY=y +CONFIG_MDIO_BITBANG=y +CONFIG_PPP=m +CONFIG_PPP_BSDCOMP=m +CONFIG_PPP_DEFLATE=m +CONFIG_PPP_ASYNC=m +CONFIG_PPP_SYNC_TTY=m +CONFIG_USB_NET_DRIVERS=m +CONFIG_USB_RTL8152=m +CONFIG_USB_USBNET=m +CONFIG_USB_NET_CDC_EEM=m +CONFIG_USB_NET_SMSC75XX=m +CONFIG_USB_NET_SMSC95XX=m +CONFIG_USB_NET_PLUSB=m +CONFIG_USB_NET_RNDIS_HOST=m +CONFIG_USB_IPHETH=m +CONFIG_ATH9K=m +CONFIG_RT2X00=m +CONFIG_RT2500USB=m +CONFIG_RT73USB=m +CONFIG_RT2800USB=m +CONFIG_RT2800USB_RT53XX=y +CONFIG_RT2800USB_RT55XX=y +CONFIG_RT2800USB_UNKNOWN=y +CONFIG_RTL8192CU=m +CONFIG_WL12XX=m +CONFIG_WLCORE_SDIO=m +CONFIG_INPUT_SPARSEKMAP=y +CONFIG_INPUT_EVDEV=y +CONFIG_SERIAL_8250=y +# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set +CONFIG_SERIAL_8250_CONSOLE=y +CONFIG_SERIAL_8250_NR_UARTS=9 +CONFIG_SERIAL_OF_PLATFORM=y +CONFIG_SERIAL_XILINX_PS_UART=y +CONFIG_SERIAL_XILINX_PS_UART_CONSOLE=y +# CONFIG_HW_RANDOM is not set +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_CADENCE=y +CONFIG_I2C_XILINX=y +CONFIG_SPI=y +CONFIG_SPI_CADENCE=y +CONFIG_SPI_SPIDEV=y +CONFIG_GPIOLIB=y +CONFIG_GPIO_ZYNQ=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=m +CONFIG_FB=y +CONFIG_FRAMEBUFFER_CONSOLE=y +CONFIG_HID_MICROSOFT=m +CONFIG_USB_HID=m +CONFIG_USB=y +CONFIG_USB_DYNAMIC_MINORS=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_ACM=m +CONFIG_USB_STORAGE=m +CONFIG_USB_CHIPIDEA=y +CONFIG_USB_CHIPIDEA_UDC=y +CONFIG_USB_CHIPIDEA_HOST=y +CONFIG_USB_SERIAL=m +CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m +CONFIG_USB_SERIAL_CP210X=m +CONFIG_USB_SERIAL_FTDI_SIO=m +CONFIG_USB_SERIAL_PL2303=m +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_ULPI=y +CONFIG_USB_GADGET=y +CONFIG_USB_ETH=y +# CONFIG_USB_ETH_RNDIS is not set +CONFIG_USB_ETH_EEM=y +CONFIG_MMC=y +CONFIG_MMC_SDHCI=y +CONFIG_MMC_SDHCI_PLTFM=y +CONFIG_MMC_SDHCI_OF_ARASAN=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_PCF8563=y +CONFIG_RTC_DRV_DS3232=y +CONFIG_DMADEVICES=y +CONFIG_PL330_DMA=y +CONFIG_COMMON_CLK_SI570=y +CONFIG_MEMORY=y +CONFIG_EXT2_FS=y +CONFIG_EXT2_FS_XATTR=y +CONFIG_EXT2_FS_SECURITY=y +CONFIG_EXT3_FS=y +# CONFIG_DNOTIFY is not set +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_UBIFS_FS=y +CONFIG_SQUASHFS=m +CONFIG_SQUASHFS_XATTR=y +CONFIG_NFS_FS=y +CONFIG_ROOT_NFS=y +CONFIG_CIFS=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ASCII=y +CONFIG_NLS_ISO8859_1=y +CONFIG_SECURITY=y +CONFIG_SECURITY_NETWORK=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SELINUX_BOOTPARAM=y +# CONFIG_INTEGRITY is not set +CONFIG_DEFAULT_SECURITY_DAC=y +CONFIG_CRC7=y +CONFIG_FONTS=y +CONFIG_FONT_8x8=y +CONFIG_FONT_8x16=y +CONFIG_PRINTK_TIME=y +CONFIG_DYNAMIC_DEBUG=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_RCU_CPU_STALL_TIMEOUT=60 From 23bc331c738ff3e96a8afba8fdf82bb3d77412a2 Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Fri, 13 Jun 2014 11:03:29 -0500 Subject: [PATCH 65/83] devicetree: Create initial NI Zynq base device tree include file and overlays Create a common device tree include file for NI Zynq based products. Create initial overlays for Zynq based target variants. Signed-off-by: Gratian Crisan Signed-off-by: Josh Cartwright (cherry picked from commit c01c07f53b544def769b5f6a40fe61a8366c2097) Signed-off-by: deooi --- arch/arm/boot/dts/ni-793x.dts | 106 +++++++++++ arch/arm/boot/dts/ni-dosequis.dts | 136 ++++++++++++++ arch/arm/boot/dts/ni-myrio.dts | 93 ++++++++++ arch/arm/boot/dts/ni-roborio.dts | 191 ++++++++++++++++++++ arch/arm/boot/dts/ni-sbrio-9607.dts | 233 ++++++++++++++++++++++++ arch/arm/boot/dts/ni-sbrio-9627.dts | 247 +++++++++++++++++++++++++ arch/arm/boot/dts/ni-sbrio-9637.dts | 137 ++++++++++++++ arch/arm/boot/dts/ni-solbetter.dts | 191 ++++++++++++++++++++ arch/arm/boot/dts/ni-solenetexp.dts | 106 +++++++++++ arch/arm/boot/dts/ni-solgood.dts | 124 +++++++++++++ arch/arm/boot/dts/ni-tecate.dts | 153 ++++++++++++++++ arch/arm/boot/dts/ni-zynq.dtsi | 269 ++++++++++++++++++++++++++++ 12 files changed, 1986 insertions(+) create mode 100644 arch/arm/boot/dts/ni-793x.dts create mode 100644 arch/arm/boot/dts/ni-dosequis.dts create mode 100644 arch/arm/boot/dts/ni-myrio.dts create mode 100644 arch/arm/boot/dts/ni-roborio.dts create mode 100644 arch/arm/boot/dts/ni-sbrio-9607.dts create mode 100644 arch/arm/boot/dts/ni-sbrio-9627.dts create mode 100644 arch/arm/boot/dts/ni-sbrio-9637.dts create mode 100644 arch/arm/boot/dts/ni-solbetter.dts create mode 100644 arch/arm/boot/dts/ni-solenetexp.dts create mode 100644 arch/arm/boot/dts/ni-solgood.dts create mode 100644 arch/arm/boot/dts/ni-tecate.dts create mode 100644 arch/arm/boot/dts/ni-zynq.dtsi diff --git a/arch/arm/boot/dts/ni-793x.dts b/arch/arm/boot/dts/ni-793x.dts new file mode 100644 index 0000000000000..74e373ccad154 --- /dev/null +++ b/arch/arm/boot/dts/ni-793x.dts @@ -0,0 +1,106 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 77AC */ +/* NIDEVCODE 77B2 */ +/* NIDEVCODE 77B1 */ + +/ { + model = "NI-793x"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + + leds-ni793x@4020F000 { + compatible = "ni,led-793x"; + reg = <0x4020F000 4>; + user1 { + label = "nilrt:user1:green"; + }; + }; + + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <15 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + + /* No fpga_clk specified because we want our FPGA clock + * (fclk0) to always be 125 MHz. The bootloader sets + * fclk0 to 125 MHz and we just leave it like that. */ + + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + emio-speed-gpios = <0>, + <&gpio 54 0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* Set RX_CLK Pad Skew [4:0] to 0b00000. */ + rxc-skew-ps = <0>; + }; +}; + +&sdhci0 { + status = "okay"; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&usb1 { + status = "okay"; + dr_mode = "host"; +}; + +&clkc { + /* Enable fclk0 for eth0 and eth1, fclk1 for serial. */ + fclk-enable = <0x3>; +}; diff --git a/arch/arm/boot/dts/ni-dosequis.dts b/arch/arm/boot/dts/ni-dosequis.dts new file mode 100644 index 0000000000000..ea43df8ff569a --- /dev/null +++ b/arch/arm/boot/dts/ni-dosequis.dts @@ -0,0 +1,136 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 76D6 */ + +/ { + model = "NI Dos Equis"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <46 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + user1-1 { + label = "nilrt:user1:yellow"; + }; + status-0 { + label = "nilrt:status:red"; + }; + status-1 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + wifi-0 { + label = "nilrt:wifi:primary"; + }; + wifi-1 { + label = "nilrt:wifi:secondary"; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + eth1-0 { + label = "nilrt:eth1:green"; + linux,default-trigger = + "e000b000.etherne:01:100Mb"; + }; + eth1-1 { + label = "nilrt:eth1:yellow"; + linux,default-trigger = + "e000b000.etherne:01:Gb"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "marvell,88e1512"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1, shared with phy1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + /* Page 3, Register 16, LED[2:0] Function + Control Register */ + leds = <0x1881>; + }; + + phy1: phy@1 { + compatible = "marvell,88e1512"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO1, shared with phy0. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + /* Page 3, Register 16, LED[2:0] Function + Control Register */ + leds = <0x1881>; + }; +}; + +&gem1 { + status = "okay"; + clocks = <&clkc 31>, <&clkc 14>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + cdns,no_mdio_bus; + emio-speed-gpios = <0>, + <&gpio 54 0>; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-485"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/ni-myrio.dts b/arch/arm/boot/dts/ni-myrio.dts new file mode 100644 index 0000000000000..cd944323a6cda --- /dev/null +++ b/arch/arm/boot/dts/ni-myrio.dts @@ -0,0 +1,93 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 762F */ + +/ { + model = "NI myRIO"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + switches { + wifi-switch { + interrupt-parent = <&gpio>; + interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-1 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + wifi-0 { + label = "nilrt:wifi:primary"; + }; + wifi-1 { + label = "nilrt:wifi:secondary"; + }; + }; + }; + }; + }; +}; + +&sdhci0 { + status = "okay"; + + /* We must force the SDHCI into test mode, so that it + * always pretends to have a card present. This is to + * work-around a hardware bug where TiWi WiFi does not + * have its CD line connected correctly. */ + force-sd-cd-test-mode = <1>; + + non-removable = <1>; + + wl12xx: wl12xx@0 { + compatible = "ti,wilink6"; + interrupt-parent = <&gpio>; + interrupts = <15 0x4>; + clocks = <&refclock>; + clock-names = "refclock"; + + refclock: refclock { + compatible = "ti,wilink-clock"; + #clock-cells = <0>; + clock-frequency = <38400000>; + }; + }; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/ni-roborio.dts b/arch/arm/boot/dts/ni-roborio.dts new file mode 100644 index 0000000000000..d41d9ba1f3bbe --- /dev/null +++ b/arch/arm/boot/dts/ni-roborio.dts @@ -0,0 +1,191 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 76F2 */ + +/ { + model = "NI roboRIO"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + aliases { + spi0 = &spi0; + spi1 = &spi1; + }; + + amba@0 { + adc: adc@f8007100 { + xlnx,channels { + #address-cells = <1>; + #size-cells = <0>; + /* Channel 0 maps to VPVN */ + channel@0 { + reg = <0>; + xlnx,extend-name = "vin_v"; + }; + /* Channel 1 maps to VAUX0 */ + channel@1 { + reg = <1>; + xlnx,extend-name = "vin_c"; + }; + /* Channel 2 maps to VAUX1 */ + channel@2 { + reg = <2>; + xlnx,extend-name = "user5v_v"; + }; + /* Channel 3 maps to VAUX2 */ + channel@3 { + reg = <3>; + xlnx,extend-name = "user5v_c"; + }; + /* Channel 4 maps to VAUX3 */ + channel@4 { + reg = <4>; + xlnx,extend-name = "user3v3_v"; + }; + /* Channel 5 maps to VAUX4 */ + channel@5 { + reg = <5>; + xlnx,extend-name = "user3v3_c"; + }; + /* Channel 9 maps to VAUX8 */ + channel@9 { + reg = <9>; + xlnx,extend-name = "user6v_c"; + }; + /* Channel 10 maps to VAUX9 */ + channel@10 { + reg = <10>; + xlnx,extend-name = "bist_ao_v"; + }; + /* Channel 11 maps to VAUX10 */ + channel@11 { + reg = <11>; + xlnx,extend-name = "bist_dio_v"; + }; + /* Channel 12 maps to VAUX11 */ + channel@12 { + reg = <12>; + xlnx,extend-name = "user6v_v"; + }; + }; + }; + + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <24 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-1 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + }; + }; + }; + + i2c1: i2c@e0005000 { + status = "okay"; + }; + + i2c2: i2c@81000000 { + status = "okay"; + }; + + spi0: spi@e0006000 { + status = "okay"; + num-cs = <7>; + is-decoded-cs = <1>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; + }; + spidev@1 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <1>; + }; + spidev@2 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <2>; + }; + spidev@3 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <3>; + }; + }; + + spi1: spi@e0007000 { + status = "okay"; + num-cs = <3>; + is-decoded-cs = <0>; + speed-hz = <200000000>; + + spidev@0 { + compatible = "spidev"; + spi-max-frequency = <2000000>; + reg = <0>; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <&gpio 54 0>, + <0>; + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "smsc,lan8720"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt pin is connected from PL pin to FPGA IRQ 3 */ + interrupts = <0 32 4>; + }; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&uart0 { + status = "okay"; +}; + +&can0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/ni-sbrio-9607.dts b/arch/arm/boot/dts/ni-sbrio-9607.dts new file mode 100644 index 0000000000000..e582fca748bf3 --- /dev/null +++ b/arch/arm/boot/dts/ni-sbrio-9607.dts @@ -0,0 +1,233 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 77D6 */ + +/ { + model = "NI sbRIO-9607"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + eth1-0 { + label = "nilrt:eth1:green"; + linux,default-trigger = + "e000b000.etherne:01:100Mb"; + }; + eth1-1 { + label = "nilrt:eth1:yellow"; + linux,default-trigger = + "e000b000.etherne:01:Gb"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO25, shared with phy1. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. */ + txc-skew-ps = <1860>; + }; + + phy1: phy@1 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO25, shared with phy0. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. */ + txc-skew-ps = <1860>; + }; +}; + +&gem1 { + status = "okay"; + clocks = <&clkc 31>, <&clkc 14>, <&clkc 17>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + cdns,no_mdio_bus; + emio-speed-gpios = <0>, + <&gpio 55 0>; +}; + +&sdhci1 { + status = "okay"; + force-sd-standard; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart3 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart4 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart5 { + status = "okay"; + transceiver = "RS-485"; +}; + +&ni_uart6 { + status = "okay"; + transceiver = "RS-485"; +}; + +&can0 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/ni-sbrio-9627.dts b/arch/arm/boot/dts/ni-sbrio-9627.dts new file mode 100644 index 0000000000000..435a6169e0604 --- /dev/null +++ b/arch/arm/boot/dts/ni-sbrio-9627.dts @@ -0,0 +1,247 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 77D5 */ + +/ { + model = "NI sbRIO-9627"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + eth1-0 { + label = "nilrt:eth1:green"; + linux,default-trigger = + "e000b000.etherne:01:100Mb"; + }; + eth1-1 { + label = "nilrt:eth1:yellow"; + linux,default-trigger = + "e000b000.etherne:01:Gb"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO25, shared with phy1. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. */ + txc-skew-ps = <1860>; + }; + + phy1: phy@1 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO25, shared with phy0. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. */ + txc-skew-ps = <1860>; + }; +}; + +&gem1 { + status = "okay"; + clocks = <&clkc 31>, <&clkc 14>, <&clkc 17>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + cdns,no_mdio_bus; + emio-speed-gpios = <0>, + <&gpio 55 0>; +}; + +&sdhci0 { + status = "okay"; +}; + +&sdhci1 { + status = "okay"; + force-sd-standard; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-485"; +}; + +&ni_uart3 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart4 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart5 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart6 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart7 { + status = "okay"; + transceiver = "RS-485"; +}; + +&ni_uart8 { + status = "okay"; + transceiver = "RS-485"; +}; + +&can0 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/ni-sbrio-9637.dts b/arch/arm/boot/dts/ni-sbrio-9637.dts new file mode 100644 index 0000000000000..7626db67b8073 --- /dev/null +++ b/arch/arm/boot/dts/ni-sbrio-9637.dts @@ -0,0 +1,137 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 77D4 */ + +/ { + model = "NI sbRIO-9637"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <1 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO25. */ + interrupts = <25 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. */ + txc-skew-ps = <1860>; + }; +}; + +&sdhci0 { + status = "okay"; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-485"; +}; + +&can0 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/ni-solbetter.dts b/arch/arm/boot/dts/ni-solbetter.dts new file mode 100644 index 0000000000000..b8315f0fe7506 --- /dev/null +++ b/arch/arm/boot/dts/ni-solbetter.dts @@ -0,0 +1,191 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 7744 */ + +/ { + model = "NI Sol"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + eth1-0 { + label = "nilrt:eth1:green"; + linux,default-trigger = + "e000b000.etherne:01:100Mb"; + }; + eth1-1 { + label = "nilrt:eth1:yellow"; + linux,default-trigger = + "e000b000.etherne:01:Gb"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. */ + txc-skew-ps = <1860>; + }; + + phy1: phy@1 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO1, shared with phy0. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. */ + txc-skew-ps = <1860>; + }; +}; + +&gem1 { + status = "okay"; + clocks = <&clkc 31>, <&clkc 14>, <&clkc 17>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + cdns,no_mdio_bus; + emio-speed-gpios = <0>, + <&gpio 55 0>; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/ni-solenetexp.dts b/arch/arm/boot/dts/ni-solenetexp.dts new file mode 100644 index 0000000000000..a495ca23e8861 --- /dev/null +++ b/arch/arm/boot/dts/ni-solenetexp.dts @@ -0,0 +1,106 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 774E */ + +/ { + model = "NI Sol"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. */ + txc-skew-ps = <1860>; + }; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; diff --git a/arch/arm/boot/dts/ni-solgood.dts b/arch/arm/boot/dts/ni-solgood.dts new file mode 100644 index 0000000000000..4b25334247076 --- /dev/null +++ b/arch/arm/boot/dts/ni-solgood.dts @@ -0,0 +1,124 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 7743 */ + +/ { + model = "NI Sol"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <25 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + user1-0 { + label = "nilrt:user1:green"; + }; + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + clocks = <&clkc 30>, <&clkc 13>, <&clkc 15>; + clock-names = "pclk", "hclk", "tx_clk"; + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* RX_DV Pad Skew [7:4] = +0.30ns (0xC0) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxdv-skew-ps = <720>; + + /* TX_EN Pad Skew [3:0] = -0.30ns (0x02) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txen-skew-ps = <120>; + + /* RXD 0-3 Pad Skew = +0.30ns (0xC) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 + 300 is 720 ps. */ + rxd0-skew-ps = <720>; + rxd1-skew-ps = <720>; + rxd2-skew-ps = <720>; + rxd3-skew-ps = <720>; + + /* TXD 0-3 Pad Skew = -0.30ns (0x2) */ + /* Default is 0b0111, or 7. 7 * 60 ps = 420 ps. 0.30 ns is 300 + * ps. 420 - 300 is 120 ps. */ + txd0-skew-ps = <120>; + txd1-skew-ps = <120>; + txd2-skew-ps = <120>; + txd3-skew-ps = <120>; + + /* Write value to MMD Address 2h, Register 8h */ + /* RX_CLK Pad Skew [4:0] = -0.9ns (0x0) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.90 ns is + * 900 ps. 900 - 900 is 0 ps. */ + rxc-skew-ps = <0>; + /* GTX_CLK Pad Skew [9:5] = +0.96ns (0x3E) */ + /* Default is 0b01111, or 15. 15 * 60 ps = 900 ps. 0.96 ns is + * 960 ps. 900 + 960 is 1860 ps. */ + txc-skew-ps = <1860>; + }; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&usb1 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&clkc { + /* Enable fclk1 for serial. */ + fclk-enable = <0x2>; +}; diff --git a/arch/arm/boot/dts/ni-tecate.dts b/arch/arm/boot/dts/ni-tecate.dts new file mode 100644 index 0000000000000..15124e4b12cad --- /dev/null +++ b/arch/arm/boot/dts/ni-tecate.dts @@ -0,0 +1,153 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 775E */ + +/ { + model = "NI Tecate"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + nicpld@40 { + watchdogs { + boot-watchdog { + interrupt-parent = <&gpio>; + interrupts = <15 2 /* IRQ_TYPE_EDGE_FALLING */>; + }; + }; + + leds { + status-0 { + label = "nilrt:status:yellow"; + max-brightness = <0xFFFF>; + }; + eth0-0 { + label = "nilrt:eth0:green"; + linux,default-trigger = + "e000b000.etherne:00:100Mb"; + }; + eth0-1 { + label = "nilrt:eth0:yellow"; + linux,default-trigger = + "e000b000.etherne:00:Gb"; + }; + }; + }; + + ds3231_rtc@68 { + status = "okay"; + }; + }; + }; +}; + +&gem0 { + status = "okay"; + + /* No fpga_clk specified because we want our FPGA clock + * (fclk0) to always be 125 MHz. The bootloader sets + * fclk0 to 125 MHz and we just leave it like that. */ + + phy-handle = <&phy0>; + phy-mode = "rgmii-id"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + emio-speed-gpios = <0>, + <&gpio 54 0>; + + phy0: phy@0 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x0>; + /* Interrupt on GPIO1. */ + interrupts = <1 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + + /* Set RX_CLK Pad Skew [4:0] to 0b00000. */ + rxc-skew-ps = <0>; + }; +}; + +&gem1 { + status = "okay"; + + /* No fpga_clk specified because we want our FPGA clock (fclk0) to + * always be 125 MHz. The bootloader sets fclk0 to 125 MHz and we just + * leave it like that. */ + + phy-handle = <&phy1>; + phy-mode = "rgmii-id"; + #address-cells = <0x1>; + #size-cells = <0x0>; + + emio-speed-gpios = <&gpio 56 0>, + <&gpio 55 0>; + + phy1: phy@1 { + compatible = "micrel,KSZ9031"; + device_type = "ethernet-phy"; + reg = <0x1>; + /* Interrupt on GPIO57. */ + interrupts = <57 8 /* IRQ_TYPE_LEVEL_LOW */>; + interrupt-parent = <&gpio>; + }; +}; + +&sdhci0 { + status = "okay"; +}; + +&ni_uart0 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart1 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart2 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart3 { + status = "okay"; + transceiver = "RS-232"; +}; + +&ni_uart4 { + status = "okay"; + transceiver = "RS-485"; +}; + +&ni_uart5 { + status = "okay"; + transceiver = "RS-485"; +}; + +&can0 { + status = "okay"; +}; + +&can1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "peripheral"; +}; + +&usb1 { + status = "okay"; + dr_mode = "host"; +}; + +&clkc { + /* Enable fclk0 for eth0 and eth1, fclk1 for serial. */ + fclk-enable = <0x3>; +}; diff --git a/arch/arm/boot/dts/ni-zynq.dtsi b/arch/arm/boot/dts/ni-zynq.dtsi new file mode 100644 index 0000000000000..3cdbf768a0032 --- /dev/null +++ b/arch/arm/boot/dts/ni-zynq.dtsi @@ -0,0 +1,269 @@ +/include/ "zynq-7000.dtsi" + +/ { + model = "NI Zynq-based Target"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + /* Populated by the bootloader */ + memory@0 { + device_type = "memory"; + reg = <0 0>; + }; + chosen { }; + + cpus { + #address-cells = <1>; + #size-cells = <0>; + + cpu@0 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <0>; + clocks = <&clkc 3>; + }; + + cpu@1 { + compatible = "arm,cortex-a9"; + device_type = "cpu"; + reg = <1>; + clocks = <&clkc 3>; + }; + }; + + amba@0 { + ni_uart0: serial@80000000 { + device_type = "serial"; + compatible = "ni16550-fifo128", "ns16550a"; + status = "disabled"; + reg = <0x80000000 0x8>; + interrupts = <0 30 4>; + clock-frequency = <58824000>; + /* Populated by the bootloader */ + /* current-speed = <0>; */ + }; + + ni_uart1: serial@80000010 { + device_type = "serial"; + compatible = "ni16550-fifo128", "ns16550a"; + status = "disabled"; + reg = <0x80000010 0x8>; + interrupts = <0 31 4>; + clock-frequency = <58824000>; + }; + + ni_uart2: serial@80000020 { + device_type = "serial"; + compatible = "ni16550-fifo128", "ns16550a"; + status = "disabled"; + reg = <0x80000020 0x8>; + interrupts = <0 32 4>; + clock-frequency = <58824000>; + }; + + ni_uart3: serial@80000030 { + device_type = "serial"; + compatible = "ni16550-fifo128", "ns16550a"; + status = "disabled"; + reg = <0x80000030 0x8>; + interrupts = <0 33 0>; + clock-frequency = <58824000>; + }; + + ni_uart4: serial@80000040 { + device_type = "serial"; + compatible = "ni16550-fifo128", "ns16550a"; + status = "disabled"; + reg = <0x80000040 0x8>; + interrupts = <0 34 0>; + clock-frequency = <58824000>; + }; + + ni_uart5: serial@80000050 { + device_type = "serial"; + compatible = "ni16550-fifo128", "ns16550a"; + status = "disabled"; + reg = <0x80000050 0x8>; + interrupts = <0 35 0>; + clock-frequency = <58824000>; + }; + + ni_uart6: serial@80000060 { + device_type = "serial"; + compatible = "ni16550-fifo128", "ns16550a"; + status = "disabled"; + reg = <0x80000060 0x8>; + interrupts = <0 36 0>; + clock-frequency = <58824000>; + }; + + ni_uart7: serial@80000070 { + device_type = "serial"; + compatible = "ni16550-fifo128", "ns16550a"; + status = "disabled"; + reg = <0x80000070 0x8>; + interrupts = <0 52 0>; + clock-frequency = <58824000>; + }; + + ni_uart8: serial@80000080 { + device_type = "serial"; + compatible = "ni16550-fifo128", "ns16550a"; + status = "disabled"; + reg = <0x80000080 0x8>; + interrupts = <0 53 0>; + clock-frequency = <58824000>; + }; + + can0: can@e0008000 { + compatible = "xlnx,zynq-can-1.00.a"; + status = "disabled"; + reg = <0xe0008000 0x1000>; + interrupts = <0 28 4>; + }; + + can1: can@e0009000 { + compatible = "xlnx,zynq-can-1.00.a"; + status = "disabled"; + reg = <0xe0009000 0x1000>; + interrupts = <0 51 4>; + }; + + fpgaperipheral@f8007000 { + compatible = "fpgaperipheral"; + reg = <0xf8007000 0x100>; + }; + + smcc@e000e000 { + #address-cells = <1>; + #size-cells = <1>; + arm,addr25 = <0x0>; + arm,nor-chip-sel0 = <0x0>; + arm,nor-chip-sel1 = <0x0>; + arm,sram-chip-sel0 = <0x0>; + arm,sram-chip-sel1 = <0x0>; + clock-names = "memclk", "aclk"; + clocks = <&clkc 11>, <&clkc 44>; + compatible = "arm,pl353-smc-r2p1"; + interrupts = <0 18 4>; + ranges ; + reg = <0xe000e000 0x1000>; + nand@e1000000 { + compatible = "arm,pl353-nand-r2p1"; + reg = <0xe1000000 0x1000000>; + bank-width = <1>; /* 8-bit width */ + xlnx,nand-width = <0x8>; + + /* SLCR SMC_CLK_CTRL value, 83MHz clock, 12ns cycle time */ + /* in cycles */ + xlnx,onfi-mode0 = <0x0001021 4 3 2 7 4 10 10>; + + /* SLCR SMC_CLK_CTRL value, 166MHz clock, 6ns cycle time */ + /* in cycles */ + xlnx,onfi-mode1 = <0x0000821 4 2 2 7 4 10 10>; + xlnx,onfi-mode2 = <0x0000821 4 2 2 5 3 8 7>; + xlnx,onfi-mode3 = <0x0000821 4 2 2 5 2 7 6>; + xlnx,onfi-mode4 = <0x0000821 4 2 2 4 2 6 5>; + xlnx,onfi-mode5 = <0x0000821 4 2 2 3 2 5 4>; + + #address-cells = <1>; + #size-cells = <1>; + }; + }; + + usb0: usb@e0002000 { + compatible = "xlnx,zynq-usb-1.00.a"; + status = "disabled"; + reg = <0xe0002000 0x1000>; + interrupts = <0 21 4>; + clocks = <&clkc 28>; + phy_type = "ulpi"; + }; + + usb1: usb@e0003000 { + compatible = "xlnx,zynq-usb-1.00.a"; + status = "disabled"; + reg = <0xe0003000 0x1000>; + interrupts = <0 44 4>; + clocks = <&clkc 29>; + phy_type = "ulpi"; + }; + + gpio: gpio@e000a000 { + compatible = "xlnx,zynq-gpio-1.0"; + reg = <0xe000a000 0x1000>; + #interrupt-cells = <0x2>; + interrupt-controller; + interrupts = <0 20 4>; + clocks = <&clkc 42>; + #gpio-cells = <2>; + gpio-controller; + }; + + i2c0: i2c@e0004000 { + compatible = "cdns,i2c-r1p10"; + reg = <0xE0004000 0x1000>; + interrupts = <0 25 4>; + bus-id = <0>; + clocks = <&clkc 38>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + status = "okay"; + + nicpld@40 { + compatible = "ni,cpld"; + reg = <0x40>; + }; + + ds3231_rtc@68 { + compatible = "ds3232"; + status = "disabled"; + reg = <0x68>; + }; + }; + + i2c1: i2c@e0005000 { + compatible = "cdns,i2c-r1p10"; + status = "disabled"; + reg = <0xe0005000 0x1000>; + interrupts = <0 48 4>; + bus-id = <1>; + clocks = <&clkc 39>; + clock-frequency = <400000>; + #address-cells = <1>; + #size-cells = <0>; + } ; + + i2c2: i2c@81000000 { + compatible = "xlnx,xps-iic-2.00.a"; + status = "disabled"; + reg = <0x81000000 0x1000>; + interrupts = <0 33 4>; + bus-id = <2>; + #address-cells = <1>; + #size-cells = <0>; + }; + + spi0: spi@e0006000 { + compatible = "cdns,spi-r1p6"; + status = "disabled"; + reg = <0xe0006000 0x1000>; + interrupts = <0 26 4>; + clock-names = "ref_clk", "pclk"; + clocks = <&clkc 25>, <&clkc 34>; + #address-cells = <1>; + #size-cells = <0>; + }; + + spi1: spi@e0007000 { + compatible = "cdns,spi-r1p6"; + status = "disabled"; + reg = <0xe0007000 0x1000>; + interrupts = <0 49 4>; + clock-names = "ref_clk", "pclk"; + clocks = <&clkc 26>, <&clkc 35>; + #address-cells = <1>; + #size-cells = <0>; + }; + }; +}; From e4ec4c8fa35ba961c9aa85445b8c2096c26f3ee3 Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Wed, 19 Aug 2015 18:00:16 -0500 Subject: [PATCH 66/83] devicetree: Update NI device trees for chipidea The chipidea USB controller driver requires a phy in the tree, so add one for all NI Zynq devices. Remove USB items from the ni-zynq tree include since they are now in zynq-7000.dtsi. Signed-off-by: Nathan Sullivan Acked-by: Josh Cartwright Acked-by: Jaeden Amero Natinst-ReviewBoard-ID: 108233 (cherry picked from commit 24943ed08d5d558409a0c1856793a5d22a2a0367) Signed-off-by: deooi --- arch/arm/boot/dts/ni-zynq.dtsi | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/arch/arm/boot/dts/ni-zynq.dtsi b/arch/arm/boot/dts/ni-zynq.dtsi index 3cdbf768a0032..5b347e6814348 100644 --- a/arch/arm/boot/dts/ni-zynq.dtsi +++ b/arch/arm/boot/dts/ni-zynq.dtsi @@ -11,6 +11,16 @@ }; chosen { }; + usb_phy0: phy0 { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; + + usb_phy1: phy1 { + compatible = "usb-nop-xceiv"; + #phy-cells = <0>; + }; + cpus { #address-cells = <1>; #size-cells = <0>; @@ -170,24 +180,6 @@ }; }; - usb0: usb@e0002000 { - compatible = "xlnx,zynq-usb-1.00.a"; - status = "disabled"; - reg = <0xe0002000 0x1000>; - interrupts = <0 21 4>; - clocks = <&clkc 28>; - phy_type = "ulpi"; - }; - - usb1: usb@e0003000 { - compatible = "xlnx,zynq-usb-1.00.a"; - status = "disabled"; - reg = <0xe0003000 0x1000>; - interrupts = <0 44 4>; - clocks = <&clkc 29>; - phy_type = "ulpi"; - }; - gpio: gpio@e000a000 { compatible = "xlnx,zynq-gpio-1.0"; reg = <0xe000a000 0x1000>; @@ -265,5 +257,13 @@ #address-cells = <1>; #size-cells = <0>; }; + + usb0: usb@e0002000 { + usb-phy = <&usb_phy0>; + }; + + usb1: usb@e0003000 { + usb-phy = <&usb_phy1>; + }; }; }; From 7d6fafec27f27db168aeec5bda16933d1b1b752a Mon Sep 17 00:00:00 2001 From: Nathan Sullivan Date: Mon, 28 Sep 2015 12:53:35 -0500 Subject: [PATCH 67/83] nizynq: Enable pl310 prefetch Signed-off-by: Nathan Sullivan Acked-by: Josh Cartwright Acked-by: Jaeden Amero Natinst-ReviewBoard-ID: 108233 (cherry picked from commit fe67634bbb41fa0be2c2a1fea9046bb1c5da1546) Signed-off-by: deooi --- arch/arm/boot/dts/ni-zynq.dtsi | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/arch/arm/boot/dts/ni-zynq.dtsi b/arch/arm/boot/dts/ni-zynq.dtsi index 5b347e6814348..8f6b06dc748a9 100644 --- a/arch/arm/boot/dts/ni-zynq.dtsi +++ b/arch/arm/boot/dts/ni-zynq.dtsi @@ -266,4 +266,10 @@ usb-phy = <&usb_phy1>; }; }; + +}; + +&L2 { + prefetch-data = <1>; + prefetch-instr = <1>; }; From 80b0a6b061c2c4bceba98af7e9e0f698d3fca378 Mon Sep 17 00:00:00 2001 From: Brad Mouring Date: Mon, 22 Feb 2016 15:40:35 -0600 Subject: [PATCH 68/83] ni-zynq.dtsi: Disable PL310 power options Since NI controllers care more about determinism than power savings, disable PM options that hinder the former at the expense of the latter. Signed-off-by: Brad Mouring Acked-by: Josh Cartwright Natinst-ReviewBoard-ID: 127729 Natinst-CAR-ID: 568817 (cherry picked from commit 8400eae10d4113f4494ab9d61fc45763a7cfb79d) Signed-off-by: deooi --- arch/arm/boot/dts/ni-zynq.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm/boot/dts/ni-zynq.dtsi b/arch/arm/boot/dts/ni-zynq.dtsi index 8f6b06dc748a9..4324e67f461a3 100644 --- a/arch/arm/boot/dts/ni-zynq.dtsi +++ b/arch/arm/boot/dts/ni-zynq.dtsi @@ -272,4 +272,6 @@ &L2 { prefetch-data = <1>; prefetch-instr = <1>; + arm,dynamic-clock-gating = <0>; + arm,standby-mode = <0>; }; From 7918440063b3ab4bc6d7e7febdafd1cb8394a088 Mon Sep 17 00:00:00 2001 From: Brandon Streiff Date: Thu, 5 May 2016 17:30:09 -0500 Subject: [PATCH 69/83] ni-bluefin: add device tree Device tree for Bluefin devices as of Rev A. Signed-off-by: Brandon Streiff Acked-by: Nathan Sullivan Natinst-ReviewBoard-ID: 158229 (cherry picked from commit c0feb6bc830a506728bd3f42050d1dd71d3f383a) Signed-off-by: deooi --- arch/arm/boot/dts/ni-bluefin.dts | 93 ++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 arch/arm/boot/dts/ni-bluefin.dts diff --git a/arch/arm/boot/dts/ni-bluefin.dts b/arch/arm/boot/dts/ni-bluefin.dts new file mode 100644 index 0000000000000..fa569f8ab5521 --- /dev/null +++ b/arch/arm/boot/dts/ni-bluefin.dts @@ -0,0 +1,93 @@ +/dts-v1/; +/include/ "ni-zynq.dtsi" + +/* NIDEVCODE 78C7 */ +/* NIDEVCODE 78B9 */ + +/ { + model = "NI Bluefin"; + compatible = "ni,zynq", "xlnx,zynq-7000"; + + amba@0 { + i2c0: i2c@e0004000 { + /* Override ni-zynq.dtsi; we do not have a CPLD at 0x40. */ + nicpld@40 { + status = "disabled"; + }; + + tmp451@4C { + compatible = "ti,tmp451"; + reg = <0x4C>; + vcc-supply = <®ulator_vccpint>; + }; + }; + }; + + leds { + compatible = "gpio-leds"; + + /* LED_STATUSy on GPIO46 */ + status { + label = "nilrt:status:yellow"; + gpios = <&gpio 46 0>; + default-state = "on"; + }; + + /* LED_ACTIVEg on GPIO47 */ + active { + label = "nilrt:active:green"; + gpios = <&gpio 47 0>; + default-state = "off"; + }; + }; + + gpio_keys { + compatible = "gpio-keys"; + #address-cells = <1>; + #size-cells = <0>; + + /* Reset switch is on GPIO48 */ + reset_sw@0 { + label = "reset_sw"; + gpios = <&gpio 48 1 /* GPIO_ACTIVE_LOW */>; + linux,code = <408>; /* KEY_RESTART */ + gpio-key,wakeup; + }; + }; + + gpio_restart { + compatible = "gpio-restart"; + + /* ~PS_FORCE_RESET is on GPIO44 */ + gpios = <&gpio 44 1 /* GPIO_ACTIVE_LOW */>; + priority = <200>; + }; +}; + +&gem0 { + status = "okay"; + emio-speed-gpios = <0>, + <&gpio 54 0>; + + #address-cells = <0x1>; + #size-cells = <0x0>; + + fixed-link { + speed = <1000>; + full-duplex; + }; +}; + +&uart1 { + status = "okay"; +}; + +&usb0 { + status = "okay"; + dr_mode = "host"; +}; + +&watchdog0 { + status = "okay"; + reset-on-timeout; +}; From f318b4539bb43ff159b0d532dbeb680716df6f19 Mon Sep 17 00:00:00 2001 From: Brandon Streiff Date: Thu, 12 Jan 2017 14:10:50 -0600 Subject: [PATCH 70/83] ni-bluefin: set phy address for fixed-link This keeps us for having to scan for it. Signed-off-by: Brandon Streiff Natinst-ReviewBoard-ID: 168093 (cherry picked from commit 56f25b5cdfcfc533e8786bc788707becddda79c2) Signed-off-by: deooi --- arch/arm/boot/dts/ni-bluefin.dts | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/boot/dts/ni-bluefin.dts b/arch/arm/boot/dts/ni-bluefin.dts index fa569f8ab5521..19f9ef5ab6614 100644 --- a/arch/arm/boot/dts/ni-bluefin.dts +++ b/arch/arm/boot/dts/ni-bluefin.dts @@ -75,6 +75,7 @@ fixed-link { speed = <1000>; full-duplex; + reg = <0>; }; }; From 0fed22fb2010df22b492bcc0387071190b3bae9a Mon Sep 17 00:00:00 2001 From: deooi Date: Fri, 17 Jan 2025 15:40:47 +0800 Subject: [PATCH 71/83] devicetree: Move xilinx device trees to the xilinx directory This change is needed to keep up with the latest file directory. Signed-off-by: deooi --- arch/arm/boot/dts/{ => xilinx}/ni-793x.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-bluefin.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-dosequis.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-myrio.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-roborio.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-sbrio-9607.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-sbrio-9627.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-sbrio-9637.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-solbetter.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-solenetexp.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-solgood.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-tecate.dts | 0 arch/arm/boot/dts/{ => xilinx}/ni-zynq.dtsi | 0 13 files changed, 0 insertions(+), 0 deletions(-) rename arch/arm/boot/dts/{ => xilinx}/ni-793x.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-bluefin.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-dosequis.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-myrio.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-roborio.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-sbrio-9607.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-sbrio-9627.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-sbrio-9637.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-solbetter.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-solenetexp.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-solgood.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-tecate.dts (100%) rename arch/arm/boot/dts/{ => xilinx}/ni-zynq.dtsi (100%) diff --git a/arch/arm/boot/dts/ni-793x.dts b/arch/arm/boot/dts/xilinx/ni-793x.dts similarity index 100% rename from arch/arm/boot/dts/ni-793x.dts rename to arch/arm/boot/dts/xilinx/ni-793x.dts diff --git a/arch/arm/boot/dts/ni-bluefin.dts b/arch/arm/boot/dts/xilinx/ni-bluefin.dts similarity index 100% rename from arch/arm/boot/dts/ni-bluefin.dts rename to arch/arm/boot/dts/xilinx/ni-bluefin.dts diff --git a/arch/arm/boot/dts/ni-dosequis.dts b/arch/arm/boot/dts/xilinx/ni-dosequis.dts similarity index 100% rename from arch/arm/boot/dts/ni-dosequis.dts rename to arch/arm/boot/dts/xilinx/ni-dosequis.dts diff --git a/arch/arm/boot/dts/ni-myrio.dts b/arch/arm/boot/dts/xilinx/ni-myrio.dts similarity index 100% rename from arch/arm/boot/dts/ni-myrio.dts rename to arch/arm/boot/dts/xilinx/ni-myrio.dts diff --git a/arch/arm/boot/dts/ni-roborio.dts b/arch/arm/boot/dts/xilinx/ni-roborio.dts similarity index 100% rename from arch/arm/boot/dts/ni-roborio.dts rename to arch/arm/boot/dts/xilinx/ni-roborio.dts diff --git a/arch/arm/boot/dts/ni-sbrio-9607.dts b/arch/arm/boot/dts/xilinx/ni-sbrio-9607.dts similarity index 100% rename from arch/arm/boot/dts/ni-sbrio-9607.dts rename to arch/arm/boot/dts/xilinx/ni-sbrio-9607.dts diff --git a/arch/arm/boot/dts/ni-sbrio-9627.dts b/arch/arm/boot/dts/xilinx/ni-sbrio-9627.dts similarity index 100% rename from arch/arm/boot/dts/ni-sbrio-9627.dts rename to arch/arm/boot/dts/xilinx/ni-sbrio-9627.dts diff --git a/arch/arm/boot/dts/ni-sbrio-9637.dts b/arch/arm/boot/dts/xilinx/ni-sbrio-9637.dts similarity index 100% rename from arch/arm/boot/dts/ni-sbrio-9637.dts rename to arch/arm/boot/dts/xilinx/ni-sbrio-9637.dts diff --git a/arch/arm/boot/dts/ni-solbetter.dts b/arch/arm/boot/dts/xilinx/ni-solbetter.dts similarity index 100% rename from arch/arm/boot/dts/ni-solbetter.dts rename to arch/arm/boot/dts/xilinx/ni-solbetter.dts diff --git a/arch/arm/boot/dts/ni-solenetexp.dts b/arch/arm/boot/dts/xilinx/ni-solenetexp.dts similarity index 100% rename from arch/arm/boot/dts/ni-solenetexp.dts rename to arch/arm/boot/dts/xilinx/ni-solenetexp.dts diff --git a/arch/arm/boot/dts/ni-solgood.dts b/arch/arm/boot/dts/xilinx/ni-solgood.dts similarity index 100% rename from arch/arm/boot/dts/ni-solgood.dts rename to arch/arm/boot/dts/xilinx/ni-solgood.dts diff --git a/arch/arm/boot/dts/ni-tecate.dts b/arch/arm/boot/dts/xilinx/ni-tecate.dts similarity index 100% rename from arch/arm/boot/dts/ni-tecate.dts rename to arch/arm/boot/dts/xilinx/ni-tecate.dts diff --git a/arch/arm/boot/dts/ni-zynq.dtsi b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi similarity index 100% rename from arch/arm/boot/dts/ni-zynq.dtsi rename to arch/arm/boot/dts/xilinx/ni-zynq.dtsi From 2f555aa1c4425dca3e990167c483499789a66d95 Mon Sep 17 00:00:00 2001 From: Jeff Westfahl Date: Fri, 10 May 2013 17:18:01 -0500 Subject: [PATCH 72/83] mtd: Introduce CONFIG_MTD_RESERVE_END Add a new config parameter CONFIG_MTD_RESERVE_END. This is used with command line partition parsing to reserve space at the end of a partition defined with a size of '-', which indicates it should use all remaining space. Signed-off-by: Jeff Westfahl (cherry picked from commit 68ca9523c2d424d8bb3f71feb244464a1c6d49c9) Signed-off-by: Hatsy Rei --- drivers/mtd/parsers/Kconfig | 24 ++++++++++++++++++++++++ drivers/mtd/parsers/cmdlinepart.c | 3 ++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/drivers/mtd/parsers/Kconfig b/drivers/mtd/parsers/Kconfig index da03ab6efe04c..93d4d3fcb786a 100644 --- a/drivers/mtd/parsers/Kconfig +++ b/drivers/mtd/parsers/Kconfig @@ -62,6 +62,30 @@ config MTD_CMDLINE_PARTS If unsure, say 'N'. +config MTD_RESERVE_END + int "Reserved space at the end of an all remaining space partition" + depends on MTD_CMDLINE_PARTS = "y" + default 0 + help + Specify an amount of reserved space at the end of the last MTD + partition when the size is specified with '-' to denote all + remaining space. + + This can be useful if, for example, the BBT is stored at the end + of the flash, and you don't want those blocks counted as part of + the last MTD partition. This is less heavyweight than reserving + the BBT blocks with a separate MTD partition. The BBT marks its + own blocks as bad blocks, which prevents an MTD driver such as + UBI from getting an accurate count of the actual bad blocks in + the MTD partition that contains the BBT. + + The value is specified in bytes. As an example, a typical BBT + reserves four erase blocks, and a typical erase block size is + 128kB. To reserve that much space at the end of the flash, the + value for this config option would be 524288. + + If unsure, use the default value of zero. + config MTD_OF_PARTS tristate "OpenFirmware (device tree) partitioning parser" default y diff --git a/drivers/mtd/parsers/cmdlinepart.c b/drivers/mtd/parsers/cmdlinepart.c index 504e5fa2b45b0..b77a40158970c 100644 --- a/drivers/mtd/parsers/cmdlinepart.c +++ b/drivers/mtd/parsers/cmdlinepart.c @@ -357,7 +357,8 @@ static int parse_cmdline_partitions(struct mtd_info *master, offset = part->parts[i].offset; if (part->parts[i].size == SIZE_REMAINING) - part->parts[i].size = master->size - offset; + part->parts[i].size = master->size - offset - + CONFIG_MTD_RESERVE_END; if (offset + part->parts[i].size > master->size) { pr_warn("%s: partitioning exceeds flash size, truncating\n", From 9d4c67d9d04776fec67e6d835d3f6491d4fffcf4 Mon Sep 17 00:00:00 2001 From: Gratian Crisan Date: Thu, 25 Sep 2014 15:18:43 -0500 Subject: [PATCH 73/83] mtd: nand: xilinx: Rename the pl353 NAND driver to match bootloader The Zynq static memory controller is based on ARM PL353. The following commit [3fa059cfa4b105f09752a4eb7480d122dd5e796b nand: pl353: Renamed zynq_nand driver as pl353_nand] renamed the driver to "pl353-nand" to match the hardware. This creates problems on shipping hardware due to a mismatch between what u-boot expects (via bootargs/mtdparts) and the kernel driver name. This commit reverts the NAND driver name to the old "xilinx_nand" in order to preserve compatibility. Signed-off-by: Gratian Crisan Acked-by: Joseph Hershberger Acked-by: Terry Wilcox Natinst-ReviewBoard-ID: 79256 (cherry picked from commit df465252df84668ac5318fe6394eca5e3fe38426) Signed-off-by: Hatsy Rei --- drivers/mtd/nand/raw/pl35x-nand-controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index 2570fd0beea0d..1823deb9eccf7 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -28,7 +28,7 @@ #include #include -#define PL35X_NANDC_DRIVER_NAME "pl35x-nand-controller" +#define PL35X_NANDC_DRIVER_NAME "xilinx_nand" /* SMC controller status register (RO) */ #define PL35X_SMC_MEMC_STATUS 0x0 From daab4b2e0a9f291823c60546033935126a53e837 Mon Sep 17 00:00:00 2001 From: Hatsy Rei Date: Tue, 4 Feb 2025 21:12:33 -0800 Subject: [PATCH 74/83] ARM: dts: ni-zynq: Drop obsolete bindings Drop device tree bindings which are already declared in zynq-7000.dtsi. This includes CPU, CAN, FPGA, PL353 SMC, NAND, GPIO, I2C and SPI bindings. 'fpgaperipheral' node, now 'devcfg' in zynq-7000.dtsi describes the Xilinx Zynq FPGA Manager. Signed-off-by: Hatsy Rei --- arch/arm/boot/dts/xilinx/ni-zynq.dtsi | 133 +------------------------- 1 file changed, 1 insertion(+), 132 deletions(-) diff --git a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi index 4324e67f461a3..295d1bf31f798 100644 --- a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi @@ -21,26 +21,7 @@ #phy-cells = <0>; }; - cpus { - #address-cells = <1>; - #size-cells = <0>; - - cpu@0 { - compatible = "arm,cortex-a9"; - device_type = "cpu"; - reg = <0>; - clocks = <&clkc 3>; - }; - - cpu@1 { - compatible = "arm,cortex-a9"; - device_type = "cpu"; - reg = <1>; - clocks = <&clkc 3>; - }; - }; - - amba@0 { + amba: axi { ni_uart0: serial@80000000 { device_type = "serial"; compatible = "ni16550-fifo128", "ns16550a"; @@ -124,84 +105,7 @@ clock-frequency = <58824000>; }; - can0: can@e0008000 { - compatible = "xlnx,zynq-can-1.00.a"; - status = "disabled"; - reg = <0xe0008000 0x1000>; - interrupts = <0 28 4>; - }; - - can1: can@e0009000 { - compatible = "xlnx,zynq-can-1.00.a"; - status = "disabled"; - reg = <0xe0009000 0x1000>; - interrupts = <0 51 4>; - }; - - fpgaperipheral@f8007000 { - compatible = "fpgaperipheral"; - reg = <0xf8007000 0x100>; - }; - - smcc@e000e000 { - #address-cells = <1>; - #size-cells = <1>; - arm,addr25 = <0x0>; - arm,nor-chip-sel0 = <0x0>; - arm,nor-chip-sel1 = <0x0>; - arm,sram-chip-sel0 = <0x0>; - arm,sram-chip-sel1 = <0x0>; - clock-names = "memclk", "aclk"; - clocks = <&clkc 11>, <&clkc 44>; - compatible = "arm,pl353-smc-r2p1"; - interrupts = <0 18 4>; - ranges ; - reg = <0xe000e000 0x1000>; - nand@e1000000 { - compatible = "arm,pl353-nand-r2p1"; - reg = <0xe1000000 0x1000000>; - bank-width = <1>; /* 8-bit width */ - xlnx,nand-width = <0x8>; - - /* SLCR SMC_CLK_CTRL value, 83MHz clock, 12ns cycle time */ - /* in cycles */ - xlnx,onfi-mode0 = <0x0001021 4 3 2 7 4 10 10>; - - /* SLCR SMC_CLK_CTRL value, 166MHz clock, 6ns cycle time */ - /* in cycles */ - xlnx,onfi-mode1 = <0x0000821 4 2 2 7 4 10 10>; - xlnx,onfi-mode2 = <0x0000821 4 2 2 5 3 8 7>; - xlnx,onfi-mode3 = <0x0000821 4 2 2 5 2 7 6>; - xlnx,onfi-mode4 = <0x0000821 4 2 2 4 2 6 5>; - xlnx,onfi-mode5 = <0x0000821 4 2 2 3 2 5 4>; - - #address-cells = <1>; - #size-cells = <1>; - }; - }; - - gpio: gpio@e000a000 { - compatible = "xlnx,zynq-gpio-1.0"; - reg = <0xe000a000 0x1000>; - #interrupt-cells = <0x2>; - interrupt-controller; - interrupts = <0 20 4>; - clocks = <&clkc 42>; - #gpio-cells = <2>; - gpio-controller; - }; - i2c0: i2c@e0004000 { - compatible = "cdns,i2c-r1p10"; - reg = <0xE0004000 0x1000>; - interrupts = <0 25 4>; - bus-id = <0>; - clocks = <&clkc 38>; - clock-frequency = <400000>; - #address-cells = <1>; - #size-cells = <0>; - status = "okay"; - nicpld@40 { compatible = "ni,cpld"; reg = <0x40>; @@ -214,18 +118,6 @@ }; }; - i2c1: i2c@e0005000 { - compatible = "cdns,i2c-r1p10"; - status = "disabled"; - reg = <0xe0005000 0x1000>; - interrupts = <0 48 4>; - bus-id = <1>; - clocks = <&clkc 39>; - clock-frequency = <400000>; - #address-cells = <1>; - #size-cells = <0>; - } ; - i2c2: i2c@81000000 { compatible = "xlnx,xps-iic-2.00.a"; status = "disabled"; @@ -236,28 +128,6 @@ #size-cells = <0>; }; - spi0: spi@e0006000 { - compatible = "cdns,spi-r1p6"; - status = "disabled"; - reg = <0xe0006000 0x1000>; - interrupts = <0 26 4>; - clock-names = "ref_clk", "pclk"; - clocks = <&clkc 25>, <&clkc 34>; - #address-cells = <1>; - #size-cells = <0>; - }; - - spi1: spi@e0007000 { - compatible = "cdns,spi-r1p6"; - status = "disabled"; - reg = <0xe0007000 0x1000>; - interrupts = <0 49 4>; - clock-names = "ref_clk", "pclk"; - clocks = <&clkc 26>, <&clkc 35>; - #address-cells = <1>; - #size-cells = <0>; - }; - usb0: usb@e0002000 { usb-phy = <&usb_phy0>; }; @@ -266,7 +136,6 @@ usb-phy = <&usb_phy1>; }; }; - }; &L2 { From 7c1614dd807e04282579c1fc9a7f241ee424bbbe Mon Sep 17 00:00:00 2001 From: Hatsy Rei Date: Tue, 4 Feb 2025 21:30:42 -0800 Subject: [PATCH 75/83] ARM: dts: ni-zynq: Enable zynq-7000 SMC, NAND nodes Enable PL353 SMC and NAND device tree nodes declared in zynq-7000.dtsi. Indicate via 'nand-on-flash-bbt' property that bad block table is stored on the nand flash, and 'nand-ecc-mode' property that on-die ECC is used. Signed-off-by: Hatsy Rei --- arch/arm/boot/dts/xilinx/ni-zynq.dtsi | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi index 295d1bf31f798..9cf6ccc57dd37 100644 --- a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi @@ -138,6 +138,20 @@ }; }; +&smcc { + status = "okay"; +}; + +&nfc0 { + status = "okay"; + + nand@0 { + reg = <0>; + nand-on-flash-bbt; + nand-ecc-mode = "on-die"; + }; +}; + &L2 { prefetch-data = <1>; prefetch-instr = <1>; From e14945795a333af4ffaa28a4caaa45367a4c0a16 Mon Sep 17 00:00:00 2001 From: Hatsy Rei Date: Tue, 4 Feb 2025 21:54:37 -0800 Subject: [PATCH 76/83] ARM: dts: ni-zynq: Extend I2C, USB nodes via phandle Avoid redeclaring these nodes and just extend them via phandles. Signed-off-by: Hatsy Rei --- arch/arm/boot/dts/xilinx/ni-zynq.dtsi | 38 +++++++++++++-------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi index 9cf6ccc57dd37..302a81ef1c2c0 100644 --- a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi @@ -105,19 +105,6 @@ clock-frequency = <58824000>; }; - i2c0: i2c@e0004000 { - nicpld@40 { - compatible = "ni,cpld"; - reg = <0x40>; - }; - - ds3231_rtc@68 { - compatible = "ds3232"; - status = "disabled"; - reg = <0x68>; - }; - }; - i2c2: i2c@81000000 { compatible = "xlnx,xps-iic-2.00.a"; status = "disabled"; @@ -127,17 +114,30 @@ #address-cells = <1>; #size-cells = <0>; }; + }; +}; - usb0: usb@e0002000 { - usb-phy = <&usb_phy0>; - }; +&i2c0 { + nicpld@40 { + compatible = "ni,cpld"; + reg = <0x40>; + }; - usb1: usb@e0003000 { - usb-phy = <&usb_phy1>; - }; + ds3231_rtc@68 { + compatible = "ds3232"; + status = "disabled"; + reg = <0x68>; }; }; +&usb0 { + usb-phy = <&usb_phy0>; +}; + +&usb1 { + usb-phy = <&usb_phy1>; +}; + &smcc { status = "okay"; }; From 2db35d7c7128149371b729f326e90f9b27d97a45 Mon Sep 17 00:00:00 2001 From: Hatsy Rei Date: Tue, 4 Feb 2025 22:20:53 -0800 Subject: [PATCH 77/83] ARM: dts: ni-bluefin: Update AMBA and GPIO bindings zynq-7000.dtsi contains updated AMBA and GPIO device tree node phandles. Adopt these changes by referencing i2c0 phandle instead of amba node for overriding i2c bindings, and refer to gpio0 phandle instead of gpio. Signed-off-by: Hatsy Rei --- arch/arm/boot/dts/xilinx/ni-bluefin.dts | 38 ++++++++++++------------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/arch/arm/boot/dts/xilinx/ni-bluefin.dts b/arch/arm/boot/dts/xilinx/ni-bluefin.dts index 19f9ef5ab6614..05d4b0ef837f9 100644 --- a/arch/arm/boot/dts/xilinx/ni-bluefin.dts +++ b/arch/arm/boot/dts/xilinx/ni-bluefin.dts @@ -8,35 +8,20 @@ model = "NI Bluefin"; compatible = "ni,zynq", "xlnx,zynq-7000"; - amba@0 { - i2c0: i2c@e0004000 { - /* Override ni-zynq.dtsi; we do not have a CPLD at 0x40. */ - nicpld@40 { - status = "disabled"; - }; - - tmp451@4C { - compatible = "ti,tmp451"; - reg = <0x4C>; - vcc-supply = <®ulator_vccpint>; - }; - }; - }; - leds { compatible = "gpio-leds"; /* LED_STATUSy on GPIO46 */ status { label = "nilrt:status:yellow"; - gpios = <&gpio 46 0>; + gpios = <&gpio0 46 0>; default-state = "on"; }; /* LED_ACTIVEg on GPIO47 */ active { label = "nilrt:active:green"; - gpios = <&gpio 47 0>; + gpios = <&gpio0 47 0>; default-state = "off"; }; }; @@ -49,7 +34,7 @@ /* Reset switch is on GPIO48 */ reset_sw@0 { label = "reset_sw"; - gpios = <&gpio 48 1 /* GPIO_ACTIVE_LOW */>; + gpios = <&gpio0 48 1 /* GPIO_ACTIVE_LOW */>; linux,code = <408>; /* KEY_RESTART */ gpio-key,wakeup; }; @@ -59,15 +44,28 @@ compatible = "gpio-restart"; /* ~PS_FORCE_RESET is on GPIO44 */ - gpios = <&gpio 44 1 /* GPIO_ACTIVE_LOW */>; + gpios = <&gpio0 44 1 /* GPIO_ACTIVE_LOW */>; priority = <200>; }; }; +&i2c0 { + /* Override ni-zynq.dtsi; we do not have a CPLD at 0x40. */ + nicpld@40 { + status = "disabled"; + }; + + tmp451@4C { + compatible = "ti,tmp451"; + reg = <0x4C>; + vcc-supply = <®ulator_vccpint>; + }; +}; + &gem0 { status = "okay"; emio-speed-gpios = <0>, - <&gpio 54 0>; + <&gpio0 54 0>; #address-cells = <0x1>; #size-cells = <0x0>; From 10be949e33205f0c673d319ca3b9eaa4427c116c Mon Sep 17 00:00:00 2001 From: HatsyRei Date: Mon, 10 Feb 2025 20:20:08 +0800 Subject: [PATCH 78/83] ARM: dts: ni-zynq: Update NI 16550 bindings Update 'compatible' property to match what is expected by the latest NI 16550 UART Driver. Signed-off-by: HatsyRei --- arch/arm/boot/dts/xilinx/ni-zynq.dtsi | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi index 302a81ef1c2c0..086e17729433b 100644 --- a/arch/arm/boot/dts/xilinx/ni-zynq.dtsi +++ b/arch/arm/boot/dts/xilinx/ni-zynq.dtsi @@ -24,7 +24,7 @@ amba: axi { ni_uart0: serial@80000000 { device_type = "serial"; - compatible = "ni16550-fifo128", "ns16550a"; + compatible = "ni,ni16550"; status = "disabled"; reg = <0x80000000 0x8>; interrupts = <0 30 4>; @@ -35,7 +35,7 @@ ni_uart1: serial@80000010 { device_type = "serial"; - compatible = "ni16550-fifo128", "ns16550a"; + compatible = "ni,ni16550"; status = "disabled"; reg = <0x80000010 0x8>; interrupts = <0 31 4>; @@ -44,7 +44,7 @@ ni_uart2: serial@80000020 { device_type = "serial"; - compatible = "ni16550-fifo128", "ns16550a"; + compatible = "ni,ni16550"; status = "disabled"; reg = <0x80000020 0x8>; interrupts = <0 32 4>; @@ -53,7 +53,7 @@ ni_uart3: serial@80000030 { device_type = "serial"; - compatible = "ni16550-fifo128", "ns16550a"; + compatible = "ni,ni16550"; status = "disabled"; reg = <0x80000030 0x8>; interrupts = <0 33 0>; @@ -62,7 +62,7 @@ ni_uart4: serial@80000040 { device_type = "serial"; - compatible = "ni16550-fifo128", "ns16550a"; + compatible = "ni,ni16550"; status = "disabled"; reg = <0x80000040 0x8>; interrupts = <0 34 0>; @@ -71,7 +71,7 @@ ni_uart5: serial@80000050 { device_type = "serial"; - compatible = "ni16550-fifo128", "ns16550a"; + compatible = "ni,ni16550"; status = "disabled"; reg = <0x80000050 0x8>; interrupts = <0 35 0>; @@ -80,7 +80,7 @@ ni_uart6: serial@80000060 { device_type = "serial"; - compatible = "ni16550-fifo128", "ns16550a"; + compatible = "ni,ni16550"; status = "disabled"; reg = <0x80000060 0x8>; interrupts = <0 36 0>; @@ -89,7 +89,7 @@ ni_uart7: serial@80000070 { device_type = "serial"; - compatible = "ni16550-fifo128", "ns16550a"; + compatible = "ni,ni16550"; status = "disabled"; reg = <0x80000070 0x8>; interrupts = <0 52 0>; @@ -98,7 +98,7 @@ ni_uart8: serial@80000080 { device_type = "serial"; - compatible = "ni16550-fifo128", "ns16550a"; + compatible = "ni,ni16550"; status = "disabled"; reg = <0x80000080 0x8>; interrupts = <0 53 0>; From 0460d997853de843ac3a17f03dcd74ca8ecf05c4 Mon Sep 17 00:00:00 2001 From: Kevin Lim Date: Thu, 13 Feb 2025 10:17:35 +0800 Subject: [PATCH 79/83] serial: core: create anonymous parent device Use platform_device_register_simple to create a parent device if parent device pointer is null. Signed-off-by: Kevin Lim --- drivers/tty/serial/serial_core.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index d94d73e45fb6d..e6c1a4ba17a09 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -31,6 +31,7 @@ #include #include +#include #include "serial_base.h" @@ -3392,6 +3393,22 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port) */ port->flags |= UPF_DEAD; + if (port->dev == NULL) { + static unsigned int next_port_number; + char port_name[21]; + struct platform_device *pdev; + + snprintf(port_name, sizeof(port_name), "anon_port_%u", next_port_number++); + pdev = platform_device_register_simple(port_name, -1, NULL, 0); + + if (PTR_ERR_OR_ZERO(pdev)) { + ret = -EINVAL; + goto err_unlock; + } + + port->dev = &pdev->dev; + } + /* Inititalize a serial core controller device if needed */ ctrl_dev = serial_core_ctrl_find(drv, port->dev, port->ctrl_id); if (!ctrl_dev) { @@ -3430,6 +3447,9 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port) err_unregister_ctrl_dev: serial_base_ctrl_device_remove(new_ctrl_dev); + if (strncmp(to_platform_device(port->dev)->name, "anon_port", 9) == 0) + platform_device_del(to_platform_device(port->dev)); + err_unlock: mutex_unlock(&port_mutex); @@ -3460,6 +3480,9 @@ void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port if (!serial_core_ctrl_find(drv, phys_dev, ctrl_id)) serial_base_ctrl_device_remove(ctrl_dev); + if (strncmp(to_platform_device(phys_dev)->name, "anon_port", 9) == 0) + platform_device_del(to_platform_device(phys_dev)); + mutex_unlock(&port_mutex); } From c5ccb95b534b34c386e19de0a5f499036aef3280 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Mon, 24 Feb 2025 11:01:09 -0600 Subject: [PATCH 80/83] github-actions: Add PR checks Add GitHub actions to do PR sanity checks. Signed-off-by: Chaitanya Vadrevu --- .github/workflows/pr-checks.yml | 46 +++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 .github/workflows/pr-checks.yml diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml new file mode 100644 index 0000000000000..8df161810f928 --- /dev/null +++ b/.github/workflows/pr-checks.yml @@ -0,0 +1,46 @@ +name: PR Checks + +on: + pull_request: {} + workflow_dispatch: {} + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} + fetch-depth: 100 + + - name: Fetch base_ref + run: git -c protocol.version=2 fetch --no-tags --prune --no-recurse-submodules --depth=1 origin ${{ github.base_ref }} + + - name: Install build dependencies + run: | + sudo apt update + sudo apt install libelf-dev + + - name: "[TEST] Build nati_x86_64_defconfig" + run: | + make nati_x86_64_defconfig + make -j8 bzImage modules + + - name: "[TEST] Does nati_x86_64_defconfig need update" + run: | + make savedefconfig + diff defconfig arch/x86/configs/nati_x86_64_defconfig + + - name: "[TEST] Is rebase required" + run: | + common_ancestor=$(git merge-base HEAD origin/${{ github.base_ref }}) + base_ref_head=$(git log -1 --format=%H origin/${{ github.base_ref }}) + + [ $common_ancestor == $base_ref_head ] + + - name: "[TEST] Run checkpatch.pl" + run: | + common_ancestor=$(git merge-base HEAD origin/${{ github.base_ref }}) + git format-patch $common_ancestor + ./scripts/checkpatch.pl *patch From f201cd76e69988b4d534f704ca3869d8a92790c7 Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Thu, 6 Mar 2025 19:45:44 -0600 Subject: [PATCH 81/83] fixup! proc/interrupts: Add polling include linux/wait.h for wait_queue_head_t Signed-off-by: Chaitanya Vadrevu --- include/linux/interrupt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 171d82ecf656f..235fb5e45fc39 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -21,6 +21,8 @@ #include #include +#include + /* * These correspond to the IORESOURCE_IRQ_* defines in * linux/ioport.h to select the interrupt line behaviour. When From 3b791177bed18f4eb4b92adb19cfdf05ec578753 Mon Sep 17 00:00:00 2001 From: HatsyRei Date: Mon, 3 Mar 2025 14:15:15 +0800 Subject: [PATCH 82/83] pl35x-nand-controller: Enable on-die ECC subpage operations Existing devices may contain partitions formatted with subpages, but the default PL35X NAND driver does not support them. This commit implements subpage read and write support for on-die ECC devices using the PL35X NAND driver. Signed-off-by: HatsyRei --- drivers/mtd/nand/raw/pl35x-nand-controller.c | 38 ++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/drivers/mtd/nand/raw/pl35x-nand-controller.c b/drivers/mtd/nand/raw/pl35x-nand-controller.c index 1823deb9eccf7..54bab5b922127 100644 --- a/drivers/mtd/nand/raw/pl35x-nand-controller.c +++ b/drivers/mtd/nand/raw/pl35x-nand-controller.c @@ -499,6 +499,14 @@ static int pl35x_nand_recover_data_hwecc(struct pl35x_nandc *nfc, return max_bitflips; } +static int pl35x_nand_write_subpage_raw(struct nand_chip *chip, + uint32_t offset, uint32_t data_len, + const uint8_t *data_buf, + int oob_required, int page) +{ + return nand_monolithic_write_page_raw(chip, data_buf, oob_required, page); +} + static int pl35x_nand_write_page_hwecc(struct nand_chip *chip, const u8 *buf, int oob_required, int page) @@ -659,6 +667,12 @@ static int pl35x_nand_read_page_hwecc(struct nand_chip *chip, return ret; } +static int pl35x_nand_read_subpage_raw(struct nand_chip *chip, uint32_t data_offs, + uint32_t readlen, uint8_t *bufpoi, int page) +{ + return nand_monolithic_read_page_raw(chip, bufpoi, 0, page); +} + static int pl35x_nand_exec_op(struct nand_chip *chip, const struct nand_subop *subop) { @@ -936,6 +950,29 @@ static int pl35x_nand_init_hw_ecc_controller(struct pl35x_nandc *nfc, return ret; } +static void pl35x_nand_init_ondie_ecc(struct pl35x_nandc *nfc, + struct nand_chip *chip) +{ + struct mtd_info *mtd = nand_to_mtd(chip); + + /* Bypass the controller ECC block */ + pl35x_smc_set_ecc_mode(nfc, chip, PL35X_SMC_ECC_CFG_MODE_BYPASS); + + chip->ecc.strength = 1; + chip->ecc.bytes = 0; + chip->ecc.read_page = nand_monolithic_read_page_raw; + chip->ecc.read_page_raw = nand_monolithic_read_page_raw; + chip->ecc.read_subpage = pl35x_nand_read_subpage_raw; + chip->ecc.write_page = nand_monolithic_write_page_raw; + chip->ecc.write_page_raw = nand_monolithic_write_page_raw; + chip->ecc.write_subpage = pl35x_nand_write_subpage_raw; + chip->ecc.size = mtd->writesize; + + /* NAND with on-die ECC supports subpage reads and writes */ + chip->options |= NAND_SUBPAGE_READ; + chip->options &= ~(NAND_NO_SUBPAGE_WRITE); +} + static int pl35x_nand_attach_chip(struct nand_chip *chip) { const struct nand_ecc_props *requirements = @@ -970,6 +1007,7 @@ static int pl35x_nand_attach_chip(struct nand_chip *chip) switch (chip->ecc.engine_type) { case NAND_ECC_ENGINE_TYPE_ON_DIE: + pl35x_nand_init_ondie_ecc(nfc, chip); /* Keep these legacy BBT descriptors for ON_DIE situations */ chip->bbt_td = &bbt_main_descr; chip->bbt_md = &bbt_mirror_descr; From b83fe9ce32e3f0c942850703865522006e5e827c Mon Sep 17 00:00:00 2001 From: Chaitanya Vadrevu Date: Thu, 12 Oct 2023 15:51:11 -0500 Subject: [PATCH 83/83] serial: 8250: add driver for NI UARTs The National Instruments (NI) 16550 is a 16550-like UART with larger FIFOs and embedded RS-232/RS-485 transceiver control circuitry. This patch adds a driver that can operate this UART, which is used for onboard serial ports in several NI embedded controller designs. Portions of this driver were originally written by Jaeden Amero and Karthik Manamcheri, with extensive cleanups and refactors since by Brenda Streiff. Cc: Gratian Crisan Co-developed-by: Jason Smith Signed-off-by: Jason Smith Signed-off-by: Chaitanya Vadrevu --- MAINTAINERS | 6 + drivers/tty/serial/8250/8250_ni.c | 474 ++++++++++++++++++++++++++++++ drivers/tty/serial/8250/Kconfig | 13 + drivers/tty/serial/8250/Makefile | 1 + 4 files changed, 494 insertions(+) create mode 100644 drivers/tty/serial/8250/8250_ni.c diff --git a/MAINTAINERS b/MAINTAINERS index 6bb4ec0c162a5..888727d778f75 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -15903,6 +15903,12 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/mtd/linux.git nand/next F: drivers/mtd/nand/ F: include/linux/mtd/*nand*.h +NATIONAL INSTRUMENTS SERIAL DRIVER +M: Chaitanya Vadrevu +L: linux-serial@vger.kernel.org +S: Maintained +F: drivers/tty/serial/8250/8250_ni.c + NATIVE INSTRUMENTS USB SOUND INTERFACE DRIVER M: Daniel Mack L: linux-sound@vger.kernel.org diff --git a/drivers/tty/serial/8250/8250_ni.c b/drivers/tty/serial/8250/8250_ni.c new file mode 100644 index 0000000000000..d837055bed96a --- /dev/null +++ b/drivers/tty/serial/8250/8250_ni.c @@ -0,0 +1,474 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * NI 16550 UART Driver + * + * The National Instruments (NI) 16550 is a UART that is compatible with the + * TL16C550C and OX16C950B register interfaces, but has additional functions + * for RS-485 transceiver control. This driver implements support for the + * additional functionality on top of the standard serial8250 core. + * + * Copyright 2012-2023 National Instruments Corporation + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "8250.h" + +/* Extra bits in UART_ACR */ +#define NI16550_ACR_AUTO_DTR_EN BIT(4) + +/* TFS - TX FIFO Size */ +#define NI16550_TFS_OFFSET 0x0C +/* RFS - RX FIFO Size */ +#define NI16550_RFS_OFFSET 0x0D + +/* PMR - Port Mode Register */ +#define NI16550_PMR_OFFSET 0x0E +/* PMR[1:0] - Port Capabilities */ +#define NI16550_PMR_CAP_MASK GENMASK(1, 0) +#define NI16550_PMR_NOT_IMPL FIELD_PREP(NI16550_PMR_CAP_MASK, 0) /* not implemented */ +#define NI16550_PMR_CAP_RS232 FIELD_PREP(NI16550_PMR_CAP_MASK, 1) /* RS-232 capable */ +#define NI16550_PMR_CAP_RS485 FIELD_PREP(NI16550_PMR_CAP_MASK, 2) /* RS-485 capable */ +#define NI16550_PMR_CAP_DUAL FIELD_PREP(NI16550_PMR_CAP_MASK, 3) /* dual-port */ +/* PMR[4] - Interface Mode */ +#define NI16550_PMR_MODE_MASK GENMASK(4, 4) +#define NI16550_PMR_MODE_RS232 FIELD_PREP(NI16550_PMR_MODE_MASK, 0) /* currently 232 */ +#define NI16550_PMR_MODE_RS485 FIELD_PREP(NI16550_PMR_MODE_MASK, 1) /* currently 485 */ + +/* PCR - Port Control Register */ +/* + * Wire Mode | Tx enabled? | Rx enabled? + * ---------------|----------------------|-------------------------- + * PCR_RS422 | Always | Always + * PCR_ECHO_RS485 | When DTR asserted | Always + * PCR_DTR_RS485 | When DTR asserted | Disabled when TX enabled + * PCR_AUTO_RS485 | When data in TX FIFO | Disabled when TX enabled + */ +#define NI16550_PCR_OFFSET 0x0F +#define NI16550_PCR_WIRE_MODE_MASK GENMASK(1, 0) +#define NI16550_PCR_RS422 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 0) +#define NI16550_PCR_ECHO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 1) +#define NI16550_PCR_DTR_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 2) +#define NI16550_PCR_AUTO_RS485 FIELD_PREP(NI16550_PCR_WIRE_MODE_MASK, 3) +#define NI16550_PCR_TXVR_ENABLE_BIT BIT(3) +#define NI16550_PCR_RS485_TERMINATION_BIT BIT(6) + +/* flags for ni16550_device_info */ +#define NI_HAS_PMR BIT(0) + +struct ni16550_device_info { + u32 uartclk; + u8 prescaler; + u8 flags; +}; + +struct ni16550_data { + int line; + struct clk *clk; +}; + +static int ni16550_enable_transceivers(struct uart_port *port) +{ + u8 pcr; + + pcr = port->serial_in(port, NI16550_PCR_OFFSET); + pcr |= NI16550_PCR_TXVR_ENABLE_BIT; + dev_dbg(port->dev, "enable transceivers: write pcr: 0x%02x\n", pcr); + port->serial_out(port, NI16550_PCR_OFFSET, pcr); + + return 0; +} + +static int ni16550_disable_transceivers(struct uart_port *port) +{ + u8 pcr; + + pcr = port->serial_in(port, NI16550_PCR_OFFSET); + pcr &= ~NI16550_PCR_TXVR_ENABLE_BIT; + dev_dbg(port->dev, "disable transceivers: write pcr: 0x%02x\n", pcr); + port->serial_out(port, NI16550_PCR_OFFSET, pcr); + + return 0; +} + +static int ni16550_rs485_config(struct uart_port *port, + struct ktermios *termios, + struct serial_rs485 *rs485) +{ + struct uart_8250_port *up = container_of(port, struct uart_8250_port, port); + u8 pcr; + + pcr = serial_in(up, NI16550_PCR_OFFSET); + pcr &= ~NI16550_PCR_WIRE_MODE_MASK; + + if ((rs485->flags & SER_RS485_MODE_RS422) || + !(rs485->flags & SER_RS485_ENABLED)) { + /* RS-422 */ + pcr |= NI16550_PCR_RS422; + up->acr &= ~NI16550_ACR_AUTO_DTR_EN; + } else { + /* RS-485 2-wire Auto */ + pcr |= NI16550_PCR_AUTO_RS485; + up->acr |= NI16550_ACR_AUTO_DTR_EN; + } + + dev_dbg(port->dev, "config rs485: write pcr: 0x%02x, acr: %02x\n", pcr, up->acr); + serial_out(up, NI16550_PCR_OFFSET, pcr); + serial_icr_write(up, UART_ACR, up->acr); + + return 0; +} + +static bool is_pmr_rs232_mode(struct uart_8250_port *up) +{ + u8 pmr = serial_in(up, NI16550_PMR_OFFSET); + u8 pmr_mode = pmr & NI16550_PMR_MODE_MASK; + u8 pmr_cap = pmr & NI16550_PMR_CAP_MASK; + + /* + * If the PMR is not implemented, then by default NI UARTs are + * connected to RS-485 transceivers + */ + if (pmr_cap == NI16550_PMR_NOT_IMPL) + return false; + + if (pmr_cap == NI16550_PMR_CAP_DUAL) + /* + * If the port is dual-mode capable, then read the mode bit + * to know the current mode + */ + return pmr_mode == NI16550_PMR_MODE_RS232; + /* + * If it is not dual-mode capable, then decide based on the + * capability + */ + return pmr_cap == NI16550_PMR_CAP_RS232; +} + +static void ni16550_config_prescaler(struct uart_8250_port *up, + u8 prescaler) +{ + /* + * Page in the Enhanced Mode Registers + * Sets EFR[4] for Enhanced Mode. + */ + u8 lcr_value; + u8 efr_value; + + lcr_value = serial_in(up, UART_LCR); + serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B); + + efr_value = serial_in(up, UART_EFR); + efr_value |= UART_EFR_ECB; + + serial_out(up, UART_EFR, efr_value); + + /* Page out the Enhanced Mode Registers */ + serial_out(up, UART_LCR, lcr_value); + + /* Set prescaler to CPR register. */ + serial_out(up, UART_SCR, UART_CPR); + serial_out(up, UART_ICR, prescaler); +} + +static const struct serial_rs485 ni16550_rs485_supported = { + .flags = SER_RS485_ENABLED | SER_RS485_MODE_RS422 | SER_RS485_RTS_ON_SEND | + SER_RS485_RTS_AFTER_SEND, + /* + * delay_rts_* and RX_DURING_TX are not supported. + * + * RTS_{ON,AFTER}_SEND are supported, but ignored; the transceiver + * is connected in only one way and we don't need userspace to tell + * us, but want to retain compatibility with applications that do. + */ +}; + +static void ni16550_rs485_setup(struct uart_port *port) +{ + port->rs485_config = ni16550_rs485_config; + port->rs485_supported = ni16550_rs485_supported; + /* + * The hardware comes up by default in 2-wire auto mode and we + * set the flags to represent that + */ + port->rs485.flags = SER_RS485_ENABLED | SER_RS485_RTS_ON_SEND; +} + +static int ni16550_port_startup(struct uart_port *port) +{ + int ret; + + ret = serial8250_do_startup(port); + if (ret) + return ret; + + return ni16550_enable_transceivers(port); +} + +static void ni16550_port_shutdown(struct uart_port *port) +{ + ni16550_disable_transceivers(port); + + serial8250_do_shutdown(port); +} + +static int ni16550_get_regs(struct platform_device *pdev, + struct uart_port *port) +{ + struct resource *regs; + + regs = platform_get_resource(pdev, IORESOURCE_IO, 0); + if (regs) { + port->iotype = UPIO_PORT; + port->iobase = regs->start; + + return 0; + } + + regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (regs) { + port->iotype = UPIO_MEM; + port->mapbase = regs->start; + port->mapsize = resource_size(regs); + port->flags |= UPF_IOREMAP; + + port->membase = devm_ioremap(&pdev->dev, port->mapbase, + port->mapsize); + if (!port->membase) + return -ENOMEM; + + return 0; + } + + dev_err(&pdev->dev, "no registers defined\n"); + return -EINVAL; +} + +/* + * Very old implementations don't have the TFS or RFS registers + * defined, so we may read all-0s or all-1s. For such devices, + * assume a FIFO size of 128. + */ +static u8 ni16550_read_fifo_size(struct uart_8250_port *uart, int reg) +{ + u8 value = serial_in(uart, reg); + + if (value == 0x00 || value == 0xFF) + return 128; + + return value; +} + +static void ni16550_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + struct uart_8250_port *up = up_to_u8250p(port); + + up->mcr |= UART_MCR_CLKSEL; + serial8250_do_set_mctrl(port, mctrl); +} + +static int ni16550_probe(struct platform_device *pdev) +{ + const struct ni16550_device_info *info; + struct device *dev = &pdev->dev; + struct uart_8250_port uart = {}; + unsigned int prescaler = 0; + struct ni16550_data *data; + const char *portmode; + unsigned int txfifosz, rxfifosz; + bool rs232_property; + int ret; + int irq; + + data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + spin_lock_init(&uart.port.lock); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = ni16550_get_regs(pdev, &uart.port); + if (ret < 0) + return ret; + + /* early setup so that serial_in()/serial_out() work */ + serial8250_set_defaults(&uart); + + info = device_get_match_data(dev); + + uart.port.dev = dev; + uart.port.irq = irq; + uart.port.irqflags = IRQF_SHARED; + uart.port.flags = UPF_SHARE_IRQ | UPF_BOOT_AUTOCONF + | UPF_FIXED_PORT | UPF_FIXED_TYPE; + uart.port.startup = ni16550_port_startup; + uart.port.shutdown = ni16550_port_shutdown; + + /* + * Hardware instantiation of FIFO sizes are held in registers. + */ + txfifosz = ni16550_read_fifo_size(&uart, NI16550_TFS_OFFSET); + rxfifosz = ni16550_read_fifo_size(&uart, NI16550_RFS_OFFSET); + + dev_dbg(dev, "NI 16550 has TX FIFO size %u, RX FIFO size %u\n", + txfifosz, rxfifosz); + + uart.port.type = PORT_16550A; + uart.port.fifosize = txfifosz; + uart.tx_loadsz = txfifosz; + uart.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10; + uart.capabilities = UART_CAP_FIFO | UART_CAP_AFE | UART_CAP_EFR; + + /* + * Declaration of the base clock frequency can come from one of: + * - static declaration in this driver (for older ACPI IDs) + * - a "clock-frquency" ACPI or OF device property + * - an associated OF clock definition + */ + if (info->uartclk) + uart.port.uartclk = info->uartclk; + if (device_property_read_u32(dev, "clock-frequency", + &uart.port.uartclk)) { + data->clk = devm_clk_get_enabled(dev, NULL); + if (!IS_ERR(data->clk)) + uart.port.uartclk = clk_get_rate(data->clk); + } + + if (!uart.port.uartclk) { + dev_err(dev, "unable to determine clock frequency!\n"); + ret = -ENODEV; + goto err; + } + + if (info->prescaler) + prescaler = info->prescaler; + device_property_read_u32(dev, "clock-prescaler", &prescaler); + + if (prescaler != 0) { + uart.port.set_mctrl = ni16550_set_mctrl; + ni16550_config_prescaler(&uart, (u8)prescaler); + } + + /* + * The determination of whether or not this is an RS-485 or RS-232 port + * can come from a device property (if present), or it can come from + * the PMR (if present), and otherwise we're solely an RS-485 port. + * + * This is a device-specific property, and thus has a vendor-prefixed + * "ni,serial-port-mode" form as a devicetree binding. However, there + * are old devices in the field using "transceiver" as an ACPI device + * property, so we have to check for that as well. + */ + if (!device_property_read_string(dev, "ni,serial-port-mode", &portmode) || + !device_property_read_string(dev, "transceiver", &portmode)) { + rs232_property = strncmp(portmode, "RS-232", 6) == 0; + + dev_dbg(dev, "port is in %s mode (via device property)\n", + rs232_property ? "RS-232" : "RS-485"); + } else if (info->flags & NI_HAS_PMR) { + rs232_property = is_pmr_rs232_mode(&uart); + + dev_dbg(dev, "port is in %s mode (via PMR)\n", + rs232_property ? "RS-232" : "RS-485"); + } else { + rs232_property = 0; + + dev_dbg(dev, "port is fixed as RS-485\n"); + } + + if (!rs232_property) { + /* + * Neither the 'transceiver' property nor the PMR indicate + * that this is an RS-232 port, so it must be an RS-485 one. + */ + ni16550_rs485_setup(&uart.port); + } + + ret = serial8250_register_8250_port(&uart); + if (ret < 0) + goto err; + data->line = ret; + + platform_set_drvdata(pdev, data); + return 0; + +err: + return ret; +} + +static void ni16550_remove(struct platform_device *pdev) +{ + struct ni16550_data *data = platform_get_drvdata(pdev); + + serial8250_unregister_port(data->line); +} + +static const struct ni16550_device_info ni16550_default = { }; + +static const struct of_device_id ni16550_of_match[] = { + { .compatible = "ni,ni16550", .data = &ni16550_default }, + { }, +}; +MODULE_DEVICE_TABLE(of, ni16550_of_match); + +#ifdef CONFIG_ACPI +/* NI 16550 RS-485 Interface */ +static const struct ni16550_device_info nic7750 = { + .uartclk = 33333333, +}; + +/* NI CVS-145x RS-485 Interface */ +static const struct ni16550_device_info nic7772 = { + .uartclk = 1843200, + .flags = NI_HAS_PMR, +}; + +/* NI cRIO-904x RS-485 Interface */ +static const struct ni16550_device_info nic792b = { + /* Sets UART clock rate to 22.222 MHz with 1.125 prescale */ + .uartclk = 22222222, + .prescaler = 0x09, +}; + +/* NI sbRIO 96x8 RS-232/485 Interfaces */ +static const struct ni16550_device_info nic7a69 = { + /* Set UART clock rate to 29.629 MHz with 1.125 prescale */ + .uartclk = 29629629, + .prescaler = 0x09, +}; +static const struct acpi_device_id ni16550_acpi_match[] = { + { "NIC7750", (kernel_ulong_t)&nic7750 }, + { "NIC7772", (kernel_ulong_t)&nic7772 }, + { "NIC792B", (kernel_ulong_t)&nic792b }, + { "NIC7A69", (kernel_ulong_t)&nic7a69 }, + { }, +}; +MODULE_DEVICE_TABLE(acpi, ni16550_acpi_match); +#endif + +static struct platform_driver ni16550_driver = { + .driver = { + .name = "ni16550", + .of_match_table = ni16550_of_match, + .acpi_match_table = ACPI_PTR(ni16550_acpi_match), + }, + .probe = ni16550_probe, + .remove = ni16550_remove, +}; + +module_platform_driver(ni16550_driver); + +MODULE_AUTHOR("Emerson Electric Co."); +MODULE_DESCRIPTION("NI 16550 Driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig index 47ff50763c048..d887a7219e947 100644 --- a/drivers/tty/serial/8250/Kconfig +++ b/drivers/tty/serial/8250/Kconfig @@ -568,6 +568,19 @@ config SERIAL_8250_BCM7271 including DMA support and high accuracy BAUD rates, say Y to this option. If unsure, say N. +config SERIAL_8250_NI + tristate "NI 16550 based serial port" + depends on SERIAL_8250 + depends on (X86 && ACPI) || (ARCH_ZYNQ && OF) || COMPILE_TEST + help + This driver supports the integrated serial ports on National + Instruments (NI) controller hardware. This is required for all NI + controller models with onboard RS-485 or dual-mode RS-485/RS-232 + ports. + + To compile this driver as a module, choose M here: the module + will be called 8250_ni. + config SERIAL_OF_PLATFORM tristate "Devicetree based probing for 8250 ports" depends on SERIAL_8250 && OF diff --git a/drivers/tty/serial/8250/Makefile b/drivers/tty/serial/8250/Makefile index 1516de629b617..b04eeda03b234 100644 --- a/drivers/tty/serial/8250/Makefile +++ b/drivers/tty/serial/8250/Makefile @@ -40,6 +40,7 @@ obj-$(CONFIG_SERIAL_8250_LPSS) += 8250_lpss.o obj-$(CONFIG_SERIAL_8250_MEN_MCB) += 8250_men_mcb.o obj-$(CONFIG_SERIAL_8250_MID) += 8250_mid.o obj-$(CONFIG_SERIAL_8250_MT6577) += 8250_mtk.o +obj-$(CONFIG_SERIAL_8250_NI) += 8250_ni.o obj-$(CONFIG_SERIAL_OF_PLATFORM) += 8250_of.o obj-$(CONFIG_SERIAL_8250_OMAP) += 8250_omap.o obj-$(CONFIG_SERIAL_8250_PARISC) += 8250_parisc.o