mirror of
https://github.com/apache/nuttx.git
synced 2026-09-06 08:56:32 +00:00
Merged nuttx/nuttx into master
This commit is contained in:
commit
79b2e13ddc
809 changed files with 17479 additions and 20581 deletions
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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/
|
||||
|
|
|
|||
|
|
@ -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
89
TODO
|
|
@ -1,4 +1,4 @@
|
|||
NuttX TODO List (Last updated November 22, 2016)
|
||||
NuttX TODO List (Last updated December 3, 2016)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
||||
|
|
@ -308,33 +308,33 @@ o Task/Scheduler (sched/)
|
|||
o SMP
|
||||
^^^
|
||||
|
||||
Title: SPINLOCKS AND DATA CACHES
|
||||
Description: If spinlocks are used in a system with a data cache, then there
|
||||
may be a problem with cache coherency in some CPU architectures:
|
||||
When one CPU modifies the spinlock, the changes may not be
|
||||
visible to another CPU if it does not share the data cache.
|
||||
That would cause failure in the spinlock logic.
|
||||
Title: SMP AND DATA CACHES
|
||||
Description: When spinlocks, semaphores, etc. are used in an SMP system with
|
||||
a data cache, then there may be problems with cache coherency
|
||||
in some CPU architectures: When one CPU modifies the shared
|
||||
object, the changes may not be visible to another CPU if it
|
||||
does not share the data cache. That would cause failure in
|
||||
the IPC logic.
|
||||
|
||||
Flushing the D-cache on writes and invalidating before a read is
|
||||
not really an option. spinlocks are normally 8-bits in size and
|
||||
cache lines are typically 32-bytes so that would have side effects
|
||||
unless the spinlocks were made to be the same size as one cache
|
||||
line.
|
||||
not really an option. That would essentially effect every memory
|
||||
access and there may be side-effects due to cache line sizes
|
||||
and alignment.
|
||||
|
||||
This might be doable if a write-through cache is used. Then you
|
||||
could always safely invalidate the cache line before reading the
|
||||
spinlock because there should never be any dirty cache lines in
|
||||
this case.
|
||||
For the same reason a separate, non-cacheable memory region is
|
||||
not an option. Essentially all data would have to go in the
|
||||
non-cached region and you would have no benefit from the data
|
||||
cache.
|
||||
|
||||
The better option is to add compiler independent "ornamentation"
|
||||
to the spinlock so that the spinlocks are all linked together
|
||||
into a separate, non-cacheable memory regions. Because of
|
||||
region alignment and minimum region mapping sizes this could
|
||||
still be wasteful of memory. This would work in systems that
|
||||
have both data cache and either an MPU or an MMU.
|
||||
Status: Open
|
||||
Priority: High. spinlocks, and hence SMP, will not work on such systems
|
||||
without this change.
|
||||
On ARM Cortex-A, each CPU has a separate data cache. However,
|
||||
the MPCore's Snoop Controller Unit supports coherency among
|
||||
the different caches. The SCU is enabled by the SCU control
|
||||
register and each CPU participates in the SMP coherency by
|
||||
setting the ACTLR_SMP bit in the auxiliary control register
|
||||
(ACTLR).
|
||||
|
||||
Status: Closed
|
||||
Priority: High on platforms that may have the issue.
|
||||
|
||||
o Memory Management (mm/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
|
@ -1043,41 +1043,18 @@ o Network (net/, drivers/net)
|
|||
Priority: Medium. Important on slow applications that will not accept
|
||||
connections promptly.
|
||||
|
||||
Title: INTERRUPT LEVEL PROCESSING IN ETHERNET DRIVERS
|
||||
Description: Too many Ethernet drivers do interrupt-level processing with
|
||||
the network stack. The network stack supports either interrupt
|
||||
level processing or normal task level processing (depending on
|
||||
CONFIG_NET_NOINTS). This is really a very bad use of CPU
|
||||
resources; All of the network stack processing should be
|
||||
modified to use a work queue (and, all use of CONFIG_NET_NOINTS=n
|
||||
should be eliminated). This applies to many Ethernet drivers:
|
||||
Title: IPv6 REQUIRES ADDRESS FILTER SUPPORT
|
||||
Description: IPv6 requires that the Ethernet driver support NuttX address
|
||||
filter interfaces. Several Ethernet drivers do support there,
|
||||
however. Others support the address filtering interfaces but
|
||||
have never been verifed:
|
||||
|
||||
ARCHITECTURE CONFIG_NET_NOINTS? ADDRESS FILTER SUPPORT?
|
||||
C5471 NO NO
|
||||
STM32 YES YES
|
||||
STM32F7 YES YES
|
||||
TIVA ----------------------- ------
|
||||
LM3S NO NO
|
||||
TM4C YES YES
|
||||
eZ80 NO NO
|
||||
Kinetis YES YES (not tested)
|
||||
LPC17xx YES YES (not tested)
|
||||
LPC43xx YES YES (not tested)
|
||||
DMxxx NIC NO NO
|
||||
PIC32 NO NO
|
||||
RGMP ??? ???
|
||||
SAM3/4 YES YES
|
||||
SAMA5D ----------------------- ------
|
||||
EMACA NO YES (not tested)
|
||||
EMACB YES YES
|
||||
GMAC NO YES (not tested)
|
||||
SAMV7 YES YES
|
||||
SIM N/A (No interrupts) NO
|
||||
C5471, LM3X, ez80, DM0x90 NIC, PIC: Do not support address
|
||||
filteringing.
|
||||
Kinetis, LPC17xx, LPC43xx: Untested address filter support
|
||||
|
||||
The general outline of how this might be done is included in
|
||||
drivers/net/skeleton.c
|
||||
Status: Open
|
||||
Priority: Pretty high if you want a well behaved system.
|
||||
Priority: Pretty high if you want a to use IPv6 on these platforms.
|
||||
|
||||
Title: UDP MULTICAST RECEPTION
|
||||
Description: The logic in udp_input() expects either a single receive socket or
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -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
|
||||
****************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
227
arch/arm/src/armv7-a/arm_scu.c
Normal file
227
arch/arm/src/armv7-a/arm_scu.c
Normal 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
|
||||
|
|
@ -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
|
||||
************************************************************************************/
|
||||
|
|
|
|||
|
|
@ -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
176
arch/arm/src/armv7-a/scu.h
Normal 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 */
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
************************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
/************************************************************************************
|
||||
|
|
|
|||
|
|
@ -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');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
1445
arch/arm/src/imx6/imx_ecspi.c
Normal file
1445
arch/arm/src/imx6/imx_ecspi.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -254,7 +254,6 @@ config KINETIS_ENET
|
|||
select ARCH_HAVE_NETDEV_STATISTICS
|
||||
select NET
|
||||
select NETDEVICES
|
||||
select NET_MULTIBUFFER
|
||||
---help---
|
||||
Support Ethernet (K6x only)
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
*/
|
||||
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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) */
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
136
arch/arm/src/sam34/sam4cm_cpuidlestack.c
Normal file
136
arch/arm/src/sam34/sam4cm_cpuidlestack.c
Normal 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 */
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
328
arch/arm/src/sam34/sam4cm_cpupause.c
Normal file
328
arch/arm/src/sam34/sam4cm_cpupause.c
Normal 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 */
|
||||
243
arch/arm/src/sam34/sam4cm_cpustart.c
Normal file
243
arch/arm/src/sam34/sam4cm_cpustart.c
Normal 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 */
|
||||
77
arch/arm/src/sam34/sam4cm_idle.c
Normal file
77
arch/arm/src/sam34/sam4cm_idle.c
Normal 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
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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().
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
1228
arch/misoc/src/common/misoc_net.c
Normal file
1228
arch/misoc/src/common/misoc_net.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
|
|
@ -77,4 +77,9 @@ void up_initialize(void)
|
|||
/* Initialize the system timer */
|
||||
|
||||
misoc_timer_initialize();
|
||||
|
||||
/* Initialize the network cores */
|
||||
|
||||
misoc_net_initialize(0);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue