diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html
index 18963bc574f..7878f2fd250 100644
--- a/Documentation/NuttX.html
+++ b/Documentation/NuttX.html
@@ -4920,34 +4920,6 @@ Mem: 29232 5920 23312 23312
-
-
|
-
|
-
-
-
|
-
-
- RGMP.
- RGMP stands for RTOS and GPOS on Multi-Processor.
- RGMP is a project for running GPOS and RTOS simultaneously on multi-processor platforms
- You can port your favorite RTOS to RGMP together with an unmodified Linux to form a hybrid operating system.
- This makes your application able to use both RTOS and GPOS features.
-
-
- See the RGMP Wiki for further information about RGMP.
-
-
-
- STATUS:
- This initial port of NuttX to RGMP was provided in NuttX-6.3.
- This initial RGP port provides only minimal driver support and does not use the native NuttX interrupt system.
- This is a great, stable starting point for anyone interest in working with NuttX under RGMP!
- Refer to the NuttX README file for further information.
-
-
- |
-
 |
diff --git a/Documentation/README.html b/Documentation/README.html
index a9577df8ce9..3ded166a0af 100644
--- a/Documentation/README.html
+++ b/Documentation/README.html
@@ -8,7 +8,7 @@
|
NuttX README Files
- Last Updated: November 14, 2016
+ Last Updated: December 4, 2016
|
@@ -203,8 +203,6 @@ nuttx/
| | `- README.txt
| |- qemu-i486/
| | `- README.txt
- | |- rgmp/
- | | `- README.txt
| |- sabre-6quad/
| | `- README.txt
| |- sama5d2-xult/
@@ -223,6 +221,8 @@ nuttx/
| | `- README.txt
| |- sam3u-ek/
| | `- README.txt
+ | |- sam4cmp-db
+ | | `- README.txt
| |- sam4e-ek/
| | `- README.txt
| |- sam4l-xplained/
diff --git a/README.txt b/README.txt
index 3a673b7e9a8..ee43ef25cc3 100644
--- a/README.txt
+++ b/README.txt
@@ -1419,8 +1419,6 @@ nuttx/
| | `- README.txt
| |- qemu-i486/
| | `- README.txt
- | |- rgmp/
- | | `- README.txt
| |- sabre-6quad/
| | `- README.txt
| |- sama5d2-xult/
@@ -1439,6 +1437,8 @@ nuttx/
| | `- README.txt
| |- sam3u-ek/
| | `- README.txt
+ | |- sam4cmp-db
+ | | `- README.txt
| |- sam4e-ek/
| | `- README.txt
| |- sam4l-xplained/
diff --git a/TODO b/TODO
index 366533c5348..9282df6df60 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,4 @@
-NuttX TODO List (Last updated November 22, 2016)
+NuttX TODO List (Last updated December 3, 2016)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This file summarizes known NuttX bugs, limitations, inconsistencies with
@@ -308,33 +308,33 @@ o Task/Scheduler (sched/)
o SMP
^^^
- Title: SPINLOCKS AND DATA CACHES
- Description: If spinlocks are used in a system with a data cache, then there
- may be a problem with cache coherency in some CPU architectures:
- When one CPU modifies the spinlock, the changes may not be
- visible to another CPU if it does not share the data cache.
- That would cause failure in the spinlock logic.
+ Title: SMP AND DATA CACHES
+ Description: When spinlocks, semaphores, etc. are used in an SMP system with
+ a data cache, then there may be problems with cache coherency
+ in some CPU architectures: When one CPU modifies the shared
+ object, the changes may not be visible to another CPU if it
+ does not share the data cache. That would cause failure in
+ the IPC logic.
Flushing the D-cache on writes and invalidating before a read is
- not really an option. spinlocks are normally 8-bits in size and
- cache lines are typically 32-bytes so that would have side effects
- unless the spinlocks were made to be the same size as one cache
- line.
+ not really an option. That would essentially effect every memory
+ access and there may be side-effects due to cache line sizes
+ and alignment.
- This might be doable if a write-through cache is used. Then you
- could always safely invalidate the cache line before reading the
- spinlock because there should never be any dirty cache lines in
- this case.
+ For the same reason a separate, non-cacheable memory region is
+ not an option. Essentially all data would have to go in the
+ non-cached region and you would have no benefit from the data
+ cache.
- The better option is to add compiler independent "ornamentation"
- to the spinlock so that the spinlocks are all linked together
- into a separate, non-cacheable memory regions. Because of
- region alignment and minimum region mapping sizes this could
- still be wasteful of memory. This would work in systems that
- have both data cache and either an MPU or an MMU.
- Status: Open
- Priority: High. spinlocks, and hence SMP, will not work on such systems
- without this change.
+ On ARM Cortex-A, each CPU has a separate data cache. However,
+ the MPCore's Snoop Controller Unit supports coherency among
+ the different caches. The SCU is enabled by the SCU control
+ register and each CPU participates in the SMP coherency by
+ setting the ACTLR_SMP bit in the auxiliary control register
+ (ACTLR).
+
+ Status: Closed
+ Priority: High on platforms that may have the issue.
o Memory Management (mm/)
^^^^^^^^^^^^^^^^^^^^^^^
@@ -1043,41 +1043,18 @@ o Network (net/, drivers/net)
Priority: Medium. Important on slow applications that will not accept
connections promptly.
- Title: INTERRUPT LEVEL PROCESSING IN ETHERNET DRIVERS
- Description: Too many Ethernet drivers do interrupt-level processing with
- the network stack. The network stack supports either interrupt
- level processing or normal task level processing (depending on
- CONFIG_NET_NOINTS). This is really a very bad use of CPU
- resources; All of the network stack processing should be
- modified to use a work queue (and, all use of CONFIG_NET_NOINTS=n
- should be eliminated). This applies to many Ethernet drivers:
+ Title: IPv6 REQUIRES ADDRESS FILTER SUPPORT
+ Description: IPv6 requires that the Ethernet driver support NuttX address
+ filter interfaces. Several Ethernet drivers do support there,
+ however. Others support the address filtering interfaces but
+ have never been verifed:
- ARCHITECTURE CONFIG_NET_NOINTS? ADDRESS FILTER SUPPORT?
- C5471 NO NO
- STM32 YES YES
- STM32F7 YES YES
- TIVA ----------------------- ------
- LM3S NO NO
- TM4C YES YES
- eZ80 NO NO
- Kinetis YES YES (not tested)
- LPC17xx YES YES (not tested)
- LPC43xx YES YES (not tested)
- DMxxx NIC NO NO
- PIC32 NO NO
- RGMP ??? ???
- SAM3/4 YES YES
- SAMA5D ----------------------- ------
- EMACA NO YES (not tested)
- EMACB YES YES
- GMAC NO YES (not tested)
- SAMV7 YES YES
- SIM N/A (No interrupts) NO
+ C5471, LM3X, ez80, DM0x90 NIC, PIC: Do not support address
+ filteringing.
+ Kinetis, LPC17xx, LPC43xx: Untested address filter support
- The general outline of how this might be done is included in
- drivers/net/skeleton.c
Status: Open
- Priority: Pretty high if you want a well behaved system.
+ Priority: Pretty high if you want a to use IPv6 on these platforms.
Title: UDP MULTICAST RECEPTION
Description: The logic in udp_input() expects either a single receive socket or
diff --git a/arch/Kconfig b/arch/Kconfig
index 0125994830f..1e26db617f6 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -46,12 +46,6 @@ config ARCH_MISOC
---help---
MISOC
-config ARCH_RGMP
- bool "RGMP"
- ---help---
- RTOS and GPOS on Multi-Processor (RGMP) architecture. See
- http://rgmp.sourceforge.net/wiki/index.php/Main_Page.
-
config ARCH_RENESAS
bool "Renesas"
select ARCH_NOINTC
@@ -107,7 +101,6 @@ config ARCH
default "hc" if ARCH_HC
default "mips" if ARCH_MIPS
default "misoc" if ARCH_MISOC
- default "rgmp" if ARCH_RGMP
default "renesas" if ARCH_RENESAS
default "risc-v" if ARCH_RISCV
default "sim" if ARCH_SIM
@@ -121,7 +114,6 @@ source arch/avr/Kconfig
source arch/hc/Kconfig
source arch/mips/Kconfig
source arch/misoc/Kconfig
-source arch/rgmp/Kconfig
source arch/renesas/Kconfig
source arch/risc-v/Kconfig
source arch/sim/Kconfig
diff --git a/arch/README.txt b/arch/README.txt
index 4d4fe01ec13..2e52e95ff02 100644
--- a/arch/README.txt
+++ b/arch/README.txt
@@ -222,17 +222,6 @@ arch/renesas - Support for Renesas and legacy Hitachi microcontrollers.
arch/renesas/include/m16c and arch/renesas/src/m16c
arch/renesas/include/sh1 and arch/renesas/src/sh1
-arch/rgmp
-
- RGMP stands for RTOS and GPOS on Multi-Processor. RGMP is a project
- for running GPOS and RTOS simultaneously on multi-processor platforms.
- You can port your favorite RTOS to RGMP together with an unmodified
- Linux to form a hybrid operating system. This makes your application
- able to use both RTOS and GPOS features.
-
- See http://rgmp.sourceforge.net/wiki/index.php/Main_Page for further
- information about RGMP.
-
arch/risc-v
This directory is dedicated to ports to the RISC-V family.
diff --git a/arch/rgmp/src/arm/sigentry.S b/arch/arm/include/arm/spinlock.h
similarity index 80%
rename from arch/rgmp/src/arm/sigentry.S
rename to arch/arm/include/arm/spinlock.h
index 1e413450bf6..ee3db052cf0 100644
--- a/arch/rgmp/src/arm/sigentry.S
+++ b/arch/arm/include/arm/spinlock.h
@@ -1,12 +1,8 @@
/****************************************************************************
- * arch/rgmp/src/arm/sigentry.S
+ * arch/arm/include/armv7-a/spinlock.h
*
- * Copyright (C) 2011 Yu Qiang. All rights reserved.
- * Author: Yu Qiang
- *
- * This file is a part of NuttX:
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,13 +33,7 @@
*
****************************************************************************/
- .globl up_sigentry
-up_sigentry:
- sub sp, sp, #68 @ 68 is the size of Trapframe
- mov r0, sp
- bl up_sigdeliver
- add sp, sp, #4 @ skip current_task
- pop {r0-r12, lr}
- rfefd sp!
+#ifndef __ARCH_ARM_INCLUDE_ARM_SPINLOCK_H
+#define __ARCH_ARM_INCLUDE_ARM_SPINLOCK_H
-
\ No newline at end of file
+#endif /* __ARCH_ARM_INCLUDE_ARM_SPINLOCK_H */
diff --git a/arch/rgmp/include/arm/arch/subarch/arch.h b/arch/arm/include/armv6-m/spinlock.h
similarity index 78%
rename from arch/rgmp/include/arm/arch/subarch/arch.h
rename to arch/arm/include/armv6-m/spinlock.h
index e5f3fff10f9..c1d154b3700 100644
--- a/arch/rgmp/include/arm/arch/subarch/arch.h
+++ b/arch/arm/include/armv6-m/spinlock.h
@@ -1,12 +1,8 @@
/****************************************************************************
- * arch/rgmp/include/arm/arch/subarch/arch.h
+ * arch/arm/include/armv7-a/spinlock.h
*
- * Copyright (C) 2011 Yu Qiang. All rights reserved.
- * Author: Yu Qiang
- *
- * This file is a part of NuttX:
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,22 +33,7 @@
*
****************************************************************************/
-#ifndef __RGMP_ARCH_SUBARCH_ARCH_H
-#define __RGMP_ARCH_SUBARCH_ARCH_H
+#ifndef __ARCH_ARM_INCLUDE_ARMV6_M_SPINLOCK_H
+#define __ARCH_ARM_INCLUDE_ARMV6_M_SPINLOCK_H
-#ifndef __ASSEMBLY__
-
-
-static inline void up_mdelay(uint32_t msec)
-{
-
-}
-
-static inline void up_udelay(uint32_t usec)
-{
-
-}
-
-#endif /* !__ASSEMBLY__ */
-
-#endif
+#endif /* __ARCH_ARM_INCLUDE_ARMV6_M_SPINLOCK_H */
diff --git a/arch/rgmp/include/x86/arch/subarch/arch.h b/arch/arm/include/armv7-a/spinlock.h
similarity index 63%
rename from arch/rgmp/include/x86/arch/subarch/arch.h
rename to arch/arm/include/armv7-a/spinlock.h
index b88cb34155c..f43df337b8c 100644
--- a/arch/rgmp/include/x86/arch/subarch/arch.h
+++ b/arch/arm/include/armv7-a/spinlock.h
@@ -1,12 +1,8 @@
/****************************************************************************
- * arch/rgmp/include/x86/arch/subarch/arch.h
+ * arch/arm/include/armv7-a/spinlock.h
*
- * Copyright (C) 2011 Yu Qiang. All rights reserved.
- * Author: Yu Qiang
- *
- * This file is a part of NuttX:
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,32 +33,28 @@
*
****************************************************************************/
-#ifndef __RGMP_ARCH_SUBARCH_ARCH_H
-#define __RGMP_ARCH_SUBARCH_ARCH_H
+#ifndef __ARCH_ARM_INCLUDE_ARMV7_A_SPINLOCK_H
+#define __ARCH_ARM_INCLUDE_ARMV7_A_SPINLOCK_H
-#ifndef __ASSEMBLY__
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
-#ifdef __cplusplus
-extern "C"
-{
+#include
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+/* Not a useful feature */
+
+#undef SMP_INTERCPU_NONCACHED
+
+#if defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
+ /* In SMP configurations, save spinlocks and other inter-CPU communications
+ * data in a non-cached memory region.
+ */
+
+# define SP_SECTION __attribute__((section(".nocache")))
#endif
-#include
-
-static inline void up_mdelay(uint32_t msec)
-{
- hpet_ndelay(msec*1000000);
-}
-
-static inline void up_udelay(uint32_t usec)
-{
- hpet_ndelay(usec*1000);
-}
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* !__ASSEMBLY__ */
-
-#endif
+#endif /* __ARCH_ARM_INCLUDE_ARMV7_A_SPINLOCK_H */
diff --git a/configs/misoc/include/generated/common.h b/arch/arm/include/armv7-m/spinlock.h
similarity index 76%
rename from configs/misoc/include/generated/common.h
rename to arch/arm/include/armv7-m/spinlock.h
index 38859deefab..79a06b4173f 100644
--- a/configs/misoc/include/generated/common.h
+++ b/arch/arm/include/armv7-m/spinlock.h
@@ -1,8 +1,8 @@
/****************************************************************************
- * configs/misoc/include/generated/common.h
+ * arch/arm/include/armv7-a/spinlock.h
*
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
- * Author: Ramtin Amin
+ * Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,17 +33,7 @@
*
****************************************************************************/
-#ifndef __CONFIGS_MISOC_INCLUDE_GENERATED_COMMON_H
-#define __CONFIGS_MISOC_INCLUDE_GENERATED_COMMON_H
+#ifndef __ARCH_ARM_INCLUDE_ARMV7_M_SPINLOCK_H
+#define __ARCH_ARM_INCLUDE_ARMV7_M_SPINLOCK_H
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-#ifdef __ASSEMBLER__
-# define MMPTR(x) x
-#else
-# define MMPTR(x) (*((volatile unsigned int *)(x)))
-#endif
-
-#endif /* __CONFIGS_MISOC_INCLUDE_GENERATED_COMMON_H */
+#endif /* __ARCH_ARM_INCLUDE_ARMV7_M_SPINLOCK_H */
diff --git a/arch/rgmp/src/x86/sigentry.S b/arch/arm/include/armv7-r/spinlock.h
similarity index 75%
rename from arch/rgmp/src/x86/sigentry.S
rename to arch/arm/include/armv7-r/spinlock.h
index 77214e8114a..ab7900fa733 100644
--- a/arch/rgmp/src/x86/sigentry.S
+++ b/arch/arm/include/armv7-r/spinlock.h
@@ -1,12 +1,8 @@
/****************************************************************************
- * arch/rgmp/src/x86/sigentry.S
+ * arch/arm/include/armv7-r/spinlock.h
*
- * Copyright (C) 2011 Yu Qiang. All rights reserved.
- * Author: Yu Qiang
- *
- * This file is a part of NuttX:
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,19 +33,7 @@
*
****************************************************************************/
- .globl up_sigentry
-up_sigentry:
- subl $172, %esp # 172 is the size of Trapframe without cross ring part
- pushl %esp
- movl %esp, %eax
- call up_sigdeliver
- addl $8, %esp # skip parameter and tf_curregs
- frstor 0(%esp)
- addl $108, %esp
- popal
- popl %es
- popl %ds
- addl $0x8, %esp # trapno and errcode
- iret
+#ifndef __ARCH_ARM_INCLUDE_ARMV7_R_SPINLOCK_H
+#define __ARCH_ARM_INCLUDE_ARMV7_R_SPINLOCK_H
-
\ No newline at end of file
+#endif /* __ARCH_ARM_INCLUDE_ARMV7_R_SPINLOCK_H */
diff --git a/arch/arm/include/spinlock.h b/arch/arm/include/spinlock.h
index 45f26e00065..16079cc81a3 100644
--- a/arch/arm/include/spinlock.h
+++ b/arch/arm/include/spinlock.h
@@ -44,6 +44,26 @@
# include
#endif /* __ASSEMBLY__ */
+/* Include ARM architecture-specific IRQ definitions (including register
+ * save structure and up_irq_save()/up_irq_restore() functions)
+ */
+
+#if defined(CONFIG_ARCH_CORTEXA5) || defined(CONFIG_ARCH_CORTEXA8) || \
+ defined(CONFIG_ARCH_CORTEXA9)
+# include
+#elif defined(CONFIG_ARCH_CORTEXR4) || defined(CONFIG_ARCH_CORTEXR4F) || \
+ defined(CONFIG_ARCH_CORTEXR5) || defined(CONFIG_ARCH_CORTEXR5F) || \
+ defined(CONFIG_ARCH_CORTEXR7) || defined(CONFIG_ARCH_CORTEXR7F)
+# include
+#elif defined(CONFIG_ARCH_CORTEXM3) || defined(CONFIG_ARCH_CORTEXM4) || \
+ defined(CONFIG_ARCH_CORTEXM7)
+# include
+#elif defined(CONFIG_ARCH_CORTEXM0)
+# include
+#else
+# include
+#endif
+
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
diff --git a/arch/arm/include/stm32l4/chip.h b/arch/arm/include/stm32l4/chip.h
index 12d71876406..9d0712b2768 100644
--- a/arch/arm/include/stm32l4/chip.h
+++ b/arch/arm/include/stm32l4/chip.h
@@ -77,7 +77,7 @@
# define STM32L4_NBTIM 2 /* Two basic timers, TIM6-7 */
# define STM32L4_NLPTIM 2 /* Two low-power timers, LPTIM1-2 */
# define STM32L4_NRNG 1 /* Random number generator (RNG) */
-# define STM32L4_NUART 4 /* UART 4-5 */
+# define STM32L4_NUART 2 /* UART 4-5 */
# define STM32L4_NUSART 3 /* USART 1-3 */
# define STM32L4_NLPUART 1 /* LPUART 1 */
# define STM32L4_NSPI 3 /* SPI1-3 */
diff --git a/arch/arm/src/armv7-a/arm_cpuhead.S b/arch/arm/src/armv7-a/arm_cpuhead.S
index 487fee0a46b..02735e36d50 100644
--- a/arch/arm/src/armv7-a/arm_cpuhead.S
+++ b/arch/arm/src/armv7-a/arm_cpuhead.S
@@ -308,7 +308,11 @@ __cpu3_start:
orr r0, r0, #(SCTLR_RR)
#endif
-#ifndef CPU_DCACHE_DISABLE
+ /* In SMP configurations, the data cache will not be enabled until later
+ * after SMP cache coherency has been setup.
+ */
+
+#if 0 /* !defined(CPU_DCACHE_DISABLE) && !defined(CONFIG_SMP) */
/* Dcache enable
*
* SCTLR_C Bit 2: DCache enable
diff --git a/arch/arm/src/armv7-a/arm_cpupause.c b/arch/arm/src/armv7-a/arm_cpupause.c
index 1b5726aba9e..ef324448e22 100644
--- a/arch/arm/src/armv7-a/arm_cpupause.c
+++ b/arch/arm/src/armv7-a/arm_cpupause.c
@@ -44,6 +44,7 @@
#include
#include
#include
+#include
#include "up_internal.h"
#include "gic.h"
@@ -69,8 +70,8 @@
* so that it will be ready for the next pause operation.
*/
-static volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS];
-static volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS];
+static volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS] SP_SECTION;
+static volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS] SP_SECTION;
/****************************************************************************
* Public Functions
@@ -131,23 +132,42 @@ int up_cpu_paused(int cpu)
sched_suspend_scheduler(tcb);
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+ /* Notify that we are paused */
+
+ sched_note_cpu_paused(tcb);
+#endif
+
/* Save the current context at CURRENT_REGS into the TCB at the head
* of the assigned task list for this CPU.
*/
up_savestate(tcb->xcp.regs);
- /* Wait for the spinlock to be released */
+ /* Release the g_cpu_puased spinlock to synchronize with the
+ * requesting CPU.
+ */
spin_unlock(&g_cpu_paused[cpu]);
+
+ /* Wait for the spinlock to be released. The requesting CPU will release
+ * the spinlcok when the CPU is resumed.
+ */
+
spin_lock(&g_cpu_wait[cpu]);
- /* Restore the exception context of the tcb at the (new) head of the
- * assigned task list.
+ /* This CPU has been resumed. Restore the exception context of the TCB at
+ * the (new) head of the assigned task list.
*/
tcb = this_task();
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+ /* Notify that we have resumed */
+
+ sched_note_cpu_resumed(tcb);
+#endif
+
/* Reset scheduler parameters */
sched_resume_scheduler(tcb);
@@ -224,6 +244,12 @@ int up_cpu_pause(int cpu)
{
int ret;
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+ /* Notify of the pause event */
+
+ sched_note_cpu_pause(this_task(), cpu);
+#endif
+
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
/* Take the both spinlocks. The g_cpu_wait spinlock will prevent the SGI2
@@ -287,6 +313,12 @@ int up_cpu_pause(int cpu)
int up_cpu_resume(int cpu)
{
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+ /* Notify of the resume event */
+
+ sched_note_cpu_resume(this_task(), cpu);
+#endif
+
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
/* Release the spinlock. Releasing the spinlock will cause the SGI2
diff --git a/arch/arm/src/armv7-a/arm_cpustart.c b/arch/arm/src/armv7-a/arm_cpustart.c
index 88906a717de..d63c035db68 100644
--- a/arch/arm/src/armv7-a/arm_cpustart.c
+++ b/arch/arm/src/armv7-a/arm_cpustart.c
@@ -43,10 +43,11 @@
#include
#include
+#include
#include "up_internal.h"
-#include "gic.h"
#include "cp15_cacheops.h"
+#include "gic.h"
#include "sched/sched.h"
#ifdef CONFIG_SMP
@@ -104,13 +105,18 @@ static inline void arm_registerdump(FAR struct tcb_s *tcb)
int arm_start_handler(int irq, FAR void *context)
{
- FAR struct tcb_s *tcb;
+ FAR struct tcb_s *tcb = this_task();
- sinfo("CPU%d Started\n", up_cpu_index());
+ sinfo("CPU%d Started\n", this_cpu());
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+ /* Notify that this CPU has started */
+
+ sched_note_cpu_started(tcb);
+#endif
/* Reset scheduler parameters */
- tcb = this_task();
sched_resume_scheduler(tcb);
/* Dump registers so that we can see what is going to happen on return */
@@ -159,6 +165,12 @@ int up_cpu_start(int cpu)
DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+ /* Notify of the start event */
+
+ sched_note_cpu_start(this_task(), cpu);
+#endif
+
/* Make the content of CPU0 L1 cache has been written to coherent L2 */
cp15_clean_dcache(CONFIG_RAM_START, CONFIG_RAM_END - 1);
diff --git a/arch/arm/src/armv7-a/arm_doirq.c b/arch/arm/src/armv7-a/arm_doirq.c
index b3d98151c0b..fa3e1045823 100644
--- a/arch/arm/src/armv7-a/arm_doirq.c
+++ b/arch/arm/src/armv7-a/arm_doirq.c
@@ -40,10 +40,10 @@
#include
#include
-#include
-#include
#include
+#include
+#include
#include
#include
@@ -51,21 +51,40 @@
#include "up_internal.h"
#include "group/group.h"
+#include "gic.h"
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* A bit set of pending, non-maskable SGI interrupts, on bit set for each
+ * supported CPU.
+ */
+
+#ifdef CONFIG_ARMV7A_HAVE_GICv2
+#ifdef CONFIG_SMP
+static uint16_t g_sgi_pending[CONFIG_SMP_NCPUS];
+#else
+static uint16_t g_sgi_pending[1];
+#endif
+#endif
/****************************************************************************
* Public Functions
****************************************************************************/
-uint32_t *arm_doirq(int irq, uint32_t *regs)
+/****************************************************************************
+ * Name: _arm_doirq
+ *
+ * Description:
+ * Receives the one decoded interrupt and dispatches control to the
+ * attached interrupt handler.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SUPPRESS_INTERRUPTS
+static inline uint32_t *_arm_doirq(int irq, uint32_t *regs)
{
- board_autoled_on(LED_INIRQ);
-#ifdef CONFIG_SUPPRESS_INTERRUPTS
- PANIC();
-#else
- /* Nested interrupts are not supported */
-
- DEBUGASSERT(CURRENT_REGS == NULL);
-
/* Current regs non-zero indicates that we are processing an interrupt;
* CURRENT_REGS is also used to manage interrupt level context switches.
*/
@@ -110,8 +129,131 @@ uint32_t *arm_doirq(int irq, uint32_t *regs)
regs = (uint32_t *)CURRENT_REGS;
CURRENT_REGS = NULL;
+
+ return regs;
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_doirq
+ *
+ * Description:
+ * Receives the decoded GIC interrupt information and dispatches control
+ * to the attached interrupt handler. There are two versions:
+ *
+ * 1) For the simple case where all interrupts are maskable. In that
+ * simple case, arm_doirq() is simply a wrapper for the inlined
+ * _arm_do_irq() that does the real work.
+ *
+ * 2) With the GICv2, there are 16 non-maskable software generated
+ * interrupts (SGIs) that also come through arm_doirq(). In that case,
+ * we must avoid nesting interrupt handling and serial the processing.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_ARMV7A_HAVE_GICv2
+uint32_t *arm_doirq(int irq, uint32_t *regs)
+{
+ board_autoled_on(LED_INIRQ);
+#ifdef CONFIG_SUPPRESS_INTERRUPTS
+ PANIC();
+#else
+ /* Nested interrupts are not supported */
+
+ DEBUGASSERT(CURRENT_REGS == NULL);
+
+ /* Dispatch the interrupt to its attached handler */
+
+ regs = _arm_doirq(irq, regs);
#endif
board_autoled_off(LED_INIRQ);
return regs;
}
+#endif
+
+#ifdef CONFIG_ARMV7A_HAVE_GICv2
+uint32_t *arm_doirq(int irq, uint32_t *regs)
+{
+#ifndef CONFIG_SUPPRESS_INTERRUPTS
+ uint32_t bit;
+ int cpu;
+ int i;
+#endif
+
+ board_autoled_on(LED_INIRQ);
+#ifdef CONFIG_SUPPRESS_INTERRUPTS
+ PANIC();
+
+#else
+ /* Get the CPU processing the interrupt */
+
+#ifdef CONFIG_SMP
+ cpu = up_cpu_index();
+#else
+ cpu = 0;
+#endif
+
+ /* Non-zero CURRENT_REGS indicates that we are already processing an
+ * interrupt. This could be a normal event for the case of the GICv2;
+ * Software generated interrupts are non-maskable.
+ *
+ * REVISIT: There is no support for nested SGIs! That will cause an
+ * assertion below. There is also no protection for concurrent access
+ * to g_sgi_pending for that case.
+ */
+
+ if (CURRENT_REGS != NULL)
+ {
+ int ndx = irq - GIC_IRQ_SGI0;
+ bit = (1 << (ndx));
+
+ /* Only an SGI should cause this event. We also cannot support
+ * multiple pending SGI interrupts.
+ */
+
+ ASSERT((unsigned int)irq <= GIC_IRQ_SGI15 &&
+ (g_sgi_pending[cpu] & bit) == 0);
+
+ /* Mare the SGI as pending and return immediately */
+
+ sinfo("SGI%d pending\n", ndx);
+ g_sgi_pending[cpu] |= bit;
+ return regs;
+ }
+
+ /* Dispatch the interrupt to its attached handler */
+
+ regs = _arm_doirq(irq, regs);
+
+ /* Then loop dispatching any pending SGI interrupts that occcurred during
+ * processing of the interrupts.
+ */
+
+ for (i = 0; i < 16 && g_sgi_pending[cpu] != 0; i++)
+ {
+ /* Check if this SGI is pending */
+
+ bit = (1 << i);
+ if ((g_sgi_pending[cpu] & bit) != 0)
+ {
+ /* Clear the pending bit */
+
+ g_sgi_pending[cpu] &= ~bit;
+
+ /* And dispatch the SGI */
+
+ sinfo("Dispatching pending SGI%d\n", i + GIC_IRQ_SGI0);
+ regs = _arm_doirq(i + GIC_IRQ_SGI0, regs);
+ }
+ }
+#endif
+
+ board_autoled_off(LED_INIRQ);
+ return regs;
+}
+#endif
diff --git a/arch/arm/src/armv7-a/arm_gicv2.c b/arch/arm/src/armv7-a/arm_gicv2.c
index e99eb540fde..dce0b621ed9 100644
--- a/arch/arm/src/armv7-a/arm_gicv2.c
+++ b/arch/arm/src/armv7-a/arm_gicv2.c
@@ -122,7 +122,7 @@ void arm_gic0_initialize(void)
}
#ifdef CONFIG_SMP
- /* Attach SGI interrupt handlers */
+ /* Attach SGI interrupt handlers. This attaches the handler for all CPUs. */
DEBUGVERIFY(irq_attach(GIC_IRQ_SGI1, arm_start_handler));
DEBUGVERIFY(irq_attach(GIC_IRQ_SGI2, arm_pause_handler));
@@ -574,5 +574,4 @@ int arm_gic_irq_trigger(int irq, bool edge)
return -EINVAL;
}
-
#endif /* CONFIG_ARMV7A_HAVE_GICv2 */
diff --git a/arch/arm/src/armv7-a/arm_head.S b/arch/arm/src/armv7-a/arm_head.S
index c98ab30719d..27c2a5b4dcf 100644
--- a/arch/arm/src/armv7-a/arm_head.S
+++ b/arch/arm/src/armv7-a/arm_head.S
@@ -450,7 +450,11 @@ __start:
orr r0, r0, #(SCTLR_RR)
#endif
-#ifndef CPU_DCACHE_DISABLE
+ /* In SMP configurations, the data cache will not be enabled until later
+ * after SMP cache coherency has been setup.
+ */
+
+#if !defined(CPU_DCACHE_DISABLE) && !defined(CONFIG_SMP)
/* Dcache enable
*
* SCTLR_C Bit 2: DCache enable
@@ -638,7 +642,7 @@ __start:
#endif
/* Perform early C-level, platform-specific initialization. Logic
- * within arm_boot() must configure SDRAM and call arm_ram_initailize.
+ * within arm_boot() must configure SDRAM and call arm_data_initialize().
*/
bl arm_boot
diff --git a/arch/arm/src/armv7-a/arm_pghead.S b/arch/arm/src/armv7-a/arm_pghead.S
index 1a546c813d4..1dda0acdd92 100644
--- a/arch/arm/src/armv7-a/arm_pghead.S
+++ b/arch/arm/src/armv7-a/arm_pghead.S
@@ -434,7 +434,11 @@ __start:
orr r0, r0, #(SCTLR_RR)
#endif
-#ifndef CPU_DCACHE_DISABLE
+ /* In SMP configurations, the data cache will not be enabled until later
+ * after SMP cache coherency has been setup.
+ */
+
+#if !defined(CPU_DCACHE_DISABLE) && !defined(CONFIG_SMP)
/* Dcache enable
*
* SCTLR_C Bit 2: DCache enable
@@ -670,7 +674,7 @@ __start:
#endif
/* Perform early C-level, platform-specific initialization. Logic
- * within arm_boot() must configure SDRAM and call arm_ram_initailize.
+ * within arm_boot() must configure SDRAM and call arm_data_initialize().
*/
bl arm_boot
diff --git a/arch/arm/src/armv7-a/arm_scu.c b/arch/arm/src/armv7-a/arm_scu.c
new file mode 100644
index 00000000000..eedf179e731
--- /dev/null
+++ b/arch/arm/src/armv7-a/arm_scu.c
@@ -0,0 +1,227 @@
+/****************************************************************************
+ * arch/arm/src/armv7-a/arm_scu.c
+ *
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+
+#include "up_arch.h"
+#include "cp15_cacheops.h"
+#include "sctlr.h"
+#include "cache.h"
+#include "scu.h"
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_get_sctlr
+ *
+ * Description:
+ * Get the contents of the SCTLR register
+ *
+ ****************************************************************************/
+
+static inline uint32_t arm_get_sctlr(void)
+{
+ uint32_t sctlr;
+
+ __asm__ __volatile__
+ (
+ "\tmrc p15, 0, %0, c1, c0, 0\n" /* Read SCTLR */
+ : "=r"(sctlr)
+ :
+ :
+ );
+
+ return sctlr;
+}
+
+/****************************************************************************
+ * Name: arm_set_sctlr
+ *
+ * Description:
+ * Set the contents of the SCTLR register
+ *
+ ****************************************************************************/
+
+static inline void arm_set_sctlr(uint32_t sctlr)
+{
+ __asm__ __volatile__
+ (
+ "\tmcr p15, 0, %0, c1, c0, 0\n" /* Write SCTLR */
+ :
+ : "r"(sctlr)
+ :
+ );
+}
+
+/****************************************************************************
+ * Name: arm_get_actlr
+ *
+ * Description:
+ * Get the contents of the ACTLR register
+ *
+ ****************************************************************************/
+
+static inline uint32_t arm_get_actlr(void)
+{
+ uint32_t actlr;
+
+ __asm__ __volatile__
+ (
+ "\tmrc p15, 0, %0, c1, c0, 1\n" /* Read ACTLR */
+ : "=r"(actlr)
+ :
+ :
+ );
+
+ return actlr;
+}
+
+/****************************************************************************
+ * Name: arm_set_actlr
+ *
+ * Description:
+ * Set the contents of the ACTLR register
+ *
+ ****************************************************************************/
+
+static inline void arm_set_actlr(uint32_t actlr)
+{
+ __asm__ __volatile__
+ (
+ "\tmcr p15, 0, %0, c1, c0, 1\n" /* Write ACTLR */
+ :
+ : "r"(actlr)
+ :
+ );
+}
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_enable_smp
+ *
+ * Description:
+ * Enable the SCU and make certain that current CPU is participating in
+ * the SMP cache coherency.
+ *
+ * Assumption:
+ * Called early in the CPU start-up. No special critical sections are
+ * needed if only CPU-private registers are modified.
+ *
+ ****************************************************************************/
+
+void arm_enable_smp(int cpu)
+{
+ uint32_t regval;
+
+ /* Handle actions unique to CPU0 which comes up first */
+
+ if (cpu == 0)
+ {
+ /* Invalidate the SCU duplicate tags for all processors */
+
+ putreg32((SCU_INVALIDATE_ALL_WAYS << SCU_INVALIDATE_CPU0_SHIFT) |
+ (SCU_INVALIDATE_ALL_WAYS << SCU_INVALIDATE_CPU1_SHIFT) |
+ (SCU_INVALIDATE_ALL_WAYS << SCU_INVALIDATE_CPU2_SHIFT) |
+ (SCU_INVALIDATE_ALL_WAYS << SCU_INVALIDATE_CPU3_SHIFT),
+ SCU_INVALIDATE);
+
+ /* Invalidate CPUn L1 data cache so that is will we be reloaded from
+ * coherent L2.
+ */
+
+ cp15_invalidate_dcache_all();
+ ARM_DSB();
+
+ /* Invalidate the L2C-310 -- Missing logic. */
+
+ /* Enable the SCU */
+
+ regval = getreg32(SCU_CTRL);
+ regval |= SCU_CTRL_ENABLE;
+ putreg32(regval, SCU_CTRL);
+ }
+
+ /* Actions for other CPUs */
+
+ else
+ {
+ /* Invalidate CPUn L1 data cache so that is will we be reloaded from
+ * coherent L2.
+ */
+
+ cp15_invalidate_dcache_all();
+ ARM_DSB();
+
+ /* Wait for the SCU to be enabled by the primary processor -- should
+ * not be necessary.
+ */
+ }
+
+ /* Enable the data cache, set the SMP mode with ACTLR.SMP=1.
+ *
+ * SMP - Sgnals if the Cortex-A9 processor is taking part in coherency
+ * or not.
+ *
+ * Cortex-A9 also needs ACTLR.FW=1
+ *
+ * FW - Cache and TLB maintenance broadcast.
+ */
+
+ regval = arm_get_actlr();
+ regval |= ACTLR_SMP;
+#ifdef CONFIG_ARCH_CORTEXA9
+ regval |= ACTLR_FW;
+#endif
+ arm_set_actlr(regval);
+
+ regval = arm_get_sctlr();
+ regval |= SCTLR_C;
+ arm_set_sctlr(regval);
+}
+
+#endif
diff --git a/arch/arm/src/armv7-a/cache.h b/arch/arm/src/armv7-a/cache.h
index dda36271e2d..c9af0611f7b 100644
--- a/arch/arm/src/armv7-a/cache.h
+++ b/arch/arm/src/armv7-a/cache.h
@@ -50,6 +50,16 @@
* Pre-processor Definitions
************************************************************************************/
+/* Intrinsics are used in these inline functions */
+
+#define arm_isb(n) __asm__ __volatile__ ("isb " #n : : : "memory")
+#define arm_dsb(n) __asm__ __volatile__ ("dsb " #n : : : "memory")
+#define arm_dmb(n) __asm__ __volatile__ ("dmb " #n : : : "memory")
+
+#define ARM_DSB() arm_dsb(15)
+#define ARM_ISB() arm_isb(15)
+#define ARM_DMB() arm_dmb(15)
+
/************************************************************************************
* Inline Functions
************************************************************************************/
diff --git a/arch/arm/src/armv7-a/mmu.h b/arch/arm/src/armv7-a/mmu.h
index c84deda6194..64406572420 100644
--- a/arch/arm/src/armv7-a/mmu.h
+++ b/arch/arm/src/armv7-a/mmu.h
@@ -601,11 +601,13 @@
#define MMU_L2_PGTABFLAGS (PTE_TYPE_SMALL | PTE_WRITE_THROUGH | PTE_AP_RW1)
#define MMU_L1_VECTORFLAGS (PMD_TYPE_PTE | PMD_PTE_PXN | PMD_PTE_DOM(0))
-
#define MMU_L2_VECTRWFLAGS (PTE_TYPE_SMALL | PTE_WRITE_THROUGH | PTE_AP_RW1)
#define MMU_L2_VECTROFLAGS (PTE_TYPE_SMALL | PTE_WRITE_THROUGH | PTE_AP_R1)
#define MMU_L2_VECTORFLAGS MMU_L2_VECTRWFLAGS
+#define MMU_L1_INTERCPUFLAGS (PMD_TYPE_PTE | PMD_PTE_PXN | PMD_PTE_DOM(0))
+#define MMU_L2_INTERCPUFLAGS (PTE_TYPE_SMALL | PTE_DEVICE | PTE_AP_RW1)
+
/* Mapped section size */
#define SECTION_SHIFT (20)
@@ -1423,6 +1425,28 @@ void mmu_l1_restore(uintptr_t vaddr, uint32_t l1entry);
# define mmu_l1_clrentry(v) mmu_l1_restore(v,0)
#endif
+/****************************************************************************
+ * Name: mmu_l2_setentry
+ *
+ * Description:
+ * Set one small (4096B) entry in a level2 translation table.
+ *
+ * Input Parameters:
+ * l2vaddr - the virtual address of the beginning of the L2 translation
+ * table.
+ * paddr - The physical address to be mapped. Must be aligned to a 4KB
+ * address boundary
+ * vaddr - The virtual address to be mapped. Must be aligned to a 4KB
+ * address boundary
+ * mmuflags - The MMU flags to use in the mapping.
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_ARCH_ROMPGTABLE
+void mmu_l2_setentry(uint32_t l2vaddr, uint32_t paddr, uint32_t vaddr,
+ uint32_t mmuflags);
+#endif
+
/************************************************************************************
* Name: mmu_l1_map_region
*
diff --git a/arch/arm/src/armv7-a/scu.h b/arch/arm/src/armv7-a/scu.h
new file mode 100644
index 00000000000..a84fb0cc4f8
--- /dev/null
+++ b/arch/arm/src/armv7-a/scu.h
@@ -0,0 +1,176 @@
+/****************************************************************************
+ * arch/arm/src/armv7-a/scu.h
+ * Generic Interrupt Controller Definitions
+ *
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Reference:
+ * Cortex™-A9 MPCore, Revision: r4p1, Technical Reference Manual, ARM DDI
+ * 0407I (ID091612).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+#ifndef __ARCH_ARM_SRC_ARMV7_A_SCU_H
+#define __ARCH_ARM_SRC_ARMV7_A_SCU_H
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include "mpcore.h" /* For MPCORE_SCU_VBASE */
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* Register offsets *********************************************************/
+
+#define SCU_CTRL_OFFSET 0x0000 /* SCU Control Register (Implementation defined) */
+#define SCU_CONFIG_OFFSET 0x0004 /* SCU Configuration Register (Implementation defined) */
+#define SCU_PWRSTATUS_OFFSET 0x0008 /* SCU CPU Power Status Register */
+#define SCU_INVALIDATE_OFFSET 0x000c /* SCU Invalidate All Registers in Secure State */
+#define SCU_FILTERSTART_OFFSET 0x0040 /* Filtering Start Address Register Defined by FILTERSTART input */
+#define SCU_FILTEREND_OFFSET 0x0044 /* Filtering End Address Register Defined by FILTEREND input */
+#define SCU_SAC_OFFSET 0x0050 /* SCU Access Control (SAC) Register */
+#define SCU_SNSAC_OFFSET 0x0054 /* SCU Non-secure Access Control (SNSAC) Register */
+
+/* Register addresses *******************************************************/
+
+#define SCU_CTRL (MPCORE_SCU_VBASE+SCU_CTRL_OFFSET)
+#define SCU_CONFIG (MPCORE_SCU_VBASE+SCU_CONFIG_OFFSET)
+#define SCU_PWRSTATUS (MPCORE_SCU_VBASE+SCU_PWRSTATUS_OFFSET)
+#define SCU_INVALIDATE (MPCORE_SCU_VBASE+SCU_INVALIDATE_OFFSET)
+#define SCU_FILTERSTART (MPCORE_SCU_VBASE+SCU_FILTERSTART_OFFSET)
+#define SCU_FILTEREND (MPCORE_SCU_VBASE+SCU_FILTEREND_OFFSET)
+#define SCU_SAC (MPCORE_SCU_VBASE+SCU_SAC_OFFSET)
+#define SCU_SNSAC (MPCORE_SCU_VBASE+SCU_SNSAC_OFFSET)
+
+/* Register bit-field definitions *******************************************/
+
+/* SCU Control Register (Implementation defined) */
+
+#define SCU_CTRL_ENABLE (1 << 0) /* SCU enable */
+#define SCU_CTRL_ADDRFILTER (1 << 1) /* Address filtering enable */
+#define SCU_CTRL_RAMPARITY (1 << 2) /* SCU RAMs parity enable */
+#define SCU_CTRL_LINFILL (1 << 3) /* SCU speculative linefill enable */
+#define SCU_CTRL_PORT0 (1 << 4) /* Force all device to port0 enable */
+#define SCU_CTRL_STANDBY (1 << 5) /* SCU standby enable */
+#define SCU_CTRL_ICSTANDBY (1 << 6) /* IC standby enable */
+
+/* SCU Configuration Register (Implementation defined) */
+
+#define SCU_CONFIG_NCPUS_SHIFT 0 /* CPU number Number of CPUs present */
+#define SCU_CONFIG_NCPUS_MASK (3 << SCU_CONFIG_NCPUS_SHIFT)
+# define SCU_CONFIG_NCPUS(r) ((((uint32_t)(r) & SCU_CONFIG_NCPUS_MASK) >> SCU_CONFIG_NCPUS_SHIFT) + 1)
+#define SCU_CONFIG_SMPCPUS_SHIFT 4 /* Processors that are in SMP or AMP mode */
+#define SCU_CONFIG_SMPCPUS_MASK (15 << SCU_CONFIG_SMPCPUS_SHIFT)
+# define SCU_CONFIG_CPU_SMP(n) (1 << ((n)+4))
+# define SCU_CONFIG_CPU0_SMP (1 << 4)
+# define SCU_CONFIG_CPU1_SMP (1 << 5)
+# define SCU_CONFIG_CPU2_SMP (1 << 6)
+# define SCU_CONFIG_CPU3_SMP (1 << 7)
+
+#define SCU_CONFIG_TAGRAM_16KB 0
+#define SCU_CONFIG_TAGRAM_32KB 1
+#define SCU_CONFIG_TAGRAM_64KB 2
+
+#define SCU_CONFIG_CPU0_TAGRAM_SHIFT 8 /* CPU 0 tag RAM size */
+#define SCU_CONFIG_CPU0_TAGRAM_MASK (3 << SCU_CONFIG_CPU0_TAGRAM_SHIFT)
+#define SCU_CONFIG_CPU1_TAGRAM_SHIFT 10 /* CPU 1 tag RAM size */
+#define SCU_CONFIG_CPU1_TAGRAM_MASK (3 << SCU_CONFIG_CPU0_TAGRAM_SHIFT)
+#define SCU_CONFIG_CPU2_TAGRAM_SHIFT 12 /* CPU 1 tag RAM size */
+#define SCU_CONFIG_CPU2_TAGRAM_MASK (3 << SCU_CONFIG_CPU0_TAGRAM_SHIFT)
+#define SCU_CONFIG_CPU3_TAGRAM_SHIFT 14 /* CPU 1 tag RAM size */
+#define SCU_CONFIG_CPU3_TAGRAM_MASK (3 << SCU_CONFIG_CPU0_TAGRAM_SHIFT)
+
+/* SCU CPU Power Status Register */
+
+#define SCU_PWRSTATUS_NORMAL 0
+#define SCU_PWRSTATUS_DORMANT 2
+#define SCU_PWRSTATUS_PWROFF 3
+
+#define SCU_PWRSTATUS_CPU0_SHIFT 0 /* CPU0 status Power status */
+#define SCU_PWRSTATUS_CPU0_MASK (3 << SCU_PWRSTATUS_CPU0_SHIFT)
+#define SCU_PWRSTATUS_CPU1_SHIFT 8 /* CPU1 status Power status */
+#define SCU_PWRSTATUS_CPU1_MASK (3 << SCU_PWRSTATUS_CPU1_SHIFT)
+#define SCU_PWRSTATUS_CPU2_SHIFT 16 /* CPU2 status Power status */
+#define SCU_PWRSTATUS_CPU2_MASK (3 << SCU_PWRSTATUS_CPU2_SHIFT)
+#define SCU_PWRSTATUS_CPU3_SHIFT 24 /* CPU3 status Power status */
+#define SCU_PWRSTATUS_CPU3_MASK (3 << SCU_PWRSTATUS_CPU3_SHIFT)
+
+/* SCU Invalidate All Registers in Secure State */
+
+#define SCU_INVALIDATE_ALL_WAYS 15
+#define SCU_INVALIDATE_CPU0_SHIFT 0 /* Ways that must be invalidated for CPU0 */
+#define SCU_INVALIDATE_CPU0_MASK (15 << SCU_INVALIDATE_CPU0_SHIFT)
+#define SCU_INVALIDATE_CPU1_SHIFT 4 /* Ways that must be invalidated for CPU1 */
+#define SCU_INVALIDATE_CPU1_MASK (15 << SCU_INVALIDATE_CPU1_SHIFT)
+#define SCU_INVALIDATE_CPU2_SHIFT 8 /* Ways that must be invalidated for CPU2 */
+#define SCU_INVALIDATE_CPU2_MASK (15 << SCU_INVALIDATE_CPU2_SHIFT)
+#define SCU_INVALIDATE_CPU3_SHIFT 12 /* Ways that must be invalidated for CPU3 */
+#define SCU_INVALIDATE_CPU3_MASK (15 << SCU_INVALIDATE_CPU3_SHIFT)
+
+/* Filtering Start Address Register Defined by FILTERSTART input */
+
+#define SCU_FILTERSTART_SHIFT 10 /* Filtering start address */
+#define SCU_FILTERSTART_MASK (0xfff << SCU_FILTERSTART_SHIFT)
+
+/* Filtering End Address Register Defined by FILTEREND input */
+
+#define SCU_FILTEREND_SHIFT 10 /* Filtering start address */
+#define SCU_FILTEREND_MASK (0xfff << SCU_FILTEREND_SHIFT)
+
+/* SCU Access Control (SAC) Register */
+
+#define SCU_SAC_CPU(n) (1 << (n)) /* CPUn may access components */
+
+/* SCU Non-secure Access Control (SNSAC) Register */
+
+#define SCU_SNSAC_COMP_CPU(n) (1 << (n)) /* CPUn has non-secure access to components */
+#define SCU_SNSAC_PTIM_CPU(n) (1 << ((n)+4)) /* CPUn has non-secure access to private timers */
+#define SCU_SNSAC_GTIM_CPU(n) (1 << ((n)+8)) /* CPUn has non-secure access to global timer */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: arm_enable_smp
+ *
+ * Description:
+ * Enable the SCU and make certain that current CPU is participating in
+ * the SMP cache coherency.
+ *
+ ****************************************************************************/
+
+void arm_enable_smp(int cpu);
+
+#endif /* __ARCH_ARM_SRC_ARMV7_A_SCU_H */
diff --git a/arch/arm/src/armv7-m/up_assert.c b/arch/arm/src/armv7-m/up_assert.c
index b34cfc73950..11f29cd6534 100644
--- a/arch/arm/src/armv7-m/up_assert.c
+++ b/arch/arm/src/armv7-m/up_assert.c
@@ -53,6 +53,7 @@
#include "up_arch.h"
#include "sched/sched.h"
+#include "irq/irq.h"
#include "up_internal.h"
/****************************************************************************
@@ -319,6 +320,12 @@ static void up_dumpstate(void)
#endif
+#ifdef CONFIG_SMP
+ /* Show the CPU number */
+
+ _alert("CPU%d:\n", up_cpu_index());
+#endif
+
/* Then dump the registers (if available) */
up_registerdump();
@@ -351,6 +358,12 @@ static void _up_assert(int errorcode)
(void)up_irq_save();
for (; ; )
{
+#ifdef CONFIG_SMP
+ /* Try (again) to stop activity on other CPUs */
+
+ (void)spin_trylock(&g_cpu_irqlock);
+#endif
+
#ifdef CONFIG_ARCH_LEDS
board_autoled_on(LED_PANIC);
up_mdelay(250);
diff --git a/arch/arm/src/armv7-m/up_schedulesigaction.c b/arch/arm/src/armv7-m/up_schedulesigaction.c
index cf70662510c..fb6a4c167c6 100644
--- a/arch/arm/src/armv7-m/up_schedulesigaction.c
+++ b/arch/arm/src/armv7-m/up_schedulesigaction.c
@@ -165,6 +165,19 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#ifdef CONFIG_BUILD_PROTECTED
CURRENT_REGS[REG_LR] = EXC_RETURN_PRIVTHR;
#endif
+
+#ifdef CONFIG_SMP
+ /* In an SMP configuration, the interrupt disable logic also
+ * involves spinlocks that are configured per the TCB irqcount
+ * field. This is logically equivalent to enter_critical_section().
+ * The matching call to leave_critical_section() will be
+ * performed in up_sigdeliver().
+ */
+
+ DEBUGASSERT(tcb->irqcount < INT16_MAX);
+ tcb->irqcount++;
+#endif
+
/* And make sure that the saved context in the TCB is the same
* as the interrupt return context.
*/
@@ -211,6 +224,19 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
#ifdef CONFIG_BUILD_PROTECTED
tcb->xcp.regs[REG_LR] = EXC_RETURN_PRIVTHR;
#endif
+
+#ifdef CONFIG_SMP
+ /* In an SMP configuration, the interrupt disable logic also
+ * involves spinlocks that are configured per the TCB irqcount
+ * field. This is logically equivalent to enter_critical_section();
+ * The matching leave_critical_section will be performed in
+ * The matching call to leave_critical_section() will be performed
+ * in up_sigdeliver().
+ */
+
+ DEBUGASSERT(tcb->irqcount < INT16_MAX);
+ tcb->irqcount++;
+#endif
}
}
diff --git a/arch/arm/src/armv7-m/up_sigdeliver.c b/arch/arm/src/armv7-m/up_sigdeliver.c
index 6169b512796..086ed882fce 100644
--- a/arch/arm/src/armv7-m/up_sigdeliver.c
+++ b/arch/arm/src/armv7-m/up_sigdeliver.c
@@ -124,9 +124,9 @@ void up_sigdeliver(void)
/* Then restore the task interrupt state */
#ifdef CONFIG_ARMV7M_USEBASEPRI
- up_irq_restore((uint8_t)regs[REG_BASEPRI]);
+ leave_critical_section((uint8_t)regs[REG_BASEPRI]);
#else
- up_irq_restore((uint16_t)regs[REG_PRIMASK]);
+ leave_critical_section((uint16_t)regs[REG_PRIMASK]);
#endif
/* Deliver the signal */
@@ -136,9 +136,18 @@ void up_sigdeliver(void)
/* Output any debug messages BEFORE restoring errno (because they may
* alter errno), then disable interrupts again and restore the original
* errno that is needed by the user logic (it is probably EINTR).
+ *
+ * REVISIT: In SMP mode up_irq_save() probably only disables interrupts
+ * on the local CPU. We do not want to call enter_critical_section()
+ * here, however, because we don't want this state to stick after the
+ * call to up_fullcontextrestore().
+ *
+ * I would prefer that all interrupts are disabled when
+ * up_fullcontextrestore() is called, but that may not be necessary.
*/
sinfo("Resuming\n");
+
(void)up_irq_save();
rtcb->pterrno = saved_errno;
diff --git a/arch/arm/src/armv7-r/cache.h b/arch/arm/src/armv7-r/cache.h
index a0d25c89410..721f40313f2 100644
--- a/arch/arm/src/armv7-r/cache.h
+++ b/arch/arm/src/armv7-r/cache.h
@@ -51,7 +51,7 @@
* Pre-processor Definitions
************************************************************************************/
-/* intrinsics are used in these inline functions */
+/* Intrinsics are used in these inline functions */
#define arm_isb(n) __asm__ __volatile__ ("isb " #n : : : "memory")
#define arm_dsb(n) __asm__ __volatile__ ("dsb " #n : : : "memory")
@@ -61,7 +61,7 @@
#define ARM_ISB() arm_isb(15)
#define ARM_DMB() arm_dmb(15)
- /************************************************************************************
+/************************************************************************************
* Inline Functions
************************************************************************************/
diff --git a/arch/arm/src/c5471/Kconfig b/arch/arm/src/c5471/Kconfig
index 17b615a0973..5f46d7684a9 100644
--- a/arch/arm/src/c5471/Kconfig
+++ b/arch/arm/src/c5471/Kconfig
@@ -110,3 +110,23 @@ config C5471_BASET10
bool "10BaseT FullDuplex"
endchoice
+
+choice
+ prompt "Ethernet work queue"
+ default C5471_LPWORK if SCHED_LPWORK
+ default C5471_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
+ depends on SCHED_WORKQUEUE
+ ---help---
+ Work queue support is required to use the Ethernet driver. If the
+ low priority work queue is available, then it should be used by the
+ driver.
+
+config C5471_HPWORK
+ bool "High priority"
+ depends on SCHED_HPWORK
+
+config C5471_LPWORK
+ bool "Low priority"
+ depends on SCHED_LPWORK
+
+endchoice # Work queue
diff --git a/arch/arm/src/c5471/c5471_ethernet.c b/arch/arm/src/c5471/c5471_ethernet.c
index b7563aa0545..a163cecaabe 100644
--- a/arch/arm/src/c5471/c5471_ethernet.c
+++ b/arch/arm/src/c5471/c5471_ethernet.c
@@ -59,6 +59,7 @@
#include
#include
#include
+#include
#include
#include
@@ -75,6 +76,25 @@
****************************************************************************/
/* Configuration ************************************************************/
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
+#else
+
+ /* Use the low priority work queue if possible */
+
+# if defined(CONFIG_C5471_HPWORK)
+# define ETHWORK HPWORK
+# elif defined(CONFIG_C5471_LPWORK)
+# define ETHWORK LPWORK
+# else
+# error Neither CONFIG_C5471_HPWORK nor CONFIG_C5471_LPWORK defined
+# endif
+#endif
+
/* CONFIG_C5471_NET_NINTERFACES determines the number of physical interfaces
* that will be supported.
*/
@@ -273,12 +293,16 @@
/* This is a helper pointer for accessing the contents of the Ethernet header */
-#define BUF ((struct eth_hdr_s *)c5471->c_dev.d_buf)
+#define BUF ((struct eth_hdr_s *)priv->c_dev.d_buf)
/****************************************************************************
* Private Types
****************************************************************************/
+/* A single packet buffer is used */
+
+static uint8_t g_pktbuf[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
+
/* The c5471_driver_s encapsulates all state information for a single c5471
* hardware interface
*/
@@ -288,6 +312,7 @@ struct c5471_driver_s
bool c_bifup; /* true:ifup false:ifdown */
WDOG_ID c_txpoll; /* TX poll timer */
WDOG_ID c_txtimeout; /* TX timeout timer */
+ struct work_s c_work; /* For deferring work to the work queue */
/* Note: According to the C547x documentation: "The software has to maintain
* two pointers to the current RX-CPU and TX-CPU descriptors. At init time,
@@ -356,36 +381,44 @@ static int c5471_phyinit (void);
/* Support logic */
-static inline void c5471_inctxcpu(struct c5471_driver_s *c5471);
-static inline void c5471_incrxcpu(struct c5471_driver_s *c5471);
+static inline void c5471_inctxcpu(struct c5471_driver_s *priv);
+static inline void c5471_incrxcpu(struct c5471_driver_s *priv);
/* Common TX logic */
-static int c5471_transmit(struct c5471_driver_s *c5471);
+static int c5471_transmit(struct c5471_driver_s *priv);
static int c5471_txpoll(struct net_driver_s *dev);
/* Interrupt handling */
#ifdef CONFIG_C5471_NET_STATS
-static void c5471_rxstatus(struct c5471_driver_s *c5471);
+static void c5471_rxstatus(struct c5471_driver_s *priv);
#endif
-static void c5471_receive(struct c5471_driver_s *c5471);
+static void c5471_receive(struct c5471_driver_s *priv);
#ifdef CONFIG_C5471_NET_STATS
-static void c5471_txstatus(struct c5471_driver_s *c5471);
+static void c5471_txstatus(struct c5471_driver_s *priv);
#endif
-static void c5471_txdone(struct c5471_driver_s *c5471);
+static void c5471_txdone(struct c5471_driver_s *priv);
+
+static void c5471_interrupt_work(FAR void *arg);
static int c5471_interrupt(int irq, FAR void *context);
/* Watchdog timer expirations */
-static void c5471_polltimer(int argc, uint32_t arg, ...);
-static void c5471_txtimeout(int argc, uint32_t arg, ...);
+static void c5471_txtimeout_work(FAR void *arg);
+static void c5471_txtimeout_expiry(int argc, uint32_t arg, ...);
+
+static void c5471_poll_work(FAR void *arg);
+static void c5471_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int c5471_ifup(struct net_driver_s *dev);
static int c5471_ifdown(struct net_driver_s *dev);
+
+static void c5471_txavail_work(FAR void *arg);
static int c5471_txavail(struct net_driver_s *dev);
+
#ifdef CONFIG_NET_IGMP
static int c5471_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
static int c5471_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
@@ -393,10 +426,10 @@ static int c5471_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
/* Initialization functions */
-static void c5471_eimreset (struct c5471_driver_s *c5471);
-static void c5471_eimconfig(struct c5471_driver_s *c5471);
-static void c5471_reset(struct c5471_driver_s *c5471);
-static void c5471_macassign(struct c5471_driver_s *c5471);
+static void c5471_eimreset (struct c5471_driver_s *priv);
+static void c5471_eimconfig(struct c5471_driver_s *priv);
+static void c5471_reset(struct c5471_driver_s *priv);
+static void c5471_macassign(struct c5471_driver_s *priv);
/****************************************************************************
* Private Functions
@@ -411,7 +444,8 @@ static void c5471_macassign(struct c5471_driver_s *c5471);
****************************************************************************/
#ifdef CONFIG_C5471_NET_DUMPBUFFER
-static inline void c5471_dumpbuffer(const char *msg, const uint8_t *buffer, unsigned int nbytes)
+static inline void c5471_dumpbuffer(const char *msg, const uint8_t *buffer,
+ unsigned int nbytes)
{
/* CONFIG_DEBUG_FEATURES, CONFIG_DEBUG_INFO, and CONFIG_DEBUG_NET have to be
* defined or the following does nothing.
@@ -789,20 +823,20 @@ static int c5471_phyinit (void)
*
****************************************************************************/
-static inline void c5471_inctxcpu(struct c5471_driver_s *c5471)
+static inline void c5471_inctxcpu(struct c5471_driver_s *priv)
{
- if (EIM_TXDESC_WRAP_NEXT & getreg32(c5471->c_txcpudesc))
+ if (EIM_TXDESC_WRAP_NEXT & getreg32(priv->c_txcpudesc))
{
/* Loop back around to base of descriptor queue */
- c5471->c_txcpudesc = getreg32(EIM_CPU_TXBA) + EIM_RAM_START;
+ priv->c_txcpudesc = getreg32(EIM_CPU_TXBA) + EIM_RAM_START;
}
else
{
- c5471->c_txcpudesc += 2*sizeof(uint32_t);
+ priv->c_txcpudesc += 2*sizeof(uint32_t);
}
- ninfo("TX CPU desc: %08x\n", c5471->c_txcpudesc);
+ ninfo("TX CPU desc: %08x\n", priv->c_txcpudesc);
}
/****************************************************************************
@@ -812,20 +846,20 @@ static inline void c5471_inctxcpu(struct c5471_driver_s *c5471)
*
****************************************************************************/
-static inline void c5471_incrxcpu(struct c5471_driver_s *c5471)
+static inline void c5471_incrxcpu(struct c5471_driver_s *priv)
{
- if (EIM_RXDESC_WRAP_NEXT & getreg32(c5471->c_rxcpudesc))
+ if (EIM_RXDESC_WRAP_NEXT & getreg32(priv->c_rxcpudesc))
{
/* Loop back around to base of descriptor queue */
- c5471->c_rxcpudesc = getreg32(EIM_CPU_RXBA) + EIM_RAM_START;
+ priv->c_rxcpudesc = getreg32(EIM_CPU_RXBA) + EIM_RAM_START;
}
else
{
- c5471->c_rxcpudesc += 2*sizeof(uint32_t);
+ priv->c_rxcpudesc += 2*sizeof(uint32_t);
}
- ninfo("RX CPU desc: %08x\n", c5471->c_rxcpudesc);
+ ninfo("RX CPU desc: %08x\n", priv->c_rxcpudesc);
}
/****************************************************************************
@@ -836,7 +870,7 @@ static inline void c5471_incrxcpu(struct c5471_driver_s *c5471)
* handling or from watchdog based polling.
*
* Parameters:
- * c5471 - Reference to the driver state structure
+ * priv - Reference to the driver state structure
*
* Returned Value:
* OK on success; a negated errno on failure
@@ -845,9 +879,9 @@ static inline void c5471_incrxcpu(struct c5471_driver_s *c5471)
*
****************************************************************************/
-static int c5471_transmit(struct c5471_driver_s *c5471)
+static int c5471_transmit(struct c5471_driver_s *priv)
{
- struct net_driver_s *dev = &c5471->c_dev;
+ struct net_driver_s *dev = &priv->c_dev;
volatile uint16_t *packetmem;
uint16_t framelen;
bool bfirstframe;
@@ -856,12 +890,12 @@ static int c5471_transmit(struct c5471_driver_s *c5471)
unsigned int i;
unsigned int j;
- nbytes = (dev->d_len + 1) & ~1;
- j = 0;
- bfirstframe = true;
- c5471->c_lastdescstart = c5471->c_rxcpudesc;
+ nbytes = (dev->d_len + 1) & ~1;
+ j = 0;
+ bfirstframe = true;
+ priv->c_lastdescstart = priv->c_rxcpudesc;
- ninfo("Packet size: %d RX CPU desc: %08x\n", nbytes, c5471->c_rxcpudesc);
+ ninfo("Packet size: %d RX CPU desc: %08x\n", nbytes, priv->c_rxcpudesc);
c5471_dumpbuffer("Transmit packet", dev->d_buf, dev->d_len);
while (nbytes)
@@ -869,7 +903,7 @@ static int c5471_transmit(struct c5471_driver_s *c5471)
/* Verify that the hardware is ready to send another packet */
/* Words #0 and #1 of descriptor */
- while (EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc))
+ while (EIM_TXDESC_OWN_HOST & getreg32(priv->c_rxcpudesc))
{
/* Loop until the SWITCH lets go of the descriptor giving us access
* rights to submit our new ether frame to it.
@@ -878,18 +912,18 @@ static int c5471_transmit(struct c5471_driver_s *c5471)
if (bfirstframe)
{
- putreg32((getreg32(c5471->c_rxcpudesc) | EIM_RXDESC_FIF), c5471->c_rxcpudesc);
+ putreg32((getreg32(priv->c_rxcpudesc) | EIM_RXDESC_FIF), priv->c_rxcpudesc);
}
else
{
- putreg32((getreg32(c5471->c_rxcpudesc) & ~EIM_RXDESC_FIF), c5471->c_rxcpudesc);
+ putreg32((getreg32(priv->c_rxcpudesc) & ~EIM_RXDESC_FIF), priv->c_rxcpudesc);
}
- putreg32((getreg32(c5471->c_rxcpudesc) & ~EIM_RXDESC_PADCRC), c5471->c_rxcpudesc);
+ putreg32((getreg32(priv->c_rxcpudesc) & ~EIM_RXDESC_PADCRC), priv->c_rxcpudesc);
if (bfirstframe)
{
- putreg32((getreg32(c5471->c_rxcpudesc) | EIM_RXDESC_PADCRC), c5471->c_rxcpudesc);
+ putreg32((getreg32(priv->c_rxcpudesc) | EIM_RXDESC_PADCRC), priv->c_rxcpudesc);
}
if (nbytes >= EIM_PACKET_BYTES)
@@ -908,7 +942,7 @@ static int c5471_transmit(struct c5471_driver_s *c5471)
/* Words #2 and #3 of descriptor */
- packetmem = (uint16_t *)getreg32(c5471->c_rxcpudesc + sizeof(uint32_t));
+ packetmem = (uint16_t *)getreg32(priv->c_rxcpudesc + sizeof(uint32_t));
for (i = 0; i < nshorts; i++, j++)
{
/* 16-bits at a time. */
@@ -916,43 +950,45 @@ static int c5471_transmit(struct c5471_driver_s *c5471)
packetmem[i] = htons(((uint16_t *)dev->d_buf)[j]);
}
- putreg32(((getreg32(c5471->c_rxcpudesc) & ~EIM_RXDESC_BYTEMASK) | framelen), c5471->c_rxcpudesc);
+ putreg32(((getreg32(priv->c_rxcpudesc) & ~EIM_RXDESC_BYTEMASK) | framelen),
+ priv->c_rxcpudesc);
nbytes -= framelen;
ninfo("Wrote framelen: %d nbytes: %d nshorts: %d\n", framelen, nbytes, nshorts);
if (0 == nbytes)
{
- putreg32((getreg32(c5471->c_rxcpudesc) | EIM_RXDESC_LIF), c5471->c_rxcpudesc);
+ putreg32((getreg32(priv->c_rxcpudesc) | EIM_RXDESC_LIF), priv->c_rxcpudesc);
}
else
{
- putreg32((getreg32(c5471->c_rxcpudesc) & ~EIM_RXDESC_LIF), c5471->c_rxcpudesc);
+ putreg32((getreg32(priv->c_rxcpudesc) & ~EIM_RXDESC_LIF), priv->c_rxcpudesc);
}
/* We're done with that descriptor; give access rights back to h/w */
- putreg32((getreg32(c5471->c_rxcpudesc) | EIM_RXDESC_OWN_HOST), c5471->c_rxcpudesc);
+ putreg32((getreg32(priv->c_rxcpudesc) | EIM_RXDESC_OWN_HOST), priv->c_rxcpudesc);
/* Next, tell Ether Module that those submitted bytes are ready for the wire */
putreg32(0x00000001, EIM_CPU_RXREADY);
- c5471->c_lastdescend = c5471->c_rxcpudesc;
+ priv->c_lastdescend = priv->c_rxcpudesc;
/* Advance to the next free descriptor */
- c5471_incrxcpu(c5471);
+ c5471_incrxcpu(priv);
bfirstframe = false;
}
/* Packet transferred .. Update statistics */
#ifdef CONFIG_C5471_NET_STATS
- c5471->c_txpackets++;
+ priv->c_txpackets++;
#endif
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
- (void)wd_start(c5471->c_txtimeout, C5471_TXTIMEOUT, c5471_txtimeout, 1, (uint32_t)c5471);
+ (void)wd_start(priv->c_txtimeout, C5471_TXTIMEOUT,
+ c5471_txtimeout_expiry, 1, (wdparm_t)priv);
return OK;
}
@@ -979,13 +1015,13 @@ static int c5471_transmit(struct c5471_driver_s *c5471)
static int c5471_txpoll(struct net_driver_s *dev)
{
- struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private;
+ struct c5471_driver_s *priv = (struct c5471_driver_s *)dev->d_private;
/* If the polling resulted in data that should be sent out on the network,
* the field d_len is set to a value > 0.
*/
- if (c5471->c_dev.d_len > 0)
+ if (priv->c_dev.d_len > 0)
{
/* Look up the destination MAC address and add it to the Ethernet
* header.
@@ -993,10 +1029,10 @@ static int c5471_txpoll(struct net_driver_s *dev)
#ifdef CONFIG_NET_IPv4
#ifdef CONFIG_NET_IPv6
- if (IFF_IS_IPv4(c5471->c_dev.d_flags))
+ if (IFF_IS_IPv4(priv->c_dev.d_flags))
#endif
{
- arp_out(&c5471->c_dev);
+ arp_out(&priv->c_dev);
}
#endif /* CONFIG_NET_IPv4 */
@@ -1005,19 +1041,19 @@ static int c5471_txpoll(struct net_driver_s *dev)
else
#endif
{
- neighbor_out(&c5471->c_dev);
+ neighbor_out(&priv->c_dev);
}
#endif /* CONFIG_NET_IPv6 */
/* Send the packet */
- c5471_transmit(c5471);
+ c5471_transmit(priv);
/* Check if the ESM has let go of the RX descriptor giving us access
* rights to submit another Ethernet frame.
*/
- if ((EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) != 0)
+ if ((EIM_TXDESC_OWN_HOST & getreg32(priv->c_rxcpudesc)) != 0)
{
/* No, then return non-zero to terminate the poll */
@@ -1039,7 +1075,7 @@ static int c5471_txpoll(struct net_driver_s *dev)
* An interrupt was received indicating that the last RX packet(s) is done
*
* Parameters:
- * c5471 - Reference to the driver state structure
+ * priv - Reference to the driver state structure
*
* Returned Value:
* None
@@ -1049,9 +1085,9 @@ static int c5471_txpoll(struct net_driver_s *dev)
****************************************************************************/
#ifdef CONFIG_C5471_NET_STATS
-static void c5471_rxstatus(struct c5471_driver_s *c5471)
+static void c5471_rxstatus(struct c5471_driver_s *priv)
{
- uint32_t desc = c5471->c_txcpudesc;
+ uint32_t desc = priv->c_txcpudesc;
uint32_t rxstatus;
/* Walk that last packet we just received to collect xmit status bits. */
@@ -1091,44 +1127,44 @@ static void c5471_rxstatus(struct c5471_driver_s *c5471)
{
if ((rxstatus & EIM_TXDESC_RETRYERROR) != 0)
{
- c5471->c_rxretries++;
- ninfo("c_rxretries: %d\n", c5471->c_rxretries);
+ priv->c_rxretries++;
+ ninfo("c_rxretries: %d\n", priv->c_rxretries);
}
if ((rxstatus & EIM_TXDESC_HEARTBEAT) != 0)
{
- c5471->c_rxheartbeat++;
- ninfo("c_rxheartbeat: %d\n", c5471->c_rxheartbeat);
+ priv->c_rxheartbeat++;
+ ninfo("c_rxheartbeat: %d\n", priv->c_rxheartbeat);
}
if ((rxstatus & EIM_TXDESC_LCOLLISON) != 0)
{
- c5471->c_rxlcollision++;
- ninfo("c_rxlcollision: %d\n", c5471->c_rxlcollision);
+ priv->c_rxlcollision++;
+ ninfo("c_rxlcollision: %d\n", priv->c_rxlcollision);
}
if ((rxstatus & EIM_TXDESC_COLLISION) != 0)
{
- c5471->c_rxcollision++;
- ninfo("c_rxcollision: %d\n", c5471->c_rxcollision);
+ priv->c_rxcollision++;
+ ninfo("c_rxcollision: %d\n", priv->c_rxcollision);
}
if ((rxstatus & EIM_TXDESC_CRCERROR) != 0)
{
- c5471->c_rxcrc++;
- ninfo("c_rxcrc: %d\n", c5471->c_rxcrc);
+ priv->c_rxcrc++;
+ ninfo("c_rxcrc: %d\n", priv->c_rxcrc);
}
if ((rxstatus & EIM_TXDESC_UNDERRUN) != 0)
{
- c5471->c_rxunderrun++;
- ninfo("c_rxunderrun: %d\n", c5471->c_rxunderrun);
+ priv->c_rxunderrun++;
+ ninfo("c_rxunderrun: %d\n", priv->c_rxunderrun);
}
if ((rxstatus & EIM_TXDESC_LOC) != 0)
{
- c5471->c_rxloc++;
- ninfo("c_rxloc: %d\n", c5471->c_rxloc);
+ priv->c_rxloc++;
+ ninfo("c_rxloc: %d\n", priv->c_rxloc);
}
}
}
@@ -1141,7 +1177,7 @@ static void c5471_rxstatus(struct c5471_driver_s *c5471)
* An interrupt was received indicating the availability of a new RX packet
*
* Parameters:
- * c5471 - Reference to the driver state structure
+ * priv - Reference to the driver state structure
*
* Returned Value:
* None
@@ -1150,9 +1186,9 @@ static void c5471_rxstatus(struct c5471_driver_s *c5471)
*
****************************************************************************/
-static void c5471_receive(struct c5471_driver_s *c5471)
+static void c5471_receive(struct c5471_driver_s *priv)
{
- struct net_driver_s *dev = &c5471->c_dev;
+ struct net_driver_s *dev = &priv->c_dev;
uint16_t *packetmem;
bool bmore = true;
int packetlen = 0;
@@ -1166,12 +1202,12 @@ static void c5471_receive(struct c5471_driver_s *c5471)
* the EIM for additional packets that might be received later from the network.
*/
- ninfo("Reading TX CPU desc: %08x\n", c5471->c_txcpudesc);
+ ninfo("Reading TX CPU desc: %08x\n", priv->c_txcpudesc);
while (bmore)
{
/* Words #0 and #1 of descriptor */
- if (EIM_TXDESC_OWN_HOST & getreg32(c5471->c_txcpudesc))
+ if (EIM_TXDESC_OWN_HOST & getreg32(priv->c_txcpudesc))
{
/* No further packets to receive. */
@@ -1182,7 +1218,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
* and update the accumulated packet size
*/
- framelen = (getreg32(c5471->c_txcpudesc) & EIM_TXDESC_BYTEMASK);
+ framelen = (getreg32(priv->c_txcpudesc) & EIM_TXDESC_BYTEMASK);
packetlen += framelen;
/* Check if the received packet will fit within the network packet buffer */
@@ -1191,7 +1227,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
{
/* Get the packet memory from words #2 and #3 of descriptor */
- packetmem = (uint16_t *)getreg32(c5471->c_txcpudesc + sizeof(uint32_t));
+ packetmem = (uint16_t *)getreg32(priv->c_txcpudesc + sizeof(uint32_t));
/* Divide by 2 with round up to get the number of 16-bit words. */
@@ -1201,7 +1237,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
for (i = 0 ; i < nshorts; i++, j++)
{
- /* Copy the data data from the hardware to c5471->c_dev.d_buf 16-bits at
+ /* Copy the data data from the hardware to priv->c_dev.d_buf 16-bits at
* a time.
*/
@@ -1213,7 +1249,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
ninfo("Discarding framelen: %d packetlen\n", framelen, packetlen);
}
- if (getreg32(c5471->c_txcpudesc) & EIM_TXDESC_LIF)
+ if (getreg32(priv->c_txcpudesc) & EIM_TXDESC_LIF)
{
bmore = false;
}
@@ -1222,16 +1258,16 @@ static void c5471_receive(struct c5471_driver_s *c5471)
* the settings of a select few. Can leave descriptor words 2/3 alone.
*/
- putreg32((getreg32(c5471->c_txcpudesc) & (EIM_TXDESC_WRAP_NEXT | EIM_TXDESC_INTRE)),
- c5471->c_txcpudesc);
+ putreg32((getreg32(priv->c_txcpudesc) & (EIM_TXDESC_WRAP_NEXT | EIM_TXDESC_INTRE)),
+ priv->c_txcpudesc);
/* Next, Give ownership of now emptied descriptor back to the Ether Module's SWITCH */
- putreg32((getreg32(c5471->c_txcpudesc) | EIM_TXDESC_OWN_HOST), c5471->c_txcpudesc);
+ putreg32((getreg32(priv->c_txcpudesc) | EIM_TXDESC_OWN_HOST), priv->c_txcpudesc);
/* Advance to the next data buffer */
- c5471_inctxcpu(c5471);
+ c5471_inctxcpu(priv);
}
/* Adjust the packet length to remove the CRC bytes that the network doesn't care about. */
@@ -1241,7 +1277,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
#ifdef CONFIG_C5471_NET_STATS
/* Increment the count of received packets */
- c5471->c_rxpackets++;
+ priv->c_rxpackets++;
#endif
/* If we successfully transferred the data into the network buffer, then pass it on
@@ -1250,7 +1286,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
if (packetlen > 0 && packetlen < CONFIG_NET_ETH_MTU)
{
- /* Set amount of data in c5471->c_dev.d_len. */
+ /* Set amount of data in priv->c_dev.d_len. */
dev->d_len = packetlen;
ninfo("Received packet, packetlen: %d type: %02x\n", packetlen, ntohs(BUF->type));
@@ -1283,7 +1319,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
*/
if (dev->d_len > 0 &&
- (EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0)
+ (EIM_TXDESC_OWN_HOST & getreg32(priv->c_rxcpudesc)) == 0)
{
/* Update the Ethernet header with the correct MAC address */
@@ -1302,7 +1338,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
/* And send the packet */
- c5471_transmit(c5471);
+ c5471_transmit(priv);
}
}
else
@@ -1323,7 +1359,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
*/
if (dev->d_len > 0 &&
- (EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0)
+ (EIM_TXDESC_OWN_HOST & getreg32(priv->c_rxcpudesc)) == 0)
{
/* Update the Ethernet header with the correct MAC address */
@@ -1342,7 +1378,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
/* And send the packet */
- c5471_transmit(c5471);
+ c5471_transmit(priv);
}
}
else
@@ -1359,9 +1395,9 @@ static void c5471_receive(struct c5471_driver_s *c5471)
*/
if (dev->d_len > 0 &&
- (EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0)
+ (EIM_TXDESC_OWN_HOST & getreg32(priv->c_rxcpudesc)) == 0)
{
- c5471_transmit(c5471);
+ c5471_transmit(priv);
}
}
#endif
@@ -1372,7 +1408,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
/* Increment the count of dropped packets */
nwarn("WARNING: Too big! packetlen: %d\n", packetlen);
- c5471->c_rxdropped++;
+ priv->c_rxdropped++;
}
#endif
}
@@ -1384,7 +1420,7 @@ static void c5471_receive(struct c5471_driver_s *c5471)
* An interrupt was received indicating that the last TX packet(s) is done
*
* Parameters:
- * c5471 - Reference to the driver state structure
+ * priv - Reference to the driver state structure
*
* Returned Value:
* None
@@ -1394,27 +1430,27 @@ static void c5471_receive(struct c5471_driver_s *c5471)
****************************************************************************/
#ifdef CONFIG_C5471_NET_STATS
-static void c5471_txstatus(struct c5471_driver_s *c5471)
+static void c5471_txstatus(struct c5471_driver_s *priv)
{
- uint32_t desc = c5471->c_lastdescstart;
+ uint32_t desc = priv->c_lastdescstart;
uint32_t txstatus;
/* Walk that last packet we just sent to collect xmit status bits. */
txstatus = 0;
- if (c5471->c_lastdescstart && c5471->c_lastdescend)
+ if (priv->c_lastdescstart && priv->c_lastdescend)
{
for (; ; )
{
txstatus |= (getreg32(desc) & EIM_RXDESC_STATUSMASK);
- if (desc == c5471->c_lastdescend)
+ if (desc == priv->c_lastdescend)
{
break;
}
/* This packet is made up of several descriptors, find next one in chain. */
- if (EIM_RXDESC_WRAP_NEXT & getreg32(c5471->c_rxcpudesc))
+ if (EIM_RXDESC_WRAP_NEXT & getreg32(priv->c_rxcpudesc))
{
/* Loop back around to base of descriptor queue. */
@@ -1431,44 +1467,44 @@ static void c5471_txstatus(struct c5471_driver_s *c5471)
{
if ((txstatus & EIM_RXDESC_MISS) != 0)
{
- c5471->c_txmiss++;
- ninfo("c_txmiss: %d\n", c5471->c_txmiss);
+ priv->c_txmiss++;
+ ninfo("c_txmiss: %d\n", priv->c_txmiss);
}
if ((txstatus & EIM_RXDESC_VLAN) != 0)
{
- c5471->c_txvlan++;
- ninfo("c_txvlan: %d\n", c5471->c_txvlan);
+ priv->c_txvlan++;
+ ninfo("c_txvlan: %d\n", priv->c_txvlan);
}
if ((txstatus & EIM_RXDESC_LFRAME) != 0)
{
- c5471->c_txlframe++;
- ninfo("c_txlframe: %d\n", c5471->c_txlframe);
+ priv->c_txlframe++;
+ ninfo("c_txlframe: %d\n", priv->c_txlframe);
}
if ((txstatus & EIM_RXDESC_SFRAME) != 0)
{
- c5471->c_txsframe++;
- ninfo("c_txsframe: %d\n", c5471->c_txsframe);
+ priv->c_txsframe++;
+ ninfo("c_txsframe: %d\n", priv->c_txsframe);
}
if ((txstatus & EIM_RXDESC_CRCERROR) != 0)
{
- c5471->c_txcrc++;
- ninfo("c_txcrc: %d\n", c5471->c_txcrc);
+ priv->c_txcrc++;
+ ninfo("c_txcrc: %d\n", priv->c_txcrc);
}
if ((txstatus & EIM_RXDESC_OVERRUN) != 0)
{
- c5471->c_txoverrun++;
- ninfo("c_txoverrun: %d\n", c5471->c_txoverrun);
+ priv->c_txoverrun++;
+ ninfo("c_txoverrun: %d\n", priv->c_txoverrun);
}
if ((txstatus & EIM_RXDESC_OVERRUN) != 0)
{
- c5471->c_txalign++;
- ninfo("c_txalign: %d\n", c5471->c_txalign);
+ priv->c_txalign++;
+ ninfo("c_txalign: %d\n", priv->c_txalign);
}
}
}
@@ -1481,7 +1517,7 @@ static void c5471_txstatus(struct c5471_driver_s *c5471)
* An interrupt was received indicating that the last TX packet(s) is done
*
* Parameters:
- * c5471 - Reference to the driver state structure
+ * priv - Reference to the driver state structure
*
* Returned Value:
* None
@@ -1490,15 +1526,95 @@ static void c5471_txstatus(struct c5471_driver_s *c5471)
*
****************************************************************************/
-static void c5471_txdone(struct c5471_driver_s *c5471)
+static void c5471_txdone(struct c5471_driver_s *priv)
{
/* If no further xmits are pending, then cancel the TX timeout */
- wd_cancel(c5471->c_txtimeout);
+ wd_cancel(priv->c_txtimeout);
/* Then poll the network for new XMIT data */
- (void)devif_poll(&c5471->c_dev, c5471_txpoll);
+ (void)devif_poll(&priv->c_dev, c5471_txpoll);
+}
+
+/****************************************************************************
+ * Function: c5471_interrupt_work
+ *
+ * Description:
+ * Perform interrupt related work from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() was called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void c5471_interrupt_work(FAR void *arg)
+{
+ FAR struct c5471_driver_s *priv = (FAR struct c5471_driver_s *)arg;
+
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
+
+ /* Get and clear interrupt status bits */
+
+ priv->c_eimstatus = getreg32(EIM_STATUS);
+
+ /* Handle interrupts according to status bit settings */
+ /* Check if we received an incoming packet, if so, call c5471_receive() */
+
+ if ((EIM_STATUS_CPU_TX & priv->c_eimstatus) != 0)
+ {
+ /* An incoming packet has been received by the EIM from the network and
+ * the interrupt associated with EIM's CPU TX queue has been asserted. It
+ * is the EIM's CPU TX queue that we need to read from to get those
+ * packets. We use this terminology to stay consistent with the Orion
+ * documentation.
+ */
+
+#ifdef CONFIG_C5471_NET_STATS
+ /* Check for RX errors */
+
+ c5471_rxstatus(priv);
+#endif
+
+ /* Process the received packet */
+
+ c5471_receive(priv);
+ }
+
+ /* Check is a packet transmission just completed. If so, call c5471_txdone */
+
+ if ((EIM_STATUS_CPU_RX & priv->c_eimstatus) != 0)
+ {
+ /* An outgoing packet has been processed by the EIM and the interrupt
+ * associated with EIM's CPU RX que has been asserted. It is the EIM's
+ * CPU RX queue that we put packets on to send them *out*. TWe use this
+ * terminology to stay consistent with the Orion documentation.
+ */
+
+#ifdef CONFIG_C5471_NET_STATS
+ /* Check for TX errors */
+
+ c5471_txstatus(priv);
+#endif
+
+ /* Handle the transmission done event */
+
+ c5471_txdone(priv);
+ }
+
+ net_unlock();
+
+ /* Re-enable Ethernet interrupts */
+
+ up_enable_irq(C5471_IRQ_ETHER);
}
/****************************************************************************
@@ -1521,68 +1637,81 @@ static void c5471_txdone(struct c5471_driver_s *c5471)
static int c5471_interrupt(int irq, FAR void *context)
{
#if CONFIG_C5471_NET_NINTERFACES == 1
- register struct c5471_driver_s *c5471 = &g_c5471[0];
+ register struct c5471_driver_s *priv = &g_c5471[0];
#else
# error "Additional logic needed to support multiple interfaces"
#endif
- /* Get and clear interrupt status bits */
-
- c5471->c_eimstatus = getreg32(EIM_STATUS);
-
- /* Handle interrupts according to status bit settings */
- /* Check if we received an incoming packet, if so, call c5471_receive() */
-
- if ((EIM_STATUS_CPU_TX & c5471->c_eimstatus) != 0)
- {
- /* An incoming packet has been received by the EIM from the network and
- * the interrupt associated with EIM's CPU TX queue has been asserted. It
- * is the EIM's CPU TX queue that we need to read from to get those
- * packets. We use this terminology to stay consistent with the Orion
- * documentation.
- */
-
-#ifdef CONFIG_C5471_NET_STATS
- /* Check for RX errors */
-
- c5471_rxstatus(c5471);
-#endif
-
- /* Process the received packet */
-
- c5471_receive(c5471);
- }
-
- /* Check is a packet transmission just completed. If so, call c5471_txdone */
-
- if ((EIM_STATUS_CPU_RX & c5471->c_eimstatus) != 0)
- {
- /* An outgoing packet has been processed by the EIM and the interrupt
- * associated with EIM's CPU RX que has been asserted. It is the EIM's
- * CPU RX queue that we put packets on to send them *out*. TWe use this
- * terminology to stay consistent with the Orion documentation.
- */
-
-#ifdef CONFIG_C5471_NET_STATS
- /* Check for TX errors */
-
- c5471_txstatus(c5471);
-#endif
-
- /* Handle the transmission done event */
-
- c5471_txdone(c5471);
- }
-
- /* Enable Ethernet interrupts (perhaps excluding the TX done interrupt if
- * there are no pending transmissions.
+ /* Disable further Ethernet interrupts. Because Ethernet interrupts are
+ * also disabled if the TX timeout event occurs, there can be no race
+ * condition here.
*/
+ up_disable_irq(C5471_IRQ_ETHER);
+
+ /* TODO: Determine if a TX transfer just completed */
+
+ {
+ /* If a TX transfer just completed, then cancel the TX timeout so
+ * there will be no race condition between any subsequent timeout
+ * expiration and the deferred interrupt processing.
+ */
+
+ wd_cancel(priv->c_txtimeout);
+ }
+
+ /* Cancel any pending poll work */
+
+ work_cancel(ETHWORK, &priv->c_work);
+
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->c_work, c5471_interrupt_work, priv, 0);
return OK;
}
/****************************************************************************
- * Function: c5471_txtimeout
+ * Function: c5471_txtimeout_work
+ *
+ * Description:
+ * Perform TX timeout related work from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void c5471_txtimeout_work(FAR void *arg)
+{
+ FAR struct c5471_driver_s *priv = (FAR struct c5471_driver_s *)arg;
+
+ /* Increment statistics */
+
+ net_lock();
+#ifdef CONFIG_C5471_NET_STATS
+ priv->c_txtimeouts++;
+ ninfo("c_txtimeouts: %d\n", priv->c_txtimeouts);
+#endif
+
+ /* Then try to restart the hardware */
+
+ c5471_ifdown(&priv->c_dev);
+ c5471_ifup(&priv->c_dev);
+
+ /* Then poll the network for new XMIT data */
+
+ (void)devif_poll(&priv->c_dev, c5471_txpoll);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: c5471_txtimeout_expiry
*
* Description:
* Our TX watchdog timed out. Called from the timer interrupt handler.
@@ -1596,32 +1725,74 @@ static int c5471_interrupt(int irq, FAR void *context)
* None
*
* Assumptions:
+ * Global interrupts are disabled by the watchdog logic.
*
****************************************************************************/
-static void c5471_txtimeout(int argc, uint32_t arg, ...)
+static void c5471_txtimeout_expiry(int argc, wdparm_t arg, ...)
{
- struct c5471_driver_s *c5471 = (struct c5471_driver_s *)arg;
+ struct c5471_driver_s *priv = (struct c5471_driver_s *)arg;
- /* Increment statistics */
+ /* Disable further Ethernet interrupts. This will prevent some race
+ * conditions with interrupt work. There is still a potential race
+ * condition with interrupt work that is already queued and in progress.
+ */
-#ifdef CONFIG_C5471_NET_STATS
- c5471->c_txtimeouts++;
- ninfo("c_txtimeouts: %d\n", c5471->c_txtimeouts);
-#endif
+ up_disable_irq(C5471_IRQ_ETHER);
- /* Then try to restart the hardware */
+ /* Cancel any pending poll or interrupt work. This will have no effect
+ * on work that has already been started.
+ */
- c5471_ifdown(&c5471->c_dev);
- c5471_ifup(&c5471->c_dev);
+ work_cancel(ETHWORK, &priv->c_work);
- /* Then poll the network for new XMIT data */
+ /* Schedule to perform the TX timeout processing on the worker thread. */
- (void)devif_poll(&c5471->c_dev, c5471_txpoll);
+ work_queue(ETHWORK, &priv->c_work, c5471_txtimeout_work, priv, 0);
}
/****************************************************************************
- * Function: c5471_polltimer
+ * Function: c5471_poll_work
+ *
+ * Description:
+ * Perform periodic polling from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void c5471_poll_work(FAR void *arg)
+{
+ FAR struct c5471_driver_s *priv = (FAR struct c5471_driver_s *)arg;
+
+ /* Check if the ESM has let go of the RX descriptor giving us access rights
+ * to submit another Ethernet frame.
+ */
+
+ net_lock();
+ if ((EIM_TXDESC_OWN_HOST & getreg32(priv->c_rxcpudesc)) == 0)
+ {
+ /* If so, update TCP timing states and poll the network for new XMIT data */
+
+ (void)devif_timer(&priv->c_dev, c5471_txpoll);
+ }
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->c_txpoll, C5471_WDDELAY, c5471_poll_expiry, 1,
+ (wdparm_t)priv);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: c5471_poll_expiry
*
* Description:
* Periodic timer handler. Called from the timer interrupt handler.
@@ -1634,27 +1805,33 @@ static void c5471_txtimeout(int argc, uint32_t arg, ...)
* None
*
* Assumptions:
+ * Global interrupts are disabled by the watchdog logic.
*
****************************************************************************/
-static void c5471_polltimer(int argc, uint32_t arg, ...)
+static void c5471_poll_expiry(int argc, wdparm_t arg, ...)
{
- struct c5471_driver_s *c5471 = (struct c5471_driver_s *)arg;
+ struct c5471_driver_s *priv = (struct c5471_driver_s *)arg;
- /* Check if the ESM has let go of the RX descriptor giving us access rights
- * to submit another Ethernet frame.
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions.
*/
- if ((EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0)
+ if (work_available(&priv->c_work))
{
- /* If so, update TCP timing states and poll the network for new XMIT data */
+ /* Schedule to perform the interrupt processing on the worker thread. */
- (void)devif_timer(&c5471->c_dev, c5471_txpoll);
+ work_queue(ETHWORK, &priv->c_work, c5471_poll_work, priv, 0);
}
+ else
+ {
+ /* No.. Just re-start the watchdog poll timer, missing one polling
+ * cycle.
+ */
- /* Setup the watchdog poll timer again */
-
- (void)wd_start(c5471->c_txpoll, C5471_WDDELAY, c5471_polltimer, 1, arg);
+ (void)wd_start(priv->c_txpoll, C5471_WDDELAY, c5471_poll_expiry,
+ 1, arg);
+ }
}
/****************************************************************************
@@ -1677,7 +1854,7 @@ static void c5471_polltimer(int argc, uint32_t arg, ...)
static int c5471_ifup(struct net_driver_s *dev)
{
- struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private;
+ struct c5471_driver_s *priv = (struct c5471_driver_s *)dev->d_private;
volatile uint32_t clearbits;
ninfo("Bringing up: %d.%d.%d.%d\n",
@@ -1686,11 +1863,11 @@ static int c5471_ifup(struct net_driver_s *dev)
/* Initilize Ethernet interface */
- c5471_reset(c5471);
+ c5471_reset(priv);
/* Assign the MAC to the device */
- c5471_macassign(c5471);
+ c5471_macassign(priv);
/* Clear pending interrupts by reading the EIM status register */
@@ -1712,11 +1889,12 @@ static int c5471_ifup(struct net_driver_s *dev)
/* Set and activate a timer process */
- (void)wd_start(c5471->c_txpoll, C5471_WDDELAY, c5471_polltimer, 1, (uint32_t)c5471);
+ (void)wd_start(priv->c_txpoll, C5471_WDDELAY, c5471_poll_expiry,
+ 1, (wdparm_t)priv);
/* Enable the Ethernet interrupt */
- c5471->c_bifup = true;
+ priv->c_bifup = true;
up_enable_irq(C5471_IRQ_ETHER);
return OK;
}
@@ -1739,7 +1917,7 @@ static int c5471_ifup(struct net_driver_s *dev)
static int c5471_ifdown(struct net_driver_s *dev)
{
- struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private;
+ struct c5471_driver_s *priv = (struct c5471_driver_s *)dev->d_private;
irqstate_t flags;
ninfo("Stopping\n");
@@ -1764,16 +1942,59 @@ static int c5471_ifdown(struct net_driver_s *dev)
/* Cancel the TX poll timer and TX timeout timers */
- wd_cancel(c5471->c_txpoll);
- wd_cancel(c5471->c_txtimeout);
+ wd_cancel(priv->c_txpoll);
+ wd_cancel(priv->c_txtimeout);
/* Reset the device */
- c5471->c_bifup = false;
+ priv->c_bifup = false;
leave_critical_section(flags);
return OK;
}
+/****************************************************************************
+ * Function: c5471_txavail_work
+ *
+ * Description:
+ * Perform an out-of-cycle poll on the worker thread.
+ *
+ * Parameters:
+ * arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+static void c5471_txavail_work(FAR void *arg)
+{
+ FAR struct c5471_driver_s *priv = (FAR struct c5471_driver_s *)arg;
+
+ ninfo("Polling\n");
+
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->c_bifup)
+ {
+ /* Check if the ESM has let go of the RX descriptor giving us access
+ * rights to submit another Ethernet frame.
+ */
+
+ if ((EIM_TXDESC_OWN_HOST & getreg32(priv->c_rxcpudesc)) == 0)
+ {
+ /* If so, then poll the network for new XMIT data */
+
+ (void)devif_poll(&priv->c_dev, c5471_txpoll);
+ }
+ }
+
+ net_unlock();
+}
+
/****************************************************************************
* Function: c5471_txavail
*
@@ -1783,7 +2004,7 @@ static int c5471_ifdown(struct net_driver_s *dev)
* latency.
*
* Parameters:
- * dev - Reference to the NuttX driver state structure
+ * dev - Reference to the NuttX driver state structure
*
* Returned Value:
* None
@@ -1793,31 +2014,22 @@ static int c5471_ifdown(struct net_driver_s *dev)
*
****************************************************************************/
-static int c5471_txavail(struct net_driver_s *dev)
+static int c5471_txavail(FAR struct net_driver_s *dev)
{
- struct c5471_driver_s *c5471 = (struct c5471_driver_s *)dev->d_private;
- irqstate_t flags;
+ struct c5471_driver_s *priv = (struct c5471_driver_s *)dev->d_private;
- ninfo("Polling\n");
- flags = enter_critical_section();
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
+ */
- /* Ignore the notification if the interface is not yet up */
-
- if (c5471->c_bifup)
+ if (work_available(&priv->c_work))
{
- /* Check if the ESM has let go of the RX descriptor giving us access
- * rights to submit another Ethernet frame.
- */
+ /* Schedule to serialize the poll on the worker thread. */
- if ((EIM_TXDESC_OWN_HOST & getreg32(c5471->c_rxcpudesc)) == 0)
- {
- /* If so, then poll the network for new XMIT data */
-
- (void)devif_poll(&c5471->c_dev, c5471_txpoll);
- }
+ work_queue(ETHWORK, &priv->c_work, c5471_txavail_work, priv, 0);
}
- leave_critical_section(flags);
return OK;
}
@@ -1895,7 +2107,7 @@ static int c5471_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac)
*
****************************************************************************/
-static void c5471_eimreset (struct c5471_driver_s *c5471)
+static void c5471_eimreset (struct c5471_driver_s *priv)
{
/* Stop the EIM module clock */
@@ -1925,8 +2137,8 @@ static void c5471_eimreset (struct c5471_driver_s *c5471)
/* All EIM register should now be in there power-up default states */
- c5471->c_lastdescstart = 0;
- c5471->c_lastdescend = 0;
+ priv->c_lastdescstart = 0;
+ priv->c_lastdescend = 0;
}
/****************************************************************************
@@ -1939,7 +2151,7 @@ static void c5471_eimreset (struct c5471_driver_s *c5471)
*
****************************************************************************/
-static void c5471_eimconfig(struct c5471_driver_s *c5471)
+static void c5471_eimconfig(struct c5471_driver_s *priv)
{
volatile uint32_t pbuf;
volatile uint32_t desc;
@@ -2006,7 +2218,7 @@ static void c5471_eimconfig(struct c5471_driver_s *c5471)
/* TX CPU */
ninfo("TX CPU desc: %08x pbuf: %08x\n", desc, pbuf);
- c5471->c_txcpudesc = desc;
+ priv->c_txcpudesc = desc;
putreg32((desc & 0x0000ffff), EIM_CPU_TXBA); /* 16-bit offset address */
for (i = NUM_DESC_TX-1; i >= 0; i--)
{
@@ -2036,7 +2248,7 @@ static void c5471_eimconfig(struct c5471_driver_s *c5471)
/* RX CPU */
ninfo("RX CPU desc: %08x pbuf: %08x\n", desc, pbuf);
- c5471->c_rxcpudesc = desc;
+ priv->c_rxcpudesc = desc;
putreg32((desc & 0x0000ffff), EIM_CPU_RXBA); /* 16-bit offset address */
for (i = NUM_DESC_RX-1; i >= 0; i--)
{
@@ -2147,17 +2359,17 @@ static void c5471_eimconfig(struct c5471_driver_s *c5471)
*
****************************************************************************/
-static void c5471_reset(struct c5471_driver_s *c5471)
+static void c5471_reset(struct c5471_driver_s *priv)
{
#if defined(CONFIG_C5471_PHY_LU3X31T_T64)
ninfo("EIM reset\n");
- c5471_eimreset(c5471);
+ c5471_eimreset(priv);
#endif
ninfo("PHY init\n");
c5471_phyinit();
ninfo("EIM config\n");
- c5471_eimconfig(c5471);
+ c5471_eimconfig(priv);
}
/****************************************************************************
@@ -2172,9 +2384,9 @@ static void c5471_reset(struct c5471_driver_s *c5471)
*
****************************************************************************/
-static void c5471_macassign(struct c5471_driver_s *c5471)
+static void c5471_macassign(struct c5471_driver_s *priv)
{
- struct net_driver_s *dev = &c5471->c_dev;
+ struct net_driver_s *dev = &priv->c_dev;
uint8_t *mptr = dev->d_mac.ether_addr_octet;
register uint32_t tmp;
@@ -2248,6 +2460,7 @@ void up_netinitialize(void)
/* Initialize the driver structure */
memset(g_c5471, 0, CONFIG_C5471_NET_NINTERFACES*sizeof(struct c5471_driver_s));
+ g_c5471[0].c_dev.d_buf = g_pktbuf; /* Single packet buffer */
g_c5471[0].c_dev.d_ifup = c5471_ifup; /* I/F down callback */
g_c5471[0].c_dev.d_ifdown = c5471_ifdown; /* I/F up (new IP address) callback */
g_c5471[0].c_dev.d_txavail = c5471_txavail; /* New TX data callback */
diff --git a/arch/arm/src/common/up_internal.h b/arch/arm/src/common/up_internal.h
index 36095a87a45..7318a70caad 100644
--- a/arch/arm/src/common/up_internal.h
+++ b/arch/arm/src/common/up_internal.h
@@ -191,6 +191,11 @@
# define _DATA_INIT &_eronly
# define _START_DATA &_sdata
# define _END_DATA &_edata
+
+#ifdef CONFIG_SMP
+# define _START_NOCACHE &_snocache
+# define _END_NOCACHE &_enocache
+#endif
#endif
/* This is the value used to mark the stack for subsequent stack monitoring
@@ -279,6 +284,11 @@ EXTERN uint32_t _edata; /* End+1 of .data */
EXTERN uint32_t _sbss; /* Start of .bss */
EXTERN uint32_t _ebss; /* End+1 of .bss */
+#ifdef CONFIG_SMP
+EXTERN uint32_t _snocache; /* Start of .nocache */
+EXTERN uint32_t _enocache; /* End+1 of .nocache */
+#endif
+
/* Sometimes, functions must be executed from RAM. In this case, the following
* macro may be used (with GCC!) to specify a function that will execute from
* RAM. For example,
diff --git a/arch/arm/src/imx6/Make.defs b/arch/arm/src/imx6/Make.defs
index 4870aa1d1de..9986ac23d9d 100644
--- a/arch/arm/src/imx6/Make.defs
+++ b/arch/arm/src/imx6/Make.defs
@@ -81,6 +81,7 @@ CMN_CSRCS += arm_unblocktask.c arm_undefinedinsn.c
ifeq ($(CONFIG_SMP),y)
CMN_CSRCS += arm_cpuindex.c arm_cpustart.c arm_cpupause.c arm_cpuidlestack.c
+CMN_CSRCS += arm_scu.c
endif
ifeq ($(CONFIG_DEBUG_IRQ_INFO),y)
diff --git a/arch/arm/src/imx6/chip/imx_memorymap.h b/arch/arm/src/imx6/chip/imx_memorymap.h
index c91fb924e09..17304c2474a 100644
--- a/arch/arm/src/imx6/chip/imx_memorymap.h
+++ b/arch/arm/src/imx6/chip/imx_memorymap.h
@@ -122,6 +122,18 @@
#define IMX_MMDCDDR_PSECTION 0x10000000 /* 10000000-ffffffff 3840 MB MMDC-DDR Controller */
/* 10000000-7fffffff 1792 MB */
+/* By default, NuttX uses a 1-1 memory mapping. So the unused, reserved
+ * address in the top-level memory map are candidates for other mapping uses:
+ *
+ * 00018000-000fffff Reserved -- Not used
+ * 00400000-007fffff Reserved -- Used as the virtual address an inter-CPU,
+ * un-cached memory region in SMP
+ * configurations
+ * 00d00000-00ffffff Reserved -- Not used
+ * 0220c000-023fffff Reserved -- Not used
+ * 80000000-efffffff Reserved -- Level 2 page table (See below)
+ */
+
/* i.MX6 DMA PSECTION Offsets */
#define IMX_CAAMRAM_OFFSET 0x00000000 /* 00000000-00003fff 16 KB CAAM (16K secure RAM) */
@@ -897,7 +909,7 @@
* 0x80000000-0xefffffff: Undefined (1.75 GB)
*
* That is the offset where the main L2 page tables will be positioned. This
- * corresponds to page table offsets 0x000002000 up to 0x000003c00. That
+ * corresponds to page table offsets 0x00002000 up to 0x00003c00. That
* is 1792 entries, each mapping 4KB of address for a total of 7MB of virtual
* address space)
*
@@ -917,7 +929,21 @@
* the address space.
*/
+#define INTERCPU_L2_PAGES 1 /* Pages allowed for inter-processor communications */
+
#ifndef CONFIG_ARCH_LOWVECTORS
+ /* Memory map
+ * VIRTUAL ADDRESS RANGE L1 PG TABLE L2 PG TABLE DESCRIPTION
+ * START END OFFSET SIZE
+ * ---------- ---------- ------------ ----------------------------
+ * 0x80000000 0x803fffff 0x000002000 0x000000400 Vectors (1MiB)
+ * 0x80100000 0x806fffff 0x000002400 0x000001800 Paging (6MiB)
+ *
+ * If SMP is enabled, then 1MiB of address spaces for the INTERCPU_L2_PAGES
+ * pages are taken from the end of the Paging L2 page table to hold non-
+ * cacheable, inter-processor communication data.
+ */
+
/* Vector L2 page table offset/size */
# define VECTOR_L2_OFFSET 0x000002000
@@ -933,16 +959,44 @@
# define VECTOR_L2_END_PADDR (VECTOR_L2_PBASE + VECTOR_L2_SIZE)
# define VECTOR_L2_END_VADDR (VECTOR_L2_VBASE + VECTOR_L2_SIZE)
- /* Paging L2 page table offset/size */
+# if defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
+ /* Paging L2 page table offset/size */
-# define PGTABLE_L2_OFFSET 0x000002400
-# define PGTABLE_L2_SIZE 0x000001800
+# define PGTABLE_L2_OFFSET 0x000002400
+# define PGTABLE_L2_SIZE 0x000001400
+
+# else
+ /* Paging L2 page table offset/size */
+
+# define PGTABLE_L2_OFFSET 0x000002400
+# define PGTABLE_L2_SIZE 0x000001800
+# endif
#else
+ /* Memory map
+ * VIRTUAL ADDRESS RANGE L1 PG TABLE L2 PG TABLE DESCRIPTION
+ * START END OFFSET SIZE
+ * ---------- ---------- ------------ ----------------------------
+ * 0x80000000 0x806fffff 0x000002000 0x000001c00 Paging (7MiB)
+ *
+ * If SMP is enabled, then 1MiB of address spaces for the INTERCPU_L2_PAGES
+ * pages are taken from the end of the Paging L2 page table to hold non-
+ * cacheable, inter-processor communication data.
+ */
+
+# if defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
/* Paging L2 page table offset/size */
-# define PGTABLE_L2_OFFSET 0x000002000
-# define PGTABLE_L2_SIZE 0x000001c00
+# define PGTABLE_L2_OFFSET 0x000002000
+# define PGTABLE_L2_SIZE 0x000001800
+
+# else
+ /* Paging L2 page table offset/size */
+
+# define PGTABLE_L2_OFFSET 0x000002000
+# define PGTABLE_L2_SIZE 0x000001c00
+# endif
+
#endif
/* Paging L2 page table base addresses
@@ -959,6 +1013,23 @@
#define PGTABLE_L2_END_PADDR (PGTABLE_L2_PBASE + PGTABLE_L2_SIZE)
#define PGTABLE_L2_END_VADDR (PGTABLE_L2_VBASE + PGTABLE_L2_SIZE)
+#if defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
+/* Non-cached inter-processor communication data */
+
+# define INTERCPU_L2_OFFSET (PGTABLE_L2_OFFSET + PGTABLE_L2_SIZE)
+# define INTERCPU_L2_SIZE (0x00000400)
+
+/* Non-cached inter-processor communication page table base addresses */
+
+# define INTERCPU_L2_PBASE (PGTABLE_BASE_PADDR + INTERCPU_L2_OFFSET)
+# define INTERCPU_L2_VBASE (PGTABLE_BASE_VADDR + INTERCPU_L2_OFFSET)
+
+/* Non-cached inter-processor communication end addresses */
+
+# define INTERCPU_L2_END_PADDR (INTERCPU_L2_PBASE + INTERCPU_L2_SIZE)
+# define INTERCPU_L2_END_VADDR (INTERCPU_L2_VBASE + INTERCPU_L2_SIZE)
+#endif
+
/* Base address of the interrupt vector table.
*
* IMX_VECTOR_PADDR - Unmapped, physical address of vector table in SRAM
@@ -974,19 +1045,62 @@
*/
#ifdef CONFIG_ARCH_LOWVECTORS /* Vectors located at 0x0000:0000 */
-
- /* Vectors will always lie at the beginnin of OCRAM */
+/* Vectors will always lie at the beginning of OCRAM
+ *
+ * OCRAM Memory Map:
+ * ---------- ---------- ---------------------------
+ * START END CONTENT
+ * ---------- ---------- ---------------------------
+ * 0x00000000 0x00010000 Vectors (VECTOR_TABLE_SIZE)
+ * 0x00010000 0x00011000 Inter-CPU communications
+ * 0x00011000 0x0003c000 Unused
+ * 0x0003c000 0x00004000 Page table (PGTABLE_SIZE)
+ */
# define IMX_VECTOR_PADDR IMX_OCRAM_PBASE
# define IMX_VECTOR_VSRAM IMX_OCRAM_VBASE
# define IMX_VECTOR_VADDR 0x00000000
+#if defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
+/* Inter-processor communications.
+ *
+ * NOTICE that we use the unused virtual address space at 0x00400000 for
+ * the inter-CPU virtual communication area.
+ */
+
+# define INTERCPU_PADDR (IMX_VECTOR_PADDR + VECTOR_TABLE_SIZE)
+# define INTERCPU_VADDR (0x00400000)
+# define INTERCPU_SIZE (INTERCPU_L2_PAGES << 12)
+# define INTERCPU_VSRAM (IMX_VECTOR_VSRAM + VECTOR_TABLE_SIZE)
+#endif
+
#else /* Vectors located at 0xffff:0000 -- this probably does not work */
+/* OCRAM Memory Map:
+ * ---------- ---------- ---------------------------
+ * START END CONTENT
+ * ---------- ---------- ---------------------------
+ * 0x00000000 0x00004000 Page table (PGTABLE_SIZE)
+ * 0x00004000 0x0002f000 Unused
+ * 0x0002f000 0x00030000 Inter-CPU communications
+ * 0x00030000 0x00010000 Vectors (VECTOR_TABLE_SIZE)
+ */
# define IMX_VECTOR_PADDR (IMX_OCRAM_PBASE + IMX_OCRAM_SIZE - VECTOR_TABLE_SIZE)
# define IMX_VECTOR_VSRAM (IMX_OCRAM_VBASE + IMX_OCRAM_SIZE - VECTOR_TABLE_SIZE)
# define IMX_VECTOR_VADDR 0xffff0000
+#if defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
+/* Inter-processor communications
+ *
+ * NOTICE that we use the unused virtual address space at 0x00400000 for
+ * the inter-CPU virtual communication area.
+ */
+
+# define INTERCPU_PADDR (IMX_VECTOR_PADDR - INTERCPU_L2_SIZE)
+# define INTERCPU_VADDR (0x00400000)
+# define INTERCPU_SIZE (INTERCPU_L2_PAGES << 12)
+# define INTERCPU_VSRAM (IMX_VECTOR_VSRAM - INTERCPU_L2_SIZE)
+#endif
#endif
/************************************************************************************
diff --git a/arch/arm/src/imx6/imx_boot.c b/arch/arm/src/imx6/imx_boot.c
index edfd5304a14..888baf53ae8 100644
--- a/arch/arm/src/imx6/imx_boot.c
+++ b/arch/arm/src/imx6/imx_boot.c
@@ -52,6 +52,7 @@
#include "chip.h"
#include "arm.h"
#include "mmu.h"
+#include "scu.h"
#include "cache.h"
#include "fpu.h"
#include "up_internal.h"
@@ -64,6 +65,16 @@
#include "imx_serial.h"
#include "imx_boot.h"
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#ifdef CONFIG_DEBUG_FEATURES
+# define PROGRESS(c) imx_lowputc(c)
+#else
+# define PROGRESS(c)
+#endif
+
/****************************************************************************
* Public Data
****************************************************************************/
@@ -224,6 +235,48 @@ static void imx_vectormapping(void)
# define imx_vectormapping()
#endif
+/****************************************************************************
+ * Name: imx_intercpu_mapping
+ *
+ * Description:
+ * Setup a special mapping for the non-cached, inter-cpu communications
+ * area.
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
+static void imx_intercpu_mapping(void)
+{
+ uint32_t intercpu_paddr = INTERCPU_PADDR & PTE_SMALL_PADDR_MASK;
+ uint32_t intercpu_vaddr = INTERCPU_VADDR & PTE_SMALL_PADDR_MASK;
+ uint32_t end_paddr = INTERCPU_PADDR + INTERCPU_SIZE;
+
+ DEBUGASSERT(intercpu_vaddr == (uint32_t)&_snocache);
+
+ /* We want to keep the inter-cpu region in on-chip RAM (OCRAM). The
+ * i.MX6 has 256Kb of OCRAM positioned at physical address 0x0090:0000.
+ */
+
+ while (intercpu_paddr < end_paddr)
+ {
+ mmu_l2_setentry(INTERCPU_L2_VBASE, intercpu_paddr, intercpu_vaddr,
+ MMU_L2_INTERCPUFLAGS);
+ intercpu_paddr += 4096;
+ intercpu_vaddr += 4096;
+ }
+
+ /* Now set the level 1 descriptor to refer to the level 2 page table. */
+
+ mmu_l1_setentry(INTERCPU_L2_PBASE & PMD_PTE_PADDR_MASK,
+ INTERCPU_VADDR & PMD_PTE_PADDR_MASK,
+ MMU_L1_INTERCPUFLAGS);
+}
+#else
+ /* No inter-cpu communications area */
+
+# define imx_intercpu_mapping()
+#endif
+
/****************************************************************************
* Name: imx_copyvectorblock
*
@@ -388,8 +441,10 @@ static inline void imx_wdtdisable(void)
void arm_boot(void)
{
-#ifdef CONFIG_ARCH_RAMFUNCS
+#if defined(CONFIG_ARCH_RAMFUNCS)
const uint32_t *src;
+#endif
+#if defined(CONFIG_ARCH_RAMFUNCS) || defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
uint32_t *dest;
#endif
@@ -398,7 +453,7 @@ void arm_boot(void)
*/
imx_setupmappings();
- imx_lowputc('A');
+ PROGRESS('A');
/* Make sure that all other CPUs are in the disabled state. This is a
* formality because the other CPUs are actually running then we have
@@ -406,13 +461,30 @@ void arm_boot(void)
*/
imx_cpu_disable();
+ PROGRESS('B');
+
+#ifdef CONFIG_SMP
+ /* Enable SMP cache coherency for CPU0 */
+
+ arm_enable_smp(0);
+ PROGRESS('C');
+#endif
/* Provide a special mapping for the OCRAM interrupt vector positioned in
* high memory.
*/
imx_vectormapping();
- imx_lowputc('B');
+ PROGRESS('D');
+
+#if defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
+ /* Provide a special mapping for the OCRAM interrupt vector positioned in
+ * high memory.
+ */
+
+ imx_intercpu_mapping();
+ PROGRESS('E');
+#endif
#ifdef CONFIG_ARCH_RAMFUNCS
/* Copy any necessary code sections from FLASH to RAM. The correct
@@ -426,14 +498,14 @@ void arm_boot(void)
*dest++ = *src++;
}
- imx_lowputc('C');
+ PROGRESS('F');
/* Flush the copied RAM functions into physical RAM so that will
* be available when fetched into the I-Cache.
*/
arch_clean_dcache((uintptr_t)&_sramfuncs, (uintptr_t)&_eramfuncs)
- imx_lowputc('D');
+ PROGRESS('G');
#endif
/* Setup up vector block. _vector_start and _vector_end are exported from
@@ -441,37 +513,35 @@ void arm_boot(void)
*/
imx_copyvectorblock();
- imx_lowputc('E');
+ PROGRESS('H');
/* Disable the watchdog timer */
imx_wdtdisable();
- imx_lowputc('F');
+ PROGRESS('I');
/* Initialize clocking to settings provided by board-specific logic */
imx_clockconfig();
- imx_lowputc('G');
+ PROGRESS('J');
#ifdef CONFIG_ARCH_FPU
/* Initialize the FPU */
arm_fpuconfig();
- imx_lowputc('H');
+ PROGRESS('K');
#endif
- /* Perform board-specific initialization, This must include:
- *
- * - Initialization of board-specific memory resources (e.g., SDRAM)
- * - Configuration of board specific resources (PIOs, LEDs, etc).
+ /* Perform board-specific memroy initialization, This must include
+ * initialization of board-specific memory resources (e.g., SDRAM)
*
* NOTE: We must use caution prior to this point to make sure that
* the logic does not access any global variables that might lie
* in SDRAM.
*/
- imx_board_initialize();
- imx_lowputc('I');
+ imx_memory_initialize();
+ PROGRESS('L');
#ifdef NEED_SDRAM_REMAPPING
/* SDRAM was configured in a temporary state to support low-level
@@ -480,7 +550,7 @@ void arm_boot(void)
*/
imx_remap();
- imx_lowputc('J');
+ PROGRESS('M');
#endif
#ifdef CONFIG_BOOT_SDRAM_DATA
@@ -489,13 +559,31 @@ void arm_boot(void)
*/
arm_data_initialize();
- imx_lowputc('K');
+ PROGRESS('N');
+#endif
+
+ /* Perform board-specific device initialization. This would include
+ * configuration of board specific resources such as GPIOs, LEDs, etc.
+ */
+
+ imx_board_initialize();
+ PROGRESS('O');
+
+#if defined(CONFIG_SMP) && defined(SMP_INTERCPU_NONCACHED)
+ /* Initialize the uncached, inter-CPU communications area */
+
+ for (dest = &_snocache; dest < &_enocache; )
+ {
+ *dest++ = 0;
+ }
+
+ PROGRESS('P');
#endif
/* Perform common, low-level chip initialization (might do nothing) */
imx_lowsetup();
- imx_lowputc('L');
+ PROGRESS('Q');
#ifdef USE_EARLYSERIALINIT
/* Perform early serial initialization if we are going to use the serial
@@ -503,7 +591,7 @@ void arm_boot(void)
*/
imx_earlyserialinit();
- imx_lowputc('M');
+ PROGRESS('R');
#endif
/* Now we can enable all other CPUs. The enabled CPUs will start execution
@@ -512,6 +600,6 @@ void arm_boot(void)
*/
imx_cpu_enable();
- imx_lowputc('N');
- imx_lowputc('\n');
+ PROGRESS('S');
+ PROGRESS('\n');
}
diff --git a/arch/arm/src/imx6/imx_boot.h b/arch/arm/src/imx6/imx_boot.h
index 11c1ef56fe3..7f98d347acd 100644
--- a/arch/arm/src/imx6/imx_boot.h
+++ b/arch/arm/src/imx6/imx_boot.h
@@ -110,14 +110,37 @@ void imx_cpu_enable(void);
# define imx_cpu_enable()
#endif
+/****************************************************************************
+ * Name: imx_memory_initialize
+ *
+ * Description:
+ * All i.MX6 architectures must provide the following entry point. This
+ * entry point is called early in the initialization before memory has
+ * been configured. This board-specific function is responsible for
+ * configuring any on-board memories.
+ *
+ * Logic in imx_memory_initialize must be careful to avoid using any
+ * global variables because those will be uninitialized at the time this
+ * function is called.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+void imx_memory_initialize(void);
+
/****************************************************************************
* Name: imx_board_initialize
*
* Description:
* All i.MX6 architectures must provide the following entry point. This
- * entry point is called early in the initialization -- after all memory
- * has been configured and mapped but before any devices have been
- * initialized.
+ * entry point is called in the initialization phase -- after
+ * imx_memory_initialize and after all memory has been configured and
+ * mapped but before any devices have been initialized.
*
* Input Parameters:
* None
diff --git a/arch/arm/src/imx6/imx_cpuboot.c b/arch/arm/src/imx6/imx_cpuboot.c
index 50b23b5c1d4..818b327a4bc 100644
--- a/arch/arm/src/imx6/imx_cpuboot.c
+++ b/arch/arm/src/imx6/imx_cpuboot.c
@@ -51,9 +51,9 @@
#include "chip/imx_src.h"
#include "sctlr.h"
#include "smp.h"
+#include "scu.h"
#include "fpu.h"
#include "gic.h"
-#include "cp15_cacheops.h"
#ifdef CONFIG_SMP
@@ -260,6 +260,10 @@ void imx_cpu_enable(void)
void arm_cpu_boot(int cpu)
{
+ /* Enable SMP cache coherency for the CPU */
+
+ arm_enable_smp(cpu);
+
#ifdef CONFIG_ARCH_FPU
/* Initialize the FPU */
@@ -297,10 +301,6 @@ void arm_cpu_boot(int cpu)
(void)up_irq_enable();
#endif
- /* Invalidate CPUn L1 so that is will be reloaded from coherent L2. */
-
- cp15_invalidate_dcache_all();
-
/* The next thing that we expect to happen is for logic running on CPU0
* to call up_cpu_start() which generate an SGI and a context switch to
* the configured NuttX IDLE task.
diff --git a/arch/arm/src/imx6/imx_ecspi.c b/arch/arm/src/imx6/imx_ecspi.c
new file mode 100644
index 00000000000..15c602a7c96
--- /dev/null
+++ b/arch/arm/src/imx6/imx_ecspi.c
@@ -0,0 +1,1445 @@
+/****************************************************************************
+ * arch/arm/src/imx6/imx_ecspi.c
+ *
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Derives from the i.MX1 CSPI driver:
+ *
+ * Copyright (C) 2009-2010, 2013, 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include
+#include
+
+#include "up_internal.h"
+#include "up_arch.h"
+
+#include "chip.h"
+#include "imx_gpio.h"
+#include "imx_ecspi.h"
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* The i.MX6 supports 25SPI interfaces. Which have been enabled? */
+
+#define __SPI1_NDX 0
+
+#ifdef CONFIG_IMX6_ECSPI1
+# define SPI1_NDX __SPI1_NDX
+# define __SPI1_PRESENT 1
+# define __SPI2_NDX (__SPI1_NDX + 1)
+#else
+# define __SPI1_PRESENT 0
+# define __SPI2_NDX __SPI1_NDX
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI2
+# define SPI2_NDX __SPI2_NDX
+# define __SPI2_PRESENT 1
+# define __SPI3_NDX (__SPI2_NDX + 1)
+#else
+# define __SPI2_PRESENT 0
+# define __SPI3_NDX __SPI2_NDX
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI3
+# define SPI3_NDX __SPI3_NDX
+# define __SPI3_PRESENT 1
+# define __SPI4_NDX (__SPI3_NDX + 1)
+#else
+# define __SPI3_PRESENT 0
+# define __SPI4_NDX __SPI3_NDX
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI4
+# define SPI4_NDX __SPI4_NDX
+# define __SPI4_PRESENT 1
+# define __SPI5_NDX (__SPI4_NDX + 1)
+#else
+# define __SPI4_PRESENT 0
+# define __SPI5_NDX __SPI5_NDX
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI5
+# define SPI5_NDX __SPI5_NDX
+# define __SPI5_PRESENT 1
+# define __SPI6_NDX (__SPI5_NDX + 1)
+#else
+# define __SPI5_PRESENT 0
+# define __SPI6_NDX __SPI5_NDX
+#endif
+
+#define NSPIS (__SPI1_PRESENT + __SPI2_PRESENT + __SPI3_PRESENT + \
+ __SPI4_PRESENT + __SPI5_PRESENT)
+
+/* Compile the rest of the file only if at least one SPI interface has been
+ * enabled.
+ */
+
+#if NSPIS > 0
+
+/* The number of words that will fit in the Tx FIFO */
+
+#define IMX_TXFIFO_WORDS 8
+
+/****************************************************************************
+ * Private Type Definitions
+ ****************************************************************************/
+
+ /* Per SPI callouts to board-specific logic */
+
+typedef CODE void (*imx_select_t)(FAR struct spi_dev_s *dev,
+ enum spi_dev_e devid, bool selected);
+typedef CODE uint8_t (*imx_status_t)(FAR struct spi_dev_s *dev,
+ enum spi_dev_e devid);
+#ifdef CONFIG_SPI_CMDDATA
+typedef CODE int (*imx_cmddata_t)(FAR struct spi_dev_s *dev,
+ enum spi_dev_e devid, bool cmd);
+#endif
+
+struct imx_spidev_s
+{
+ const struct spi_ops_s *ops; /* Common SPI operations */
+#ifndef CONFIG_SPI_POLLWAIT
+ sem_t waitsem; /* Wait for transfer to complete */
+#endif
+ sem_t exclsem; /* Supports mutually exclusive access */
+
+ /* These following are the source and destination buffers of the transfer.
+ * they are retained in this structure so that they will be accessible
+ * from an interrupt handler. The actual type of the buffer is uint8_t is
+ * nbits <=8 and uint16_t is nbits >8.
+ */
+
+ void *txbuffer; /* Source buffer */
+ void *rxbuffer; /* Destination buffer */
+
+ /* These are functions pointers that are configured to perform the
+ * appropriate transfer for the particular kind of exchange that is
+ * occurring. Differnt functions may be selected depending on (1)
+ * if the tx or txbuffer is NULL and depending on the number of bits
+ * per word.
+ */
+
+ void (*txword)(struct imx_spidev_s *priv);
+ void (*rxword)(struct imx_spidev_s *priv);
+
+ uint32_t base; /* SPI register base address */
+ uint32_t frequency; /* Current desired SCLK frequency */
+ uint32_t actual; /* Current actual SCLK frequency */
+
+ int ntxwords; /* Number of words left to transfer on the Tx FIFO */
+ int nrxwords; /* Number of words received on the Rx FIFO */
+ int nwords; /* Number of words to be exchanged */
+
+ uint8_t mode; /* Current mode */
+ uint8_t nbits; /* Current number of bits per word */
+ uint8_t spindx; /* SPI index */
+#ifndef CONFIG_SPI_POLLWAIT
+ uint8_t irq; /* SPI IRQ number */
+ xcpt_t handler; /* ECSPI interrupt handler */
+#endif
+
+ /* Per SPI callouts to board-specific logic */
+
+ imx_select_t select; /* Select callout */
+ imx_status_t status; /* Status callout */
+#ifdef CONFIG_SPI_CMDDATA
+ imx_cmddata_t cmddata; /* Cmddata callout */
+#endif
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* SPI register access */
+
+static inline uint32_t spi_getreg(struct imx_spidev_s *priv, unsigned int offset);
+static inline void spi_putreg(struct imx_spidev_s *priv, unsigned int offset, uint32_t value);
+
+/* SPI data transfer */
+
+static void spi_txnull(struct imx_spidev_s *priv);
+static void spi_txuint16(struct imx_spidev_s *priv);
+static void spi_txuint8(struct imx_spidev_s *priv);
+static void spi_rxnull(struct imx_spidev_s *priv);
+static void spi_rxuint16(struct imx_spidev_s *priv);
+static void spi_rxuint8(struct imx_spidev_s *priv);
+static int spi_performtx(struct imx_spidev_s *priv);
+static inline void spi_performrx(struct imx_spidev_s *priv);
+static int spi_transfer(struct imx_spidev_s *priv, const void *txbuffer,
+ void *rxbuffer, unsigned int nwords);
+
+/* Interrupt handling */
+
+#ifndef CONFIG_SPI_POLLWAIT
+static int spi_interrupt(struct imx_spidev_s *priv);
+#ifdef CONFIG_IMX6_ECSPI1
+static int ecspi1_interrupt(int irq, void *context);
+#endif
+#ifdef CONFIG_IMX6_ECSPI2
+static int ecspi2_interrupt(int irq, void *context);
+#endif
+#ifdef CONFIG_IMX6_ECSPI3
+static int ecspi3_interrupt(int irq, void *context);
+#endif
+#ifdef CONFIG_IMX6_ECSPI4
+static int ecspi4_interrupt(int irq, void *context);
+#endif
+#ifdef CONFIG_IMX6_ECSPI5
+static int ecspi5_interrupt(int irq, void *context);
+#endif
+#endif
+
+/* SPI methods */
+
+static int spi_lock(FAR struct spi_dev_s *dev, bool lock);
+static void spi_select(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
+ bool selected);
+static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev,
+ uint32_t frequency);
+static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode);
+static void spi_setbits(FAR struct spi_dev_s *dev, int nbits);
+static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t wd);
+static uint8_t spi_status(FAR struct spi_dev_s *dev, enum spi_dev_e devid);
+#ifdef CONFIG_SPI_CMDDATA
+static int spi_cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
+ bool cmd);
+#endif
+#ifdef CONFIG_SPI_EXCHANGE
+static void spi_exchange(FAR struct spi_dev_s *dev,
+ FAR const void *txbuffer,
+ FAR void *rxbuffer, size_t nwords);
+#else
+static void spi_sndblock(FAR struct spi_dev_s *dev,
+ FAR const void *buffer, size_t nwords);
+static void spi_recvblock(FAR struct spi_dev_s *dev,
+ FAR void *buffer, size_t nwords);
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* Common SPI operations */
+
+static const struct spi_ops_s g_spiops =
+{
+ .lock = spi_lock,
+ .select = spi_select, /* Provided externally by board logic */
+ .setfrequency = spi_setfrequency,
+ .setmode = spi_setmode,
+ .setbits = spi_setbits,
+#ifdef CONFIG_SPI_HWFEATURES
+ .hwfeatures = 0, /* Not supported */
+#endif
+ .status = spi_status, /* Provided externally by board logic */
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = spi_cmddata,
+#endif
+ .send = spi_send,
+#ifdef CONFIG_SPI_EXCHANGE
+ .exchange = spi_exchange,
+#else
+ .sndblock = spi_sndblock,
+ .recvblock = spi_recvblock,
+#endif
+};
+
+/* This supports is up to five SPI busses/ports */
+
+static struct imx_spidev_s g_spidev[] =
+{
+#ifdef CONFIG_IMX6_ECSPI1
+ {
+ .ops = &g_spiops,
+ .base = IMX_ECSPI1_VBASE,
+ .spindx = SPI1_NDX,
+#ifndef CONFIG_SPI_POLLWAIT
+ .irq = IMX_IRQ_ECSPI1,
+ .handler = ecspi1_interrupt,
+#endif
+ .select = imx_spi1select,
+ .status = imx_spi1status,
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = imx_spi1cmddata,
+#endif
+ }
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI2
+ , {
+ .ops = &g_spiops,
+ .base = IMX_ECSPI2_VBASE,
+ .spindx = SPI2_NDX,
+#ifndef CONFIG_SPI_POLLWAIT
+ .irq = IMX_IRQ_ECSPI2,
+ .handler = ecspi2_interrupt,
+#endif
+ .select = imx_spi2select,
+ .status = imx_spi2status,
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = imx_spi2cmddata,
+#endif
+ }
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI3
+ , {
+ .ops = &g_spiops,
+ .base = IMX_ECSPI3_VBASE,
+ .spindx = SPI3_NDX,
+#ifndef CONFIG_SPI_POLLWAIT
+ .irq = IMX_IRQ_ECSPI3,
+ .handler = ecspi3_interrupt,
+#endif
+ .select = imx_spi3select,
+ .status = imx_spi3status,
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = imx_spi3cmddata,
+#endif
+ }
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI4
+ , {
+ .ops = &g_spiops,
+ .base = IMX_ECSPI4_VBASE,
+ .spindx = SPI4_NDX,
+#ifndef CONFIG_SPI_POLLWAIT
+ .irq = IMX_IRQ_ECSPI4,
+ .handler = ecspi4_interrupt,
+#endif
+ .select = imx_spi4select,
+ .status = imx_spi4status,
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = imx_spi4cmddata,
+#endif
+ }
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI5
+ , {
+ .ops = &g_spiops,
+ .base = IMX_ECSPI5_VBASE,
+ .spindx = SPI5_NDX,
+#ifndef CONFIG_SPI_POLLWAIT
+ .irq = IMX_IRQ_ECSPI5,
+ .handler = ecspi5_interrupt,
+#endif
+ .select = imx_spi5select,
+ .status = imx_spi5status,
+#ifdef CONFIG_SPI_CMDDATA
+ .cmddata = imx_spi5cmddata,
+#endif
+ }
+#endif
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: spi_getreg
+ *
+ * Description:
+ * Read the SPI register at this offeset
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * offset - Offset to the SPI register from the register base address
+ *
+ * Returned Value:
+ * Value of the register at this offset
+ *
+ ****************************************************************************/
+
+static inline uint32_t spi_getreg(struct imx_spidev_s *priv, unsigned int offset)
+{
+ return getreg32(priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: spi_putreg
+ *
+ * Description:
+ * Write the value to the SPI register at this offeset
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * offset - Offset to the SPI register from the register base address
+ * value - Value to write
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void spi_putreg(struct imx_spidev_s *priv, unsigned int offset, uint32_t value)
+{
+ putreg32(value, priv->base + offset);
+}
+
+/****************************************************************************
+ * Name: spi_txnull, spi_txuint16, and spi_txuint8
+ *
+ * Description:
+ * Transfer all ones, a uint8_t, or uint16_t to Tx FIFO and update the txbuffer
+ * pointer appropriately. The selected function dependes on (1) if there
+ * is a source txbuffer provided, and (2) if the number of bits per
+ * word is <=8 or >8.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void spi_txnull(struct imx_spidev_s *priv)
+{
+ spi_putreg(priv, ECSPI_TXDATA_OFFSET, 0xffff);
+}
+
+static void spi_txuint16(struct imx_spidev_s *priv)
+{
+ uint16_t *ptr = (uint16_t *)priv->txbuffer;
+ spi_putreg(priv, ECSPI_TXDATA_OFFSET, *ptr++);
+ priv->txbuffer = (void *)ptr;
+}
+
+static void spi_txuint8(struct imx_spidev_s *priv)
+{
+ uint8_t *ptr = (uint8_t *)priv->txbuffer;
+ spi_putreg(priv, ECSPI_TXDATA_OFFSET, *ptr++);
+ priv->txbuffer = (void *)ptr;
+}
+
+/****************************************************************************
+ * Name: spi_rxnull,spi_rxuint16, and spi_rxuint8
+ *
+ * Description:
+ * Discard input, save a uint8_t, or or save a uint16_t from Tx FIFO in the
+ * user rxvbuffer and update the rxbuffer pointer appropriately. The
+ * selected function dependes on (1) if there is a desination rxbuffer
+ * provided, and (2) if the number of bits per word is <=8 or >8.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void spi_rxnull(struct imx_spidev_s *priv)
+{
+ (void)spi_getreg(priv, ECSPI_RXDATA_OFFSET);
+}
+
+static void spi_rxuint16(struct imx_spidev_s *priv)
+{
+ uint16_t *ptr = (uint16_t *)priv->rxbuffer;
+ *ptr++ = (uint16_t)spi_getreg(priv, ECSPI_TXDATA_OFFSET);
+ priv->rxbuffer = (void *)ptr;
+}
+
+static void spi_rxuint8(struct imx_spidev_s *priv)
+{
+ uint8_t *ptr = (uint8_t *)priv->rxbuffer;
+ *ptr++ = (uint8_t)spi_getreg(priv, ECSPI_TXDATA_OFFSET);
+ priv->rxbuffer = (void *)ptr;
+}
+
+/****************************************************************************
+ * Name: spi_performtx
+ *
+ * Description:
+ * If the Tx FIFO is empty, then transfer as many words as we can to
+ * the FIFO.
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * The number of words written to the Tx FIFO (a value from 0 to 8,
+ * inclusive).
+ *
+ ****************************************************************************/
+
+static int spi_performtx(struct imx_spidev_s *priv)
+{
+ uint32_t regval;
+ int ntxd = 0; /* Number of words written to Tx FIFO */
+
+ /* Check if the Tx FIFO is empty */
+
+ if ((spi_getreg(priv, ECSPI_STATREG_OFFSET) & ECSPI_INT_TE) != 0)
+ {
+ /* Check if all of the Tx words have been sent */
+
+ if (priv->ntxwords > 0)
+ {
+ /* No.. Transfer more words until either the TxFIFO is full or
+ * until all of the user provided data has been sent.
+ */
+
+ for (; ntxd < priv->ntxwords && ntxd < IMX_TXFIFO_WORDS; ntxd++)
+ {
+ priv->txword(priv);
+ }
+
+ /* Update the count of words to to transferred */
+
+ priv->ntxwords -= ntxd;
+ }
+ else
+ {
+ /* Yes.. The transfer is complete, disable Tx FIFO empty interrupt */
+
+ regval = spi_getreg(priv, ECSPI_INTREG_OFFSET);
+ regval &= ~ECSPI_INT_TE;
+ spi_putreg(priv, ECSPI_INTREG_OFFSET, regval);
+ }
+ }
+ return ntxd;
+}
+
+/****************************************************************************
+ * Name: spi_performrx
+ *
+ * Description:
+ * Transfer as many bytes as possible from the Rx FIFO to the user Rx
+ * buffer (if one was provided).
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static inline void spi_performrx(struct imx_spidev_s *priv)
+{
+ /* Loop while data is available in the Rx FIFO */
+
+ while ((spi_getreg(priv, ECSPI_STATREG_OFFSET) & ECSPI_INT_RR) != 0)
+ {
+ /* Have all of the requested words been transferred from the Rx FIFO? */
+
+ if (priv->nrxwords < priv->nwords)
+ {
+ /* No.. Read more data from Rx FIFO */
+
+ priv->rxword(priv);
+ priv->nrxwords++;
+ }
+ }
+}
+
+/****************************************************************************
+ * Name: spi_startxfr
+ *
+ * Description:
+ * If data was added to the Tx FIFO, then start the exchange
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * ntxd - The number of bytes added to the Tx FIFO by spi_performtx.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void spi_startxfr(struct imx_spidev_s *priv, int ntxd)
+{
+ uint32_t regval;
+
+ /* The XCH bit initiates an exchange in master mode. It remains set
+ * remains set while the exchange is in progress but is automatically
+ * clear when all data in the Tx FIFO and shift register are shifted out.
+ * So if we have added data to the Tx FIFO on this interrupt, we must
+ * set the XCH bit to resume the exchange.
+ */
+
+ if (ntxd > 0)
+ {
+ regval = spi_getreg(priv, ECSPI_CONREG_OFFSET);
+ regval |= ECSPI_CONREG_XCH;
+ spi_putreg(priv, ECSPI_CONREG_OFFSET, regval);
+ }
+}
+
+/****************************************************************************
+ * Name: spi_transfer
+ *
+ * Description:
+ * Exchange a block data with the SPI device
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ * txbuffer - The buffer of data to send to the device (may be NULL).
+ * rxbuffer - The buffer to receive data from the device (may be NULL).
+ * nwords - The total number of words to be exchanged. If the interface
+ * uses <= 8 bits per word, then this is the number of uint8_t's;
+ * if the interface uses >8 bits per word, then this is the
+ * number of uint16_t's
+ *
+ * Returned Value:
+ * 0: success, <0:Negated error number on failure
+ *
+ ****************************************************************************/
+
+static int spi_transfer(struct imx_spidev_s *priv, const void *txbuffer,
+ void *rxbuffer, unsigned int nwords)
+{
+#ifndef CONFIG_SPI_POLLWAIT
+ irqstate_t flags;
+ uint32_t regval;
+ int ret;
+#endif
+ int ntxd;
+
+ /* Set up to perform the transfer */
+
+ priv->txbuffer = (uint8_t *)txbuffer; /* Source buffer */
+ priv->rxbuffer = (uint8_t *)rxbuffer; /* Destination buffer */
+ priv->ntxwords = nwords; /* Number of words left to send */
+ priv->nrxwords = 0; /* Number of words received */
+ priv->nwords = nwords; /* Total number of exchanges */
+
+ /* Set up the low-level data transfer function pointers */
+
+ if (priv->nbits > 8)
+ {
+ priv->txword = spi_txuint16;
+ priv->rxword = spi_rxuint16;
+ }
+ else
+ {
+ priv->txword = spi_txuint8;
+ priv->rxword = spi_rxuint8;
+ }
+
+ if (!txbuffer)
+ {
+ priv->txword = spi_txnull;
+ }
+
+ if (!rxbuffer)
+ {
+ priv->rxword = spi_rxnull;
+ }
+
+ /* Prime the Tx FIFO to start the sequence (saves one interrupt) */
+
+#ifndef CONFIG_SPI_POLLWAIT
+ flags = enter_critical_section();
+ ntxd = spi_performtx(priv);
+ spi_startxfr(priv, ntxd);
+
+ /* Enable transmit empty interrupt */
+
+ regval = spi_getreg(priv, ECSPI_INTREG_OFFSET);
+ regval |= ECSPI_INT_TE;
+ spi_putreg(priv, ECSPI_INTREG_OFFSET, regval);
+ leave_critical_section(flags);
+
+ /* Wait for the transfer to complete. Since there is no handshake
+ * with SPI, the following should complete even if there are problems
+ * with the transfer, so it should be safe with no timeout.
+ */
+
+ do
+ {
+ /* Wait to be signaled from the interrupt handler */
+
+ ret = sem_wait(&priv->waitsem);
+ }
+ while (ret < 0 && errno == EINTR);
+
+#else
+ /* Perform the transfer using polling logic. This will totally
+ * dominate the CPU until the transfer is complete. Only recommended
+ * if (1) your SPI is very fast, and (2) if you only use very short
+ * transfers.
+ */
+
+ do
+ {
+ /* Handle outgoing Tx FIFO transfers */
+
+ ntxd = spi_performtx(priv);
+
+ /* Handle incoming Rx FIFO transfers */
+
+ spi_performrx(priv);
+
+ /* Resume the transfer */
+
+ spi_startxfr(priv, ntxd);
+
+ /* If there are other threads at this same priority level,
+ * the following may help:
+ */
+
+ sched_yield();
+ }
+ while (priv->nrxwords < priv->nwords);
+#endif
+ return OK;
+}
+
+/****************************************************************************
+ * Name: spi_interrupt
+ *
+ * Description:
+ * Common ECSPI interrupt handling logic
+ *
+ * Input Parameters:
+ * priv - Device-specific state data
+ *
+ * Returned Value:
+ * 0: success, <0:Negated error number on failure
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SPI_POLLWAIT
+static int spi_interrupt(struct imx_spidev_s *priv)
+{
+ int ntxd;
+
+ DEBUGASSERT(priv != NULL);
+
+ /* Handle outgoing Tx FIFO transfers */
+
+ ntxd = spi_performtx(priv);
+
+ /* Handle incoming Rx FIFO transfers */
+
+ spi_performrx(priv);
+
+ /* Resume the transfer */
+
+ spi_startxfr(priv, ntxd);
+
+ /* Check if the transfer is complete */
+
+ if (priv->nrxwords >= priv->nwords)
+ {
+ /* Yes, wake up the waiting thread */
+
+ sem_post(&priv->waitsem);
+ }
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Name: ecspiN_interrupt, N=1..5
+ *
+ * Description:
+ * Individual ECPSI interrupt handlers.
+ *
+ * Input Parameters:
+ * Standard interrupt handler inputs
+ *
+ * Returned Value:
+ * 0: success, <0:Negated error number on failure
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SPI_POLLWAIT
+#ifdef CONFIG_IMX6_ECSPI1
+static int ecspi1_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spidev[SPI1_NDX]);
+}
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI2
+static int ecspi2_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spidev[SPI2_NDX]);
+}
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI3
+static int ecspi3_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spidev[SPI3_NDX]);
+}
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI4
+static int ecspi4_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spidev[SPI4_NDX]);
+}
+#endif
+
+#ifdef CONFIG_IMX6_ECSPI5
+static int ecspi5_interrupt(int irq, void *context)
+{
+ return spi_interrupt(&g_spidev[SPI5_NDX]);
+}
+#endif
+#endif
+
+/****************************************************************************
+ * Name: spi_lock
+ *
+ * Description:
+ * On SPI busses where there are multiple devices, it will be necessary to
+ * lock SPI to have exclusive access to the busses for a sequence of
+ * transfers. The bus should be locked before the chip is selected. After
+ * locking the SPI bus, the caller should then also call the setfrequency,
+ * setbits, and setmode methods to make sure that the SPI is properly
+ * configured for the device. If the SPI buss is being shared, then it
+ * may have been left in an incompatible state.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * lock - true: Lock spi bus, false: unlock SPI bus
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static int spi_lock(FAR struct spi_dev_s *dev, bool lock)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+
+ if (lock)
+ {
+ /* Take the semaphore (perhaps waiting) */
+
+ while (sem_wait(&priv->exclsem) != 0)
+ {
+ /* The only case that an error should occur here is if the wait
+ * was awakened by a signal.
+ */
+
+ DEBUGASSERT(errno == EINTR);
+ }
+ }
+ else
+ {
+ (void)sem_post(&priv->exclsem);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: spi_select
+ *
+ * Description:
+ * Enable/disable the SPI chip select. The implementation of this method
+ * must include handshaking: If a device is selected, it must hold off
+ * all other attempts to select the device until the device is deselected.
+ * Required.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * devid - Identifies the device to select
+ * selected - true: slave selected, false: slave de-selected
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void spi_select(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
+ bool selected)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+
+ DEBUGASSERT(priv != NULL && priv->select != NULL);
+ priv->select(dev, devid, selected);
+}
+
+/****************************************************************************
+ * Name: spi_setfrequency
+ *
+ * Description:
+ * Set the SPI frequency.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * frequency - The SPI frequency requested
+ *
+ * Returned Value:
+ * Returns the actual frequency selected
+ *
+ ****************************************************************************/
+
+static uint32_t spi_setfrequency(FAR struct spi_dev_s *dev, uint32_t frequency)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+ uint32_t actual;
+
+ DEBUGASSERT(priv != NULL);
+ actual = priv->actual;
+
+ if (frequency != priv->frequency)
+ {
+ uint32_t freqbits;
+ uint32_t regval;
+
+ if (frequency >= IMX_PERCLK2_FREQ / 4)
+ {
+ freqbits = ECSPI_CONREG_DIV4;
+ actual = IMX_PERCLK2_FREQ / 4;
+ }
+ else if (frequency >= IMX_PERCLK2_FREQ / 8)
+ {
+ freqbits = ECSPI_CONREG_DIV8;
+ actual = IMX_PERCLK2_FREQ / 8;
+ }
+ else if (frequency >= IMX_PERCLK2_FREQ / 16)
+ {
+ freqbits = ECSPI_CONREG_DIV16;
+ actual = IMX_PERCLK2_FREQ / 16;
+ }
+ else if (frequency >= IMX_PERCLK2_FREQ / 32)
+ {
+ freqbits = ECSPI_CONREG_DIV32;
+ actual = IMX_PERCLK2_FREQ / 32;
+ }
+ else if (frequency >= IMX_PERCLK2_FREQ / 64)
+ {
+ freqbits = ECSPI_CONREG_DIV64;
+ actual = IMX_PERCLK2_FREQ / 64;
+ }
+ else if (frequency >= IMX_PERCLK2_FREQ / 128)
+ {
+ freqbits = ECSPI_CONREG_DIV128;
+ actual = IMX_PERCLK2_FREQ / 128;
+ }
+ else if (frequency >= IMX_PERCLK2_FREQ / 256)
+ {
+ freqbits = ECSPI_CONREG_DIV256;
+ actual = IMX_PERCLK2_FREQ / 256;
+ }
+ else /* if (frequency >= IMX_PERCLK2_FREQ / 512) */
+ {
+ freqbits = ECSPI_CONREG_DIV512;
+ actual = IMX_PERCLK2_FREQ / 512;
+ }
+
+ /* Then set the selected frequency */
+
+ regval = spi_getreg(priv, ECSPI_CONREG_OFFSET);
+ regval &= ~(ECSPI_CONREG_DATARATE_MASK);
+ regval |= freqbits;
+ spi_putreg(priv, ECSPI_CONREG_OFFSET, regval);
+
+ priv->frequency = frequency;
+ priv->actual = actual;
+ }
+
+ return actual;
+}
+
+/****************************************************************************
+ * Name: spi_setmode
+ *
+ * Description:
+ * Set the SPI mode. Optional. See enum spi_mode_e for mode definitions
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * mode - The SPI mode requested
+ *
+ * Returned Value:
+ * none
+ *
+ ****************************************************************************/
+
+static void spi_setmode(FAR struct spi_dev_s *dev, enum spi_mode_e mode)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+ if (priv && mode != priv->mode)
+ {
+ uint32_t modebits;
+ uint32_t regval;
+
+ /* Select the CTL register bits based on the selected mode */
+
+ switch (mode)
+ {
+ case SPIDEV_MODE0: /* CPOL=0 CHPHA=0 */
+ modebits = 0;
+ break;
+
+ case SPIDEV_MODE1: /* CPOL=0 CHPHA=1 */
+ modebits = ECSPI_CONREG_PHA;
+ break;
+
+ case SPIDEV_MODE2: /* CPOL=1 CHPHA=0 */
+ modebits = ECSPI_CONREG_POL;
+ break;
+
+ case SPIDEV_MODE3: /* CPOL=1 CHPHA=1 */
+ modebits = ECSPI_CONREG_PHA | ECSPI_CONREG_POL;
+ break;
+
+ default:
+ return;
+ }
+
+ /* Then set the selected mode */
+
+ regval = spi_getreg(priv, ECSPI_CONREG_OFFSET);
+ regval &= ~(ECSPI_CONREG_PHA | ECSPI_CONREG_POL);
+ regval |= modebits;
+ spi_putreg(priv, ECSPI_CONREG_OFFSET, regval);
+ }
+}
+
+/****************************************************************************
+ * Name: spi_setbits
+ *
+ * Description:
+ * Set the number of bits per word.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * nbits - The number of bits requests
+ *
+ * Returned Value:
+ * none
+ *
+ ****************************************************************************/
+
+static void spi_setbits(FAR struct spi_dev_s *dev, int nbits)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+ if (priv && nbits != priv->nbits && nbits > 0 && nbits <= 16)
+ {
+ uint32_t regval = spi_getreg(priv, ECSPI_CONREG_OFFSET);
+ regval &= ~ECSPI_CONREG_BITCOUNT_MASK;
+ regval |= ((nbits - 1) << ECSPI_CONREG_BITCOUNT_SHIFT);
+ spi_putreg(priv, ECSPI_CONREG_OFFSET, regval);
+ priv->nbits = nbits;
+ }
+}
+
+/****************************************************************************
+ * Name: spi_send
+ *
+ * Description:
+ * Exchange one word on SPI
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * wd - The word to send. the size of the data is determined by the
+ * number of bits selected for the SPI interface.
+ *
+ * Returned Value:
+ * response
+ *
+ ****************************************************************************/
+
+static uint16_t spi_send(FAR struct spi_dev_s *dev, uint16_t wd)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+ uint16_t response = 0;
+
+ (void)spi_transfer(priv, &wd, &response, 1);
+ return response;
+}
+
+/****************************************************************************
+ * Name: spi_status
+ *
+ * Description:
+ * Get SPI/MMC status. Optional.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * devid - Identifies the device to report status on
+ *
+ * Returned Value:
+ * Returns a bitset of status values (see SPI_STATUS_* defines)
+ *
+ ****************************************************************************/
+
+static uint8_t spi_status(FAR struct spi_dev_s *dev, enum spi_dev_e devid)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+ uint8_t ret = 0;
+
+ DEBUGASSERT(priv != NULL);
+
+ if (priv->status != NULL);
+ {
+ ret = priv->select(dev, devid);
+ }
+
+ return ret;
+}
+
+/****************************************************************************
+ * Name: spi_cmddata
+ *
+ * Description:
+ * Some devices require and additional out-of-band bit to specify if the
+ * next word sent to the device is a command or data. This is typical, for
+ * example, in "9-bit" displays where the 9th bit is the CMD/DATA bit.
+ * This function provides selection of command or data.
+ *
+ * This "latches" the CMD/DATA state. It does not have to be called before
+ * every word is transferred; only when the CMD/DATA state changes. This
+ * method is required if CONFIG_SPI_CMDDATA is selected in the NuttX
+ * configuration
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * cmd - TRUE: The following word is a command; FALSE: the following words
+ * are data.
+ *
+ * Returned Value:
+ * OK unless an error occurs. Then a negated errno value is returned
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_CMDDATA
+static int spi_cmddata(FAR struct spi_dev_s *dev, enum spi_dev_e devid,
+ bool cmd)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+ int ret = -ENOSYS;
+
+ DEBUGASSERT(priv != NULL);
+
+ if (priv->cmddata != NULL);
+ {
+ ret = priv->cmddata(dev, devid, cmd);
+ }
+
+ return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: SPI_EXCHANGE
+ *
+ * Description:
+ * Exahange a block of data from SPI. Required.
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * buffer - A pointer to the buffer of data to be sent
+ * rxbuffer - A pointer to the buffer in which to recieve data
+ * nwords - the length of data that to be exchanged in units of words.
+ * The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface. If nbits <= 8, the data is
+ * packed into uint8_t's; if nbits >8, the data is packed into uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SPI_EXCHANGE
+static void spi_exchange(FAR struct spi_dev_s *dev, FAR const void *txbuffer,
+ FAR void *rxbuffer, size_t nwords)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+ (void)spi_transfer(priv, txbuffer, rxbuffer, nwords);
+}
+#endif
+
+/****************************************************************************
+ * Name: spi_sndblock
+ *
+ * Description:
+ * Send a block of data on SPI
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * buffer - A pointer to the buffer of data to be sent
+ * nwords - the length of data to send from the buffer in number of words.
+ * The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface. If nbits <= 8, the data is
+ * packed into uint8_t's; if nbits >8, the data is packed into uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SPI_EXCHANGE
+static void spi_sndblock(FAR struct spi_dev_s *dev, FAR const void *buffer, size_t nwords)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+ (void)spi_transfer(priv, buffer, NULL, nwords);
+}
+#endif
+
+/****************************************************************************
+ * Name: spi_recvblock
+ *
+ * Description:
+ * Revice a block of data from SPI
+ *
+ * Input Parameters:
+ * dev - Device-specific state data
+ * buffer - A pointer to the buffer in which to recieve data
+ * nwords - the length of data that can be received in the buffer in number
+ * of words. The wordsize is determined by the number of bits-per-word
+ * selected for the SPI interface. If nbits <= 8, the data is
+ * packed into uint8_t's; if nbits >8, the data is packed into uint16_t's
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+#ifndef CONFIG_SPI_EXCHANGE
+static void spi_recvblock(FAR struct spi_dev_s *dev, FAR void *buffer, size_t nwords)
+{
+ struct imx_spidev_s *priv = (struct imx_spidev_s *)dev;
+ (void)spi_transfer(priv, NULL, buffer, nwords);
+}
+#endif
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: imx_spibus_initialize
+ *
+ * Description:
+ * Initialize common parts the selected SPI port. Initialization of
+ * chip select GPIOs must have been performed by board specific logic
+ * prior to calling this function. Specifically: GPIOs should have
+ * been configured for output, and all chip selects disabled.
+ *
+ * One GPIO, SS (PB2 on the eZ8F091) is reserved as a chip select. However,
+ * If multiple devices on on the bus, then multiple chip selects will be
+ * required. Theregore, all GPIO chip management is deferred to board-
+ * specific logic.
+ *
+ * Input Parameter:
+ * Port number (for hardware that has mutiple SPI interfaces)
+ *
+ * Returned Value:
+ * Valid SPI device structre reference on succcess; a NULL on failure
+ *
+ ****************************************************************************/
+
+FAR struct spi_dev_s *imx_spibus_initialize(int port)
+{
+ struct imx_spidev_s *priv;
+ uint8_t regval;
+
+ /* Only the SPI1 interface is supported */
+
+ switch (port)
+ {
+#ifdef CONFIG_IMX6_ECSPI1
+ case 1:
+ /* Select SPI1 */
+
+ priv = &g_spidev[SPI1_NDX];
+
+ /* Configure SPI1 GPIOs (NOTE that SS is not initialized here, the
+ * logic in this file makes no assumptions about chip select)
+ */
+
+ imxgpio_configpfinput(GPIOC, 13); /* Port C, pin 13: RDY */
+ imxgpio_configpfoutput(GPIOC, 14); /* Port C, pin 14: SCLK */
+ imxgpio_configpfinput(GPIOC, 16); /* Port C, pin 16: MISO */
+ imxgpio_configpfoutput(GPIOC, 17); /* Port C, pin 17: MOSI */
+ break;
+#endif /* CONFIG_IMX6_ECSPI1 */
+
+#ifdef CONFIG_IMX6_ECSPI2
+ case 2:
+ /* Select SPI2 */
+
+ priv = &g_spidev[SPI2_NDX];
+
+ /* Configure SPI2 GPIOs */
+ /* SCLK: AIN of Port A, pin 0 -OR- AIN of Port D, pin 7 */
+
+#if 1
+ imxgpio_configoutput(GPIOA, 0); /* Set GIUS=1 OCR=0 DIR=OUT */
+#else
+ imxgpio_configoutput(GPIOD, 7); /* Set GIUS=1 OCR=0 DIR=OUT */
+#endif
+
+ /* SS: AIN of Port A, pin 17 -OR- AIN of Port D, pin 8.(NOTE that SS
+ * is not initialized here, the logic in this file makes no assumptions
+ * about chip select)
+ */
+
+ /* RXD: AOUT of Port A, pin 1 -OR- AOUT of Port D, pin 9 */
+
+#if 1
+ imxgpio_configinput(GPIOA, 1); /* Set GIUS=1 OCR=0 DIR=IN */
+
+ /* Select input from SPI2_RXD_0 pin (AOUT Port A, pin 1) */
+
+ regval = getreg32(IMX_SC_FMCR);
+ regval &= ~FMCR_SPI2_RXDSEL;
+ putreg32(regval, IMX_SC_FMCR);
+#else
+ imxgpio_configinput(GPIOD, 9); /* Set GIUS=1 OCR=0 DIR=IN */
+
+ /* Select input from SPI2_RXD_1 pin (AOUT Port D, pin 9) */
+
+ regval = getreg32(IMX_SC_FMCR);
+ regval |= FMCR_SPI2_RXDSEL;
+ putreg32(regval, IMX_SC_FMCR);
+#endif
+
+ /* TXD: BIN of Port D, pin 31 -OR- AIN of Port D, pin 10 */
+
+#if 1
+ imxgpio_configinput(GPIOD, 31);
+ imxgpio_ocrbin(GPIOD, 31);
+ imxgpio_dirout(GPIOD, 31);
+#else
+ imxgpio_configoutput(GPIOD, 10);
+#endif
+ break;
+#endif /* CONFIG_IMX6_ECSPI2 */
+
+ default:
+ return NULL;
+ }
+
+ /* Initialize the state structure */
+ /* Initialize Semaphores */
+
+#ifndef CONFIG_SPI_POLLWAIT
+ /* Initialize the semaphore that is used to wake up the waiting
+ * thread when the DMA transfer completes. This semaphore is used for
+ * signaling and, hence, should not have priority inheritance enabled.
+ */
+
+ sem_init(&priv->waitsem, 0, 0);
+ sem_setprotocol(&priv->waitsem, SEM_PRIO_NONE);
+#endif
+ sem_init(&priv->exclsem, 0, 1);
+
+ /* Initialize control register: min frequency, ignore ready, master mode, mode=0, 8-bit */
+
+ spi_putreg(priv, ECSPI_CONREG_OFFSET,
+ ECSPI_CONREG_DIV512 | /* Lowest frequency */
+ ECSPI_CONREG_DRCTL_IGNRDY | /* Ignore ready */
+ ECSPI_CONREG_MODE | /* Master mode */
+ (7 << ECSPI_CONREG_BITCOUNT_SHIFT)); /* 8-bit data */
+
+ /* Make sure state agrees with data */
+
+ priv->mode = SPIDEV_MODE0;
+ priv->nbits = 8;
+
+ /* Set the initial clock frequency for identification mode < 400kHz */
+
+ spi_setfrequency((FAR struct spi_dev_s *)priv, 400000);
+
+ /* Enable interrupts on data ready (and certain error conditions */
+
+#ifndef CONFIG_SPI_POLLWAIT
+ spi_putreg(priv, ECSPI_INTREG_OFFSET,
+ ECSPI_INT_RR | /* RXFIFO Data Ready Interrupt Enable */
+ ECSPI_INT_RO | /* RXFIFO Overflow Interrupt Enable */
+ ECSPI_INT_BO); /* Bit Count Overflow Interrupt Enable */
+#else
+ spi_putreg(priv, ECSPI_INTREG_OFFSET, 0); /* No interrupts */
+#endif
+
+ /* Set the clock source=bit clock and number of clocks inserted between
+ * transactions = 2.
+ */
+
+ spi_putreg(priv, ECSPI_PERIODREG_OFFSET, 2);
+
+ /* No DMA */
+
+ spi_putreg(priv, ECSPI_DMAREG_OFFSET, 0);
+
+ /* Attach the interrupt */
+
+#ifndef CONFIG_SPI_POLLWAIT
+ DEBUGVERIFY(irq_attach(priv->irq, priv->handler));
+#endif
+
+ /* Enable SPI */
+
+ regval = spi_getreg(priv, ECSPI_CONREG_OFFSET);
+ regval |= ECSPI_CONREG_SPIEN;
+ spi_putreg(priv, ECSPI_CONREG_OFFSET, regval);
+
+ /* Enable SPI interrupts */
+
+#ifndef CONFIG_SPI_POLLWAIT
+ up_enable_irq(priv->irq);
+#endif
+ return (FAR struct spi_dev_s *)priv;
+}
+
+#endif /* NSPIS > 0 */
diff --git a/arch/arm/src/imx6/imx_irq.c b/arch/arm/src/imx6/imx_irq.c
index e00a8e9527d..b15a9a4e6dd 100644
--- a/arch/arm/src/imx6/imx_irq.c
+++ b/arch/arm/src/imx6/imx_irq.c
@@ -134,11 +134,11 @@ void up_irqinitialize(void)
CURRENT_REGS = NULL;
#ifndef CONFIG_SUPPRESS_INTERRUPTS
+#ifdef CONFIG_IMX6_PIO_IRQ
/* Initialize logic to support a second level of interrupt decoding for
* PIO pins.
*/
-#ifdef CONFIG_IMX6_PIO_IRQ
imx_gpioirq_initialize();
#endif
diff --git a/arch/arm/src/kinetis/Kconfig b/arch/arm/src/kinetis/Kconfig
index cf781ade5e0..a585a57fe43 100644
--- a/arch/arm/src/kinetis/Kconfig
+++ b/arch/arm/src/kinetis/Kconfig
@@ -254,7 +254,6 @@ config KINETIS_ENET
select ARCH_HAVE_NETDEV_STATISTICS
select NET
select NETDEVICES
- select NET_MULTIBUFFER
---help---
Support Ethernet (K6x only)
diff --git a/arch/arm/src/kinetis/kinetis_enet.c b/arch/arm/src/kinetis/kinetis_enet.c
index a546103d365..30707e47ac1 100644
--- a/arch/arm/src/kinetis/kinetis_enet.c
+++ b/arch/arm/src/kinetis/kinetis_enet.c
@@ -53,14 +53,11 @@
#include
#include
#include
+#include
#include
#include
#include
-#ifdef CONFIG_NET_NOINTS
-# include
-#endif
-
#ifdef CONFIG_NET_PKT
# include
#endif
@@ -84,13 +81,12 @@
* is required.
*/
-#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
+#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
-#endif
+#else
-/* Select work queue */
+ /* Select work queue */
-#if defined(CONFIG_SCHED_WORKQUEUE)
# if defined(CONFIG_KINETIS_EMAC_HPWORK)
# define ETHWORK HPWORK
# elif defined(CONFIG_KINETIS_EMAC_LPWORK)
@@ -119,10 +115,6 @@
#define NENET_NBUFFERS \
(CONFIG_KINETIS_ENETNTXBUFFERS+CONFIG_KINETIS_ENETNRXBUFFERS)
-#ifndef CONFIG_NET_MULTIBUFFER
-# error "CONFIG_NET_MULTIBUFFER is required in the configuration"
-#endif
-
/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per
* second.
*/
@@ -223,9 +215,7 @@ struct kinetis_driver_s
uint8_t phyaddr; /* Selected PHY address */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
-#ifdef CONFIG_NET_NOINTS
struct work_s work; /* For deferring work to the work queue */
-#endif
struct enet_desc_s *txdesc; /* A pointer to the list of TX descriptor */
struct enet_desc_s *rxdesc; /* A pointer to the list of RX descriptors */
@@ -283,24 +273,15 @@ static int kinetis_txpoll(struct net_driver_s *dev);
static void kinetis_receive(FAR struct kinetis_driver_s *priv);
static void kinetis_txdone(FAR struct kinetis_driver_s *priv);
-static inline void kinetis_interrupt_process(FAR struct kinetis_driver_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void kinetis_interrupt_work(FAR void *arg);
-#endif
static int kinetis_interrupt(int irq, FAR void *context);
/* Watchdog timer expirations */
-static inline void kinetis_txtimeout_process(FAR struct kinetis_driver_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void kinetis_txtimeout_work(FAR void *arg);
-#endif
static void kinetis_txtimeout_expiry(int argc, uint32_t arg, ...);
-static inline void kinetis_poll_process(FAR struct kinetis_driver_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void kinetis_poll_work(FAR void *arg);
-#endif
static void kinetis_polltimer_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
@@ -308,10 +289,7 @@ static void kinetis_polltimer_expiry(int argc, uint32_t arg, ...);
static int kinetis_ifup(struct net_driver_s *dev);
static int kinetis_ifdown(struct net_driver_s *dev);
-static inline void kinetis_txavail_process(FAR struct kinetis_driver_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void kinetis_txavail_work(FAR void *arg);
-#endif
static int kinetis_txavail(struct net_driver_s *dev);
#ifdef CONFIG_NET_IGMP
@@ -828,27 +806,31 @@ static void kinetis_txdone(FAR struct kinetis_driver_s *priv)
}
/****************************************************************************
- * Function: kinetis_interrupt_process
+ * Function: kinetis_interrupt_work
*
* Description:
- * Interrupt processing. This may be performed either within the interrupt
- * handler or on the worker thread, depending upon the configuration
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
* The network is locked.
*
****************************************************************************/
-static inline void kinetis_interrupt_process(FAR struct kinetis_driver_s *priv)
+static void kinetis_interrupt_work(FAR void *arg)
{
+ FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
uint32_t pending;
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
+
/* Get the set of unmasked, pending interrupt. */
pending = getreg32(KINETIS_ENET_EIR) & getreg32(KINETIS_ENET_EIMR);
@@ -896,36 +878,8 @@ static inline void kinetis_interrupt_process(FAR struct kinetis_driver_s *priv)
putreg32(ENET_RDAR, KINETIS_ENET_RDAR);
}
-}
-/****************************************************************************
- * Function: kinetis_interrupt_work
- *
- * Description:
- * Perform interrupt related work from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() was called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * The network is locked.
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void kinetis_interrupt_work(FAR void *arg)
-{
- FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
- net_lock_t state;
-
- /* Process pending Ethernet interrupts */
-
- state = net_lock();
- kinetis_interrupt_process(priv);
- net_unlock(state);
+ net_unlock();
/* Re-enable Ethernet interrupts */
@@ -936,7 +890,6 @@ static void kinetis_interrupt_work(FAR void *arg)
up_enable_irq(KINETIS_IRQ_EMACRX);
up_enable_irq(KINETIS_IRQ_EMACMISC);
}
-#endif
/****************************************************************************
* Function: kinetis_interrupt
@@ -962,7 +915,6 @@ static int kinetis_interrupt(int irq, FAR void *context)
{
register FAR struct kinetis_driver_s *priv = &g_enet[0];
-#ifdef CONFIG_NET_NOINTS
/* Disable further Ethernet interrupts. Because Ethernet interrupts are
* also disabled if the TX timeout event occurs, there can be no race
* condition here.
@@ -991,51 +943,9 @@ static int kinetis_interrupt(int irq, FAR void *context)
/* Schedule to perform the interrupt processing on the worker thread. */
work_queue(ETHWORK, &priv->work, kinetis_interrupt_work, priv, 0);
-
-#else
- /* Process the interrupt now */
-
- kinetis_interrupt_process(priv);
-#endif
-
return OK;
}
-/****************************************************************************
- * Function: kinetis_txtimeout_process
- *
- * Description:
- * Process a TX timeout. Called from the either the watchdog timer
- * expiration logic or from the worker thread, depending upon the
- * configuration. The timeout means that the last TX never completed.
- * Reset the hardware and start again.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-static inline void kinetis_txtimeout_process(FAR struct kinetis_driver_s *priv)
-{
- /* Increment statistics and dump debug info */
-
- NETDEV_TXTIMEOUTS(&priv->dev);
-
- /* Take the interface down and bring it back up. The is the most agressive
- * hardware reset.
- */
-
- (void)kinetis_ifdown(&priv->dev);
- (void)kinetis_ifup(&priv->dev);
-
- /* Then poll the network for new XMIT data */
-
- (void)devif_poll(&priv->dev, kinetis_txpoll);
-}
-
/****************************************************************************
* Function: kinetis_txtimeout_work
*
@@ -1053,19 +963,27 @@ static inline void kinetis_txtimeout_process(FAR struct kinetis_driver_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void kinetis_txtimeout_work(FAR void *arg)
{
FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
- net_lock_t state;
- /* Process pending Ethernet interrupts */
+ /* Increment statistics and dump debug info */
- state = net_lock();
- kinetis_txtimeout_process(priv);
- net_unlock(state);
+ net_lock();
+ NETDEV_TXTIMEOUTS(&priv->dev);
+
+ /* Take the interface down and bring it back up. The is the most agressive
+ * hardware reset.
+ */
+
+ (void)kinetis_ifdown(&priv->dev);
+ (void)kinetis_ifup(&priv->dev);
+
+ /* Then poll the network for new XMIT data */
+
+ (void)devif_poll(&priv->dev, kinetis_txpoll);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: kinetis_txtimeout_expiry
@@ -1090,7 +1008,6 @@ static void kinetis_txtimeout_expiry(int argc, uint32_t arg, ...)
{
FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Disable further Ethernet interrupts. This will prevent some race
* conditions with interrupt work. There is still a potential race
* condition with interrupt work that is already queued and in progress.
@@ -1110,50 +1027,6 @@ static void kinetis_txtimeout_expiry(int argc, uint32_t arg, ...)
/* Schedule to perform the TX timeout processing on the worker thread. */
work_queue(ETHWORK, &priv->work, kinetis_txtimeout_work, priv, 0);
-#else
- /* Process the timeout now */
-
- kinetis_txtimeout_process(priv);
-#endif
-}
-
-/****************************************************************************
- * Function: kinetis_poll_process
- *
- * Description:
- * Perform the periodic poll. This may be called either from watchdog
- * timer logic or from the worker thread, depending upon the configuration.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
-
-static inline void kinetis_poll_process(FAR struct kinetis_driver_s *priv)
-{
- /* Check if there is there is a transmission in progress. We cannot perform
- * the TX poll if he are unable to accept another packet for transmission.
- */
-
- if (!kinetics_txringfull(priv))
- {
- /* If so, update TCP timing states and poll the network for new XMIT data. Hmmm..
- * might be bug here. Does this mean if there is a transmit in progress,
- * we will missing TCP time state updates?
- */
-
- (void)devif_timer(&priv->dev, kinetis_txpoll);
- }
-
- /* Setup the watchdog poll timer again in any case */
-
- (void)wd_start(priv->txpoll, KINETIS_WDDELAY, kinetis_polltimer_expiry,
- 1, (wdparm_t)priv);
}
/****************************************************************************
@@ -1173,19 +1046,31 @@ static inline void kinetis_poll_process(FAR struct kinetis_driver_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void kinetis_poll_work(FAR void *arg)
{
FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
- net_lock_t state;
- /* Perform the poll */
+ /* Check if there is there is a transmission in progress. We cannot perform
+ * the TX poll if he are unable to accept another packet for transmission.
+ */
- state = net_lock();
- kinetis_poll_process(priv);
- net_unlock(state);
+ net_lock();
+ if (!kinetics_txringfull(priv))
+ {
+ /* If so, update TCP timing states and poll the network for new XMIT data. Hmmm..
+ * might be bug here. Does this mean if there is a transmit in progress,
+ * we will missing TCP time state updates?
+ */
+
+ (void)devif_timer(&priv->dev, kinetis_txpoll);
+ }
+
+ /* Setup the watchdog poll timer again in any case */
+
+ (void)wd_start(priv->txpoll, KINETIS_WDDELAY, kinetis_polltimer_expiry,
+ 1, (wdparm_t)priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: kinetis_polltimer_expiry
@@ -1209,7 +1094,6 @@ static void kinetis_polltimer_expiry(int argc, uint32_t arg, ...)
{
FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions.
*/
@@ -1229,12 +1113,6 @@ static void kinetis_polltimer_expiry(int argc, uint32_t arg, ...)
(void)wd_start(priv->txpoll, KINETIS_WDDELAY, kinetis_polltimer_expiry,
1, (wdparm_t)arg);
}
-
-#else
- /* Process the interrupt now */
-
- kinetis_poll_process(priv);
-#endif
}
/****************************************************************************
@@ -1420,49 +1298,6 @@ static int kinetis_ifdown(struct net_driver_s *dev)
return OK;
}
-/****************************************************************************
- * Function: kinetis_txavail_process
- *
- * Description:
- * Perform an out-of-cycle poll.
- *
- * Parameters:
- * dev - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called in normal user mode
- *
- ****************************************************************************/
-
-static inline void kinetis_txavail_process(FAR struct kinetis_driver_s *priv)
-{
- net_lock_t state;
-
- /* Ignore the notification if the interface is not yet up */
-
- state = net_lock();
- if (priv->bifup)
- {
- /* Check if there is room in the hardware to hold another outgoing
- * packet.
- */
-
- if (!kinetics_txringfull(priv))
- {
- /* No, there is space for another transfer. Poll the network for new
- * XMIT data.
- */
-
- (void)devif_poll(&priv->dev, kinetis_txpoll);
- }
- }
-
- net_unlock(state);
-}
-
/****************************************************************************
* Function: kinetis_txavail_work
*
@@ -1480,16 +1315,31 @@ static inline void kinetis_txavail_process(FAR struct kinetis_driver_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void kinetis_txavail_work(FAR void *arg)
{
FAR struct kinetis_driver_s *priv = (FAR struct kinetis_driver_s *)arg;
- /* Perform the poll */
+ /* Ignore the notification if the interface is not yet up */
- kinetis_txavail_process(priv);
+ net_lock();
+ if (priv->bifup)
+ {
+ /* Check if there is room in the hardware to hold another outgoing
+ * packet.
+ */
+
+ if (!kinetics_txringfull(priv))
+ {
+ /* No, there is space for another transfer. Poll the network for new
+ * XMIT data.
+ */
+
+ (void)devif_poll(&priv->dev, kinetis_txpoll);
+ }
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: kinetis_txavail
@@ -1515,7 +1365,6 @@ static int kinetis_txavail(struct net_driver_s *dev)
FAR struct kinetis_driver_s *priv =
(FAR struct kinetis_driver_s *)dev->d_private;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions and we will have to ignore the Tx
* availability action.
@@ -1528,12 +1377,6 @@ static int kinetis_txavail(struct net_driver_s *dev)
work_queue(ETHWORK, &priv->work, kinetis_txavail_work, priv, 0);
}
-#else
- /* Perform the out-of-cycle poll now */
-
- kinetis_txavail_process(priv);
-#endif
-
return OK;
}
diff --git a/arch/arm/src/lpc17xx/lpc17_allocateheap.c b/arch/arm/src/lpc17xx/lpc17_allocateheap.c
index 20568f0457f..dd1652bf18d 100644
--- a/arch/arm/src/lpc17xx/lpc17_allocateheap.c
+++ b/arch/arm/src/lpc17xx/lpc17_allocateheap.c
@@ -136,7 +136,7 @@
# endif /* LPC17_HAVE_BANK1 && LPC17_BANK1_HEAPSIZE */
# else /* !LPC17_BANK0_HEAPSIZE */
- /* We have Bnak 0, but no memory is available for the heap there.
+ /* We have Bank 0, but no memory is available for the heap there.
* Do we have Bank 1? Is any heap memory available in Bank 1?
*/
diff --git a/arch/arm/src/lpc17xx/lpc17_ethernet.c b/arch/arm/src/lpc17xx/lpc17_ethernet.c
index d5ff009fd6d..fa9b65a95f5 100644
--- a/arch/arm/src/lpc17xx/lpc17_ethernet.c
+++ b/arch/arm/src/lpc17xx/lpc17_ethernet.c
@@ -52,15 +52,12 @@
#include
#include
#include
+#include
#include
#include
#include
#include
-#ifdef CONFIG_NET_NOINTS
-# include
-#endif
-
#ifdef CONFIG_NET_PKT
# include
#endif
@@ -87,13 +84,12 @@
* is required.
*/
-#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
+#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
-#endif
+#else
-/* Select work queue */
+ /* Select work queue */
-#if defined(CONFIG_SCHED_WORKQUEUE)
# if defined(CONFIG_LPC17_ETHERNET_HPWORK)
# define ETHWORK HPWORK
# elif defined(CONFIG_LPC17_ETHERNET_LPWORK)
@@ -138,6 +134,8 @@
# define CONFIG_NET_PRIORITY NVIC_SYSH_PRIORITY_DEFAULT
#endif
+#define PKTBUF_SIZE (MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE)
+
/* Debug Configuration *****************************************************/
/* Register debug -- can only happen of CONFIG_DEBUG_NET_INFO is selected */
@@ -274,12 +272,10 @@ struct lpc17_driver_s
WDOG_ID lp_txpoll; /* TX poll timer */
WDOG_ID lp_txtimeout; /* TX timeout timer */
-#ifdef CONFIG_NET_NOINTS
struct work_s lp_txwork; /* TX work continuation */
struct work_s lp_rxwork; /* RX work continuation */
struct work_s lp_pollwork; /* Poll work continuation */
uint32_t status;
-#endif /* CONFIG_NET_NOINTS */
/* This holds the information visible to the NuttX networking layer */
@@ -290,6 +286,10 @@ struct lpc17_driver_s
* Private Data
****************************************************************************/
+/* A single packet buffer per interface is used */
+
+static uint8_t g_pktbuf[PKTBUF_SIZE * CONFIG_LPC17_NINTERFACES];
+
/* Array of ethernet driver status structures */
static struct lpc17_driver_s g_ethdrvr[CONFIG_LPC17_NINTERFACES];
@@ -332,26 +332,17 @@ static int lpc17_txpoll(struct net_driver_s *dev);
/* Interrupt handling */
static void lpc17_response(struct lpc17_driver_s *priv);
-static void lpc17_rxdone_process(struct lpc17_driver_s *priv);
-static void lpc17_txdone_process(struct lpc17_driver_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void lpc17_txdone_work(FAR void *arg);
static void lpc17_rxdone_work(FAR void *arg);
-#endif /* CONFIG_NET_NOINTS */
static int lpc17_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static void lpc17_txtimeout_process(FAR struct lpc17_driver_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void lpc17_txtimeout_work(FAR void *arg);
-#endif /* CONFIG_NET_NOINTS */
static void lpc17_txtimeout_expiry(int argc, uint32_t arg, ...);
-static void lpc17_poll_process(FAR struct lpc17_driver_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void lpc17_poll_work(FAR void *arg);
-#endif /* CONFIG_NET_NOINTS */
static void lpc17_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
@@ -362,11 +353,9 @@ static void lpc17_ipv6multicast(FAR struct lpc17_driver_s *priv);
static int lpc17_ifup(struct net_driver_s *dev);
static int lpc17_ifdown(struct net_driver_s *dev);
-static void lpc17_txavail_process(FAR struct lpc17_driver_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void lpc17_txavail_work(FAR void *arg);
-#endif
static int lpc17_txavail(struct net_driver_s *dev);
+
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
static uint32_t lpc17_calcethcrc(const uint8_t *data, size_t length);
static int lpc17_addmac(struct net_driver_s *dev, const uint8_t *mac);
@@ -654,6 +643,7 @@ static int lpc17_transmit(struct lpc17_driver_s *priv)
prodidx = 0;
}
+
lpc17_putreg(prodidx, LPC17_ETH_TXPRODIDX);
/* Enable Tx interrupts */
@@ -798,30 +788,40 @@ static void lpc17_response(struct lpc17_driver_s *priv)
}
/****************************************************************************
- * Function: lpc17_rxdone_process
+ * Function: lpc17_rxdone_work
*
* Description:
- * An interrupt was received indicating the availability of a new RX packet
+ * Perform Rx interrupt handling logic outside of the interrupt handler (on
+ * the work queue thread).
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The reference to the driver structure (case to void*)
*
* Returned Value:
* None
*
* Assumptions:
- * Global interrupts are disabled by interrupt handling logic.
*
****************************************************************************/
-static void lpc17_rxdone_process(struct lpc17_driver_s *priv)
+static void lpc17_rxdone_work(FAR void *arg)
{
- uint32_t *rxstat;
- bool fragment;
+ FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg;
+ irqstate_t flags;
+ uint32_t *rxstat;
+ bool fragment;
unsigned int prodidx;
unsigned int considx;
unsigned int pktlen;
+ DEBUGASSERT(priv);
+
+ /* Perform pending RX work. RX interrupts were disabled prior to
+ * scheduling this work to prevent work queue overruns.
+ */
+
+ net_lock();
+
/* Get the current producer and consumer indices */
considx = lpc17_getreg(LPC17_ETH_RXCONSIDX) & ETH_RXCONSIDX_MASK;
@@ -844,7 +844,7 @@ static void lpc17_rxdone_process(struct lpc17_driver_s *priv)
pktlen = (*rxstat & RXSTAT_INFO_RXSIZE_MASK) - 3;
/* Check for errors. NOTE: The DMA engine reports bogus length errors,
- * making this a pretty useless check.
+ * making this a pretty useless (as well as annoying) check.
*/
if ((*rxstat & RXSTAT_INFO_ERROR) != 0)
@@ -1035,37 +1035,55 @@ static void lpc17_rxdone_process(struct lpc17_driver_s *priv)
lpc17_putreg(considx, LPC17_ETH_RXCONSIDX);
prodidx = lpc17_getreg(LPC17_ETH_RXPRODIDX) & ETH_RXPRODIDX_MASK;
}
+
+ net_unlock();
+
+ /* Re-enable RX interrupts (this must be atomic). Skip this step if the
+ * lp-txpending TX underrun state is in effect.
+ */
+
+ flags = enter_critical_section();
+ if (!priv->lp_txpending)
+ {
+ priv->lp_inten |= ETH_RXINTS;
+ lpc17_putreg(priv->lp_inten, LPC17_ETH_INTEN);
+ }
+
+ leave_critical_section(flags);
}
+
/****************************************************************************
- * Function: lpc17_txdone_process
+ * Function: lpc17_txdone_work
*
* Description:
- * An interrupt was received indicating that the last TX packet(s) is done
+ * Perform Tx interrupt handling logic outside of the interrupt handler (on
+ * the work queue thread).
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The reference to the driver structure (case to void*)
*
* Returned Value:
* None
*
- * Assumptions:
- * Global interrupts are disabled by interrupt handling logic.
- *
****************************************************************************/
-static void lpc17_txdone_process(struct lpc17_driver_s *priv)
+static void lpc17_txdone_work(FAR void *arg)
{
+ FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg;
+
/* Verify that the hardware is ready to send another packet. Since a Tx
* just completed, this must be the case.
*/
+ DEBUGASSERT(priv);
DEBUGASSERT(lpc17_txdesc(priv) == OK);
/* Check if there is a pending Tx transfer that was scheduled by Rx handling
* while the Tx logic was busy. If so, processing that pending Tx now.
*/
+ net_lock();
if (priv->lp_txpending)
{
/* Clear the pending condition, send the packet, and restore Rx interrupts */
@@ -1084,74 +1102,10 @@ static void lpc17_txdone_process(struct lpc17_driver_s *priv)
{
(void)devif_poll(&priv->lp_dev, lpc17_txpoll);
}
+
+ net_unlock();
}
-/****************************************************************************
- * Function: lpc17_txdone_work and lpc17_rxdone_work
- *
- * Description:
- * Perform interrupt handling logic outside of the interrupt handler (on
- * the work queue thread).
- *
- * Parameters:
- * arg - The reference to the driver structure (case to void*)
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void lpc17_txdone_work(FAR void *arg)
-{
- FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg;
- net_lock_t state;
-
- DEBUGASSERT(priv);
-
- /* Perform pending TX work. At this point TX interrupts are disable but
- * may be re-enabled again depending on the actions of
- * lpc17_txdone_process().
- */
-
- state = net_lock();
- lpc17_txdone_process(priv);
- net_unlock(state);
-}
-
-static void lpc17_rxdone_work(FAR void *arg)
-{
- FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg;
- irqstate_t flags;
- net_lock_t state;
-
- DEBUGASSERT(priv);
-
- /* Perform pending RX work. RX interrupts were disabled prior to
- * scheduling this work to prevent work queue overruns.
- */
-
- state = net_lock();
- lpc17_rxdone_process(priv);
- net_unlock(state);
-
- /* Re-enable RX interrupts (this must be atomic). Skip this step if the
- * lp-txpending TX underrun state is in effect.
- */
-
- flags = enter_critical_section();
- if (!priv->lp_txpending)
- {
- priv->lp_inten |= ETH_RXINTS;
- lpc17_putreg(priv->lp_inten, LPC17_ETH_INTEN);
- }
-
- leave_critical_section(flags);
-}
-#endif /* CONFIG_NET_NOINTS */
-
/****************************************************************************
* Function: lpc17_interrupt
*
@@ -1236,7 +1190,7 @@ static int lpc17_interrupt(int irq, void *context)
* or Overrun. NOTE: (1) We will still need to call lpc17_rxdone_process
* on RX errors to bump the considx over the bad packet. (2) The
* DMA engine reports bogus length errors, making this a pretty
- * useless check anyway.
+ * useless (as well as annoying) check anyway.
*/
if ((status & ETH_INT_RXERR) != 0)
@@ -1260,8 +1214,6 @@ static int lpc17_interrupt(int irq, void *context)
if ((status & ETH_INT_RXFIN) != 0 || (status & ETH_INT_RXDONE) != 0)
{
/* We have received at least one new incoming packet. */
-
-#ifdef CONFIG_NET_NOINTS
/* Disable further TX interrupts for now. TX interrupts will
* be re-enabled after the work has been processed.
*/
@@ -1277,11 +1229,6 @@ static int lpc17_interrupt(int irq, void *context)
work_queue(ETHWORK, &priv->lp_rxwork, (worker_t)lpc17_rxdone_work,
priv, 0);
-
-#else /* CONFIG_NET_NOINTS */
- lpc17_rxdone_process(priv);
-
-#endif /* CONFIG_NET_NOINTS */
}
/* Check for Tx events ********************************************/
@@ -1330,7 +1277,6 @@ static int lpc17_interrupt(int irq, void *context)
priv->lp_inten &= ~ETH_TXINTS;
lpc17_putreg(priv->lp_inten, LPC17_ETH_INTEN);
-#ifdef CONFIG_NET_NOINTS
/* Cancel any pending TX done work (to prevent overruns and also
* to avoid race conditions with the TX timeout work)
*/
@@ -1350,13 +1296,6 @@ static int lpc17_interrupt(int irq, void *context)
work_queue(ETHWORK, &priv->lp_txwork, (worker_t)lpc17_txdone_work,
priv, 0);
-
-#else /* CONFIG_NET_NOINTS */
- /* Perform the TX work at the interrupt level */
-
- lpc17_txdone_process(priv);
-
-#endif /* CONFIG_NET_NOINTS */
}
}
}
@@ -1374,42 +1313,6 @@ static int lpc17_interrupt(int irq, void *context)
return OK;
}
-/****************************************************************************
- * Function: lpc17_txtimeout_process
- *
- * Description:
- * Process a TX timeout. Called from the either the watchdog timer
- * expiration logic or from the worker thread, depending upon the
- * configuration. The timeout means that the last TX never completed.
- * Reset the hardware and start again.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- ****************************************************************************/
-
-static void lpc17_txtimeout_process(FAR struct lpc17_driver_s *priv)
-{
- /* Increment statistics and dump debug info */
-
- NETDEV_TXTIMEOUTS(&priv->lp_dev);
- if (priv->lp_ifup)
- {
- /* Then reset the hardware. ifup() will reset the interface, then bring
- * it back up.
- */
-
- (void)lpc17_ifup(&priv->lp_dev);
-
- /* Then poll the network layer for new XMIT data */
-
- (void)devif_poll(&priv->lp_dev, lpc17_txpoll);
- }
-}
-
/****************************************************************************
* Function: lpc17_txtimeout_work
*
@@ -1427,19 +1330,29 @@ static void lpc17_txtimeout_process(FAR struct lpc17_driver_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void lpc17_txtimeout_work(FAR void *arg)
{
FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg;
- net_lock_t state;
- /* Process pending Ethernet interrupts */
+ /* Increment statistics and dump debug info */
- state = net_lock();
- lpc17_txtimeout_process(priv);
- net_unlock(state);
+ net_lock();
+ NETDEV_TXTIMEOUTS(&priv->lp_dev);
+ if (priv->lp_ifup)
+ {
+ /* Then reset the hardware. ifup() will reset the interface, then bring
+ * it back up.
+ */
+
+ (void)lpc17_ifup(&priv->lp_dev);
+
+ /* Then poll the network layer for new XMIT data */
+
+ (void)devif_poll(&priv->lp_dev, lpc17_txpoll);
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: lpc17_txtimeout_expiry
@@ -1471,7 +1384,6 @@ static void lpc17_txtimeout_expiry(int argc, uint32_t arg, ...)
priv->lp_inten &= ~ETH_TXINTS;
lpc17_putreg(priv->lp_inten, LPC17_ETH_INTEN);
-#ifdef CONFIG_NET_NOINTS
/* Is the single TX work structure available? If not, then there is
* pending TX work to be done this must be a false alarm TX timeout.
*/
@@ -1482,33 +1394,28 @@ static void lpc17_txtimeout_expiry(int argc, uint32_t arg, ...)
work_queue(ETHWORK, &priv->lp_txwork, lpc17_txtimeout_work, priv, 0);
}
-
-#else
- /* Process the timeout now */
-
- lpc17_txtimeout_process(priv);
-#endif
}
/****************************************************************************
- * Function: lpc17_poll_process
+ * Function: lpc17_poll_work
*
* Description:
- * Perform the periodic poll. This may be called either from watchdog
- * timer logic or from the worker thread, depending upon the configuration.
+ * Perform periodic polling from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() as called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
+ * Ethernet interrupts are disabled
*
****************************************************************************/
-static void lpc17_poll_process(FAR struct lpc17_driver_s *priv)
+static void lpc17_poll_work(FAR void *arg)
{
+ FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg;
unsigned int prodidx;
unsigned int considx;
@@ -1516,6 +1423,7 @@ static void lpc17_poll_process(FAR struct lpc17_driver_s *priv)
* the TX poll if he are unable to accept another packet for transmission.
*/
+ net_lock();
if (lpc17_txdesc(priv) == OK)
{
/* If so, update TCP timing states and poll the network layer for new
@@ -1537,54 +1445,17 @@ static void lpc17_poll_process(FAR struct lpc17_driver_s *priv)
if (considx != prodidx)
{
-#ifdef CONFIG_NET_NOINTS
work_queue(ETHWORK, &priv->lp_rxwork, (worker_t)lpc17_rxdone_work,
priv, 0);
-
-#else /* CONFIG_NET_NOINTS */
- lpc17_rxdone_process(priv);
-
-#endif /* CONFIG_NET_NOINTS */
}
/* Setup the watchdog poll timer again */
(void)wd_start(priv->lp_txpoll, LPC17_WDDELAY, lpc17_poll_expiry,
1, priv);
+ net_unlock();
}
-/****************************************************************************
- * Function: lpc17_poll_work
- *
- * Description:
- * Perform periodic polling from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() as called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void lpc17_poll_work(FAR void *arg)
-{
- FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg;
- net_lock_t state;
-
- /* Perform the poll */
-
- state = net_lock();
- lpc17_poll_process(priv);
- net_unlock(state);
-}
-#endif
-
-
/****************************************************************************
* Function: lpc17_poll_expiry
*
@@ -1609,7 +1480,6 @@ static void lpc17_poll_expiry(int argc, uint32_t arg, ...)
DEBUGASSERT(arg);
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions.
*/
@@ -1628,12 +1498,6 @@ static void lpc17_poll_expiry(int argc, uint32_t arg, ...)
(void)wd_start(priv->lp_txpoll, LPC17_WDDELAY, lpc17_poll_expiry, 1, arg);
}
-
-#else
- /* Process the interrupt now */
-
- lpc17_poll_process(priv);
-#endif
}
/****************************************************************************
@@ -1924,45 +1788,6 @@ static int lpc17_ifdown(struct net_driver_s *dev)
return OK;
}
-/****************************************************************************
- * Function: lpc17_txavail_process
- *
- * Description:
- * Perform an out-of-cycle poll.
- *
- * Parameters:
- * dev - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called in normal user mode
- *
- ****************************************************************************/
-
-static inline void lpc17_txavail_process(FAR struct lpc17_driver_s *priv)
-{
- net_lock_t state;
-
- /* Ignore the notification if the interface is not yet up */
-
- state = net_lock();
- if (priv->lp_ifup)
- {
- /* Check if there is room in the hardware to hold another outgoing packet. */
-
- if (lpc17_txdesc(priv) == OK)
- {
- /* If so, then poll the network layer for new XMIT data */
-
- (void)devif_poll(&priv->lp_dev, lpc17_txpoll);
- }
- }
-
- net_unlock(state);
-}
-
/****************************************************************************
* Function: lpc17_txavail_work
*
@@ -1980,16 +1805,27 @@ static inline void lpc17_txavail_process(FAR struct lpc17_driver_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void lpc17_txavail_work(FAR void *arg)
{
FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)arg;
- /* Perform the poll */
+ /* Ignore the notification if the interface is not yet up */
- lpc17_txavail_process(priv);
+ net_lock();
+ if (priv->lp_ifup)
+ {
+ /* Check if there is room in the hardware to hold another outgoing packet. */
+
+ if (lpc17_txdesc(priv) == OK)
+ {
+ /* If so, then poll the network layer for new XMIT data */
+
+ (void)devif_poll(&priv->lp_dev, lpc17_txpoll);
+ }
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: lpc17_txavail
@@ -2014,7 +1850,6 @@ static int lpc17_txavail(struct net_driver_s *dev)
{
FAR struct lpc17_driver_s *priv = (FAR struct lpc17_driver_s *)dev->d_private;
-#ifdef CONFIG_NET_NOINTS
/* Is our single poll work structure available? It may not be if there
* are pending polling actions and we will have to ignore the Tx
* availability action (which is okay because all poll actions have,
@@ -2028,13 +1863,6 @@ static int lpc17_txavail(struct net_driver_s *dev)
work_queue(ETHWORK, &priv->lp_pollwork, lpc17_txavail_work, priv, 0);
}
-#else
-
- /* Perform the out-of-cycle poll now */
-
- lpc17_txavail_process(priv);
-#endif
-
return OK;
}
@@ -3206,6 +3034,7 @@ static inline int lpc17_ethinitialize(int intf)
#endif
{
struct lpc17_driver_s *priv;
+ uint8_t *pktbuf;
uint32_t regval;
int ret;
int i;
@@ -3225,11 +3054,17 @@ static inline int lpc17_ethinitialize(int intf)
{
(void)lpc17_configgpio(g_enetpins[i]);
}
+
lpc17_showpins();
+ /* Select the packet buffer */
+
+ pktbuf = &g_pktbuf[PKTBUF_SIZE * intf];
+
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct lpc17_driver_s));
+ priv->lp_dev.d_buf = pktbuf; /* Single packet buffer */
priv->lp_dev.d_ifup = lpc17_ifup; /* I/F down callback */
priv->lp_dev.d_ifdown = lpc17_ifdown; /* I/F up (new IP address) callback */
priv->lp_dev.d_txavail = lpc17_txavail; /* New TX data callback */
@@ -3237,7 +3072,7 @@ static inline int lpc17_ethinitialize(int intf)
priv->lp_dev.d_addmac = lpc17_addmac; /* Add multicast MAC address */
priv->lp_dev.d_rmmac = lpc17_rmmac; /* Remove multicast MAC address */
#endif
- priv->lp_dev.d_private = (void *)priv; /* Used to recover private state from dev */
+ priv->lp_dev.d_private = (void *)priv; /* Used to recover private state from dev */
#if CONFIG_LPC17_NINTERFACES > 1
# error "A mechanism to associate base address an IRQ with an interface is needed"
diff --git a/arch/arm/src/lpc43xx/chip/lpc43_gpdma.h b/arch/arm/src/lpc43xx/chip/lpc43_gpdma.h
index 2139e09766f..e9912534dd5 100644
--- a/arch/arm/src/lpc43xx/chip/lpc43_gpdma.h
+++ b/arch/arm/src/lpc43xx/chip/lpc43_gpdma.h
@@ -70,12 +70,12 @@
#define LPC43_GPDMA_CONTROL_CHOFFSET 0x000c /* DMA Channel Control Register */
#define LPC43_GPDMA_CONFIG_CHOFFSET 0x0010 /* DMA Channel Configuration Register */
-#define LPC43_GPDMA_CHOFFSET(n) (0x0100 ((n) << 5))
+#define LPC43_GPDMA_CHOFFSET(n) (0x0100 + ((n) << 5))
#define LPC43_GPDMA_SRCADDR_OFFSET(n) (LPC43_GPDMA_CHOFFSET(n)+LPC43_GPDMA_SRCADDR_CHOFFSET)
#define LPC43_GPDMA_DESTADDR_OFFSET(n) (LPC43_GPDMA_CHOFFSET(n)+LPC43_GPDMA_DESTADDR_CHOFFSET)
#define LPC43_GPDMA_LLI_OFFSET(n) (LPC43_GPDMA_CHOFFSET(n)+LPC43_GPDMA_LLI_CHOFFSET)
#define LPC43_GPDMA_CONTROL_OFFSET(n) (LPC43_GPDMA_CHOFFSET(n)+LPC43_GPDMA_CONTROL_CHOFFSET)
-#define LPC43_GPDMA_CONFIG_OFFSET(n) (LPC43_GPDMA_CHOFFSET(n)+LPC43_GPDMA_CONFIG_CHOFFSET)
+#define LPC43_GPDMA_CONFIG_OFFSET_(n) (LPC43_GPDMA_CHOFFSET(n)+LPC43_GPDMA_CONFIG_CHOFFSET)
#define LPC43_GPDMA_SRCADDR0_OFFSET 0x0100 /* DMA Channel 0 Source Address Register */
#define LPC43_GPDMA_DESTADDR0_OFFSET 0x0104 /* DMA Channel 0 Destination Address Register */
@@ -149,7 +149,7 @@
#define LPC43_GPDMA_DESTADDR(n) (LPC43_DMA_BASE+LPC43_GPDMA_DESTADDR_OFFSET(n))
#define LPC43_GPDMA_LLI(n) (LPC43_DMA_BASE+LPC43_GPDMA_LLI_OFFSET(n))
#define LPC43_GPDMA_CONTROL(n) (LPC43_DMA_BASE+LPC43_GPDMA_CONTROL_OFFSET(n))
-#define LPC43_GPDMA_CONFIG(n) (LPC43_DMA_BASE+LPC43_GPDMA_CONFIG_OFFSET(n))
+#define LPC43_GPDMA_CONFIG_(n) (LPC43_DMA_BASE+LPC43_GPDMA_CONFIG_OFFSET_(n))
#define LPC43_GPDMA_SRCADDR0 (LPC43_DMA_BASE+LPC43_GPDMA_SRCADDR0_OFFSET)
#define LPC43_GPDMA_DESTADDR0 (LPC43_DMA_BASE+LPC43_GPDMA_DESTADDR0_OFFSET)
@@ -203,6 +203,9 @@
/* Common macros for DMA channel and source bit settings */
+#define DMACH_ALL (0xff)
+#define LPC43_NDMACH 8 /* Eight DMA channels */
+#define LPC43_NDMAREQ (16) /* The number of DMA requests */
#define GPDMA_CHANNEL(n) (1 << (n)) /* Bits 0-7 correspond to DMA channel 0-7 */
#define GPDMA_SOURCE(n) (1 << (n)) /* Bits 0-15 correspond to DMA source 0-15 */
#define GPDMA_REQUEST(n) (1 << (n)) /* Bits 0-15 correspond to DMA request 0-15 */
diff --git a/arch/arm/src/lpc43xx/chip/lpc43_sdmmc.h b/arch/arm/src/lpc43xx/chip/lpc43_sdmmc.h
index 1236d82f31c..05a51178fb2 100644
--- a/arch/arm/src/lpc43xx/chip/lpc43_sdmmc.h
+++ b/arch/arm/src/lpc43xx/chip/lpc43_sdmmc.h
@@ -143,10 +143,11 @@
#define SDMMC_CTRL_CEATAINT (1 << 11) /* Bit 11: CE-ATA device interrupts enabled */
/* Bits 12-15: Reserved */
#define SDMMC_CTRL_CDVA0 (1 << 16) /* Bit 16: Controls SD_VOLT0 pin */
-#define SDMMC_CTRL_CDVA0 (1 << 17) /* Bit 17: Controls SD_VOLT1 pin */
-#define SDMMC_CTRL_CDVA0 (1 << 18) /* Bit 18: Controls SD_VOLT2 pin */
+#define SDMMC_CTRL_CDVA1 (1 << 17) /* Bit 17: Controls SD_VOLT1 pin */
+#define SDMMC_CTRL_CDVA2 (1 << 18) /* Bit 18: Controls SD_VOLT2 pin */
/* Bits 19-23: Reserved */
-#define SDMMC_CTRL_INTDMA (1 << 25) /* Bit 24: SD/MMC DMA use */
+ /* Bit 24: Reserved - always write it as 0 */
+#define SDMMC_CTRL_INTDMA (1 << 25) /* Bit 25: SD/MMC DMA use */
/* Bits 26-31: Reserved */
/* Power Enable Register (PWREN) */
diff --git a/arch/arm/src/lpc43xx/lpc43_ethernet.c b/arch/arm/src/lpc43xx/lpc43_ethernet.c
index c96f1a75511..6060c9cb2af 100644
--- a/arch/arm/src/lpc43xx/lpc43_ethernet.c
+++ b/arch/arm/src/lpc43xx/lpc43_ethernet.c
@@ -53,11 +53,7 @@
#include
#include
#include
-
-#ifdef CONFIG_NET_NOINTS
-# include
-#endif
-
+#include
#include
#include
#include
@@ -87,13 +83,12 @@
* is required.
*/
-#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
+#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
-#endif
+#else
-/* Select work queue */
+ /* Select work queue */
-#if defined(CONFIG_SCHED_WORKQUEUE)
# if defined(CONFIG_LPC43_ETHERNET_HPWORK)
# define ETHWORK HPWORK
# elif defined(CONFIG_LPC43_ETHERNET_LPWORK)
@@ -164,12 +159,6 @@
#undef CONFIG_LPC43_ETH_ENHANCEDDESC
#undef CONFIG_LPC43_ETH_HWCHECKSUM
-/* Ethernet buffer sizes, number of buffers, and number of descriptors */
-
-#ifndef CONFIG_NET_MULTIBUFFER
-# error "CONFIG_NET_MULTIBUFFER is required"
-#endif
-
/* Add 4 to the configured buffer size to account for the 2 byte checksum
* memory needed at the end of the maximum size packet. Buffer sizes must
* be an even multiple of 4, 8, or 16 bytes (depending on buswidth). We
@@ -530,9 +519,7 @@ struct lpc43_ethmac_s
uint8_t fduplex : 1; /* Full (vs. half) duplex */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
-#ifdef CONFIG_NET_NOINTS
struct work_s work; /* For deferring work to the work queue */
-#endif
/* This holds the information visible to the NuttX network */
@@ -605,34 +592,26 @@ static int lpc43_recvframe(FAR struct lpc43_ethmac_s *priv);
static void lpc43_receive(FAR struct lpc43_ethmac_s *priv);
static void lpc43_freeframe(FAR struct lpc43_ethmac_s *priv);
static void lpc43_txdone(FAR struct lpc43_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void lpc43_interrupt_work(FAR void *arg);
-#endif
static int lpc43_interrupt(int irq, FAR void *context);
/* Watchdog timer expirations */
-static inline void lpc43_txtimeout_process(FAR struct lpc43_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void lpc43_txtimeout_work(FAR void *arg);
-#endif
static void lpc43_txtimeout_expiry(int argc, uint32_t arg, ...);
-static inline void lpc43_poll_process(FAR struct lpc43_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void lpc43_poll_work(FAR void *arg);
-#endif
static void lpc43_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int lpc43_ifup(struct net_driver_s *dev);
static int lpc43_ifdown(struct net_driver_s *dev);
-static inline void lpc43_txavail_process(FAR struct lpc43_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void lpc43_txavail_work(FAR void *arg);
-#endif
static int lpc43_txavail(struct net_driver_s *dev);
+
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
static int lpc43_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
#endif
@@ -1906,29 +1885,32 @@ static void lpc43_txdone(FAR struct lpc43_ethmac_s *priv)
}
/****************************************************************************
- * Function: lpc43_interrupt_process
+ * Function: lpc43_interrupt_work
*
* Description:
- * Interrupt processing. This may be performed either within the interrupt
- * handler or on the worker thread, depending upon the configuration
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void lpc43_interrupt_process(FAR struct lpc43_ethmac_s *priv)
+static void lpc43_interrupt_work(FAR void *arg)
{
+ FAR struct lpc43_ethmac_s *priv = (FAR struct lpc43_ethmac_s *)arg;
uint32_t dmasr;
+ DEBUGASSERT(priv);
+
/* Get the DMA interrupt status bits (no MAC interrupts are expected) */
+ net_lock();
dmasr = lpc43_getreg(LPC43_ETH_DMASTAT);
/* Mask only enabled interrupts. This depends on the fact that the interrupt
@@ -1980,7 +1962,6 @@ static inline void lpc43_interrupt_process(FAR struct lpc43_ethmac_s *priv)
/* Handle error interrupt only if CONFIG_DEBUG_NET is eanbled */
#ifdef CONFIG_DEBUG_NET
-
/* Check if there are pending "abnormal" interrupts */
if ((dmasr & ETH_DMAINT_AIS) != 0)
@@ -1997,45 +1978,13 @@ static inline void lpc43_interrupt_process(FAR struct lpc43_ethmac_s *priv)
lpc43_putreg(ETH_DMAINT_AIS, LPC43_ETH_DMASTAT);
}
-#endif
-}
-/****************************************************************************
- * Function: lpc43_interrupt_work
- *
- * Description:
- * Perform interrupt related work from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() was called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void lpc43_interrupt_work(FAR void *arg)
-{
- FAR struct lpc43_ethmac_s *priv = (FAR struct lpc43_ethmac_s *)arg;
- net_lock_t state;
-
- DEBUGASSERT(priv);
-
- /* Process pending Ethernet interrupts */
-
- state = net_lock();
- lpc43_interrupt_process(priv);
- net_unlock(state);
+ net_unlock();
/* Re-enable Ethernet interrupts at the NVIC */
up_enable_irq(LPC43M4_IRQ_ETHERNET);
}
-#endif
/****************************************************************************
* Function: lpc43_interrupt
@@ -2057,8 +2006,6 @@ static void lpc43_interrupt_work(FAR void *arg)
static int lpc43_interrupt(int irq, FAR void *context)
{
FAR struct lpc43_ethmac_s *priv = &g_lpc43ethmac;
-
-#ifdef CONFIG_NET_NOINTS
uint32_t dmasr;
/* Get the DMA interrupt status bits (no MAC interrupts are expected) */
@@ -2094,49 +2041,9 @@ static int lpc43_interrupt(int irq, FAR void *context)
work_queue(ETHWORK, &priv->work, lpc43_interrupt_work, priv, 0);
}
-#else
- /* Process the interrupt now */
-
- lpc43_interrupt_process(priv);
-#endif
-
return OK;
}
-/****************************************************************************
- * Function: lpc43_txtimeout_process
- *
- * Description:
- * Process a TX timeout. Called from the either the watchdog timer
- * expiration logic or from the worker thread, depending upon the
- * configuration. The timeout means that the last TX never completed.
- * Reset the hardware and start again.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Global interrupts are disabled by the watchdog logic.
- *
- ****************************************************************************/
-
-static inline void lpc43_txtimeout_process(FAR struct lpc43_ethmac_s *priv)
-{
- /* Then reset the hardware. Just take the interface down, then back
- * up again.
- */
-
- lpc43_ifdown(&priv->dev);
- lpc43_ifup(&priv->dev);
-
- /* Then poll the network for new XMIT data */
-
- lpc43_dopoll(priv);
-}
-
/****************************************************************************
* Function: lpc43_txtimeout_work
*
@@ -2154,19 +2061,23 @@ static inline void lpc43_txtimeout_process(FAR struct lpc43_ethmac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void lpc43_txtimeout_work(FAR void *arg)
{
FAR struct lpc43_ethmac_s *priv = (FAR struct lpc43_ethmac_s *)arg;
- net_lock_t state;
- /* Process pending Ethernet interrupts */
+ /* Then reset the hardware. Just take the interface down, then back
+ * up again.
+ */
- state = net_lock();
- lpc43_txtimeout_process(priv);
- net_unlock(state);
+ net_lock();
+ lpc43_ifdown(&priv->dev);
+ lpc43_ifup(&priv->dev);
+
+ /* Then poll the network for new XMIT data */
+
+ lpc43_dopoll(priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: lpc43_txtimeout_expiry
@@ -2193,7 +2104,6 @@ static void lpc43_txtimeout_expiry(int argc, uint32_t arg, ...)
ninfo("Timeout!\n");
-#ifdef CONFIG_NET_NOINTS
/* Disable further Ethernet interrupts. This will prevent some race
* conditions with interrupt work. There is still a potential race
* condition with interrupt work that is already queued and in progress.
@@ -2212,33 +2122,28 @@ static void lpc43_txtimeout_expiry(int argc, uint32_t arg, ...)
/* Schedule to perform the TX timeout processing on the worker thread. */
work_queue(ETHWORK, &priv->work, lpc43_txtimeout_work, priv, 0);
-
-#else
- /* Process the timeout now */
-
- lpc43_txtimeout_process(priv);
-#endif
}
/****************************************************************************
- * Function: lpc43_poll_process
+ * Function: lpc43_poll_work
*
* Description:
- * Perform the periodic poll. This may be called either from watchdog
- * timer logic or from the worker thread, depending upon the configuration.
+ * Perform periodic polling from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() as called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
+ * Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void lpc43_poll_process(FAR struct lpc43_ethmac_s *priv)
+static void lpc43_poll_work(FAR void *arg)
{
+ FAR struct lpc43_ethmac_s *priv = (FAR struct lpc43_ethmac_s *)arg;
FAR struct net_driver_s *dev = &priv->dev;
/* Check if the next TX descriptor is owned by the Ethernet DMA or CPU. We
@@ -2252,6 +2157,7 @@ static inline void lpc43_poll_process(FAR struct lpc43_ethmac_s *priv)
* CONFIG_LPC43_ETH_NTXDESC).
*/
+ net_lock();
if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0 &&
priv->txhead->tdes2 == 0)
{
@@ -2287,39 +2193,9 @@ static inline void lpc43_poll_process(FAR struct lpc43_ethmac_s *priv)
/* Setup the watchdog poll timer again */
(void)wd_start(priv->txpoll, LPC43_WDDELAY, lpc43_poll_expiry, 1, priv);
+ net_unlock();
}
-/****************************************************************************
- * Function: lpc43_poll_work
- *
- * Description:
- * Perform periodic polling from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() as called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void lpc43_poll_work(FAR void *arg)
-{
- FAR struct lpc43_ethmac_s *priv = (FAR struct lpc43_ethmac_s *)arg;
- net_lock_t state;
-
- /* Perform the poll */
-
- state = net_lock();
- lpc43_poll_process(priv);
- net_unlock(state);
-}
-#endif
-
/****************************************************************************
* Function: lpc43_poll_expiry
*
@@ -2342,7 +2218,6 @@ static void lpc43_poll_expiry(int argc, uint32_t arg, ...)
{
FAR struct lpc43_ethmac_s *priv = (FAR struct lpc43_ethmac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions.
*/
@@ -2362,12 +2237,6 @@ static void lpc43_poll_expiry(int argc, uint32_t arg, ...)
(void)wd_start(priv->txpoll, LPC43_WDDELAY, lpc43_poll_expiry, 1,
(uint32_t)priv);
}
-
-#else
- /* Process the interrupt now */
-
- lpc43_poll_process(priv);
-#endif
}
/****************************************************************************
@@ -2473,37 +2342,6 @@ static int lpc43_ifdown(struct net_driver_s *dev)
return OK;
}
-/****************************************************************************
- * Function: lpc43_txavail_process
- *
- * Description:
- * Perform an out-of-cycle poll.
- *
- * Parameters:
- * priv - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called in normal user mode
- *
- ****************************************************************************/
-
-static inline void lpc43_txavail_process(FAR struct lpc43_ethmac_s *priv)
-{
- ninfo("ifup: %d\n", priv->ifup);
-
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
- {
- /* Poll for new XMIT data */
-
- lpc43_dopoll(priv);
- }
-}
-
/****************************************************************************
* Function: lpc43_txavail_work
*
@@ -2521,19 +2359,23 @@ static inline void lpc43_txavail_process(FAR struct lpc43_ethmac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void lpc43_txavail_work(FAR void *arg)
{
FAR struct lpc43_ethmac_s *priv = (FAR struct lpc43_ethmac_s *)arg;
- net_lock_t state;
- /* Perform the poll */
+ /* Ignore the notification if the interface is not yet up */
- state = net_lock();
- lpc43_txavail_process(priv);
- net_unlock(state);
+ net_lock();
+ ninfo("ifup: %d\n", priv->ifup);
+ if (priv->ifup)
+ {
+ /* Poll for new XMIT data */
+
+ lpc43_dopoll(priv);
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: lpc43_txavail
@@ -2558,7 +2400,6 @@ static int lpc43_txavail(struct net_driver_s *dev)
{
FAR struct lpc43_ethmac_s *priv = (FAR struct lpc43_ethmac_s *)dev->d_private;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions and we will have to ignore the Tx
* availability action.
@@ -2571,21 +2412,6 @@ static int lpc43_txavail(struct net_driver_s *dev)
work_queue(ETHWORK, &priv->work, lpc43_txavail_work, priv, 0);
}
-#else
- irqstate_t flags;
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
- */
-
- flags = enter_critical_section();
-
- /* Perform the out-of-cycle poll now */
-
- lpc43_txavail_process(priv);
- leave_critical_section(flags);
-#endif
-
return OK;
}
diff --git a/arch/arm/src/lpc43xx/lpc43_gpdma.c b/arch/arm/src/lpc43xx/lpc43_gpdma.c
index d104080a94d..ab2942189cd 100644
--- a/arch/arm/src/lpc43xx/lpc43_gpdma.c
+++ b/arch/arm/src/lpc43xx/lpc43_gpdma.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/lpc43xx/lpc43_gpdma.c
*
- * Copyright (C) 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -52,11 +52,218 @@
#include "chip.h"
-#include "lpc43_syscon.h"
+#include "lpc43_ccu.h"
+#include "lpc43_creg.h"
#include "lpc43_gpdma.h"
#ifdef CONFIG_LPC43_GPDMA
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* This structure represents the state of one DMA channel */
+
+struct lpc43_dmach_s
+{
+ uint8_t chn; /* The DMA channel number */
+ bool inuse; /* True: The channel is in use */
+ bool inprogress; /* True: DMA is in progress on this channel */
+ uint16_t nxfrs; /* Number of bytes to transfers */
+ dma_callback_t callback; /* DMA completion callback function */
+ void *arg; /* Argument to pass to the callback function */
+};
+
+/* This structure represents the state of the LPC43 DMA block */
+
+struct lpc43_gpdma_s
+{
+ sem_t exclsem; /* For exclusive access to the DMA channel list */
+
+ /* This is the state of each DMA channel */
+
+ struct lpc43_dmach_s dmach[LPC43_NDMACH];
+};
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* The state of the LPC43 DMA block */
+
+static struct lpc43_gpdma_s g_gpdma;
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+/* If the following value is zero, then there is no DMA in progress. This
+ * value is needed in the IDLE loop to determine if the IDLE loop should
+ * go into lower power power consumption modes. According to the LPC43xx
+ * User Manual: "The DMA controller can continue to work in Sleep mode, and
+ * has access to the peripheral SRAMs and all peripheral registers. The
+ * flash memory and the Main SRAM are not available in Sleep mode, they are
+ * disabled in order to save power."
+ */
+
+volatile uint8_t g_dma_inprogress;
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: lpc43_dmainprogress
+ *
+ * Description:
+ * Another DMA has started. Increment the g_dma_inprogress counter.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lpc43_dmainprogress(struct lpc43_dmach_s *dmach)
+{
+ irqstate_t flags;
+
+ /* Increment the DMA in progress counter */
+
+ flags = enter_critical_section();
+ DEBUGASSERT(!dmach->inprogress && g_dma_inprogress < LPC43_NDMACH);
+ g_dma_inprogress++;
+ dmach->inprogress = true;
+ leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: lpc43_dmadone
+ *
+ * Description:
+ * A DMA has completed. Decrement the g_dma_inprogress counter.
+ *
+ * This function is called only from lpc43_dmastop which, in turn, will be
+ * called either by the user directly, by the user indirectly via
+ * lpc43_dmafree(), or from gpdma_interrupt when the transfer completes.
+ *
+ * NOTE: In the first two cases, we must be able to handle the case where
+ * there is no DMA in progress and gracefully ignore the call.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static void lpc43_dmadone(struct lpc43_dmach_s *dmach)
+{
+ irqstate_t flags;
+
+ /* Increment the DMA in progress counter */
+
+ flags = enter_critical_section();
+ if (dmach->inprogress)
+ {
+ DEBUGASSERT(g_dma_inprogress > 0);
+ dmach->inprogress = false;
+ g_dma_inprogress--;
+ }
+
+ leave_critical_section(flags);
+}
+
+/****************************************************************************
+ * Name: gpdma_interrupt
+ *
+ * Description:
+ * The common GPDMA interrupt handler.
+ *
+ * Returned Value:
+ * None
+ *
+ ****************************************************************************/
+
+static int gpdma_interrupt(int irq, FAR void *context)
+{
+ struct lpc43_dmach_s *dmach;
+ uint32_t regval;
+ uint32_t chbit;
+ int result;
+ int i;
+
+ /* Check each DMA channel */
+
+ for (i = 0; i < LPC43_NDMACH; i++)
+ {
+ chbit = GPDMA_CHANNEL((uint32_t)i);
+
+ /* Is there an interrupt pending for this channel? If the bit for
+ * this channel is set, that indicates that a specific DMA channel
+ * interrupt request is active. The request can be generated from
+ * either the error or terminal count interrupt requests.
+ */
+
+ regval = getreg32(LPC43_GPDMA_INTSTAT);
+ if ((regval & chbit) != 0)
+ {
+ /* Yes.. Is this channel assigned? Is there a callback function? */
+
+ dmach = &g_gpdma.dmach[i];
+ if (dmach->inuse && dmach->callback)
+ {
+ /* Yes.. did an error occur? */
+
+ regval = getreg32(LPC43_GPDMA_INTERRSTAT);
+ if ((regval & chbit) != 0)
+ {
+ /* Yes.. report error status */
+
+ result = -EIO;
+ }
+
+ /* Then this must be a terminal transfer event */
+
+ else
+ {
+ /* Let's make sure it is the terminal transfer event. */
+
+ regval = getreg32(LPC43_GPDMA_INTTCSTAT);
+ if ((regval & chbit) != 0)
+ {
+ result = OK;
+ }
+
+ /* This should not happen */
+
+ else
+ {
+ result = -EINVAL;
+ }
+ }
+
+ /* Perform the callback */
+
+ dmach->callback((DMA_HANDLE)dmach, dmach->arg, result);
+ }
+
+ /* Disable this channel, mask any further interrupts for
+ * this channel, and clear any pending interrupts.
+ */
+
+ lpc43_dmastop((DMA_HANDLE)dmach);
+ }
+ }
+
+ return OK;
+}
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -68,12 +275,101 @@
* Initialize the GPDMA subsystem.
*
* Returned Value:
+ * Zero on success; A negated errno value on failure.
+ *
+ ****************************************************************************/
+
+void weak_function up_dmainitialize(void)
+{
+ uint32_t regval;
+ int ret;
+ int i;
+
+ /* Enable clocking to the GPDMA block */
+
+ regval = getreg32(LPC43_CCU1_M4_DMA_CFG);
+ regval |= CCU_CLK_CFG_RUN;
+ putreg32(regval, LPC43_CCU1_M4_DMA_CFG);
+
+ /* Reset all channel configurations */
+
+ for (i = 0; i < LPC43_NDMACH; i++)
+ {
+ putreg32(0, LPC43_GPDMA_CONFIG_(i));
+ }
+
+ /* Clear all DMA interrupts */
+
+ putreg32(DMACH_ALL, LPC43_GPDMA_INTTCCLEAR);
+ putreg32(DMACH_ALL, LPC43_GPDMA_INTERRCLR);
+
+ /* Initialize the DMA state structure */
+
+ sem_init(&g_gpdma.exclsem, 0, 1);
+
+ for (i = 0; i < LPC43_NDMACH; i++)
+ {
+ g_gpdma.dmach[i].chn = i; /* Channel number */
+ g_gpdma.dmach[i].inuse = false; /* Channel is not in-use */
+ }
+
+ /* Attach and enable the common interrupt handler */
+
+ ret = irq_attach(LPC43M4_IRQ_DMA, gpdma_interrupt);
+ if (ret == OK)
+ {
+ up_enable_irq(LPC43M4_IRQ_DMA);
+ }
+
+ /* Enable the DMA controller (for little endian operation) */
+
+ putreg32(GPDMA_CONFIG_ENA, LPC43_GPDMA_CONFIG);
+}
+
+/****************************************************************************
+ * Name: lpc43_dmaconfigure
+ *
+ * Description:
+ * Configure a DMA request. Each DMA request may have four different DMA
+ * request sources. This associates one of the sources with a DMA request.
+ *
+ * Returned Value:
* None
*
****************************************************************************/
-void lpc43_dmainitilaize(void)
+void lpc43_dmaconfigure(uint8_t dmarequest, uint8_t dmasrc)
{
+ uint32_t regval;
+
+ DEBUGASSERT(dmarequest < LPC43_NDMAREQ);
+
+ /* Set or clear the DMASEL bit corresponding to the request number */
+
+ regval = getreg32(LPC43_CREG_DMAMUX);
+
+ switch (dmasrc)
+ {
+ case 0:
+ regval &= ~(3 << dmarequest);
+ break;
+
+ case 1:
+ regval &= ~(3 << dmarequest);
+ regval |= (1 << dmarequest);
+ break;
+
+ case 2:
+ regval &= ~(3 << dmarequest);
+ regval |= (2 << dmarequest);
+ break;
+
+ case 3:
+ regval |= (3 << dmarequest);
+ break;
+ }
+
+ putreg32(regval, LPC43_CREG_DMAMUX);
}
/****************************************************************************
@@ -92,7 +388,37 @@ void lpc43_dmainitilaize(void)
DMA_HANDLE lpc43_dmachannel(void)
{
- return NULL;
+ struct lpc43_dmach_s *dmach = NULL;
+ int ret;
+ int i;
+
+ /* Get exclusive access to the GPDMA state structure */
+
+ do
+ {
+ ret = sem_wait(&g_gpdma.exclsem);
+ DEBUGASSERT(ret == 0 || errno == EINTR);
+ }
+ while (ret < 0);
+
+ /* Find an available DMA channel */
+
+ for (i = 0; i < LPC43_NDMACH; i++)
+ {
+ if (!g_gpdma.dmach[i].inuse)
+ {
+ /* Found one! */
+
+ dmach = &g_gpdma.dmach[i];
+ g_gpdma.dmach[i].inuse = true;
+ break;
+ }
+ }
+
+ /* Return what we found (or not) */
+
+ sem_post(&g_gpdma.exclsem);
+ return (DMA_HANDLE)dmach;
}
/****************************************************************************
@@ -110,6 +436,19 @@ DMA_HANDLE lpc43_dmachannel(void)
void lpc43_dmafree(DMA_HANDLE handle)
{
+ struct lpc43_dmach_s *dmach = (DMA_HANDLE)handle;
+
+ DEBUGASSERT(dmach && dmach->inuse);
+
+ /* Make sure that the DMA channel was properly stopped */
+
+ lpc43_dmastop(handle);
+
+ /* Mark the channel available. This is an atomic operation and needs no
+ * special protection.
+ */
+
+ dmach->inuse = false;
}
/****************************************************************************
@@ -123,7 +462,87 @@ void lpc43_dmafree(DMA_HANDLE handle)
int lpc43_dmarxsetup(DMA_HANDLE handle, uint32_t control, uint32_t config,
uint32_t srcaddr, uint32_t destaddr, size_t nbytes)
{
- return -ENOSYS;
+ struct lpc43_dmach_s *dmach = (DMA_HANDLE)handle;
+ uint32_t chbit;
+ uint32_t regval;
+ uint32_t base;
+
+ DEBUGASSERT(dmach && dmach->inuse && nbytes < 4096);
+
+ chbit = GPDMA_CHANNEL((uint32_t)dmach->chn);
+ base = LPC43_GPDMA_CHANNEL((uint32_t)dmach->chn);
+
+ /* Put the channel in a known state. Zero disables everything */
+
+ putreg32(0, base + LPC43_GPDMA_CONTROL_CHOFFSET);
+ putreg32(0, base + LPC43_GPDMA_CONFIG_CHOFFSET);
+
+ /* "Programming a DMA channel
+ *
+ * 1. "Choose a free DMA channel with the priority needed. DMA channel 0
+ * has the highest priority and DMA channel 7 the lowest priority.
+ */
+
+ regval = getreg32(LPC43_GPDMA_ENBLDCHNS);
+ if ((regval & chbit) != 0)
+ {
+ /* There is an active DMA on this channel! */
+
+ return -EBUSY;
+ }
+
+ /* 2. "Clear any pending interrupts on the channel to be used by writing
+ * to the DMACIntTCClear and DMACIntErrClear register. The previous
+ * channel operation might have left interrupt active.
+ */
+
+ putreg32(chbit, LPC43_GPDMA_INTTCCLEAR);
+ putreg32(chbit, LPC43_GPDMA_INTERRCLR);
+
+ /* 3. "Write the source address into the DMACCxSrcAddr register. */
+
+ putreg32(srcaddr, base + LPC43_GPDMA_SRCADDR_CHOFFSET);
+
+ /* 4. "Write the destination address into the DMACCxDestAddr register. */
+
+ putreg32(destaddr, base + LPC43_GPDMA_DESTADDR_CHOFFSET);
+
+ /* 5. "Write the address of the next LLI into the DMACCxLLI register. If
+ * the transfer comprises of a single packet of data then 0 must be
+ * written into this register.
+ */
+
+ putreg32(0, base + LPC43_GPDMA_LLI_CHOFFSET);
+
+ /* 6. "Write the control information into the DMACCxControl register."
+ *
+ * The caller provides all CONTROL register fields except for the transfer
+ * size which is passed as a separate parameter and for the terminal count
+ * interrupt enable bit which is controlled by the driver.
+ */
+
+ regval = control & ~(GPDMA_CONTROL_XFRSIZE_MASK | GPDMA_CONTROL_IE);
+ regval |= ((uint32_t)nbytes << GPDMA_CONTROL_XFRSIZE_SHIFT);
+ putreg32(regval, base + LPC43_GPDMA_CONTROL_CHOFFSET);
+
+ /* Save the number of transfer to perform for lpc43_dmastart */
+
+ dmach->nxfrs = (uint16_t)nbytes;
+
+ /* 7. "Write the channel configuration information into the DMACCxConfig
+ * register. If the enable bit is set then the DMA channel is
+ * automatically enabled."
+ *
+ * Only the SRCPER, DSTPER, and FCNTRL fields of the CONFIG register
+ * are provided by the caller. Little endian is assumed.
+ */
+
+ regval = config & (GPDMA_CONFIG_SRCPER_MASK |
+ GPDMA_CONFIG_DESTPER_MASK |
+ GPDMA_CONFIG_FCNTRL_MASK);
+ putreg32(regval, base + LPC43_GPDMA_CONFIG_CHOFFSET);
+
+ return OK;
}
/****************************************************************************
@@ -136,7 +555,53 @@ int lpc43_dmarxsetup(DMA_HANDLE handle, uint32_t control, uint32_t config,
int lpc43_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
{
- return -ENOSYS;
+ struct lpc43_dmach_s *dmach = (DMA_HANDLE)handle;
+ uint32_t regval;
+ uint32_t chbit;
+ uint32_t base;
+
+ DEBUGASSERT(dmach && dmach->inuse && callback);
+
+ /* Save the callback information */
+
+ dmach->callback = callback;
+ dmach->arg = arg;
+
+ /* Increment the count of DMAs in-progress. This count will be
+ * decremented when lpc43_dmastop() is called, either by the user,
+ * indirectly via lpc43_dmafree(), or from gpdma_interrupt when the
+ * transfer completes.
+ */
+
+ lpc43_dmainprogress(dmach);
+
+ /* Clear any pending DMA interrupts */
+
+ chbit = GPDMA_CHANNEL((uint32_t)dmach->chn);
+ putreg32(chbit, LPC43_GPDMA_INTTCCLEAR);
+ putreg32(chbit, LPC43_GPDMA_INTERRCLR);
+
+ /* Enable terminal count interrupt. Note that we need to restore the
+ * number transfers. That is because the value has a different meaning
+ * when it is read.
+ */
+
+ base = LPC43_GPDMA_CHANNEL((uint32_t)dmach->chn);
+ regval = getreg32(base + LPC43_GPDMA_CONTROL_CHOFFSET);
+ regval &= ~GPDMA_CONTROL_XFRSIZE_MASK;
+ regval |= (GPDMA_CONTROL_IE | ((uint32_t)dmach->nxfrs << GPDMA_CONTROL_XFRSIZE_SHIFT));
+ putreg32(regval, base + LPC43_GPDMA_CONTROL_CHOFFSET);
+
+ /* Enable the channel and unmask terminal count and error interrupts.
+ * According to the user manual, zero masks and one unmasks (hence,
+ * these are really enables).
+ */
+
+ regval = getreg32(base + LPC43_GPDMA_CONFIG_CHOFFSET);
+ regval |= (GPDMA_CONFIG_ENA | GPDMA_CONFIG_IE | GPDMA_CONFIG_ITC);
+ putreg32(regval, base + LPC43_GPDMA_CONFIG_CHOFFSET);
+
+ return OK;
}
/****************************************************************************
@@ -147,10 +612,40 @@ int lpc43_dmastart(DMA_HANDLE handle, dma_callback_t callback, void *arg)
* reset and lpc43_dmasetup() must be called before lpc43_dmastart() can be
* called again
*
+ * This function will be called either by the user directly, by the user
+ * indirectly via lpc43_dmafree(), or from gpdma_interrupt when the
+ * transfer completes.
+ *
****************************************************************************/
void lpc43_dmastop(DMA_HANDLE handle)
{
+ struct lpc43_dmach_s *dmach = (DMA_HANDLE)handle;
+ uint32_t regaddr;
+ uint32_t regval;
+ uint32_t chbit;
+
+ DEBUGASSERT(dmach && dmach->inuse);
+
+ /* Disable this channel and mask any further interrupts from the channel.
+ * this channel. The channel is disabled by clearning the channel
+ * enable bit. Any outstanding data in the FIFOs is lost.
+ */
+
+ regaddr = LPC43_GPDMA_CONFIG_((uint32_t)dmach->chn);
+ regval = getreg32(regaddr);
+ regval &= ~(GPDMA_CONFIG_ENA | GPDMA_CONFIG_IE | GPDMA_CONFIG_ITC);
+ putreg32(regval, regaddr);
+
+ /* Clear any pending interrupts for this channel */
+
+ chbit = GPDMA_CHANNEL((uint32_t)dmach->chn);
+ putreg32(chbit, LPC43_GPDMA_INTTCCLEAR);
+ putreg32(chbit, LPC43_GPDMA_INTERRCLR);
+
+ /* Decrement the count of DMAs in progress */
+
+ lpc43_dmadone(dmach);
}
/****************************************************************************
@@ -164,6 +659,34 @@ void lpc43_dmastop(DMA_HANDLE handle)
#ifdef CONFIG_DEBUG_DMA
void lpc43_dmasample(DMA_HANDLE handle, struct lpc43_dmaregs_s *regs)
{
+ struct lpc43_dmach_s *dmach = (DMA_HANDLE)handle;
+ uint32_t base;
+
+ DEBUGASSERT(dmach);
+
+ /* Sample the global DMA registers */
+
+ regs->gbl.intst = getreg32(LPC43_GPDMA_INTSTAT);
+ regs->gbl.inttcstat = getreg32(LPC43_GPDMA_INTTCSTAT);
+ regs->gbl.interrstat = getreg32(LPC43_GPDMA_INTERRSTAT);
+ regs->gbl.rawinttcstat = getreg32(LPC43_GPDMA_RAWINTTCSTAT);
+ regs->gbl.rawinterrstat = getreg32(LPC43_GPDMA_RAWINTERRSTAT);
+ regs->gbl.enbldchns = getreg32(LPC43_GPDMA_ENBLDCHNS);
+ regs->gbl.softbreq = getreg32(LPC43_GPDMA_SOFTBREQ);
+ regs->gbl.softsreq = getreg32(LPC43_GPDMA_SOFTSREQ);
+ regs->gbl.softlbreq = getreg32(LPC43_GPDMA_SOFTLBREQ);
+ regs->gbl.softlsreq = getreg32(LPC43_GPDMA_SOFTLSREQ);
+ regs->gbl.config = getreg32(LPC43_GPDMA_CONFIG);
+ regs->gbl.sync = getreg32(LPC43_GPDMA_SYNC);
+
+ /* Sample the DMA channel registers */
+
+ base = LPC43_GPDMA_CHANNEL((uint32_t)dmach->chn);
+ regs->ch.srcaddr = getreg32(base + LPC43_GPDMA_SRCADDR_CHOFFSET);
+ regs->ch.destaddr = getreg32(base + LPC43_GPDMA_DESTADDR_CHOFFSET);
+ regs->ch.lli = getreg32(base + LPC43_GPDMA_LLI_CHOFFSET);
+ regs->ch.control = getreg32(base + LPC43_GPDMA_CONTROL_CHOFFSET);
+ regs->ch.config = getreg32(base + LPC43_GPDMA_CONFIG_CHOFFSET);
}
#endif /* CONFIG_DEBUG_DMA */
@@ -178,6 +701,55 @@ void lpc43_dmasample(DMA_HANDLE handle, struct lpc43_dmaregs_s *regs)
#ifdef CONFIG_DEBUG_DMA
void lpc43_dmadump(DMA_HANDLE handle, const struct lpc43_dmaregs_s *regs, const char *msg)
{
+ struct lpc43_dmach_s *dmach = (DMA_HANDLE)handle;
+ uint32_t base;
+
+ DEBUGASSERT(dmach);
+
+ /* Dump the sampled global DMA registers */
+
+ dmainfo("Global GPDMA Registers: %s\n", msg);
+ dmainfo(" INTST[%08x]: %08x\n",
+ LPC43_GPDMA_INTSTAT, regs->gbl.intst);
+ dmainfo(" INTTCSTAT[%08x]: %08x\n",
+ LPC43_GPDMA_INTTCSTAT, regs->gbl.inttcstat);
+ dmainfo(" INTERRSTAT[%08x]: %08x\n",
+ LPC43_GPDMA_INTERRSTAT, regs->gbl.interrstat);
+ dmainfo(" RAWINTTCSTAT[%08x]: %08x\n",
+ LPC43_GPDMA_RAWINTTCSTAT, regs->gbl.rawinttcstat);
+ dmainfo(" RAWINTERRSTAT[%08x]: %08x\n",
+ LPC43_GPDMA_RAWINTERRSTAT, regs->gbl.rawinterrstat);
+ dmainfo(" ENBLDCHNS[%08x]: %08x\n",
+ LPC43_GPDMA_ENBLDCHNS, regs->gbl.enbldchns);
+ dmainfo(" SOFTBREQ[%08x]: %08x\n",
+ LPC43_GPDMA_SOFTBREQ, regs->gbl.softbreq);
+ dmainfo(" SOFTSREQ[%08x]: %08x\n",
+ LPC43_GPDMA_SOFTSREQ, regs->gbl.softsreq);
+ dmainfo(" SOFTLBREQ[%08x]: %08x\n",
+ LPC43_GPDMA_SOFTLBREQ, regs->gbl.softlbreq);
+ dmainfo(" SOFTLSREQ[%08x]: %08x\n",
+ LPC43_GPDMA_SOFTLSREQ, regs->gbl.softlsreq);
+ dmainfo(" CONFIG[%08x]: %08x\n",
+ LPC43_GPDMA_CONFIG, regs->gbl.config);
+ dmainfo(" SYNC[%08x]: %08x\n",
+ LPC43_GPDMA_SYNC, regs->gbl.sync);
+
+ /* Dump the DMA channel registers */
+
+ base = LPC43_GPDMA_CHANNEL((uint32_t)dmach->chn);
+
+ dmainfo("Channel GPDMA Registers: %d\n", dmach->chn);
+
+ dmainfo(" SRCADDR[%08x]: %08x\n",
+ base + LPC43_GPDMA_SRCADDR_CHOFFSET, regs->ch.srcaddr);
+ dmainfo(" DESTADDR[%08x]: %08x\n",
+ base + LPC43_GPDMA_DESTADDR_CHOFFSET, regs->ch.destaddr);
+ dmainfo(" LLI[%08x]: %08x\n",
+ base + LPC43_GPDMA_LLI_CHOFFSET, regs->ch.lli);
+ dmainfo(" CONTROL[%08x]: %08x\n",
+ base + LPC43_GPDMA_CONTROL_CHOFFSET, regs->ch.control);
+ dmainfo(" CONFIG[%08x]: %08x\n",
+ base + LPC43_GPDMA_CONFIG_CHOFFSET, regs->ch.config);
}
#endif /* CONFIG_DEBUG_DMA */
diff --git a/arch/arm/src/sam34/Kconfig b/arch/arm/src/sam34/Kconfig
index df137147922..01194134c2b 100644
--- a/arch/arm/src/sam34/Kconfig
+++ b/arch/arm/src/sam34/Kconfig
@@ -240,6 +240,7 @@ config ARCH_CHIP_SAM3A
config ARCH_CHIP_SAM4CM
bool
default n
+ select ARCH_HAVE_MULTICPU
select ARCH_HAVE_TICKLESS
config ARCH_CHIP_SAM4L
diff --git a/arch/arm/src/sam34/Make.defs b/arch/arm/src/sam34/Make.defs
index dab10fb45e1..9b4e75079ad 100644
--- a/arch/arm/src/sam34/Make.defs
+++ b/arch/arm/src/sam34/Make.defs
@@ -50,13 +50,17 @@ CMN_ASRCS = up_saveusercontext.S up_fullcontextrestore.S up_switchcontext.S
CMN_ASRCS += up_testset.S vfork.S
CMN_CSRCS = up_assert.c up_blocktask.c up_copyfullstate.c up_createstack.c
-CMN_CSRCS += up_mdelay.c up_udelay.c up_exit.c up_idle.c up_initialize.c
+CMN_CSRCS += up_mdelay.c up_udelay.c up_exit.c up_initialize.c
CMN_CSRCS += up_initialstate.c up_interruptcontext.c up_memfault.c up_modifyreg8.c
CMN_CSRCS += up_modifyreg16.c up_modifyreg32.c up_releasepending.c
CMN_CSRCS += up_releasestack.c up_reprioritizertr.c up_schedulesigaction.c
CMN_CSRCS += up_sigdeliver.c up_stackframe.c up_unblocktask.c up_usestack.c
CMN_CSRCS += up_doirq.c up_hardfault.c up_svcall.c up_vfork.c
+ifneq ($(CONFIG_SMP),y)
+CMN_CSRCS += up_idle.c
+endif
+
# Configuration-dependent common files
ifeq ($(CONFIG_ARMV7M_CMNVECTOR),y)
@@ -198,14 +202,22 @@ endif
ifeq ($(CONFIG_ARCH_CHIP_SAM4CM),y)
ifeq ($(CONFIG_SAM34_TC),y)
CHIP_CSRCS += sam4cm_tc.c
+
ifeq ($(CONFIG_SAM34_ONESHOT),y)
CHIP_CSRCS += sam4cm_oneshot.c sam4cm_oneshot_lowerhalf.c
-endif
+endif # CONFIG_SAM34_ONESHOT
+
ifeq ($(CONFIG_SAM34_FREERUN),y)
CHIP_CSRCS += sam4cm_freerun.c
-endif
+endif # CONFIG_SAM34_FREERUN
+
ifeq ($(CONFIG_SCHED_TICKLESS),y)
CHIP_CSRCS += sam4cm_tickless.c
-endif
-endif
-endif
+endif # CONFIG_SCHED_TICKLESS
+endif # CONFIG_SAM34_TC
+
+ifeq ($(CONFIG_SMP),y)
+CHIP_CSRCS += sam4cm_cpuindex.c sam4cm_cpuidlestack.c
+CHIP_CSRCS += sam4cm_cpupause.c sam4cm_cpustart.c sam4cm_idle.c
+endif # CONFIG_SMP
+endif # CONFIG_ARCH_CHIP_SAM4CM
diff --git a/arch/arm/src/sam34/chip/sam4cm_memorymap.h b/arch/arm/src/sam34/chip/sam4cm_memorymap.h
index c0b2de041b8..d719e268c01 100644
--- a/arch/arm/src/sam34/chip/sam4cm_memorymap.h
+++ b/arch/arm/src/sam34/chip/sam4cm_memorymap.h
@@ -65,6 +65,7 @@
/* Internal SRAM memory region */
#define SAM_INTSRAM0_BASE 0x20000000 /* For SAM3U compatibility */
+#define SAM_INTSRAM1_BASE 0x20080000 /* 0x20080000-0x200fffff: Internal SRAM 1 */
#define SAM_BBSRAM_BASE 0x22000000 /* 0x22000000-0x23ffffff: 32MB bit-band region */
/* 0x24000000-0x3fffffff: Undefined */
/* Peripherals address region */
diff --git a/arch/arm/src/sam34/chip/sam_pmc.h b/arch/arm/src/sam34/chip/sam_pmc.h
index 6514d1f42e4..d7a75f6b038 100644
--- a/arch/arm/src/sam34/chip/sam_pmc.h
+++ b/arch/arm/src/sam34/chip/sam_pmc.h
@@ -402,10 +402,10 @@
# define PMC_MCKR_CPCSS_SHIFT (16)
# define PMC_MCKR_CPCSS_MASK (0x7 << PMC_MCKR_CPCSS_SHIFT)
# define PMC_MCKR_CPCSS_SLOW (0 << PMC_MCKR_CPCSS_SHIFT) /* Slow Clock */
-# define PMC_MCKR_CCPSS_MAIN (1 << PMC_MCKR_CPCSS_SHIFT) /* Main Clock */
-# define PMC_MCKR_CCPSS_PLLA (2 << PMC_MCKR_CPCSS_SHIFT) /* PLLA Clock */
-# define PMC_MCKR_CCPSS_PLLB (3 << PMC_MCKR_CPCSS_SHIFT) /* PLLB Clock */
-# define PMC_MCKR_CCPSS_MCK (4 << PMC_MCKR_CPCSS_SHIFT) /* Master Clock */
+# define PMC_MCKR_CPCSS_MAIN (1 << PMC_MCKR_CPCSS_SHIFT) /* Main Clock */
+# define PMC_MCKR_CPCSS_PLLA (2 << PMC_MCKR_CPCSS_SHIFT) /* PLLA Clock */
+# define PMC_MCKR_CPCSS_PLLB (3 << PMC_MCKR_CPCSS_SHIFT) /* PLLB Clock */
+# define PMC_MCKR_CPCSS_MCK (4 << PMC_MCKR_CPCSS_SHIFT) /* Master Clock */
# define PMC_MCKR_CPPRES_SHIFT (20)
# define PMC_MCKR_CPPRES_MASK (0xF << PMC_MCKR_CPPRES_SHIFT)
# define PMC_MCKR_CPPRES(D) (((D) - 1) << PMC_MCKR_CPPRES_SHIFT)
@@ -547,13 +547,14 @@
/* Peripheral Clock Status Register 1 */
#if defined(CONFIG_ARCH_CHIP_SAM3X) || defined(CONFIG_ARCH_CHIP_SAM3X) || \
- defined(CONFIG_ARCH_CHIP_SAM4S) || defined(CONFIG_ARCH_CHIP_SAM4E)
+ defined(CONFIG_ARCH_CHIP_SAM4S) || defined(CONFIG_ARCH_CHIP_SAM4E) || \
+ defined(CONFIG_ARCH_CHIP_SAM4CM)
# define PMC_PIDH(n) (1 << ((n) - 32))
# define PMC_PID32 (1 << 0) /* Bit 0: PID32 */
# define PMC_PID33 (1 << 1) /* Bit 1: PID33 */
# define PMC_PID34 (1 << 2) /* Bit 2: PID34 */
# if defined(CONFIG_ARCH_CHIP_SAM3X) || defined(CONFIG_ARCH_CHIP_SAM3X) || \
- defined(CONFIG_ARCH_CHIP_SAM4E)
+ defined(CONFIG_ARCH_CHIP_SAM4E) || defined(CONFIG_ARCH_CHIP_SAM4CM)
# define PMC_PID35 (1 << 3) /* Bit 3: PID35 */
# define PMC_PID36 (1 << 4) /* Bit 4: PID36 */
# define PMC_PID37 (1 << 5) /* Bit 5: PID37 */
diff --git a/arch/arm/src/sam34/sam4cm_cpuidlestack.c b/arch/arm/src/sam34/sam4cm_cpuidlestack.c
new file mode 100644
index 00000000000..411ebfaad77
--- /dev/null
+++ b/arch/arm/src/sam34/sam4cm_cpuidlestack.c
@@ -0,0 +1,136 @@
+/****************************************************************************
+ * arch/arm/src/sam34/sam4cm_cpuidlestack.c
+ *
+ * Copyright (C) 2016 Masayuki Ishikawa. All rights reserved.
+ * Author: Masayuki Ishikawa
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+
+#include
+#include
+
+#include "up_internal.h"
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_idle
+ *
+ * Description:
+ * up_idle() is the logic that will be executed when their is no other
+ * ready-to-run task. This is processor idle time and will continue until
+ * some interrupt occurs to cause a context switch from the idle task.
+ *
+ * Processing in this state may be processor-specific. e.g., this is where
+ * power management operations might be performed.
+ *
+ ****************************************************************************/
+
+void up_idle(void)
+{
+#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_TIMER_INTS)
+ /* If the system is idle and there are no timer interrupts, then process
+ * "fake" timer interrupts. Hopefully, something will wake up.
+ */
+
+ sched_process_timer();
+#else
+
+ /* Sleep until an interrupt occurs to save power */
+
+ asm("WFI");
+
+#endif
+}
+
+/****************************************************************************
+ * Name: up_cpu_idlestack
+ *
+ * Description:
+ * Allocate a stack for the CPU[n] IDLE task (n > 0) if appropriate and
+ * setup up stack-related information in the IDLE task's TCB. This
+ * function is always called before up_cpu_start(). This function is
+ * only called for the CPU's initial IDLE task; up_create_task is used for
+ * all normal tasks, pthreads, and kernel threads for all CPUs.
+ *
+ * The initial IDLE task is a special case because the CPUs can be started
+ * in different wans in different environments:
+ *
+ * 1. The CPU may already have been started and waiting in a low power
+ * state for up_cpu_start(). In this case, the IDLE thread's stack
+ * has already been allocated and is already in use. Here
+ * up_cpu_idlestack() only has to provide information about the
+ * already allocated stack.
+ *
+ * 2. The CPU may be disabled but started when up_cpu_start() is called.
+ * In this case, a new stack will need to be created for the IDLE
+ * thread and this function is then equivalent to:
+ *
+ * return up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL);
+ *
+ * The following TCB fields must be initialized by this function:
+ *
+ * - adj_stack_size: Stack size after adjustment for hardware, processor,
+ * etc. This value is retained only for debug purposes.
+ * - stack_alloc_ptr: Pointer to allocated stack
+ * - adj_stack_ptr: Adjusted stack_alloc_ptr for HW. The initial value of
+ * the stack pointer.
+ *
+ * Inputs:
+ * - cpu: CPU index that indicates which CPU the IDLE task is
+ * being created for.
+ * - tcb: The TCB of new CPU IDLE task
+ * - stack_size: The requested stack size for the IDLE task. At least
+ * this much must be allocated. This should be
+ * CONFIG_SMP_STACK_SIZE.
+ *
+ ****************************************************************************/
+
+int up_cpu_idlestack(int cpu, FAR struct tcb_s *tcb, size_t stack_size)
+{
+#if CONFIG_SMP_NCPUS > 1
+ (void)up_create_stack(tcb, stack_size, TCB_FLAG_TTYPE_KERNEL);
+#endif
+ return OK;
+}
+
+#endif /* CONFIG_SMP */
diff --git a/arch/rgmp/src/arm/arch_nuttx.c b/arch/arm/src/sam34/sam4cm_cpuindex.c
similarity index 57%
rename from arch/rgmp/src/arm/arch_nuttx.c
rename to arch/arm/src/sam34/sam4cm_cpuindex.c
index dd737946d9d..867d36e5c1b 100644
--- a/arch/rgmp/src/arm/arch_nuttx.c
+++ b/arch/arm/src/sam34/sam4cm_cpuindex.c
@@ -1,12 +1,8 @@
/****************************************************************************
- * arch/rgmp/src/arm/arch_nuttx.c
+ * arch/arm/src/sam34/sam4cm_cpuindex.c
*
- * Copyright (C) 2011 Yu Qiang. All rights reserved.
- * Author: Yu Qiang
- *
- * This file is a part of NuttX:
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2016 Masayuki Ishikawa. All rights reserved.
+ * Author: Masayuki Ishikawa
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -37,53 +33,45 @@
*
****************************************************************************/
-#include
-#include
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
-#include
-#include
+#include
+#include
+#include
-void nuttx_arch_init(void)
+#include "mpu.h"
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_cpu_index
+ *
+ * Description:
+ * Return an index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
+ * corresponds to the currently executing CPU.
+ *
+ * Input Parameters:
+ * None
+ *
+ * Returned Value:
+ * An integer index in the range of 0 through (CONFIG_SMP_NCPUS-1) that
+ * corresponds to the currently executing CPU.
+ *
+ ****************************************************************************/
+
+int up_cpu_index(void)
{
+ /* MPU is not supported on CM4P1 */
+
+ return (getreg32(MPU_TYPE) == 0) ? 1 : 0;
}
-void nuttx_arch_exit(void)
-{
-}
+#endif /* CONFIG_SMP */
-void up_initial_state(struct tcb_s *tcb)
-{
- struct Trapframe *tf;
-
- if (tcb->pid != 0)
- {
- tf = (struct Trapframe *)tcb->adj_stack_ptr-1;
- memset(tf, 0, sizeof(struct Trapframe));
- tf->tf_cpsr = SVC_MOD;
- tf->tf_pc = (uint32_t)tcb->start;
- tcb->xcp.tf = tf;
- }
-}
-
-void push_xcptcontext(struct xcptcontext *xcp)
-{
- xcp->save_eip = xcp->tf->tf_pc;
- xcp->save_eflags = xcp->tf->tf_cpsr;
-
- // set interrupts disabled
-
- xcp->tf->tf_pc = (uint32_t)up_sigentry;
- xcp->tf->tf_cpsr |= CPSR_IF;
-}
-
-void pop_xcptcontext(struct xcptcontext *xcp)
-{
- xcp->tf->tf_pc = xcp->save_eip;
- xcp->tf->tf_cpsr = xcp->save_eflags;
-}
-
-void raise(void)
-{
-
-}
diff --git a/arch/arm/src/sam34/sam4cm_cpupause.c b/arch/arm/src/sam34/sam4cm_cpupause.c
new file mode 100644
index 00000000000..9b9d126f252
--- /dev/null
+++ b/arch/arm/src/sam34/sam4cm_cpupause.c
@@ -0,0 +1,328 @@
+/****************************************************************************
+ * arch/arm/src/sam34/sam4cm_cpupause.c
+ *
+ * Copyright (C) 2016 Masayuki Ishikawa. All rights reserved.
+ * Author: Masayuki Ishikawa
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "up_arch.h"
+#include "sched/sched.h"
+#include "up_internal.h"
+#include "chip/sam4cm_ipc.h"
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+# define DPRINTF(fmt, args...) _err(fmt, ##args)
+#else
+# define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* These spinlocks are used in the SMP configuration in order to implement
+ * up_cpu_pause(). The protocol for CPUn to pause CPUm is as follows
+ *
+ * 1. The up_cpu_pause() implementation on CPUn locks both g_cpu_wait[m]
+ * and g_cpu_paused[m]. CPUn then waits spinning on g_cpu_paused[m].
+ * 2. CPUm receives the interrupt it (1) unlocks g_cpu_paused[m] and
+ * (2) locks g_cpu_wait[m]. The first unblocks CPUn and the second
+ * blocks CPUm in the interrupt handler.
+ *
+ * When CPUm resumes, CPUn unlocks g_cpu_wait[m] and the interrupt handler
+ * on CPUm continues. CPUm must, of course, also then unlock g_cpu_wait[m]
+ * so that it will be ready for the next pause operation.
+ */
+
+static volatile spinlock_t g_cpu_wait[CONFIG_SMP_NCPUS];
+static volatile spinlock_t g_cpu_paused[CONFIG_SMP_NCPUS];
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_cpu_pausereq
+ *
+ * Description:
+ * Return true if a pause request is pending for this CPU.
+ *
+ * Input Parameters:
+ * cpu - The index of the CPU to be queried
+ *
+ * Returned Value:
+ * true = a pause request is pending.
+ * false = no pasue request is pending.
+ *
+ ****************************************************************************/
+
+bool up_cpu_pausereq(int cpu)
+{
+ return spin_islocked(&g_cpu_paused[cpu]);
+}
+
+/****************************************************************************
+ * Name: up_cpu_paused
+ *
+ * Description:
+ * Handle a pause request from another CPU. Normally, this logic is
+ * executed from interrupt handling logic within the architecture-specific
+ * However, it is sometimes necessary necessary to perform the pending
+ * pause operation in other contexts where the interrupt cannot be taken
+ * in order to avoid deadlocks.
+ *
+ * This function performs the following operations:
+ *
+ * 1. It saves the current task state at the head of the current assigned
+ * task list.
+ * 2. It waits on a spinlock, then
+ * 3. Returns from interrupt, restoring the state of the new task at the
+ * head of the ready to run list.
+ *
+ * Input Parameters:
+ * cpu - The index of the CPU to be paused
+ *
+ * Returned Value:
+ * On success, OK is returned. Otherwise, a negated errno value indicating
+ * the nature of the failure is returned.
+ *
+ ****************************************************************************/
+
+int up_cpu_paused(int cpu)
+{
+ FAR struct tcb_s *tcb = this_task();
+
+ /* Update scheduler parameters */
+
+ sched_suspend_scheduler(tcb);
+
+ /* Save the current context at CURRENT_REGS into the TCB at the head
+ * of the assigned task list for this CPU.
+ */
+
+ up_savestate(tcb->xcp.regs);
+
+ /* Wait for the spinlock to be released */
+
+ spin_unlock(&g_cpu_paused[cpu]);
+ spin_lock(&g_cpu_wait[cpu]);
+
+ /* Restore the exception context of the tcb at the (new) head of the
+ * assigned task list.
+ */
+
+ tcb = this_task();
+
+ /* Reset scheduler parameters */
+
+ sched_resume_scheduler(tcb);
+
+ /* Then switch contexts. Any necessary address environment changes
+ * will be made when the interrupt returns.
+ */
+
+ up_restorestate(tcb->xcp.regs);
+ spin_unlock(&g_cpu_wait[cpu]);
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: arm_pause_handler
+ *
+ * Description:
+ * Inter-CPU interrupt handler
+ *
+ * Input Parameters:
+ * Standard interrupt handler inputs
+ *
+ * Returned Value:
+ * Should always return OK
+ *
+ ****************************************************************************/
+
+int arm_pause_handler(int irq, void *c)
+{
+ int cpu = up_cpu_index();
+
+ /* Clear : Pause IRQ */
+ /* IPC Interrupt Clear Command Register (write-only) */
+
+ if (1 == cpu)
+ {
+ DPRINTF("CPU0 -> CPU1\n");
+ putreg32(0x1, SAM_IPC1_ICCR);
+ }
+ else
+ {
+ DPRINTF("CPU1 -> CPU0\n");
+ putreg32(0x1, SAM_IPC0_ICCR);
+ }
+
+ /* Check for false alarms. Such false could occur as a consequence of
+ * some deadlock breaking logic that might have already serviced the SG2
+ * interrupt by calling up_cpu_paused.
+ */
+
+ if (spin_islocked(&g_cpu_paused[cpu]))
+ {
+ return up_cpu_paused(cpu);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Name: up_cpu_pause
+ *
+ * Description:
+ * Save the state of the current task at the head of the
+ * g_assignedtasks[cpu] task list and then pause task execution on the
+ * CPU.
+ *
+ * This function is called by the OS when the logic executing on one CPU
+ * needs to modify the state of the g_assignedtasks[cpu] list for another
+ * CPU.
+ *
+ * Input Parameters:
+ * cpu - The index of the CPU to be stopped/
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_cpu_pause(int cpu)
+{
+ DPRINTF("cpu=%d\n",cpu);
+
+ DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
+
+ /* Take the both spinlocks. The g_cpu_wait spinlock will prevent the SGI2
+ * handler from returning until up_cpu_resume() is called; g_cpu_paused
+ * is a handshake that will prefent this function from returning until
+ * the CPU is actually paused.
+ */
+
+ spin_lock(&g_cpu_wait[cpu]);
+ spin_lock(&g_cpu_paused[cpu]);
+
+ DEBUGASSERT(spin_islocked(&g_cpu_wait[cpu]) &&
+ spin_islocked(&g_cpu_paused[cpu]));
+
+ /* Execute Pause IRQ to CPU(cpu) */
+ /* Set IPC Interrupt (IRQ0) (write-only) */
+
+ if (cpu == 1)
+ {
+ putreg32(0x1, SAM_IPC1_ISCR);
+ }
+ else
+ {
+ putreg32(0x1, SAM_IPC0_ISCR);
+ }
+
+ /* Wait for the other CPU to unlock g_cpu_paused meaning that
+ * it is fully paused and ready for up_cpu_resume();
+ */
+
+ spin_lock(&g_cpu_paused[cpu]);
+
+ spin_unlock(&g_cpu_paused[cpu]);
+
+ /* On successful return g_cpu_wait will be locked, the other CPU will be
+ * spinninf on g_cpu_wait and will not continue until g_cpu_resume() is
+ * called. g_cpu_paused will be unlocked in any case.
+ */
+
+ return 0;
+}
+
+/****************************************************************************
+ * Name: up_cpu_resume
+ *
+ * Description:
+ * Restart the cpu after it was paused via up_cpu_pause(), restoring the
+ * state of the task at the head of the g_assignedtasks[cpu] list, and
+ * resume normal tasking.
+ *
+ * This function is called after up_cpu_pause in order resume operation of
+ * the CPU after modifying its g_assignedtasks[cpu] list.
+ *
+ * Input Parameters:
+ * cpu - The index of the CPU being re-started.
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_cpu_resume(int cpu)
+{
+ DPRINTF("cpu=%d\n",cpu);
+
+ DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS && cpu != this_cpu());
+
+ /* Release the spinlock. Releasing the spinlock will cause the SGI2
+ * handler on 'cpu' to continue and return from interrupt to the newly
+ * established thread.
+ */
+
+ DEBUGASSERT(spin_islocked(&g_cpu_wait[cpu]) &&
+ !spin_islocked(&g_cpu_paused[cpu]));
+
+ spin_unlock(&g_cpu_wait[cpu]);
+
+ return 0;
+}
+
+#endif /* CONFIG_SMP */
diff --git a/arch/arm/src/sam34/sam4cm_cpustart.c b/arch/arm/src/sam34/sam4cm_cpustart.c
new file mode 100644
index 00000000000..7a5c62f0fc6
--- /dev/null
+++ b/arch/arm/src/sam34/sam4cm_cpustart.c
@@ -0,0 +1,243 @@
+/****************************************************************************
+ * arch/arm/src/sam34/sam4cm_cpustart.c
+ *
+ * Copyright (C) 2016 Masayuki Ishikawa. All rights reserved.
+ * Author: Masayuki Ishikawa
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+#include "nvic.h"
+#include "up_arch.h"
+#include "sched/sched.h"
+#include "init/init.h"
+#include "up_internal.h"
+#include "chip/sam_pmc.h"
+#include "chip/sam_rstc.h"
+#include "chip/sam4cm_ipc.h"
+#include "sam4cm_periphclks.h"
+
+#ifdef CONFIG_SMP
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+#if 0
+# define DPRINTF(fmt, args...) _err(fmt, ##args)
+#else
+# define DPRINTF(fmt, args...) do {} while (0)
+#endif
+
+#define CPU1_VECTOR_RESETV (SAM_INTSRAM1_BASE)
+#define CPU1_VECTOR_ISTACK (SAM_INTSRAM1_BASE + 4)
+
+/****************************************************************************
+ * Public Data
+ ****************************************************************************/
+
+volatile static spinlock_t g_cpu1_boot;
+extern int arm_pause_handler(int irq, void *c);
+
+/****************************************************************************
+ * Name: cpu1_boot
+ *
+ * Description:
+ * This is the boot vector for CM4P1
+ *
+ * Input Parameters:
+ *
+ * Returned Value:
+ *
+ ****************************************************************************/
+
+static void cpu1_boot(void)
+{
+ int cpu;
+
+ /* Disable CMCC1 */
+
+ putreg32(0, 0x48018008);
+ while ((getreg32(0x4801800c) & 0x01) != 0);
+
+ cpu = up_cpu_index();
+ DPRINTF("cpu = %d\n", cpu);
+
+ if (cpu == 1)
+ {
+ /* Use CPU0 vectors */
+
+ putreg32((uint32_t)&_stext, NVIC_VECTAB);
+ sam_ipc1_enableclk();
+
+ /* Clear : write-only */
+
+ putreg32(0x1, SAM_IPC1_ICCR);
+
+ /* Enable : write-only */
+
+ putreg32(0x1, SAM_IPC1_IECR);
+ irq_attach(SAM_IRQ_IPC1, arm_pause_handler);
+ up_enable_irq(SAM_IRQ_IPC1);
+ }
+
+ spin_unlock(&g_cpu1_boot);
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+ /* Notify that this CPU has started */
+
+ sched_note_cpu_started(this_task());
+#endif
+
+ /* Then transfer control to the IDLE task */
+
+ (void)os_idle_task(0, NULL);
+}
+
+/****************************************************************************
+ * Name: up_cpu_start
+ *
+ * Description:
+ * In an SMP configution, only one CPU is initially active (CPU 0). System
+ * initialization occurs on that single thread. At the completion of the
+ * initialization of the OS, just before beginning normal multitasking,
+ * the additional CPUs would be started by calling this function.
+ *
+ * Each CPU is provided the entry point to is IDLE task when started. A
+ * TCB for each CPU's IDLE task has been initialized and placed in the
+ * CPU's g_assignedtasks[cpu] list. Not stack has been alloced or
+ * initialized.
+ *
+ * The OS initialization logic calls this function repeatedly until each
+ * CPU has been started, 1 through (CONFIG_SMP_NCPUS-1).
+ *
+ * Input Parameters:
+ * cpu - The index of the CPU being started. This will be a numeric
+ * value in the range of from one to (CONFIG_SMP_NCPUS-1). (CPU
+ * 0 is already active)
+ *
+ * Returned Value:
+ * Zero on success; a negated errno value on failure.
+ *
+ ****************************************************************************/
+
+int up_cpu_start(int cpu)
+{
+ struct tcb_s *tcb = current_task(cpu);
+
+ DPRINTF("cpu=%d\n",cpu);
+
+ if (cpu != 1)
+ {
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_SCHED_INSTRUMENTATION
+ /* Notify of the start event */
+
+ sched_note_cpu_start(this_task(), cpu);
+#endif
+
+ /* Reset coprocessor */
+
+ putreg32(0x5a000000, SAM_RSTC_CPMR);
+
+ /* Enable Coprocessor Bus Master Clock (write-only) */
+
+ putreg32(PMC_CPKEY | PMC_CPBMCK, SAM_PMC_SCER);
+
+ /* Enable Coprocessor Clock (write-only) */
+
+ putreg32(PMC_CPKEY | PMC_CPCK, SAM_PMC_SCER);
+
+ /* Set Coprocessor Clock Prescalar */
+
+ modifyreg32(SAM_PMC_MCKR, PMC_MCKR_CPPRES_MASK, 0);
+
+ /* Set Coprocessor Clock Source */
+
+ modifyreg32(SAM_PMC_MCKR, PMC_MCKR_CPCSS_MASK, PMC_MCKR_CPCSS_PLLB);
+
+ /* Unreset coprocessor pheripheral */
+
+ putreg32(0x5a000010, SAM_RSTC_CPMR);
+
+ /* Enable clock for SRAM1 where CPU1 starts (write-only) */
+
+ putreg32(PMC_PID42, SAM_PMC_PCER1);
+
+ /* Clear SRAM1 */
+
+ memset((void *)SAM_INTSRAM1_BASE, 0, 16 * 1024);
+
+ /* Copy initial vectors for CPU1 */
+
+ putreg32((uint32_t)tcb->adj_stack_ptr, CPU1_VECTOR_RESETV);
+ putreg32((uint32_t)cpu1_boot, CPU1_VECTOR_ISTACK);
+
+ spin_lock(&g_cpu1_boot);
+
+ /* Unreset coprocessor */
+
+ putreg32(0x5a000011, SAM_RSTC_CPMR);
+
+ /* IRQ setup CPU1->CPU0 */
+
+ sam_ipc0_enableclk();
+ putreg32(0x1, SAM_IPC0_ICCR); /* clear : write-only */
+ putreg32(0x1, SAM_IPC0_IECR); /* enable : write-only */
+ irq_attach(SAM_IRQ_IPC0, arm_pause_handler);
+ up_enable_irq(SAM_IRQ_IPC0);
+
+ spin_lock(&g_cpu1_boot);
+
+ /* CPU1 boot done */
+
+ spin_unlock(&g_cpu1_boot);
+
+ return 0;
+}
+
+#endif /* CONFIG_SMP */
diff --git a/arch/arm/src/sam34/sam4cm_idle.c b/arch/arm/src/sam34/sam4cm_idle.c
new file mode 100644
index 00000000000..9c3810136cf
--- /dev/null
+++ b/arch/arm/src/sam34/sam4cm_idle.c
@@ -0,0 +1,77 @@
+/****************************************************************************
+ * arch/arm/src/sam34/sam4cm_idle.c
+ *
+ * Copyright (C) 2016 Masayuki Ishikawa. All rights reserved.
+ * Author: Masayuki Ishikawa
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+
+#include
+#include "up_internal.h"
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Name: up_idle
+ *
+ * Description:
+ * up_idle() is the logic that will be executed when their is no other
+ * ready-to-run task. This is processor idle time and will continue until
+ * some interrupt occurs to cause a context switch from the idle task.
+ *
+ * Processing in this state may be processor-specific. e.g., this is where
+ * power management operations might be performed.
+ *
+ ****************************************************************************/
+
+void up_idle(void)
+{
+#if defined(CONFIG_SUPPRESS_INTERRUPTS) || defined(CONFIG_SUPPRESS_TIMER_INTS)
+ /* If the system is idle and there are no timer interrupts, then process
+ * "fake" timer interrupts. Hopefully, something will wake up.
+ */
+
+ sched_process_timer();
+#else
+
+ /* Sleep until an interrupt occurs to save power */
+
+ asm("WFI");
+
+#endif
+}
diff --git a/arch/arm/src/sam34/sam_emac.c b/arch/arm/src/sam34/sam_emac.c
index 15e7b1b4ba4..7ce3b0c3165 100644
--- a/arch/arm/src/sam34/sam_emac.c
+++ b/arch/arm/src/sam34/sam_emac.c
@@ -64,11 +64,7 @@
#include
#include
#include
-
-#ifdef CONFIG_NET_NOINTS
-# include
-#endif
-
+#include
#include
#include
#include
@@ -101,13 +97,12 @@
* is required.
*/
-#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
+#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
-#endif
+#else
-/* Select work queue */
+ /* Select work queue */
-#if defined(CONFIG_SCHED_WORKQUEUE)
# if defined(CONFIG_SAM34_EMAC_HPWORK)
# define ETHWORK HPWORK
# elif defined(CONFIG_SAM34_EMAC_LPWORK)
@@ -275,9 +270,7 @@ struct sam_emac_s
uint8_t ifup : 1; /* true:ifup false:ifdown */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
-#ifdef CONFIG_NET_NOINTS
struct work_s work; /* For deferring work to the work queue */
-#endif
/* This holds the information visible to the NuttX network */
@@ -313,7 +306,6 @@ struct sam_emac_s
static struct sam_emac_s g_emac;
-#ifdef CONFIG_NET_MULTIBUFFER
/* A single packet buffer is used
*
* REVISIT: It might be possible to use this option to send and receive
@@ -324,7 +316,6 @@ static struct sam_emac_s g_emac;
*/
static uint8_t g_pktbuf[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
-#endif
#ifdef CONFIG_SAM34_EMAC_PREALLOCATE
/* Preallocated data */
@@ -388,24 +379,16 @@ static void sam_dopoll(struct sam_emac_s *priv);
static int sam_recvframe(struct sam_emac_s *priv);
static void sam_receive(struct sam_emac_s *priv);
static void sam_txdone(struct sam_emac_s *priv);
-static inline void sam_interrupt_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void sam_interrupt_work(FAR void *arg);
-#endif
static int sam_emac_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static inline void sam_txtimeout_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void sam_txtimeout_work(FAR void *arg);
-#endif
static void sam_txtimeout_expiry(int argc, uint32_t arg, ...);
-static inline void sam_poll_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void sam_poll_work(FAR void *arg);
-#endif
static void sam_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
@@ -413,10 +396,7 @@ static void sam_poll_expiry(int argc, uint32_t arg, ...);
static int sam_ifup(struct net_driver_s *dev);
static int sam_ifdown(struct net_driver_s *dev);
-static inline void sam_txavail_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void sam_txavail_work(FAR void *arg);
-#endif
static int sam_txavail(struct net_driver_s *dev);
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
@@ -467,6 +447,7 @@ static int sam_emac_configure(struct sam_emac_s *priv);
/****************************************************************************
* Private Functions
****************************************************************************/
+
/****************************************************************************
* Name: sam_checkreg
*
@@ -1423,25 +1404,25 @@ static void sam_txdone(struct sam_emac_s *priv)
}
/****************************************************************************
- * Function: sam_interrupt_process
+ * Function: sam_interrupt_work
*
* Description:
- * Interrupt processing. This may be performed either within the interrupt
- * handler or on the worker thread, depending upon the configuration
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void sam_interrupt_process(FAR struct sam_emac_s *priv)
+static void sam_interrupt_work(FAR void *arg)
{
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
uint32_t isr;
uint32_t rsr;
uint32_t tsr;
@@ -1450,6 +1431,9 @@ static inline void sam_interrupt_process(FAR struct sam_emac_s *priv)
uint32_t pending;
uint32_t clrbits;
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
isr = sam_getreg(priv, SAM_EMAC_ISR);
rsr = sam_getreg(priv, SAM_EMAC_RSR);
tsr = sam_getreg(priv, SAM_EMAC_TSR);
@@ -1605,42 +1589,13 @@ static inline void sam_interrupt_process(FAR struct sam_emac_s *priv)
nwarn("WARNING: Pause TO!\n");
}
#endif
-}
-/****************************************************************************
- * Function: sam_interrupt_work
- *
- * Description:
- * Perform interrupt related work from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() was called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void sam_interrupt_work(FAR void *arg)
-{
- FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
-
- /* Process pending Ethernet interrupts */
-
- state = net_lock();
- sam_interrupt_process(priv);
- net_unlock(state);
+ net_unlock();
/* Re-enable Ethernet interrupts */
up_enable_irq(SAM_IRQ_EMAC);
}
-#endif
/****************************************************************************
* Function: sam_emac_interrupt
@@ -1663,7 +1618,6 @@ static int sam_emac_interrupt(int irq, void *context)
{
struct sam_emac_s *priv = &g_emac;
-#ifdef CONFIG_NET_NOINTS
uint32_t tsr;
/* Disable further Ethernet interrupts. Because Ethernet interrupts are
@@ -1707,52 +1661,9 @@ static int sam_emac_interrupt(int irq, void *context)
/* Schedule to perform the interrupt processing on the worker thread. */
work_queue(ETHWORK, &priv->work, sam_interrupt_work, priv, 0);
-
-#else
- /* Process the interrupt now */
-
- sam_interrupt_process(priv);
-#endif
-
return OK;
}
-/****************************************************************************
- * Function: sam_txtimeout_process
- *
- * Description:
- * Process a TX timeout. Called from the either the watchdog timer
- * expiration logic or from the worker thread, depending upon the
- * configuration. The timeout means that the last TX never completed.
- * Reset the hardware and start again.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Global interrupts are disabled by the watchdog logic.
- *
- ****************************************************************************/
-
-static inline void sam_txtimeout_process(FAR struct sam_emac_s *priv)
-{
- nerr("ERROR: Timeout!\n");
-
- /* Then reset the hardware. Just take the interface down, then back
- * up again.
- */
-
- sam_ifdown(&priv->dev);
- sam_ifup(&priv->dev);
-
- /* Then poll the network for new XMIT data */
-
- sam_dopoll(priv);
-}
-
/****************************************************************************
* Function: sam_txtimeout_work
*
@@ -1770,19 +1681,25 @@ static inline void sam_txtimeout_process(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void sam_txtimeout_work(FAR void *arg)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
- /* Process pending Ethernet interrupts */
+ nerr("ERROR: Timeout!\n");
- state = net_lock();
- sam_txtimeout_process(priv);
- net_unlock(state);
+ /* Then reset the hardware. Just take the interface down, then back
+ * up again.
+ */
+
+ net_lock();
+ sam_ifdown(&priv->dev);
+ sam_ifup(&priv->dev);
+
+ /* Then poll the network for new XMIT data */
+
+ sam_dopoll(priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: sam_txtimeout_expiry
@@ -1807,7 +1724,6 @@ static void sam_txtimeout_expiry(int argc, uint32_t arg, ...)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Disable further Ethernet interrupts. This will prevent some race
* conditions with interrupt work. There is still a potential race
* condition with interrupt work that is already queued and in progress.
@@ -1824,48 +1740,6 @@ static void sam_txtimeout_expiry(int argc, uint32_t arg, ...)
/* Schedule to perform the TX timeout processing on the worker thread. */
work_queue(ETHWORK, &priv->work, sam_txtimeout_work, priv, 0);
-#else
- /* Process the timeout now */
-
- sam_txtimeout_process(priv);
-#endif
-}
-
-/****************************************************************************
- * Function: sam_poll_process
- *
- * Description:
- * Perform the periodic poll. This may be called either from watchdog
- * timer logic or from the worker thread, depending upon the configuration.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
-
-static inline void sam_poll_process(FAR struct sam_emac_s *priv)
-{
- struct net_driver_s *dev = &priv->dev;
-
- /* Check if the there are any free TX descriptors. We cannot perform the
- * TX poll if we do not have buffering for another packet.
- */
-
- if (sam_txfree(priv) > 0)
- {
- /* Update TCP timing states and poll the network for new XMIT data. */
-
- (void)devif_timer(dev, sam_txpoll);
- }
-
- /* Setup the watchdog poll timer again */
-
- (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
}
/****************************************************************************
@@ -1885,19 +1759,28 @@ static inline void sam_poll_process(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void sam_poll_work(FAR void *arg)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
+ struct net_driver_s *dev = &priv->dev;
- /* Perform the poll */
+ /* Check if the there are any free TX descriptors. We cannot perform the
+ * TX poll if we do not have buffering for another packet.
+ */
- state = net_lock();
- sam_poll_process(priv);
- net_unlock(state);
+ net_lock();
+ if (sam_txfree(priv) > 0)
+ {
+ /* Update TCP timing states and poll the network for new XMIT data. */
+
+ (void)devif_timer(dev, sam_txpoll);
+ }
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: sam_poll_expiry
@@ -1921,7 +1804,6 @@ static void sam_poll_expiry(int argc, uint32_t arg, ...)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions.
*/
@@ -1940,12 +1822,6 @@ static void sam_poll_expiry(int argc, uint32_t arg, ...)
(void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, arg);
}
-
-#else
- /* Process the interrupt now */
-
- sam_poll_process(priv);
-#endif
}
/****************************************************************************
@@ -2072,37 +1948,6 @@ static int sam_ifdown(struct net_driver_s *dev)
return OK;
}
-/****************************************************************************
- * Function: sam_txavail_process
- *
- * Description:
- * Perform an out-of-cycle poll.
- *
- * Parameters:
- * dev - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called in normal user mode
- *
- ****************************************************************************/
-
-static inline void sam_txavail_process(FAR struct sam_emac_s *priv)
-{
- ninfo("ifup: %d\n", priv->ifup);
-
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
- {
- /* Poll the network for new XMIT data */
-
- sam_dopoll(priv);
- }
-}
-
/****************************************************************************
* Function: sam_txavail_work
*
@@ -2120,19 +1965,24 @@ static inline void sam_txavail_process(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void sam_txavail_work(FAR void *arg)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
- /* Perform the poll */
+ ninfo("ifup: %d\n", priv->ifup);
- state = net_lock();
- sam_txavail_process(priv);
- net_unlock(state);
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->ifup)
+ {
+ /* Poll the network for new XMIT data */
+
+ sam_dopoll(priv);
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: sam_txavail
@@ -2157,7 +2007,6 @@ static int sam_txavail(struct net_driver_s *dev)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)dev->d_private;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions and we will have to ignore the Tx
* availability action.
@@ -2170,21 +2019,6 @@ static int sam_txavail(struct net_driver_s *dev)
work_queue(ETHWORK, &priv->work, sam_txavail_work, priv, 0);
}
-#else
- irqstate_t flags;
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
- */
-
- flags = enter_critical_section();
-
- /* Perform the out-of-cycle poll now */
-
- sam_txavail_process(priv);
- leave_critical_section(flags);
-#endif
-
return OK;
}
@@ -3820,9 +3654,7 @@ void up_netinitialize(void)
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct sam_emac_s));
-#ifdef CONFIG_NET_MULTIBUFFER
priv->dev.d_buf = g_pktbuf; /* Single packet buffer */
-#endif
priv->dev.d_ifup = sam_ifup; /* I/F up (new IP address) callback */
priv->dev.d_ifdown = sam_ifdown; /* I/F down callback */
priv->dev.d_txavail = sam_txavail; /* New TX data callback */
diff --git a/arch/arm/src/sam34/sam_irq.c b/arch/arm/src/sam34/sam_irq.c
index 68f17774347..0b3286d0cac 100644
--- a/arch/arm/src/sam34/sam_irq.c
+++ b/arch/arm/src/sam34/sam_irq.c
@@ -84,7 +84,11 @@
* CURRENT_REGS for portability.
*/
+#ifdef CONFIG_SMP
+volatile uint32_t *g_current_regs[CONFIG_SMP_NCPUS];
+#else
volatile uint32_t *g_current_regs[1];
+#endif
/* This is the address of the exception vector table (determined by the
* linker script).
diff --git a/arch/arm/src/sam34/sam_start.c b/arch/arm/src/sam34/sam_start.c
index abae1da7615..71537f1c38b 100644
--- a/arch/arm/src/sam34/sam_start.c
+++ b/arch/arm/src/sam34/sam_start.c
@@ -241,6 +241,13 @@ void __start(void)
const uint32_t *src;
uint32_t *dest;
+#ifdef CONFIG_SMP
+ /* Disable CMCC0 */
+
+ putreg32(0, 0x4007c008);
+ while ((getreg32(0x4007c00c) & 0x01) != 0);
+#endif
+
#ifdef CONFIG_ARMV7M_STACKCHECK
/* Set the stack limit before we attempt to call any functions */
diff --git a/arch/arm/src/sama5/Kconfig b/arch/arm/src/sama5/Kconfig
index 1400aea5c96..d4ccc256be6 100644
--- a/arch/arm/src/sama5/Kconfig
+++ b/arch/arm/src/sama5/Kconfig
@@ -1437,6 +1437,26 @@ config SAMA5_GMAC_NBC
---help---
Select to disable receipt of broadcast packets.
+choice
+ prompt "Work queue"
+ default SAMA5_GMAC_LPWORK if SCHED_LPWORK
+ default SAMA5_GMAC_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
+ depends on SCHED_WORKQUEUE
+ ---help---
+ Work queue support is required to use the Ethernet driver. If the
+ low priority work queue is available, then it should be used by the
+ driver.
+
+config SAMA5_GMAC_HPWORK
+ bool "High priority"
+ depends on SCHED_HPWORK
+
+config SAMA5_GMAC_LPWORK
+ bool "Low priority"
+ depends on SCHED_LPWORK
+
+endchoice # Work queue
+
config SAMA5_GMAC_PHYADDR
int "PHY address"
default 1
@@ -1675,6 +1695,26 @@ config SAMA5_EMACA_NBC
---help---
Select to disable receipt of broadcast packets.
+choice
+ prompt "Work queue"
+ default SAMA5_EMACA_LPWORK if SCHED_LPWORK
+ default SAMA5_EMACA_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
+ depends on SCHED_WORKQUEUE
+ ---help---
+ Work queue support is required to use the Ethernet driver. If the
+ low priority work queue is available, then it should be used by the
+ driver.
+
+config SAMA5_EMACA_HPWORK
+ bool "High priority"
+ depends on SCHED_HPWORK
+
+config SAMA5_EMACA_LPWORK
+ bool "Low priority"
+ depends on SCHED_LPWORK
+
+endchoice # Work queue
+
config SAMA5_EMACA_REGDEBUG
bool "Register-Level Debug"
default n
diff --git a/arch/arm/src/sama5/chip/sam_pwm.h b/arch/arm/src/sama5/chip/sam_pwm.h
index aa5ca2ed0ff..8aef808f293 100644
--- a/arch/arm/src/sama5/chip/sam_pwm.h
+++ b/arch/arm/src/sama5/chip/sam_pwm.h
@@ -286,6 +286,7 @@
# define PWM_CLK_DIVA(n) ((uint32_t)(n) << PWM_CLK_DIVA_SHIFT) /* CLKA clock = clock selected by PREA / DIVA */
#define PWM_CLK_PREA_SHIFT (8) /* Bits 8-11: CLKA Source Clock Selection */
#define PWM_CLK_PREA_MASK (15 << PWM_CLK_PREA_SHIFT)
+# define PWM_CLK_PREA_DIV(n) ((uint32_t)(n) << PWM_CLK_PREA_SHIFT)
# define PWM_CLK_PREA_DIV1 (0 << PWM_CLK_PREA_SHIFT) /* MCK */
# define PWM_CLK_PREA_DIV2 (1 << PWM_CLK_PREA_SHIFT) /* MCK/2 */
# define PWM_CLK_PREA_DIV4 (2 << PWM_CLK_PREA_SHIFT) /* MCK/4 */
@@ -298,11 +299,13 @@
# define PWM_CLK_PREA_DIV512 (9 << PWM_CLK_PREA_SHIFT) /* MCK/512 */
# define PWM_CLK_PREA_DIV1024 (10 << PWM_CLK_PREA_SHIFT) /* MCK/1024 */
#define PWM_CLK_DIVB_SHIFT (16) /* Bits 16-23: CLKB Divide Factor */
+#define PWM_CLK_DIVB_MASK (0xff << PWM_CLK_DIVB_SHIFT)
# define PWM_CLK_DIVB_OFF (0 << PWM_CLK_DIVB_SHIFT) /* CLKB clock = off */
# define PWM_CLK_DIVB_PREB (1 << PWM_CLK_DIVB_SHIFT) /* CLKB clock = clock selected by PREB */
# define PWM_CLK_DIVB(n) ((uint32_t)(n) << PWM_CLK_DIVB_SHIFT) /* CLKB clock = clock selected by PREB / DIVB */
#define PWM_CLK_PREB_SHIFT (24) /* Bits 24-27: CLKB Source Clock Selection */
#define PWM_CLK_PREB_MASK (15 << PWM_CLK_PREB_SHIFT)
+# define PWM_CLK_PREB_DIV(n) ((uint32_t)(n) << PWM_CLK_PREB_SHIFT)
# define PWM_CLK_PREB_DIV1 (0 << PWM_CLK_PREB_SHIFT) /* MCK */
# define PWM_CLK_PREB_DIV2 (1 << PWM_CLK_PREB_SHIFT) /* MCK/2 */
# define PWM_CLK_PREB_DIV4 (2 << PWM_CLK_PREB_SHIFT) /* MCK/4 */
diff --git a/arch/arm/src/sama5/sam_emaca.c b/arch/arm/src/sama5/sam_emaca.c
index 672a3efc7fb..29bd28c5a75 100644
--- a/arch/arm/src/sama5/sam_emaca.c
+++ b/arch/arm/src/sama5/sam_emaca.c
@@ -4,7 +4,7 @@
* 10/100 Base-T Ethernet driver for the SAMA5D3. Denoted as 'A' to
* distinguish it from the SAMA5D4 EMAC driver.
*
- * Copyright (C) 2013-2015 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2013-2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* References:
@@ -65,6 +65,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -94,6 +95,25 @@
****************************************************************************/
/* Configuration ************************************************************/
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+# error Work queue support is required
+#else
+
+ /* Select work queue */
+
+# if defined(CONFIG_SAMA5_EMACA_HPWORK)
+# define ETHWORK HPWORK
+# elif defined(CONFIG_SAMA5_EMACA_LPWORK)
+# define ETHWORK LPWORK
+# else
+# error Neither CONFIG_SAMA5_EMACA_HPWORK nor CONFIG_SAMA5_EMACA_LPWORK defined
+# endif
+#endif
+
/* Number of buffers for RX */
#ifndef CONFIG_SAMA5_EMAC_NRXBUFFERS
@@ -255,6 +275,7 @@ struct sam_emac_s
uint8_t ifup : 1; /* true:ifup false:ifdown */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
+ struct work_s work; /* For deferring work to the work queue */
/* This holds the information visible to the NuttX network */
@@ -290,7 +311,6 @@ struct sam_emac_s
static struct sam_emac_s g_emac;
-#ifdef CONFIG_NET_MULTIBUFFER
/* A single packet buffer is used
*
* REVISIT: It might be possible to use this option to send and receive
@@ -301,7 +321,6 @@ static struct sam_emac_s g_emac;
*/
static uint8_t g_pktbuf[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
-#endif
#ifdef CONFIG_SAMA5_EMACA_PREALLOCATE
/* Preallocated data */
@@ -365,17 +384,24 @@ static void sam_dopoll(struct sam_emac_s *priv);
static int sam_recvframe(struct sam_emac_s *priv);
static void sam_receive(struct sam_emac_s *priv);
static void sam_txdone(struct sam_emac_s *priv);
+
+static void sam_interrupt_work(FAR void *arg);
static int sam_emac_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static void sam_polltimer(int argc, uint32_t arg, ...);
-static void sam_txtimeout(int argc, uint32_t arg, ...);
+static void sam_txtimeout_work(FAR void *arg);
+static void sam_txtimeout_expiry(int argc, uint32_t arg, ...);
+
+static void sam_poll_work(FAR void *arg);
+static void sam_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int sam_ifup(struct net_driver_s *dev);
static int sam_ifdown(struct net_driver_s *dev);
+
+static void sam_txavail_work(FAR void *arg);
static int sam_txavail(struct net_driver_s *dev);
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
@@ -790,7 +816,7 @@ static int sam_transmit(struct sam_emac_s *priv)
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
- (void)wd_start(priv->txtimeout, SAM_TXTIMEOUT, sam_txtimeout, 1,
+ (void)wd_start(priv->txtimeout, SAM_TXTIMEOUT, sam_txtimeout_expiry, 1,
(uint32_t)priv);
/* Set d_len to zero meaning that the d_buf[] packet buffer is again
@@ -905,7 +931,7 @@ static int sam_txpoll(struct net_driver_s *dev)
*
* 1. After completion of a transmission (sam_txdone),
* 2. When new TX data is available (sam_txavail), and
- * 3. After a TX timeout to restart the sending process (sam_txtimeout).
+ * 3. After a TX timeout to restart the sending process (sam_txtimeout_expiry).
*
* Parameters:
* priv - Reference to the driver state structure
@@ -1418,25 +1444,25 @@ static void sam_txdone(struct sam_emac_s *priv)
}
/****************************************************************************
- * Function: sam_emac_interrupt
+ * Function: sam_interrupt_work
*
* Description:
- * Hardware interrupt handler
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * irq - Number of the IRQ that generated the interrupt
- * context - Interrupt register state save info (architecture-specific)
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
* OK on success
*
* Assumptions:
+ * Ethernet interrupts are disabled
*
****************************************************************************/
-static int sam_emac_interrupt(int irq, void *context)
+static void sam_interrupt_work(FAR void *arg)
{
- struct sam_emac_s *priv = &g_emac;
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
uint32_t isr;
uint32_t rsr;
uint32_t tsr;
@@ -1445,6 +1471,9 @@ static int sam_emac_interrupt(int irq, void *context)
uint32_t pending;
uint32_t clrbits;
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
isr = sam_getreg(priv, SAM_EMAC_ISR);
rsr = sam_getreg(priv, SAM_EMAC_RSR);
tsr = sam_getreg(priv, SAM_EMAC_TSR);
@@ -1600,11 +1629,116 @@ static int sam_emac_interrupt(int irq, void *context)
}
#endif
+ net_unlock();
+
+ /* Re-enable Ethernet interrupts */
+
+ up_enable_irq(SAM_IRQ_EMAC);
+}
+
+/****************************************************************************
+ * Function: sam_emac_interrupt
+ *
+ * Description:
+ * Hardware interrupt handler
+ *
+ * Parameters:
+ * irq - Number of the IRQ that generated the interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int sam_emac_interrupt(int irq, void *context)
+{
+ struct sam_emac_s *priv = &g_emac;
+ uint32_t tsr;
+
+ /* Disable further Ethernet interrupts. Because Ethernet interrupts are
+ * also disabled if the TX timeout event occurs, there can be no race
+ * condition here.
+ */
+
+ up_disable_irq(SAM_IRQ_EMAC);
+
+ /* Check for the completion of a transmission. Careful:
+ *
+ * ISR:TCOMP is set when a frame has been transmitted. Cleared on read (so
+ * we cannot read it here).
+ * TSR:TXCOMP is set when a frame has been transmitted. Cleared by writing a
+ * one to this bit.
+ */
+
+ tsr = sam_getreg(priv, SAM_EMAC_TSR_OFFSET);
+ if ((tsr & EMAC_TSR_COMP) != 0)
+ {
+ /* If a TX transfer just completed, then cancel the TX timeout so
+ * there will be do race condition between any subsequent timeout
+ * expiration and the deferred interrupt processing.
+ */
+
+ wd_cancel(priv->txtimeout);
+
+ /* Make sure that the TX poll timer is running (if it is already
+ * running, the following would restart it). This is necessary to
+ * avoid certain race conditions where the polling sequence can be
+ * interrupted.
+ */
+
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
+ }
+
+ /* Cancel any pending poll work */
+
+ work_cancel(ETHWORK, &priv->work);
+
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->work, sam_interrupt_work, priv, 0);
return OK;
}
/****************************************************************************
- * Function: sam_txtimeout
+ * Function: sam_txtimeout_work
+ *
+ * Description:
+ * Perform TX timeout related work from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * Ethernet interrupts are disabled
+ *
+ ****************************************************************************/
+
+static void sam_txtimeout_work(FAR void *arg)
+{
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
+
+ nerr("ERROR: Timeout!\n");
+
+ /* Reset the hardware. Just take the interface down, then back up again. */
+
+ net_lock();
+ sam_ifdown(&priv->dev);
+ sam_ifup(&priv->dev);
+
+ /* Then poll the network for new XMIT data */
+
+ sam_dopoll(priv);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: sam_txtimeout_expiry
*
* Description:
* Our TX watchdog timed out. Called from the timer interrupt handler.
@@ -1622,26 +1756,70 @@ static int sam_emac_interrupt(int irq, void *context)
*
****************************************************************************/
-static void sam_txtimeout(int argc, uint32_t arg, ...)
+static void sam_txtimeout_expiry(int argc, uint32_t arg, ...)
{
- struct sam_emac_s *priv = (struct sam_emac_s *)arg;
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- nerr("ERROR: Timeout!\n");
-
- /* Then reset the hardware. Just take the interface down, then back
- * up again.
+ /* Disable further Ethernet interrupts. This will prevent some race
+ * conditions with interrupt work. There is still a potential race
+ * condition with interrupt work that is already queued and in progress.
*/
- sam_ifdown(&priv->dev);
- sam_ifup(&priv->dev);
+ up_disable_irq(SAM_IRQ_EMAC);
- /* Then poll the network for new XMIT data */
+ /* Cancel any pending poll or interrupt work. This will have no effect
+ * on work that has already been started.
+ */
- sam_dopoll(priv);
+ work_cancel(ETHWORK, &priv->work);
+
+ /* Schedule to perform the TX timeout processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->work, sam_txtimeout_work, priv, 0);
}
/****************************************************************************
- * Function: sam_polltimer
+ * Function: sam_poll_work
+ *
+ * Description:
+ * Perform periodic polling from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * Ethernet interrupts are disabled
+ *
+ ****************************************************************************/
+
+static void sam_poll_work(FAR void *arg)
+{
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
+ struct net_driver_s *dev = &priv->dev;
+
+ /* Check if the there are any free TX descriptors. We cannot perform the
+ * TX poll if we do not have buffering for another packet.
+ */
+
+ net_lock();
+ if (sam_txfree(priv) > 0)
+ {
+ /* Update TCP timing states and poll the network for new XMIT data. */
+
+ (void)devif_timer(dev, sam_txpoll);
+ }
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: sam_poll_expiry
*
* Description:
* Periodic timer handler. Called from the timer interrupt handler.
@@ -1658,25 +1836,28 @@ static void sam_txtimeout(int argc, uint32_t arg, ...)
*
****************************************************************************/
-static void sam_polltimer(int argc, uint32_t arg, ...)
+static void sam_poll_expiry(int argc, uint32_t arg, ...)
{
- struct sam_emac_s *priv = (struct sam_emac_s *)arg;
- struct net_driver_s *dev = &priv->dev;
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- /* Check if the there are any free TX descriptors. We cannot perform the
- * TX poll if we do not have buffering for another packet.
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions.
*/
- if (sam_txfree(priv) > 0)
+ if (work_available(&priv->work))
{
- /* Update TCP timing states and poll the network for new XMIT data. */
+ /* Schedule to perform the interrupt processing on the worker thread. */
- (void)devif_timer(dev, sam_txpoll);
+ work_queue(ETHWORK, &priv->work, sam_poll_work, priv, 0);
}
+ else
+ {
+ /* No.. Just re-start the watchdog poll timer, missing one polling
+ * cycle.
+ */
- /* Setup the watchdog poll timer again */
-
- (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_polltimer, 1, arg);
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, arg);
+ }
}
/****************************************************************************
@@ -1747,7 +1928,7 @@ static int sam_ifup(struct net_driver_s *dev)
/* Set and activate a timer process */
- (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_polltimer, 1, (uint32_t)priv);
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, (uint32_t)priv);
/* Enable the EMAC interrupt */
@@ -1803,6 +1984,42 @@ static int sam_ifdown(struct net_driver_s *dev)
return OK;
}
+/****************************************************************************
+ * Function: sam_txavail_work
+ *
+ * Description:
+ * Perform an out-of-cycle poll on the worker thread.
+ *
+ * Parameters:
+ * arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+static void sam_txavail_work(FAR void *arg)
+{
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
+
+ ninfo("ifup: %d\n", priv->ifup);
+
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->ifup)
+ {
+ /* Poll the network for new XMIT data */
+
+ sam_dopoll(priv);
+ }
+
+ net_unlock();
+}
+
/****************************************************************************
* Function: sam_txavail
*
@@ -1812,7 +2029,7 @@ static int sam_ifdown(struct net_driver_s *dev)
* latency.
*
* Parameters:
- * dev - Reference to the NuttX driver state structure
+ * dev - Reference to the NuttX driver state structure
*
* Returned Value:
* None
@@ -1824,27 +2041,20 @@ static int sam_ifdown(struct net_driver_s *dev)
static int sam_txavail(struct net_driver_s *dev)
{
- struct sam_emac_s *priv = (struct sam_emac_s *)dev->d_private;
- irqstate_t flags;
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)dev->d_private;
- ninfo("ifup: %d\n", priv->ifup);
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
*/
- flags = enter_critical_section();
-
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
+ if (work_available(&priv->work))
{
- /* Poll the network for new XMIT data */
+ /* Schedule to serialize the poll on the worker thread. */
- sam_dopoll(priv);
+ work_queue(ETHWORK, &priv->work, sam_txavail_work, priv, 0);
}
- leave_critical_section(flags);
return OK;
}
@@ -3486,9 +3696,7 @@ int sam_emac_initialize(void)
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct sam_emac_s));
-#ifdef CONFIG_NET_MULTIBUFFER
priv->dev.d_buf = g_pktbuf; /* Single packet buffer */
-#endif
priv->dev.d_ifup = sam_ifup; /* I/F up (new IP address) callback */
priv->dev.d_ifdown = sam_ifdown; /* I/F down callback */
priv->dev.d_txavail = sam_txavail; /* New TX data callback */
diff --git a/arch/arm/src/sama5/sam_emacb.c b/arch/arm/src/sama5/sam_emacb.c
index 3d9f282ce96..44b477cb7ba 100644
--- a/arch/arm/src/sama5/sam_emacb.c
+++ b/arch/arm/src/sama5/sam_emacb.c
@@ -79,11 +79,7 @@
#include
#include
#include
-
-#ifdef CONFIG_NET_NOINTS
-# include
-#endif
-
+#include
#include
#include
#include
@@ -117,13 +113,12 @@
* is required.
*/
-#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
+#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
-#endif
+#else
-/* Select work queue */
+ /* Select work queue */
-#if defined(CONFIG_SCHED_WORKQUEUE)
# if defined(CONFIG_SAMA5_EMACB_HPWORK)
# define ETHWORK HPWORK
# elif defined(CONFIG_SAMA5_EMACB_LPWORK)
@@ -418,9 +413,7 @@ struct sam_emac_s
uint8_t ifup : 1; /* true:ifup false:ifdown */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
-#ifdef CONFIG_NET_NOINTS
struct work_s work; /* For deferring work to the work queue */
-#endif
/* This holds the information visible to the NuttX network */
@@ -486,10 +479,8 @@ static void sam_dopoll(struct sam_emac_s *priv);
static int sam_recvframe(struct sam_emac_s *priv);
static void sam_receive(struct sam_emac_s *priv);
static void sam_txdone(struct sam_emac_s *priv);
-static inline void sam_interrupt_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void sam_interrupt_work(FAR void *arg);
-#endif
static int sam_emac_interrupt(struct sam_emac_s *priv);
#ifdef CONFIG_SAMA5_EMAC0
static int sam_emac0_interrupt(int irq, void *context);
@@ -500,16 +491,10 @@ static int sam_emac1_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static inline void sam_txtimeout_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void sam_txtimeout_work(FAR void *arg);
-#endif
static void sam_txtimeout_expiry(int argc, uint32_t arg, ...);
-static inline void sam_poll_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void sam_poll_work(FAR void *arg);
-#endif
static void sam_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
@@ -517,10 +502,7 @@ static void sam_poll_expiry(int argc, uint32_t arg, ...);
static int sam_ifup(struct net_driver_s *dev);
static int sam_ifdown(struct net_driver_s *dev);
-static inline void sam_txavail_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void sam_txavail_work(FAR void *arg);
-#endif
static int sam_txavail(struct net_driver_s *dev);
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
@@ -710,7 +692,6 @@ static const struct sam_emacattr_s g_emac0_attr =
#endif
};
-#ifdef CONFIG_NET_MULTIBUFFER
/* A single packet buffer is used
*
* REVISIT: It might be possible to use this option to send and receive
@@ -721,7 +702,6 @@ static const struct sam_emacattr_s g_emac0_attr =
*/
static uint8_t g_pktbuf0[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
-#endif
/* EMAC0 peripheral state */
@@ -793,7 +773,6 @@ static const struct sam_emacattr_s g_emac1_attr =
#endif
};
-#ifdef CONFIG_NET_MULTIBUFFER
/* A single packet buffer is used
*
* REVISIT: It might be possible to use this option to send and receive
@@ -804,7 +783,6 @@ static const struct sam_emacattr_s g_emac1_attr =
*/
static uint8_t g_pktbuf1[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
-#endif
/* EMAC1 peripheral state */
@@ -1834,25 +1812,25 @@ static void sam_txdone(struct sam_emac_s *priv)
}
/****************************************************************************
- * Function: sam_interrupt_process
+ * Function: sam_interrupt_work
*
* Description:
- * Interrupt processing. This may be performed either within the interrupt
- * handler or on the worker thread, depending upon the configuration
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void sam_interrupt_process(FAR struct sam_emac_s *priv)
+static void sam_interrupt_work(FAR void *arg)
{
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
uint32_t isr;
uint32_t rsr;
uint32_t tsr;
@@ -1861,6 +1839,9 @@ static inline void sam_interrupt_process(FAR struct sam_emac_s *priv)
uint32_t pending;
uint32_t clrbits;
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
isr = sam_getreg(priv, SAM_EMAC_ISR_OFFSET);
rsr = sam_getreg(priv, SAM_EMAC_RSR_OFFSET);
tsr = sam_getreg(priv, SAM_EMAC_TSR_OFFSET);
@@ -2016,42 +1997,13 @@ static inline void sam_interrupt_process(FAR struct sam_emac_s *priv)
nwarn("WARNING: Pause TO!\n");
}
#endif
-}
-/****************************************************************************
- * Function: sam_interrupt_work
- *
- * Description:
- * Perform interrupt related work from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() was called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void sam_interrupt_work(FAR void *arg)
-{
- FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
-
- /* Process pending Ethernet interrupts */
-
- state = net_lock();
- sam_interrupt_process(priv);
- net_unlock(state);
+ net_unlock();
/* Re-enable Ethernet interrupts */
up_enable_irq(priv->attr->irq);
}
-#endif
/****************************************************************************
* Function: sam_emac_interrupt
@@ -2071,7 +2023,6 @@ static void sam_interrupt_work(FAR void *arg)
static int sam_emac_interrupt(struct sam_emac_s *priv)
{
-#ifdef CONFIG_NET_NOINTS
uint32_t tsr;
/* Disable further Ethernet interrupts. Because Ethernet interrupts are
@@ -2115,13 +2066,6 @@ static int sam_emac_interrupt(struct sam_emac_s *priv)
/* Schedule to perform the interrupt processing on the worker thread. */
work_queue(ETHWORK, &priv->work, sam_interrupt_work, priv, 0);
-
-#else
- /* Process the interrupt now */
-
- sam_interrupt_process(priv);
-#endif
-
return OK;
}
@@ -2156,40 +2100,6 @@ static int sam_emac1_interrupt(int irq, void *context)
}
#endif
-/****************************************************************************
- * Function: sam_txtimeout_process
- *
- * Description:
- * Process a TX timeout. Called from the either the watchdog timer
- * expiration logic or from the worker thread, depending upon the
- * configuration. The timeout means that the last TX never completed.
- * Reset the hardware and start again.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Global interrupts are disabled by the watchdog logic.
- *
- ****************************************************************************/
-
-static inline void sam_txtimeout_process(FAR struct sam_emac_s *priv)
-{
- nerr("ERROR: Timeout!\n");
-
- /* Reset the hardware. Just take the interface down, then back up again. */
-
- sam_ifdown(&priv->dev);
- sam_ifup(&priv->dev);
-
- /* Then poll the network for new XMIT data */
-
- sam_dopoll(priv);
-}
-
/****************************************************************************
* Function: sam_txtimeout_work
*
@@ -2207,19 +2117,23 @@ static inline void sam_txtimeout_process(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void sam_txtimeout_work(FAR void *arg)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
- /* Process pending Ethernet interrupts */
+ nerr("ERROR: Timeout!\n");
- state = net_lock();
- sam_txtimeout_process(priv);
- net_unlock(state);
+ /* Reset the hardware. Just take the interface down, then back up again. */
+
+ net_lock();
+ sam_ifdown(&priv->dev);
+ sam_ifup(&priv->dev);
+
+ /* Then poll the network for new XMIT data */
+
+ sam_dopoll(priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: sam_txtimeout_expiry
@@ -2244,7 +2158,6 @@ static void sam_txtimeout_expiry(int argc, uint32_t arg, ...)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Disable further Ethernet interrupts. This will prevent some race
* conditions with interrupt work. There is still a potential race
* condition with interrupt work that is already queued and in progress.
@@ -2261,48 +2174,6 @@ static void sam_txtimeout_expiry(int argc, uint32_t arg, ...)
/* Schedule to perform the TX timeout processing on the worker thread. */
work_queue(ETHWORK, &priv->work, sam_txtimeout_work, priv, 0);
-#else
- /* Process the timeout now */
-
- sam_txtimeout_process(priv);
-#endif
-}
-
-/****************************************************************************
- * Function: sam_poll_process
- *
- * Description:
- * Perform the periodic poll. This may be called either from watchdog
- * timer logic or from the worker thread, depending upon the configuration.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
-
-static inline void sam_poll_process(FAR struct sam_emac_s *priv)
-{
- struct net_driver_s *dev = &priv->dev;
-
- /* Check if the there are any free TX descriptors. We cannot perform the
- * TX poll if we do not have buffering for another packet.
- */
-
- if (sam_txfree(priv) > 0)
- {
- /* Update TCP timing states and poll the network for new XMIT data. */
-
- (void)devif_timer(dev, sam_txpoll);
- }
-
- /* Setup the watchdog poll timer again */
-
- (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
}
/****************************************************************************
@@ -2322,19 +2193,28 @@ static inline void sam_poll_process(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void sam_poll_work(FAR void *arg)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
+ struct net_driver_s *dev = &priv->dev;
- /* Perform the poll */
+ /* Check if the there are any free TX descriptors. We cannot perform the
+ * TX poll if we do not have buffering for another packet.
+ */
- state = net_lock();
- sam_poll_process(priv);
- net_unlock(state);
+ net_lock();
+ if (sam_txfree(priv) > 0)
+ {
+ /* Update TCP timing states and poll the network for new XMIT data. */
+
+ (void)devif_timer(dev, sam_txpoll);
+ }
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: sam_poll_expiry
@@ -2358,7 +2238,6 @@ static void sam_poll_expiry(int argc, uint32_t arg, ...)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions.
*/
@@ -2377,12 +2256,6 @@ static void sam_poll_expiry(int argc, uint32_t arg, ...)
(void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, arg);
}
-
-#else
- /* Process the interrupt now */
-
- sam_poll_process(priv);
-#endif
}
/****************************************************************************
@@ -2517,37 +2390,6 @@ static int sam_ifdown(struct net_driver_s *dev)
return OK;
}
-/****************************************************************************
- * Function: sam_txavail_process
- *
- * Description:
- * Perform an out-of-cycle poll.
- *
- * Parameters:
- * dev - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called in normal user mode
- *
- ****************************************************************************/
-
-static inline void sam_txavail_process(FAR struct sam_emac_s *priv)
-{
- ninfo("ifup: %d\n", priv->ifup);
-
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
- {
- /* Poll the network for new XMIT data */
-
- sam_dopoll(priv);
- }
-}
-
/****************************************************************************
* Function: sam_txavail_work
*
@@ -2565,19 +2407,24 @@ static inline void sam_txavail_process(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void sam_txavail_work(FAR void *arg)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
- /* Perform the poll */
+ ninfo("ifup: %d\n", priv->ifup);
- state = net_lock();
- sam_txavail_process(priv);
- net_unlock(state);
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->ifup)
+ {
+ /* Poll the network for new XMIT data */
+
+ sam_dopoll(priv);
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: sam_txavail
@@ -2602,7 +2449,6 @@ static int sam_txavail(struct net_driver_s *dev)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)dev->d_private;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions and we will have to ignore the Tx
* availability action.
@@ -2615,21 +2461,6 @@ static int sam_txavail(struct net_driver_s *dev)
work_queue(ETHWORK, &priv->work, sam_txavail_work, priv, 0);
}
-#else
- irqstate_t flags;
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
- */
-
- flags = enter_critical_section();
-
- /* Perform the out-of-cycle poll now */
-
- sam_txavail_process(priv);
- leave_critical_section(flags);
-#endif
-
return OK;
}
@@ -4546,9 +4377,7 @@ int sam_emac_initialize(int intf)
{
struct sam_emac_s *priv;
const struct sam_emacattr_s *attr;
-#ifdef CONFIG_NET_MULTIBUFFER
uint8_t *pktbuf;
-#endif
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
uint8_t phytype;
#endif
@@ -4559,10 +4388,7 @@ int sam_emac_initialize(int intf)
{
priv = &g_emac0;
attr = &g_emac0_attr;
-
-#ifdef CONFIG_NET_MULTIBUFFER
pktbuf = g_pktbuf0;
-#endif
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
phytype = SAMA5_EMAC0_PHY_TYPE;
@@ -4575,10 +4401,7 @@ int sam_emac_initialize(int intf)
{
priv = &g_emac1;
attr = &g_emac1_attr;
-
-#ifdef CONFIG_NET_MULTIBUFFER
pktbuf = g_pktbuf1;
-#endif
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
phytype = SAMA5_EMAC1_PHY_TYPE;
@@ -4595,9 +4418,7 @@ int sam_emac_initialize(int intf)
memset(priv, 0, sizeof(struct sam_emac_s));
priv->attr = attr; /* Save the constant attributes */
-#ifdef CONFIG_NET_MULTIBUFFER
priv->dev.d_buf = pktbuf; /* Single packet buffer */
-#endif
priv->dev.d_ifup = sam_ifup; /* I/F up (new IP address) callback */
priv->dev.d_ifdown = sam_ifdown; /* I/F down callback */
priv->dev.d_txavail = sam_txavail; /* New TX data callback */
diff --git a/arch/arm/src/sama5/sam_gmac.c b/arch/arm/src/sama5/sam_gmac.c
index 5442920ee03..da6b320d523 100644
--- a/arch/arm/src/sama5/sam_gmac.c
+++ b/arch/arm/src/sama5/sam_gmac.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/sama5/sam_gmac.c
*
- * Copyright (C) 2013-2015 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2013-2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* References:
@@ -62,6 +62,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -91,6 +92,25 @@
****************************************************************************/
/* Configuration ************************************************************/
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+# error Work queue support is required
+#else
+
+ /* Select work queue */
+
+# if defined(CONFIG_SAMA5_GMAC_HPWORK)
+# define ETHWORK HPWORK
+# elif defined(CONFIG_SAMA5_GMAC_LPWORK)
+# define ETHWORK LPWORK
+# else
+# error Neither CONFIG_SAMA5_GMAC_HPWORK nor CONFIG_SAMA5_GMAC_LPWORK defined
+# endif
+#endif
+
/* Number of buffer for RX */
#ifndef CONFIG_SAMA5_GMAC_NRXBUFFERS
@@ -181,6 +201,7 @@ struct sam_gmac_s
uint8_t ifup : 1; /* true:ifup false:ifdown */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
+ struct work_s work; /* For deferring work to the work queue */
/* This holds the information visible to the NuttX network */
@@ -216,7 +237,6 @@ struct sam_gmac_s
static struct sam_gmac_s g_gmac;
-#ifdef CONFIG_NET_MULTIBUFFER
/* A single packet buffer is used
*
* REVISIT: It might be possible to use this option to send and receive
@@ -227,7 +247,6 @@ static struct sam_gmac_s g_gmac;
*/
static uint8_t g_pktbuf[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
-#endif
#ifdef CONFIG_SAMA5_GMAC_PREALLOCATE
/* Preallocated data */
@@ -290,17 +309,24 @@ static void sam_dopoll(struct sam_gmac_s *priv);
static int sam_recvframe(struct sam_gmac_s *priv);
static void sam_receive(struct sam_gmac_s *priv);
static void sam_txdone(struct sam_gmac_s *priv);
+
+static void sam_interrupt_work(FAR void *arg);
static int sam_gmac_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static void sam_polltimer(int argc, uint32_t arg, ...);
-static void sam_txtimeout(int argc, uint32_t arg, ...);
+static void sam_txtimeout_work(FAR void *arg);
+static void sam_txtimeout_expiry(int argc, uint32_t arg, ...);
+
+static void sam_poll_work(FAR void *arg);
+static void sam_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int sam_ifup(struct net_driver_s *dev);
static int sam_ifdown(struct net_driver_s *dev);
+
+static void sam_txavail_work(FAR void *arg);
static int sam_txavail(struct net_driver_s *dev);
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
@@ -722,7 +748,7 @@ static int sam_transmit(struct sam_gmac_s *priv)
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
- (void)wd_start(priv->txtimeout, SAM_TXTIMEOUT, sam_txtimeout, 1,
+ (void)wd_start(priv->txtimeout, SAM_TXTIMEOUT, sam_txtimeout_expiry, 1,
(uint32_t)priv);
/* Set d_len to zero meaning that the d_buf[] packet buffer is again
@@ -837,7 +863,7 @@ static int sam_txpoll(struct net_driver_s *dev)
*
* 1. After completion of a transmission (sam_txdone),
* 2. When new TX data is available (sam_txavail), and
- * 3. After a TX timeout to restart the sending process (sam_txtimeout).
+ * 3. After a TX timeout to restart the sending process (sam_txtimeout_expiry).
*
* Parameters:
* priv - Reference to the driver state structure
@@ -1346,25 +1372,25 @@ static void sam_txdone(struct sam_gmac_s *priv)
}
/****************************************************************************
- * Function: sam_gmac_interrupt
+ * Function: sam_interrupt_work
*
* Description:
- * Hardware interrupt handler
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * irq - Number of the IRQ that generated the interrupt
- * context - Interrupt register state save info (architecture-specific)
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
* OK on success
*
* Assumptions:
+ * Ethernet interrupts are disabled
*
****************************************************************************/
-static int sam_gmac_interrupt(int irq, void *context)
+static void sam_interrupt_work(FAR void *arg)
{
- struct sam_gmac_s *priv = &g_gmac;
+ FAR struct sam_gmac_s *priv = (FAR struct sam_gmac_s *)arg;
uint32_t isr;
uint32_t rsr;
uint32_t tsr;
@@ -1373,6 +1399,9 @@ static int sam_gmac_interrupt(int irq, void *context)
uint32_t pending;
uint32_t clrbits;
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
isr = sam_getreg(priv, SAM_GMAC_ISR);
rsr = sam_getreg(priv, SAM_GMAC_RSR);
tsr = sam_getreg(priv, SAM_GMAC_TSR);
@@ -1552,11 +1581,116 @@ static int sam_gmac_interrupt(int irq, void *context)
}
#endif
+ net_unlock();
+
+ /* Re-enable Ethernet interrupts */
+
+ up_enable_irq(SAM_IRQ_GMAC);
+}
+
+/****************************************************************************
+ * Function: sam_gmac_interrupt
+ *
+ * Description:
+ * Hardware interrupt handler
+ *
+ * Parameters:
+ * irq - Number of the IRQ that generated the interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int sam_gmac_interrupt(int irq, void *context)
+{
+ struct sam_gmac_s *priv = &g_gmac;
+ uint32_t tsr;
+
+ /* Disable further Ethernet interrupts. Because Ethernet interrupts are
+ * also disabled if the TX timeout event occurs, there can be no race
+ * condition here.
+ */
+
+ up_disable_irq(SAM_IRQ_GMAC);
+
+ /* Check for the completion of a transmission. Careful:
+ *
+ * ISR:TCOMP is set when a frame has been transmitted. Cleared on read (so
+ * we cannot read it here).
+ * TSR:TXCOMP is set when a frame has been transmitted. Cleared by writing a
+ * one to this bit.
+ */
+
+ tsr = sam_getreg(priv, SAM_GMAC_TSR_OFFSET);
+ if ((tsr & GMAC_TSR_TXCOMP) != 0)
+ {
+ /* If a TX transfer just completed, then cancel the TX timeout so
+ * there will be do race condition between any subsequent timeout
+ * expiration and the deferred interrupt processing.
+ */
+
+ wd_cancel(priv->txtimeout);
+
+ /* Make sure that the TX poll timer is running (if it is already
+ * running, the following would restart it). This is necessary to
+ * avoid certain race conditions where the polling sequence can be
+ * interrupted.
+ */
+
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
+ }
+
+ /* Cancel any pending poll work */
+
+ work_cancel(ETHWORK, &priv->work);
+
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->work, sam_interrupt_work, priv, 0);
return OK;
}
/****************************************************************************
- * Function: sam_txtimeout
+ * Function: sam_txtimeout_work
+ *
+ * Description:
+ * Perform TX timeout related work from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * Ethernet interrupts are disabled
+ *
+ ****************************************************************************/
+
+static void sam_txtimeout_work(FAR void *arg)
+{
+ FAR struct sam_gmac_s *priv = (FAR struct sam_gmac_s *)arg;
+
+ nerr("ERROR: Timeout!\n");
+
+ /* Reset the hardware. Just take the interface down, then back up again. */
+
+ net_lock();
+ sam_ifdown(&priv->dev);
+ sam_ifup(&priv->dev);
+
+ /* Then poll the network for new XMIT data */
+
+ sam_dopoll(priv);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: sam_txtimeout_expiry
*
* Description:
* Our TX watchdog timed out. Called from the timer interrupt handler.
@@ -1574,26 +1708,70 @@ static int sam_gmac_interrupt(int irq, void *context)
*
****************************************************************************/
-static void sam_txtimeout(int argc, uint32_t arg, ...)
+static void sam_txtimeout_expiry(int argc, uint32_t arg, ...)
{
- struct sam_gmac_s *priv = (struct sam_gmac_s *)arg;
+ FAR struct sam_gmac_s *priv = (FAR struct sam_gmac_s *)arg;
- nerr("ERROR: Timeout!\n");
-
- /* Then reset the hardware. Just take the interface down, then back
- * up again.
+ /* Disable further Ethernet interrupts. This will prevent some race
+ * conditions with interrupt work. There is still a potential race
+ * condition with interrupt work that is already queued and in progress.
*/
- sam_ifdown(&priv->dev);
- sam_ifup(&priv->dev);
+ up_disable_irq(SAM_IRQ_GMAC);
- /* Then poll the network for new XMIT data */
+ /* Cancel any pending poll or interrupt work. This will have no effect
+ * on work that has already been started.
+ */
- sam_dopoll(priv);
+ work_cancel(ETHWORK, &priv->work);
+
+ /* Schedule to perform the TX timeout processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->work, sam_txtimeout_work, priv, 0);
}
/****************************************************************************
- * Function: sam_polltimer
+ * Function: sam_poll_work
+ *
+ * Description:
+ * Perform periodic polling from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * Ethernet interrupts are disabled
+ *
+ ****************************************************************************/
+
+static void sam_poll_work(FAR void *arg)
+{
+ FAR struct sam_gmac_s *priv = (FAR struct sam_gmac_s *)arg;
+ struct net_driver_s *dev = &priv->dev;
+
+ /* Check if the there are any free TX descriptors. We cannot perform the
+ * TX poll if we do not have buffering for another packet.
+ */
+
+ net_lock();
+ if (sam_txfree(priv) > 0)
+ {
+ /* Update TCP timing states and poll the network for new XMIT data. */
+
+ (void)devif_timer(dev, sam_txpoll);
+ }
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: sam_poll_expiry
*
* Description:
* Periodic timer handler. Called from the timer interrupt handler.
@@ -1610,25 +1788,28 @@ static void sam_txtimeout(int argc, uint32_t arg, ...)
*
****************************************************************************/
-static void sam_polltimer(int argc, uint32_t arg, ...)
+static void sam_poll_expiry(int argc, uint32_t arg, ...)
{
- struct sam_gmac_s *priv = (struct sam_gmac_s *)arg;
- struct net_driver_s *dev = &priv->dev;
+ FAR struct sam_gmac_s *priv = (FAR struct sam_gmac_s *)arg;
- /* Check if the there are any free TX descriptors. We cannot perform the
- * TX poll if we do not have buffering for another packet.
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions.
*/
- if (sam_txfree(priv) > 0)
+ if (work_available(&priv->work))
{
- /* Update TCP timing states and poll the network for new XMIT data. */
+ /* Schedule to perform the interrupt processing on the worker thread. */
- (void)devif_timer(dev, sam_txpoll);
+ work_queue(ETHWORK, &priv->work, sam_poll_work, priv, 0);
}
+ else
+ {
+ /* No.. Just re-start the watchdog poll timer, missing one polling
+ * cycle.
+ */
- /* Setup the watchdog poll timer again */
-
- (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_polltimer, 1, arg);
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, arg);
+ }
}
/****************************************************************************
@@ -1702,7 +1883,7 @@ static int sam_ifup(struct net_driver_s *dev)
/* Set and activate a timer process */
- (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_polltimer, 1, (uint32_t)priv);
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, (uint32_t)priv);
/* Enable the GMAC interrupt */
@@ -1758,6 +1939,42 @@ static int sam_ifdown(struct net_driver_s *dev)
return OK;
}
+/****************************************************************************
+ * Function: sam_txavail_work
+ *
+ * Description:
+ * Perform an out-of-cycle poll on the worker thread.
+ *
+ * Parameters:
+ * arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+static void sam_txavail_work(FAR void *arg)
+{
+ FAR struct sam_gmac_s *priv = (FAR struct sam_gmac_s *)arg;
+
+ ninfo("ifup: %d\n", priv->ifup);
+
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->ifup)
+ {
+ /* Poll the network for new XMIT data */
+
+ sam_dopoll(priv);
+ }
+
+ net_unlock();
+}
+
/****************************************************************************
* Function: sam_txavail
*
@@ -1767,7 +1984,7 @@ static int sam_ifdown(struct net_driver_s *dev)
* latency.
*
* Parameters:
- * dev - Reference to the NuttX driver state structure
+ * dev - Reference to the NuttX driver state structure
*
* Returned Value:
* None
@@ -1779,27 +1996,20 @@ static int sam_ifdown(struct net_driver_s *dev)
static int sam_txavail(struct net_driver_s *dev)
{
- struct sam_gmac_s *priv = (struct sam_gmac_s *)dev->d_private;
- irqstate_t flags;
+ FAR struct sam_gmac_s *priv = (FAR struct sam_gmac_s *)dev->d_private;
- ninfo("ifup: %d\n", priv->ifup);
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
*/
- flags = enter_critical_section();
-
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
+ if (work_available(&priv->work))
{
- /* Poll the network for new XMIT data */
+ /* Schedule to serialize the poll on the worker thread. */
- sam_dopoll(priv);
+ work_queue(ETHWORK, &priv->work, sam_txavail_work, priv, 0);
}
- leave_critical_section(flags);
return OK;
}
@@ -3558,9 +3768,7 @@ int sam_gmac_initialize(void)
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct sam_gmac_s));
-#ifdef CONFIG_NET_MULTIBUFFER
priv->dev.d_buf = g_pktbuf; /* Single packet buffer */
-#endif
priv->dev.d_ifup = sam_ifup; /* I/F up (new IP address) callback */
priv->dev.d_ifdown = sam_ifdown; /* I/F down callback */
priv->dev.d_txavail = sam_txavail; /* New TX data callback */
diff --git a/arch/arm/src/sama5/sam_pwm.c b/arch/arm/src/sama5/sam_pwm.c
index d523da24a1c..622d4569b0f 100644
--- a/arch/arm/src/sama5/sam_pwm.c
+++ b/arch/arm/src/sama5/sam_pwm.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/sama5/sam_pwm.c
*
- * Copyright (C) 2013 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2013, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -82,154 +82,14 @@
# warning CONFIG_PWM_PULSECOUNT no supported by this driver.
#endif
-/* Are we using CLKA? CLKB? If so, what frequency? Select the prescaler
- * value that allows the largest, valid divider value. This may not be
- * optimal in all cases, but in general should provide a reasonable frequency
- * value.
- *
- * frequency = MCK / prescaler / div
- *
- * Pick smallest prescaler such that:
- *
- * prescaler = MCK / frequency / div < 256
- *
- * Then:
- *
- * div = MCK / prescaler / frequency
- *
- * Calulcated Values
- *
- * CLKn_PRE = CLKn prescaler value
- * PWM_CLK_PREn = CLKn prescaler register setting
- * CLKn_DIV = CLKn divider value
- * PWM_CLK_DIVn = CLKn divider register setting
- * CLKn_FREQUENCY = Actual resulting CLKn frequency
- */
+/* Are we using CLKA? CLKB? If so, at what frequency? */
-#ifdef CONFIG_SAMA5_PWM_CLKA
-
-# if !defined(CONFIG_SAMA5_PWM_CLKA_FREQUENCY)
+#if defined(CONFIG_SAMA5_PWM_CLKA) && !defined(CONFIG_SAMA5_PWM_CLKA_FREQUENCY)
# error CONFIG_SAMA5_PWM_CLKA_FREQUENCY is not defined
-
-# elif (BOARD_MCK_FREQUENCY / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV1
-# define CLKA_PRE 1
-
-# elif (BOARD_MCK_FREQUENCY / 2 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV2
-# define CLKA_PRE 2
-
-# elif (BOARD_MCK_FREQUENCY / 4 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV4
-# define CLKA_PRE 4
-
-# elif (BOARD_MCK_FREQUENCY / 8 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV8
-# define CLKA_PRE 8
-
-# elif (BOARD_MCK_FREQUENCY / 16 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV16
-# define CLKA_PRE 16
-
-# elif (BOARD_MCK_FREQUENCY / 32 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV32
-# define CLKA_PRE 32
-
-# elif (BOARD_MCK_FREQUENCY / 64 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV64
-# define CLKA_PRE 64
-
-# elif (BOARD_MCK_FREQUENCY / 128 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV128
-# define CLKA_PRE 128
-
-# elif (BOARD_MCK_FREQUENCY / 256 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV256
-# define CLKA_PRE 256
-
-# elif (BOARD_MCK_FREQUENCY / 512 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV512
-# define CLKA_PRE 512
-
-# elif (BOARD_MCK_FREQUENCY / 1024 / CONFIG_SAMA5_PWM_CLKA_FREQUENCY) < 256
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV1024
-# define CLKA_PRE 1024
-
-# else
-# error Cannot realize CONFIG_SAMA5_PWM_CLKA_FREQUENCY
-# endif
-
-# define CLKA_DIV (BOARD_MCK_FREQUENCY / CLKA_PRE / CONFIG_SAMA5_PWM_CLKA_FREQUENCY)
-# define CLKA_FREQUENCY (BOARD_MCK_FREQUENCY / CLKA_PRE / CLKA_DIV)
-# define CLKA_DIV_BITS PWM_CLK_DIVA(CLKA_DIV)
-
-#else
-# undef CONFIG_SAMA5_PWM_CLKA_FREQUENCY
-# define CLKA_PRE_BITS PWM_CLK_PREA_DIV1
-# define CLKA_DIV_BITS PWM_CLK_DIVA_OFF
#endif
-#ifdef CONFIG_SAMA5_PWM_CLKB
-
-# if !defined(CONFIG_SAMA5_PWM_CLKB_FREQUENCY)
+#if defined(CONFIG_SAMA5_PWM_CLKB) && !defined(CONFIG_SAMA5_PWM_CLKB_FREQUENCY)
# error CONFIG_SAMA5_PWM_CLKB_FREQUENCY is not defined
-
-# elif (BOARD_MCK_FREQUENCY / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV1
-# define CLKB_PRE 1
-
-# elif (BOARD_MCK_FREQUENCY / 2 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV2
-# define CLKB_PRE 2
-
-# elif (BOARD_MCK_FREQUENCY / 4 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV4
-# define CLKB_PRE 4
-
-# elif (BOARD_MCK_FREQUENCY / 8 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV8
-# define CLKB_PRE 8
-
-# elif (BOARD_MCK_FREQUENCY / 16 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV16
-# define CLKB_PRE 16
-
-# elif (BOARD_MCK_FREQUENCY / 32 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV32
-# define CLKB_PRE 32
-
-# elif (BOARD_MCK_FREQUENCY / 64 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV64
-# define CLKB_PRE 64
-
-# elif (BOARD_MCK_FREQUENCY / 128 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV128
-# define CLKB_PRE 128
-
-# elif (BOARD_MCK_FREQUENCY / 256 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV256
-# define CLKB_PRE 256
-
-# elif (BOARD_MCK_FREQUENCY / 512 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV512
-# define CLKB_PRE 512
-
-# elif (BOARD_MCK_FREQUENCY / 1024 / CONFIG_SAMA5_PWM_CLKB_FREQUENCY) < 256
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV1024
-# define CLKB_PRE 1024
-
-# else
-# error Cannot realize CONFIG_SAMA5_PWM_CLKB_FREQUENCY
-# endif
-
-# define CLKB_DIV (BOARD_MCK_FREQUENCY / CLKB_PRE / CONFIG_SAMA5_PWM_CLKB_FREQUENCY)
-# define CLKB_FREQUENCY (BOARD_MCK_FREQUENCY / CLKB_PRE / CLKB_DIV)
-# define CLKB_DIV_BITS PWM_CLK_DIVB(CLKB_DIV)
-
-#else
-# undef CONFIG_SAMA5_PWM_CLKB_FREQUENCY
-# define CLKB_PRE_BITS PWM_CLK_PREB_DIV1
-# define CLKB_DIV_BITS PWM_CLK_DIVB_OFF
#endif
#ifdef CONFIG_SAMA5_PWM_CHAN0
@@ -237,27 +97,27 @@
# undef CONFIG_SAMA5_PWM_CHAN0_CLKA
# undef CONFIG_SAMA5_PWM_CHAN0_CLKB
# if CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 1
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 0
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 0
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 2
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 1
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 1
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 4
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 2
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 2
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 8
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 3
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 3
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 16
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 4
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 4
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 32
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 5
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 5
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 64
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 6
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 6
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 128
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 7
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 7
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 256
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 8
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 8
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 512
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 9
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 9
# elif CONFIG_SAMA5_PWM_CHAN0_MCKDIV == 1024
-# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 = 10
+# define SAMA5_PWM_CHAN0_MCKDIV_LOG2 10
# else
# error Unsupported MCK divider value
# endif
@@ -485,6 +345,11 @@ static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev,
/* Initialization */
+static unsigned int pwm_clk_prescaler_log2(uint32_t mck, uint32_t fclk);
+static unsigned int pwm_clk_divider(uint32_t mck, uint32_t fclk,
+ unsigned int prelog2);
+static uint32_t pwm_clk_frequency(uint32_t mck, unsigned int prelog2,
+ unsigned int div);
static void pwm_resetpins(FAR struct sam_pwm_chan_s *chan);
/****************************************************************************
@@ -779,6 +644,7 @@ static uint32_t pwm_getreg(struct sam_pwm_chan_s *chan, int offset)
*
****************************************************************************/
+#ifdef CONFIG_DEBUG_PWM_INFO /* Currently only used for debug output */
static uint32_t pwm_chan_getreg(struct sam_pwm_chan_s *chan, int offset)
{
uintptr_t regaddr;
@@ -800,6 +666,7 @@ static uint32_t pwm_chan_getreg(struct sam_pwm_chan_s *chan, int offset)
return regval;
}
+#endif
/****************************************************************************
* Name: pwm_putreg
@@ -1073,6 +940,11 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
FAR const struct pwm_info_s *info)
{
FAR struct sam_pwm_chan_s *chan = (FAR struct sam_pwm_chan_s *)dev;
+#if defined(CONFIG_SAMA5_PWM_CLKA) || defined(CONFIG_SAMA5_PWM_CLKB)
+ unsigned int prelog2;
+ unsigned int div;
+ uint32_t mck;
+#endif
uint32_t regval;
uint32_t cprd;
uint32_t fsrc;
@@ -1086,21 +958,35 @@ static int pwm_start(FAR struct pwm_lowerhalf_s *dev,
switch (chan->clksrc)
{
case PWM_CLKSRC_MCK:
- regval = PWM_CMR_CPRE_MCKDIV(chan->divlog2);
- fsrc = BOARD_MCK_FREQUENCY >> chan->divlog2;
+ {
+ regval = PWM_CMR_CPRE_MCKDIV(chan->divlog2);
+ fsrc = BOARD_MCK_FREQUENCY >> chan->divlog2;
+ }
break;
#ifdef CONFIG_SAMA5_PWM_CLKA
case PWM_CLKSRC_CLKA:
- regval = PWM_CMR_CPRE_CLKA;
- fsrc = CLKA_FREQUENCY;
+ {
+ regval = pwm_getreg(chan, SAM_PWM_CLK_OFFSET);
+ prelog2 = (unsigned int)((regval & PWM_CLK_PREA_MASK) >> PWM_CLK_PREA_SHIFT);
+ div = (unsigned int)((regval & PWM_CLK_DIVA_MASK) >> PWM_CLK_DIVA_SHIFT);
+ mck = BOARD_MCK_FREQUENCY;
+ fsrc = pwm_clk_frequency(mck, prelog2, div);
+ regval = PWM_CMR_CPRE_CLKA;
+ }
break;
#endif
#ifdef CONFIG_SAMA5_PWM_CLKB
case PWM_CLKSRC_CLKB:
- regval = PWM_CMR_CPRE_CLKB;
- fsrc = CLKB_FREQUENCY;
+ {
+ regval = pwm_getreg(chan, SAM_PWM_CLK_OFFSET);
+ prelog2 = (unsigned int)((regval & PWM_CLK_PREB_MASK) >> PWM_CLK_PREB_SHIFT);
+ div = (unsigned int)((regval & PWM_CLK_DIVB_MASK) >> PWM_CLK_DIVB_SHIFT);
+ mck = BOARD_MCK_FREQUENCY;
+ fsrc = pwm_clk_frequency(mck, prelog2, div);
+ regval = PWM_CMR_CPRE_CLKB;
+ }
break;
#endif
@@ -1223,18 +1109,157 @@ static int pwm_ioctl(FAR struct pwm_lowerhalf_s *dev, int cmd, unsigned long arg
}
/****************************************************************************
- * Name: pwm_ioctl
+ * Name: pwm_clk_prescaler_log2
+ *
+ * Description:
+ * Return log2 of the clock prescaler value. The PWM clock divisor
+ * register fields use this kind of value. The return value of this
+ * function can be converted into a PWM clock register value or an absolute
+ * prescaler value by applying the following operations (macros defined in
+ * chip/sam_pwm.h):
+ *
+ * This function selects the prescaler value that allows the largest, valid
+ * divider value. This may not be optimal in all cases, but in general
+ * should provide a reasonable frequency value. The frequency is given by:
+ *
+ * frequency = MCK / prescaler / div
+ *
+ * The divider has a range of 1-255. Pick smallest prescaler such that:
+ *
+ * prescaler = MCK / frequency / div < 256
+ *
+ * Example usage given:
+ * unsigned int prelog2;
+ * unsigned int prescaler;
+ * uint32_t regbits;
+ *
+ * For clock A:
+ * prelog2 = pwm_clk_prescaler_log2(BOARD_MCK_FREQUENCY,
+ * CONFIG_SAMA5_PWM_CLKA_FREQUENCY )
+ * regbits = PWM_CLK_PREA_DIV(prelog2);
+ * prescaler = (1 << prelog2)
+ *
+ * For clock B:
+ * prelog2 = pwm_clk_prescaler_log2(BOARD_MCK_FREQUENCY,
+ * CONFIG_SAMA5_PWM_CLKB_FREQUENCY )
+ * regbits = PWM_CLK_PREB_DIV(prelog2);
+ * prescaler = (1 << prelog2)
+ *
+ * Input parameters:
+ * mck - The main clock frequency
+ * fclk - The desired clock A or B frequency
+ *
+ * Returned Value:
+ * The select value of log2(prescaler) in the range 0-10 corresponding to
+ * the actual prescaler value in the range 1-1024.
+ *
+ ****************************************************************************/
+
+static unsigned int pwm_clk_prescaler_log2(uint32_t mck, uint32_t fclk)
+{
+ uint32_t unscaled;
+ unsigned int prelog2;
+
+ unscaled = mck / fclk;
+ prelog2 = 0;
+
+ /* Loop, incrementing the log2(prescaler) value. Exit with either:
+ *
+ * 1) unscaled < 256 and prelog2 <= 10, or with
+ * 2) unscaled >= 256 and prelog2 == 10
+ */
+
+ while (unscaled >= 256 && prelog2 < 10)
+ {
+ unscaled >>= 1;
+ prelog2++;
+ }
+
+ DEBUGASSERT(unscaled < 256);
+ return prelog2;
+}
+
+/****************************************************************************
+ * Name: pwm_clk_divider
+ *
+ * Description:
+ * Given that we have already selected the prescaler value, select the
+ * divider in the range of 1 through 255. The CLKA/B frequency is
+ * determined by both the prescaler and divider valuess:
+ *
+ * frequency = MCK / prescaler / div
+ *
+ * Then:
+ *
+ * div = MCK / prescaler / frequency
+ *
+ * Input parameters:
+ * mck - The main clock frequency
+ * fclk - The desired clock A or B frequency
+ * prelog2 - The log2(prescaler) value previously selected by
+ * pwm_prescale_log2().
+ *
+ * Returned Value:
+ * The select value of log2(prescaler) in the range 0-10 corresponding to
+ * the actual prescaler value in the range 1-1024.
+ *
+ ****************************************************************************/
+
+static unsigned int pwm_clk_divider(uint32_t mck, uint32_t fclk,
+ unsigned int prelog2)
+{
+ uint32_t div = (mck >> prelog2) / fclk;
+
+ if (div < 1)
+ {
+ div = 1;
+ }
+ else if (div > 255)
+ {
+ div = 255;
+ }
+
+ return div;
+}
+
+/****************************************************************************
+ * Name: pwm_clk_frequency
+ *
+ * Description:
+ * Given that we have already selected the prescaler value and cacluated
+ * the corresponding divider, the result clock frequency is give by:
+ *
+ * frequency = MCK / prescaler / div
+ *
+ * Input parameters:
+ * mck - The main clock frequency
+ * prelog2 - The log2(prescaler) value previously selected by
+ * pwm_prescale_log2().
+ * div - The divider previously calculated from pwm_clk_divider().
+ *
+ * Returned Value:
+ * The select value of log2(prescaler) in the range 0-10 corresponding to
+ * the actual prescaler value in the range 1-1024.
+ *
+ ****************************************************************************/
+
+static uint32_t pwm_clk_frequency(uint32_t mck, unsigned int prelog2,
+ unsigned int div)
+{
+ return (mck >> prelog2) / div;
+}
+
+/****************************************************************************
+ * Name: pwm_resetpins
*
* Description:
* Lower-half logic may support platform-specific ioctl commands
*
* Input parameters:
- * dev - A reference to the lower half PWM driver state structure
- * cmd - The ioctl command
- * arg - The argument accompanying the ioctl command
+ * chan - A reference to the PWM channel instance
*
* Returned Value:
- * Zero on success; a negated errno value on failure
+ * None
*
****************************************************************************/
@@ -1327,13 +1352,37 @@ FAR struct pwm_lowerhalf_s *sam_pwminitialize(int channel)
if (!g_pwm.initialized)
{
+#if defined(CONFIG_SAMA5_PWM_CLKA) || defined(CONFIG_SAMA5_PWM_CLKB)
+ uint32_t mck;
+ unsigned int prelog2;
+ unsigned int div;
+#endif
+
/* Enable the PWM peripheral clock */
sam_pwm_enableclk();
- /* Set clock A and clock B */
+#if defined(CONFIG_SAMA5_PWM_CLKA) || defined(CONFIG_SAMA5_PWM_CLKB)
+ mck = BOARD_MCK_FREQUENCY;
+#endif
+#ifdef CONFIG_SAMA5_PWM_CLKA
+ /* Set clock A configuration */
+
+ prelog2 = pwm_clk_prescaler_log2(mck, CONFIG_SAMA5_PWM_CLKA_FREQUENCY);
+ div = pwm_clk_divider(mck, CONFIG_SAMA5_PWM_CLKA_FREQUENCY, prelog2);
+ regval = (PWM_CLK_DIVA(div) | PWM_CLK_PREA_DIV(prelog2));
+#else
+ regval = 0;
+#endif
+
+#ifdef CONFIG_SAMA5_PWM_CLKB
+ /* Set clock B configuration */
+
+ prelog2 = pwm_clk_prescaler_log2(mck, CONFIG_SAMA5_PWM_CLKB_FREQUENCY);
+ div = pwm_clk_divider(mck, CONFIG_SAMA5_PWM_CLKA_FREQUENCY, prelog2);
+ regval |= (PWM_CLK_DIVB(div) | PWM_CLK_PREB_DIV(prelog2));
+#endif
- regval = (CLKA_PRE_BITS | CLKA_DIV_BITS | CLKB_PRE_BITS | CLKB_DIV_BITS);
pwm_putreg(chan, SAM_PWM_CLK_OFFSET, regval);
/* Disable all PWM interrupts at the PWM peripheral */
diff --git a/arch/arm/src/samv7/sam_emac.c b/arch/arm/src/samv7/sam_emac.c
index 2eefdcefa7d..271ab994be9 100644
--- a/arch/arm/src/samv7/sam_emac.c
+++ b/arch/arm/src/samv7/sam_emac.c
@@ -69,11 +69,7 @@
#include
#include
#include
-
-#ifdef CONFIG_NET_NOINTS
-# include
-#endif
-
+#include
#include
#include
#include
@@ -107,13 +103,12 @@
* is required.
*/
-#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
+#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
-#endif
+#else
-/* Select work queue */
+ /* Select work queue */
-#if defined(CONFIG_SCHED_WORKQUEUE)
# if defined(CONFIG_SAMV7_EMAC_HPWORK)
# define ETHWORK HPWORK
# elif defined(CONFIG_SAMV7_EMAC_LPWORK)
@@ -523,9 +518,7 @@ struct sam_emac_s
uint8_t ifup : 1; /* true:ifup false:ifdown */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
-#ifdef CONFIG_NET_NOINTS
struct work_s work; /* For deferring work to the work queue */
-#endif
/* This holds the information visible to the NuttX network */
@@ -588,11 +581,8 @@ static int sam_recvframe(struct sam_emac_s *priv, int qid);
static void sam_receive(struct sam_emac_s *priv, int qid);
static void sam_txdone(struct sam_emac_s *priv, int qid);
static void sam_txerr_interrupt(FAR struct sam_emac_s *priv, int qid);
-static inline void sam_interrupt_process(FAR struct sam_emac_s *priv,
- int qid);
-#ifdef CONFIG_NET_NOINTS
+
static void sam_interrupt_work(FAR void *arg);
-#endif
static int sam_emac_interrupt(struct sam_emac_s *priv);
#ifdef CONFIG_SAMV7_EMAC0
static int sam_emac0_interrupt(int irq, void *context);
@@ -603,16 +593,10 @@ static int sam_emac1_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static inline void sam_txtimeout_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void sam_txtimeout_work(FAR void *arg);
-#endif
static void sam_txtimeout_expiry(int argc, uint32_t arg, ...);
-static inline void sam_poll_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void sam_poll_work(FAR void *arg);
-#endif
static void sam_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
@@ -620,10 +604,7 @@ static void sam_poll_expiry(int argc, uint32_t arg, ...);
static int sam_ifup(struct net_driver_s *dev);
static int sam_ifdown(struct net_driver_s *dev);
-static inline void sam_txavail_process(FAR struct sam_emac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void sam_txavail_work(FAR void *arg);
-#endif
static int sam_txavail(struct net_driver_s *dev);
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
@@ -856,7 +837,6 @@ static const struct sam_emacattr_s g_emac0_attr =
#endif
};
-#ifdef CONFIG_NET_MULTIBUFFER
/* A single packet buffer is used
*
* REVISIT: It might be possible to use this option to send and receive
@@ -867,7 +847,6 @@ static const struct sam_emacattr_s g_emac0_attr =
*/
static uint8_t g_pktbuf0[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
-#endif
/* EMAC0 peripheral state */
@@ -939,7 +918,6 @@ static const struct sam_emacattr_s g_emac1_attr =
#endif
};
-#ifdef CONFIG_NET_MULTIBUFFER
/* A single packet buffer is used
*
* REVISIT: It might be possible to use this option to send and receive
@@ -950,7 +928,6 @@ static const struct sam_emacattr_s g_emac1_attr =
*/
static uint8_t g_pktbuf1[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
-#endif
/* EMAC1 peripheral state */
@@ -2276,26 +2253,25 @@ static void sam_txerr_interrupt(FAR struct sam_emac_s *priv, int qid)
}
/****************************************************************************
- * Function: sam_interrupt_process
+ * Function: sam_interrupt_work
*
* Description:
- * Interrupt processing. This may be performed either within the interrupt
- * handler or on the worker thread, depending upon the configuration
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
- * quid - Index of the transfer queue that generated the interrupt
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void sam_interrupt_process(FAR struct sam_emac_s *priv, int qid)
+static void sam_interrupt_work(FAR void *arg)
{
+ FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
uint32_t isr;
uint32_t rsr;
uint32_t tsr;
@@ -2304,6 +2280,10 @@ static inline void sam_interrupt_process(FAR struct sam_emac_s *priv, int qid)
uint32_t pending;
uint32_t clrbits;
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
+
/* Read the interrupt status, RX status, and TX status registers.
* NOTE that the interrupt status register is cleared by this read.
*/
@@ -2462,42 +2442,13 @@ static inline void sam_interrupt_process(FAR struct sam_emac_s *priv, int qid)
ninfo("Pause TO!\n");
}
#endif
-}
-/****************************************************************************
- * Function: sam_interrupt_work
- *
- * Description:
- * Perform interrupt related work from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() was called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void sam_interrupt_work(FAR void *arg)
-{
- FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
-
- /* Process pending Ethernet interrupts */
-
- state = net_lock();
- sam_interrupt_process(priv, EMAC_QUEUE_0);
- net_unlock(state);
+ net_unlock();
/* Re-enable Ethernet interrupts */
up_enable_irq(priv->attr->irq);
}
-#endif
/****************************************************************************
* Function: sam_emac_interrupt
@@ -2517,7 +2468,6 @@ static void sam_interrupt_work(FAR void *arg)
static int sam_emac_interrupt(struct sam_emac_s *priv)
{
-#ifdef CONFIG_NET_NOINTS
uint32_t tsr;
/* Disable further Ethernet interrupts. Because Ethernet interrupts are
@@ -2561,13 +2511,6 @@ static int sam_emac_interrupt(struct sam_emac_s *priv)
/* Schedule to perform the interrupt processing on the worker thread. */
work_queue(ETHWORK, &priv->work, sam_interrupt_work, priv, 0);
-
-#else
- /* Process the interrupt now */
-
- sam_interrupt_process(priv, EMAC_QUEUE_0);
-#endif
-
return OK;
}
@@ -2602,41 +2545,6 @@ static int sam_emac1_interrupt(int irq, void *context)
}
#endif
-/****************************************************************************
- * Function: sam_txtimeout_process
- *
- * Description:
- * Process a TX timeout. Called from the either the watchdog timer
- * expiration logic or from the worker thread, depending upon the
- * configuration. The timeout means that the last TX never completed.
- * Reset the hardware and start again.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Global interrupts are disabled by the watchdog logic.
- *
- ****************************************************************************/
-
-static inline void sam_txtimeout_process(FAR struct sam_emac_s *priv)
-{
- nerr("ERROR: Timeout!\n");
- NETDEV_TXTIMEOUTS(&priv->dev);
-
- /* Reset the hardware. Just take the interface down, then back up again. */
-
- sam_ifdown(&priv->dev);
- sam_ifup(&priv->dev);
-
- /* Then poll the network for new XMIT data */
-
- sam_dopoll(priv, EMAC_QUEUE_0);
-}
-
/****************************************************************************
* Function: sam_txtimeout_work
*
@@ -2654,19 +2562,25 @@ static inline void sam_txtimeout_process(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void sam_txtimeout_work(FAR void *arg)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
- /* Process pending Ethernet interrupts */
+ nerr("ERROR: Timeout!\n");
- state = net_lock();
- sam_txtimeout_process(priv);
- net_unlock(state);
+ net_lock();
+ NETDEV_TXTIMEOUTS(&priv->dev);
+
+ /* Reset the hardware. Just take the interface down, then back up again. */
+
+ sam_ifdown(&priv->dev);
+ sam_ifup(&priv->dev);
+
+ /* Then poll the network for new XMIT data */
+
+ sam_dopoll(priv, EMAC_QUEUE_0);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: sam_txtimeout_expiry
@@ -2691,7 +2605,6 @@ static void sam_txtimeout_expiry(int argc, uint32_t arg, ...)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Disable further Ethernet interrupts. This will prevent some race
* conditions with interrupt work. There is still a potential race
* condition with interrupt work that is already queued and in progress.
@@ -2708,48 +2621,6 @@ static void sam_txtimeout_expiry(int argc, uint32_t arg, ...)
/* Schedule to perform the TX timeout processing on the worker thread. */
work_queue(ETHWORK, &priv->work, sam_txtimeout_work, priv, 0);
-#else
- /* Process the timeout now */
-
- sam_txtimeout_process(priv);
-#endif
-}
-
-/****************************************************************************
- * Function: sam_poll_process
- *
- * Description:
- * Perform the periodic poll. This may be called either from watchdog
- * timer logic or from the worker thread, depending upon the configuration.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- *
- ****************************************************************************/
-
-static inline void sam_poll_process(FAR struct sam_emac_s *priv)
-{
- struct net_driver_s *dev = &priv->dev;
-
- /* Check if the there are any free TX descriptors. We cannot perform the
- * TX poll if we do not have buffering for another packet.
- */
-
- if (sam_txfree(priv, EMAC_QUEUE_0) > 0)
- {
- /* Update TCP timing states and poll the network for new XMIT data. */
-
- (void)devif_timer(dev, sam_txpoll);
- }
-
- /* Setup the watchdog poll timer again */
-
- (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
}
/****************************************************************************
@@ -2769,19 +2640,28 @@ static inline void sam_poll_process(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void sam_poll_work(FAR void *arg)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
+ struct net_driver_s *dev = &priv->dev;
- /* Perform the poll */
+ /* Check if the there are any free TX descriptors. We cannot perform the
+ * TX poll if we do not have buffering for another packet.
+ */
- state = net_lock();
- sam_poll_process(priv);
- net_unlock(state);
+ net_lock();
+ if (sam_txfree(priv, EMAC_QUEUE_0) > 0)
+ {
+ /* Update TCP timing states and poll the network for new XMIT data. */
+
+ (void)devif_timer(dev, sam_txpoll);
+ }
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: sam_poll_expiry
@@ -2805,7 +2685,6 @@ static void sam_poll_expiry(int argc, uint32_t arg, ...)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions.
*/
@@ -2824,12 +2703,6 @@ static void sam_poll_expiry(int argc, uint32_t arg, ...)
(void)wd_start(priv->txpoll, SAM_WDDELAY, sam_poll_expiry, 1, arg);
}
-
-#else
- /* Process the interrupt now */
-
- sam_poll_process(priv);
-#endif
}
/****************************************************************************
@@ -2967,37 +2840,6 @@ static int sam_ifdown(struct net_driver_s *dev)
return OK;
}
-/****************************************************************************
- * Function: sam_txavail_process
- *
- * Description:
- * Perform an out-of-cycle poll.
- *
- * Parameters:
- * dev - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called in normal user mode
- *
- ****************************************************************************/
-
-static inline void sam_txavail_process(FAR struct sam_emac_s *priv)
-{
- ninfo("ifup: %d\n", priv->ifup);
-
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
- {
- /* Poll the network for new XMIT data */
-
- sam_dopoll(priv, EMAC_QUEUE_0);
- }
-}
-
/****************************************************************************
* Function: sam_txavail_work
*
@@ -3015,19 +2857,24 @@ static inline void sam_txavail_process(FAR struct sam_emac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void sam_txavail_work(FAR void *arg)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)arg;
- net_lock_t state;
- /* Perform the poll */
+ ninfo("ifup: %d\n", priv->ifup);
- state = net_lock();
- sam_txavail_process(priv);
- net_unlock(state);
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->ifup)
+ {
+ /* Poll the network for new XMIT data */
+
+ sam_dopoll(priv, EMAC_QUEUE_0);
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: sam_txavail
@@ -3052,7 +2899,6 @@ static int sam_txavail(struct net_driver_s *dev)
{
FAR struct sam_emac_s *priv = (FAR struct sam_emac_s *)dev->d_private;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions and we will have to ignore the Tx
* availability action.
@@ -3065,21 +2911,6 @@ static int sam_txavail(struct net_driver_s *dev)
work_queue(ETHWORK, &priv->work, sam_txavail_work, priv, 0);
}
-#else
- irqstate_t flags;
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
- */
-
- flags = enter_critical_section();
-
- /* Perform the out-of-cycle poll now */
-
- sam_txavail_process(priv);
- leave_critical_section(flags);
-#endif
-
return OK;
}
@@ -5112,9 +4943,7 @@ int sam_emac_initialize(int intf)
{
struct sam_emac_s *priv;
const struct sam_emacattr_s *attr;
-#ifdef CONFIG_NET_MULTIBUFFER
uint8_t *pktbuf;
-#endif
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
uint8_t phytype;
#endif
@@ -5125,10 +4954,7 @@ int sam_emac_initialize(int intf)
{
priv = &g_emac0;
attr = &g_emac0_attr;
-
-#ifdef CONFIG_NET_MULTIBUFFER
pktbuf = g_pktbuf0;
-#endif
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
phytype = SAMV7_EMAC0_PHY_TYPE;
@@ -5141,10 +4967,7 @@ int sam_emac_initialize(int intf)
{
priv = &g_emac1;
attr = &g_emac1_attr;
-
-#ifdef CONFIG_NET_MULTIBUFFER
pktbuf = g_pktbuf1;
-#endif
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
phytype = SAMV7_EMAC1_PHY_TYPE;
@@ -5161,9 +4984,7 @@ int sam_emac_initialize(int intf)
memset(priv, 0, sizeof(struct sam_emac_s));
priv->attr = attr; /* Save the constant attributes */
-#ifdef CONFIG_NET_MULTIBUFFER
priv->dev.d_buf = pktbuf; /* Single packet buffer */
-#endif
priv->dev.d_ifup = sam_ifup; /* I/F up (new IP address) callback */
priv->dev.d_ifdown = sam_ifdown; /* I/F down callback */
priv->dev.d_txavail = sam_txavail; /* New TX data callback */
diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig
index 57165d8ab0f..b6c04586498 100644
--- a/arch/arm/src/stm32/Kconfig
+++ b/arch/arm/src/stm32/Kconfig
@@ -1580,6 +1580,10 @@ config STM32_STM32F446
select STM32_HAVE_UART5
select STM32_HAVE_USART6
select STM32_HAVE_TIM1
+ select STM32_HAVE_TIM2
+ select STM32_HAVE_TIM3
+ select STM32_HAVE_TIM4
+ select STM32_HAVE_TIM5
select STM32_HAVE_TIM6
select STM32_HAVE_TIM7
select STM32_HAVE_TIM8
@@ -1613,6 +1617,10 @@ config STM32_STM32F469
select STM32_HAVE_UART7
select STM32_HAVE_UART8
select STM32_HAVE_TIM1
+ select STM32_HAVE_TIM2
+ select STM32_HAVE_TIM3
+ select STM32_HAVE_TIM4
+ select STM32_HAVE_TIM5
select STM32_HAVE_TIM6
select STM32_HAVE_TIM7
select STM32_HAVE_TIM8
@@ -1632,6 +1640,9 @@ config STM32_STM32F469
select STM32_HAVE_SPI4
select STM32_HAVE_SPI5
select STM32_HAVE_SPI6
+ select STM32_HAVE_SAIPLL
+ select STM32_HAVE_I2SPLL
+
config STM32_DFU
bool "DFU bootloader"
diff --git a/arch/arm/src/stm32/chip/stm32_dac.h b/arch/arm/src/stm32/chip/stm32_dac.h
index 81a69b71e68..61332080eab 100644
--- a/arch/arm/src/stm32/chip/stm32_dac.h
+++ b/arch/arm/src/stm32/chip/stm32_dac.h
@@ -51,17 +51,17 @@
#define STM32_DAC_CR_OFFSET 0x0000 /* DAC control register */
#define STM32_DAC_SWTRIGR_OFFSET 0x0004 /* DAC software trigger register */
-#define STM32_DAC_DHR12R1_OFFSET 0x0008 /* DAC channel1 12-bit right-aligned data holding register */
-#define STM32_DAC_DHR12L1_OFFSET 0x000c /* DAC channel1 12-bit left aligned data holding register */
-#define STM32_DAC_DHR8R1_OFFSET 0x0010 /* DAC channel1 8-bit right aligned data holding register */
-#define STM32_DAC_DHR12R2_OFFSET 0x0014 /* DAC channel2 12-bit right aligned data holding register */
-#define STM32_DAC_DHR12L2_OFFSET 0x0018 /* DAC channel2 12-bit left aligned data holding register */
-#define STM32_DAC_DHR8R2_OFFSET 0x001c /* DAC channel2 8-bit right-aligned data holding register */
+#define STM32_DAC_DHR12R1_OFFSET 0x0008 /* DAC channel 1 12-bit right-aligned data holding register */
+#define STM32_DAC_DHR12L1_OFFSET 0x000c /* DAC channel 1 12-bit left aligned data holding register */
+#define STM32_DAC_DHR8R1_OFFSET 0x0010 /* DAC channel 1 8-bit right aligned data holding register */
+#define STM32_DAC_DHR12R2_OFFSET 0x0014 /* DAC channel 2 12-bit right aligned data holding register */
+#define STM32_DAC_DHR12L2_OFFSET 0x0018 /* DAC channel 2 12-bit left aligned data holding register */
+#define STM32_DAC_DHR8R2_OFFSET 0x001c /* DAC channel 2 8-bit right-aligned data holding register */
#define STM32_DAC_DHR12RD_OFFSET 0x0020 /* Dual DAC 12-bit right-aligned data holding register */
#define STM32_DAC_DHR12LD_OFFSET 0x0024 /* DUAL DAC 12-bit left aligned data holding register */
#define STM32_DAC_DHR8RD_OFFSET 0x0028 /* DUAL DAC 8-bit right aligned data holding register */
-#define STM32_DAC_DOR1_OFFSET 0x002c /* DAC channel1 data output register */
-#define STM32_DAC_DOR2_OFFSET 0x0030 /* DAC channel2 data output register */
+#define STM32_DAC_DOR1_OFFSET 0x002c /* DAC channel 1 data output register */
+#define STM32_DAC_DOR2_OFFSET 0x0030 /* DAC channel 2 data output register */
#define STM32_DAC_SR_OFFSET 0x0034 /* DAC status register */
/* Register Addresses ***************************************************************/
@@ -164,10 +164,10 @@
/* These definitions may be used with the full, 32-bit register */
-#define DAC_CR_EN1 (1 << 0) /* Bit 0: DAC channel1 enable */
-#define DAC_CR_BOFF1 (1 << 1) /* Bit 1: DAC channel1 output buffer disable */
-#define DAC_CR_TEN1 (1 << 2) /* Bit 2: DAC channel1 trigger enable */
-#define DAC_CR_TSEL1_SHIFT (3) /* Bits 3-5: DAC channel1 trigger selection */
+#define DAC_CR_EN1 (1 << 0) /* Bit 0: DAC channel 1 enable */
+#define DAC_CR_BOFF1 (1 << 1) /* Bit 1: DAC channel 1 output buffer disable */
+#define DAC_CR_TEN1 (1 << 2) /* Bit 2: DAC channel 1 trigger enable */
+#define DAC_CR_TSEL1_SHIFT (3) /* Bits 3-5: DAC channel 1 trigger selection */
#define DAC_CR_TSEL1_MASK (7 << DAC_CR_TSEL1_SHIFT)
# define DAC_CR_TSEL1_TIM6 (0 << DAC_CR_TSEL1_SHIFT) /* Timer 6 TRGO event */
# define DAC_CR_TSEL1_TIM8 (1 << DAC_CR_TSEL1_SHIFT) /* Timer 8 TRGO event */
@@ -177,12 +177,12 @@
# define DAC_CR_TSEL1_TIM4 (5 << DAC_CR_TSEL1_SHIFT) /* Timer 4 TRGO event */
# define DAC_CR_TSEL1_EXT9 (6 << DAC_CR_TSEL1_SHIFT) /* External line9 */
# define DAC_CR_TSEL1_SW (7 << DAC_CR_TSEL1_SHIFT) /* Software trigger */
-#define DAC_CR_WAVE1_SHIFT (6) /* Bits 6-7: DAC channel1 noise/triangle wave generation */enable
+#define DAC_CR_WAVE1_SHIFT (6) /* Bits 6-7: DAC channel 1 noise/triangle wave generation */enable
#define DAC_CR_WAVE1_MASK (3 << DAC_CR_WAVE1_SHIFT)
# define DAC_CR_WAVE1_DISABLED (0 << DAC_CR_WAVE1_SHIFT) /* Wave generation disabled */
# define DAC_CR_WAVE1_NOISE (1 << DAC_CR_WAVE1_SHIFT) /* Noise wave generation enabled */
# define DAC_CR_WAVE1_TRIANGLE (2 << DAC_CR_WAVE1_SHIFT) /* Triangle wave generation enabled */
-#define DAC_CR_MAMP1_SHIFT (8) /* Bits 8-11: DAC channel1 mask/amplitude selector */
+#define DAC_CR_MAMP1_SHIFT (8) /* Bits 8-11: DAC channel 1 mask/amplitude selector */
#define DAC_CR_MAMP1_MASK (15 << DAC_CR_MAMP1_SHIFT)
# define DAC_CR_MAMP1_AMP1 (0 << DAC_CR_MAMP1_SHIFT) /* Unmask bit0 of LFSR/triangle amplitude=1 */
# define DAC_CR_MAMP1_AMP3 (1 << DAC_CR_MAMP1_SHIFT) /* Unmask bits[1:0] of LFSR/triangle amplitude=3 */
@@ -196,13 +196,13 @@
# define DAC_CR_MAMP1_AMP1023 (9 << DAC_CR_MAMP1_SHIFT) /* Unmask bits[9:0] of LFSR/triangle amplitude=1023 */
# define DAC_CR_MAMP1_AMP2047 (10 << DAC_CR_MAMP1_SHIFT) /* Unmask bits[10:0] of LFSR/triangle amplitude=2047 */
# define DAC_CR_MAMP1_AMP4095 (11 << DAC_CR_MAMP1_SHIFT) /* Unmask bits[11:0] of LFSR/triangle amplitude=4095 */
-#define DAC_CR_DMAEN1 (1 << 12) /* Bit 12: DAC channel1 DMA enable */
-#define DAC_CR_DMAUDRIE1 (1 << 13) /* Bit 13: DAC channel1 DMA Underrun Interrupt enable */
+#define DAC_CR_DMAEN1 (1 << 12) /* Bit 12: DAC channel 1 DMA enable */
+#define DAC_CR_DMAUDRIE1 (1 << 13) /* Bit 13: DAC channel 1 DMA Underrun Interrupt enable */
-#define DAC_CR_EN2 (1 << 16) /* Bit 16: DAC channel2 enable */
-#define DAC_CR_BOFF2 (1 << 17) /* Bit 17: DAC channel2 output buffer disable */
-#define DAC_CR_TEN2 (1 << 18) /* Bit 18: DAC channel2 trigger enable */
-#define DAC_CR_TSEL2_SHIFT (19) /* Bits 19-21: DAC channel2 trigger selection */
+#define DAC_CR_EN2 (1 << 16) /* Bit 16: DAC channel 2 enable */
+#define DAC_CR_BOFF2 (1 << 17) /* Bit 17: DAC channel 2 output buffer disable */
+#define DAC_CR_TEN2 (1 << 18) /* Bit 18: DAC channel 2 trigger enable */
+#define DAC_CR_TSEL2_SHIFT (19) /* Bits 19-21: DAC channel 2 trigger selection */
#define DAC_CR_TSEL2_MASK (7 << DAC_CR_TSEL2_SHIFT)
# define DAC_CR_TSEL2_TIM6 (0 << DAC_CR_TSEL2_SHIFT) /* Timer 6 TRGO event */
# define DAC_CR_TSEL2_TIM8 (1 << DAC_CR_TSEL2_SHIFT) /* Timer 8 TRGO event */
@@ -212,12 +212,12 @@
# define DAC_CR_TSEL2_TIM4 (5 << DAC_CR_TSEL2_SHIFT) /* Timer 4 TRGO event */
# define DAC_CR_TSEL2_EXT9 (6 << DAC_CR_TSEL2_SHIFT) /* External line9 */
# define DAC_CR_TSEL2_SW (7 << DAC_CR_TSEL2_SHIFT) /* Software trigger */
-#define DAC_CR_WAVE2_SHIFT (22) /* Bit 22-23: DAC channel2 noise/triangle wave generation enable */
+#define DAC_CR_WAVE2_SHIFT (22) /* Bit 22-23: DAC channel 2 noise/triangle wave generation enable */
#define DAC_CR_WAVE2_MASK (3 << DAC_CR_WAVE2_SHIFT)
# define DAC_CR_WAVE2_DISABLED (0 << DAC_CR_WAVE2_SHIFT) /* Wave generation disabled */
# define DAC_CR_WAVE2_NOISE (1 << DAC_CR_WAVE2_SHIFT) /* Noise wave generation enabled */
# define DAC_CR_WAVE2_TRIANGLE (2 << DAC_CR_WAVE2_SHIFT) /* Triangle wave generation enabled */
-#define DAC_CR_MAMP2_SHIFT (24) /* Bit 24-27: DAC channel2 mask/amplitude selector */
+#define DAC_CR_MAMP2_SHIFT (24) /* Bit 24-27: DAC channel 2 mask/amplitude selector */
#define DAC_CR_MAMP2_MASK (15 << DAC_CR_MAMP2_SHIFT)
# define DAC_CR_MAMP2_AMP1 (0 << DAC_CR_MAMP2_SHIFT) /* Unmask bit0 of LFSR/triangle amplitude=1 */
# define DAC_CR_MAMP2_AMP3 (1 << DAC_CR_MAMP2_SHIFT) /* Unmask bits[1:0] of LFSR/triangle amplitude=3 */
@@ -231,24 +231,24 @@
# define DAC_CR_MAMP2_AMP1023 (9 << DAC_CR_MAMP2_SHIFT) /* Unmask bits[9:0] of LFSR/triangle amplitude=1023 */
# define DAC_CR_MAMP2_AMP2047 (10 << DAC_CR_MAMP2_SHIFT) /* Unmask bits[10:0] of LFSR/triangle amplitude=2047 */
# define DAC_CR_MAMP2_AMP4095 (11 << DAC_CR_MAMP2_SHIFT) /* Unmask bits[11:0] of LFSR/triangle amplitude=4095 */
-#define DAC_CR_DMAEN2 (1 << 28) /* Bit 28: DAC channel2 DMA enable */
-#define DAC_CR_DMAUDRIE2 (1 << 29) /* Bits 29: DAC channel2 DMA underrun interrupt enable */
+#define DAC_CR_DMAEN2 (1 << 28) /* Bit 28: DAC channel 2 DMA enable */
+#define DAC_CR_DMAUDRIE2 (1 << 29) /* Bits 29: DAC channel 2 DMA underrun interrupt enable */
/* DAC software trigger register */
#define DAC_SWTRIGR_SWTRIG(n) (1 << ((n)-1))
-#define DAC_SWTRIGR_SWTRIG1 (1 << 0) /* Bit 0: DAC channel1 software trigger */
-#define DAC_SWTRIGR_SWTRIG2 (1 << 1) /* Bit 1: DAC channel2 software trigger */
+#define DAC_SWTRIGR_SWTRIG1 (1 << 0) /* Bit 0: DAC channel 1 software trigger */
+#define DAC_SWTRIGR_SWTRIG2 (1 << 1) /* Bit 1: DAC channel 2 software trigger */
-/* DAC channel1/2 12-bit right-aligned data holding register */
+/* DAC channel 1/2 12-bit right-aligned data holding register */
#define DAC_DHR12R_MASK (0x0fff)
-/* DAC channel1/2 12-bit left aligned data holding register */
+/* DAC channel 1/2 12-bit left aligned data holding register */
#define DAC_DHR12L_MASK (0xfff0)
-/* DAC channel1/2 8-bit right aligned data holding register */
+/* DAC channel 1/2 8-bit right aligned data holding register */
#define DAC_DHR8R_MASK (0x00ff)
@@ -257,9 +257,9 @@
#define DAC_DHR12RD_DACC_SHIFT(n) (1 << (((n)-1) << 4))
#define DAC_DHR12RD_DACC_MASK(n) (0xfff << DAC_DHR12RD_DACC_SHIFT(n))
-#define DAC_DHR12RD_DACC1_SHIFT (0) /* Bits 0-11: DAC channel1 12-bit right-aligned data */
+#define DAC_DHR12RD_DACC1_SHIFT (0) /* Bits 0-11: DAC channel 1 12-bit right-aligned data */
#define DAC_DHR12RD_DACC1_MASK (0xfff << DAC_DHR12RD_DACC2_SHIFT)
-#define DAC_DHR12RD_DACC2_SHIFT (16) /* Bits 16-27: DAC channel2 12-bit right-aligned data */
+#define DAC_DHR12RD_DACC2_SHIFT (16) /* Bits 16-27: DAC channel 2 12-bit right-aligned data */
#define DAC_DHR12RD_DACC2_MASK (0xfff << DAC_DHR12RD_DACC2_SHIFT)
/* Dual DAC 12-bit left-aligned data holding register */
@@ -267,9 +267,9 @@
#define DAC_DHR12LD_DACC_SHIFT(n) ((1 << (((n)-1) << 4)) + 4)
#define DAC_DHR12LD_DACC_MASK(n) (0xfff << DAC_DHR12LD_DACC_SHIFT(n))
-#define DAC_DHR12LD_DACC1_SHIFT (4) /* Bits 4-15: DAC channel1 12-bit left-aligned data */
+#define DAC_DHR12LD_DACC1_SHIFT (4) /* Bits 4-15: DAC channel 1 12-bit left-aligned data */
#define DAC_DHR12LD_DACC1_MASK (0xfff << DAC_DHR12LD_DACC1_SHIFT)
-#define DAC_DHR12LD_DACC2_SHIFT (20) /* Bits 20-31: DAC channel2 12-bit left-aligned data */
+#define DAC_DHR12LD_DACC2_SHIFT (20) /* Bits 20-31: DAC channel 2 12-bit left-aligned data */
#define DAC_DHR12LD_DACC2_MASK (0xfff << DAC_DHR12LD_DACC2_SHIFT)
/* DUAL DAC 8-bit right aligned data holding register */
@@ -277,19 +277,19 @@
#define DAC_DHR8RD_DACC_SHIFT(n) (1 << (((n)-1) << 3))
#define DAC_DHR8RD_DACC_MASK(n) (0xff << DAC_DHR8RD_DACC_SHIFT(n))
-#define DAC_DHR8RD_DACC1_SHIFT (0) /* Bits 0-7: DAC channel1 8-bit right-aligned data */
+#define DAC_DHR8RD_DACC1_SHIFT (0) /* Bits 0-7: DAC channel 1 8-bit right-aligned data */
#define DAC_DHR8RD_DACC1_MASK (0xff << DAC_DHR8RD_DACC1_SHIFT)
-#define DAC_DHR8RD_DACC2_SHIFT (8) /* Bits 8-15: DAC channel2 8-bit right-aligned data */
+#define DAC_DHR8RD_DACC2_SHIFT (8) /* Bits 8-15: DAC channel 2 8-bit right-aligned data */
#define DAC_DHR8RD_DACC2_MASK (0xff << DAC_DHR8RD_DACC2_SHIFT)
-/* DAC channel1/2 data output register */
+/* DAC channel 1/2 data output register */
#define DAC_DOR_MASK (0x0fff)
/* DAC status register */
#define DAC_SR_DMAUDR(n) ((1 << (((n)-1) << 4)) + 13)
-#define DAC_SR_DMAUDR1 (1 << 13) /* Bit 13: DAC channel1 DMA underrun flag */
-#define DAC_SR_DMAUDR2 (1 << 29) /* Bit 29: DAC channel2 DMA underrun flag */
+#define DAC_SR_DMAUDR1 (1 << 13) /* Bit 13: DAC channel 1 DMA underrun flag */
+#define DAC_SR_DMAUDR2 (1 << 29) /* Bit 29: DAC channel 2 DMA underrun flag */
#endif /* __ARCH_ARM_SRC_STM32_CHIP_STM32_DAC_H */
diff --git a/arch/arm/src/stm32/chip/stm32_otgfs.h b/arch/arm/src/stm32/chip/stm32_otgfs.h
deleted file mode 100644
index 575214e6482..00000000000
--- a/arch/arm/src/stm32/chip/stm32_otgfs.h
+++ /dev/null
@@ -1,1018 +0,0 @@
-/****************************************************************************************************
- * arch/arm/src/stm32/chip/stm32_otgfs.h
- *
- * Copyright (C) 2012, 2014 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************************************/
-
-#ifndef __ARCH_ARM_SRC_STM32_CHIP_STM32_OTGFS_H
-#define __ARCH_ARM_SRC_STM32_CHIP_STM32_OTGFS_H
-
-/****************************************************************************************************
- * Included Files
- ****************************************************************************************************/
-
-#include
-#include "chip.h"
-
-/****************************************************************************************************
- * Pre-processor Definitions
- ****************************************************************************************************/
-/* General definitions */
-
-#define OTGFS_EPTYPE_CTRL (0) /* Control */
-#define OTGFS_EPTYPE_ISOC (1) /* Isochronous */
-#define OTGFS_EPTYPE_BULK (2) /* Bulk */
-#define OTGFS_EPTYPE_INTR (3) /* Interrupt */
-
-#define OTGFS_PID_DATA0 (0)
-#define OTGFS_PID_DATA2 (1)
-#define OTGFS_PID_DATA1 (2)
-#define OTGFS_PID_MDATA (3) /* Non-control */
-#define OTGFS_PID_SETUP (3) /* Control */
-
-/* Register Offsets *********************************************************************************/
-/* Core global control and status registers */
-
-#define STM32_OTGFS_GOTGCTL_OFFSET 0x0000 /* Control and status register */
-#define STM32_OTGFS_GOTGINT_OFFSET 0x0004 /* Interrupt register */
-#define STM32_OTGFS_GAHBCFG_OFFSET 0x0008 /* AHB configuration register */
-#define STM32_OTGFS_GUSBCFG_OFFSET 0x000c /* USB configuration register */
-#define STM32_OTGFS_GRSTCTL_OFFSET 0x0010 /* Reset register */
-#define STM32_OTGFS_GINTSTS_OFFSET 0x0014 /* Core interrupt register */
-#define STM32_OTGFS_GINTMSK_OFFSET 0x0018 /* Interrupt mask register */
-#define STM32_OTGFS_GRXSTSR_OFFSET 0x001c /* Receive status debug read/OTG status read register */
-#define STM32_OTGFS_GRXSTSP_OFFSET 0x0020 /* Receive status debug read/OTG status pop register */
-#define STM32_OTGFS_GRXFSIZ_OFFSET 0x0024 /* Receive FIFO size register */
-#define STM32_OTGFS_HNPTXFSIZ_OFFSET 0x0028 /* Host non-periodic transmit FIFO size register */
-#define STM32_OTGFS_DIEPTXF0_OFFSET 0x0028 /* Endpoint 0 Transmit FIFO size */
-#define STM32_OTGFS_HNPTXSTS_OFFSET 0x002c /* Non-periodic transmit FIFO/queue status register */
-#define STM32_OTGFS_GCCFG_OFFSET 0x0038 /* General core configuration register */
-#define STM32_OTGFS_CID_OFFSET 0x003c /* Core ID register */
-#define STM32_OTGFS_HPTXFSIZ_OFFSET 0x0100 /* Host periodic transmit FIFO size register */
-
-#define STM32_OTGFS_DIEPTXF_OFFSET(n) (104+(((n)-1) << 2))
-#define STM32_OTGFS_DIEPTXF1_OFFSET 0x0104 /* Device IN endpoint transmit FIFO1 size register */
-#define STM32_OTGFS_DIEPTXF2_OFFSET 0x0108 /* Device IN endpoint transmit FIFO2 size register */
-#define STM32_OTGFS_DIEPTXF3_OFFSET 0x010c /* Device IN endpoint transmit FIFO3 size register */
-
-/* Host-mode control and status registers */
-
-#define STM32_OTGFS_HCFG_OFFSET 0x0400 /* Host configuration register */
-#define STM32_OTGFS_HFIR_OFFSET 0x0404 /* Host frame interval register */
-#define STM32_OTGFS_HFNUM_OFFSET 0x0408 /* Host frame number/frame time remaining register */
-#define STM32_OTGFS_HPTXSTS_OFFSET 0x0410 /* Host periodic transmit FIFO/queue status register */
-#define STM32_OTGFS_HAINT_OFFSET 0x0414 /* Host all channels interrupt register */
-#define STM32_OTGFS_HAINTMSK_OFFSET 0x0418 /* Host all channels interrupt mask register */
-#define STM32_OTGFS_HPRT_OFFSET 0x0440 /* Host port control and status register */
-
-#define STM32_OTGFS_CHAN_OFFSET(n) (0x500 + ((n) << 5)
-#define STM32_OTGFS_HCCHAR_CHOFFSET 0x0000 /* Host channel characteristics register */
-#define STM32_OTGFS_HCINT_CHOFFSET 0x0008 /* Host channel interrupt register */
-#define STM32_OTGFS_HCINTMSK_CHOFFSET 0x000c /* Host channel interrupt mask register */
-#define STM32_OTGFS_HCTSIZ_CHOFFSET 0x0010 /* Host channel interrupt register */
-
-#define STM32_OTGFS_HCCHAR_OFFSET(n) (0x500 + ((n) << 5))
-#define STM32_OTGFS_HCCHAR0_OFFSET 0x0500 /* Host channel-0 characteristics register */
-#define STM32_OTGFS_HCCHAR1_OFFSET 0x0520 /* Host channel-1 characteristics register */
-#define STM32_OTGFS_HCCHAR2_OFFSET 0x0540 /* Host channel-2 characteristics register */
-#define STM32_OTGFS_HCCHAR3_OFFSET 0x0560 /* Host channel-3 characteristics register */
-#define STM32_OTGFS_HCCHAR4_OFFSET 0x0580 /* Host channel-4 characteristics register */
-#define STM32_OTGFS_HCCHAR5_OFFSET 0x05a0 /* Host channel-5 characteristics register */
-#define STM32_OTGFS_HCCHAR6_OFFSET 0x05c0 /* Host channel-6 characteristics register */
-#define STM32_OTGFS_HCCHAR7_OFFSET 0x05e0 /* Host channel-7 characteristics register */
-
-#define STM32_OTGFS_HCINT_OFFSET(n) (0x508 + ((n) << 5))
-#define STM32_OTGFS_HCINT0_OFFSET 0x0508 /* Host channel-0 interrupt register */
-#define STM32_OTGFS_HCINT1_OFFSET 0x0528 /* Host channel-1 interrupt register */
-#define STM32_OTGFS_HCINT2_OFFSET 0x0548 /* Host channel-2 interrupt register */
-#define STM32_OTGFS_HCINT3_OFFSET 0x0568 /* Host channel-3 interrupt register */
-#define STM32_OTGFS_HCINT4_OFFSET 0x0588 /* Host channel-4 interrupt register */
-#define STM32_OTGFS_HCINT5_OFFSET 0x05a8 /* Host channel-5 interrupt register */
-#define STM32_OTGFS_HCINT6_OFFSET 0x05c8 /* Host channel-6 interrupt register */
-#define STM32_OTGFS_HCINT7_OFFSET 0x05e8 /* Host channel-7 interrupt register */
-
-#define STM32_OTGFS_HCINTMSK_OFFSET(n) (0x50c + ((n) << 5))
-#define STM32_OTGFS_HCINTMSK0_OFFSET 0x050c /* Host channel-0 interrupt mask register */
-#define STM32_OTGFS_HCINTMSK1_OFFSET 0x052c /* Host channel-1 interrupt mask register */
-#define STM32_OTGFS_HCINTMSK2_OFFSET 0x054c /* Host channel-2 interrupt mask register */
-#define STM32_OTGFS_HCINTMSK3_OFFSET 0x056c /* Host channel-3 interrupt mask register */
-#define STM32_OTGFS_HCINTMSK4_OFFSET 0x058c /* Host channel-4 interrupt mask register */
-#define STM32_OTGFS_HCINTMSK5_OFFSET 0x05ac /* Host channel-5 interrupt mask register */
-#define STM32_OTGFS_HCINTMSK6_OFFSET 0x05cc /* Host channel-6 interrupt mask register */
-#define STM32_OTGFS_HCINTMSK7_OFFSET 0x05ec /* Host channel-7 interrupt mask register */
-
-#define STM32_OTGFS_HCTSIZ_OFFSET(n) (0x510 + ((n) << 5))
-#define STM32_OTGFS_HCTSIZ0_OFFSET 0x0510 /* Host channel-0 interrupt register */
-#define STM32_OTGFS_HCTSIZ1_OFFSET 0x0530 /* Host channel-1 interrupt register */
-#define STM32_OTGFS_HCTSIZ2_OFFSET 0x0550 /* Host channel-2 interrupt register */
-#define STM32_OTGFS_HCTSIZ3_OFFSET 0x0570 /* Host channel-3 interrupt register */
-#define STM32_OTGFS_HCTSIZ4_OFFSET 0x0590 /* Host channel-4 interrupt register */
-#define STM32_OTGFS_HCTSIZ5_OFFSET 0x05b0 /* Host channel-5 interrupt register */
-#define STM32_OTGFS_HCTSIZ6_OFFSET 0x05d0 /* Host channel-6 interrupt register */
-#define STM32_OTGFS_HCTSIZ7_OFFSET 0x05f0 /* Host channel-7 interrupt register */
-
-/* Device-mode control and status registers */
-
-#define STM32_OTGFS_DCFG_OFFSET 0x0800 /* Device configuration register */
-#define STM32_OTGFS_DCTL_OFFSET 0x0804 /* Device control register */
-#define STM32_OTGFS_DSTS_OFFSET 0x0808 /* Device status register */
-#define STM32_OTGFS_DIEPMSK_OFFSET 0x0810 /* Device IN endpoint common interrupt mask register */
-#define STM32_OTGFS_DOEPMSK_OFFSET 0x0814 /* Device OUT endpoint common interrupt mask register */
-#define STM32_OTGFS_DAINT_OFFSET 0x0818 /* Device all endpoints interrupt register */
-#define STM32_OTGFS_DAINTMSK_OFFSET 0x081c /* All endpoints interrupt mask register */
-#define STM32_OTGFS_DVBUSDIS_OFFSET 0x0828 /* Device VBUS discharge time register */
-#define STM32_OTGFS_DVBUSPULSE_OFFSET 0x082c /* Device VBUS pulsing time register */
-#define STM32_OTGFS_DIEPEMPMSK_OFFSET 0x0834 /* Device IN endpoint FIFO empty interrupt mask register */
-
-#define STM32_OTGFS_DIEP_OFFSET(n) (0x0900 + ((n) << 5))
-#define STM32_OTGFS_DIEPCTL_EPOFFSET 0x0000 /* Device endpoint control register */
-#define STM32_OTGFS_DIEPINT_EPOFFSET 0x0008 /* Device endpoint interrupt register */
-#define STM32_OTGFS_DIEPTSIZ_EPOFFSET 0x0010 /* Device IN endpoint transfer size register */
-#define STM32_OTGFS_DTXFSTS_EPOFFSET 0x0018 /* Device IN endpoint transmit FIFO status register */
-
-#define STM32_OTGFS_DIEPCTL_OFFSET(n) (0x0900 + ((n) << 5))
-#define STM32_OTGFS_DIEPCTL0_OFFSET 0x0900 /* Device control IN endpoint 0 control register */
-#define STM32_OTGFS_DIEPCTL1_OFFSET 0x0920 /* Device control IN endpoint 2 control register */
-#define STM32_OTGFS_DIEPCTL2_OFFSET 0x0940 /* Device control IN endpoint 3 control register */
-#define STM32_OTGFS_DIEPCTL3_OFFSET 0x0960 /* Device control IN endpoint 4 control register */
-
-#define STM32_OTGFS_DIEPINT_OFFSET(n) (0x0908 + ((n) << 5))
-#define STM32_OTGFS_DIEPINT0_OFFSET 0x0908 /* Device endpoint-0 interrupt register */
-#define STM32_OTGFS_DIEPINT1_OFFSET 0x0928 /* Device endpoint-1 interrupt register */
-#define STM32_OTGFS_DIEPINT2_OFFSET 0x0948 /* Device endpoint-2 interrupt register */
-#define STM32_OTGFS_DIEPINT3_OFFSET 0x0968 /* Device endpoint-3 interrupt register */
-
-#define STM32_OTGFS_DIEPTSIZ_OFFSET(n) (0x910 + ((n) << 5))
-#define STM32_OTGFS_DIEPTSIZ0_OFFSET 0x0910 /* Device IN endpoint 0 transfer size register */
-#define STM32_OTGFS_DIEPTSIZ1_OFFSET 0x0930 /* Device IN endpoint 1 transfer size register */
-#define STM32_OTGFS_DIEPTSIZ2_OFFSET 0x0950 /* Device IN endpoint 2 transfer size register */
-#define STM32_OTGFS_DIEPTSIZ3_OFFSET 0x0970 /* Device IN endpoint 3 transfer size register */
-
-#define STM32_OTGFS_DTXFSTS_OFFSET(n) (0x0918 + ((n) << 5))
-#define STM32_OTGFS_DTXFSTS0_OFFSET 0x0918 /* Device OUT endpoint-0 TxFIFO status register */
-#define STM32_OTGFS_DTXFSTS1_OFFSET 0x0938 /* Device OUT endpoint-1 TxFIFO status register */
-#define STM32_OTGFS_DTXFSTS2_OFFSET 0x0958 /* Device OUT endpoint-2 TxFIFO status register */
-#define STM32_OTGFS_DTXFSTS3_OFFSET 0x0978 /* Device OUT endpoint-3 TxFIFO status register */
-
-#define STM32_OTGFS_DOEP_OFFSET(n) (0x0b00 + ((n) << 5))
-#define STM32_OTGFS_DOEPCTL_EPOFFSET 0x0000 /* Device control OUT endpoint 0 control register */
-#define STM32_OTGFS_DOEPINT_EPOFFSET 0x0008 /* Device endpoint-x interrupt register */
-
-#define STM32_OTGFS_DOEPCTL_OFFSET(n) (0x0b00 + ((n) << 5))
-#define STM32_OTGFS_DOEPCTL0_OFFSET 0x00b00 /* Device OUT endpoint 0 control register */
-#define STM32_OTGFS_DOEPCTL1_OFFSET 0x00b20 /* Device OUT endpoint 1 control register */
-#define STM32_OTGFS_DOEPCTL2_OFFSET 0x00b40 /* Device OUT endpoint 2 control register */
-#define STM32_OTGFS_DOEPCTL3_OFFSET 0x00b60 /* Device OUT endpoint 3 control register */
-
-#define STM32_OTGFS_DOEPINT_OFFSET(n) (0x0b08 + ((n) << 5))
-#define STM32_OTGFS_DOEPINT0_OFFSET 0x00b08 /* Device endpoint-0 interrupt register */
-#define STM32_OTGFS_DOEPINT1_OFFSET 0x00b28 /* Device endpoint-1 interrupt register */
-#define STM32_OTGFS_DOEPINT2_OFFSET 0x00b48 /* Device endpoint-2 interrupt register */
-#define STM32_OTGFS_DOEPINT3_OFFSET 0x00b68 /* Device endpoint-3 interrupt register */
-
-#define STM32_OTGFS_DOEPTSIZ_OFFSET(n) (0x0b10 + ((n) << 5))
-#define STM32_OTGFS_DOEPTSIZ0_OFFSET 0x00b10 /* Device OUT endpoint-0 transfer size register */
-#define STM32_OTGFS_DOEPTSIZ1_OFFSET 0x00b30 /* Device OUT endpoint-1 transfer size register */
-#define STM32_OTGFS_DOEPTSIZ2_OFFSET 0x00b50 /* Device OUT endpoint-2 transfer size register */
-#define STM32_OTGFS_DOEPTSIZ3_OFFSET 0x00b70 /* Device OUT endpoint-3 transfer size register */
-
-/* Power and clock gating registers */
-
-#define STM32_OTGFS_PCGCCTL_OFFSET 0x0e00 /* Power and clock gating control register */
-
-/* Data FIFO (DFIFO) access registers */
-
-#define STM32_OTGFS_DFIFO_DEP_OFFSET(n) (0x1000 + ((n) << 12))
-#define STM32_OTGFS_DFIFO_HCH_OFFSET(n) (0x1000 + ((n) << 12))
-
-#define STM32_OTGFS_DFIFO_DEP0_OFFSET 0x1000 /* 0x1000-0x1ffc Device IN/OUT Endpoint 0 DFIFO Write/Read Access */
-#define STM32_OTGFS_DFIFO_HCH0_OFFSET 0x1000 /* 0x1000-0x1ffc Host OUT/IN Channel 0 DFIFO Read/Write Access */
-
-#define STM32_OTGFS_DFIFO_DEP1_OFFSET 0x2000 /* 0x2000-0x2ffc Device IN/OUT Endpoint 1 DFIFO Write/Read Access */
-#define STM32_OTGFS_DFIFO_HCH1_OFFSET 0x2000 /* 0x2000-0x2ffc Host OUT/IN Channel 1 DFIFO Read/Write Access */
-
-#define STM32_OTGFS_DFIFO_DEP2_OFFSET 0x3000 /* 0x3000-0x3ffc Device IN/OUT Endpoint 2 DFIFO Write/Read Access */
-#define STM32_OTGFS_DFIFO_HCH2_OFFSET 0x3000 /* 0x3000-0x3ffc Host OUT/IN Channel 2 DFIFO Read/Write Access */
-
-#define STM32_OTGFS_DFIFO_DEP3_OFFSET 0x4000 /* 0x4000-0x4ffc Device IN/OUT Endpoint 3 DFIFO Write/Read Access */
-#define STM32_OTGFS_DFIFO_HCH3_OFFSET 0x4000 /* 0x4000-0x4ffc Host OUT/IN Channel 3 DFIFO Read/Write Access */
-
-/* Register Addresses *******************************************************************************/
-
-#define STM32_OTGFS_GOTGCTL (STM32_OTGFS_BASE+STM32_OTGFS_GOTGCTL_OFFSET)
-#define STM32_OTGFS_GOTGINT (STM32_OTGFS_BASE+STM32_OTGFS_GOTGINT_OFFSET)
-#define STM32_OTGFS_GAHBCFG (STM32_OTGFS_BASE+STM32_OTGFS_GAHBCFG_OFFSET)
-#define STM32_OTGFS_GUSBCFG (STM32_OTGFS_BASE+STM32_OTGFS_GUSBCFG_OFFSET)
-#define STM32_OTGFS_GRSTCTL (STM32_OTGFS_BASE+STM32_OTGFS_GRSTCTL_OFFSET)
-#define STM32_OTGFS_GINTSTS (STM32_OTGFS_BASE+STM32_OTGFS_GINTSTS_OFFSET)
-#define STM32_OTGFS_GINTMSK (STM32_OTGFS_BASE+STM32_OTGFS_GINTMSK_OFFSET)
-#define STM32_OTGFS_GRXSTSR (STM32_OTGFS_BASE+STM32_OTGFS_GRXSTSR_OFFSET)
-#define STM32_OTGFS_GRXSTSP (STM32_OTGFS_BASE+STM32_OTGFS_GRXSTSP_OFFSET)
-#define STM32_OTGFS_GRXFSIZ (STM32_OTGFS_BASE+STM32_OTGFS_GRXFSIZ_OFFSET)
-#define STM32_OTGFS_HNPTXFSIZ (STM32_OTGFS_BASE+STM32_OTGFS_HNPTXFSIZ_OFFSET)
-#define STM32_OTGFS_DIEPTXF0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF0_OFFSET)
-#define STM32_OTGFS_HNPTXSTS (STM32_OTGFS_BASE+STM32_OTGFS_HNPTXSTS_OFFSET)
-#define STM32_OTGFS_GCCFG (STM32_OTGFS_BASE+STM32_OTGFS_GCCFG_OFFSET)
-#define STM32_OTGFS_CID (STM32_OTGFS_BASE+STM32_OTGFS_CID_OFFSET)
-#define STM32_OTGFS_HPTXFSIZ (STM32_OTGFS_BASE+STM32_OTGFS_HPTXFSIZ_OFFSET)
-
-#define STM32_OTGFS_DIEPTXF(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF_OFFSET(n))
-#define STM32_OTGFS_DIEPTXF1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF1_OFFSET)
-#define STM32_OTGFS_DIEPTXF2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF2_OFFSET)
-#define STM32_OTGFS_DIEPTXF3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTXF3_OFFSET)
-
-/* Host-mode control and status registers */
-
-#define STM32_OTGFS_HCFG (STM32_OTGFS_BASE+STM32_OTGFS_HCFG_OFFSET)
-#define STM32_OTGFS_HFIR (STM32_OTGFS_BASE+STM32_OTGFS_HFIR_OFFSET)
-#define STM32_OTGFS_HFNUM (STM32_OTGFS_BASE+STM32_OTGFS_HFNUM_OFFSET)
-#define STM32_OTGFS_HPTXSTS (STM32_OTGFS_BASE+STM32_OTGFS_HPTXSTS_OFFSET)
-#define STM32_OTGFS_HAINT (STM32_OTGFS_BASE+STM32_OTGFS_HAINT_OFFSET)
-#define STM32_OTGFS_HAINTMSK (STM32_OTGFS_BASE+STM32_OTGFS_HAINTMSK_OFFSET)
-#define STM32_OTGFS_HPRT (STM32_OTGFS_BASE+STM32_OTGFS_HPRT_OFFSET)
-
-#define STM32_OTGFS_CHAN(n) (STM32_OTGFS_BASE+STM32_OTGFS_CHAN_OFFSET(n))
-
-#define STM32_OTGFS_HCCHAR(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR_OFFSET(n))
-#define STM32_OTGFS_HCCHAR0 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR0_OFFSET)
-#define STM32_OTGFS_HCCHAR1 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR1_OFFSET)
-#define STM32_OTGFS_HCCHAR2 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR2_OFFSET)
-#define STM32_OTGFS_HCCHAR3 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR3_OFFSET)
-#define STM32_OTGFS_HCCHAR4 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR4_OFFSET)
-#define STM32_OTGFS_HCCHAR5 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR5_OFFSET)
-#define STM32_OTGFS_HCCHAR6 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR6_OFFSET)
-#define STM32_OTGFS_HCCHAR7 (STM32_OTGFS_BASE+STM32_OTGFS_HCCHAR7_OFFSET)
-
-#define STM32_OTGFS_HCINT(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCINT_OFFSET(n))
-#define STM32_OTGFS_HCINT0 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT0_OFFSET)
-#define STM32_OTGFS_HCINT1 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT1_OFFSET)
-#define STM32_OTGFS_HCINT2 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT2_OFFSET)
-#define STM32_OTGFS_HCINT3 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT3_OFFSET)
-#define STM32_OTGFS_HCINT4 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT4_OFFSET)
-#define STM32_OTGFS_HCINT5 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT5_OFFSET)
-#define STM32_OTGFS_HCINT6 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT6_OFFSET)
-#define STM32_OTGFS_HCINT7 (STM32_OTGFS_BASE+STM32_OTGFS_HCINT7_OFFSET)
-
-#define STM32_OTGFS_HCINTMSK(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK_OFFSET(n))
-#define STM32_OTGFS_HCINTMSK0 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK0_OFFSET)
-#define STM32_OTGFS_HCINTMSK1 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK1_OFFSET)
-#define STM32_OTGFS_HCINTMSK2 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK2_OFFSET)
-#define STM32_OTGFS_HCINTMSK3 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK3_OFFSET)
-#define STM32_OTGFS_HCINTMSK4 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK4_OFFSET)
-#define STM32_OTGFS_HCINTMSK5 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK5_OFFSET)
-#define STM32_OTGFS_HCINTMSK6 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK6_OFFSET)
-#define STM32_OTGFS_HCINTMSK7 (STM32_OTGFS_BASE+STM32_OTGFS_HCINTMSK7_OFFSET)_
-
-#define STM32_OTGFS_HCTSIZ(n) (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ_OFFSET(n))
-#define STM32_OTGFS_HCTSIZ0 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ0_OFFSET)
-#define STM32_OTGFS_HCTSIZ1 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ1_OFFSET)
-#define STM32_OTGFS_HCTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ2_OFFSET)
-#define STM32_OTGFS_HCTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ3_OFFSET)
-#define STM32_OTGFS_HCTSIZ4 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ4_OFFSET)
-#define STM32_OTGFS_HCTSIZ5 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ5_OFFSET)
-#define STM32_OTGFS_HCTSIZ6 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ6_OFFSET)
-#define STM32_OTGFS_HCTSIZ7 (STM32_OTGFS_BASE+STM32_OTGFS_HCTSIZ7_OFFSET)
-
-/* Device-mode control and status registers */
-
-#define STM32_OTGFS_DCFG (STM32_OTGFS_BASE+STM32_OTGFS_DCFG_OFFSET)
-#define STM32_OTGFS_DCTL (STM32_OTGFS_BASE+STM32_OTGFS_DCTL_OFFSET)
-#define STM32_OTGFS_DSTS (STM32_OTGFS_BASE+STM32_OTGFS_DSTS_OFFSET)
-#define STM32_OTGFS_DIEPMSK (STM32_OTGFS_BASE+STM32_OTGFS_DIEPMSK_OFFSET)
-#define STM32_OTGFS_DOEPMSK (STM32_OTGFS_BASE+STM32_OTGFS_DOEPMSK_OFFSET)
-#define STM32_OTGFS_DAINT (STM32_OTGFS_BASE+STM32_OTGFS_DAINT_OFFSET)
-#define STM32_OTGFS_DAINTMSK (STM32_OTGFS_BASE+STM32_OTGFS_DAINTMSK_OFFSET)
-#define STM32_OTGFS_DVBUSDIS (STM32_OTGFS_BASE+STM32_OTGFS_DVBUSDIS_OFFSET)
-#define STM32_OTGFS_DVBUSPULSE (STM32_OTGFS_BASE+STM32_OTGFS_DVBUSPULSE_OFFSET)
-#define STM32_OTGFS_DIEPEMPMSK (STM32_OTGFS_BASE+STM32_OTGFS_DIEPEMPMSK_OFFSET)
-
-#define STM32_OTGFS_DIEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEP_OFFSET(n))
-
-#define STM32_OTGFS_DIEPCTL(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL_OFFSET(n))
-#define STM32_OTGFS_DIEPCTL0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL0_OFFSET)
-#define STM32_OTGFS_DIEPCTL1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL1_OFFSET)
-#define STM32_OTGFS_DIEPCTL2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL2_OFFSET)
-#define STM32_OTGFS_DIEPCTL3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPCTL3_OFFSET)
-
-#define STM32_OTGFS_DIEPINT(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT_OFFSET(n))
-#define STM32_OTGFS_DIEPINT0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT0_OFFSET)
-#define STM32_OTGFS_DIEPINT1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT1_OFFSET)
-#define STM32_OTGFS_DIEPINT2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT2_OFFSET)
-#define STM32_OTGFS_DIEPINT3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPINT3_OFFSET)
-
-#define STM32_OTGFS_DIEPTSIZ(n) (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ_OFFSET(n))
-#define STM32_OTGFS_DIEPTSIZ0 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ0_OFFSET)
-#define STM32_OTGFS_DIEPTSIZ1 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ1_OFFSET)
-#define STM32_OTGFS_DIEPTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ2_OFFSET)
-#define STM32_OTGFS_DIEPTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_DIEPTSIZ3_OFFSET)
-
-#define STM32_OTGFS_DTXFSTS(n) (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS_OFFSET(n))
-#define STM32_OTGFS_DTXFSTS0 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS0_OFFSET)
-#define STM32_OTGFS_DTXFSTS1 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS1_OFFSET)
-#define STM32_OTGFS_DTXFSTS2 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS2_OFFSET)
-#define STM32_OTGFS_DTXFSTS3 (STM32_OTGFS_BASE+STM32_OTGFS_DTXFSTS3_OFFSET)
-
-#define STM32_OTGFS_DOEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEP_OFFSET(n))
-
-#define STM32_OTGFS_DOEPCTL(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL_OFFSET(n))
-#define STM32_OTGFS_DOEPCTL0 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL0_OFFSET)
-#define STM32_OTGFS_DOEPCTL1 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL1_OFFSET)
-#define STM32_OTGFS_DOEPCTL2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL2_OFFSET)
-#define STM32_OTGFS_DOEPCTL3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPCTL3_OFFSET)
-
-#define STM32_OTGFS_DOEPINT(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT_OFFSET(n))
-#define STM32_OTGFS_DOEPINT0 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT0_OFFSET)
-#define STM32_OTGFS_DOEPINT1 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT1_OFFSET)
-#define STM32_OTGFS_DOEPINT2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT2_OFFSET)
-#define STM32_OTGFS_DOEPINT3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPINT3_OFFSET)
-
-#define STM32_OTGFS_DOEPTSIZ(n) (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ_OFFSET(n))
-#define STM32_OTGFS_DOEPTSIZ0 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ0_OFFSET)
-#define STM32_OTGFS_DOEPTSIZ1 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ1_OFFSET)
-#define STM32_OTGFS_DOEPTSIZ2 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ2_OFFSET)
-#define STM32_OTGFS_DOEPTSIZ3 (STM32_OTGFS_BASE+STM32_OTGFS_DOEPTSIZ3_OFFSET)
-
-/* Power and clock gating registers */
-
-#define STM32_OTGFS_PCGCCTL (STM32_OTGFS_BASE+STM32_OTGFS_PCGCCTL_OFFSET)
-
-/* Data FIFO (DFIFO) access registers */
-
-#define STM32_OTGFS_DFIFO_DEP(n) (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP_OFFSET(n))
-#define STM32_OTGFS_DFIFO_HCH(n) (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH_OFFSET(n))
-
-#define STM32_OTGFS_DFIFO_DEP0 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP0_OFFSET)
-#define STM32_OTGFS_DFIFO_HCH0 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH0_OFFSET)
-
-#define STM32_OTGFS_DFIFO_DEP1 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP1_OFFSET)
-#define STM32_OTGFS_DFIFO_HCH1 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH1_OFFSET)
-
-#define STM32_OTGFS_DFIFO_DEP2 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP2_OFFSET)
-#define STM32_OTGFS_DFIFO_HCH2 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH2_OFFSET)
-
-#define STM32_OTGFS_DFIFO_DEP3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_DEP3_OFFSET)
-#define STM32_OTGFS_DFIFO_HCH3 (STM32_OTGFS_BASE+STM32_OTGFS_DFIFO_HCH3_OFFSET)
-
-/* Register Bitfield Definitions ********************************************************************/
-/* Core global control and status registers */
-
-/* Control and status register */
-
-#define OTGFS_GOTGCTL_SRQSCS (1 << 0) /* Bit 0: Session request success */
-#define OTGFS_GOTGCTL_SRQ (1 << 1) /* Bit 1: Session request */
- /* Bits 2-72 Reserved, must be kept at reset value */
-#define OTGFS_GOTGCTL_HNGSCS (1 << 8) /* Bit 8: Host negotiation success */
-#define OTGFS_GOTGCTL_HNPRQ (1 << 9) /* Bit 9: HNP request */
-#define OTGFS_GOTGCTL_HSHNPEN (1 << 10) /* Bit 10: host set HNP enable */
-#define OTGFS_GOTGCTL_DHNPEN (1 << 11) /* Bit 11: Device HNP enabled */
- /* Bits 12-15: Reserved, must be kept at reset value */
-#define OTGFS_GOTGCTL_CIDSTS (1 << 16) /* Bit 16: Connector ID status */
-#define OTGFS_GOTGCTL_DBCT (1 << 17) /* Bit 17: Long/short debounce time */
-#define OTGFS_GOTGCTL_ASVLD (1 << 18) /* Bit 18: A-session valid */
-#define OTGFS_GOTGCTL_BSVLD (1 << 19) /* Bit 19: B-session valid */
- /* Bits 20-31: Reserved, must be kept at reset value */
-/* Interrupt register */
- /* Bits 1:0 Reserved, must be kept at reset value */
-#define OTGFS_GOTGINT_SEDET (1 << 2) /* Bit 2: Session end detected */
- /* Bits 3-7: Reserved, must be kept at reset value */
-#define OTGFS_GOTGINT_SRSSCHG (1 << 8) /* Bit 8: Session request success status change */
-#define OTGFS_GOTGINT_HNSSCHG (1 << 9) /* Bit 9: Host negotiation success status change */
- /* Bits 16:10 Reserved, must be kept at reset value */
-#define OTGFS_GOTGINT_HNGDET (1 << 17) /* Bit 17: Host negotiation detected */
-#define OTGFS_GOTGINT_ADTOCHG (1 << 18) /* Bit 18: A-device timeout change */
-#define OTGFS_GOTGINT_DBCDNE (1 << 19) /* Bit 19: Debounce done */
- /* Bits 2-31: Reserved, must be kept at reset value */
-
-/* AHB configuration register */
-
-#define OTGFS_GAHBCFG_GINTMSK (1 << 0) /* Bit 0: Global interrupt mask */
- /* Bits 1-6: Reserved, must be kept at reset value */
-#define OTGFS_GAHBCFG_TXFELVL (1 << 7) /* Bit 7: TxFIFO empty level */
-#define OTGFS_GAHBCFG_PTXFELVL (1 << 8) /* Bit 8: Periodic TxFIFO empty level */
- /* Bits 20-31: Reserved, must be kept at reset value */
-/* USB configuration register */
-
-#define OTGFS_GUSBCFG_TOCAL_SHIFT (0) /* Bits 0-2: FS timeout calibration */
-#define OTGFS_GUSBCFG_TOCAL_MASK (7 << OTGFS_GUSBCFG_TOCAL_SHIFT)
- /* Bits 3-5: Reserved, must be kept at reset value */
-#define OTGFS_GUSBCFG_PHYSEL (1 << 6) /* Bit 6: Full Speed serial transceiver select */
- /* Bit 7: Reserved, must be kept at reset value */
-#define OTGFS_GUSBCFG_SRPCAP (1 << 8) /* Bit 8: SRP-capable */
-#define OTGFS_GUSBCFG_HNPCAP (1 << 9) /* Bit 9: HNP-capable */
-#define OTGFS_GUSBCFG_TRDT_SHIFT (10) /* Bits 10-13: USB turnaround time */
-#define OTGFS_GUSBCFG_TRDT_MASK (15 << OTGFS_GUSBCFG_TRDT_SHIFT)
-# define OTGFS_GUSBCFG_TRDT(n) ((n) << OTGFS_GUSBCFG_TRDT_SHIFT)
- /* Bits 14-28: Reserved, must be kept at reset value */
-#define OTGFS_GUSBCFG_FHMOD (1 << 29) /* Bit 29: Force host mode */
-#define OTGFS_GUSBCFG_FDMOD (1 << 30) /* Bit 30: Force device mode */
-#define OTGFS_GUSBCFG_CTXPKT (1 << 31) /* Bit 31: Corrupt Tx packet */
- /* Bits 20-31: Reserved, must be kept at reset value */
-/* Reset register */
-
-#define OTGFS_GRSTCTL_CSRST (1 << 0) /* Bit 0: Core soft reset */
-#define OTGFS_GRSTCTL_HSRST (1 << 1) /* Bit 1: HCLK soft reset */
-#define OTGFS_GRSTCTL_FCRST (1 << 2) /* Bit 2: Host frame counter reset */
- /* Bit 3 Reserved, must be kept at reset value */
-#define OTGFS_GRSTCTL_RXFFLSH (1 << 4) /* Bit 4: RxFIFO flush */
-#define OTGFS_GRSTCTL_TXFFLSH (1 << 5) /* Bit 5: TxFIFO flush */
-#define OTGFS_GRSTCTL_TXFNUM_SHIFT (6) /* Bits 6-10: TxFIFO number */
-#define OTGFS_GRSTCTL_TXFNUM_MASK (31 << OTGFS_GRSTCTL_TXFNUM_SHIFT)
-# define OTGFS_GRSTCTL_TXFNUM_HNONPER (0 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Non-periodic TxFIFO flush in host mode */
-# define OTGFS_GRSTCTL_TXFNUM_HPER (1 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Periodic TxFIFO flush in host mode */
-# define OTGFS_GRSTCTL_TXFNUM_HALL (16 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Flush all the transmit FIFOs in host mode.*/
-# define OTGFS_GRSTCTL_TXFNUM_D(n) ((n) << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* TXFIFO n flush in device mode, n=0-15 */
-# define OTGFS_GRSTCTL_TXFNUM_DALL (16 << OTGFS_GRSTCTL_TXFNUM_SHIFT) /* Flush all the transmit FIFOs in device mode.*/
- /* Bits 11-31: Reserved, must be kept at reset value */
-#define OTGFS_GRSTCTL_AHBIDL (1 << 31) /* Bit 31: AHB master idle */
-
-/* Core interrupt and Interrupt mask registers */
-
-#define OTGFS_GINTSTS_CMOD (1 << 0) /* Bit 0: Current mode of operation */
-# define OTGFS_GINTSTS_DEVMODE (0)
-# define OTGFS_GINTSTS_HOSTMODE (OTGFS_GINTSTS_CMOD)
-#define OTGFS_GINT_MMIS (1 << 1) /* Bit 1: Mode mismatch interrupt */
-#define OTGFS_GINT_OTG (1 << 2) /* Bit 2: OTG interrupt */
-#define OTGFS_GINT_SOF (1 << 3) /* Bit 3: Start of frame */
-#define OTGFS_GINT_RXFLVL (1 << 4) /* Bit 4: RxFIFO non-empty */
-#define OTGFS_GINT_NPTXFE (1 << 5) /* Bit 5: Non-periodic TxFIFO empty */
-#define OTGFS_GINT_GINAKEFF (1 << 6) /* Bit 6: Global IN non-periodic NAK effective */
-#define OTGFS_GINT_GONAKEFF (1 << 7) /* Bit 7: Global OUT NAK effective */
- /* Bits 8-9: Reserved, must be kept at reset value */
-#define OTGFS_GINT_ESUSP (1 << 10) /* Bit 10: Early suspend */
-#define OTGFS_GINT_USBSUSP (1 << 11) /* Bit 11: USB suspend */
-#define OTGFS_GINT_USBRST (1 << 12) /* Bit 12: USB reset */
-#define OTGFS_GINT_ENUMDNE (1 << 13) /* Bit 13: Enumeration done */
-#define OTGFS_GINT_ISOODRP (1 << 14) /* Bit 14: Isochronous OUT packet dropped interrupt */
-#define OTGFS_GINT_EOPF (1 << 15) /* Bit 15: End of periodic frame interrupt */
- /* Bits 16 Reserved, must be kept at reset value */
-#define OTGFS_GINTMSK_EPMISM (1 << 17) /* Bit 17: Endpoint mismatch interrupt mask */
-#define OTGFS_GINT_IEP (1 << 18) /* Bit 18: IN endpoint interrupt */
-#define OTGFS_GINT_OEP (1 << 19) /* Bit 19: OUT endpoint interrupt */
-#define OTGFS_GINT_IISOIXFR (1 << 20) /* Bit 20: Incomplete isochronous IN transfer */
-#define OTGFS_GINT_IISOOXFR (1 << 21) /* Bit 21: Incomplete isochronous OUT transfer (device) */
-#define OTGFS_GINT_IPXFR (1 << 21) /* Bit 21: Incomplete periodic transfer (host) */
- /* Bits 22-23: Reserved, must be kept at reset value */
-#define OTGFS_GINT_HPRT (1 << 24) /* Bit 24: Host port interrupt */
-#define OTGFS_GINT_HC (1 << 25) /* Bit 25: Host channels interrupt */
-#define OTGFS_GINT_PTXFE (1 << 26) /* Bit 26: Periodic TxFIFO empty */
- /* Bit 27 Reserved, must be kept at reset value */
-#define OTGFS_GINT_CIDSCHG (1 << 28) /* Bit 28: Connector ID status change */
-#define OTGFS_GINT_DISC (1 << 29) /* Bit 29: Disconnect detected interrupt */
-#define OTGFS_GINT_SRQ (1 << 30) /* Bit 30: Session request/new session detected interrupt */
-#define OTGFS_GINT_WKUP (1 << 31) /* Bit 31: Resume/remote wakeup detected interrupt */
-
-/* Receive status debug read/OTG status read and pop registers (host mode) */
-
-#define OTGFS_GRXSTSH_CHNUM_SHIFT (0) /* Bits 0-3: Channel number */
-#define OTGFS_GRXSTSH_CHNUM_MASK (15 << OTGFS_GRXSTSH_CHNUM_SHIFT)
-#define OTGFS_GRXSTSH_BCNT_SHIFT (4) /* Bits 4-14: Byte count */
-#define OTGFS_GRXSTSH_BCNT_MASK (0x7ff << OTGFS_GRXSTSH_BCNT_SHIFT)
-#define OTGFS_GRXSTSH_DPID_SHIFT (15) /* Bits 15-16: Data PID */
-#define OTGFS_GRXSTSH_DPID_MASK (3 << OTGFS_GRXSTSH_DPID_SHIFT)
-# define OTGFS_GRXSTSH_DPID_DATA0 (0 << OTGFS_GRXSTSH_DPID_SHIFT)
-# define OTGFS_GRXSTSH_DPID_DATA2 (1 << OTGFS_GRXSTSH_DPID_SHIFT)
-# define OTGFS_GRXSTSH_DPID_DATA1 (2 << OTGFS_GRXSTSH_DPID_SHIFT)
-# define OTGFS_GRXSTSH_DPID_MDATA (3 << OTGFS_GRXSTSH_DPID_SHIFT)
-#define OTGFS_GRXSTSH_PKTSTS_SHIFT (17) /* Bits 17-20: Packet status */
-#define OTGFS_GRXSTSH_PKTSTS_MASK (15 << OTGFS_GRXSTSH_PKTSTS_SHIFT)
-# define OTGFS_GRXSTSH_PKTSTS_INRECVD (2 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* IN data packet received */
-# define OTGFS_GRXSTSH_PKTSTS_INDONE (3 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* IN transfer completed */
-# define OTGFS_GRXSTSH_PKTSTS_DTOGERR (5 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* Data toggle error */
-# define OTGFS_GRXSTSH_PKTSTS_HALTED (7 << OTGFS_GRXSTSH_PKTSTS_SHIFT) /* Channel halted */
- /* Bits 21-31: Reserved, must be kept at reset value */
-/* Receive status debug read/OTG status read and pop registers (device mode) */
-
-#define OTGFS_GRXSTSD_EPNUM_SHIFT (0) /* Bits 0-3: Endpoint number */
-#define OTGFS_GRXSTSD_EPNUM_MASK (15 << OTGFS_GRXSTSD_EPNUM_SHIFT)
-#define OTGFS_GRXSTSD_BCNT_SHIFT (4) /* Bits 4-14: Byte count */
-#define OTGFS_GRXSTSD_BCNT_MASK (0x7ff << OTGFS_GRXSTSD_BCNT_SHIFT)
-#define OTGFS_GRXSTSD_DPID_SHIFT (15) /* Bits 15-16: Data PID */
-#define OTGFS_GRXSTSD_DPID_MASK (3 << OTGFS_GRXSTSD_DPID_SHIFT)
-# define OTGFS_GRXSTSD_DPID_DATA0 (0 << OTGFS_GRXSTSD_DPID_SHIFT)
-# define OTGFS_GRXSTSD_DPID_DATA2 (1 << OTGFS_GRXSTSD_DPID_SHIFT)
-# define OTGFS_GRXSTSD_DPID_DATA1 (2 << OTGFS_GRXSTSD_DPID_SHIFT)
-# define OTGFS_GRXSTSD_DPID_MDATA (3 << OTGFS_GRXSTSD_DPID_SHIFT)
-#define OTGFS_GRXSTSD_PKTSTS_SHIFT (17) /* Bits 17-20: Packet status */
-#define OTGFS_GRXSTSD_PKTSTS_MASK (15 << OTGFS_GRXSTSD_PKTSTS_SHIFT)
-# define OTGFS_GRXSTSD_PKTSTS_OUTNAK (1 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* Global OUT NAK */
-# define OTGFS_GRXSTSD_PKTSTS_OUTRECVD (2 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* OUT data packet received */
-# define OTGFS_GRXSTSD_PKTSTS_OUTDONE (3 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* OUT transfer completed */
-# define OTGFS_GRXSTSD_PKTSTS_SETUPDONE (4 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* SETUP transaction completed */
-# define OTGFS_GRXSTSD_PKTSTS_SETUPRECVD (6 << OTGFS_GRXSTSD_PKTSTS_SHIFT) /* SETUP data packet received */
-#define OTGFS_GRXSTSD_FRMNUM_SHIFT (21) /* Bits 21-24: Frame number */
-#define OTGFS_GRXSTSD_FRMNUM_MASK (15 << OTGFS_GRXSTSD_FRMNUM_SHIFT)
- /* Bits 25-31: Reserved, must be kept at reset value */
-/* Receive FIFO size register */
-
-#define OTGFS_GRXFSIZ_MASK (0xffff)
-
-/* Host non-periodic transmit FIFO size register */
-
-#define OTGFS_HNPTXFSIZ_NPTXFSA_SHIFT (0) /* Bits 0-15: Non-periodic transmit RAM start address */
-#define OTGFS_HNPTXFSIZ_NPTXFSA_MASK (0xffff << OTGFS_HNPTXFSIZ_NPTXFSA_SHIFT)
-#define OTGFS_HNPTXFSIZ_NPTXFD_SHIFT (16) /* Bits 16-31: Non-periodic TxFIFO depth */
-#define OTGFS_HNPTXFSIZ_NPTXFD_MASK (0xffff << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT)
-# define OTGFS_HNPTXFSIZ_NPTXFD_MIN (16 << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT)
-# define OTGFS_HNPTXFSIZ_NPTXFD_MAX (256 << OTGFS_HNPTXFSIZ_NPTXFD_SHIFT)
-
-/* Endpoint 0 Transmit FIFO size */
-
-#define OTGFS_DIEPTXF0_TX0FD_SHIFT (0) /* Bits 0-15: Endpoint 0 transmit RAM start address */
-#define OTGFS_DIEPTXF0_TX0FD_MASK (0xffff << OTGFS_DIEPTXF0_TX0FD_SHIFT)
-#define OTGFS_DIEPTXF0_TX0FSA_SHIFT (16) /* Bits 16-31: Endpoint 0 TxFIFO depth */
-#define OTGFS_DIEPTXF0_TX0FSA_MASK (0xffff << OTGFS_DIEPTXF0_TX0FSA_SHIFT)
-# define OTGFS_DIEPTXF0_TX0FSA_MIN (16 << OTGFS_DIEPTXF0_TX0FSA_SHIFT)
-# define OTGFS_DIEPTXF0_TX0FSA_MAX (256 << OTGFS_DIEPTXF0_TX0FSA_SHIFT)
-
-/* Non-periodic transmit FIFO/queue status register */
-
-#define OTGFS_HNPTXSTS_NPTXFSAV_SHIFT (0) /* Bits 0-15: Non-periodic TxFIFO space available */
-#define OTGFS_HNPTXSTS_NPTXFSAV_MASK (0xffff << OTGFS_HNPTXSTS_NPTXFSAV_SHIFT)
-# define OTGFS_HNPTXSTS_NPTXFSAV_FULL (0 << OTGFS_HNPTXSTS_NPTXFSAV_SHIFT)
-#define OTGFS_HNPTXSTS_NPTQXSAV_SHIFT (16) /* Bits 16-23: Non-periodic transmit request queue space available */
-#define OTGFS_HNPTXSTS_NPTQXSAV_MASK (0xff << OTGFS_HNPTXSTS_NPTQXSAV_SHIFT)
-# define OTGFS_HNPTXSTS_NPTQXSAV_FULL (0 << OTGFS_HNPTXSTS_NPTQXSAV_SHIFT)
-#define OTGFS_HNPTXSTS_NPTXQTOP_SHIFT (24) /* Bits 24-30: Top of the non-periodic transmit request queue */
-#define OTGFS_HNPTXSTS_NPTXQTOP_MASK (0x7f << OTGFS_HNPTXSTS_NPTXQTOP_SHIFT)
-# define OTGFS_HNPTXSTS_TERMINATE (1 << 24) /* Bit 24: Terminate (last entry for selected channel/endpoint) */
-# define OTGFS_HNPTXSTS_TYPE_SHIFT (25) /* Bits 25-26: Status */
-# define OTGFS_HNPTXSTS_TYPE_MASK (3 << OTGFS_HNPTXSTS_TYPE_SHIFT)
-# define OTGFS_HNPTXSTS_TYPE_INOUT (0 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* IN/OUT token */
-# define OTGFS_HNPTXSTS_TYPE_ZLP (1 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* Zero-length transmit packet (device IN/host OUT) */
-# define OTGFS_HNPTXSTS_TYPE_HALT (3 << OTGFS_HNPTXSTS_TYPE_SHIFT) /* Channel halt command */
-# define OTGFS_HNPTXSTS_CHNUM_SHIFT (27) /* Bits 27-30: Channel number */
-# define OTGFS_HNPTXSTS_CHNUM_MASK (15 << OTGFS_HNPTXSTS_CHNUM_SHIFT)
-# define OTGFS_HNPTXSTS_EPNUM_SHIFT (27) /* Bits 27-30: Endpoint number */
-# define OTGFS_HNPTXSTS_EPNUM_MASK (15 << OTGFS_HNPTXSTS_EPNUM_SHIFT)
- /* Bit 31 Reserved, must be kept at reset value */
-/* General core configuration register */
- /* Bits 15:0 Reserved, must be kept at reset value */
-#define OTGFS_GCCFG_PWRDWN (1 << 16) /* Bit 16: Power down */
- /* Bit 17 Reserved, must be kept at reset value */
-#define OTGFS_GCCFG_VBUSASEN (1 << 18) /* Bit 18: Enable the VBUS sensing “A” device */
-#define OTGFS_GCCFG_VBUSBSEN (1 << 19) /* Bit 19: Enable the VBUS sensing “B” device */
-#define OTGFS_GCCFG_SOFOUTEN (1 << 20) /* Bit 20: SOF output enable */
-#define OTGFS_GCCFG_NOVBUSSENS (1 << 21) /* Bit 21: VBUS sensing disable option */
- /* Bits 31:22 Reserved, must be kept at reset value */
-/* Core ID register (32-bit product ID) */
-
-/* Host periodic transmit FIFO size register */
-
-#define OTGFS_HPTXFSIZ_PTXSA_SHIFT (0) /* Bits 0-15: Host periodic TxFIFO start address */
-#define OTGFS_HPTXFSIZ_PTXSA_MASK (0xffff << OTGFS_HPTXFSIZ_PTXSA_SHIFT)
-#define OTGFS_HPTXFSIZ_PTXFD_SHIFT (16) /* Bits 16-31: Host periodic TxFIFO depth */
-#define OTGFS_HPTXFSIZ_PTXFD_MASK (0xffff << OTGFS_HPTXFSIZ_PTXFD_SHIFT)
-
-/* Device IN endpoint transmit FIFOn size register */
-
-#define OTGFS_DIEPTXF_INEPTXSA_SHIFT (0) /* Bits 0-15: IN endpoint FIFOx transmit RAM start address */
-#define OTGFS_DIEPTXF_INEPTXSA_MASK (0xffff << OTGFS_DIEPTXF_INEPTXSA_SHIFT)
-#define OTGFS_DIEPTXF_INEPTXFD_SHIFT (16) /* Bits 16-31: IN endpoint TxFIFO depth */
-#define OTGFS_DIEPTXF_INEPTXFD_MASK (0xffff << OTGFS_DIEPTXF_INEPTXFD_SHIFT)
-# define OTGFS_DIEPTXF_INEPTXFD_MIN (16 << OTGFS_DIEPTXF_INEPTXFD_MASK)
-
-/* Host-mode control and status registers */
-
-/* Host configuration register */
-
-#define OTGFS_HCFG_FSLSPCS_SHIFT (0) /* Bits 0-1: FS/LS PHY clock select */
-#define OTGFS_HCFG_FSLSPCS_MASK (3 << OTGFS_HCFG_FSLSPCS_SHIFT)
-# define OTGFS_HCFG_FSLSPCS_FS48MHz (1 << OTGFS_HCFG_FSLSPCS_SHIFT) /* FS host mode, PHY clock is running at 48 MHz */
-# define OTGFS_HCFG_FSLSPCS_LS48MHz (1 << OTGFS_HCFG_FSLSPCS_SHIFT) /* LS host mode, Select 48 MHz PHY clock frequency */
-# define OTGFS_HCFG_FSLSPCS_LS6MHz (2 << OTGFS_HCFG_FSLSPCS_SHIFT) /* LS host mode, Select 6 MHz PHY clock frequency */
-#define OTGFS_HCFG_FSLSS (1 << 2) /* Bit 2: FS- and LS-only support */
- /* Bits 31:3 Reserved, must be kept at reset value */
-/* Host frame interval register */
-
-#define OTGFS_HFIR_MASK (0xffff)
-
-/* Host frame number/frame time remaining register */
-
-#define OTGFS_HFNUM_FRNUM_SHIFT (0) /* Bits 0-15: Frame number */
-#define OTGFS_HFNUM_FRNUM_MASK (0xffff << OTGFS_HFNUM_FRNUM_SHIFT)
-#define OTGFS_HFNUM_FTREM_SHIFT (16) /* Bits 16-31: Frame time remaining */
-#define OTGFS_HFNUM_FTREM_MASK (0xffff << OTGFS_HFNUM_FTREM_SHIFT)
-
-/* Host periodic transmit FIFO/queue status register */
-
-#define OTGFS_HPTXSTS_PTXFSAVL_SHIFT (0) /* Bits 0-15: Periodic transmit data FIFO space available */
-#define OTGFS_HPTXSTS_PTXFSAVL_MASK (0xffff << OTGFS_HPTXSTS_PTXFSAVL_SHIFT)
-# define OTGFS_HPTXSTS_PTXFSAVL_FULL (0 << OTGFS_HPTXSTS_PTXFSAVL_SHIFT)
-#define OTGFS_HPTXSTS_PTXQSAV_SHIFT (16) /* Bits 16-23: Periodic transmit request queue space available */
-#define OTGFS_HPTXSTS_PTXQSAV_MASK (0xff << OTGFS_HPTXSTS_PTXQSAV_SHIFT)
-# define OTGFS_HPTXSTS_PTXQSAV_FULL (0 << OTGFS_HPTXSTS_PTXQSAV_SHIFT)
-#define OTGFS_HPTXSTS_PTXQTOP_SHIFT (24) /* Bits 24-31: Top of the periodic transmit request queue */
-#define OTGFS_HPTXSTS_PTXQTOP_MASK (0x7f << OTGFS_HPTXSTS_PTXQTOP_SHIFT)
-# define OTGFS_HPTXSTS_TERMINATE (1 << 24) /* Bit 24: Terminate (last entry for selected channel/endpoint) */
-# define OTGFS_HPTXSTS_TYPE_SHIFT (25) /* Bits 25-26: Type */
-# define OTGFS_HPTXSTS_TYPE_MASK (3 << OTGFS_HPTXSTS_TYPE_SHIFT)
-# define OTGFS_HPTXSTS_TYPE_INOUT (0 << OTGFS_HPTXSTS_TYPE_SHIFT) /* IN/OUT token */
-# define OTGFS_HPTXSTS_TYPE_ZLP (1 << OTGFS_HPTXSTS_TYPE_SHIFT) /* Zero-length transmit packet */
-# define OTGFS_HPTXSTS_TYPE_HALT (3 << OTGFS_HPTXSTS_TYPE_SHIFT) /* Disable channel command */
-# define OTGFS_HPTXSTS_EPNUM_SHIFT (27) /* Bits 27-30: Endpoint number */
-# define OTGFS_HPTXSTS_EPNUM_MASK (15 << OTGFS_HPTXSTS_EPNUM_SHIFT)
-# define OTGFS_HPTXSTS_CHNUM_SHIFT (27) /* Bits 27-30: Channel number */
-# define OTGFS_HPTXSTS_CHNUM_MASK (15 << OTGFS_HPTXSTS_CHNUM_SHIFT)
-# define OTGFS_HPTXSTS_ODD (1 << 24) /* Bit 31: Send in odd (vs even) frame */
-
-/* Host all channels interrupt and all channels interrupt mask registers */
-
-#define OTGFS_HAINT(n) (1 << (n)) /* Bits 15:0 HAINTM: Channel interrupt */
-
-/* Host port control and status register */
-
-#define OTGFS_HPRT_PCSTS (1 << 0) /* Bit 0: Port connect status */
-#define OTGFS_HPRT_PCDET (1 << 1) /* Bit 1: Port connect detected */
-#define OTGFS_HPRT_PENA (1 << 2) /* Bit 2: Port enable */
-#define OTGFS_HPRT_PENCHNG (1 << 3) /* Bit 3: Port enable/disable change */
-#define OTGFS_HPRT_POCA (1 << 4) /* Bit 4: Port overcurrent active */
-#define OTGFS_HPRT_POCCHNG (1 << 5) /* Bit 5: Port overcurrent change */
-#define OTGFS_HPRT_PRES (1 << 6) /* Bit 6: Port resume */
-#define OTGFS_HPRT_PSUSP (1 << 7) /* Bit 7: Port suspend */
-#define OTGFS_HPRT_PRST (1 << 8) /* Bit 8: Port reset */
- /* Bit 9: Reserved, must be kept at reset value */
-#define OTGFS_HPRT_PLSTS_SHIFT (10) /* Bits 10-11: Port line status */
-#define OTGFS_HPRT_PLSTS_MASK (3 << OTGFS_HPRT_PLSTS_SHIFT)
-# define OTGFS_HPRT_PLSTS_DP (1 << 10) /* Bit 10: Logic level of OTG_FS_FS_DP */
-# define OTGFS_HPRT_PLSTS_DM (1 << 11) /* Bit 11: Logic level of OTG_FS_FS_DM */
-#define OTGFS_HPRT_PPWR (1 << 12) /* Bit 12: Port power */
-#define OTGFS_HPRT_PTCTL_SHIFT (13) /* Bits 13-16: Port test control */
-#define OTGFS_HPRT_PTCTL_MASK (15 << OTGFS_HPRT_PTCTL_SHIFT)
-# define OTGFS_HPRT_PTCTL_DISABLED (0 << OTGFS_HPRT_PTCTL_SHIFT) /* Test mode disabled */
-# define OTGFS_HPRT_PTCTL_J (1 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_J mode */
-# define OTGFS_HPRT_PTCTL_L (2 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_K mode */
-# define OTGFS_HPRT_PTCTL_SE0_NAK (3 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_SE0_NAK mode */
-# define OTGFS_HPRT_PTCTL_PACKET (4 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_Packet mode */
-# define OTGFS_HPRT_PTCTL_FORCE (5 << OTGFS_HPRT_PTCTL_SHIFT) /* Test_Force_Enable */
-#define OTGFS_HPRT_PSPD_SHIFT (17) /* Bits 17-18: Port speed */
-#define OTGFS_HPRT_PSPD_MASK (3 << OTGFS_HPRT_PSPD_SHIFT)
-# define OTGFS_HPRT_PSPD_FS (1 << OTGFS_HPRT_PSPD_SHIFT) /* Full speed */
-# define OTGFS_HPRT_PSPD_LS (2 << OTGFS_HPRT_PSPD_SHIFT) /* Low speed */
- /* Bits 19-31: Reserved, must be kept at reset value */
-
-/* Host channel-n characteristics register */
-
-#define OTGFS_HCCHAR_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */
-#define OTGFS_HCCHAR_MPSIZ_MASK (0x7ff << OTGFS_HCCHAR_MPSIZ_SHIFT)
-#define OTGFS_HCCHAR_EPNUM_SHIFT (11) /* Bits 11-14: Endpoint number */
-#define OTGFS_HCCHAR_EPNUM_MASK (15 << OTGFS_HCCHAR_EPNUM_SHIFT)
-#define OTGFS_HCCHAR_EPDIR (1 << 15) /* Bit 15: Endpoint direction */
-# define OTGFS_HCCHAR_EPDIR_OUT (0)
-# define OTGFS_HCCHAR_EPDIR_IN OTGFS_HCCHAR_EPDIR
- /* Bit 16 Reserved, must be kept at reset value */
-#define OTGFS_HCCHAR_LSDEV (1 << 17) /* Bit 17: Low-speed device */
-#define OTGFS_HCCHAR_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */
-#define OTGFS_HCCHAR_EPTYP_MASK (3 << OTGFS_HCCHAR_EPTYP_SHIFT)
-# define OTGFS_HCCHAR_EPTYP_CTRL (0 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Control */
-# define OTGFS_HCCHAR_EPTYP_ISOC (1 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Isochronous */
-# define OTGFS_HCCHAR_EPTYP_BULK (2 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Bulk */
-# define OTGFS_HCCHAR_EPTYP_INTR (3 << OTGFS_HCCHAR_EPTYP_SHIFT) /* Interrupt */
-#define OTGFS_HCCHAR_MCNT_SHIFT (20) /* Bits 20-21: Multicount */
-#define OTGFS_HCCHAR_MCNT_MASK (3 << OTGFS_HCCHAR_MCNT_SHIFT)
-#define OTGFS_HCCHAR_DAD_SHIFT (22) /* Bits 22-28: Device address */
-#define OTGFS_HCCHAR_DAD_MASK (0x7f << OTGFS_HCCHAR_DAD_SHIFT)
-#define OTGFS_HCCHAR_ODDFRM (1 << 29) /* Bit 29: Odd frame */
-#define OTGFS_HCCHAR_CHDIS (1 << 30) /* Bit 30: Channel disable */
-#define OTGFS_HCCHAR_CHENA (1 << 31) /* Bit 31: Channel enable */
-
-/* Host channel-n interrupt and Host channel-0 interrupt mask registers */
-
-#define OTGFS_HCINT_XFRC (1 << 0) /* Bit 0: Transfer completed */
-#define OTGFS_HCINT_CHH (1 << 1) /* Bit 1: Channel halted */
- /* Bit 2: Reserved, must be kept at reset value */
-#define OTGFS_HCINT_STALL (1 << 3) /* Bit 3: STALL response received interrupt */
-#define OTGFS_HCINT_NAK (1 << 4) /* Bit 4: NAK response received interrupt */
-#define OTGFS_HCINT_ACK (1 << 5) /* Bit 5: ACK response received/transmitted interrupt */
-#define OTGFS_HCINT_NYET (1 << 6) /* Bit 6: Response received interrupt */
-#define OTGFS_HCINT_TXERR (1 << 7) /* Bit 7: Transaction error */
-#define OTGFS_HCINT_BBERR (1 << 8) /* Bit 8: Babble error */
-#define OTGFS_HCINT_FRMOR (1 << 9) /* Bit 9: Frame overrun */
-#define OTGFS_HCINT_DTERR (1 << 10) /* Bit 10: Data toggle error */
- /* Bits 11-31 Reserved, must be kept at reset value */
-/* Host channel-n interrupt register */
-
-#define OTGFS_HCTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */
-#define OTGFS_HCTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_HCTSIZ_XFRSIZ_SHIFT)
-#define OTGFS_HCTSIZ_PKTCNT_SHIFT (19) /* Bits 19-28: Packet count */
-#define OTGFS_HCTSIZ_PKTCNT_MASK (0x3ff << OTGFS_HCTSIZ_PKTCNT_SHIFT)
-#define OTGFS_HCTSIZ_DPID_SHIFT (29) /* Bits 29-30: Data PID */
-#define OTGFS_HCTSIZ_DPID_MASK (3 << OTGFS_HCTSIZ_DPID_SHIFT)
-# define OTGFS_HCTSIZ_DPID_DATA0 (0 << OTGFS_HCTSIZ_DPID_SHIFT)
-# define OTGFS_HCTSIZ_DPID_DATA2 (1 << OTGFS_HCTSIZ_DPID_SHIFT)
-# define OTGFS_HCTSIZ_DPID_DATA1 (2 << OTGFS_HCTSIZ_DPID_SHIFT)
-# define OTGFS_HCTSIZ_DPID_MDATA (3 << OTGFS_HCTSIZ_DPID_SHIFT) /* Non-control */
-# define OTGFS_HCTSIZ_PID_SETUP (3 << OTGFS_HCTSIZ_DPID_SHIFT) /* Control */
- /* Bit 31 Reserved, must be kept at reset value */
-/* Device-mode control and status registers */
-
-/* Device configuration register */
-
-#define OTGFS_DCFG_DSPD_SHIFT (0) /* Bits 0-1: Device speed */
-#define OTGFS_DCFG_DSPD_MASK (3 << OTGFS_DCFG_DSPD_SHIFT)
-# define OTGFS_DCFG_DSPD_FS (3 << OTGFS_DCFG_DSPD_SHIFT) /* Full speed */
-#define OTGFS_DCFG_NZLSOHSK (1 << 2) /* Bit 2: Non-zero-length status OUT handshake */
- /* Bit 3: Reserved, must be kept at reset value */
-#define OTGFS_DCFG_DAD_SHIFT (4) /* Bits 4-10: Device address */
-#define OTGFS_DCFG_DAD_MASK (0x7f << OTGFS_DCFG_DAD_SHIFT)
-#define OTGFS_DCFG_PFIVL_SHIFT (11) /* Bits 11-12: Periodic frame interval */
-#define OTGFS_DCFG_PFIVL_MASK (3 << OTGFS_DCFG_PFIVL_SHIFT)
-# define OTGFS_DCFG_PFIVL_80PCT (0 << OTGFS_DCFG_PFIVL_SHIFT) /* 80% of the frame interval */
-# define OTGFS_DCFG_PFIVL_85PCT (1 << OTGFS_DCFG_PFIVL_SHIFT) /* 85% of the frame interval */
-# define OTGFS_DCFG_PFIVL_90PCT (2 << OTGFS_DCFG_PFIVL_SHIFT) /* 90% of the frame interval */
-# define OTGFS_DCFG_PFIVL_95PCT (3 << OTGFS_DCFG_PFIVL_SHIFT) /* 95% of the frame interval */
- /* Bits 13-31 Reserved, must be kept at reset value */
-/* Device control register */
-
-#define OTGFS_TESTMODE_DISABLED (0) /* Test mode disabled */
-#define OTGFS_TESTMODE_J (1) /* Test_J mode */
-#define OTGFS_TESTMODE_K (2) /* Test_K mode */
-#define OTGFS_TESTMODE_SE0_NAK (3) /* Test_SE0_NAK mode */
-#define OTGFS_TESTMODE_PACKET (4) /* Test_Packet mode */
-#define OTGFS_TESTMODE_FORCE (5) /* Test_Force_Enable */
-
-#define OTGFS_DCTL_RWUSIG (1 << 0) /* Bit 0: Remote wakeup signaling */
-#define OTGFS_DCTL_SDIS (1 << 1) /* Bit 1: Soft disconnect */
-#define OTGFS_DCTL_GINSTS (1 << 2) /* Bit 2: Global IN NAK status */
-#define OTGFS_DCTL_GONSTS (1 << 3) /* Bit 3: Global OUT NAK status */
-#define OTGFS_DCTL_TCTL_SHIFT (4) /* Bits 4-6: Test control */
-#define OTGFS_DCTL_TCTL_MASK (7 << OTGFS_DCTL_TCTL_SHIFT)
-# define OTGFS_DCTL_TCTL_DISABLED (0 << OTGFS_DCTL_TCTL_SHIFT) /* Test mode disabled */
-# define OTGFS_DCTL_TCTL_J (1 << OTGFS_DCTL_TCTL_SHIFT) /* Test_J mode */
-# define OTGFS_DCTL_TCTL_K (2 << OTGFS_DCTL_TCTL_SHIFT) /* Test_K mode */
-# define OTGFS_DCTL_TCTL_SE0_NAK (3 << OTGFS_DCTL_TCTL_SHIFT) /* Test_SE0_NAK mode */
-# define OTGFS_DCTL_TCTL_PACKET (4 << OTGFS_DCTL_TCTL_SHIFT) /* Test_Packet mode */
-# define OTGFS_DCTL_TCTL_FORCE (5 << OTGFS_DCTL_TCTL_SHIFT) /* Test_Force_Enable */
-#define OTGFS_DCTL_SGINAK (1 << 7) /* Bit 7: Set global IN NAK */
-#define OTGFS_DCTL_CGINAK (1 << 8) /* Bit 8: Clear global IN NAK */
-#define OTGFS_DCTL_SGONAK (1 << 9) /* Bit 9: Set global OUT NAK */
-#define OTGFS_DCTL_CGONAK (1 << 10) /* Bit 10: Clear global OUT NAK */
-#define OTGFS_DCTL_POPRGDNE (1 << 11) /* Bit 11: Power-on programming done */
- /* Bits 12-31: Reserved, must be kept at reset value */
-/* Device status register */
-
-#define OTGFS_DSTS_SUSPSTS (1 << 0) /* Bit 0: Suspend status */
-#define OTGFS_DSTS_ENUMSPD_SHIFT (1) /* Bits 1-2: Enumerated speed */
-#define OTGFS_DSTS_ENUMSPD_MASK (3 << OTGFS_DSTS_ENUMSPD_SHIFT)
-# define OTGFS_DSTS_ENUMSPD_FS (3 << OTGFS_DSTS_ENUMSPD_MASK) /* Full speed */
- /* Bits 4-7: Reserved, must be kept at reset value */
-#define OTGFS_DSTS_EERR (1 << 3) /* Bit 3: Erratic error */
-#define OTGFS_DSTS_SOFFN_SHIFT (8) /* Bits 8-21: Frame number of the received SOF */
-#define OTGFS_DSTS_SOFFN_MASK (0x3fff << OTGFS_DSTS_SOFFN_SHIFT)
-#define OTGFS_DSTS_SOFFN0 (1 << 8) /* Bits 8: Frame number even/odd bit */
-#define OTGFS_DSTS_SOFFN_EVEN 0
-#define OTGFS_DSTS_SOFFN_ODD OTGFS_DSTS_SOFFN0
- /* Bits 22-31: Reserved, must be kept at reset value */
-/* Device IN endpoint common interrupt mask register */
-
-#define OTGFS_DIEPMSK_XFRCM (1 << 0) /* Bit 0: Transfer completed interrupt mask */
-#define OTGFS_DIEPMSK_EPDM (1 << 1) /* Bit 1: Endpoint disabled interrupt mask */
- /* Bit 2: Reserved, must be kept at reset value */
-#define OTGFS_DIEPMSK_TOM (1 << 3) /* Bit 3: Timeout condition mask (Non-isochronous endpoints) */
-#define OTGFS_DIEPMSK_ITTXFEMSK (1 << 4) /* Bit 4: IN token received when TxFIFO empty mask */
-#define OTGFS_DIEPMSK_INEPNMM (1 << 5) /* Bit 5: IN token received with EP mismatch mask */
-#define OTGFS_DIEPMSK_INEPNEM (1 << 6) /* Bit 6: IN endpoint NAK effective mask */
- /* Bits 7-31: Reserved, must be kept at reset value */
-/* Device OUT endpoint common interrupt mask register */
-
-#define OTGFS_DOEPMSK_XFRCM (1 << 0) /* Bit 0: Transfer completed interrupt mask */
-#define OTGFS_DOEPMSK_EPDM (1 << 1) /* Bit 1: Endpoint disabled interrupt mask */
- /* Bit 2: Reserved, must be kept at reset value */
-#define OTGFS_DOEPMSK_STUPM (1 << 3) /* Bit 3: SETUP phase done mask */
-#define OTGFS_DOEPMSK_OTEPDM (1 << 4) /* Bit 4: OUT token received when endpoint disabled mask */
- /* Bits 5-31: Reserved, must be kept at reset value */
-/* Device all endpoints interrupt and All endpoints interrupt mask registers */
-
-#define OTGFS_DAINT_IEP_SHIFT (0) /* Bits 0-15: IN endpoint interrupt bits */
-#define OTGFS_DAINT_IEP_MASK (0xffff << OTGFS_DAINT_IEP_SHIFT)
-# define OTGFS_DAINT_IEP(n) (1 << (n))
-#define OTGFS_DAINT_OEP_SHIFT (16) /* Bits 16-31: OUT endpoint interrupt bits */
-#define OTGFS_DAINT_OEP_MASK (0xffff << OTGFS_DAINT_OEP_SHIFT)
-# define OTGFS_DAINT_OEP(n) (1 << ((n)+16))
-
-/* Device VBUS discharge time register */
-
-#define OTGFS_DVBUSDIS_MASK (0xffff)
-
-/* Device VBUS pulsing time register */
-
-#define OTGFS_DVBUSPULSE_MASK (0xfff)
-
-/* Device IN endpoint FIFO empty interrupt mask register */
-
-#define OTGFS_DIEPEMPMSK(n) (1 << (n))
-
-/* Device control IN endpoint 0 control register */
-
-#define OTGFS_DIEPCTL0_MPSIZ_SHIFT (0) /* Bits 0-1: Maximum packet size */
-#define OTGFS_DIEPCTL0_MPSIZ_MASK (3 << OTGFS_DIEPCTL0_MPSIZ_SHIFT)
-# define OTGFS_DIEPCTL0_MPSIZ_64 (0 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 64 bytes */
-# define OTGFS_DIEPCTL0_MPSIZ_32 (1 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 32 bytes */
-# define OTGFS_DIEPCTL0_MPSIZ_16 (2 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 16 bytes */
-# define OTGFS_DIEPCTL0_MPSIZ_8 (3 << OTGFS_DIEPCTL0_MPSIZ_SHIFT) /* 8 bytes */
- /* Bits 2-14: Reserved, must be kept at reset value */
-#define OTGFS_DIEPCTL0_USBAEP (1 << 15) /* Bit 15: USB active endpoint */
- /* Bit 16: Reserved, must be kept at reset value */
-#define OTGFS_DIEPCTL0_NAKSTS (1 << 17) /* Bit 17: NAK status */
-#define OTGFS_DIEPCTL0_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */
-#define OTGFS_DIEPCTL0_EPTYP_MASK (3 << OTGFS_DIEPCTL0_EPTYP_SHIFT)
-# define OTGFS_DIEPCTL0_EPTYP_CTRL (0 << OTGFS_DIEPCTL0_EPTYP_SHIFT) /* Control (hard-coded) */
- /* Bit 20: Reserved, must be kept at reset value */
-#define OTGFS_DIEPCTL0_STALL (1 << 21) /* Bit 21: STALL handshake */
-#define OTGFS_DIEPCTL0_TXFNUM_SHIFT (22) /* Bits 22-25: TxFIFO number */
-#define OTGFS_DIEPCTL0_TXFNUM_MASK (15 << OTGFS_DIEPCTL0_TXFNUM_SHIFT)
-#define OTGFS_DIEPCTL0_CNAK (1 << 26) /* Bit 26: Clear NAK */
-#define OTGFS_DIEPCTL0_SNAK (1 << 27) /* Bit 27: Set NAK */
- /* Bits 28-29: Reserved, must be kept at reset value */
-#define OTGFS_DIEPCTL0_EPDIS (1 << 30) /* Bit 30: Endpoint disable */
-#define OTGFS_DIEPCTL0_EPENA (1 << 31) /* Bit 31: Endpoint enable */
-
-/* Device control IN endpoint n control register */
-
-#define OTGFS_DIEPCTL_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */
-#define OTGFS_DIEPCTL_MPSIZ_MASK (0x7ff << OTGFS_DIEPCTL_MPSIZ_SHIFT)
- /* Bits 11-14: Reserved, must be kept at reset value */
-#define OTGFS_DIEPCTL_USBAEP (1 << 15) /* Bit 15: USB active endpoint */
-#define OTGFS_DIEPCTL_EONUM (1 << 16) /* Bit 16: Even/odd frame */
-# define OTGFS_DIEPCTL_EVEN (0)
-# define OTGFS_DIEPCTL_ODD OTGFS_DIEPCTL_EONUM
-# define OTGFS_DIEPCTL_DATA0 (0)
-# define OTGFS_DIEPCTL_DATA1 OTGFS_DIEPCTL_EONUM
-#define OTGFS_DIEPCTL_NAKSTS (1 << 17) /* Bit 17: NAK status */
-#define OTGFS_DIEPCTL_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */
-#define OTGFS_DIEPCTL_EPTYP_MASK (3 << OTGFS_DIEPCTL_EPTYP_SHIFT)
-# define OTGFS_DIEPCTL_EPTYP_CTRL (0 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Control */
-# define OTGFS_DIEPCTL_EPTYP_ISOC (1 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Isochronous */
-# define OTGFS_DIEPCTL_EPTYP_BULK (2 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Bulk */
-# define OTGFS_DIEPCTL_EPTYP_INTR (3 << OTGFS_DIEPCTL_EPTYP_SHIFT) /* Interrupt */
- /* Bit 20: Reserved, must be kept at reset value */
-#define OTGFS_DIEPCTL_STALL (1 << 21) /* Bit 21: STALL handshake */
-#define OTGFS_DIEPCTL_TXFNUM_SHIFT (22) /* Bits 22-25: TxFIFO number */
-#define OTGFS_DIEPCTL_TXFNUM_MASK (15 << OTGFS_DIEPCTL_TXFNUM_SHIFT)
-#define OTGFS_DIEPCTL_CNAK (1 << 26) /* Bit 26: Clear NAK */
-#define OTGFS_DIEPCTL_SNAK (1 << 27) /* Bit 27: Set NAK */
-#define OTGFS_DIEPCTL_SD0PID (1 << 28) /* Bit 28: Set DATA0 PID (interrupt/bulk) */
-#define OTGFS_DIEPCTL_SEVNFRM (1 << 28) /* Bit 28: Set even frame (isochronous)) */
-#define OTGFS_DIEPCTL_SODDFRM (1 << 29) /* Bit 29: Set odd frame (isochronous) */
-#define OTGFS_DIEPCTL_EPDIS (1 << 30) /* Bit 30: Endpoint disable */
-#define OTGFS_DIEPCTL_EPENA (1 << 31) /* Bit 31: Endpoint enable */
-
-/* Device endpoint-n interrupt register */
-
-#define OTGFS_DIEPINT_XFRC (1 << 0) /* Bit 0: Transfer completed interrupt */
-#define OTGFS_DIEPINT_EPDISD (1 << 1) /* Bit 1: Endpoint disabled interrupt */
- /* Bit 2: Reserved, must be kept at reset value */
-#define OTGFS_DIEPINT_TOC (1 << 3) /* Bit 3: Timeout condition */
-#define OTGFS_DIEPINT_ITTXFE (1 << 4) /* Bit 4: IN token received when TxFIFO is empty */
- /* Bit 5: Reserved, must be kept at reset value */
-#define OTGFS_DIEPINT_INEPNE (1 << 6) /* Bit 6: IN endpoint NAK effective */
-#define OTGFS_DIEPINT_TXFE (1 << 7) /* Bit 7: Transmit FIFO empty */
- /* Bits 8-31: Reserved, must be kept at reset value */
-/* Device IN endpoint 0 transfer size register */
-
-#define OTGFS_DIEPTSIZ0_XFRSIZ_SHIFT (0) /* Bits 0-6: Transfer size */
-#define OTGFS_DIEPTSIZ0_XFRSIZ_MASK (0x7f << OTGFS_DIEPTSIZ0_XFRSIZ_SHIFT)
- /* Bits 7-18: Reserved, must be kept at reset value */
-#define OTGFS_DIEPTSIZ0_PKTCNT_SHIFT (19) /* Bits 19-20: Packet count */
-#define OTGFS_DIEPTSIZ0_PKTCNT_MASK (3 << OTGFS_DIEPTSIZ0_PKTCNT_SHIFT)
- /* Bits 21-31: Reserved, must be kept at reset value */
-/* Device IN endpoint n transfer size register */
-
-#define OTGFS_DIEPTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */
-#define OTGFS_DIEPTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_DIEPTSIZ_XFRSIZ_SHIFT)
-#define OTGFS_DIEPTSIZ_PKTCNT_SHIFT (19) /* Bit 19-28: Packet count */
-#define OTGFS_DIEPTSIZ_PKTCNT_MASK (0x3ff << OTGFS_DIEPTSIZ_PKTCNT_SHIFT)
-#define OTGFS_DIEPTSIZ_MCNT_SHIFT (29) /* Bits 29-30: Multi count */
-#define OTGFS_DIEPTSIZ_MCNT_MASK (3 << OTGFS_DIEPTSIZ_MCNT_SHIFT)
- /* Bit 31: Reserved, must be kept at reset value */
-/* Device OUT endpoint TxFIFO status register */
-
-#define OTGFS_DTXFSTS_MASK (0xffff)
-
-/* Device OUT endpoint 0 control register */
-
-#define OTGFS_DOEPCTL0_MPSIZ_SHIFT (0) /* Bits 0-1: Maximum packet size */
-#define OTGFS_DOEPCTL0_MPSIZ_MASK (3 << OTGFS_DOEPCTL0_MPSIZ_SHIFT)
-# define OTGFS_DOEPCTL0_MPSIZ_64 (0 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 64 bytes */
-# define OTGFS_DOEPCTL0_MPSIZ_32 (1 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 32 bytes */
-# define OTGFS_DOEPCTL0_MPSIZ_16 (2 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 16 bytes */
-# define OTGFS_DOEPCTL0_MPSIZ_8 (3 << OTGFS_DOEPCTL0_MPSIZ_SHIFT) /* 8 bytes */
- /* Bits 2-14: Reserved, must be kept at reset value */
-#define OTGFS_DOEPCTL0_USBAEP (1 << 15) /* Bit 15: USB active endpoint */
- /* Bit 16: Reserved, must be kept at reset value */
-#define OTGFS_DOEPCTL0_NAKSTS (1 << 17) /* Bit 17: NAK status */
-#define OTGFS_DOEPCTL0_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */
-#define OTGFS_DOEPCTL0_EPTYP_MASK (3 << OTGFS_DOEPCTL0_EPTYP_SHIFT)
-# define OTGFS_DOEPCTL0_EPTYP_CTRL (0 << OTGFS_DOEPCTL0_EPTYP_SHIFT) /* Control (hard-coded) */
-#define OTGFS_DOEPCTL0_SNPM (1 << 20) /* Bit 20: Snoop mode */
-#define OTGFS_DOEPCTL0_STALL (1 << 21) /* Bit 21: STALL handshake */
- /* Bits 22-25: Reserved, must be kept at reset value */
-#define OTGFS_DOEPCTL0_CNAK (1 << 26) /* Bit 26: Clear NAK */
-#define OTGFS_DOEPCTL0_SNAK (1 << 27) /* Bit 27: Set NAK */
- /* Bits 28-29: Reserved, must be kept at reset value */
-#define OTGFS_DOEPCTL0_EPDIS (1 << 30) /* Bit 30: Endpoint disable */
-#define OTGFS_DOEPCTL0_EPENA (1 << 31) /* Bit 31: Endpoint enable */
-
-/* Device OUT endpoint n control register */
-
-#define OTGFS_DOEPCTL_MPSIZ_SHIFT (0) /* Bits 0-10: Maximum packet size */
-#define OTGFS_DOEPCTL_MPSIZ_MASK (0x7ff << OTGFS_DOEPCTL_MPSIZ_SHIFT)
- /* Bits 11-14: Reserved, must be kept at reset value */
-#define OTGFS_DOEPCTL_USBAEP (1 << 15) /* Bit 15: USB active endpoint */
-#define OTGFS_DOEPCTL_DPID (1 << 16) /* Bit 16: Endpoint data PID (interrupt/buld) */
-# define OTGFS_DOEPCTL_DATA0 (0)
-# define OTGFS_DOEPCTL_DATA1 OTGFS_DOEPCTL_DPID
-#define OTGFS_DOEPCTL_EONUM (1 << 16) /* Bit 16: Even/odd frame (isochronous) */
-# define OTGFS_DOEPCTL_EVEN (0)
-# define OTGFS_DOEPCTL_ODD OTGFS_DOEPCTL_EONUM
-#define OTGFS_DOEPCTL_NAKSTS (1 << 17) /* Bit 17: NAK status */
-#define OTGFS_DOEPCTL_EPTYP_SHIFT (18) /* Bits 18-19: Endpoint type */
-#define OTGFS_DOEPCTL_EPTYP_MASK (3 << OTGFS_DOEPCTL_EPTYP_SHIFT)
-# define OTGFS_DOEPCTL_EPTYP_CTRL (0 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Control */
-# define OTGFS_DOEPCTL_EPTYP_ISOC (1 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Isochronous */
-# define OTGFS_DOEPCTL_EPTYP_BULK (2 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Bulk */
-# define OTGFS_DOEPCTL_EPTYP_INTR (3 << OTGFS_DOEPCTL_EPTYP_SHIFT) /* Interrupt */
-#define OTGFS_DOEPCTL_SNPM (1 << 20) /* Bit 20: Snoop mode */
-#define OTGFS_DOEPCTL_STALL (1 << 21) /* Bit 21: STALL handshake */
- /* Bits 22-25: Reserved, must be kept at reset value */
-#define OTGFS_DOEPCTL_CNAK (1 << 26) /* Bit 26: Clear NAK */
-#define OTGFS_DOEPCTL_SNAK (1 << 27) /* Bit 27: Set NAK */
-#define OTGFS_DOEPCTL_SD0PID (1 << 28) /* Bit 28: Set DATA0 PID (interrupt/bulk) */
-#define OTGFS_DOEPCTL_SEVNFRM (1 << 28) /* Bit 28: Set even frame (isochronous) */
-#define OTGFS_DOEPCTL_SD1PID (1 << 29) /* Bit 29: Set DATA1 PID (interrupt/bulk) */
-#define OTGFS_DOEPCTL_SODDFRM (1 << 29) /* Bit 29: Set odd frame (isochronous */
-#define OTGFS_DOEPCTL_EPDIS (1 << 30) /* Bit 30: Endpoint disable */
-#define OTGFS_DOEPCTL_EPENA (1 << 31) /* Bit 31: Endpoint enable */
-
-/* Device endpoint-n interrupt register */
-
-#define OTGFS_DOEPINT_XFRC (1 << 0) /* Bit 0: Transfer completed interrupt */
-#define OTGFS_DOEPINT_EPDISD (1 << 1) /* Bit 1: Endpoint disabled interrupt */
- /* Bit 2: Reserved, must be kept at reset value */
-#define OTGFS_DOEPINT_SETUP (1 << 3) /* Bit 3: SETUP phase done */
-#define OTGFS_DOEPINT_OTEPDIS (1 << 4) /* Bit 4: OUT token received when endpoint disabled */
- /* Bit 5: Reserved, must be kept at reset value */
-#define OTGFS_DOEPINT_B2BSTUP (1 << 6) /* Bit 6: Back-to-back SETUP packets received */
- /* Bits 7-31: Reserved, must be kept at reset value */
-/* Device OUT endpoint-0 transfer size register */
-
-#define OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT (0) /* Bits 0-6: Transfer size */
-#define OTGFS_DOEPTSIZ0_XFRSIZ_MASK (0x7f << OTGFS_DOEPTSIZ0_XFRSIZ_SHIFT)
- /* Bits 7-18: Reserved, must be kept at reset value */
-#define OTGFS_DOEPTSIZ0_PKTCNT (1 << 19) /* Bit 19 PKTCNT: Packet count */
- /* Bits 20-28: Reserved, must be kept at reset value */
-#define OTGFS_DOEPTSIZ0_STUPCNT_SHIFT (29) /* Bits 29-30: SETUP packet count */
-#define OTGFS_DOEPTSIZ0_STUPCNT_MASK (3 << OTGFS_DOEPTSIZ0_STUPCNT_SHIFT)
- /* Bit 31: Reserved, must be kept at reset value */
-/* Device OUT endpoint-n transfer size register */
-
-#define OTGFS_DOEPTSIZ_XFRSIZ_SHIFT (0) /* Bits 0-18: Transfer size */
-#define OTGFS_DOEPTSIZ_XFRSIZ_MASK (0x7ffff << OTGFS_DOEPTSIZ_XFRSIZ_SHIFT)
-#define OTGFS_DOEPTSIZ_PKTCNT_SHIFT (19) /* Bit 19-28: Packet count */
-#define OTGFS_DOEPTSIZ_PKTCNT_MASK (0x3ff << OTGFS_DOEPTSIZ_PKTCNT_SHIFT)
-#define OTGFS_DOEPTSIZ_STUPCNT_SHIFT (29) /* Bits 29-30: SETUP packet count */
-#define OTGFS_DOEPTSIZ_STUPCNT_MASK (3 << OTGFS_DOEPTSIZ_STUPCNT_SHIFT)
-#define OTGFS_DOEPTSIZ_RXDPID_SHIFT (29) /* Bits 29-30: Received data PID */
-#define OTGFS_DOEPTSIZ_RXDPID_MASK (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT)
-# define OTGFS_DOEPTSIZ_RXDPID_DATA0 (0 << OTGFS_DOEPTSIZ_RXDPID_SHIFT)
-# define OTGFS_DOEPTSIZ_RXDPID_DATA2 (1 << OTGFS_DOEPTSIZ_RXDPID_SHIFT)
-# define OTGFS_DOEPTSIZ_RXDPID_DATA1 (2 << OTGFS_DOEPTSIZ_RXDPID_SHIFT)
-# define OTGFS_DOEPTSIZ_RXDPID_MDATA (3 << OTGFS_DOEPTSIZ_RXDPID_SHIFT)
- /* Bit 31: Reserved, must be kept at reset value */
-/* Power and clock gating control register */
-
-#define OTGFS_PCGCCTL_STPPCLK (1 << 0) /* Bit 0: Stop PHY clock */
-#define OTGFS_PCGCCTL_GATEHCLK (1 << 1) /* Bit 1: Gate HCLK */
- /* Bits 2-3: Reserved, must be kept at reset value */
-#define OTGFS_PCGCCTL_PHYSUSP (1 << 4) /* Bit 4: PHY Suspended */
- /* Bits 5-31: Reserved, must be kept at reset value */
-
-#endif /* __ARCH_ARM_SRC_STM32_CHIP_STM32_OTGFS_H */
diff --git a/arch/arm/src/stm32/chip/stm32fxxxxx_otgfs.h b/arch/arm/src/stm32/chip/stm32fxxxxx_otgfs.h
index 8658aec0a89..36606382671 100644
--- a/arch/arm/src/stm32/chip/stm32fxxxxx_otgfs.h
+++ b/arch/arm/src/stm32/chip/stm32fxxxxx_otgfs.h
@@ -475,30 +475,40 @@
# define OTGFS_GINTSTS_DEVMODE (0)
# define OTGFS_GINTSTS_HOSTMODE (OTGFS_GINTSTS_CMOD)
#define OTGFS_GINT_MMIS (1 << 1) /* Bit 1: rc_w1 Mode mismatch interrupt */
-#define OTGFS_GINT_OTG (1 << 2) /* Bit 2: ro OTG interrupt */
+#define OTGFS_GINT_OTG (1 << 2) /* Bit 2: ro OTG interrupt */
#define OTGFS_GINT_SOF (1 << 3) /* Bit 3: rc_w1 Start of frame */
-#define OTGFS_GINT_RXFLVL (1 << 4) /* Bit 4: ro RxFIFO non-empty */
-#define OTGFS_GINT_NPTXFE (1 << 5) /* Bit 5: ro Non-periodic TxFIFO empty */
-#define OTGFS_GINT_GINAKEFF (1 << 6) /* Bit 6: ro Global IN non-periodic NAK effective */
+#define OTGFS_GINT_RXFLVL (1 << 4) /* Bit 4: ro RxFIFO non-empty */
+#define OTGFS_GINT_NPTXFE (1 << 5) /* Bit 5: ro Non-periodic TxFIFO empty */
+#define OTGFS_GINT_GINAKEFF (1 << 6) /* Bit 6: ro Global IN non-periodic NAK effective */
#define OTGFS_GINT_GONAKEFF (1 << 7) /* Bit 7: Global OUT NAK effective */
-#define OTGFS_GINT_RES89 (3 << 8) /* Bits 8-9: Reserved, must be kept at reset value */
+#define OTGFS_GINT_RES89 (3 << 8) /* Bits 8-9: Reserved, must be kept at reset value */
#define OTGFS_GINT_ESUSP (1 << 10) /* Bit 10: rc_w1 Early suspend */
#define OTGFS_GINT_USBSUSP (1 << 11) /* Bit 11: rc_w1 USB suspend */
#define OTGFS_GINT_USBRST (1 << 12) /* Bit 12: rc_w1 USB reset */
#define OTGFS_GINT_ENUMDNE (1 << 13) /* Bit 13: rc_w1 Enumeration done */
#define OTGFS_GINT_ISOODRP (1 << 14) /* Bit 14: rc_w1 Isochronous OUT packet dropped interrupt */
#define OTGFS_GINT_EOPF (1 << 15) /* Bit 15: rc_w1 End of periodic frame interrupt */
-#define OTGFS_GINT_RES16 (1 << 16) /* Bits 16 Reserved, must be kept at reset value */
-#define OTGFS_GINTMSK_EPMISM (1 << 17) /* Bit 17: Reserved in GINT rw Endpoint mismatch interrupt mask */
-#define OTGFS_GINT_IEP (1 << 18) /* Bit 18: ro IN endpoint interrupt */
-#define OTGFS_GINT_OEP (1 << 19) /* Bit 19: ro OUT endpoint interrupt */
-#define OTGFS_GINT_IISOIXFR (1 << 20) /* Bit 20: rc_w1Incomplete isochronous IN transfer */
-#define OTGFS_GINT_IISOOXFR (1 << 21) /* Bit 21: rc_w1 Incomplete isochronous OUT transfer */
-#define OTGFS_GINT_RES2223 (3 << 22) /* Bits 22-23: Reserved, must be kept at reset value */
-#define OTGFS_GINT_HPRT (1 << 24) /* Bit 24: ro Host port interrupt */
-#define OTGFS_GINT_HC (1 << 25) /* Bit 25: ro Host channels interrupt */
-#define OTGFS_GINT_PTXFE (1 << 26) /* Bit 26: ro Periodic TxFIFO empty */
+#define OTGFS_GINT_RES16 (1 << 16) /* Bit 16 Reserved, must be kept at reset value */
+#define OTGFS_GINTMSK_EPMISM (1 << 17) /* Bit 17: Reserved in GINT rw Endpoint mismatch interrupt mask */
+#define OTGFS_GINT_IEP (1 << 18) /* Bit 18: ro IN endpoint interrupt */
+#define OTGFS_GINT_OEP (1 << 19) /* Bit 19: ro OUT endpoint interrupt */
+#define OTGFS_GINT_IISOIXFR (1 << 20) /* Bit 20: rc_w1 Incomplete isochronous IN transfer */
+#define OTGFS_GINT_IISOOXFR (1 << 21) /* Bit 21: rc_w1 Incomplete isochronous OUT transfer (device) */
+#define OTGFS_GINT_IPXFR (1 << 21) /* Bit 21: Incomplete periodic transfer (host) */
+#if defined(CONFIG_STM32_STM32F446) || defined(CONFIG_STM32_STM32F469)
+# define OTGFS_GINT_RES22 (1 << 22) /* Bits 22: Reserved, must be kept at reset value */
+# define OTGFS_GINT_RSTDET (1 << 23) /* Bits 23: asserted when a reset is detected on the USB in partial */
+#else
+# define OTGFS_GINT_RES2223 (3 << 22) /* Bits 22-23: Reserved, must be kept at reset value */
+#endif
+#define OTGFS_GINT_HPRT (1 << 24) /* Bit 24: ro Host port interrupt */
+#define OTGFS_GINT_HC (1 << 25) /* Bit 25: ro Host channels interrupt */
+#define OTGFS_GINT_PTXFE (1 << 26) /* Bit 26: ro Periodic TxFIFO empty */
+#if defined(CONFIG_STM32_STM32F446) || defined(CONFIG_STM32_STM32F469)
+#define OTGFS_GINT_LPMINT (1 << 27) /* Bit 27 LPM interrupt */
+#else
#define OTGFS_GINT_RES27 (1 << 27) /* Bit 27 Reserved, must be kept at reset value */
+#endif
#define OTGFS_GINT_CIDSCHG (1 << 28) /* Bit 28: rc_w1 Connector ID status change */
#define OTGFS_GINT_DISC (1 << 29) /* Bit 29: rc_w1 Disconnect detected interrupt */
#define OTGFS_GINT_SRQ (1 << 30) /* Bit 30: rc_w1 Session request/new session detected interrupt */
diff --git a/arch/arm/src/stm32/stm32_dac.c b/arch/arm/src/stm32/stm32_dac.c
index fdcbaf050a9..796bb81d213 100644
--- a/arch/arm/src/stm32/stm32_dac.c
+++ b/arch/arm/src/stm32/stm32_dac.c
@@ -472,7 +472,7 @@ static struct dac_dev_s g_dac2dev =
#endif
#ifdef CONFIG_STM32_DAC2
-/* Channel 1 */
+/* Channel 3 */
static struct stm32_chan_s g_dac3priv =
{
@@ -514,9 +514,18 @@ static struct stm32_dac_s g_dacblock;
static inline void stm32_dac_modify_cr(FAR struct stm32_chan_s *chan,
uint32_t clearbits, uint32_t setbits)
{
- uint32_t shift;
+ unsigned int shift;
- shift = chan->intf * 16;
+ /* DAC1 channels 1 and 2 share the STM32_DAC[1]_CR control register. DAC2
+ * channel 1 (and perhaps channel 2) uses the STM32_DAC2_CR control
+ * register. In either case, bit 0 of the interface number provides the
+ * correct shift.
+ *
+ * Bit 0 = 0: Shift = 0
+ * Bit 0 = 1: Shift = 16
+ */
+
+ shift = (chan->intf & 1) << 4;
modifyreg32(chan->cr, clearbits << shift, setbits << shift);
}
diff --git a/arch/arm/src/stm32/stm32_eth.c b/arch/arm/src/stm32/stm32_eth.c
index 635940ac95c..52dcaacd728 100644
--- a/arch/arm/src/stm32/stm32_eth.c
+++ b/arch/arm/src/stm32/stm32_eth.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/stm32/stm32_eth.c
*
- * Copyright (C) 2011-2012, 2014 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2011-2012, 2014, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -53,14 +53,11 @@
#include
#include
#include
-
-#ifdef CONFIG_NET_NOINTS
-# include
-#endif
-
+#include
#include
#include
#include
+
#if defined(CONFIG_NET_PKT)
# include
#endif
@@ -97,13 +94,12 @@
* is required.
*/
-#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
+#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
-#endif
+#else
-/* Select work queue */
+ /* Select work queue */
-#if defined(CONFIG_SCHED_WORKQUEUE)
# if defined(CONFIG_STM32_ETHMAC_HPWORK)
# define ETHWORK HPWORK
# elif defined(CONFIG_STM32_ETHMAC_LPWORK)
@@ -207,12 +203,6 @@
#undef CONFIG_STM32_ETH_ENHANCEDDESC
#undef CONFIG_STM32_ETH_HWCHECKSUM
-/* Ethernet buffer sizes, number of buffers, and number of descriptors */
-
-#ifndef CONFIG_NET_MULTIBUFFER
-# error "CONFIG_NET_MULTIBUFFER is required"
-#endif
-
/* Add 4 to the configured buffer size to account for the 2 byte checksum
* memory needed at the end of the maximum size packet. Buffer sizes must
* be an even multiple of 4, 8, or 16 bytes (depending on buswidth). We
@@ -593,9 +583,7 @@ struct stm32_ethmac_s
uint8_t fduplex : 1; /* Full (vs. half) duplex */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
-#ifdef CONFIG_NET_NOINTS
struct work_s work; /* For deferring work to the work queue */
-#endif
/* This holds the information visible to the NuttX network */
@@ -668,34 +656,26 @@ static int stm32_recvframe(FAR struct stm32_ethmac_s *priv);
static void stm32_receive(FAR struct stm32_ethmac_s *priv);
static void stm32_freeframe(FAR struct stm32_ethmac_s *priv);
static void stm32_txdone(FAR struct stm32_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void stm32_interrupt_work(FAR void *arg);
-#endif
static int stm32_interrupt(int irq, FAR void *context);
/* Watchdog timer expirations */
-static inline void stm32_txtimeout_process(FAR struct stm32_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void stm32_txtimeout_work(FAR void *arg);
-#endif
static void stm32_txtimeout_expiry(int argc, uint32_t arg, ...);
-static inline void stm32_poll_process(FAR struct stm32_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void stm32_poll_work(FAR void *arg);
-#endif
static void stm32_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int stm32_ifup(struct net_driver_s *dev);
static int stm32_ifdown(struct net_driver_s *dev);
-static inline void stm32_txavail_process(FAR struct stm32_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void stm32_txavail_work(FAR void *arg);
-#endif
static int stm32_txavail(struct net_driver_s *dev);
+
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
static int stm32_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
#endif
@@ -1970,27 +1950,33 @@ static void stm32_txdone(FAR struct stm32_ethmac_s *priv)
}
/****************************************************************************
- * Function: stm32_interrupt_process
+ * Function: stm32_interrupt_work
*
* Description:
- * Interrupt processing. This may be performed either within the interrupt
- * handler or on the worker thread, depending upon the configuration
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void stm32_interrupt_process(FAR struct stm32_ethmac_s *priv)
+static void stm32_interrupt_work(FAR void *arg)
{
+ FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)arg;
uint32_t dmasr;
+ DEBUGASSERT(priv);
+
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
+
/* Get the DMA interrupt status bits (no MAC interrupts are expected) */
dmasr = stm32_getreg(STM32_ETH_DMASR);
@@ -2062,44 +2048,13 @@ static inline void stm32_interrupt_process(FAR struct stm32_ethmac_s *priv)
stm32_putreg(ETH_DMAINT_AIS, STM32_ETH_DMASR);
}
#endif
-}
-/****************************************************************************
- * Function: stm32_interrupt_work
- *
- * Description:
- * Perform interrupt related work from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() was called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void stm32_interrupt_work(FAR void *arg)
-{
- FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)arg;
- net_lock_t state;
-
- DEBUGASSERT(priv);
-
- /* Process pending Ethernet interrupts */
-
- state = net_lock();
- stm32_interrupt_process(priv);
- net_unlock(state);
+ net_unlock();
/* Re-enable Ethernet interrupts at the NVIC */
up_enable_irq(STM32_IRQ_ETH);
}
-#endif
/****************************************************************************
* Function: stm32_interrupt
@@ -2121,8 +2076,6 @@ static void stm32_interrupt_work(FAR void *arg)
static int stm32_interrupt(int irq, FAR void *context)
{
FAR struct stm32_ethmac_s *priv = &g_stm32ethmac[0];
-
-#ifdef CONFIG_NET_NOINTS
uint32_t dmasr;
/* Get the DMA interrupt status bits (no MAC interrupts are expected) */
@@ -2158,49 +2111,9 @@ static int stm32_interrupt(int irq, FAR void *context)
work_queue(ETHWORK, &priv->work, stm32_interrupt_work, priv, 0);
}
-#else
- /* Process the interrupt now */
-
- stm32_interrupt_process(priv);
-#endif
-
return OK;
}
-/****************************************************************************
- * Function: stm32_txtimeout_process
- *
- * Description:
- * Process a TX timeout. Called from the either the watchdog timer
- * expiration logic or from the worker thread, depending upon the
- * configuration. The timeout means that the last TX never completed.
- * Reset the hardware and start again.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Global interrupts are disabled by the watchdog logic.
- *
- ****************************************************************************/
-
-static inline void stm32_txtimeout_process(FAR struct stm32_ethmac_s *priv)
-{
- /* Then reset the hardware. Just take the interface down, then back
- * up again.
- */
-
- stm32_ifdown(&priv->dev);
- stm32_ifup(&priv->dev);
-
- /* Then poll for new XMIT data */
-
- stm32_dopoll(priv);
-}
-
/****************************************************************************
* Function: stm32_txtimeout_work
*
@@ -2218,19 +2131,21 @@ static inline void stm32_txtimeout_process(FAR struct stm32_ethmac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void stm32_txtimeout_work(FAR void *arg)
{
FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)arg;
- net_lock_t state;
- /* Process pending Ethernet interrupts */
+ /* Reset the hardware. Just take the interface down, then back up again. */
- state = net_lock();
- stm32_txtimeout_process(priv);
- net_unlock(state);
+ net_lock();
+ stm32_ifdown(&priv->dev);
+ stm32_ifup(&priv->dev);
+
+ /* Then poll for new XMIT data */
+
+ stm32_dopoll(priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: stm32_txtimeout_expiry
@@ -2257,7 +2172,6 @@ static void stm32_txtimeout_expiry(int argc, uint32_t arg, ...)
nerr("ERROR: Timeout!\n");
-#ifdef CONFIG_NET_NOINTS
/* Disable further Ethernet interrupts. This will prevent some race
* conditions with interrupt work. There is still a potential race
* condition with interrupt work that is already queued and in progress.
@@ -2276,33 +2190,28 @@ static void stm32_txtimeout_expiry(int argc, uint32_t arg, ...)
/* Schedule to perform the TX timeout processing on the worker thread. */
work_queue(ETHWORK, &priv->work, stm32_txtimeout_work, priv, 0);
-
-#else
- /* Process the timeout now */
-
- stm32_txtimeout_process(priv);
-#endif
}
/****************************************************************************
- * Function: stm32_poll_process
+ * Function: stm32_poll_work
*
* Description:
- * Perform the periodic poll. This may be called either from watchdog
- * timer logic or from the worker thread, depending upon the configuration.
+ * Perform periodic polling from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() as called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
+ * Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void stm32_poll_process(FAR struct stm32_ethmac_s *priv)
+static void stm32_poll_work(FAR void *arg)
{
+ FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)arg;
FAR struct net_driver_s *dev = &priv->dev;
/* Check if the next TX descriptor is owned by the Ethernet DMA or CPU. We
@@ -2316,6 +2225,7 @@ static inline void stm32_poll_process(FAR struct stm32_ethmac_s *priv)
* CONFIG_STM32_ETH_NTXDESC).
*/
+ net_lock();
if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0 &&
priv->txhead->tdes2 == 0)
{
@@ -2351,39 +2261,9 @@ static inline void stm32_poll_process(FAR struct stm32_ethmac_s *priv)
/* Setup the watchdog poll timer again */
(void)wd_start(priv->txpoll, STM32_WDDELAY, stm32_poll_expiry, 1, priv);
+ net_unlock();
}
-/****************************************************************************
- * Function: stm32_poll_work
- *
- * Description:
- * Perform periodic polling from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() as called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void stm32_poll_work(FAR void *arg)
-{
- FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)arg;
- net_lock_t state;
-
- /* Perform the poll */
-
- state = net_lock();
- stm32_poll_process(priv);
- net_unlock(state);
-}
-#endif
-
/****************************************************************************
* Function: stm32_poll_expiry
*
@@ -2406,7 +2286,6 @@ static void stm32_poll_expiry(int argc, uint32_t arg, ...)
{
FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions.
*/
@@ -2425,12 +2304,6 @@ static void stm32_poll_expiry(int argc, uint32_t arg, ...)
(void)wd_start(priv->txpoll, STM32_WDDELAY, stm32_poll_expiry, 1, (uint32_t)priv);
}
-
-#else
- /* Process the interrupt now */
-
- stm32_poll_process(priv);
-#endif
}
/****************************************************************************
@@ -2535,37 +2408,6 @@ static int stm32_ifdown(struct net_driver_s *dev)
return OK;
}
-/****************************************************************************
- * Function: stm32_txavail_process
- *
- * Description:
- * Perform an out-of-cycle poll.
- *
- * Parameters:
- * priv - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called in normal user mode
- *
- ****************************************************************************/
-
-static inline void stm32_txavail_process(FAR struct stm32_ethmac_s *priv)
-{
- ninfo("ifup: %d\n", priv->ifup);
-
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
- {
- /* Poll the network for new XMIT data */
-
- stm32_dopoll(priv);
- }
-}
-
/****************************************************************************
* Function: stm32_txavail_work
*
@@ -2583,19 +2425,24 @@ static inline void stm32_txavail_process(FAR struct stm32_ethmac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void stm32_txavail_work(FAR void *arg)
{
FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)arg;
- net_lock_t state;
- /* Perform the poll */
+ ninfo("ifup: %d\n", priv->ifup);
- state = net_lock();
- stm32_txavail_process(priv);
- net_unlock(state);
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->ifup)
+ {
+ /* Poll the network for new XMIT data */
+
+ stm32_dopoll(priv);
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: stm32_txavail
@@ -2620,7 +2467,6 @@ static int stm32_txavail(struct net_driver_s *dev)
{
FAR struct stm32_ethmac_s *priv = (FAR struct stm32_ethmac_s *)dev->d_private;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions and we will have to ignore the Tx
* availability action.
@@ -2633,21 +2479,6 @@ static int stm32_txavail(struct net_driver_s *dev)
work_queue(ETHWORK, &priv->work, stm32_txavail_work, priv, 0);
}
-#else
- irqstate_t flags;
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
- */
-
- flags = enter_critical_section();
-
- /* Perform the out-of-cycle poll now */
-
- stm32_txavail_process(priv);
- leave_critical_section(flags);
-#endif
-
return OK;
}
diff --git a/arch/arm/src/stm32/stm32_otgfsdev.c b/arch/arm/src/stm32/stm32_otgfsdev.c
index c570e6d084f..2fcbf599f06 100644
--- a/arch/arm/src/stm32/stm32_otgfsdev.c
+++ b/arch/arm/src/stm32/stm32_otgfsdev.c
@@ -153,25 +153,50 @@
# error "CONFIG_USBDEV_EP3_TXFIFO_SIZE is out of range"
#endif
-#define OTGFS_GINT_RESERVED (OTGFS_GINT_RES89 | \
- (OTGFS_GINT_RES16 | OTGFS_GINTMSK_EPMISM) \
- |OTGFS_GINT_RES2223 | \
- OTGFS_GINT_RES27)
+#if defined(CONFIG_STM32_STM32F446) || defined(CONFIG_STM32_STM32F469)
+# define OTGFS_GINT_RESETS (OTGFS_GINT_USBRST | OTGFS_GINT_RSTDET)
+# define OTGFS_GINT_RESERVED (OTGFS_GINT_RES89 | \
+ (OTGFS_GINT_RES16 | OTGFS_GINTMSK_EPMISM) \
+ |OTGFS_GINT_RES22)
-#define OTGFS_GINT_RC_W1 (OTGFS_GINT_MMIS | \
- OTGFS_GINT_SOF | \
- OTGFS_GINT_ESUSP | \
- OTGFS_GINT_USBSUSP | \
- OTGFS_GINT_USBRST | \
- OTGFS_GINT_ENUMDNE | \
- OTGFS_GINT_ISOODRP | \
- OTGFS_GINT_EOPF | \
- OTGFS_GINT_IISOIXFR | \
- OTGFS_GINT_IISOOXFR | \
- OTGFS_GINT_CIDSCHG | \
- OTGFS_GINT_DISC | \
- OTGFS_GINT_SRQ | \
- OTGFS_GINT_WKUP)
+# define OTGFS_GINT_RC_W1 (OTGFS_GINT_MMIS | \
+ OTGFS_GINT_SOF | \
+ OTGFS_GINT_ESUSP | \
+ OTGFS_GINT_USBSUSP | \
+ OTGFS_GINT_USBRST | \
+ OTGFS_GINT_ENUMDNE | \
+ OTGFS_GINT_ISOODRP | \
+ OTGFS_GINT_EOPF | \
+ OTGFS_GINT_IISOIXFR | \
+ OTGFS_GINT_IISOOXFR | \
+ OTGFS_GINT_RSTDET | \
+ OTGFS_GINT_LPMINT | \
+ OTGFS_GINT_CIDSCHG | \
+ OTGFS_GINT_DISC | \
+ OTGFS_GINT_SRQ | \
+ OTGFS_GINT_WKUP)
+#else
+# define OTGFS_GINT_RESETS OTGFS_GINT_USBRST
+# define OTGFS_GINT_RESERVED (OTGFS_GINT_RES89 | \
+ (OTGFS_GINT_RES16 | OTGFS_GINTMSK_EPMISM) \
+ |OTGFS_GINT_RES2223 | \
+ OTGFS_GINT_RES27)
+
+# define OTGFS_GINT_RC_W1 (OTGFS_GINT_MMIS | \
+ OTGFS_GINT_SOF | \
+ OTGFS_GINT_ESUSP | \
+ OTGFS_GINT_USBSUSP | \
+ OTGFS_GINT_USBRST | \
+ OTGFS_GINT_ENUMDNE | \
+ OTGFS_GINT_ISOODRP | \
+ OTGFS_GINT_EOPF | \
+ OTGFS_GINT_IISOIXFR | \
+ OTGFS_GINT_IISOOXFR | \
+ OTGFS_GINT_CIDSCHG | \
+ OTGFS_GINT_DISC | \
+ OTGFS_GINT_SRQ | \
+ OTGFS_GINT_WKUP)
+#endif
/* Debug ***********************************************************************/
/* Trace error codes */
@@ -3517,7 +3542,7 @@ static inline void stm32_otginterrupt(FAR struct stm32_usbdev_s *priv)
/* Clear OTG interrupt */
- stm32_putreg(retval, STM32_OTGFS_GOTGINT);
+ stm32_putreg(regval, STM32_OTGFS_GOTGINT);
}
#endif
@@ -3642,7 +3667,7 @@ static int stm32_usbinterrupt(int irq, FAR void *context)
/* USB reset interrupt */
- if ((regval & OTGFS_GINT_USBRST) != 0)
+ if ((regval & OTGFS_GINT_RESETS) != 0)
{
usbtrace(TRACE_INTDECODE(STM32_TRACEINTID_DEVRESET), (uint16_t)regval);
@@ -5201,9 +5226,9 @@ static void stm32_hwinitialize(FAR struct stm32_usbdev_s *priv)
/* Deactivate the power down */
-#if defined(CONFIG_STM32_STM32F446)
- /* In the case of the STM32F446 the meaning of the bit has changed to VBUS
- * Detection Enable when set
+#if defined(CONFIG_STM32_STM32F446) || defined(CONFIG_STM32_STM32F469)
+ /* In the case of the STM32F446 or STM32F469 the meaning of the bit
+ * has changed to VBUS Detection Enable when set
*/
regval = OTGFS_GCCFG_PWRDWN;
@@ -5228,11 +5253,11 @@ static void stm32_hwinitialize(FAR struct stm32_usbdev_s *priv)
stm32_putreg(regval, STM32_OTGFS_GCCFG);
up_mdelay(20);
- /* For the new OTG controller in the F446 when VBUS sensing is not used we
+ /* For the new OTG controller in the F446, F469 when VBUS sensing is not used we
* need to force the B session valid
*/
-#if defined(CONFIG_STM32_STM32F446)
+#if defined(CONFIG_STM32_STM32F446) || defined(CONFIG_STM32_STM32F469)
# ifndef CONFIG_USBDEV_VBUSSENSING
regval = stm32_getreg(STM32_OTGFS_GOTGCTL);
regval |= (OTGFS_GOTGCTL_BVALOEN | OTGFS_GOTGCTL_BVALOVAL);
diff --git a/arch/arm/src/stm32/stm32_otghshost.c b/arch/arm/src/stm32/stm32_otghshost.c
index aec4fc37d5a..9dee00ae45c 100644
--- a/arch/arm/src/stm32/stm32_otghshost.c
+++ b/arch/arm/src/stm32/stm32_otghshost.c
@@ -139,11 +139,16 @@
/* HCD Setup *******************************************************************/
/* Hardware capabilities */
-#define STM32_NHOST_CHANNELS 12 /* Number of host channels */
+#if defined(CONFIG_STM32_STM32F446)
+# define STM32_NHOST_CHANNELS 16 /* Number of host channels */
+# define STM32_MAX_TX_FIFOS 16 /* Max number of TX FIFOs */
+#else
+# define STM32_NHOST_CHANNELS 12 /* Number of host channels */
+# define STM32_MAX_TX_FIFOS 12 /* Max number of TX FIFOs */
+#endif
#define STM32_MAX_PACKET_SIZE 64 /* Full speed max packet size */
#define STM32_EP0_DEF_PACKET_SIZE 8 /* EP0 default packet size */
#define STM32_EP0_MAX_PACKET_SIZE 64 /* EP0 HS max packet size */
-#define STM32_MAX_TX_FIFOS 12 /* Max number of TX FIFOs */
#define STM32_MAX_PKTCOUNT 256 /* Max packet count */
#define STM32_RETRY_COUNT 3 /* Number of ctrl transfer retries */
diff --git a/arch/arm/src/stm32/stm32_rtcounter.c b/arch/arm/src/stm32/stm32_rtcounter.c
index 137e7344a03..1c90be9c14d 100644
--- a/arch/arm/src/stm32/stm32_rtcounter.c
+++ b/arch/arm/src/stm32/stm32_rtcounter.c
@@ -378,13 +378,12 @@ int up_rtc_initialize(void)
*/
stm32_pwr_enablebkp(true);
-
- /* Set access to the peripheral, enable the backup domain (BKP) and the lower
- * power external 32,768Hz (Low-Speed External, LSE) oscillator. Configure the
- * LSE to drive the RTC.
- */
-
- stm32_rcc_enablelse();
+
+ /* Select the lower power external 32,768Hz (Low-Speed External, LSE) oscillator
+ * as RTC Clock Source and enable the Clock */
+
+ modifyreg16(STM32_RCC_BDCR, RCC_BDCR_RTCSEL_MASK, RCC_BDCR_RTCSEL_LSE);
+ modifyreg16(STM32_RCC_BDCR, 0, RCC_BDCR_RTCEN);
/* TODO: Get state from this function, if everything is
* okay and whether it is already enabled (if it was disabled
diff --git a/arch/arm/src/stm32/stm32_sdio.c b/arch/arm/src/stm32/stm32_sdio.c
index be060c70263..9d93a432c03 100644
--- a/arch/arm/src/stm32/stm32_sdio.c
+++ b/arch/arm/src/stm32/stm32_sdio.c
@@ -149,18 +149,27 @@
#define SDIO_CLKCR_RISINGEDGE (0)
#define SDIO_CLKCR_FALLINGEDGE SDIO_CLKCR_NEGEDGE
+/* Use the default of the rising edge but allow a configuration,
+ * that does not have the errata, to override the edge the SDIO
+ * command and data is changed on.
+ */
+
+#if !defined(SDIO_CLKCR_EDGE)
+# define SDIO_CLKCR_EDGE SDIO_CLKCR_RISINGEDGE
+#endif
+
/* Mode dependent settings. These depend on clock devisor settings that must
* be defined in the board-specific board.h header file: SDIO_INIT_CLKDIV,
* SDIO_MMCXFR_CLKDIV, and SDIO_SDXFR_CLKDIV.
*/
-#define STM32_CLCKCR_INIT (SDIO_INIT_CLKDIV | SDIO_CLKCR_RISINGEDGE | \
+#define STM32_CLCKCR_INIT (SDIO_INIT_CLKDIV | SDIO_CLKCR_EDGE | \
SDIO_CLKCR_WIDBUS_D1)
-#define SDIO_CLKCR_MMCXFR (SDIO_MMCXFR_CLKDIV | SDIO_CLKCR_RISINGEDGE | \
+#define SDIO_CLKCR_MMCXFR (SDIO_MMCXFR_CLKDIV | SDIO_CLKCR_EDGE | \
SDIO_CLKCR_WIDBUS_D1)
-#define SDIO_CLCKR_SDXFR (SDIO_SDXFR_CLKDIV | SDIO_CLKCR_RISINGEDGE | \
+#define SDIO_CLCKR_SDXFR (SDIO_SDXFR_CLKDIV | SDIO_CLKCR_EDGE | \
SDIO_CLKCR_WIDBUS_D1)
-#define SDIO_CLCKR_SDWIDEXFR (SDIO_SDXFR_CLKDIV | SDIO_CLKCR_RISINGEDGE | \
+#define SDIO_CLCKR_SDWIDEXFR (SDIO_SDXFR_CLKDIV | SDIO_CLKCR_EDGE | \
SDIO_CLKCR_WIDBUS_D4)
/* Timing */
diff --git a/arch/arm/src/stm32/stm32_usbhost.h b/arch/arm/src/stm32/stm32_usbhost.h
index 7c036a8fa61..04a64190be9 100644
--- a/arch/arm/src/stm32/stm32_usbhost.h
+++ b/arch/arm/src/stm32/stm32_usbhost.h
@@ -46,7 +46,7 @@
#include
#include "chip.h"
-#include "chip/stm32_otgfs.h"
+#include "chip/stm32fxxxxx_otgfs.h"
#include "chip/stm32_otghs.h"
#if (defined(CONFIG_STM32_OTGFS) || defined(CONFIG_STM32_OTGHS)) && defined(CONFIG_USBHOST)
diff --git a/arch/arm/src/stm32/stm32f10xxx_rcc.c b/arch/arm/src/stm32/stm32f10xxx_rcc.c
index 736b3ee7ef8..218e534e222 100644
--- a/arch/arm/src/stm32/stm32f10xxx_rcc.c
+++ b/arch/arm/src/stm32/stm32f10xxx_rcc.c
@@ -756,12 +756,6 @@ static void stm32_stdclockconfig(void)
stm32_rcc_enablelsi();
#endif
-
-#if defined(CONFIG_RTC_LSECLOCK)
- /* Low speed external clock source LSE */
-
- stm32_rcc_enablelse();
-#endif
}
#endif
@@ -774,6 +768,14 @@ static inline void rcc_enableperipherals(void)
rcc_enableahb();
rcc_enableapb2();
rcc_enableapb1();
+
+#if defined(CONFIG_RTC_LSECLOCK)
+ /* Low speed external clock source LSE
+ * For F1 it requires PWR and BKP from APB1
+ */
+
+ stm32_rcc_enablelse();
+#endif
}
/****************************************************************************
diff --git a/arch/arm/src/stm32/stm32f40xxx_rcc.c b/arch/arm/src/stm32/stm32f40xxx_rcc.c
index 347d8a3d62b..abb44313c89 100644
--- a/arch/arm/src/stm32/stm32f40xxx_rcc.c
+++ b/arch/arm/src/stm32/stm32f40xxx_rcc.c
@@ -725,7 +725,7 @@ static void stm32_stdclockconfig(void)
#else /* if STM32_BOARD_USEHSE */
| RCC_PLLCFG_PLLSRC_HSE
#endif
-#if defined(CONFIG_STM32_STM32F446)
+#if defined(STM32_PLLCFG_PLLR)
| STM32_PLLCFG_PLLR
#endif
);
@@ -743,7 +743,8 @@ static void stm32_stdclockconfig(void)
{
}
-#if defined(CONFIG_STM32_STM32F429) || defined(CONFIG_STM32_STM32F446)
+#if defined(PWR_CSR_ODRDY)
+
/* Enable the Over-drive to extend the clock frequency to 180 Mhz */
regval = getreg32(STM32_PWR_CR);
@@ -783,12 +784,12 @@ static void stm32_stdclockconfig(void)
{
}
-#if defined(CONFIG_STM32_LTDC) || \
- (defined(CONFIG_STM32_STM32F446) && defined(CONFIG_STM32_SAIPLL))
+#if defined(CONFIG_STM32_LTDC) || defined(CONFIG_STM32_SAIPLL)
+
/* Configure PLLSAI */
regval = getreg32(STM32_RCC_PLLSAICFGR);
-#if defined(CONFIG_STM32_STM32F446)
+# if defined(CONFIG_STM32_STM32F446)
regval &= ~(RCC_PLLSAICFGR_PLLSAIM_MASK
| RCC_PLLSAICFGR_PLLSAIN_MASK
| RCC_PLLSAICFGR_PLLSAIP_MASK
@@ -797,35 +798,64 @@ static void stm32_stdclockconfig(void)
| STM32_RCC_PLLSAICFGR_PLLSAIN
| STM32_RCC_PLLSAICFGR_PLLSAIP
| STM32_RCC_PLLSAICFGR_PLLSAIQ);
-#else
+# elif defined(CONFIG_STM32_STM32F469)
regval &= ~(RCC_PLLSAICFGR_PLLSAIN_MASK
- | RCC_PLLSAICFGR_PLLSAIR_MASK
- | RCC_PLLSAICFGR_PLLSAIQ_MASK);
+ | RCC_PLLSAICFGR_PLLSAIP_MASK
+ | RCC_PLLSAICFGR_PLLSAIQ_MASK
+ | RCC_PLLSAICFGR_PLLSAIR_MASK);
regval |= (STM32_RCC_PLLSAICFGR_PLLSAIN
- | STM32_RCC_PLLSAICFGR_PLLSAIR
- | STM32_RCC_PLLSAICFGR_PLLSAIQ);
-#endif
+ | STM32_RCC_PLLSAICFGR_PLLSAIP
+ | STM32_RCC_PLLSAICFGR_PLLSAIQ
+ | STM32_RCC_PLLSAICFGR_PLLSAIR);
+# else
+ regval &= ~(RCC_PLLSAICFGR_PLLSAIN_MASK
+ | RCC_PLLSAICFGR_PLLSAIQ_MASK
+ | RCC_PLLSAICFGR_PLLSAIR_MASK);
+ regval |= (STM32_RCC_PLLSAICFGR_PLLSAIN
+ | STM32_RCC_PLLSAICFGR_PLLSAIQ
+ | STM32_RCC_PLLSAICFGR_PLLSAIR);
+# endif
putreg32(regval, STM32_RCC_PLLSAICFGR);
regval = getreg32(STM32_RCC_DCKCFGR);
-#if defined(CONFIG_STM32_STM32F446)
+# if defined(CONFIG_STM32_STM32F446)
regval &= ~(RCC_DCKCFGR_PLLI2SDIVQ_MASK
- | RCC_DCKCFGR_PLLSAIDIVQ_MASK
- | RCC_DCKCFGR_SAI1SRC_MASK
- | RCC_DCKCFGR_SAI2SRC_MASK
- | RCC_DCKCFGR_I2S1SRC_MASK
- | RCC_DCKCFGR_I2S2SRC_MASK);
+ | RCC_DCKCFGR_PLLSAIDIVQ_MASK
+ | RCC_DCKCFGR_SAI1SRC_MASK
+ | RCC_DCKCFGR_SAI2SRC_MASK
+ | RCC_DCKCFGR_TIMPRE
+ | RCC_DCKCFGR_I2S1SRC_MASK
+ | RCC_DCKCFGR_I2S2SRC_MASK);
regval |= (STM32_RCC_DCKCFGR_PLLI2SDIVQ
- | STM32_RCC_DCKCFGR_PLLSAIDIVQ
- | STM32_RCC_DCKCFGR_SAI1SRC
- | STM32_RCC_DCKCFGR_SAI2SRC
- | STM32_RCC_DCKCFGR_TIMPRE
- | STM32_RCC_DCKCFGR_I2S1SRC
- | STM32_RCC_DCKCFGR_I2S2SRC);
-#else
+ | STM32_RCC_DCKCFGR_PLLSAIDIVQ
+ | STM32_RCC_DCKCFGR_SAI1SRC
+ | STM32_RCC_DCKCFGR_SAI2SRC
+ | STM32_RCC_DCKCFGR_TIMPRE
+ | STM32_RCC_DCKCFGR_I2S1SRC
+ | STM32_RCC_DCKCFGR_I2S2SRC);
+# elif defined(CONFIG_STM32_STM32F469)
+ regval &= ~(RCC_DCKCFGR_PLLI2SDIVQ_MASK
+ | RCC_DCKCFGR_PLLSAIDIVQ_MASK
+ | RCC_DCKCFGR_PLLSAIDIVR_MASK
+ | RCC_DCKCFGR_SAI1ASRC_MASK
+ | RCC_DCKCFGR_SAI1BSRC_MASK
+ | RCC_DCKCFGR_TIMPRE
+ | RCC_DCKCFGR_48MSEL_MASK
+ | RCC_DCKCFGR_SDMMCSEL_MASK
+ | RCC_DCKCFGR_DSISEL_MASK);
+ regval |= (STM32_RCC_DCKCFGR_PLLI2SDIVQ
+ | STM32_RCC_DCKCFGR_PLLSAIDIVQ
+ | STM32_RCC_DCKCFGR_PLLSAIDIVR
+ | STM32_RCC_DCKCFGR_SAI1ASRC
+ | STM32_RCC_DCKCFGR_SAI1BSRC
+ | STM32_RCC_DCKCFGR_TIMPRE
+ | STM32_RCC_DCKCFGR_48MSEL
+ | STM32_RCC_DCKCFGR_SDMMCSEL
+ | STM32_RCC_DCKCFGR_DSISEL);
+# else
regval &= ~RCC_DCKCFGR_PLLSAIDIVR_MASK;
regval |= STM32_RCC_DCKCFGR_PLLSAIDIVR;
-#endif
+# endif
putreg32(regval, STM32_RCC_DCKCFGR);
/* Enable PLLSAI */
@@ -841,34 +871,54 @@ static void stm32_stdclockconfig(void)
}
#endif
-#if defined(CONFIG_STM32_STM32F446) && defined(CONFIG_STM32_I2SPLL)
+#if defined(CONFIG_STM32_I2SPLL)
+
/* Configure PLLI2S */
regval = getreg32(STM32_RCC_PLLI2SCFGR);
+
+# if defined(CONFIG_STM32_STM32F446)
+
regval &= ~(RCC_PLLI2SCFGR_PLLI2SM_MASK
- | RCC_PLLI2SCFGR_PLLI2SN_MASK
- | RCC_PLLI2SCFGR_PLLI2SP_MASK
- | RCC_PLLI2SCFGR_PLLI2SQ_MASK);
+ | RCC_PLLI2SCFGR_PLLI2SN_MASK
+ | RCC_PLLI2SCFGR_PLLI2SP_MASK
+ | RCC_PLLI2SCFGR_PLLI2SQ_MASK
+ | RCC_PLLI2SCFGR_PLLI2SR_MASK);
regval |= (STM32_RCC_PLLI2SCFGR_PLLI2SM
- | STM32_RCC_PLLI2SCFGR_PLLI2SN
- | STM32_RCC_PLLI2SCFGR_PLLI2SP
- | STM32_RCC_PLLI2SCFGR_PLLI2SQ
- | STM32_RCC_PLLI2SCFGR_PLLI2SR);
+ | STM32_RCC_PLLI2SCFGR_PLLI2SN
+ | STM32_RCC_PLLI2SCFGR_PLLI2SP
+ | STM32_RCC_PLLI2SCFGR_PLLI2SQ
+ | STM32_RCC_PLLI2SCFGR_PLLI2SR);
+
+# elif defined(CONFIG_STM32_STM32F469)
+
+ regval &= ~(RCC_PLLI2SCFGR_PLLI2SN_MASK
+ | RCC_PLLI2SCFGR_PLLI2SQ_MASK
+ | RCC_PLLI2SCFGR_PLLI2SR_MASK);
+ regval |= (STM32_RCC_PLLI2SCFGR_PLLI2SN
+ | STM32_RCC_PLLI2SCFGR_PLLI2SQ
+ | STM32_RCC_PLLI2SCFGR_PLLI2SR);
+# endif
+
putreg32(regval, STM32_RCC_PLLI2SCFGR);
+# if defined(STM32_RCC_DCKCFGR2)
+
regval = getreg32(STM32_RCC_DCKCFGR2);
+
regval &= ~(RCC_DCKCFGR2_FMPI2C1SEL_MASK
- | RCC_DCKCFGR2_CECSEL_MASK
- | RCC_DCKCFGR2_CK48MSEL_MASK
- | RCC_DCKCFGR2_SDIOSEL_MASK
- | RCC_DCKCFGR2_SPDIFRXSEL_MASK);
+ | RCC_DCKCFGR2_CECSEL_MASK
+ | RCC_DCKCFGR2_CK48MSEL_MASK
+ | RCC_DCKCFGR2_SDIOSEL_MASK
+ | RCC_DCKCFGR2_SPDIFRXSEL_MASK);
regval |= (STM32_RCC_DCKCFGR2_FMPI2C1SEL
- | STM32_RCC_DCKCFGR2_CECSEL
- | STM32_RCC_DCKCFGR2_CK48MSEL
- | STM32_RCC_DCKCFGR2_SDIOSEL
- | STM32_RCC_DCKCFGR2_SPDIFRXSEL);
+ | STM32_RCC_DCKCFGR2_CECSEL
+ | STM32_RCC_DCKCFGR2_CK48MSEL
+ | STM32_RCC_DCKCFGR2_SDIOSEL
+ | STM32_RCC_DCKCFGR2_SPDIFRXSEL);
putreg32(regval, STM32_RCC_DCKCFGR2);
+# endif
/* Enable PLLI2S */
diff --git a/arch/arm/src/stm32f7/stm32_ethernet.c b/arch/arm/src/stm32f7/stm32_ethernet.c
index eccf15b348f..b84e8511ac8 100644
--- a/arch/arm/src/stm32f7/stm32_ethernet.c
+++ b/arch/arm/src/stm32f7/stm32_ethernet.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/stm32f7/stm32_ethernet.c
*
- * Copyright (C) 2015 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2015-2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -52,14 +52,11 @@
#include
#include
#include
-
-#ifdef CONFIG_NET_NOINTS
-# include
-#endif
-
+#include
#include
#include
#include
+
#if defined(CONFIG_NET_PKT)
# include
#endif
@@ -98,13 +95,12 @@
* is required.
*/
-#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
+#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
-#endif
+#else
-/* Select work queue */
+ /* Select work queue */
-#if defined(CONFIG_SCHED_WORKQUEUE)
# if defined(CONFIG_STM32F7_ETHMAC_HPWORK)
# define ETHWORK HPWORK
# elif defined(CONFIG_STM32F7_ETHMAC_LPWORK)
@@ -194,12 +190,6 @@
#undef CONFIG_STM32F7_ETH_ENHANCEDDESC
#undef CONFIG_STM32F7_ETH_HWCHECKSUM
-/* Ethernet buffer sizes, number of buffers, and number of descriptors */
-
-#ifndef CONFIG_NET_MULTIBUFFER
-# error "CONFIG_NET_MULTIBUFFER is required"
-#endif
-
/* Add 4 to the configured buffer size to account for the 2 byte checksum
* memory needed at the end of the maximum size packet. Buffer sizes must
* be an even multiple of 4, 8, or 16 bytes (depending on buswidth). We
@@ -617,9 +607,7 @@ struct stm32_ethmac_s
uint8_t intf; /* Ethernet interface number */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
-#ifdef CONFIG_NET_NOINTS
struct work_s work; /* For deferring work to the work queue */
-#endif
/* This holds the information visible to the NuttX network */
@@ -711,35 +699,26 @@ static int stm32_recvframe(struct stm32_ethmac_s *priv);
static void stm32_receive(struct stm32_ethmac_s *priv);
static void stm32_freeframe(struct stm32_ethmac_s *priv);
static void stm32_txdone(struct stm32_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void stm32_interrupt_work(void *arg);
-#endif
static int stm32_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static inline void stm32_txtimeout_process(struct stm32_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void stm32_txtimeout_work(void *arg);
-#endif
static void stm32_txtimeout_expiry(int argc, uint32_t arg, ...);
-static inline void stm32_poll_process(struct stm32_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void stm32_poll_work(void *arg);
-#endif
static void stm32_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int stm32_ifup(struct net_driver_s *dev);
static int stm32_ifdown(struct net_driver_s *dev);
-static int stm32_ifdown(struct net_driver_s *dev);
-static inline void stm32_txavail_process(struct stm32_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void stm32_txavail_work(void *arg);
-#endif
static int stm32_txavail(struct net_driver_s *dev);
+
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
static int stm32_addmac(struct net_driver_s *dev, const uint8_t *mac);
#endif
@@ -2084,27 +2063,33 @@ static void stm32_txdone(struct stm32_ethmac_s *priv)
}
/****************************************************************************
- * Function: stm32_interrupt_process
+ * Function: stm32_interrupt_work
*
* Description:
- * Interrupt processing. This may be performed either within the interrupt
- * handler or on the worker thread, depending upon the configuration
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void stm32_interrupt_process(struct stm32_ethmac_s *priv)
+static void stm32_interrupt_work(void *arg)
{
+ struct stm32_ethmac_s *priv = (struct stm32_ethmac_s *)arg;
uint32_t dmasr;
+ DEBUGASSERT(priv);
+
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
+
/* Get the DMA interrupt status bits (no MAC interrupts are expected) */
dmasr = stm32_getreg(STM32_ETH_DMASR);
@@ -2175,44 +2160,13 @@ static inline void stm32_interrupt_process(struct stm32_ethmac_s *priv)
stm32_putreg(ETH_DMAINT_AIS, STM32_ETH_DMASR);
}
#endif
-}
-/****************************************************************************
- * Function: stm32_interrupt_work
- *
- * Description:
- * Perform interrupt related work from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() was called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void stm32_interrupt_work(void *arg)
-{
- struct stm32_ethmac_s *priv = (struct stm32_ethmac_s *)arg;
- net_lock_t state;
-
- DEBUGASSERT(priv);
-
- /* Process pending Ethernet interrupts */
-
- state = net_lock();
- stm32_interrupt_process(priv);
- net_unlock(state);
+ net_unlock();
/* Re-enable Ethernet interrupts at the NVIC */
up_enable_irq(STM32_IRQ_ETH);
}
-#endif
/****************************************************************************
* Function: stm32_interrupt
@@ -2234,8 +2188,6 @@ static void stm32_interrupt_work(void *arg)
static int stm32_interrupt(int irq, void *context)
{
struct stm32_ethmac_s *priv = &g_stm32ethmac[0];
-
-#ifdef CONFIG_NET_NOINTS
uint32_t dmasr;
/* Get the DMA interrupt status bits (no MAC interrupts are expected) */
@@ -2271,49 +2223,9 @@ static int stm32_interrupt(int irq, void *context)
work_queue(ETHWORK, &priv->work, stm32_interrupt_work, priv, 0);
}
-#else
- /* Process the interrupt now */
-
- stm32_interrupt_process(priv);
-#endif
-
return OK;
}
-/****************************************************************************
- * Function: stm32_txtimeout_process
- *
- * Description:
- * Process a TX timeout. Called from the either the watchdog timer
- * expiration logic or from the worker thread, depending upon the
- * configuration. The timeout means that the last TX never completed.
- * Reset the hardware and start again.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Global interrupts are disabled by the watchdog logic.
- *
- ****************************************************************************/
-
-static inline void stm32_txtimeout_process(struct stm32_ethmac_s *priv)
-{
- /* Then reset the hardware. Just take the interface down, then back
- * up again.
- */
-
- stm32_ifdown(&priv->dev);
- stm32_ifup(&priv->dev);
-
- /* Then poll for new XMIT data */
-
- stm32_dopoll(priv);
-}
-
/****************************************************************************
* Function: stm32_txtimeout_work
*
@@ -2331,19 +2243,21 @@ static inline void stm32_txtimeout_process(struct stm32_ethmac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void stm32_txtimeout_work(void *arg)
{
struct stm32_ethmac_s *priv = (struct stm32_ethmac_s *)arg;
- net_lock_t state;
- /* Process pending Ethernet interrupts */
+ /* Reset the hardware. Just take the interface down, then back up again. */
- state = net_lock();
- stm32_txtimeout_process(priv);
- net_unlock(state);
+ net_lock();
+ stm32_ifdown(&priv->dev);
+ stm32_ifup(&priv->dev);
+
+ /* Then poll for new XMIT data */
+
+ stm32_dopoll(priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: stm32_txtimeout_expiry
@@ -2370,7 +2284,6 @@ static void stm32_txtimeout_expiry(int argc, uint32_t arg, ...)
nerr("ERROR: Timeout!\n");
-#ifdef CONFIG_NET_NOINTS
/* Disable further Ethernet interrupts. This will prevent some race
* conditions with interrupt work. There is still a potential race
* condition with interrupt work that is already queued and in progress.
@@ -2389,33 +2302,28 @@ static void stm32_txtimeout_expiry(int argc, uint32_t arg, ...)
/* Schedule to perform the TX timeout processing on the worker thread. */
work_queue(ETHWORK, &priv->work, stm32_txtimeout_work, priv, 0);
-
-#else
- /* Process the timeout now */
-
- stm32_txtimeout_process(priv);
-#endif
}
/****************************************************************************
- * Function: stm32_poll_process
+ * Function: stm32_poll_work
*
* Description:
- * Perform the periodic poll. This may be called either from watchdog
- * timer logic or from the worker thread, depending upon the configuration.
+ * Perform periodic polling from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() as called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
+ * Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void stm32_poll_process(struct stm32_ethmac_s *priv)
+static void stm32_poll_work(void *arg)
{
+ struct stm32_ethmac_s *priv = (struct stm32_ethmac_s *)arg;
struct net_driver_s *dev = &priv->dev;
/* Check if the next TX descriptor is owned by the Ethernet DMA or CPU. We
@@ -2429,6 +2337,7 @@ static inline void stm32_poll_process(struct stm32_ethmac_s *priv)
* CONFIG_STM32F7_ETH_NTXDESC).
*/
+ net_lock();
if ((priv->txhead->tdes0 & ETH_TDES0_OWN) == 0 &&
priv->txhead->tdes2 == 0)
{
@@ -2464,39 +2373,9 @@ static inline void stm32_poll_process(struct stm32_ethmac_s *priv)
/* Setup the watchdog poll timer again */
(void)wd_start(priv->txpoll, STM32_WDDELAY, stm32_poll_expiry, 1, priv);
+ net_unlock();
}
-/****************************************************************************
- * Function: stm32_poll_work
- *
- * Description:
- * Perform periodic polling from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() as called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void stm32_poll_work(void *arg)
-{
- struct stm32_ethmac_s *priv = (struct stm32_ethmac_s *)arg;
- net_lock_t state;
-
- /* Perform the poll */
-
- state = net_lock();
- stm32_poll_process(priv);
- net_unlock(state);
-}
-#endif
-
/****************************************************************************
* Function: stm32_poll_expiry
*
@@ -2519,7 +2398,6 @@ static void stm32_poll_expiry(int argc, uint32_t arg, ...)
{
struct stm32_ethmac_s *priv = (struct stm32_ethmac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions.
*/
@@ -2538,12 +2416,6 @@ static void stm32_poll_expiry(int argc, uint32_t arg, ...)
(void)wd_start(priv->txpoll, STM32_WDDELAY, stm32_poll_expiry, 1, (uint32_t)priv);
}
-
-#else
- /* Process the interrupt now */
-
- stm32_poll_process(priv);
-#endif
}
/****************************************************************************
@@ -2648,38 +2520,6 @@ static int stm32_ifdown(struct net_driver_s *dev)
return OK;
}
-/****************************************************************************
- * Function: stm32_txavail_process
- *
- * Description:
- * Perform an out-of-cycle poll.
- *
- * Parameters:
- * priv - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called in normal user mode
- *
- ****************************************************************************/
-
-static inline void stm32_txavail_process(struct stm32_ethmac_s *priv)
-{
- ninfo("ifup: %d\n", priv->ifup);
-
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
- {
- /* Poll the network for new XMIT data */
-
- stm32_dopoll(priv);
- }
-
-}
-
/****************************************************************************
* Function: stm32_txavail_work
*
@@ -2697,19 +2537,24 @@ static inline void stm32_txavail_process(struct stm32_ethmac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void stm32_txavail_work(void *arg)
{
struct stm32_ethmac_s *priv = (struct stm32_ethmac_s *)arg;
- net_lock_t state;
- /* Perform the poll */
+ ninfo("ifup: %d\n", priv->ifup);
- state = net_lock();
- stm32_txavail_process(priv);
- net_unlock(state);
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->ifup)
+ {
+ /* Poll the network for new XMIT data */
+
+ stm32_dopoll(priv);
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: stm32_txavail
@@ -2734,7 +2579,6 @@ static int stm32_txavail(struct net_driver_s *dev)
{
struct stm32_ethmac_s *priv = (struct stm32_ethmac_s *)dev->d_private;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions and we will have to ignore the Tx
* availability action.
@@ -2747,21 +2591,6 @@ static int stm32_txavail(struct net_driver_s *dev)
work_queue(ETHWORK, &priv->work, stm32_txavail_work, priv, 0);
}
-#else
- irqstate_t flags;
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
- */
-
- flags = enter_critical_section();
-
- /* Perform the out-of-cycle poll now */
-
- stm32_txavail_process(priv);
- leave_critical_section(flags);
-#endif
-
return OK;
}
diff --git a/arch/arm/src/stm32f7/stm32_sdmmc.c b/arch/arm/src/stm32f7/stm32_sdmmc.c
index 52e7ef38788..2df98c10a94 100644
--- a/arch/arm/src/stm32f7/stm32_sdmmc.c
+++ b/arch/arm/src/stm32f7/stm32_sdmmc.c
@@ -154,7 +154,16 @@
/* Friendly CLKCR bit re-definitions ****************************************/
#define STM32_CLKCR_RISINGEDGE (0)
-#define STM32_CLKCR_FALLINGEDGE STM32_CLKCR_NEGEDGE
+#define STM32_CLKCR_FALLINGEDGE STM32_SDMMC_CLKCR_NEGEDGE
+
+/* Use the default of the rising edge but allow a configuration,
+ * that does not have the errata, to override the edge the SDIO
+ * command and data is changed on.
+ */
+
+#if !defined(STM32_SDMMC_CLKCR_EDGE)
+# define STM32_SDMMC_CLKCR_EDGE STM32_CLKCR_RISINGEDGE
+#endif
/* Mode dependent settings. These depend on clock divisor settings that must
* be defined in the board-specific board.h header file: STM32_SDMMC_INIT_CLKDIV,
@@ -162,16 +171,16 @@
*/
#define STM32_CLCKCR_INIT (STM32_SDMMC_INIT_CLKDIV | \
- STM32_CLKCR_RISINGEDGE | \
+ STM32_SDMMC_CLKCR_EDGE | \
STM32_SDMMC_CLKCR_WIDBUS_D1)
#define STM32_SDMMC_CLKCR_MMCXFR (STM32_SDMMC_MMCXFR_CLKDIV | \
- STM32_CLKCR_RISINGEDGE | \
+ STM32_SDMMC_CLKCR_EDGE | \
STM32_SDMMC_CLKCR_WIDBUS_D1)
#define STM32_SDMMC_CLCKR_SDXFR (STM32_SDMMC_SDXFR_CLKDIV | \
- STM32_CLKCR_RISINGEDGE | \
+ STM32_SDMMC_CLKCR_EDGE | \
STM32_SDMMC_CLKCR_WIDBUS_D1)
#define STM32_SDMMC_CLCKR_SDWIDEXFR (STM32_SDMMC_SDXFR_CLKDIV | \
- STM32_CLKCR_RISINGEDGE | \
+ STM32_SDMMC_CLKCR_EDGE | \
STM32_SDMMC_CLKCR_WIDBUS_D4)
/* Timing */
diff --git a/arch/arm/src/stm32l4/Kconfig b/arch/arm/src/stm32l4/Kconfig
index 6995a514218..9f8d6cbda11 100644
--- a/arch/arm/src/stm32l4/Kconfig
+++ b/arch/arm/src/stm32l4/Kconfig
@@ -44,6 +44,8 @@ config STM32L4_STM32L476XX
select ARCH_HAVE_DPFPU # REVISIT
select ARMV7M_HAVE_ITCM
select ARMV7M_HAVE_DTCM
+ select STM32L4_HAVE_USART1
+ select STM32L4_HAVE_USART2
select STM32L4_HAVE_USART3
select STM32L4_HAVE_UART4
select STM32L4_HAVE_UART5
@@ -55,6 +57,8 @@ config STM32L4_STM32L486XX
select ARCH_HAVE_DPFPU # REVISIT
select ARMV7M_HAVE_ITCM
select ARMV7M_HAVE_DTCM
+ select STM32L4_HAVE_USART1
+ select STM32L4_HAVE_USART2
select STM32L4_HAVE_USART3
select STM32L4_HAVE_UART4
select STM32L4_HAVE_UART5
@@ -408,15 +412,17 @@ config STM32L4_SPI3
config STM32L4_USART1
bool "USART1"
default n
- select USART1_SERIALDRIVER
+ depends on STM32L4_HAVE_USART1
select ARCH_HAVE_SERIAL_TERMIOS
+ select USART1_SERIALDRIVER
select STM32L4_USART
config STM32L4_USART2
bool "USART2"
default n
- select USART2_SERIALDRIVER
+ depends on STM32L4_HAVE_USART2
select ARCH_HAVE_SERIAL_TERMIOS
+ select USART2_SERIALDRIVER
select STM32L4_USART
config STM32L4_USART3
@@ -2517,6 +2523,14 @@ config STM32L4_DAC_DMA_BUFFER_SIZE
endmenu
+config STM32L4_HAVE_USART1
+ bool
+ default n
+
+config STM32L4_HAVE_USART2
+ bool
+ default n
+
config STM32L4_HAVE_USART3
bool
default n
diff --git a/arch/arm/src/stm32l4/stm32l4_serial.c b/arch/arm/src/stm32l4/stm32l4_serial.c
index 8e4b8d3bee9..dfef76a9b10 100644
--- a/arch/arm/src/stm32l4/stm32l4_serial.c
+++ b/arch/arm/src/stm32l4/stm32l4_serial.c
@@ -731,7 +731,7 @@ static struct stm32l4_serial_s g_uart5priv =
/* This table lets us iterate over the configured USARTs */
-FAR static struct stm32l4_serial_s * const uart_devs[STM32L4_NUSART] =
+FAR static struct stm32l4_serial_s * const uart_devs[STM32L4_NUSART+STM32L4_NUART] =
{
#ifdef CONFIG_STM32L4_USART1
[0] = &g_usart1priv,
@@ -2407,7 +2407,7 @@ void up_earlyserialinit(void)
/* Disable all USART interrupts */
- for (i = 0; i < STM32L4_NUSART; i++)
+ for (i = 0; i < STM32L4_NUSART+STM32L4_NUART; i++)
{
if (uart_devs[i])
{
@@ -2476,7 +2476,7 @@ void up_serialinit(void)
strcpy(devname, "/dev/ttySx");
- for (i = 0; i < STM32L4_NUSART; i++)
+ for (i = 0; i < STM32L4_NUSART+STM32L4_NUART; i++)
{
/* Don't create a device for non-configured ports. */
diff --git a/arch/arm/src/stm32l4/stm32l4_uart.h b/arch/arm/src/stm32l4/stm32l4_uart.h
index 24fc9bd3136..e66302d8e4d 100644
--- a/arch/arm/src/stm32l4/stm32l4_uart.h
+++ b/arch/arm/src/stm32l4/stm32l4_uart.h
@@ -57,19 +57,19 @@
* device.
*/
-#if STM32L4_NUSART < 5 || !defined(CONFIG_STM32L4_HAVE_UART5)
+#if !defined(CONFIG_STM32L4_HAVE_UART5)
# undef CONFIG_STM32L4_UART5
#endif
-#if STM32L4_NUSART < 4 || !defined(CONFIG_STM32L4_HAVE_UART4)
+#if !defined(CONFIG_STM32L4_HAVE_UART4)
# undef CONFIG_STM32L4_UART4
#endif
-#if STM32L4_NUSART < 3 || !defined(CONFIG_STM32L4_HAVE_USART3)
+#if !defined(CONFIG_STM32L4_HAVE_USART3)
# undef CONFIG_STM32L4_USART3
#endif
-#if STM32L4_NUSART < 2
+#if !defined(CONFIG_STM32L4_HAVE_USART2)
# undef CONFIG_STM32L4_USART2
#endif
-#if STM32L4_NUSART < 1
+#if !defined(CONFIG_STM32L4_HAVE_USART1)
# undef CONFIG_STM32L4_USART1
#endif
diff --git a/arch/arm/src/tiva/Kconfig b/arch/arm/src/tiva/Kconfig
index 78a7ae07f17..fb82d1fb5a3 100644
--- a/arch/arm/src/tiva/Kconfig
+++ b/arch/arm/src/tiva/Kconfig
@@ -911,6 +911,26 @@ config TIVA_BADCRC
---help---
Set to enable bad CRC rejection.
+choice
+ prompt "Work queue"
+ default LM3S_ETHERNET_LPWORK if SCHED_LPWORK
+ default LM3S_ETHERNET_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
+ depends on SCHED_WORKQUEUE
+ ---help---
+ Work queue support is required to use the Ethernet driver. If the
+ low priority work queue is available, then it should be used by the
+ driver.
+
+config LM3S_ETHERNET_HPWORK
+ bool "High priority"
+ depends on SCHED_HPWORK
+
+config LM3S_ETHERNET_LPWORK
+ bool "Low priority"
+ depends on SCHED_LPWORK
+
+endchoice # Work queue
+
config TIVA_DUMPPACKET
bool "Dump Packets"
default n
@@ -1119,6 +1139,7 @@ config TIVA_ETHERNET_LPWORK
depends on SCHED_LPWORK
endchoice # Work queue
+
config TIVA_ETHERNET_REGDEBUG
bool "Register-Level Debug"
default n
diff --git a/arch/arm/src/tiva/lm3s_ethernet.c b/arch/arm/src/tiva/lm3s_ethernet.c
index cbdf0dac530..bfe8f2669d9 100644
--- a/arch/arm/src/tiva/lm3s_ethernet.c
+++ b/arch/arm/src/tiva/lm3s_ethernet.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/arm/src/tiva/lm3s_ethernet.c
*
- * Copyright (C) 2009-2010, 2014 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2009-2010, 2014, 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -52,6 +52,8 @@
#include
#include
#include
+#include
+
#include
#include
#include
@@ -71,6 +73,25 @@
* Pre-processor Definitions
****************************************************************************/
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
+#else
+
+ /* Use the low priority work queue if possible */
+
+# if defined(CONFIG_LM3S_ETHERNET_HPWORK)
+# define ETHWORK HPWORK
+# elif defined(CONFIG_LM3S_ETHERNET_LPWORK)
+# define ETHWORK LPWORK
+# else
+# error Neither CONFIG_LM3S_ETHERNET_HPWORK nor CONFIG_LM3S_ETHERNET_LPWORK defined
+# endif
+#endif
+
/* Half duplex can be forced if CONFIG_TIVA_ETHHDUPLEX is defined. */
#ifdef CONFIG_TIVA_ETHHDUPLEX
@@ -181,6 +202,7 @@ struct tiva_driver_s
bool ld_bifup; /* true:ifup false:ifdown */
WDOG_ID ld_txpoll; /* TX poll timer */
WDOG_ID ld_txtimeout; /* TX timeout timer */
+ struct work_s ld_work; /* For deferring work to the work queue */
/* This holds the information visible to the NuttX network */
@@ -191,11 +213,9 @@ struct tiva_driver_s
* Private Data
****************************************************************************/
-#ifdef CONFIG_NET_MULTIBUFFER
/* A single packet buffer is used */
static uint8_t g_pktbuf[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
-#endif
/* Ethernet peripheral state */
@@ -229,21 +249,29 @@ static int tiva_txpoll(struct net_driver_s *dev);
static void tiva_receive(struct tiva_driver_s *priv);
static void tiva_txdone(struct tiva_driver_s *priv);
-static int tiva_interrupt(int irq, FAR void *context);
+
+static void tiva_interrupt_work(void *arg);
+static int tiva_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static void tiva_polltimer(int argc, uint32_t arg, ...);
-static void tiva_txtimeout(int argc, uint32_t arg, ...);
+static void tiva_txtimeout_work(void *arg);
+static void tiva_txtimeout_expiry(int argc, uint32_t arg, ...);
+
+static void tiva_poll_work(void *arg);
+static void tiva_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int tiva_ifup(struct net_driver_s *dev);
static int tiva_ifdown(struct net_driver_s *dev);
+
+static void tiva_txavail_work(void *arg);
static int tiva_txavail(struct net_driver_s *dev);
+
#ifdef CONFIG_NET_IGMP
-static int tiva_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
-static int tiva_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac);
+static int tiva_addmac(struct net_driver_s *dev, const uint8_t *mac);
+static int tiva_rmmac(struct net_driver_s *dev, const uint8_t *mac);
#endif
/****************************************************************************
@@ -549,7 +577,8 @@ static int tiva_transmit(struct tiva_driver_s *priv)
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
- (void)wd_start(priv->ld_txtimeout, TIVA_TXTIMEOUT, tiva_txtimeout, 1, (uint32_t)priv);
+ (void)wd_start(priv->ld_txtimeout, TIVA_TXTIMEOUT,
+ tiva_txtimeout_expiry, 1, (uint32_t)priv);
ret = OK;
}
@@ -915,32 +944,30 @@ static void tiva_txdone(struct tiva_driver_s *priv)
}
/****************************************************************************
- * Function: tiva_interrupt
+ * Function: tiva_interrupt_work
*
* Description:
- * Hardware interrupt handler
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * irq - Number of the IRQ that generated the interrupt
- * context - Interrupt register state save info (architecture-specific)
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
* OK on success
*
* Assumptions:
+ * The network is locked.
*
****************************************************************************/
-static int tiva_interrupt(int irq, FAR void *context)
+static void tiva_interrupt_work(void *arg)
{
- register struct tiva_driver_s *priv;
+ struct tiva_driver_s *priv = (struct tiva_driver_s *)arg;
uint32_t ris;
-#if TIVA_NETHCONTROLLERS > 1
-# error "A mechanism to associate and interface with an IRQ is needed"
-#else
- priv = &g_lm3sdev[0];
-#endif
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
/* Read the raw interrupt status register */
@@ -997,15 +1024,126 @@ static int tiva_interrupt(int irq, FAR void *context)
tiva_txdone(priv);
}
- /* Enable Ethernet interrupts (perhaps excluding the TX done interrupt if
- * there are no pending transmissions).
+ net_unlock();
+
+ /* Re-enable Ethernet interrupts */
+
+#if TIVA_NETHCONTROLLERS > 1
+ up_disable_irq(priv->irq);
+#else
+ up_disable_irq(TIVA_IRQ_ETHCON);
+#endif
+}
+
+/****************************************************************************
+ * Function: tiva_interrupt
+ *
+ * Description:
+ * Hardware interrupt handler
+ *
+ * Parameters:
+ * irq - Number of the IRQ that generated the interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int tiva_interrupt(int irq, void *context)
+{
+ struct tiva_driver_s *priv;
+ uint32_t ris;
+
+#if TIVA_NETHCONTROLLERS > 1
+# error "A mechanism to associate and interface with an IRQ is needed"
+#else
+ priv = &g_lm3sdev[0];
+#endif
+
+ /* Disable further Ethernet interrupts. Because Ethernet interrupts are
+ * also disabled if the TX timeout event occurs, there can be no race
+ * condition here.
*/
+#if TIVA_NETHCONTROLLERS > 1
+ up_disable_irq(priv->irq);
+#else
+ up_disable_irq(TIVA_IRQ_ETHCON);
+#endif
+
+ /* Read the raw interrupt status register (masking out any disabled
+ * interrupts).
+ */
+
+ ris = tiva_ethin(priv, TIVA_MAC_RIS_OFFSET);
+ ris &= tiva_ethin(priv, TIVA_MAC_IM_OFFSET);
+
+ /* Is this an Tx interrupt (meaning that the Tx FIFO is empty)? */
+
+ if ((ris & MAC_RIS_TXEMP) != 0)
+ {
+ /* If a TX transfer just completed, then cancel the TX timeout so
+ * there will be do race condition between any subsequent timeout
+ * expiration and the deferred interrupt processing.
+ */
+
+ wd_cancel(priv->ld_txtimeout);
+ }
+
+ /* Cancel any pending poll work */
+
+ work_cancel(ETHWORK, &priv->ld_work);
+
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->ld_work, tiva_interrupt_work, priv, 0);
return OK;
}
/****************************************************************************
- * Function: tiva_txtimeout
+ * Function: tiva_txtimeout_work
+ *
+ * Description:
+ * Perform TX timeout related work from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void tiva_txtimeout_work(void *arg)
+{
+ struct tiva_driver_s *priv = (struct tiva_driver_s *)arg;
+
+ /* Increment statistics */
+
+ net_lock();
+ nerr("ERROR: Tx timeout\n");
+ NETDEV_TXTIMEOUTS(&priv->ld_dev);
+
+ /* Then reset the hardware */
+
+ DEBUGASSERT(priv->ld_bifup);
+ tiva_ifdown(&priv->ld_dev);
+ tiva_ifup(&priv->ld_dev);
+
+ /* Then poll the network for new XMIT data */
+
+ (void)devif_poll(&priv->ld_dev, tiva_txpoll);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: tiva_txtimeout_expiry
*
* Description:
* Our TX watchdog timed out. Called from the timer interrupt handler.
@@ -1019,31 +1157,85 @@ static int tiva_interrupt(int irq, FAR void *context)
* None
*
* Assumptions:
+ * Global interrupts are disabled by the watchdog logic.
*
****************************************************************************/
-static void tiva_txtimeout(int argc, uint32_t arg, ...)
+static void tiva_txtimeout_expiry(int argc, wdparm_t arg, ...)
{
struct tiva_driver_s *priv = (struct tiva_driver_s *)arg;
- /* Increment statistics */
+ /* Disable further Ethernet interrupts. This will prevent some race
+ * conditions with interrupt work. There is still a potential race
+ * condition with interrupt work that is already queued and in progress.
+ */
- nerr("ERROR: Tx timeout\n");
- NETDEV_TXTIMEOUTS(&priv->ld_dev);
+#if TIVA_NETHCONTROLLERS > 1
+ up_disable_irq(priv->irq);
+#else
+ up_disable_irq(TIVA_IRQ_ETHCON);
+#endif
- /* Then reset the hardware */
+ /* Cancel any pending poll or interrupt work. This will have no effect
+ * on work that has already been started.
+ */
- DEBUGASSERT(priv->ld_bifup);
- tiva_ifdown(&priv->ld_dev);
- tiva_ifup(&priv->ld_dev);
+ work_cancel(ETHWORK, &priv->ld_work);
- /* Then poll the network for new XMIT data */
+ /* Schedule to perform the TX timeout processing on the worker thread. */
- (void)devif_poll(&priv->ld_dev, tiva_txpoll);
+ work_queue(ETHWORK, &priv->ld_work, tiva_txtimeout_work, priv, 0);
}
/****************************************************************************
- * Function: tiva_polltimer
+ * Function: tiva_poll_work
+ *
+ * Description:
+ * Perform periodic polling from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void tiva_poll_work(void *arg)
+{
+ struct tiva_driver_s *priv = (struct tiva_driver_s *)arg;
+
+ /* Check if we can send another Tx packet now. The NEWTX bit initiates an
+ * Ethernet transmission once the packet has been placed in the TX FIFO.
+ * This bit is cleared once the transmission has been completed.
+ *
+ * NOTE: This can cause missing poll cycles and, hence, some timing
+ * inaccuracies.
+ */
+
+ net_lock();
+ if ((tiva_ethin(priv, TIVA_MAC_TR_OFFSET) & MAC_TR_NEWTX) == 0)
+ {
+ /* If so, update TCP timing states and poll the network for new XMIT
+ * data.
+ */
+
+ (void)devif_timer(&priv->ld_dev, tiva_txpoll);
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->ld_txpoll, TIVA_WDDELAY, tiva_poll_expiry,
+ 1, priv);
+ }
+
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: tiva_poll_expiry
*
* Description:
* Periodic timer handler. Called from the timer interrupt handler.
@@ -1056,30 +1248,31 @@ static void tiva_txtimeout(int argc, uint32_t arg, ...)
* None
*
* Assumptions:
+ * Global interrupts are disabled by the watchdog logic.
*
****************************************************************************/
-static void tiva_polltimer(int argc, uint32_t arg, ...)
+static void tiva_poll_expiry(int argc, wdparm_t arg, ...)
{
struct tiva_driver_s *priv = (struct tiva_driver_s *)arg;
- /* Check if we can send another Tx packet now. The NEWTX bit initiates an
- * Ethernet transmission once the packet has been placed in the TX FIFO.
- * This bit is cleared once the transmission has been completed.
- *
- * NOTE: This can cause missing poll cycles and, hence, some timing
- * inaccuracies.
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions.
*/
- if ((tiva_ethin(priv, TIVA_MAC_TR_OFFSET) & MAC_TR_NEWTX) == 0)
+ if (work_available(&priv->ld_work))
{
- /* If so, update TCP timing states and poll the network for new XMIT data */
+ /* Schedule to perform the interrupt processing on the worker thread. */
- (void)devif_timer(&priv->ld_dev, tiva_txpoll);
+ work_queue(ETHWORK, &priv->ld_work, tiva_poll_work, priv, 0);
+ }
+ else
+ {
+ /* No.. Just re-start the watchdog poll timer, missing one polling
+ * cycle.
+ */
- /* Setup the watchdog poll timer again */
-
- (void)wd_start(priv->ld_txpoll, TIVA_WDDELAY, tiva_polltimer, 1, arg);
+ (void)wd_start(priv->ld_txpoll, TIVA_WDDELAY, tiva_poll_expiry, 1, arg);
}
}
@@ -1232,7 +1425,7 @@ static int tiva_ifup(struct net_driver_s *dev)
/* Set and activate a timer process */
- (void)wd_start(priv->ld_txpoll, TIVA_WDDELAY, tiva_polltimer, 1, (uint32_t)priv);
+ (void)wd_start(priv->ld_txpoll, TIVA_WDDELAY, tiva_poll_expiry, 1, (uint32_t)priv);
priv->ld_bifup = true;
leave_critical_section(flags);
@@ -1322,6 +1515,48 @@ static int tiva_ifdown(struct net_driver_s *dev)
return OK;
}
+/****************************************************************************
+ * Function: tiva_txavail_work
+ *
+ * Description:
+ * Perform an out-of-cycle poll on the worker thread.
+ *
+ * Parameters:
+ * arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+static void tiva_txavail_work(void *arg)
+{
+ struct tiva_driver_s *priv = (struct tiva_driver_s *)arg;
+
+ /* Ignore the notification if the interface is not yet up or if the Tx FIFO
+ * hardware is not available at this time. The NEWTX bit initiates an
+ * Ethernet transmission once the packet has been placed in the TX FIFO.
+ * This bit is cleared once the transmission has been completed. When the
+ * transmission completes, tiva_txdone() will be called and the Tx polling
+ * will occur at that time.
+ */
+
+ net_lock();
+ if (priv->ld_bifup && (tiva_ethin(priv, TIVA_MAC_TR_OFFSET) & MAC_TR_NEWTX) == 0)
+ {
+ /* If the interface is up and we can use the Tx FIFO, then poll the network
+ * for new Tx data
+ */
+
+ (void)devif_poll(&priv->ld_dev, tiva_txpoll);
+ }
+
+ net_unlock();
+}
+
/****************************************************************************
* Function: tiva_txavail
*
@@ -1331,7 +1566,7 @@ static int tiva_ifdown(struct net_driver_s *dev)
* latency.
*
* Parameters:
- * dev - Reference to the NuttX driver state structure
+ * dev - Reference to the NuttX driver state structure
*
* Returned Value:
* None
@@ -1344,27 +1579,19 @@ static int tiva_ifdown(struct net_driver_s *dev)
static int tiva_txavail(struct net_driver_s *dev)
{
struct tiva_driver_s *priv = (struct tiva_driver_s *)dev->d_private;
- irqstate_t flags;
- /* Ignore the notification if the interface is not yet up or if the Tx FIFO
- * hardware is not available at this time. The NEWTX bit initiates an
- * Ethernet transmission once the packet has been placed in the TX FIFO.
- * This bit is cleared once the transmission has been completed. When the
- * transmission completes, tiva_txdone() will be called and the Tx polling
- * will occur at that time.
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
*/
- flags = enter_critical_section();
- if (priv->ld_bifup && (tiva_ethin(priv, TIVA_MAC_TR_OFFSET) & MAC_TR_NEWTX) == 0)
+ if (work_available(&priv->ld_work))
{
- /* If the interface is up and we can use the Tx FIFO, then poll the network
- * for new Tx data
- */
+ /* Schedule to serialize the poll on the worker thread. */
- (void)devif_poll(&priv->ld_dev, tiva_txpoll);
+ work_queue(ETHWORK, &priv->ld_work, tiva_txavail_work, priv, 0);
}
- leave_critical_section(flags);
return OK;
}
@@ -1387,9 +1614,9 @@ static int tiva_txavail(struct net_driver_s *dev)
****************************************************************************/
#ifdef CONFIG_NET_IGMP
-static int tiva_addmac(struct net_driver_s *dev, FAR const uint8_t *mac)
+static int tiva_addmac(struct net_driver_s *dev, const uint8_t *mac)
{
- FAR struct tiva_driver_s *priv = (FAR struct tiva_driver_s *)dev->d_private;
+ struct tiva_driver_s *priv = (struct tiva_driver_s *)dev->d_private;
/* Add the MAC address to the hardware multicast routing table */
@@ -1417,9 +1644,9 @@ static int tiva_addmac(struct net_driver_s *dev, FAR const uint8_t *mac)
****************************************************************************/
#ifdef CONFIG_NET_IGMP
-static int tiva_rmmac(struct net_driver_s *dev, FAR const uint8_t *mac)
+static int tiva_rmmac(struct net_driver_s *dev, const uint8_t *mac)
{
- FAR struct tiva_driver_s *priv = (FAR struct tiva_driver_s *)dev->d_private;
+ struct tiva_driver_s *priv = (struct tiva_driver_s *)dev->d_private;
/* Add the MAC address to the hardware multicast routing table */
@@ -1472,9 +1699,7 @@ static inline int tiva_ethinitialize(int intf)
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct tiva_driver_s));
-#ifdef CONFIG_NET_MULTIBUFFER
priv->ld_dev.d_buf = g_pktbuf; /* Single packet buffer */
-#endif
priv->ld_dev.d_ifup = tiva_ifup; /* I/F down callback */
priv->ld_dev.d_ifdown = tiva_ifdown; /* I/F up (new IP address) callback */
priv->ld_dev.d_txavail = tiva_txavail; /* New TX data callback */
diff --git a/arch/arm/src/tiva/tm4c_ethernet.c b/arch/arm/src/tiva/tm4c_ethernet.c
index 3882a95db33..a04854879d6 100644
--- a/arch/arm/src/tiva/tm4c_ethernet.c
+++ b/arch/arm/src/tiva/tm4c_ethernet.c
@@ -53,11 +53,7 @@
#include
#include
#include
-
-#ifdef CONFIG_NET_NOINTS
-# include
-#endif
-
+#include
#include
#include
#include
@@ -102,13 +98,12 @@
* is required.
*/
-#if defined(CONFIG_NET_NOINTS) && !defined(CONFIG_SCHED_WORKQUEUE)
+#if !defined(CONFIG_SCHED_WORKQUEUE)
# error Work queue support is required
-#endif
+#else
-/* Select work queue */
+ /* Select work queue */
-#if defined(CONFIG_SCHED_WORKQUEUE)
# if defined(CONFIG_TIVA_ETHERNET_HPWORK)
# define ETHWORK HPWORK
# elif defined(CONFIG_TIVA_ETHERNET_LPWORK)
@@ -219,10 +214,6 @@
/* Ethernet buffer sizes, number of buffers, and number of descriptors */
-#ifndef CONFIG_NET_MULTIBUFFER
-# error CONFIG_NET_MULTIBUFFER is required
-#endif
-
#ifndef CONFIG_TIVA_EMAC_NRXDESC
# define CONFIG_TIVA_EMAC_NRXDESC 8
#endif
@@ -635,9 +626,7 @@ struct tiva_ethmac_s
uint8_t fduplex : 1; /* Full (vs. half) duplex */
WDOG_ID txpoll; /* TX poll timer */
WDOG_ID txtimeout; /* TX timeout timer */
-#ifdef CONFIG_NET_NOINTS
struct work_s work; /* For deferring work to the work queue */
-#endif
#ifdef CONFIG_TIVA_PHY_INTERRUPTS
xcpt_t handler; /* Attached PHY interrupt handler */
#endif
@@ -713,35 +702,26 @@ static int tiva_recvframe(FAR struct tiva_ethmac_s *priv);
static void tiva_receive(FAR struct tiva_ethmac_s *priv);
static void tiva_freeframe(FAR struct tiva_ethmac_s *priv);
static void tiva_txdone(FAR struct tiva_ethmac_s *priv);
-static inline void tiva_interrupt_process(FAR struct tiva_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void tiva_interrupt_work(FAR void *arg);
-#endif
static int tiva_interrupt(int irq, FAR void *context);
/* Watchdog timer expirations */
-static inline void tiva_txtimeout_process(FAR struct tiva_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void tiva_txtimeout_work(FAR void *arg);
-#endif
static void tiva_txtimeout_expiry(int argc, uint32_t arg, ...);
-static inline void tiva_poll_process(FAR struct tiva_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
static void tiva_poll_work(FAR void *arg);
-#endif
static void tiva_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int tiva_ifup(struct net_driver_s *dev);
static int tiva_ifdown(struct net_driver_s *dev);
-static inline void tiva_txavail_process(FAR struct tiva_ethmac_s *priv);
-#ifdef CONFIG_NET_NOINTS
+
static void tiva_txavail_work(FAR void *arg);
-#endif
static int tiva_txavail(struct net_driver_s *dev);
+
#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
static int tiva_addmac(struct net_driver_s *dev, FAR const uint8_t *mac);
#endif
@@ -1998,27 +1978,33 @@ static void tiva_txdone(FAR struct tiva_ethmac_s *priv)
}
/****************************************************************************
- * Function: tiva_interrupt_process
+ * Function: tiva_interrupt_work
*
* Description:
- * Interrupt processing. This may be performed either within the interrupt
- * handler or on the worker thread, depending upon the configuration
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
* Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void tiva_interrupt_process(FAR struct tiva_ethmac_s *priv)
+static void tiva_interrupt_work(FAR void *arg)
{
+ FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)arg;
uint32_t dmaris;
+ DEBUGASSERT(priv);
+
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
+
/* Get the DMA interrupt status bits (no MAC interrupts are expected) */
dmaris = tiva_getreg(TIVA_EMAC_DMARIS);
@@ -2090,44 +2076,13 @@ static inline void tiva_interrupt_process(FAR struct tiva_ethmac_s *priv)
tiva_putreg(EMAC_DMAINT_AIS, TIVA_EMAC_DMARIS);
}
#endif
-}
-/****************************************************************************
- * Function: tiva_interrupt_work
- *
- * Description:
- * Perform interrupt related work from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() was called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void tiva_interrupt_work(FAR void *arg)
-{
- FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)arg;
- net_lock_t state;
-
- DEBUGASSERT(priv);
-
- /* Process pending Ethernet interrupts */
-
- state = net_lock();
- tiva_interrupt_process(priv);
- net_unlock(state);
+ net_unlock();
/* Re-enable Ethernet interrupts at the NVIC */
up_enable_irq(TIVA_IRQ_ETHCON);
}
-#endif
/****************************************************************************
* Function: tiva_interrupt
@@ -2149,8 +2104,6 @@ static void tiva_interrupt_work(FAR void *arg)
static int tiva_interrupt(int irq, FAR void *context)
{
FAR struct tiva_ethmac_s *priv = &g_tiva_ethmac[0];
-
-#ifdef CONFIG_NET_NOINTS
uint32_t dmaris;
/* Get the raw interrupt status. */
@@ -2186,12 +2139,6 @@ static int tiva_interrupt(int irq, FAR void *context)
work_queue(ETHWORK, &priv->work, tiva_interrupt_work, priv, 0);
}
-#else
- /* Process the interrupt now */
-
- tiva_interrupt_process(priv);
-#endif
-
#ifdef CONFIG_TIVA_PHY_INTERRUPTS
/* Check for pending PHY interrupts */
@@ -2213,38 +2160,6 @@ static int tiva_interrupt(int irq, FAR void *context)
return OK;
}
-/****************************************************************************
- * Function: tiva_txtimeout_process
- *
- * Description:
- * Process a TX timeout. Called from the either the watchdog timer
- * expiration logic or from the worker thread, depending upon the
- * configuration. The timeout means that the last TX never completed.
- * Reset the hardware and start again.
- *
- * Parameters:
- * priv - Reference to the driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Global interrupts are disabled by the watchdog logic.
- *
- ****************************************************************************/
-
-static inline void tiva_txtimeout_process(FAR struct tiva_ethmac_s *priv)
-{
- /* Reset the hardware. Just take the interface down, then back up again. */
-
- tiva_ifdown(&priv->dev);
- tiva_ifup(&priv->dev);
-
- /* Then poll the network for new XMIT data */
-
- tiva_dopoll(priv);
-}
-
/****************************************************************************
* Function: tiva_txtimeout_work
*
@@ -2262,19 +2177,21 @@ static inline void tiva_txtimeout_process(FAR struct tiva_ethmac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void tiva_txtimeout_work(FAR void *arg)
{
FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)arg;
- net_lock_t state;
- /* Process pending Ethernet interrupts */
+ /* Reset the hardware. Just take the interface down, then back up again. */
- state = net_lock();
- tiva_txtimeout_process(priv);
- net_unlock(state);
+ net_lock();
+ tiva_ifdown(&priv->dev);
+ tiva_ifup(&priv->dev);
+
+ /* Then poll the network for new XMIT data */
+
+ tiva_dopoll(priv);
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: tiva_txtimeout_expiry
@@ -2301,7 +2218,6 @@ static void tiva_txtimeout_expiry(int argc, uint32_t arg, ...)
nerr("ERROR: Timeout!\n");
-#ifdef CONFIG_NET_NOINTS
/* Disable further Ethernet interrupts. This will prevent some race
* conditions with interrupt work. There is still a potential race
* condition with interrupt work that is already queued and in progress.
@@ -2320,33 +2236,28 @@ static void tiva_txtimeout_expiry(int argc, uint32_t arg, ...)
/* Schedule to perform the TX timeout processing on the worker thread. */
work_queue(ETHWORK, &priv->work, tiva_txtimeout_work, priv, 0);
-
-#else
- /* Process the timeout now */
-
- tiva_txtimeout_process(priv);
-#endif
}
/****************************************************************************
- * Function: tiva_poll_process
+ * Function: tiva_poll_work
*
* Description:
- * Perform the periodic poll. This may be called either from watchdog
- * timer logic or from the worker thread, depending upon the configuration.
+ * Perform periodic polling from the worker thread
*
* Parameters:
- * priv - Reference to the driver state structure
+ * arg - The argument passed when work_queue() as called.
*
* Returned Value:
- * None
+ * OK on success
*
* Assumptions:
+ * Ethernet interrupts are disabled
*
****************************************************************************/
-static inline void tiva_poll_process(FAR struct tiva_ethmac_s *priv)
+static void tiva_poll_work(FAR void *arg)
{
+ FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)arg;
FAR struct net_driver_s *dev = &priv->dev;
/* Check if the next TX descriptor is owned by the Ethernet DMA or CPU. We
@@ -2360,6 +2271,7 @@ static inline void tiva_poll_process(FAR struct tiva_ethmac_s *priv)
* CONFIG_TIVA_EMAC_NTXDESC).
*/
+ net_lock();
if ((priv->txhead->tdes0 & EMAC_TDES0_OWN) == 0 &&
priv->txhead->tdes2 == 0)
{
@@ -2395,39 +2307,9 @@ static inline void tiva_poll_process(FAR struct tiva_ethmac_s *priv)
/* Setup the watchdog poll timer again */
(void)wd_start(priv->txpoll, TIVA_WDDELAY, tiva_poll_expiry, 1, (uint32_t)priv);
+ net_unlock();
}
-/****************************************************************************
- * Function: tiva_poll_work
- *
- * Description:
- * Perform periodic polling from the worker thread
- *
- * Parameters:
- * arg - The argument passed when work_queue() as called.
- *
- * Returned Value:
- * OK on success
- *
- * Assumptions:
- * Ethernet interrupts are disabled
- *
- ****************************************************************************/
-
-#ifdef CONFIG_NET_NOINTS
-static void tiva_poll_work(FAR void *arg)
-{
- FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)arg;
- net_lock_t state;
-
- /* Perform the poll */
-
- state = net_lock();
- tiva_poll_process(priv);
- net_unlock(state);
-}
-#endif
-
/****************************************************************************
* Function: tiva_poll_expiry
*
@@ -2450,7 +2332,6 @@ static void tiva_poll_expiry(int argc, uint32_t arg, ...)
{
FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)arg;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions.
*/
@@ -2469,12 +2350,6 @@ static void tiva_poll_expiry(int argc, uint32_t arg, ...)
(void)wd_start(priv->txpoll, TIVA_WDDELAY, tiva_poll_expiry, 1, (uint32_t)priv);
}
-
-#else
- /* Process the interrupt now */
-
- tiva_poll_process(priv);
-#endif
}
/****************************************************************************
@@ -2579,37 +2454,6 @@ static int tiva_ifdown(struct net_driver_s *dev)
return OK;
}
-/****************************************************************************
- * Function: tiva_txavail_process
- *
- * Description:
- * Perform an out-of-cycle poll.
- *
- * Parameters:
- * priv - Reference to the NuttX driver state structure
- *
- * Returned Value:
- * None
- *
- * Assumptions:
- * Called in normal user mode
- *
- ****************************************************************************/
-
-static inline void tiva_txavail_process(FAR struct tiva_ethmac_s *priv)
-{
- ninfo("ifup: %d\n", priv->ifup);
-
- /* Ignore the notification if the interface is not yet up */
-
- if (priv->ifup)
- {
- /* Poll the network for new XMIT data */
-
- tiva_dopoll(priv);
- }
-}
-
/****************************************************************************
* Function: tiva_txavail_work
*
@@ -2627,19 +2471,24 @@ static inline void tiva_txavail_process(FAR struct tiva_ethmac_s *priv)
*
****************************************************************************/
-#ifdef CONFIG_NET_NOINTS
static void tiva_txavail_work(FAR void *arg)
{
FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)arg;
- net_lock_t state;
- /* Perform the poll */
+ ninfo("ifup: %d\n", priv->ifup);
- state = net_lock();
- tiva_txavail_process(priv);
- net_unlock(state);
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->ifup)
+ {
+ /* Poll the network for new XMIT data */
+
+ tiva_dopoll(priv);
+ }
+
+ net_unlock();
}
-#endif
/****************************************************************************
* Function: tiva_txavail
@@ -2664,7 +2513,6 @@ static int tiva_txavail(struct net_driver_s *dev)
{
FAR struct tiva_ethmac_s *priv = (FAR struct tiva_ethmac_s *)dev->d_private;
-#ifdef CONFIG_NET_NOINTS
/* Is our single work structure available? It may not be if there are
* pending interrupt actions and we will have to ignore the Tx
* availability action.
@@ -2677,21 +2525,6 @@ static int tiva_txavail(struct net_driver_s *dev)
work_queue(ETHWORK, &priv->work, tiva_txavail_work, priv, 0);
}
-#else
- irqstate_t flags;
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
- */
-
- flags = enter_critical_section();
-
- /* Perform the out-of-cycle poll now */
-
- tiva_txavail_process(priv);
- leave_critical_section(flags);
-#endif
-
return OK;
}
diff --git a/arch/hc/src/m9s12/m9s12_ethernet.c b/arch/hc/src/m9s12/m9s12_ethernet.c
index fe2656e97a9..3a85446e6dc 100644
--- a/arch/hc/src/m9s12/m9s12_ethernet.c
+++ b/arch/hc/src/m9s12/m9s12_ethernet.c
@@ -1,7 +1,7 @@
/****************************************************************************
* arch/hc/src/m9s12/m9s12_ethernet.c
*
- * Copyright (C) 2011, 2014-2015 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2011, 2014-2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
*
* Redistribution and use in source and binary forms, with or without
@@ -106,6 +106,12 @@ struct emac_driver_s
* Private Data
****************************************************************************/
+/* A single packet buffer is used */
+
+static uint8_t g_pktbuf[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
+
+/* Driver state structure */
+
static struct emac_driver_s g_emac[CONFIG_HCS12_NINTERFACES];
/****************************************************************************
@@ -756,6 +762,7 @@ int emac_initialize(int intf)
/* Initialize the driver structure */
memset(priv, 0, sizeof(struct emac_driver_s));
+ priv->d_dev.d_buf = g_pktbuf; /* Single packet buffer */
priv->d_dev.d_ifup = emac_ifup; /* I/F down callback */
priv->d_dev.d_ifdown = emac_ifdown; /* I/F up (new IP address) callback */
priv->d_dev.d_txavail = emac_txavail; /* New TX data callback */
@@ -767,8 +774,8 @@ int emac_initialize(int intf)
/* Create a watchdog for timing polling for and timing of transmisstions */
- priv->d_txpoll = wd_create(); /* Create periodic poll timer */
- priv->d_txtimeout = wd_create(); /* Create TX timeout timer */
+ priv->d_txpoll = wd_create(); /* Create periodic poll timer */
+ priv->d_txtimeout = wd_create(); /* Create TX timeout timer */
/* Put the interface in the down state. This usually amounts to resetting
* the device and/or calling emac_ifdown().
diff --git a/arch/mips/src/pic32mx/Kconfig b/arch/mips/src/pic32mx/Kconfig
index 366c50fdf5e..52dd7745667 100644
--- a/arch/mips/src/pic32mx/Kconfig
+++ b/arch/mips/src/pic32mx/Kconfig
@@ -1094,13 +1094,6 @@ config NET_WOL
---help---
Enable Wake-up on LAN (not fully implemented).
-config NET_REGDEBUG
- bool "Register level debug"
- default n
- depends on PIC32MX_ETHERNET && DEBUG_NET_INFO
- ---help---
- Enabled low level register debug. Also needs CONFIG_DEBUG_FEATURES.
-
config NET_HASH
bool "Hash"
default n
@@ -1116,6 +1109,33 @@ config PIC32MX_MULTICAST
Enable receipt of multicast (and unicast) frames. Automatically set if
NET_IGMP is selected.
+choice
+ prompt "Work queue"
+ default PIC32MX_ETHERNET_LPWORK if SCHED_LPWORK
+ default PIC32MX_ETHERNET_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
+ depends on SCHED_WORKQUEUE
+ ---help---
+ Work queue support is required to use the Ethernet driver. If the
+ low priority work queue is available, then it should be used by the
+ driver.
+
+config PIC32MX_ETHERNET_HPWORK
+ bool "High priority"
+ depends on SCHED_HPWORK
+
+config PIC32MX_ETHERNET_LPWORK
+ bool "Low priority"
+ depends on SCHED_LPWORK
+
+endchoice # Work queue
+
+config NET_REGDEBUG
+ bool "Register level debug"
+ default n
+ depends on PIC32MX_ETHERNET && DEBUG_NET_INFO
+ ---help---
+ Enabled low level register debug. Also needs CONFIG_DEBUG_FEATURES.
+
endmenu
menu "Device Configuration 0 (DEVCFG0)"
diff --git a/arch/mips/src/pic32mx/pic32mx-ethernet.c b/arch/mips/src/pic32mx/pic32mx-ethernet.c
index 8a1bc084828..3515635f220 100644
--- a/arch/mips/src/pic32mx/pic32mx-ethernet.c
+++ b/arch/mips/src/pic32mx/pic32mx-ethernet.c
@@ -55,6 +55,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -81,6 +82,25 @@
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
+#else
+
+ /* Use the low priority work queue if possible */
+
+# if defined(CONFIG_PIC32MX_ETHERNET_HPWORK)
+# define ETHWORK HPWORK
+# elif defined(CONFIG_PIC32MX_ETHERNET_LPWORK)
+# define ETHWORK LPWORK
+# else
+# error Neither CONFIG_PIC32MX_ETHERNET_HPWORK nor CONFIG_PIC32MX_ETHERNET_LPWORK defined
+# endif
+#endif
+
/* CONFIG_PIC32MX_NINTERFACES determines the number of physical interfaces
* that will be supported -- unless it is more than actually supported by the
* hardware!
@@ -102,12 +122,6 @@
# define CONFIG_PIC32MX_NINTERFACES 1
#endif
-/* CONFIG_NET_MULTIBUFFER is required */
-
-#ifndef CONFIG_NET_MULTIBUFFER
-# error "CONFIG_NET_MULTIBUFFER=y is required"
-#endif
-
/* If IGMP is enabled, then accept multi-cast frames. */
#if defined(CONFIG_NET_IGMP) && !defined(CONFIG_PIC32MX_MULTICAST)
@@ -307,6 +321,7 @@ struct pic32mx_driver_s
uint32_t pd_inten; /* Shadow copy of INTEN register */
WDOG_ID pd_txpoll; /* TX poll timer */
WDOG_ID pd_txtimeout; /* TX timeout timer */
+ struct work_s pd_work; /* For deferring work to the work queue */
sq_queue_t pd_freebuffers; /* The free buffer list */
@@ -378,18 +393,26 @@ static void pic32mx_timerpoll(struct pic32mx_driver_s *priv);
static void pic32mx_response(struct pic32mx_driver_s *priv);
static void pic32mx_rxdone(struct pic32mx_driver_s *priv);
static void pic32mx_txdone(struct pic32mx_driver_s *priv);
+
+static void pic32mx_interrupt_work(void *arg);
static int pic32mx_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static void pic32mx_polltimer(int argc, uint32_t arg, ...);
-static void pic32mx_txtimeout(int argc, uint32_t arg, ...);
+static void pic32mx_txtimeout_work(void *arg);
+static void pic32mx_txtimeout_expiry(int argc, uint32_t arg, ...);
+
+static void pic32mx_poll_work(void *arg);
+static void pic32mx_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int pic32mx_ifup(struct net_driver_s *dev);
static int pic32mx_ifdown(struct net_driver_s *dev);
+
+static void pic32mx_txavail_work(void *arg);
static int pic32mx_txavail(struct net_driver_s *dev);
+
#ifdef CONFIG_NET_IGMP
static int pic32mx_addmac(struct net_driver_s *dev, const uint8_t *mac);
static int pic32mx_rmmac(struct net_driver_s *dev, const uint8_t *mac);
@@ -1061,8 +1084,8 @@ static int pic32mx_transmit(struct pic32mx_driver_s *priv)
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
- (void)wd_start(priv->pd_txtimeout, PIC32MX_TXTIMEOUT, pic32mx_txtimeout,
- 1, (uint32_t)priv);
+ (void)wd_start(priv->pd_txtimeout, PIC32MX_TXTIMEOUT,
+ pic32mx_txtimeout_expiry, 1, (uint32_t)priv);
return OK;
}
@@ -1640,32 +1663,30 @@ static void pic32mx_txdone(struct pic32mx_driver_s *priv)
}
/****************************************************************************
- * Function: pic32mx_interrupt
+ * Function: pic32mx_interrupt_work
*
* Description:
- * Hardware interrupt handler
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * irq - Number of the IRQ that generated the interrupt
- * context - Interrupt register state save info (architecture-specific)
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
* OK on success
*
* Assumptions:
+ * The network is locked.
*
****************************************************************************/
-static int pic32mx_interrupt(int irq, void *context)
+static void pic32mx_interrupt_work(void *arg)
{
- register struct pic32mx_driver_s *priv;
+ struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
uint32_t status;
-#if CONFIG_PIC32MX_NINTERFACES > 1
-# error "A mechanism to associate and interface with an IRQ is needed"
-#else
- priv = &g_ethdrvr[0];
-#endif
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
/* Get the interrupt status (zero means no interrupts pending). */
@@ -1795,22 +1816,136 @@ static int pic32mx_interrupt(int irq, void *context)
* (ETHCON1:0) bit to decrement the BUFCNT counter. Writing a ‘0’ or a
* ‘1’ has no effect.
*/
-
}
/* Clear the pending interrupt */
-# if CONFIG_PIC32MX_NINTERFACES > 1
+#if CONFIG_PIC32MX_NINTERFACES > 1
up_clrpend_irq(priv->pd_irqsrc);
-# else
+#else
up_clrpend_irq(PIC32MX_IRQSRC_ETH);
-# endif
+#endif
+ net_unlock();
+ /* Re-enable Ethernet interrupts */
+
+#if CONFIG_PIC32MX_NINTERFACES > 1
+ up_enable_irq(priv->pd_irqsrc);
+#else
+ up_enable_irq(PIC32MX_IRQSRC_ETH);
+#endif
+}
+
+/****************************************************************************
+ * Function: pic32mx_interrupt
+ *
+ * Description:
+ * Hardware interrupt handler
+ *
+ * Parameters:
+ * irq - Number of the IRQ that generated the interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int pic32mx_interrupt(int irq, void *context)
+{
+ struct pic32mx_driver_s *priv;
+ uint32_t status;
+
+#if CONFIG_PIC32MX_NINTERFACES > 1
+# error "A mechanism to associate an interface with an IRQ is needed"
+#else
+ priv = &g_ethdrvr[0];
+#endif
+
+ /* Disable further Ethernet interrupts. Because Ethernet interrupts are
+ * also disabled if the TX timeout event occurs, there can be no race
+ * condition here.
+ */
+
+#if CONFIG_PIC32MX_NINTERFACES > 1
+ up_disable_irq(priv->pd_irqsrc);
+#else
+ up_disable_irq(PIC32MX_IRQSRC_ETH);
+#endif
+
+ /* Get the interrupt status (zero means no interrupts pending). */
+
+ status = pic32mx_getreg(PIC32MX_ETH_IRQ);
+
+ /* Determine if a TX transfer just completed */
+
+ if ((status & ETH_INT_TXDONE) != 0)
+ {
+ /* If a TX transfer just completed, then cancel the TX timeout so
+ * there will be no race condition between any subsequent timeout
+ * expiration and the deferred interrupt processing.
+ */
+
+ wd_cancel(priv->pd_txtimeout);
+ }
+
+ /* Cancel any pending poll work */
+
+ work_cancel(HPWORK, &priv->pd_work);
+
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pd_work, pic32mx_interrupt_work, priv, 0);
return OK;
}
/****************************************************************************
- * Function: pic32mx_txtimeout
+ * Function: pic32mx_txtimeout_work
+ *
+ * Description:
+ * Perform TX timeout related work from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void pic32mx_txtimeout_work(void *arg)
+{
+ struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
+
+ /* Increment statistics and dump debug info */
+
+ net_lock();
+ NETDEV_TXTIMEOUTS(&priv->pd_dev);
+ if (priv->pd_ifup)
+ {
+ /* Then reset the hardware. ifup() will reset the interface, then bring
+ * it back up.
+ */
+
+ (void)pic32mx_ifup(&priv->pd_dev);
+
+ /* Then poll the network for new XMIT data (We are guaranteed to have
+ * a free buffer here).
+ */
+
+ pic32mx_poll(priv);
+ }
+
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: pic32mx_txtimeout_expiry
*
* Description:
* Our TX watchdog timed out. Called from the timer interrupt handler.
@@ -1828,31 +1963,77 @@ static int pic32mx_interrupt(int irq, void *context)
*
****************************************************************************/
-static void pic32mx_txtimeout(int argc, uint32_t arg, ...)
+static void pic32mx_txtimeout_expiry(int argc, wdparm_t arg, ...)
{
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
- /* Increment statistics and dump debug info */
+ /* Disable further Ethernet interrupts. This will prevent some race
+ * conditions with interrupt work. There is still a potential race
+ * condition with interrupt work that is already queued and in progress.
+ */
- NETDEV_TXTIMEOUTS(&priv->pd_dev);
- if (priv->pd_ifup)
- {
- /* Then reset the hardware. ifup() will reset the interface, then bring
- * it back up.
- */
+#if CONFIG_PIC32MX_NINTERFACES > 1
+ up_disable_irq(priv->pd_irqsrc);
+#else
+ up_disable_irq(PIC32MX_IRQSRC_ETH);
+#endif
- (void)pic32mx_ifup(&priv->pd_dev);
+ /* Cancel any pending poll or interrupt work. This will have no effect
+ * on work that has already been started.
+ */
- /* Then poll the network for new XMIT data (We are guaranteed to have a free
- * buffer here).
- */
+ work_cancel(ETHWORK, &priv->pd_work);
- pic32mx_poll(priv);
- }
+ /* Schedule to perform the TX timeout processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pd_work, pic32mx_txtimeout_work, priv, 0);
}
/****************************************************************************
- * Function: pic32mx_polltimer
+ * Function: pic32mx_poll_work
+ *
+ * Description:
+ * Perform periodic polling from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void pic32mx_poll_work(void *arg)
+{
+ struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
+
+ /* Check if the next Tx descriptor is available. We cannot perform the Tx
+ * poll if we are unable to accept another packet for transmission.
+ */
+
+ net_lock();
+ if (pic32mx_txdesc(priv) != NULL)
+ {
+ /* If so, update TCP timing states and poll the network for new XMIT data. Hmmm..
+ * might be bug here. Does this mean if there is a transmit in progress,
+ * we will missing TCP time state updates?
+ */
+
+ pic32mx_timerpoll(priv);
+ }
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_poll_expiry,
+ 1, priv);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: pic32mx_poll_expiry
*
* Description:
* Periodic timer handler. Called from the timer interrupt handler.
@@ -1869,27 +2050,29 @@ static void pic32mx_txtimeout(int argc, uint32_t arg, ...)
*
****************************************************************************/
-static void pic32mx_polltimer(int argc, uint32_t arg, ...)
+static void pic32mx_poll_expiry(int argc, wdparm_t arg, ...)
{
struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
- /* Check if the next Tx descriptor is available. We cannot perform the Tx
- * poll if we are unable to accept another packet for transmission.
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions.
*/
- if (pic32mx_txdesc(priv) != NULL)
+ if (work_available(&priv->pd_work))
{
- /* If so, update TCP timing states and poll the network for new XMIT data. Hmmm..
- * might be bug here. Does this mean if there is a transmit in progress,
- * we will missing TCP time state updates?
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pd_work, pic32mx_poll_work, priv, 0);
+ }
+ else
+ {
+ /* No.. Just re-start the watchdog poll timer, missing one polling
+ * cycle.
*/
- pic32mx_timerpoll(priv);
+ (void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_poll_expiry,
+ 1, arg);
}
-
- /* Setup the watchdog poll timer again */
-
- (void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_polltimer, 1, arg);
}
/****************************************************************************
@@ -2181,12 +2364,13 @@ static int pic32mx_ifup(struct net_driver_s *dev)
/* Set and activate a timer process */
- (void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_polltimer, 1,
+ (void)wd_start(priv->pd_txpoll, PIC32MX_WDDELAY, pic32mx_poll_expiry, 1,
(uint32_t)priv);
/* Finally, enable the Ethernet interrupt at the interrupt controller */
priv->pd_ifup = true;
+
#if CONFIG_PIC32MX_NINTERFACES > 1
up_enable_irq(priv->pd_irqsrc);
#else
@@ -2239,37 +2423,29 @@ static int pic32mx_ifdown(struct net_driver_s *dev)
}
/****************************************************************************
- * Function: pic32mx_txavail
+ * Function: pic32mx_txavail_work
*
* Description:
- * Driver callback invoked when new TX data is available. This is a
- * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
- * latency.
+ * Perform an out-of-cycle poll on the worker thread.
*
* Parameters:
- * dev - Reference to the NuttX driver state structure
+ * arg - Reference to the NuttX driver state structure (cast to void*)
*
* Returned Value:
* None
*
* Assumptions:
- * Called in normal user mode
+ * Called on the higher priority worker thread.
*
****************************************************************************/
-static int pic32mx_txavail(struct net_driver_s *dev)
+static void pic32mx_txavail_work(void *arg)
{
- struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)dev->d_private;
- irqstate_t flags;
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
- */
-
- flags = enter_critical_section();
+ struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)arg;
/* Ignore the notification if the interface is not yet up */
+ net_lock();
if (priv->pd_ifup)
{
/* Check if the next Tx descriptor is available. */
@@ -2284,7 +2460,44 @@ static int pic32mx_txavail(struct net_driver_s *dev)
}
}
- leave_critical_section(flags);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: pic32mx_txavail
+ *
+ * Description:
+ * Driver callback invoked when new TX data is available. This is a
+ * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ * latency.
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called in normal user mode
+ *
+ ****************************************************************************/
+
+static int pic32mx_txavail(struct net_driver_s *dev)
+{
+ struct pic32mx_driver_s *priv = (struct pic32mx_driver_s *)dev->d_private;
+
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
+ */
+
+ if (work_available(&priv->pd_work))
+ {
+ /* Schedule to serialize the poll on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pd_work, pic32mx_txavail_work, priv, 0);
+ }
+
return OK;
}
diff --git a/arch/mips/src/pic32mz/Kconfig b/arch/mips/src/pic32mz/Kconfig
index 70dcf7d0766..0ea6cfeae4d 100644
--- a/arch/mips/src/pic32mz/Kconfig
+++ b/arch/mips/src/pic32mz/Kconfig
@@ -265,7 +265,7 @@ config PIC32MZ_CTMU
bool "Charge Time Measurement Unit (CMTU)"
default n
-endmenu # PIC32MX Peripheral Support
+endmenu # PIC32MZ Peripheral Support
menuconfig PIC32MZ_GPIOIRQ
bool "GPIO Interrupt Support"
@@ -397,13 +397,6 @@ config NET_WOL
---help---
Enable Wake-up on LAN (not fully implemented).
-config NET_REGDEBUG
- bool "Register level debug"
- default n
- depends on PIC32MZ_ETHERNET && DEBUG_NET_INFO
- ---help---
- Enabled low level register debug. Also needs CONFIG_DEBUG_FEATURES.
-
config NET_HASH
bool "Hash"
default n
@@ -419,6 +412,33 @@ config PIC32MZ_MULTICAST
Enable receipt of multicast (and unicast) frames. Automatically set if
NET_IGMP is selected.
+choice
+ prompt "Work queue"
+ default PIC32MZ_ETHERNET_LPWORK if SCHED_LPWORK
+ default PIC32MZ_ETHERNET_HPWORK if !SCHED_LPWORK && SCHED_HPWORK
+ depends on SCHED_WORKQUEUE
+ ---help---
+ Work queue support is required to use the Ethernet driver. If the
+ low priority work queue is available, then it should be used by the
+ driver.
+
+config PIC32MZ_ETHERNET_HPWORK
+ bool "High priority"
+ depends on SCHED_HPWORK
+
+config PIC32MZ_ETHERNET_LPWORK
+ bool "Low priority"
+ depends on SCHED_LPWORK
+
+endchoice # Work queue
+
+config NET_REGDEBUG
+ bool "Register level debug"
+ default n
+ depends on PIC32MZ_ETHERNET && DEBUG_NET_INFO
+ ---help---
+ Enabled low level register debug. Also needs CONFIG_DEBUG_FEATURES.
+
endmenu # PIC32MZ PHY/Ethernet device driver settings
menu "Device Configuration 0 (DEVCFG0)"
diff --git a/arch/mips/src/pic32mz/pic32mz-ethernet.c b/arch/mips/src/pic32mz/pic32mz-ethernet.c
index b2df3654497..7eb5c4d54cf 100644
--- a/arch/mips/src/pic32mz/pic32mz-ethernet.c
+++ b/arch/mips/src/pic32mz/pic32mz-ethernet.c
@@ -55,6 +55,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -81,6 +82,25 @@
* Pre-processor Definitions
****************************************************************************/
/* Configuration ************************************************************/
+/* If processing is not done at the interrupt level, then work queue support
+ * is required.
+ */
+
+#if !defined(CONFIG_SCHED_WORKQUEUE)
+# error Work queue support is required in this configuration (CONFIG_SCHED_WORKQUEUE)
+#else
+
+ /* Use the low priority work queue if possible */
+
+# if defined(CONFIG_PIC32MZ_ETHERNET_HPWORK)
+# define ETHWORK HPWORK
+# elif defined(CONFIG_PIC32MZ_ETHERNET_LPWORK)
+# define ETHWORK LPWORK
+# else
+# error Neither CONFIG_PIC32MZ_ETHERNET_HPWORK nor CONFIG_PIC32MZ_ETHERNET_LPWORK defined
+# endif
+#endif
+
/* CONFIG_PIC32MZ_NINTERFACES determines the number of physical interfaces
* that will be supported -- unless it is more than actually supported by the
* hardware!
@@ -102,12 +122,6 @@
# define CONFIG_PIC32MZ_NINTERFACES 1
#endif
-/* CONFIG_NET_MULTIBUFFER is required */
-
-#ifndef CONFIG_NET_MULTIBUFFER
-# error "CONFIG_NET_MULTIBUFFER=y is required"
-#endif
-
/* If IGMP is enabled, then accept multi-cast frames. */
#if defined(CONFIG_NET_IGMP) && !defined(CONFIG_PIC32MZ_MULTICAST)
@@ -334,6 +348,7 @@ struct pic32mz_driver_s
uint32_t pd_inten; /* Shadow copy of INTEN register */
WDOG_ID pd_txpoll; /* TX poll timer */
WDOG_ID pd_txtimeout; /* TX timeout timer */
+ struct work_s pd_work; /* For deferring work to the work queue */
sq_queue_t pd_freebuffers; /* The free buffer list */
@@ -405,18 +420,26 @@ static void pic32mz_timerpoll(struct pic32mz_driver_s *priv);
static void pic32mz_response(struct pic32mz_driver_s *priv);
static void pic32mz_rxdone(struct pic32mz_driver_s *priv);
static void pic32mz_txdone(struct pic32mz_driver_s *priv);
+
+static void pic32mz_interrupt_work(void *arg);
static int pic32mz_interrupt(int irq, void *context);
/* Watchdog timer expirations */
-static void pic32mz_polltimer(int argc, uint32_t arg, ...);
-static void pic32mz_txtimeout(int argc, uint32_t arg, ...);
+static void pic32mz_txtimeout_work(void *arg);
+static void pic32mz_txtimeout_expiry(int argc, uint32_t arg, ...);
+
+static void pic32mz_poll_work(void *arg);
+static void pic32mz_poll_expiry(int argc, uint32_t arg, ...);
/* NuttX callback functions */
static int pic32mz_ifup(struct net_driver_s *dev);
static int pic32mz_ifdown(struct net_driver_s *dev);
+
+static void pic32mz_txavail_work(void *arg);
static int pic32mz_txavail(struct net_driver_s *dev);
+
#ifdef CONFIG_NET_IGMP
static int pic32mz_addmac(struct net_driver_s *dev, const uint8_t *mac);
static int pic32mz_rmmac(struct net_driver_s *dev, const uint8_t *mac);
@@ -1088,7 +1111,7 @@ static int pic32mz_transmit(struct pic32mz_driver_s *priv)
/* Setup the TX timeout watchdog (perhaps restarting the timer) */
- (void)wd_start(priv->pd_txtimeout, PIC32MZ_TXTIMEOUT, pic32mz_txtimeout,
+ (void)wd_start(priv->pd_txtimeout, PIC32MZ_TXTIMEOUT, pic32mz_txtimeout_expiry,
1, (uint32_t)priv);
return OK;
@@ -1667,32 +1690,30 @@ static void pic32mz_txdone(struct pic32mz_driver_s *priv)
}
/****************************************************************************
- * Function: pic32mz_interrupt
+ * Function: pic32mz_interrupt_work
*
* Description:
- * Hardware interrupt handler
+ * Perform interrupt related work from the worker thread
*
* Parameters:
- * irq - Number of the IRQ that generated the interrupt
- * context - Interrupt register state save info (architecture-specific)
+ * arg - The argument passed when work_queue() was called.
*
* Returned Value:
* OK on success
*
* Assumptions:
+ * The network is locked.
*
****************************************************************************/
-static int pic32mz_interrupt(int irq, void *context)
+static void pic32mz_interrupt_work(void *arg)
{
- register struct pic32mz_driver_s *priv;
+ struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
uint32_t status;
-#if CONFIG_PIC32MZ_NINTERFACES > 1
-# error "A mechanism to associate and interface with an IRQ is needed"
-#else
- priv = &g_ethdrvr[0];
-#endif
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
/* Get the interrupt status (zero means no interrupts pending). */
@@ -1822,22 +1843,136 @@ static int pic32mz_interrupt(int irq, void *context)
* (ETHCON1:0) bit to decrement the BUFCNT counter. Writing a ‘0’ or a
* ‘1’ has no effect.
*/
-
}
/* Clear the pending interrupt */
-# if CONFIG_PIC32MZ_NINTERFACES > 1
+#if CONFIG_PIC32MZ_NINTERFACES > 1
up_clrpend_irq(priv->pd_irqsrc);
-# else
+#else
up_clrpend_irq(PIC32MZ_IRQ_ETH);
-# endif
+#endif
+ net_unlock();
+ /* Re-enable Ethernet interrupts */
+
+#if CONFIG_PIC32MZ_NINTERFACES > 1
+ up_enable_irq(priv->pd_irqsrc);
+#else
+ up_enable_irq(PIC32MZ_IRQ_ETH);
+#endif
+}
+
+/****************************************************************************
+ * Function: pic32mz_interrupt
+ *
+ * Description:
+ * Hardware interrupt handler
+ *
+ * Parameters:
+ * irq - Number of the IRQ that generated the interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int pic32mz_interrupt(int irq, void *context)
+{
+ struct pic32mz_driver_s *priv;
+ uint32_t status;
+
+#if CONFIG_PIC32MZ_NINTERFACES > 1
+# error "A mechanism to associate an interface with an IRQ is needed"
+#else
+ priv = &g_ethdrvr[0];
+#endif
+
+ /* Disable further Ethernet interrupts. Because Ethernet interrupts are
+ * also disabled if the TX timeout event occurs, there can be no race
+ * condition here.
+ */
+
+#if CONFIG_PIC32MZ_NINTERFACES > 1
+ up_disable_irq(priv->pd_irqsrc);
+#else
+ up_disable_irq(PIC32MZ_IRQ_ETH);
+#endif
+
+ /* Get the interrupt status (zero means no interrupts pending). */
+
+ status = pic32mz_getreg(PIC32MZ_ETH_IRQ);
+
+ /* Determine if a TX transfer just completed */
+
+ if ((status & ETH_INT_TXDONE) != 0)
+ {
+ /* If a TX transfer just completed, then cancel the TX timeout so
+ * there will be no race condition between any subsequent timeout
+ * expiration and the deferred interrupt processing.
+ */
+
+ wd_cancel(priv->pd_txtimeout);
+ }
+
+ /* Cancel any pending poll work */
+
+ work_cancel(HPWORK, &priv->pd_work);
+
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pd_work, pic32mz_interrupt_work, priv, 0);
return OK;
}
/****************************************************************************
- * Function: pic32mz_txtimeout
+ * Function: pic32mz_txtimeout_work
+ *
+ * Description:
+ * Perform TX timeout related work from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void pic32mz_txtimeout_work(void *arg)
+{
+ struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
+
+ /* Increment statistics and dump debug info */
+
+ net_lock();
+ NETDEV_TXTIMEOUTS(&priv->pd_dev);
+ if (priv->pd_ifup)
+ {
+ /* Then reset the hardware. ifup() will reset the interface, then bring
+ * it back up.
+ */
+
+ (void)pic32mz_ifup(&priv->pd_dev);
+
+ /* Then poll the network for new XMIT data (We are guaranteed to have a free
+ * buffer here).
+ */
+
+ pic32mz_poll(priv);
+ }
+
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: pic32mz_txtimeout_expiry
*
* Description:
* Our TX watchdog timed out. Called from the timer interrupt handler.
@@ -1855,31 +1990,77 @@ static int pic32mz_interrupt(int irq, void *context)
*
****************************************************************************/
-static void pic32mz_txtimeout(int argc, uint32_t arg, ...)
+static void pic32mz_txtimeout_expiry(int argc, wdparm_t arg, ...)
{
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
- /* Increment statistics and dump debug info */
+ /* Disable further Ethernet interrupts. This will prevent some race
+ * conditions with interrupt work. There is still a potential race
+ * condition with interrupt work that is already queued and in progress.
+ */
- NETDEV_TXTIMEOUTS(&priv->pd_dev);
- if (priv->pd_ifup)
- {
- /* Then reset the hardware. ifup() will reset the interface, then bring
- * it back up.
- */
+#if CONFIG_PIC32MZ_NINTERFACES > 1
+ up_disable_irq(priv->pd_irqsrc);
+#else
+ up_disable_irq(PIC32MZ_IRQ_ETH);
+#endif
- (void)pic32mz_ifup(&priv->pd_dev);
+ /* Cancel any pending poll or interrupt work. This will have no effect
+ * on work that has already been started.
+ */
- /* Then poll the network for new XMIT data (We are guaranteed to have a free
- * buffer here).
- */
+ work_cancel(ETHWORK, &priv->pd_work);
- pic32mz_poll(priv);
- }
+ /* Schedule to perform the TX timeout processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pd_work, pic32mz_txtimeout_work, priv, 0);
}
/****************************************************************************
- * Function: pic32mz_polltimer
+ * Function: pic32mz_poll_work
+ *
+ * Description:
+ * Perform periodic polling from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void pic32mz_poll_work(void *arg)
+{
+ struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
+
+ /* Check if the next Tx descriptor is available. We cannot perform the Tx
+ * poll if we are unable to accept another packet for transmission.
+ */
+
+ net_lock();
+ if (pic32mz_txdesc(priv) != NULL)
+ {
+ /* If so, update TCP timing states and poll the network for new XMIT
+ * data. Hmmm.. might be bug here. Does this mean if there is a
+ * transmit in progress, we will missing TCP time state updates?
+ */
+
+ pic32mz_timerpoll(priv);
+ }
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_poll_expiry,
+ 1, priv);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: pic32mz_poll_expiry
*
* Description:
* Periodic timer handler. Called from the timer interrupt handler.
@@ -1896,27 +2077,28 @@ static void pic32mz_txtimeout(int argc, uint32_t arg, ...)
*
****************************************************************************/
-static void pic32mz_polltimer(int argc, uint32_t arg, ...)
+static void pic32mz_poll_expiry(int argc, wdparm_t arg, ...)
{
struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
- /* Check if the next Tx descriptor is available. We cannot perform the Tx
- * poll if we are unable to accept another packet for transmission.
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions.
*/
- if (pic32mz_txdesc(priv) != NULL)
+ if (work_available(&priv->pd_work))
{
- /* If so, update TCP timing states and poll the network for new XMIT data. Hmmm..
- * might be bug here. Does this mean if there is a transmit in progress,
- * we will missing TCP time state updates?
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pd_work, pic32mz_poll_work, priv, 0);
+ }
+ else
+ {
+ /* No.. Just re-start the watchdog poll timer, missing one polling
+ * cycle.
*/
- pic32mz_timerpoll(priv);
+ (void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_poll_expiry, 1, arg);
}
-
- /* Setup the watchdog poll timer again */
-
- (void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_polltimer, 1, arg);
}
/****************************************************************************
@@ -2213,17 +2395,19 @@ static int pic32mz_ifup(struct net_driver_s *dev)
/* Set and activate a timer process */
- (void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_polltimer, 1,
+ (void)wd_start(priv->pd_txpoll, PIC32MZ_WDDELAY, pic32mz_poll_expiry, 1,
(uint32_t)priv);
/* Finally, enable the Ethernet interrupt at the interrupt controller */
priv->pd_ifup = true;
+
#if CONFIG_PIC32MZ_NINTERFACES > 1
up_enable_irq(priv->pd_irqsrc);
#else
up_enable_irq(PIC32MZ_IRQ_ETH);
#endif
+
return OK;
}
@@ -2271,37 +2455,29 @@ static int pic32mz_ifdown(struct net_driver_s *dev)
}
/****************************************************************************
- * Function: pic32mz_txavail
+ * Function: pic32mz_txavail_work
*
* Description:
- * Driver callback invoked when new TX data is available. This is a
- * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
- * latency.
+ * Perform an out-of-cycle poll on the worker thread.
*
* Parameters:
- * dev - Reference to the NuttX driver state structure
+ * arg - Reference to the NuttX driver state structure (cast to void*)
*
* Returned Value:
* None
*
* Assumptions:
- * Called in normal user mode
+ * Called on the higher priority worker thread.
*
****************************************************************************/
-static int pic32mz_txavail(struct net_driver_s *dev)
+static void pic32mz_txavail_work(void *arg)
{
- struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)dev->d_private;
- irqstate_t flags;
-
- /* Disable interrupts because this function may be called from interrupt
- * level processing.
- */
-
- flags = enter_critical_section();
+ struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)arg;
/* Ignore the notification if the interface is not yet up */
+ net_lock();
if (priv->pd_ifup)
{
/* Check if the next Tx descriptor is available. */
@@ -2316,7 +2492,44 @@ static int pic32mz_txavail(struct net_driver_s *dev)
}
}
- leave_critical_section(flags);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: pic32mz_txavail
+ *
+ * Description:
+ * Driver callback invoked when new TX data is available. This is a
+ * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ * latency.
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called in normal user mode
+ *
+ ****************************************************************************/
+
+static int pic32mz_txavail(struct net_driver_s *dev)
+{
+ struct pic32mz_driver_s *priv = (struct pic32mz_driver_s *)dev->d_private;
+
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
+ */
+
+ if (work_available(&priv->pd_work))
+ {
+ /* Schedule to serialize the poll on the worker thread. */
+
+ work_queue(ETHWORK, &priv->pd_work, pic32mz_txavail_work, priv, 0);
+ }
+
return OK;
}
@@ -2800,6 +3013,7 @@ static inline int pic32mz_phyinit(struct pic32mz_driver_s *priv)
nerr("ERROR: No PHY detected\n");
return -ENODEV;
}
+
ninfo("phyaddr: %d\n", phyaddr);
/* Save the discovered PHY device address */
@@ -2813,6 +3027,7 @@ static inline int pic32mz_phyinit(struct pic32mz_driver_s *priv)
{
return ret;
}
+
pic32mz_showmii(phyaddr, "After reset");
/* Set the MII/RMII operation mode. This usually requires access to a
diff --git a/arch/misoc/Kconfig b/arch/misoc/Kconfig
index 615b741c52b..eee7005c38e 100644
--- a/arch/misoc/Kconfig
+++ b/arch/misoc/Kconfig
@@ -43,6 +43,13 @@ config MISOC_UART1
select ARCH_HAVE_UART1
select MISOC_UART
+config MISOC_ETHERNET
+ bool "Ethernet"
+ default n
+ select NETDEVICES
+ select ARCH_HAVE_PHY
+ select ARCH_HAVE_NETDEV_STATISTICS
+
endmenu # MISOC Peripheral Support
config MISOC_UART
diff --git a/arch/misoc/src/common/misoc.h b/arch/misoc/src/common/misoc.h
index 1531f3dc7fc..ab99f6aca25 100644
--- a/arch/misoc/src/common/misoc.h
+++ b/arch/misoc/src/common/misoc.h
@@ -73,6 +73,16 @@
void misoc_timer_initialize(void);
+/****************************************************************************
+ * Name: flush_cpu_dcache
+ *
+ * Description:
+ * flush cpu cache Data cache
+ *
+ ****************************************************************************/
+
+void flush_cpu_dcache(void);
+
/****************************************************************************
* Name: up_serialinit
*
@@ -84,6 +94,16 @@ void misoc_timer_initialize(void);
void misoc_serial_initialize(void);
+/****************************************************************************
+ * Name: up_net_initialize
+ *
+ * Description:
+ * Register Network
+ *
+ ****************************************************************************/
+
+int misoc_net_initialize(int intf);
+
/****************************************************************************
* Name: misoc_puts
*
@@ -126,5 +146,25 @@ void modifyreg8(unsigned int addr, uint8_t clearbits, uint8_t setbits);
void modifyreg16(unsigned int addr, uint16_t clearbits, uint16_t setbits);
void modifyreg32(unsigned int addr, uint32_t clearbits, uint32_t setbits);
+/****************************************************************************
+ * Name: misoc_flush_dcache
+ *
+ * Description:
+ * Flush the data cache of the cpu
+ *
+ ****************************************************************************/
+
+void misoc_flush_dcache(void);
+
+/****************************************************************************
+ * Name: misoc_flush_icache
+ *
+ * Description:
+ * Flush the instruction cache of the cpu
+ *
+ ****************************************************************************/
+
+void misoc_flush_icache(void);
+
#endif /* __ASSEMBLY__ */
#endif /* __ARCH_MISOC_SRC_COMMON_MISOC_H */
diff --git a/arch/rgmp/include/stdbool.h b/arch/misoc/src/common/misoc_flushcache.c
similarity index 61%
rename from arch/rgmp/include/stdbool.h
rename to arch/misoc/src/common/misoc_flushcache.c
index eb1bee1adb8..655ba8ab358 100644
--- a/arch/rgmp/include/stdbool.h
+++ b/arch/misoc/src/common/misoc_flushcache.c
@@ -1,8 +1,9 @@
/****************************************************************************
- * arch/rgmp/include/stdbool.h
+ * arch/misoc/src/common/misoc_flushcache.c
*
- * Copyright (C) 2009, 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt
+ * Author: Ramtin Amin
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,52 +34,48 @@
*
****************************************************************************/
-#ifndef __ARCH_RGMP_INCLUDE_STDBOOL_H
-#define __ARCH_RGMP_INCLUDE_STDBOOL_H
-
/****************************************************************************
* Included Files
****************************************************************************/
#include
-#include
+#include
+#include "misoc.h"
-#include
+#ifdef CONFIG_ARCH_CHIP_LM32
+#include "lm32.h"
+#endif
/****************************************************************************
- * Pre-processor Definitions
+ * Public Functions
****************************************************************************/
-/* bool, true, and false must be provided as macros so that they can be
- * redefined by the application if necessary.
- *
- * NOTE: Under C99 'bool' is required to be defined to be the intrinsic type
- * _Bool. However, in this NuttX context, we need backward compatibility
- * to pre-C99 standards where _Bool is not an intrinsic type. Hence, we
- * use _Bool8 as the underlying type.
- */
-
-#define true 1
-#define false 0
-
-#define __bool_true_false_are_defined 1
-
/****************************************************************************
- * Public Types
+ * Name: misoc_flush_dcache
+ *
+ * Description:
+ * Flush the data cache of the cpu
+ *
****************************************************************************/
-/* A byte is the smallest address memory element (at least in architectures
- * that do not support bit banding). The requirement is only that type _Bool
- * be large enough to hold the values 0 and 1. We select uint8_t to minimize
- * the RAM footprint of the executable.
+void misoc_flush_dcache()
+{
+#ifdef CONFIG_ARCH_CHIP_LM32
+ lm32_flush_dcache();
+#endif
+}
+
+/****************************************************************************
+ * Name: misoc_flush_icache
*
- * NOTE: We can't actually define the type _Bool here. Under C99 _Bool is
- * an intrinsic type and cannot be the target of a typedef. However, in this
- * NuttX context, we also need backward compatibility to pre-C99 standards
- * where _Bool is not an intrinsic type. We work around this by using _Bool8
- * as the underlying type.
- */
+ * Description:
+ * Flush the instruction cache of the cpu
+ *
+ ****************************************************************************/
-typedef uint8_t _Bool8;
-
-#endif /* __ARCH_RGMP_INCLUDE_STDBOOL_H */
+void misoc_flush_icache()
+{
+#ifdef CONFIG_ARCH_CHIP_LM32
+ lm32_flush_icache();
+#endif
+}
diff --git a/arch/misoc/src/common/misoc_net.c b/arch/misoc/src/common/misoc_net.c
new file mode 100644
index 00000000000..85d6e60bbf2
--- /dev/null
+++ b/arch/misoc/src/common/misoc_net.c
@@ -0,0 +1,1228 @@
+/****************************************************************************
+ * arch/misoc/src/commong/misoc_net_net.c
+ *
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Gregory Nutt
+ * Ramtin Amin
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name NuttX nor the names of its contributors may be
+ * used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * Included Files
+ ****************************************************************************/
+
+#include
+#if defined(CONFIG_NET) && defined(CONFIG_MISOC_ETHERNET)
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "chip.h"
+#include "hw/flags.h"
+#include "hw/ethmac_mem.h"
+#include "misoc.h"
+
+#ifdef CONFIG_NET_PKT
+# include
+#endif
+
+/****************************************************************************
+ * Pre-processor Definitions
+ ****************************************************************************/
+
+/* If processing is not done at the interrupt level, then high priority
+ * work queue support is required.
+ */
+
+#if !defined(CONFIG_SCHED_HPWORK)
+ /* REVISIT: The low priority work queue would be preferred if it is avaiable */
+
+# error High priority work queue support is required
+#endif
+
+/* CONFIG_MISOC_NET_NINTERFACES determines the number of physical interfaces
+ * that will be supported.
+ */
+
+#ifndef CONFIG_MISOC_NET_NINTERFACES
+# define CONFIG_MISOC_NET_NINTERFACES 1
+#endif
+
+/* TX poll delay = 1 seconds. CLK_TCK is the number of clock ticks per second */
+
+#define MISOC_NET_WDDELAY (1*CLK_TCK)
+
+/* TX timeout = 1 minute */
+
+#define MISOC_NET_TXTIMEOUT (60*CLK_TCK)
+
+/* This is a helper pointer for accessing the contents of the Ethernet header */
+
+#define BUF ((struct eth_hdr_s *)priv->misoc_net_dev.d_buf)
+
+/****************************************************************************
+ * Private Types
+ ****************************************************************************/
+
+/* The misoc_net_driver_s encapsulates all state information for a single hardware
+ * interface
+ */
+
+struct misoc_net_driver_s
+{
+ bool misoc_net_bifup; /* true:ifup false:ifdown */
+ WDOG_ID misoc_net_txpoll; /* TX poll timer */
+ WDOG_ID misoc_net_txtimeout; /* TX timeout timer */
+ struct work_s misoc_net_work; /* For deferring work to the work queue */
+
+ uint8_t *rx0_buf; /* 2 RX and 2 TX buffer */
+ uint8_t *rx1_buf;
+ uint8_t *tx0_buf;
+ uint8_t *tx1_buf;
+
+ uint8_t *tx_buf;
+
+
+ uint8_t tx_slot; /* The slot from which we send packet (tx0/tx1) */
+
+ /* This holds the information visible to the NuttX network */
+
+ struct net_driver_s misoc_net_dev; /* Interface understood by the network */
+};
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+/* A single packet buffer is used */
+
+static uint8_t g_pktbuf[MAX_NET_DEV_MTU + CONFIG_NET_GUARDSIZE];
+
+/* Driver state structur */
+
+static struct misoc_net_driver_s g_misoc_net[CONFIG_MISOC_NET_NINTERFACES];
+
+/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+/* Common TX logic */
+
+static int misoc_net_transmit(FAR struct misoc_net_driver_s *priv);
+static int misoc_net_txpoll(FAR struct net_driver_s *dev);
+
+/* Interrupt handling */
+
+static void misoc_net_receive(FAR struct misoc_net_driver_s *priv);
+static void misoc_net_txdone(FAR struct misoc_net_driver_s *priv);
+
+static void misoc_net_interrupt_work(FAR void *arg);
+static int misoc_net_interrupt(int irq, FAR void *context);
+
+/* Watchdog timer expirations */
+
+static void misoc_net_txtimeout_work(FAR void *arg);
+static void misoc_net_txtimeout_expiry(int argc, wdparm_t arg, ...);
+
+static void misoc_net_poll_work(FAR void *arg);
+static void misoc_net_poll_expiry(int argc, wdparm_t arg, ...);
+
+/* NuttX callback functions */
+
+static int misoc_net_ifup(FAR struct net_driver_s *dev);
+static int misoc_net_ifdown(FAR struct net_driver_s *dev);
+
+static void misoc_net_txavail_work(FAR void *arg);
+static int misoc_net_txavail(FAR struct net_driver_s *dev);
+
+#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
+static int misoc_net_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
+#ifdef CONFIG_NET_IGMP
+static int misoc_net_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac);
+#endif
+#ifdef CONFIG_NET_ICMPv6
+static void misoc_net_ipv6multicast(FAR struct misoc_net_driver_s *priv);
+#endif
+#endif
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: misoc_net_transmit
+ *
+ * Description:
+ * Start hardware transmission. Called either from the txdone interrupt
+ * handling or from watchdog based polling.
+ *
+ * Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ * May or may not be called from an interrupt handler. In either case,
+ * the network is locked.
+ *
+ ****************************************************************************/
+
+static int misoc_net_transmit(FAR struct misoc_net_driver_s *priv)
+{
+ /* Verify that the hardware is ready to send another packet. If we get
+ * here, then we are committed to sending a packet; Higher level logic
+ * must have assured that there is no transmission in progress.
+ */
+
+ /* Increment statistics */
+
+ NETDEV_TXPACKETS(priv->misoc_net_dev);
+
+ /* Send the packet: address=priv->misoc_net_dev.d_buf,
+ * length=priv->misoc_net_dev.d_len
+ *
+ * NOTE: This memcpy could be avoided by setting tx_buf
+ * to the d_buf pointer and setting d_buf to an alternate
+ * buffer. Some additional buffer management logic would
+ * be required.
+ */
+
+ memcpy(priv->tx_buf, priv->misoc_net_dev.d_buf,
+ priv->misoc_net_dev.d_len);
+
+ /* Choose the slot on which we write */
+
+ ethmac_sram_reader_slot_write(priv->tx_slot);
+
+ /* Write the len */
+
+ if (priv->misoc_net_dev.d_len < 60)
+ {
+ ethmac_sram_reader_length_write(60);
+ }
+ else
+ {
+ ethmac_sram_reader_length_write(priv->misoc_net_dev.d_len);
+ }
+
+ /* Trigger the writing */
+
+ ethmac_sram_reader_start_write(1);
+
+ /* switch tx slot */
+
+ priv->tx_slot = (priv->tx_slot+1)%2;
+ if (priv->tx_slot)
+ {
+ priv->tx_buf = priv->tx1_buf;
+ }
+ else
+ {
+ priv->tx_buf = priv->tx0_buf;
+ }
+
+ /* Enable Tx interrupts */
+
+ ethmac_sram_reader_ev_enable_write(1);
+
+ /* Setup the TX timeout watchdog (perhaps restarting the timer) */
+
+ (void)wd_start(priv->misoc_net_txtimeout, MISOC_NET_TXTIMEOUT,
+ misoc_net_txtimeout_expiry, 1, (wdparm_t)priv);
+ return OK;
+}
+
+/****************************************************************************
+ * Function: misoc_net_txpoll
+ *
+ * Description:
+ * The transmitter is available, check if the network has any outgoing
+ * packets ready to send. This is a callback from devif_poll().
+ * devif_poll() may be called:
+ *
+ * 1. When the preceding TX packet send is complete,
+ * 2. When the preceding TX packet send timesout and the interface is reset
+ * 3. During normal TX polling
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * OK on success; a negated errno on failure
+ *
+ * Assumptions:
+ * May or may not be called from an interrupt handler. In either case,
+ * the network is locked.
+ *
+ ****************************************************************************/
+
+static int misoc_net_txpoll(FAR struct net_driver_s *dev)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)dev->d_private;
+
+ /* If the polling resulted in data that should be sent out on the network,
+ * the field d_len is set to a value > 0.
+ */
+
+ if (priv->misoc_net_dev.d_len > 0)
+ {
+ /* Look up the destination MAC address and add it to the Ethernet
+ * header.
+ */
+
+#ifdef CONFIG_NET_IPv4
+#ifdef CONFIG_NET_IPv6
+ if (IFF_IS_IPv4(priv->misoc_net_dev.d_flags))
+#endif
+ {
+ arp_out(&priv->misoc_net_dev);
+ }
+#endif /* CONFIG_NET_IPv4 */
+
+#ifdef CONFIG_NET_IPv6
+#ifdef CONFIG_NET_IPv4
+ else
+#endif
+ {
+ neighbor_out(&priv->misoc_net_dev);
+ }
+#endif /* CONFIG_NET_IPv6 */
+
+ /* Send the packet */
+
+ misoc_net_transmit(priv);
+
+ /* Check if there is room in the device to hold another packet. If not,
+ * return a non-zero value to terminate the poll.
+ */
+ }
+
+ /* If zero is returned, the polling will continue until all connections have
+ * been examined.
+ */
+
+ return 0;
+}
+
+/****************************************************************************
+ * Function: misoc_net_receive
+ *
+ * Description:
+ * An interrupt was received indicating the availability of a new RX packet
+ *
+ * Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void misoc_net_receive(FAR struct misoc_net_driver_s *priv)
+{
+ uint8_t rxslot;
+ uint32_t rxlen;
+
+ do
+ {
+ /* Check for errors and update statistics */
+
+ /* Check if the packet is a valid size for the network buffer
+ * configuration.
+ */
+
+ /* Find rx slot */
+
+ rxslot = ethmac_sram_writer_slot_read();
+
+ /* Get rx len */
+
+ rxlen = ethmac_sram_writer_length_read();
+
+ /* Copy the data data from the hardware to priv->misoc_net_dev.d_buf. Set
+ * amount of data in priv->misoc_net_dev.d_len
+ *
+ * NOTE: These memcpy's could be avoided by simply setting the d_buf
+ * pointer to the rx*_buf containing the received data. Some additional
+ * buffer management logic would also be required.
+ */
+
+ misoc_flush_dcache();
+
+ if (rxslot)
+ {
+ memcpy(priv->misoc_net_dev.d_buf, priv->rx1_buf, rxlen);
+ }
+ else
+ {
+ memcpy(priv->misoc_net_dev.d_buf, priv->rx0_buf, rxlen);
+ }
+
+ /* Clear event pending */
+
+ ethmac_sram_writer_ev_pending_write(1);
+
+ priv->misoc_net_dev.d_len = rxlen;
+
+#ifdef CONFIG_NET_PKT
+ /* When packet sockets are enabled, feed the frame into the packet tap */
+
+ pkt_input(&priv->misoc_net_dev);
+#endif
+
+ /* We only accept IP packets of the configured type and ARP packets */
+
+#ifdef CONFIG_NET_IPv4
+ if (BUF->type == HTONS(ETHTYPE_IP))
+ {
+ ninfo("IPv4 frame\n");
+ NETDEV_RXIPV4(&priv->misoc_net_dev);
+
+ /* Handle ARP on input then give the IPv4 packet to the network
+ * layer
+ */
+
+ arp_ipin(&priv->misoc_net_dev);
+ ipv4_input(&priv->misoc_net_dev);
+
+ /* If the above function invocation resulted in data that should be
+ * sent out on the network, the field d_len will set to a value > 0.
+ */
+
+ if (priv->misoc_net_dev.d_len > 0)
+ {
+ /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv6
+ if (IFF_IS_IPv4(priv->misoc_net_dev.d_flags))
+#endif
+ {
+ arp_out(&priv->misoc_net_dev);
+ }
+#ifdef CONFIG_NET_IPv6
+ else
+ {
+ neighbor_out(&kel->misoc_net_dev);
+ }
+#endif
+
+ /* And send the packet */
+
+ misoc_net_transmit(priv);
+ }
+ }
+ else
+#endif
+#ifdef CONFIG_NET_IPv6
+ if (BUF->type == HTONS(ETHTYPE_IP6))
+ {
+ ninfo("Iv6 frame\n");
+ NETDEV_RXIPV6(&priv->misoc_net_dev);
+
+ /* Give the IPv6 packet to the network layer */
+
+ ipv6_input(&priv->misoc_net_dev);
+
+ /* If the above function invocation resulted in data that should be
+ * sent out on the network, the field d_len will set to a value > 0.
+ */
+
+ if (priv->misoc_net_dev.d_len > 0)
+ {
+ /* Update the Ethernet header with the correct MAC address */
+
+#ifdef CONFIG_NET_IPv4
+ if (IFF_IS_IPv4(priv->misoc_net_dev.d_flags))
+ {
+ arp_out(&priv->misoc_net_dev);
+ }
+ else
+#endif
+#ifdef CONFIG_NET_IPv6
+ {
+ neighbor_out(&priv->misoc_net_dev);
+ }
+#endif
+
+ /* And send the packet */
+
+ misoc_net_transmit(priv);
+ }
+ }
+ else
+#endif
+#ifdef CONFIG_NET_ARP
+ if (BUF->type == htons(ETHTYPE_ARP))
+ {
+ arp_arpin(&priv->misoc_net_dev);
+ NETDEV_RXARP(&priv->misoc_net_dev);
+
+ /* If the above function invocation resulted in data that should be
+ * sent out on the network, the field d_len will set to a value > 0.
+ */
+
+ if (priv->misoc_net_dev.d_len > 0)
+ {
+ misoc_net_transmit(priv);
+ }
+ }
+#endif
+ else
+ {
+ NETDEV_RXDROPPED(&priv->misoc_net_dev);
+ }
+ }
+ while (ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER);
+}
+
+/****************************************************************************
+ * Function: misoc_net_txdone
+ *
+ * Description:
+ * An interrupt was received indicating that the last TX packet(s) is done
+ *
+ * Parameters:
+ * priv - Reference to the driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void misoc_net_txdone(FAR struct misoc_net_driver_s *priv)
+{
+ /* Check for errors and update statistics */
+
+ NETDEV_TXDONE(priv->misoc_net_dev);
+
+ /* Check if there are pending transmissions */
+
+ /* If no further transmissions are pending, then cancel the TX timeout and
+ * disable further Tx interrupts.
+ */
+
+ wd_cancel(priv->misoc_net_txtimeout);
+
+ /* Then make sure that the TX poll timer is running (if it is already
+ * running, the following would restart it). This is necessary to
+ * avoid certain race conditions where the polling sequence can be
+ * interrupted.
+ */
+
+ (void)wd_start(priv->misoc_net_txpoll, MISOC_NET_WDDELAY,
+ misoc_net_poll_expiry, 1, (wdparm_t)priv);
+
+ /* And disable further TX interrupts. */
+
+ ethmac_sram_reader_ev_enable_write(0);
+
+ /* In any event, poll the network for new TX data */
+
+ (void)devif_poll(&priv->misoc_net_dev, misoc_net_txpoll);
+}
+
+/****************************************************************************
+ * Function: misoc_net_interrupt_work
+ *
+ * Description:
+ * Perform interrupt related work from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() was called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void misoc_net_interrupt_work(FAR void *arg)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)arg;
+
+ /* Process pending Ethernet interrupts */
+
+ net_lock();
+
+ /* Check if we received an incoming packet, if so, call misoc_net_receive() */
+
+ if (ethmac_sram_writer_ev_pending_read() & ETHMAC_EV_SRAM_WRITER)
+ {
+ misoc_net_receive(priv);
+ }
+
+ /* Check if a packet transmission just completed. If so, call misoc_net_txdone.
+ * This may disable further Tx interrupts if there are no pending
+ * transmissions.
+ */
+
+ if (ethmac_sram_reader_ev_pending_read() & ETHMAC_EV_SRAM_READER)
+ {
+ misoc_net_txdone(priv);
+ ethmac_sram_reader_ev_pending_write(1);
+ }
+
+ net_unlock();
+
+ /* Re-enable Ethernet interrupts */
+
+ up_enable_irq(ETHMAC_INTERRUPT);
+}
+
+/****************************************************************************
+ * Function: misoc_net_interrupt
+ *
+ * Description:
+ * Hardware interrupt handler
+ *
+ * Parameters:
+ * irq - Number of the IRQ that generated the interrupt
+ * context - Interrupt register state save info (architecture-specific)
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int misoc_net_interrupt(int irq, FAR void *context)
+{
+ FAR struct misoc_net_driver_s *priv = &g_misoc_net[0];
+
+ /* Disable further Ethernet interrupts. Because Ethernet interrupts are
+ * also disabled if the TX timeout event occurs, there can be no race
+ * condition here.
+ */
+
+ /* TODO: Determine if a TX transfer just completed */
+
+ if (ethmac_sram_reader_ev_pending_read() & ETHMAC_EV_SRAM_READER)
+ {
+ /* If a TX transfer just completed, then cancel the TX timeout so
+ * there will be do race condition between any subsequent timeout
+ * expiration and the deferred interrupt processing.
+ */
+
+ wd_cancel(priv->misoc_net_txtimeout);
+ }
+
+ /* Cancel any pending poll work */
+
+ work_cancel(HPWORK, &priv->misoc_net_work);
+
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(HPWORK, &priv->misoc_net_work, misoc_net_interrupt_work, priv, 0);
+ return OK;
+}
+
+/****************************************************************************
+ * Function: misoc_net_txtimeout_work
+ *
+ * Description:
+ * Perform TX timeout related work from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void misoc_net_txtimeout_work(FAR void *arg)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)arg;
+
+ /* Increment statistics and dump debug info */
+
+ net_lock();
+ NETDEV_TXTIMEOUTS(priv->misoc_net_dev);
+
+ /* Then reset the hardware */
+
+ /* Then poll the network for new XMIT data */
+
+ (void)devif_poll(&priv->misoc_net_dev, misoc_net_txpoll);
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: misoc_net_txtimeout_expiry
+ *
+ * Description:
+ * Our TX watchdog timed out. Called from the timer interrupt handler.
+ * The last TX never completed. Reset the hardware and start again.
+ *
+ * Parameters:
+ * argc - The number of available arguments
+ * arg - The first argument
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Global interrupts are disabled by the watchdog logic.
+ *
+ ****************************************************************************/
+
+static void misoc_net_txtimeout_expiry(int argc, wdparm_t arg, ...)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)arg;
+
+ /* Disable further Ethernet interrupts. This will prevent some race
+ * conditions with interrupt work. There is still a potential race
+ * condition with interrupt work that is already queued and in progress.
+ */
+
+ //up_disable_irq(ETHMAC_INTERRUPT);
+
+ /* Cancel any pending poll or interrupt work. This will have no effect
+ * on work that has already been started.
+ */
+
+ work_cancel(HPWORK, &priv->misoc_net_work);
+
+ /* Schedule to perform the TX timeout processing on the worker thread. */
+
+ work_queue(HPWORK, &priv->misoc_net_work, misoc_net_txtimeout_work, priv, 0);
+}
+
+/****************************************************************************
+ * Function: misoc_net_poll_work
+ *
+ * Description:
+ * Perform periodic polling from the worker thread
+ *
+ * Parameters:
+ * arg - The argument passed when work_queue() as called.
+ *
+ * Returned Value:
+ * OK on success
+ *
+ * Assumptions:
+ * The network is locked.
+ *
+ ****************************************************************************/
+
+static void misoc_net_poll_work(FAR void *arg)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)arg;
+
+ /* Perform the poll */
+
+ net_lock();
+
+ /* Check if there is room in the send another TX packet. We cannot perform
+ * the TX poll if he are unable to accept another packet for transmission.
+ */
+
+ /* If so, update TCP timing states and poll the network for new XMIT data.
+ * Hmmm.. might be bug here. Does this mean if there is a transmit in
+ * progress, we will missing TCP time state updates?
+ */
+
+ (void)devif_timer(&priv->misoc_net_dev, misoc_net_txpoll);
+
+ /* Setup the watchdog poll timer again */
+
+ (void)wd_start(priv->misoc_net_txpoll, MISOC_NET_WDDELAY, misoc_net_poll_expiry, 1,
+ (wdparm_t)priv);
+
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: misoc_net_poll_expiry
+ *
+ * Description:
+ * Periodic timer handler. Called from the timer interrupt handler.
+ *
+ * Parameters:
+ * argc - The number of available arguments
+ * arg - The first argument
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Global interrupts are disabled by the watchdog logic.
+ *
+ ****************************************************************************/
+
+static void misoc_net_poll_expiry(int argc, wdparm_t arg, ...)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)arg;
+
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions.
+ */
+
+ if (work_available(&priv->misoc_net_work))
+ {
+ /* Schedule to perform the interrupt processing on the worker thread. */
+
+ work_queue(HPWORK, &priv->misoc_net_work, misoc_net_poll_work, priv, 0);
+ }
+ else
+ {
+ /* No.. Just re-start the watchdog poll timer, missing one polling
+ * cycle.
+ */
+
+ (void)wd_start(priv->misoc_net_txpoll, MISOC_NET_WDDELAY,
+ misoc_net_poll_expiry, 1, arg);
+ }
+}
+
+/****************************************************************************
+ * Function: misoc_net_ifup
+ *
+ * Description:
+ * NuttX Callback: Bring up the Ethernet interface when an IP address is
+ * provided
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int misoc_net_ifup(FAR struct net_driver_s *dev)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)dev->d_private;
+
+#ifdef CONFIG_NET_IPv4
+ ninfo("Bringing up: %d.%d.%d.%d\n",
+ dev->d_ipaddr & 0xff, (dev->d_ipaddr >> 8) & 0xff,
+ (dev->d_ipaddr >> 16) & 0xff, dev->d_ipaddr >> 24);
+#endif
+#ifdef CONFIG_NET_IPv6
+ ninfo("Bringing up: %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
+ dev->d_ipv6addr[0], dev->d_ipv6addr[1], dev->d_ipv6addr[2],
+ dev->d_ipv6addr[3], dev->d_ipv6addr[4], dev->d_ipv6addr[5],
+ dev->d_ipv6addr[6], dev->d_ipv6addr[7]);
+#endif
+
+ /* Initialize PHYs, the Ethernet interface, and setup up Ethernet interrupts */
+
+ /* Instantiate the MAC address from priv->misoc_net_dev.d_mac.ether_addr_octet */
+
+#ifdef CONFIG_NET_ICMPv6
+ /* Set up IPv6 multicast address filtering */
+
+ misoc_net_ipv6multicast(priv);
+#endif
+
+ /* Set and activate a timer process */
+
+ (void)wd_start(priv->misoc_net_txpoll, MISOC_NET_WDDELAY, misoc_net_poll_expiry, 1,
+ (wdparm_t)priv);
+
+ priv->misoc_net_bifup = true;
+ up_enable_irq(ETHMAC_INTERRUPT);
+
+ /* Enable the RX Event Handler */
+
+ ethmac_sram_writer_ev_enable_write(1);
+ return OK;
+}
+
+/****************************************************************************
+ * Function: misoc_net_ifdown
+ *
+ * Description:
+ * NuttX Callback: Stop the interface.
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+static int misoc_net_ifdown(FAR struct net_driver_s *dev)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)dev->d_private;
+ irqstate_t flags;
+
+ /* Disable the Ethernet interrupt */
+
+ flags = enter_critical_section();
+ up_disable_irq(ETHMAC_INTERRUPT);
+
+ /* Cancel the TX poll timer and TX timeout timers */
+
+ wd_cancel(priv->misoc_net_txpoll);
+ wd_cancel(priv->misoc_net_txtimeout);
+
+ /* Put the EMAC in its reset, non-operational state. This should be
+ * a known configuration that will guarantee the misoc_net_ifup() always
+ * successfully brings the interface back up.
+ */
+
+ /* Mark the device "down" */
+
+ priv->misoc_net_bifup = false;
+ leave_critical_section(flags);
+ return OK;
+}
+
+/****************************************************************************
+ * Function: misoc_net_txavail_work
+ *
+ * Description:
+ * Perform an out-of-cycle poll on the worker thread.
+ *
+ * Parameters:
+ * arg - Reference to the NuttX driver state structure (cast to void*)
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called on the higher priority worker thread.
+ *
+ ****************************************************************************/
+
+static void misoc_net_txavail_work(FAR void *arg)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)arg;
+
+ /* Ignore the notification if the interface is not yet up */
+
+ net_lock();
+ if (priv->misoc_net_bifup)
+ {
+ /* Check if there is room in the hardware to hold another outgoing packet. */
+
+ if (!ethmac_sram_reader_ready_read())
+ {
+ /* If so, then poll the network for new XMIT data */
+
+ (void)devif_poll(&priv->misoc_net_dev, misoc_net_txpoll);
+ }
+ }
+
+ net_unlock();
+}
+
+/****************************************************************************
+ * Function: misoc_net_txavail
+ *
+ * Description:
+ * Driver callback invoked when new TX data is available. This is a
+ * stimulus perform an out-of-cycle poll and, thereby, reduce the TX
+ * latency.
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ * Called in normal user mode
+ *
+ ****************************************************************************/
+
+static int misoc_net_txavail(FAR struct net_driver_s *dev)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)dev->d_private;
+
+ /* Is our single work structure available? It may not be if there are
+ * pending interrupt actions and we will have to ignore the Tx
+ * availability action.
+ */
+
+ if (work_available(&priv->misoc_net_work))
+ {
+ /* Schedule to serialize the poll on the worker thread. */
+
+ work_queue(HPWORK, &priv->misoc_net_work, misoc_net_txavail_work, priv, 0);
+ }
+
+ return OK;
+}
+
+/****************************************************************************
+ * Function: misoc_net_addmac
+ *
+ * Description:
+ * NuttX Callback: Add the specified MAC address to the hardware multicast
+ * address filtering
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ * mac - The MAC address to be added
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6)
+static int misoc_net_addmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)dev->d_private;
+
+ /* Add the MAC address to the hardware multicast routing table */
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Function: misoc_net_rmmac
+ *
+ * Description:
+ * NuttX Callback: Remove the specified MAC address from the hardware multicast
+ * address filtering
+ *
+ * Parameters:
+ * dev - Reference to the NuttX driver state structure
+ * mac - The MAC address to be removed
+ *
+ * Returned Value:
+ * None
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_IGMP
+static int misoc_net_rmmac(FAR struct net_driver_s *dev, FAR const uint8_t *mac)
+{
+ FAR struct misoc_net_driver_s *priv = (FAR struct misoc_net_driver_s *)dev->d_private;
+
+ /* Add the MAC address to the hardware multicast routing table */
+
+ return OK;
+}
+#endif
+
+/****************************************************************************
+ * Function: misoc_net_ipv6multicast
+ *
+ * Description:
+ * Configure the IPv6 multicast MAC address.
+ *
+ * Parameters:
+ * priv - A reference to the private driver state structure
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_NET_ICMPv6
+static void misoc_net_ipv6multicast(FAR struct misoc_net_driver_s *priv)
+{
+ FAR struct net_driver_s *dev;
+ uint16_t tmp16;
+ uint8_t mac[6];
+
+ /* For ICMPv6, we need to add the IPv6 multicast address
+ *
+ * For IPv6 multicast addresses, the Ethernet MAC is derived by
+ * the four low-order octets OR'ed with the MAC 33:33:00:00:00:00,
+ * so for example the IPv6 address FF02:DEAD:BEEF::1:3 would map
+ * to the Ethernet MAC address 33:33:00:01:00:03.
+ *
+ * NOTES: This appears correct for the ICMPv6 Router Solicitation
+ * Message, but the ICMPv6 Neighbor Solicitation message seems to
+ * use 33:33:ff:01:00:03.
+ */
+
+ mac[0] = 0x33;
+ mac[1] = 0x33;
+
+ dev = &priv->dev;
+ tmp16 = dev->d_ipv6addr[6];
+ mac[2] = 0xff;
+ mac[3] = tmp16 >> 8;
+
+ tmp16 = dev->d_ipv6addr[7];
+ mac[4] = tmp16 & 0xff;
+ mac[5] = tmp16 >> 8;
+
+ ninfo("IPv6 Multicast: %02x:%02x:%02x:%02x:%02x:%02x\n",
+ mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+
+ (void)misoc_net_addmac(dev, mac);
+
+#ifdef CONFIG_NET_ICMPv6_AUTOCONF
+ /* Add the IPv6 all link-local nodes Ethernet address. This is the
+ * address that we expect to receive ICMPv6 Router Advertisement
+ * packets.
+ */
+
+ (void)misoc_net_addmac(dev, g_ipv6_ethallnodes.ether_addr_octet);
+
+#endif /* CONFIG_NET_ICMPv6_AUTOCONF */
+#ifdef CONFIG_NET_ICMPv6_ROUTER
+ /* Add the IPv6 all link-local routers Ethernet address. This is the
+ * address that we expect to receive ICMPv6 Router Solicitation
+ * packets.
+ */
+
+ (void)misoc_net_addmac(dev, g_ipv6_ethallrouters.ether_addr_octet);
+
+#endif /* CONFIG_NET_ICMPv6_ROUTER */
+}
+#endif /* CONFIG_NET_ICMPv6 */
+
+/****************************************************************************
+ * Public Functions
+ ****************************************************************************/
+
+/****************************************************************************
+ * Function: misoc_net_initialize
+ *
+ * Description:
+ * Initialize the Ethernet controller and driver
+ *
+ * Parameters:
+ * intf - In the case where there are multiple EMACs, this value
+ * identifies which EMAC is to be initialized.
+ *
+ * Returned Value:
+ * OK on success; Negated errno on failure.
+ *
+ * Assumptions:
+ *
+ ****************************************************************************/
+
+int misoc_net_initialize(int intf)
+{
+ FAR struct misoc_net_driver_s *priv;
+
+ /* Get the interface structure associated with this interface number. */
+
+ DEBUGASSERT(intf < CONFIG_MISOC_NET_NINTERFACES);
+ priv = &g_misoc_net[intf];
+
+ /* Check if a Ethernet chip is recognized at its I/O base */
+
+ /* Attach the IRQ to the driver */
+
+ if (irq_attach(ETHMAC_INTERRUPT, misoc_net_interrupt))
+ {
+ /* We could not attach the ISR to the interrupt */
+
+ return -EAGAIN;
+ }
+
+ /* clear pending int */
+
+ ethmac_sram_writer_ev_pending_write(1);
+ ethmac_sram_reader_ev_pending_write(1);
+
+ /* Initialize the driver structure */
+
+ memset(priv, 0, sizeof(struct misoc_net_driver_s));
+ priv->rx0_buf = (uint8_t *)ETHMAC_RX0_BASE;
+ priv->rx1_buf = (uint8_t *)ETHMAC_RX1_BASE;
+ priv->tx0_buf = (uint8_t *)ETHMAC_TX0_BASE;
+ priv->tx1_buf = (uint8_t *)ETHMAC_TX1_BASE;
+ priv->tx_buf = priv->tx0_buf;
+ priv->tx_slot=0;
+
+ priv->misoc_net_dev.d_buf = g_pktbuf; /* Single packet buffer */
+ priv->misoc_net_dev.d_ifup = misoc_net_ifup; /* I/F up (new IP address) callback */
+ priv->misoc_net_dev.d_ifdown = misoc_net_ifdown; /* I/F down callback */
+ priv->misoc_net_dev.d_txavail = misoc_net_txavail; /* New TX data callback */
+#ifdef CONFIG_NET_IGMP
+ priv->misoc_net_dev.d_addmac = misoc_net_addmac; /* Add multicast MAC address */
+ priv->misoc_net_dev.d_rmmac = misoc_net_rmmac; /* Remove multicast MAC address */
+#endif
+ priv->misoc_net_dev.d_private = (FAR void *)g_misoc_net; /* Used to recover private state from dev */
+
+ /* Create a watchdog for timing polling for and timing of transmisstions */
+
+ priv->misoc_net_txpoll = wd_create(); /* Create periodic poll timer */
+ priv->misoc_net_txtimeout = wd_create(); /* Create TX timeout timer */
+
+ /* Put the interface in the down state. This usually amounts to resetting
+ * the device and/or calling misoc_net_ifdown().
+ */
+
+ /* Read the MAC address from the hardware into
+ * priv->misoc_net_dev.d_mac.ether_addr_octet
+ */
+
+ /* Register the device with the OS so that socket IOCTLs can be performed */
+
+ (void)netdev_register(&priv->misoc_net_dev, NET_LL_ETHERNET);
+ return OK;
+}
+
+#endif /* CONFIG_NET && CONFIG_MISOC_NET_ETHERNET */
diff --git a/arch/misoc/src/lm32/Make.defs b/arch/misoc/src/lm32/Make.defs
index addffc59848..a2ea84d61c8 100644
--- a/arch/misoc/src/lm32/Make.defs
+++ b/arch/misoc/src/lm32/Make.defs
@@ -39,7 +39,8 @@ HEAD_ASRC = lm32_vectors.S
CMN_ASRCS =
CMN_CSRCS = misoc_lowputs.c misoc_serial.c misoc_mdelay.c
CMN_CSRCS += misoc_modifyreg8.c misoc_modifyreg16.c misoc_modifyreg32.c
-CMN_CSRCS += misoc_puts.c misoc_udelay.c misoc_timerisr.c
+CMN_CSRCS += misoc_puts.c misoc_udelay.c misoc_timerisr.c misoc_net.c
+CMN_CSRCS += misoc_flushcache.c
CHIP_ASRCS = lm32_syscall.S
@@ -50,3 +51,4 @@ CHIP_CSRCS += lm32_initialize.c lm32_initialstate.c lm32_interruptcontext.c
CHIP_CSRCS += lm32_irq.c lm32_releasepending.c lm32_releasestack.c
CHIP_CSRCS += lm32_stackframe.c lm32_swint.c lm32_unblocktask.c
CHIP_CSRCS += lm32_reprioritizertr.c lm32_schedulesigaction.c lm32_sigdeliver.c
+CHIP_CSRCS += lm32_flushcache.c
\ No newline at end of file
diff --git a/arch/misoc/src/lm32/lm32.h b/arch/misoc/src/lm32/lm32.h
index b23e60e4f20..a09bcfec47c 100644
--- a/arch/misoc/src/lm32/lm32.h
+++ b/arch/misoc/src/lm32/lm32.h
@@ -149,6 +149,11 @@ void lm32_timer_initialize(void);
void lm32_sigdeliver(void);
+/* Cache flushing ***********************************************************/
+
+void lm32_flush_dcache(void);
+void lm32_flush_icache(void);
+
/* Debug ********************************************************************/
void lm32_dumpstate(void);
diff --git a/arch/rgmp/include/types.h b/arch/misoc/src/lm32/lm32_flushcache.c
similarity index 58%
rename from arch/rgmp/include/types.h
rename to arch/misoc/src/lm32/lm32_flushcache.c
index 1f515cb70c6..8d1d653a6b5 100644
--- a/arch/rgmp/include/types.h
+++ b/arch/misoc/src/lm32/lm32_flushcache.c
@@ -1,8 +1,8 @@
/****************************************************************************
- * arch/rgmp/include/types.h
+ * arch/misoc/src/lm32/lm32_flushcache.c
*
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
- * Author: Gregory Nutt
+ * Copyright (C) 2016 Gregory Nutt. All rights reserved.
+ * Author: Ramtin Amin
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -14,7 +14,7 @@
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
- * 3. Neither the name Gregory Nutt nor the names of its contributors may be
+ * 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -33,64 +33,54 @@
*
****************************************************************************/
-/* This file should never be included directed but, rather,
- * only indirectly through sys/types.h
- */
-
-#ifndef __ARCH_RGMP_INCLUDE_TYPES_H
-#define __ARCH_RGMP_INCLUDE_TYPES_H
-
/****************************************************************************
* Included Files
****************************************************************************/
+#include
+#include
+
+#include "chip.h"
+#include "lm32.h"
+
/****************************************************************************
- * Pre-processor Definitions
+ * Public Functions
****************************************************************************/
/****************************************************************************
- * Type Declarations
+ * Name: lm32_flush_dcache
+ *
+ * Description:
+ * Flush the data cache of the cpu
+ *
****************************************************************************/
-#ifndef __ASSEMBLY__
-
-/* These are the sizes of the standard integer types. NOTE that these type
- * names have a leading underscore character. This file will be included
- * (indirectly) by include/stdint.h and typedef'ed to the final name without
- * the underscore character. This roundabout way of doings things allows
- * the stdint.h to be removed from the include/ directory in the event that
- * the user prefers to use the definitions provided by their toolchain header
- * files
- */
-
-typedef char _int8_t;
-typedef unsigned char _uint8_t;
-
-typedef short _int16_t;
-typedef unsigned short _uint16_t;
-
-typedef int _int32_t;
-typedef unsigned int _uint32_t;
-
-typedef long long _int64_t;
-typedef unsigned long long _uint64_t;
-#define __INT64_DEFINED
-
-/* A pointer is 4 bytes */
-
-typedef unsigned int _intptr_t;
-typedef unsigned int _uintptr_t;
-
-/* This is the size of the interrupt state save returned by
- * up_irq_save()
- */
-
-typedef unsigned int irqstate_t;
-
-#endif /* __ASSEMBLY__ */
+void lm32_flush_dcache(void)
+{
+ asm volatile(
+ "wcsr DCC, r0\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ );
+}
/****************************************************************************
- * Public Function Prototypes
+ * Name: lm32_flush_icache
+ *
+ * Description:
+ * Flush the instruction cache of the cpu
+ *
****************************************************************************/
-#endif /* __ARCH_RGMP_INCLUDE_TYPES_H */
+void lm32_flush_icache(void)
+{
+ asm volatile(
+ "wcsr ICC, r0\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ "nop\n"
+ );
+}
diff --git a/arch/misoc/src/lm32/lm32_initialize.c b/arch/misoc/src/lm32/lm32_initialize.c
index dd93cce4b65..1c4323215af 100644
--- a/arch/misoc/src/lm32/lm32_initialize.c
+++ b/arch/misoc/src/lm32/lm32_initialize.c
@@ -77,4 +77,9 @@ void up_initialize(void)
/* Initialize the system timer */
misoc_timer_initialize();
+
+ /* Initialize the network cores */
+
+ misoc_net_initialize(0);
+
}
diff --git a/arch/misoc/src/lm32/lm32_schedulesigaction.c b/arch/misoc/src/lm32/lm32_schedulesigaction.c
index 15f06e0e779..d72e68cf64c 100644
--- a/arch/misoc/src/lm32/lm32_schedulesigaction.c
+++ b/arch/misoc/src/lm32/lm32_schedulesigaction.c
@@ -97,7 +97,6 @@
void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
{
irqstate_t flags;
- uint32_t int_ctx;
sinfo("tcb=0x%p sigdeliver=0x%p\n", tcb, sigdeliver);
@@ -155,7 +154,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
* disabled
*/
- g_current_regs[REG_EPC] = (uint32_t)up_sigdeliver;
+ g_current_regs[REG_EPC] = (uint32_t)lm32_sigdeliver;
g_current_regs[REG_INT_CTX] = 0;
@@ -192,7 +191,7 @@ void up_schedule_sigaction(struct tcb_s *tcb, sig_deliver_t sigdeliver)
* disabled
*/
- tcb->xcp.regs[REG_EPC] = (uint32_t)up_sigdeliver;
+ tcb->xcp.regs[REG_EPC] = (uint32_t)lm32_sigdeliver;
tcb->xcp.regs[REG_INT_CTX] = 0;
sinfo("PC/STATUS Saved: %08x/%08x New: %08x/%08x\n",
diff --git a/arch/misoc/src/lm32/lm32_sigdeliver.c b/arch/misoc/src/lm32/lm32_sigdeliver.c
index ce3378e57df..f8896914697 100644
--- a/arch/misoc/src/lm32/lm32_sigdeliver.c
+++ b/arch/misoc/src/lm32/lm32_sigdeliver.c
@@ -59,7 +59,7 @@
****************************************************************************/
/****************************************************************************
- * Name: up_sigdeliver
+ * Name: lm32_sigdeliver
*
* Description:
* This is the a signal handling trampoline. When a signal action was
@@ -68,7 +68,7 @@
*
****************************************************************************/
-void up_sigdeliver(void)
+void lm32_sigdeliver(void)
{
struct tcb_s *rtcb = this_task();
uint32_t regs[XCPTCONTEXT_REGS];
diff --git a/arch/rgmp/Kconfig b/arch/rgmp/Kconfig
deleted file mode 100644
index 690f88e6145..00000000000
--- a/arch/rgmp/Kconfig
+++ /dev/null
@@ -1,46 +0,0 @@
-#
-# For a description of the syntax of this configuration file,
-# see the file kconfig-language.txt in the NuttX tools repository.
-#
-
-if ARCH_RGMP
-comment "RGMP Configuration Options"
-
-choice
- prompt "RGMP Architecture"
- default RGMP_SUBARCH_X86
-
-config RGMP_SUBARCH_ARM
- bool "ARM"
- ---help---
- RGMP ARM architecture"
-
-config RGMP_SUBARCH_X86
- bool "x86"
- ---help---
- RGMP x86 architecture"
-
-endchoice # RGMP Architecture
-
-config RGMP_SUBARCH
- string
- default "arm" if RGMP_SUBARCH_ARM
- default "x86" if RGMP_SUBARCH_X86
-
-menu "x86 Peripheral Selections"
- depends on RGMP_SUBARCH_X86
-
-config COM1
- bool "COM1"
-
-config COM2
- bool "COM1"
-
-config COM3
- bool "COM1"
-
-config COM4
- bool "COM1"
-
-endmenu # x86 Peripheral Selections
-endif # ARCH_RGMP
diff --git a/arch/rgmp/include/.gitignore b/arch/rgmp/include/.gitignore
deleted file mode 100644
index e6460c4a678..00000000000
--- a/arch/rgmp/include/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-/board
-/chip
-
diff --git a/arch/rgmp/include/arch.h b/arch/rgmp/include/arch.h
deleted file mode 100644
index af99356ea16..00000000000
--- a/arch/rgmp/include/arch.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/****************************************************************************
- * arch/rgmp/include/arch.h
- *
- * Copyright (C) 2011 Yu Qiang. All rights reserved.
- * Author: Yu Qiang
- *
- * This file is a part of NuttX:
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-#ifndef __RGMP_ARCH_ARCH_H
-#define __RGMP_ARCH_ARCH_H
-
-#include
-
-#ifndef __ASSEMBLY__
-
-#include
-
-struct up_wait {
- struct up_wait *next;
- struct tcb_s *task;
-};
-
-extern struct tcb_s *current_task;
-
-void up_sigentry(void);
-
-int up_register_bridge(char *name, int size);
-int up_unregister_bridge(char *name);
-
-#endif /* !__ASSEMBLY__ */
-
-#endif
diff --git a/arch/rgmp/include/inttypes.h b/arch/rgmp/include/inttypes.h
deleted file mode 100644
index 4d3d40aef2e..00000000000
--- a/arch/rgmp/include/inttypes.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/****************************************************************************
- * arch/rgmp/include/inttypes.h
- *
- * Copyright (C) 2016 Omni Hoverboards Inc. All rights reserved.
- * Author: Paul Alexander Patience
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-#ifndef __ARCH_RGMP_INCLUDE_INTTYPES_H
-#define __ARCH_RGMP_INCLUDE_INTTYPES_H
-
-/****************************************************************************
- * Included Files
- ****************************************************************************/
-
-/****************************************************************************
- * Pre-processor Definitions
- ****************************************************************************/
-
-#define PRId8 "d"
-#define PRId16 "d"
-#define PRId32 "d"
-#define PRId64 "lld"
-
-#define PRIdLEAST8 "d"
-#define PRIdLEAST16 "d"
-#define PRIdLEAST32 "d"
-#define PRIdLEAST64 "lld"
-
-#define PRIdFAST8 "d"
-#define PRIdFAST16 "d"
-#define PRIdFAST32 "d"
-#define PRIdFAST64 "lld"
-
-#define PRIdMAX "lld"
-#define PRIdPTR "d"
-
-#define PRIi8 "i"
-#define PRIi16 "i"
-#define PRIi32 "i"
-#define PRIi64 "lli"
-
-#define PRIiLEAST8 "i"
-#define PRIiLEAST16 "i"
-#define PRIiLEAST32 "i"
-#define PRIiLEAST64 "lli"
-
-#define PRIiFAST8 "i"
-#define PRIiFAST16 "i"
-#define PRIiFAST32 "i"
-#define PRIiFAST64 "lli"
-
-#define PRIiMAX "lli"
-#define PRIiPTR "i"
-
-#define PRIo8 "o"
-#define PRIo16 "o"
-#define PRIo32 "o"
-#define PRIo64 "llo"
-
-#define PRIoLEAST8 "o"
-#define PRIoLEAST16 "o"
-#define PRIoLEAST32 "o"
-#define PRIoLEAST64 "llo"
-
-#define PRIoFAST8 "o"
-#define PRIoFAST16 "o"
-#define PRIoFAST32 "o"
-#define PRIoFAST64 "llo"
-
-#define PRIoMAX "llo"
-#define PRIoPTR "o"
-
-#define PRIu8 "u"
-#define PRIu16 "u"
-#define PRIu32 "u"
-#define PRIu64 "llu"
-
-#define PRIuLEAST8 "u"
-#define PRIuLEAST16 "u"
-#define PRIuLEAST32 "u"
-#define PRIuLEAST64 "llu"
-
-#define PRIuFAST8 "u"
-#define PRIuFAST16 "u"
-#define PRIuFAST32 "u"
-#define PRIuFAST64 "llu"
-
-#define PRIuMAX "llu"
-#define PRIuPTR "u"
-
-#define PRIx8 "x"
-#define PRIx16 "x"
-#define PRIx32 "x"
-#define PRIx64 "llx"
-
-#define PRIxLEAST8 "x"
-#define PRIxLEAST16 "x"
-#define PRIxLEAST32 "x"
-#define PRIxLEAST64 "llx"
-
-#define PRIxFAST8 "x"
-#define PRIxFAST16 "x"
-#define PRIxFAST32 "x"
-#define PRIxFAST64 "llx"
-
-#define PRIxMAX "llx"
-#define PRIxPTR "x"
-
-#define PRIX8 "X"
-#define PRIX16 "X"
-#define PRIX32 "X"
-#define PRIX64 "llX"
-
-#define PRIXLEAST8 "X"
-#define PRIXLEAST16 "X"
-#define PRIXLEAST32 "X"
-#define PRIXLEAST64 "llX"
-
-#define PRIXFAST8 "X"
-#define PRIXFAST16 "X"
-#define PRIXFAST32 "X"
-#define PRIXFAST64 "llX"
-
-#define PRIXMAX "llX"
-#define PRIXPTR "X"
-
-#define SCNd8 "hhd"
-#define SCNd16 "hd"
-#define SCNd32 "d"
-#define SCNd64 "lld"
-
-#define SCNdLEAST8 "hhd"
-#define SCNdLEAST16 "hd"
-#define SCNdLEAST32 "d"
-#define SCNdLEAST64 "lld"
-
-#define SCNdFAST8 "hhd"
-#define SCNdFAST16 "hd"
-#define SCNdFAST32 "d"
-#define SCNdFAST64 "lld"
-
-#define SCNdMAX "lld"
-#define SCNdPTR "d"
-
-#define SCNi8 "hhi"
-#define SCNi16 "hi"
-#define SCNi32 "i"
-#define SCNi64 "lli"
-
-#define SCNiLEAST8 "hhi"
-#define SCNiLEAST16 "hi"
-#define SCNiLEAST32 "i"
-#define SCNiLEAST64 "lli"
-
-#define SCNiFAST8 "hhi"
-#define SCNiFAST16 "hi"
-#define SCNiFAST32 "i"
-#define SCNiFAST64 "lli"
-
-#define SCNiMAX "lli"
-#define SCNiPTR "i"
-
-#define SCNo8 "hho"
-#define SCNo16 "ho"
-#define SCNo32 "o"
-#define SCNo64 "llo"
-
-#define SCNoLEAST8 "hho"
-#define SCNoLEAST16 "ho"
-#define SCNoLEAST32 "o"
-#define SCNoLEAST64 "llo"
-
-#define SCNoFAST8 "hho"
-#define SCNoFAST16 "ho"
-#define SCNoFAST32 "o"
-#define SCNoFAST64 "llo"
-
-#define SCNoMAX "llo"
-#define SCNoPTR "o"
-
-#define SCNu8 "hhu"
-#define SCNu16 "hu"
-#define SCNu32 "u"
-#define SCNu64 "llu"
-
-#define SCNuLEAST8 "hhu"
-#define SCNuLEAST16 "hu"
-#define SCNuLEAST32 "u"
-#define SCNuLEAST64 "llu"
-
-#define SCNuFAST8 "hhu"
-#define SCNuFAST16 "hu"
-#define SCNuFAST32 "u"
-#define SCNuFAST64 "llu"
-
-#define SCNuMAX "llu"
-#define SCNuPTR "u"
-
-#define SCNx8 "hhx"
-#define SCNx16 "hx"
-#define SCNx32 "x"
-#define SCNx64 "llx"
-
-#define SCNxLEAST8 "hhx"
-#define SCNxLEAST16 "hx"
-#define SCNxLEAST32 "x"
-#define SCNxLEAST64 "llx"
-
-#define SCNxFAST8 "hhx"
-#define SCNxFAST16 "hx"
-#define SCNxFAST32 "x"
-#define SCNxFAST64 "llx"
-
-#define SCNxMAX "llx"
-#define SCNxPTR "x"
-
-#endif /* __ARCH_RGMP_INCLUDE_INTTYPES_H */
diff --git a/arch/rgmp/include/irq.h b/arch/rgmp/include/irq.h
deleted file mode 100644
index b4c4f37d2d0..00000000000
--- a/arch/rgmp/include/irq.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/****************************************************************************
- * arch/rgmp/include/irq.h
- *
- * Copyright (C) 2011 Yu Qiang. All rights reserved.
- * Author: Yu Qiang
- *
- * This file is a part of NuttX:
- *
- * Copyright (C) 2011 Gregory Nutt. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in
- * the documentation and/or other materials provided with the
- * distribution.
- * 3. Neither the name NuttX nor the names of its contributors may be
- * used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
- * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
- * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
- * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- *
- ****************************************************************************/
-
-#ifndef __ARCH_RGMP_INCLUDE_IRQ_H
-#define __ARCH_RGMP_INCLUDE_IRQ_H
-
-#define NR_IRQS 0
-
-#ifndef __ASSEMBLY__
-
-#include
-
-#include