Merged nuttx/nuttx into master

This commit is contained in:
Aleksandr Vyhovanec 2016-12-08 11:41:11 +03:00
commit 79b2e13ddc
809 changed files with 17479 additions and 20581 deletions

View file

@ -4920,34 +4920,6 @@ Mem: 29232 5920 23312 23312
</ul>
</td>
</tr>
<tr>
<td><br></td>
<td><hr></td>
</tr>
<tr>
<td><br></td>
<td>
<p>
<b>RGMP</b>.
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.
</p>
<p>
See the <a href="http://rgmp.sourceforge.net/wiki/index.php/Main_Page">RGMP Wiki</a> for further information about RGMP.
</p>
<ul>
<p>
<b>STATUS:</b>
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 <a href="https://bitbucket.org/nuttx/nuttx/src/master/configs/rgmp/README.txt" target="_blank">README</a> file for further information.
</p>
</ul>
</td>
</tr>
<tr>
<td valign="top"><img height="20" width="20" src="favicon.ico"></td>
<td bgcolor="#5eaee1">

View file

@ -8,7 +8,7 @@
<tr align="center" bgcolor="#e4e4e4">
<td>
<h1><big><font color="#3c34ec"><i>NuttX README Files</i></font></big></h1>
<p>Last Updated: November 14, 2016</p>
<p>Last Updated: December 4, 2016</p>
</td>
</tr>
</table>
@ -203,8 +203,6 @@ nuttx/
| | `- <a href="https://bitbucket.org/nuttx/nuttx/src/master/configs/pirelli_dpl10/README.txt" target="_blank"><b><i>README.txt</i></b></a>
| |- qemu-i486/
| | `- <a href="https://bitbucket.org/nuttx/nuttx/src/master/configs/qemu-i486/README.txt" target="_blank"><b><i>README.txt</i></b></a>
| |- rgmp/
| | `- <a href="https://bitbucket.org/nuttx/nuttx/src/master/configs/rgmp/README.txt" target="_blank"><b><i>README.txt</i></b></a>
| |- sabre-6quad/
| | `- <a href="https://bitbucket.org/nuttx/nuttx/src/master/configs/sabre-6quad/README.txt" target="_blank"><b><i>README.txt</i></b></a>
| |- sama5d2-xult/
@ -223,6 +221,8 @@ nuttx/
| | `- <a href="https://bitbucket.org/nuttx/nuttx/src/master/configs/saml21-xplained/README.txt" target="_blank"><b><i>README.txt</i></b></a>
| |- sam3u-ek/
| | `- <a href="https://bitbucket.org/nuttx/nuttx/src/master/configs/sam3u-ek/README.txt" target="_blank"><b><i>README.txt</i></b></a>
| |- sam4cmp-db
| | `- <a href="https://bitbucket.org/nuttx/nuttx/src/master/configs/sam4cmp-d/README.txt" target="_blank"><b><i>README.txt</i></b></a>
| |- sam4e-ek/
| | `- <a href="https://bitbucket.org/nuttx/nuttx/src/master/configs/sam4e-ek/README.txt" target="_blank"><b><i>README.txt</i></b></a>
| |- sam4l-xplained/

View file

@ -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/

89
TODO
View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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 <yuq825@gmail.com>
*
* 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 <gnutt@nuttx.org>
*
* 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
#endif /* __ARCH_ARM_INCLUDE_ARM_SPINLOCK_H */

View file

@ -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 <yuq825@gmail.com>
*
* 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 <gnutt@nuttx.org>
*
* 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 */

View file

@ -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 <yuq825@gmail.com>
*
* 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 <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
/****************************************************************************
* 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 <rgmp/arch/hpet.h>
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 */

View file

@ -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 <keytwo@gmail.com>
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 */

View file

@ -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 <yuq825@gmail.com>
*
* 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 <gnutt@nuttx.org>
*
* 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
#endif /* __ARCH_ARM_INCLUDE_ARMV7_R_SPINLOCK_H */

View file

@ -44,6 +44,26 @@
# include <stdint.h>
#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 <arch/armv7-a/spinlock.h>
#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 <arch/armv7-r/spinlock.h>
#elif defined(CONFIG_ARCH_CORTEXM3) || defined(CONFIG_ARCH_CORTEXM4) || \
defined(CONFIG_ARCH_CORTEXM7)
# include <arch/armv7-m/spinlock.h>
#elif defined(CONFIG_ARCH_CORTEXM0)
# include <arch/armv6-m/spinlock.h>
#else
# include <arch/arm/spinlock.h>
#endif
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/

View file

@ -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 */

View file

@ -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

View file

@ -44,6 +44,7 @@
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/spinlock.h>
#include <nuttx/sched_note.h>
#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

View file

@ -43,10 +43,11 @@
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#include <nuttx/sched_note.h>
#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);

View file

@ -40,10 +40,10 @@
#include <nuttx/config.h>
#include <stdint.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <assert.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/board.h>
#include <arch/board/board.h>
@ -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

View file

@ -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 */

View file

@ -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

View file

@ -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

View file

@ -0,0 +1,227 @@
/****************************************************************************
* arch/arm/src/armv7-a/arm_scu.c
*
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* 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 <nuttx/config.h>
#include <stdint.h>
#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

View file

@ -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
************************************************************************************/

View file

@ -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
*

176
arch/arm/src/armv7-a/scu.h Normal file
View file

@ -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 <gnutt@nuttx.org>
*
* 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 */

View file

@ -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);

View file

@ -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
}
}

View file

@ -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;

View file

@ -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
************************************************************************************/

View file

@ -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

File diff suppressed because it is too large Load diff

View file

@ -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,

View file

@ -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)

View file

@ -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
/************************************************************************************

View file

@ -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');
}

View file

@ -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

View file

@ -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.

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -254,7 +254,6 @@ config KINETIS_ENET
select ARCH_HAVE_NETDEV_STATISTICS
select NET
select NETDEVICES
select NET_MULTIBUFFER
---help---
Support Ethernet (K6x only)

View file

@ -53,14 +53,11 @@
#include <nuttx/wdog.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
#ifdef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
#ifdef CONFIG_NET_PKT
# include <nuttx/net/pkt.h>
#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;
}

View file

@ -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?
*/

View file

@ -52,15 +52,12 @@
#include <nuttx/wdog.h>
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
#ifdef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
#ifdef CONFIG_NET_PKT
# include <nuttx/net/pkt.h>
#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"

View file

@ -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 */

View file

@ -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) */

View file

@ -53,11 +53,7 @@
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#ifdef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
@ -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;
}

View file

@ -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 <gnutt@nuttx.org>
*
* 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 */

View file

@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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 */

View file

@ -0,0 +1,136 @@
/****************************************************************************
* arch/arm/src/sam34/sam4cm_cpuidlestack.c
*
* Copyright (C) 2016 Masayuki Ishikawa. All rights reserved.
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
*
* 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 <nuttx/config.h>
#include <sys/types.h>
#include <nuttx/arch.h>
#include <nuttx/sched.h>
#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 */

View file

@ -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 <yuq825@gmail.com>
*
* 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 <masayuki.ishikawa@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -37,53 +33,45 @@
*
****************************************************************************/
#include <rgmp/mmu.h>
#include <rgmp/string.h>
/****************************************************************************
* Included Files
****************************************************************************/
#include <arch/arch.h>
#include <nuttx/sched.h>
#include <nuttx/config.h>
#include <stdint.h>
#include <nuttx/arch.h>
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)
{
}

View file

@ -0,0 +1,328 @@
/****************************************************************************
* arch/arm/src/sam34/sam4cm_cpupause.c
*
* Copyright (C) 2016 Masayuki Ishikawa. All rights reserved.
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
*
* 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 <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <string.h>
#include <stdio.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#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 */

View file

@ -0,0 +1,243 @@
/****************************************************************************
* arch/arm/src/sam34/sam4cm_cpustart.c
*
* Copyright (C) 2016 Masayuki Ishikawa. All rights reserved.
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
*
* 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 <nuttx/config.h>
#include <stdint.h>
#include <assert.h>
#include <debug.h>
#include <string.h>
#include <stdio.h>
#include <nuttx/arch.h>
#include <nuttx/spinlock.h>
#include <nuttx/sched_note.h>
#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 */

View file

@ -0,0 +1,77 @@
/****************************************************************************
* arch/arm/src/sam34/sam4cm_idle.c
*
* Copyright (C) 2016 Masayuki Ishikawa. All rights reserved.
* Author: Masayuki Ishikawa <masayuki.ishikawa@gmail.com>
*
* 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 <nuttx/config.h>
#include <nuttx/arch.h>
#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
}

View file

@ -64,11 +64,7 @@
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#include <nuttx/kmalloc.h>
#ifdef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
@ -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 */

View file

@ -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).

View file

@ -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 */

View file

@ -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

View file

@ -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 */

View file

@ -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 <gnutt@nuttx.org>
*
* References:
@ -65,6 +65,7 @@
#include <nuttx/arch.h>
#include <nuttx/wdog.h>
#include <nuttx/kmalloc.h>
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
@ -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 */

View file

@ -79,11 +79,7 @@
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#include <nuttx/kmalloc.h>
#ifdef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
@ -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 */

View file

@ -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 <gnutt@nuttx.org>
*
* References:
@ -62,6 +62,7 @@
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#include <nuttx/kmalloc.h>
#include <nuttx/wqueue.h>
#include <nuttx/net/gmii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
@ -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 */

View file

@ -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 <gnutt@nuttx.org>
*
* 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 */

View file

@ -69,11 +69,7 @@
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#include <nuttx/kmalloc.h>
#ifdef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
@ -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 */

View file

@ -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"

View file

@ -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 */

File diff suppressed because it is too large Load diff

View file

@ -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 */

View file

@ -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);
}

View file

@ -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 <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -53,14 +53,11 @@
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#ifdef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
#if defined(CONFIG_NET_PKT)
# include <nuttx/net/pkt.h>
#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;
}

View file

@ -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);

View file

@ -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 */

View file

@ -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

View file

@ -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 */

View file

@ -46,7 +46,7 @@
#include <stdint.h>
#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)

View file

@ -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
}
/****************************************************************************

View file

@ -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 */

View file

@ -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 <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -52,14 +52,11 @@
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#ifdef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
#if defined(CONFIG_NET_PKT)
# include <nuttx/net/pkt.h>
#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;
}

View file

@ -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 */

View file

@ -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

View file

@ -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. */

View file

@ -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

View file

@ -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

View file

@ -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 <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@ -52,6 +52,8 @@
#include <nuttx/arch.h>
#include <nuttx/wdog.h>
#include <nuttx/irq.h>
#include <nuttx/wqueue.h>
#include <arch/board/board.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
@ -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 */

View file

@ -53,11 +53,7 @@
#include <nuttx/arch.h>
#include <nuttx/irq.h>
#include <nuttx/wdog.h>
#ifdef CONFIG_NET_NOINTS
# include <nuttx/wqueue.h>
#endif
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/arp.h>
#include <nuttx/net/netdev.h>
@ -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;
}

View file

@ -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 <gnutt@nuttx.org>
*
* 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().

View file

@ -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)"

View file

@ -55,6 +55,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/wdog.h>
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/arp.h>
@ -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;
}

View file

@ -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)"

View file

@ -55,6 +55,7 @@
#include <nuttx/irq.h>
#include <nuttx/arch.h>
#include <nuttx/wdog.h>
#include <nuttx/wqueue.h>
#include <nuttx/net/mii.h>
#include <nuttx/net/netconfig.h>
#include <nuttx/net/arp.h>
@ -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

View file

@ -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

View file

@ -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 */

View file

@ -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 <gnutt@nuttx.org>
* Author: Ramtin Amin <keytwo@gmail.com>
*
* 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 <nuttx/config.h>
#include <nuttx/compiler.h>
#include <nuttx/arch.h>
#include "misoc.h"
#include <stdint.h>
#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
}

File diff suppressed because it is too large Load diff

View file

@ -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

View file

@ -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);

View file

@ -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 <gnutt@nuttx.org>
* Copyright (C) 2016 Gregory Nutt. All rights reserved.
* Author: Ramtin Amin <keytwo@gmail.com>
*
* 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 <nuttx/config.h>
#include <nuttx/arch.h>
#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"
);
}

View file

@ -77,4 +77,9 @@ void up_initialize(void)
/* Initialize the system timer */
misoc_timer_initialize();
/* Initialize the network cores */
misoc_net_initialize(0);
}

View file

@ -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",

Some files were not shown because too many files have changed in this diff Show more