mirror of
https://github.com/apache/nuttx.git
synced 2026-05-31 23:40:19 +08:00
Merge remote-tracking branch 'origin/master' into ieee802154
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
NuttX TODO List (Last updated April 15, 2017)
|
||||
NuttX TODO List (Last updated May 18, 2017)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
This file summarizes known NuttX bugs, limitations, inconsistencies with
|
||||
@@ -25,7 +25,7 @@ nuttx/:
|
||||
(12) Libraries (libc/, libm/)
|
||||
(10) File system/Generic drivers (fs/, drivers/)
|
||||
(9) Graphics Subsystem (graphics/)
|
||||
(2) Build system / Toolchains
|
||||
(3) Build system / Toolchains
|
||||
(3) Linux/Cywgin simulation (arch/sim)
|
||||
(4) ARM (arch/arm/)
|
||||
|
||||
@@ -1825,6 +1825,43 @@ o Build system
|
||||
Priority: Low, since I am not aware of anyone using the Windows Native build.
|
||||
But, of course, very high if you want to use it.
|
||||
|
||||
Title: CONTROL-C CAN BREAK DEPENDENCIES
|
||||
Description: If you control C out of a make, then there are things that can go
|
||||
wrong. For one, you can break the dependencies in this scenario:
|
||||
|
||||
- The build in a given directory begins with all of the compilations.
|
||||
On terminal, this the long phase with CC: on each line. As each
|
||||
.o file is created, it is timestamped with the current time.
|
||||
|
||||
- The dependencies on each .o are such that the C file will be re-
|
||||
compile if the .o file is OLDER that the corresponding .a archive
|
||||
file.
|
||||
|
||||
- The compilation phase is followed by a single, relatively short
|
||||
AR: phase that adds each of the file to the .a archive file. As
|
||||
each file is added to archive, the timestamp of the of archive is
|
||||
updated to the current time. After the first .o file has been
|
||||
added, then archive file will have a newly timestamp than any of
|
||||
the newly compiled .o file.
|
||||
|
||||
- If the user aborts with control-C during this AR: phase, then we
|
||||
are left with: (1) not all of the files have bee added to the
|
||||
archive, and (2) the archive file has a newer timestamp than any
|
||||
of the .o file.
|
||||
|
||||
So when the make is restarted after a control, the dependencies will
|
||||
see that the .a archive file has the newer time stamp and those .o
|
||||
file will never be added to the archive until the directory is cleaned
|
||||
or some other dependency changes.
|
||||
Status Open
|
||||
Priority: Medium-High. It is a rare event that control-C happens at just the
|
||||
point in time. However, when it does occur the resulting code may
|
||||
have binary incompatiblies in the code taken from the out-of-sync
|
||||
archives and cost a lot of debug time before you realize the issue.
|
||||
|
||||
A work-around is to do 'make clean' if you ever decide to control-C
|
||||
out of a make.
|
||||
|
||||
o Other drivers (drivers/)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@
|
||||
#include <nuttx/irq.h>
|
||||
#include <nuttx/wdog.h>
|
||||
#include <nuttx/wqueue.h>
|
||||
#include <nuttx/net/phy.h>
|
||||
#include <nuttx/net/mii.h>
|
||||
#include <nuttx/net/arp.h>
|
||||
#include <nuttx/net/netdev.h>
|
||||
@@ -189,6 +190,42 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* These definitions are used to enable the PHY interrupts */
|
||||
|
||||
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
|
||||
# if defined( CONFIG_ETH0_PHY_AM79C874)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_KS8721)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_KSZ8041)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_KSZ8051)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_KSZ8061)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_KSZ8081)
|
||||
# define MII_INT_REG MII_KSZ8081_INT
|
||||
# define MII_INT_SETEN MII_KSZ80x1_INT_LDEN | MII_KSZ80x1_INT_LUEN
|
||||
# define MII_INT_CLREN 0
|
||||
# elif defined( CONFIG_ETH0_PHY_KSZ90x1)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_DP83848C)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_LAN8720)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_LAN8740)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_LAN8740A)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_LAN8742A)
|
||||
# error missing logic
|
||||
# elif defined( CONFIG_ETH0_PHY_DM9161)
|
||||
# error missing logic
|
||||
# else
|
||||
# error unknown PHY
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STM32_ETH_PTP
|
||||
# warning "CONFIG_STM32_ETH_PTP is not yet supported"
|
||||
#endif
|
||||
@@ -2889,8 +2926,19 @@ static int stm32_ioctl(struct net_driver_s *dev, int cmd, unsigned long arg)
|
||||
#if defined(CONFIG_NETDEV_PHY_IOCTL) && defined(CONFIG_ARCH_PHY_INTERRUPT)
|
||||
static int stm32_phyintenable(struct stm32_ethmac_s *priv)
|
||||
{
|
||||
#warning Missing logic
|
||||
return -ENOSYS;
|
||||
uint16_t phyval;
|
||||
int ret;
|
||||
|
||||
ret = stm32_phyread(CONFIG_STM32_PHYADDR, MII_INT_REG, &phyval);
|
||||
if (ret == OK)
|
||||
{
|
||||
/* Enable link up/down interrupts */
|
||||
|
||||
ret = stm32_phywrite(CONFIG_STM32_PHYADDR, MII_INT_REG,
|
||||
(phyval & ~MII_INT_CLREN) | MII_INT_SETEN);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1050,10 +1050,10 @@ static inline void up_serialout(struct up_dev_s *priv, int offset, uint32_t valu
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_restoreusartint
|
||||
* Name: up_setusartint
|
||||
****************************************************************************/
|
||||
|
||||
static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie)
|
||||
static inline void up_setusartint(struct up_dev_s *priv, uint16_t ie)
|
||||
{
|
||||
uint32_t cr;
|
||||
|
||||
@@ -1074,12 +1074,31 @@ static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie)
|
||||
up_serialout(priv, STM32_USART_CR3_OFFSET, cr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_restoreusartint
|
||||
****************************************************************************/
|
||||
|
||||
static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
up_setusartint(priv, ie);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_disableusartint
|
||||
****************************************************************************/
|
||||
|
||||
static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie)
|
||||
static void up_disableusartint(struct up_dev_s *priv, uint16_t *ie)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
if (ie)
|
||||
{
|
||||
uint32_t cr1;
|
||||
@@ -1116,7 +1135,9 @@ static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie)
|
||||
|
||||
/* Disable all interrupts */
|
||||
|
||||
up_restoreusartint(priv, 0);
|
||||
up_setusartint(priv, 0);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@@ -318,7 +318,7 @@ static int stm32_i2c_reset(FAR struct i2c_master_s *dev);
|
||||
|
||||
/* Device Structures, Instantiation */
|
||||
|
||||
const struct i2c_ops_s stm32_i2c_ops =
|
||||
static const struct i2c_ops_s stm32_i2c_ops =
|
||||
{
|
||||
.transfer = stm32_i2c_transfer
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
@@ -340,7 +340,7 @@ static const struct stm32_i2c_config_s stm32_i2c1_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32_i2c_priv_s stm32_i2c1_priv =
|
||||
static struct stm32_i2c_priv_s stm32_i2c1_priv =
|
||||
{
|
||||
.ops = &stm32_i2c_ops,
|
||||
.config = &stm32_i2c1_config,
|
||||
@@ -369,7 +369,7 @@ static const struct stm32_i2c_config_s stm32_i2c2_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32_i2c_priv_s stm32_i2c2_priv =
|
||||
static struct stm32_i2c_priv_s stm32_i2c2_priv =
|
||||
{
|
||||
.ops = &stm32_i2c_ops,
|
||||
.config = &stm32_i2c2_config,
|
||||
@@ -398,7 +398,7 @@ static const struct stm32_i2c_config_s stm32_i2c3_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32_i2c_priv_s stm32_i2c3_priv =
|
||||
static struct stm32_i2c_priv_s stm32_i2c3_priv =
|
||||
{
|
||||
.ops = &stm32_i2c_ops,
|
||||
.config = &stm32_i2c3_config,
|
||||
|
||||
@@ -307,7 +307,7 @@ static int stm32f0_i2c_reset(FAR struct i2c_master_s *dev);
|
||||
|
||||
/* Device Structures, Instantiation */
|
||||
|
||||
const struct i2c_ops_s stm32f0_i2c_ops =
|
||||
static const struct i2c_ops_s stm32f0_i2c_ops =
|
||||
{
|
||||
.transfer = stm32f0_i2c_transfer
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
@@ -328,7 +328,7 @@ static const struct stm32f0_i2c_config_s stm32f0_i2c1_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32f0_i2c_priv_s stm32f0_i2c1_priv =
|
||||
static struct stm32f0_i2c_priv_s stm32f0_i2c1_priv =
|
||||
{
|
||||
.ops = &stm32f0_i2c_ops,
|
||||
.config = &stm32f0_i2c1_config,
|
||||
@@ -356,7 +356,7 @@ static const struct stm32f0_i2c_config_s stm32f0_i2c2_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32f0_i2c_priv_s stm32f0_i2c2_priv =
|
||||
static struct stm32f0_i2c_priv_s stm32f0_i2c2_priv =
|
||||
{
|
||||
.ops = &stm32f0_i2c_ops,
|
||||
.config = &stm32f0_i2c2_config,
|
||||
@@ -384,7 +384,7 @@ static const struct stm32f0_i2c_config_s stm32f0_i2c3_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32f0_i2c_priv_s stm32f0_i2c3_priv =
|
||||
static struct stm32f0_i2c_priv_s stm32f0_i2c3_priv =
|
||||
{
|
||||
.ops = &stm32f0_i2c_ops,
|
||||
.config = &stm32f0_i2c3_config,
|
||||
|
||||
@@ -769,10 +769,10 @@ static inline void stm32f0serial_putreg(FAR struct stm32f0_serial_s *priv,
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32f0serial_restoreusartint
|
||||
* Name: stm32f0serial_setusartint
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32f0serial_restoreusartint(FAR struct stm32f0_serial_s *priv,
|
||||
static void stm32f0serial_setusartint(FAR struct stm32f0_serial_s *priv,
|
||||
uint16_t ie)
|
||||
{
|
||||
uint32_t cr;
|
||||
@@ -794,13 +794,33 @@ static void stm32f0serial_restoreusartint(FAR struct stm32f0_serial_s *priv,
|
||||
stm32f0serial_putreg(priv, STM32F0_USART_CR3_OFFSET, cr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32f0serial_restoreusartint
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32f0serial_restoreusartint(FAR struct stm32f0_serial_s *priv,
|
||||
uint16_t ie)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
stm32f0serial_setusartint(priv, ie);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32f0serial_disableusartint
|
||||
****************************************************************************/
|
||||
|
||||
static inline void stm32f0serial_disableusartint(FAR struct stm32f0_serial_s *priv,
|
||||
FAR uint16_t *ie)
|
||||
static void stm32f0serial_disableusartint(FAR struct stm32f0_serial_s *priv,
|
||||
FAR uint16_t *ie)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
if (ie)
|
||||
{
|
||||
uint32_t cr1;
|
||||
@@ -837,7 +857,9 @@ static inline void stm32f0serial_disableusartint(FAR struct stm32f0_serial_s *pr
|
||||
|
||||
/* Disable all interrupts */
|
||||
|
||||
stm32f0serial_restoreusartint(priv, 0);
|
||||
stm32f0serial_setusartint(priv, 0);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
+126
-126
@@ -290,7 +290,7 @@
|
||||
#if !defined(CONFIG_STM32F7_I2CTIMEOSEC) && !defined(CONFIG_STM32F7_I2CTIMEOMS)
|
||||
# define CONFIG_STM32F7_I2CTIMEOSEC 0
|
||||
# define CONFIG_STM32F7_I2CTIMEOMS 500 /* Default is 500 milliseconds */
|
||||
# warning "Using Defualt 500 Ms Timeout"
|
||||
# warning "Using Default 500 Ms Timeout"
|
||||
#elif !defined(CONFIG_STM32F7_I2CTIMEOSEC)
|
||||
# define CONFIG_STM32F7_I2CTIMEOSEC 0 /* User provided milliseconds */
|
||||
#elif !defined(CONFIG_STM32F7_I2CTIMEOMS)
|
||||
@@ -445,7 +445,7 @@ struct stm32_i2c_priv_s
|
||||
|
||||
struct stm32_i2c_inst_s
|
||||
{
|
||||
struct i2c_ops_s *ops; /* Standard I2C operations */
|
||||
const struct i2c_ops_s *ops; /* Standard I2C operations */
|
||||
struct stm32_i2c_priv_s *priv; /* Common driver private data structure */
|
||||
};
|
||||
|
||||
@@ -495,7 +495,7 @@ static int stm32_i2c_process(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s
|
||||
static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s *msgs,
|
||||
int count);
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
int stm32_i2c_reset(FAR struct i2c_master_s * dev);
|
||||
static int stm32_i2c_reset(FAR struct i2c_master_s * dev);
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
@@ -516,7 +516,7 @@ static const struct stm32_i2c_config_s stm32_i2c1_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32_i2c_priv_s stm32_i2c1_priv =
|
||||
static struct stm32_i2c_priv_s stm32_i2c1_priv =
|
||||
{
|
||||
.config = &stm32_i2c1_config,
|
||||
.refs = 0,
|
||||
@@ -545,7 +545,7 @@ static const struct stm32_i2c_config_s stm32_i2c2_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32_i2c_priv_s stm32_i2c2_priv =
|
||||
static struct stm32_i2c_priv_s stm32_i2c2_priv =
|
||||
{
|
||||
.config = &stm32_i2c2_config,
|
||||
.refs = 0,
|
||||
@@ -574,7 +574,7 @@ static const struct stm32_i2c_config_s stm32_i2c3_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32_i2c_priv_s stm32_i2c3_priv =
|
||||
static struct stm32_i2c_priv_s stm32_i2c3_priv =
|
||||
{
|
||||
.config = &stm32_i2c3_config,
|
||||
.refs = 0,
|
||||
@@ -603,7 +603,7 @@ static const struct stm32_i2c_config_s stm32_i2c4_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32_i2c_priv_s stm32_i2c4_priv =
|
||||
static struct stm32_i2c_priv_s stm32_i2c4_priv =
|
||||
{
|
||||
.config = &stm32_i2c4_config,
|
||||
.refs = 0,
|
||||
@@ -620,7 +620,7 @@ struct stm32_i2c_priv_s stm32_i2c4_priv =
|
||||
|
||||
/* Device Structures, Instantiation */
|
||||
|
||||
struct i2c_ops_s stm32_i2c_ops =
|
||||
static const struct i2c_ops_s stm32_i2c_ops =
|
||||
{
|
||||
.transfer = stm32_i2c_transfer
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
@@ -2485,6 +2485,124 @@ static int stm32_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg_s
|
||||
return stm32_i2c_process(dev, msgs, count);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: stm32_i2c_reset
|
||||
*
|
||||
* Description:
|
||||
* Reset an I2C bus
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
static int stm32_i2c_reset(FAR struct i2c_master_s * dev)
|
||||
{
|
||||
struct stm32_i2c_priv_s * priv;
|
||||
unsigned int clock_count;
|
||||
unsigned int stretch_count;
|
||||
uint32_t scl_gpio;
|
||||
uint32_t sda_gpio;
|
||||
int ret = ERROR;
|
||||
|
||||
ASSERT(dev);
|
||||
|
||||
/* Get I2C private structure */
|
||||
|
||||
priv = ((struct stm32_i2c_inst_s *)dev)->priv;
|
||||
|
||||
/* Our caller must own a ref */
|
||||
|
||||
ASSERT(priv->refs > 0);
|
||||
|
||||
/* Lock out other clients */
|
||||
|
||||
stm32_i2c_sem_wait(dev);
|
||||
|
||||
/* De-init the port */
|
||||
|
||||
stm32_i2c_deinit(priv);
|
||||
|
||||
/* Use GPIO configuration to un-wedge the bus */
|
||||
|
||||
scl_gpio = MKI2C_OUTPUT(priv->config->scl_pin);
|
||||
sda_gpio = MKI2C_OUTPUT(priv->config->sda_pin);
|
||||
|
||||
/* Let SDA go high */
|
||||
|
||||
stm32_gpiowrite(sda_gpio, 1);
|
||||
|
||||
/* Clock the bus until any slaves currently driving it let it go. */
|
||||
|
||||
clock_count = 0;
|
||||
while (!stm32_gpioread(sda_gpio))
|
||||
{
|
||||
/* Give up if we have tried too hard */
|
||||
|
||||
if (clock_count++ > 10)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Sniff to make sure that clock stretching has finished.
|
||||
*
|
||||
* If the bus never relaxes, the reset has failed.
|
||||
*/
|
||||
|
||||
stretch_count = 0;
|
||||
while (!stm32_gpioread(scl_gpio))
|
||||
{
|
||||
/* Give up if we have tried too hard */
|
||||
|
||||
if (stretch_count++ > 10)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
up_udelay(10);
|
||||
}
|
||||
|
||||
/* Drive SCL low */
|
||||
|
||||
stm32_gpiowrite(scl_gpio, 0);
|
||||
up_udelay(10);
|
||||
|
||||
/* Drive SCL high again */
|
||||
|
||||
stm32_gpiowrite(scl_gpio, 1);
|
||||
up_udelay(10);
|
||||
}
|
||||
|
||||
/* Generate a start followed by a stop to reset slave
|
||||
* state machines.
|
||||
*/
|
||||
|
||||
stm32_gpiowrite(sda_gpio, 0);
|
||||
up_udelay(10);
|
||||
stm32_gpiowrite(scl_gpio, 0);
|
||||
up_udelay(10);
|
||||
stm32_gpiowrite(scl_gpio, 1);
|
||||
up_udelay(10);
|
||||
stm32_gpiowrite(sda_gpio, 1);
|
||||
up_udelay(10);
|
||||
|
||||
/* Revert the GPIO configuration. */
|
||||
|
||||
stm32_unconfiggpio(sda_gpio);
|
||||
stm32_unconfiggpio(scl_gpio);
|
||||
|
||||
/* Re-init the port */
|
||||
|
||||
stm32_i2c_init(priv);
|
||||
ret = OK;
|
||||
|
||||
out:
|
||||
|
||||
/* Release the port for re-use by other clients */
|
||||
|
||||
stm32_i2c_sem_post(dev);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_I2C_RESET */
|
||||
|
||||
/************************************************************************************
|
||||
* Public Functions
|
||||
************************************************************************************/
|
||||
@@ -2608,122 +2726,4 @@ int stm32_i2cbus_uninitialize(FAR struct i2c_master_s * dev)
|
||||
return OK;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
* Name: stm32_i2c_reset
|
||||
*
|
||||
* Description:
|
||||
* Reset an I2C bus
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
int stm32_i2c_reset(FAR struct i2c_master_s * dev)
|
||||
{
|
||||
struct stm32_i2c_priv_s * priv;
|
||||
unsigned int clock_count;
|
||||
unsigned int stretch_count;
|
||||
uint32_t scl_gpio;
|
||||
uint32_t sda_gpio;
|
||||
int ret = ERROR;
|
||||
|
||||
ASSERT(dev);
|
||||
|
||||
/* Get I2C private structure */
|
||||
|
||||
priv = ((struct stm32_i2c_inst_s *)dev)->priv;
|
||||
|
||||
/* Our caller must own a ref */
|
||||
|
||||
ASSERT(priv->refs > 0);
|
||||
|
||||
/* Lock out other clients */
|
||||
|
||||
stm32_i2c_sem_wait(dev);
|
||||
|
||||
/* De-init the port */
|
||||
|
||||
stm32_i2c_deinit(priv);
|
||||
|
||||
/* Use GPIO configuration to un-wedge the bus */
|
||||
|
||||
scl_gpio = MKI2C_OUTPUT(priv->config->scl_pin);
|
||||
sda_gpio = MKI2C_OUTPUT(priv->config->sda_pin);
|
||||
|
||||
/* Let SDA go high */
|
||||
|
||||
stm32_gpiowrite(sda_gpio, 1);
|
||||
|
||||
/* Clock the bus until any slaves currently driving it let it go. */
|
||||
|
||||
clock_count = 0;
|
||||
while (!stm32_gpioread(sda_gpio))
|
||||
{
|
||||
/* Give up if we have tried too hard */
|
||||
|
||||
if (clock_count++ > 10)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Sniff to make sure that clock stretching has finished.
|
||||
*
|
||||
* If the bus never relaxes, the reset has failed.
|
||||
*/
|
||||
|
||||
stretch_count = 0;
|
||||
while (!stm32_gpioread(scl_gpio))
|
||||
{
|
||||
/* Give up if we have tried too hard */
|
||||
|
||||
if (stretch_count++ > 10)
|
||||
{
|
||||
goto out;
|
||||
}
|
||||
|
||||
up_udelay(10);
|
||||
}
|
||||
|
||||
/* Drive SCL low */
|
||||
|
||||
stm32_gpiowrite(scl_gpio, 0);
|
||||
up_udelay(10);
|
||||
|
||||
/* Drive SCL high again */
|
||||
|
||||
stm32_gpiowrite(scl_gpio, 1);
|
||||
up_udelay(10);
|
||||
}
|
||||
|
||||
/* Generate a start followed by a stop to reset slave
|
||||
* state machines.
|
||||
*/
|
||||
|
||||
stm32_gpiowrite(sda_gpio, 0);
|
||||
up_udelay(10);
|
||||
stm32_gpiowrite(scl_gpio, 0);
|
||||
up_udelay(10);
|
||||
stm32_gpiowrite(scl_gpio, 1);
|
||||
up_udelay(10);
|
||||
stm32_gpiowrite(sda_gpio, 1);
|
||||
up_udelay(10);
|
||||
|
||||
/* Revert the GPIO configuration. */
|
||||
|
||||
stm32_unconfiggpio(sda_gpio);
|
||||
stm32_unconfiggpio(scl_gpio);
|
||||
|
||||
/* Re-init the port */
|
||||
|
||||
stm32_i2c_init(priv);
|
||||
ret = OK;
|
||||
|
||||
out:
|
||||
|
||||
/* Release the port for re-use by other clients */
|
||||
|
||||
stm32_i2c_sem_post(dev);
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_I2C_RESET */
|
||||
|
||||
#endif /* CONFIG_STM32F7_I2C1 || CONFIG_STM32F7_I2C2 || CONFIG_STM32F7_I2C3 */
|
||||
|
||||
@@ -1096,10 +1096,10 @@ static inline void up_serialout(struct up_dev_s *priv, int offset, uint32_t valu
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_restoreusartint
|
||||
* Name: up_setusartint
|
||||
****************************************************************************/
|
||||
|
||||
static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie)
|
||||
static inline void up_setusartint(struct up_dev_s *priv, uint16_t ie)
|
||||
{
|
||||
uint32_t cr;
|
||||
|
||||
@@ -1120,12 +1120,31 @@ static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie)
|
||||
up_serialout(priv, STM32_USART_CR3_OFFSET, cr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_restoreusartint
|
||||
****************************************************************************/
|
||||
|
||||
static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
up_setusartint(priv, ie);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_disableusartint
|
||||
****************************************************************************/
|
||||
|
||||
static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie)
|
||||
static void up_disableusartint(struct up_dev_s *priv, uint16_t *ie)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
if (ie)
|
||||
{
|
||||
uint32_t cr1;
|
||||
@@ -1162,7 +1181,9 @@ static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie)
|
||||
|
||||
/* Disable all interrupts */
|
||||
|
||||
up_restoreusartint(priv, 0);
|
||||
up_setusartint(priv, 0);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
@@ -2868,6 +2889,7 @@ int up_putc(int ch)
|
||||
|
||||
up_lowputc(ch);
|
||||
up_restoreusartint(priv, ie);
|
||||
|
||||
#endif
|
||||
return ch;
|
||||
}
|
||||
|
||||
@@ -1008,14 +1008,6 @@ config STM32L4_SPI3
|
||||
select SPI
|
||||
select STM32L4_SPI
|
||||
|
||||
config STM32L4_USART1
|
||||
bool "USART1"
|
||||
default n
|
||||
depends on STM32L4_HAVE_USART1
|
||||
select ARCH_HAVE_SERIAL_TERMIOS
|
||||
select USART1_SERIALDRIVER
|
||||
select STM32L4_USART
|
||||
|
||||
config STM32L4_USART2
|
||||
bool "USART2"
|
||||
default n
|
||||
@@ -1155,8 +1147,9 @@ config STM32L4_TIM8
|
||||
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_TIM15
|
||||
@@ -1306,9 +1299,6 @@ config STM32L4_SAI2PLL
|
||||
Set this true and provide configuration parameters in
|
||||
board.h to use this PLL.
|
||||
|
||||
config STM32L4_USART
|
||||
bool
|
||||
|
||||
menu "Timer Configuration"
|
||||
|
||||
if SCHED_TICKLESS
|
||||
|
||||
@@ -307,7 +307,7 @@ static int stm32l4_i2c_reset(FAR struct i2c_master_s *dev);
|
||||
|
||||
/* Device Structures, Instantiation */
|
||||
|
||||
const struct i2c_ops_s stm32l4_i2c_ops =
|
||||
static const struct i2c_ops_s stm32l4_i2c_ops =
|
||||
{
|
||||
.transfer = stm32l4_i2c_transfer
|
||||
#ifdef CONFIG_I2C_RESET
|
||||
@@ -329,7 +329,7 @@ static const struct stm32l4_i2c_config_s stm32l4_i2c1_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32l4_i2c_priv_s stm32l4_i2c1_priv =
|
||||
static struct stm32l4_i2c_priv_s stm32l4_i2c1_priv =
|
||||
{
|
||||
.ops = &stm32l4_i2c_ops,
|
||||
.config = &stm32l4_i2c1_config,
|
||||
@@ -358,7 +358,7 @@ static const struct stm32l4_i2c_config_s stm32l4_i2c2_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32l4_i2c_priv_s stm32l4_i2c2_priv =
|
||||
static struct stm32l4_i2c_priv_s stm32l4_i2c2_priv =
|
||||
{
|
||||
.ops = &stm32l4_i2c_ops,
|
||||
.config = &stm32l4_i2c2_config,
|
||||
@@ -387,7 +387,7 @@ static const struct stm32l4_i2c_config_s stm32l4_i2c3_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32l4_i2c_priv_s stm32l4_i2c3_priv =
|
||||
static struct stm32l4_i2c_priv_s stm32l4_i2c3_priv =
|
||||
{
|
||||
.ops = &stm32l4_i2c_ops,
|
||||
.config = &stm32l4_i2c3_config,
|
||||
@@ -416,7 +416,7 @@ static const struct stm32l4_i2c_config_s stm32l4_i2c4_config =
|
||||
#endif
|
||||
};
|
||||
|
||||
struct stm32l4_i2c_priv_s stm32l4_i2c4_priv =
|
||||
static struct stm32l4_i2c_priv_s stm32l4_i2c4_priv =
|
||||
{
|
||||
.ops = &stm32l4_i2c_ops,
|
||||
.config = &stm32l4_i2c4_config,
|
||||
@@ -1831,7 +1831,7 @@ static int stm32l4_i2c_transfer(FAR struct i2c_master_s *dev, FAR struct i2c_msg
|
||||
* dev - Device-specific state data
|
||||
*
|
||||
* Returned Value:
|
||||
* Zero (OK) on success; a negated errno value on failure.
|
||||
* Zero (OK) on success; negative value on failure.
|
||||
*
|
||||
************************************************************************************/
|
||||
|
||||
|
||||
@@ -765,11 +765,11 @@ static inline void stm32l4serial_putreg(FAR struct stm32l4_serial_s *priv,
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32l4serial_restoreusartint
|
||||
* Name: stm32l4serial_setusartint
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32l4serial_restoreusartint(FAR struct stm32l4_serial_s *priv,
|
||||
uint16_t ie)
|
||||
static inline void stm32l4serial_setusartint(FAR struct stm32l4_serial_s *priv,
|
||||
uint16_t ie)
|
||||
{
|
||||
uint32_t cr;
|
||||
|
||||
@@ -790,13 +790,33 @@ static void stm32l4serial_restoreusartint(FAR struct stm32l4_serial_s *priv,
|
||||
stm32l4serial_putreg(priv, STM32L4_USART_CR3_OFFSET, cr);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: up_restoreusartint
|
||||
****************************************************************************/
|
||||
|
||||
static void stm32l4serial_restoreusartint(FAR struct stm32l4_serial_s *priv,
|
||||
uint16_t ie)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
stm32l4serial_setusartint(priv, ie);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: stm32l4serial_disableusartint
|
||||
****************************************************************************/
|
||||
|
||||
static inline void stm32l4serial_disableusartint(FAR struct stm32l4_serial_s *priv,
|
||||
FAR uint16_t *ie)
|
||||
static void stm32l4serial_disableusartint(FAR struct stm32l4_serial_s *priv,
|
||||
FAR uint16_t *ie)
|
||||
{
|
||||
irqstate_t flags;
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
if (ie)
|
||||
{
|
||||
uint32_t cr1;
|
||||
@@ -833,7 +853,9 @@ static inline void stm32l4serial_disableusartint(FAR struct stm32l4_serial_s *pr
|
||||
|
||||
/* Disable all interrupts */
|
||||
|
||||
stm32l4serial_restoreusartint(priv, 0);
|
||||
stm32l4serial_setusartint(priv, 0);
|
||||
|
||||
leave_critical_section(flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
||||
@@ -163,14 +163,14 @@ int elf_loaddtors(FAR struct elf_loadinfo_s *loadinfo)
|
||||
{
|
||||
/* Allocate memory to hold a copy of the .dtor section */
|
||||
|
||||
loadinfo->ctoralloc = (binfmt_dtor_t *)kumm_malloc(dtorsize);
|
||||
if (!loadinfo->ctoralloc)
|
||||
loadinfo->dtoralloc = (binfmt_dtor_t *)kumm_malloc(dtorsize);
|
||||
if (!loadinfo->dtoralloc)
|
||||
{
|
||||
berr("Failed to allocate memory for .dtors\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
loadinfo->dtors = (binfmt_dtor_t *)loadinfo->ctoralloc;
|
||||
loadinfo->dtors = (binfmt_dtor_t *)loadinfo->dtoralloc;
|
||||
|
||||
/* Read the section header table into memory */
|
||||
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/sched.h>
|
||||
#include <nuttx/syslog/syslog.h>
|
||||
|
||||
#include "syslog.h"
|
||||
@@ -100,8 +103,21 @@ ssize_t syslog_default_write(FAR const char *buffer, size_t buflen)
|
||||
ssize_t syslog_write(FAR const char *buffer, size_t buflen)
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_WRITE
|
||||
return g_syslog_channel->sc_write(buffer, buflen);
|
||||
#else
|
||||
return syslog_default_write(buffer, buflen);
|
||||
if (!up_interrupt_context() && !sched_idletask())
|
||||
{
|
||||
#ifdef CONFIG_SYSLOG_INTBUFFER
|
||||
/* Flush any characters that may have been added to the interrupt
|
||||
* buffer.
|
||||
*/
|
||||
|
||||
(void)syslog_flush_intbuffer(g_syslog_channel, false);
|
||||
#endif
|
||||
|
||||
return g_syslog_channel->sc_write(buffer, buflen);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return syslog_default_write(buffer, buflen);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-1
@@ -63,12 +63,15 @@ config IOB_THROTTLE
|
||||
config IOB_DEBUG
|
||||
bool "Force I/O buffer debug"
|
||||
default n
|
||||
depends on DEBUG_FEATURES
|
||||
depends on DEBUG_FEATURES && !SYSLOG_BUFFER
|
||||
---help---
|
||||
This option will force debug output from I/O buffer logic. This
|
||||
is not normally something that would want to do but is convenient
|
||||
if you are debugging the I/O buffer logic and do not want to get
|
||||
overloaded with other un-related debug output.
|
||||
|
||||
NOTE that this selection is not avaiable with IOBs are being used
|
||||
to syslog buffering logic (CONFIG_SYSLOG_BUFFER=y)!
|
||||
|
||||
endif # MM_IOB
|
||||
endmenu # Common I/O buffer support
|
||||
|
||||
+9
-1
@@ -91,10 +91,18 @@
|
||||
|
||||
extern FAR struct iob_s *g_iob_freelist;
|
||||
|
||||
/* A list of all free, unallocated I/O buffer queue containers */
|
||||
/* A list of I/O buffers that are committed for allocation */
|
||||
|
||||
extern FAR struct iob_s *g_iob_committed;
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
/* A list of all free, unallocated I/O buffer queue containers */
|
||||
|
||||
extern FAR struct iob_qentry_s *g_iob_freeqlist;
|
||||
|
||||
/* A list of I/O buffer queue containers that are committed for allocation */
|
||||
|
||||
extern FAR struct iob_s *g_iob_qcommitted;
|
||||
#endif
|
||||
|
||||
/* Counting semaphores that tracks the number of free IOBs/qentries */
|
||||
|
||||
+91
-47
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* mm/iob/iob_alloc.c
|
||||
*
|
||||
* Copyright (C) 2014, 2016 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2014, 2016-2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -54,6 +54,47 @@
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_alloc_committed
|
||||
*
|
||||
* Description:
|
||||
* Allocate an I/O buffer by taking the buffer at the head of the committed
|
||||
* list.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct iob_s *iob_alloc_committed(void)
|
||||
{
|
||||
FAR struct iob_s *iob = NULL;
|
||||
irqstate_t flags;
|
||||
|
||||
/* We don't know what context we are called from so we use extreme measures
|
||||
* to protect the committed list: We disable interrupts very briefly.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Take the I/O buffer from the head of the committed list */
|
||||
|
||||
iob = g_iob_committed;
|
||||
if (iob != NULL)
|
||||
{
|
||||
/* Remove the I/O buffer from the committed list */
|
||||
|
||||
g_iob_committed = iob->io_flink;
|
||||
|
||||
/* Put the I/O buffer in a known state */
|
||||
|
||||
iob->io_flink = NULL; /* Not in a chain */
|
||||
iob->io_len = 0; /* Length of the data in the entry */
|
||||
iob->io_offset = 0; /* Offset to the beginning of data */
|
||||
iob->io_pktlen = 0; /* Total length of the packet */
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
return iob;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_allocwait
|
||||
*
|
||||
@@ -85,73 +126,76 @@ static FAR struct iob_s *iob_allocwait(bool throttled)
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
do
|
||||
|
||||
/* Try to get an I/O buffer. If successful, the semaphore count will be
|
||||
* decremented atomically.
|
||||
*/
|
||||
|
||||
iob = iob_tryalloc(throttled);
|
||||
while (ret == OK && iob == NULL)
|
||||
{
|
||||
/* Try to get an I/O buffer. If successful, the semaphore count
|
||||
* will be decremented atomically.
|
||||
/* If not successful, then the semaphore count was less than or equal
|
||||
* to zero (meaning that there are no free buffers). We need to wait
|
||||
* for an I/O buffer to be released and placed in the committed
|
||||
* list.
|
||||
*/
|
||||
|
||||
iob = iob_tryalloc(throttled);
|
||||
if (!iob)
|
||||
ret = sem_wait(sem);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* If not successful, then the semaphore count was less than or
|
||||
* equal to zero (meaning that there are no free buffers). We
|
||||
* need to wait for an I/O buffer to be released when the semaphore
|
||||
* count will be incremented.
|
||||
int errcode = get_errno();
|
||||
|
||||
/* EINTR is not an error! EINTR simply means that we were
|
||||
* awakened by a signal and we should try again.
|
||||
*
|
||||
* REVISIT: Many end-user interfaces are required to return with
|
||||
* an error if EINTR is set. Most uses of this function are in
|
||||
* internal, non-user logic. But are there cases where the error
|
||||
* should be returned.
|
||||
*/
|
||||
|
||||
ret = sem_wait(sem);
|
||||
if (ret < 0)
|
||||
if (errcode == EINTR)
|
||||
{
|
||||
int errcode = get_errno();
|
||||
/* Force a success indication so that we will continue looping. */
|
||||
|
||||
/* EINTR is not an error! EINTR simply means that we were
|
||||
* awakened by a signal and we should try again.
|
||||
*
|
||||
* REVISIT: Many end-user interfaces are required to return
|
||||
* with an error if EINTR is set. Most uses of this function
|
||||
* is in internal, non-user logic. But are there cases where
|
||||
* the error should be returned.
|
||||
*/
|
||||
|
||||
if (errcode == EINTR)
|
||||
{
|
||||
/* Force a success indication so that we will continue
|
||||
* looping.
|
||||
*/
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Stop the loop and return a error */
|
||||
|
||||
DEBUGASSERT(errcode > 0);
|
||||
ret = -errcode;
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* When we wake up from wait successfully, an I/O buffer was
|
||||
* returned to the free list. However, if there are concurrent
|
||||
* allocations from interrupt handling, then I suspect that
|
||||
* there is a race condition. But no harm, we will just wait
|
||||
* again in that case.
|
||||
/* Stop the loop and return a error */
|
||||
|
||||
DEBUGASSERT(errcode > 0);
|
||||
ret = -errcode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* When we wake up from wait successfully, an I/O buffer was
|
||||
* freed and we hold a count for one IOB. Unless somehting
|
||||
* failed, we should have an IOB waiting for us in the
|
||||
* committed list.
|
||||
*/
|
||||
|
||||
iob = iob_alloc_committed();
|
||||
DEBUGASSERT(iob != NULL);
|
||||
|
||||
if (iob == NULL)
|
||||
{
|
||||
/* This should not fail, but we allow for that possibility to
|
||||
* handle any potential, non-obvious race condition. Perhaps
|
||||
* the free IOB ended up in the g_iob_free list?
|
||||
*
|
||||
* We need release our count so that it is available to
|
||||
* iob_tryalloc(), perhaps allowing another thread to take our
|
||||
* count. In that event, iob_tryalloc() will fail above and
|
||||
* we will have to wait again.
|
||||
*
|
||||
* TODO: Consider a design modification to permit us to
|
||||
* complete the allocation without losing our count.
|
||||
*/
|
||||
|
||||
sem_post(sem);
|
||||
iob = iob_tryalloc(throttled);
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ret == OK && iob == NULL);
|
||||
|
||||
leave_critical_section(flags);
|
||||
return iob;
|
||||
@@ -225,7 +269,7 @@ FAR struct iob_s *iob_tryalloc(bool throttled)
|
||||
/* Take the I/O buffer from the head of the free list */
|
||||
|
||||
iob = g_iob_freelist;
|
||||
if (iob)
|
||||
if (iob != NULL)
|
||||
{
|
||||
/* Remove the I/O buffer from the free list and decrement the
|
||||
* counting semaphore(s) that tracks the number of available
|
||||
|
||||
+90
-47
@@ -55,6 +55,44 @@
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_alloc_qcommitted
|
||||
*
|
||||
* Description:
|
||||
* Allocate an I/O buffer by taking the buffer at the head of the committed
|
||||
* list.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static FAR struct iob_qentry_s *iob_alloc_qcommitted(void)
|
||||
{
|
||||
FAR struct iob_qentry_s *iobq = NULL;
|
||||
irqstate_t flags;
|
||||
|
||||
/* We don't know what context we are called from so we use extreme measures
|
||||
* to protect the committed list: We disable interrupts very briefly.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
|
||||
/* Take the I/O buffer from the head of the committed list */
|
||||
|
||||
iobq = g_iob_qcommitted;
|
||||
if (iobq != NULL)
|
||||
{
|
||||
/* Remove the I/O buffer from the committed list */
|
||||
|
||||
g_iob_qcommitted = iobq->qe_flink;
|
||||
|
||||
/* Put the I/O buffer in a known state */
|
||||
|
||||
iobq->qe_head = NULL; /* Nothing is contained */
|
||||
}
|
||||
|
||||
leave_critical_section(flags);
|
||||
return iobq;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: iob_allocwait_qentry
|
||||
*
|
||||
@@ -78,73 +116,78 @@ static FAR struct iob_qentry_s *iob_allocwait_qentry(void)
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
do
|
||||
|
||||
/* Try to get an I/O buffer chain container. If successful, the semaphore
|
||||
* count will bedecremented atomically.
|
||||
*/
|
||||
|
||||
qentry = iob_tryalloc_qentry();
|
||||
while (ret == OK && qentry == NULL)
|
||||
{
|
||||
/* Try to get an I/O buffer chain container. If successful, the
|
||||
* semaphore count will be decremented atomically.
|
||||
/* If not successful, then the semaphore count was less than or equal
|
||||
* to zero (meaning that there are no free buffers). We need to wait
|
||||
* for an I/O buffer chain container to be released when the
|
||||
* semaphore count will be incremented.
|
||||
*/
|
||||
|
||||
qentry = iob_tryalloc_qentry();
|
||||
if (!qentry)
|
||||
ret = sem_wait(&g_qentry_sem);
|
||||
if (ret < 0)
|
||||
{
|
||||
/* If not successful, then the semaphore count was less than or
|
||||
* equal to zero (meaning that there are no free buffers). We
|
||||
* need to wait for an I/O buffer chain container to be released
|
||||
* when the semaphore count will be incremented.
|
||||
int errcode = get_errno();
|
||||
|
||||
/* EINTR is not an error! EINTR simply means that we were
|
||||
* awakened by a signal and we should try again.
|
||||
*
|
||||
* REVISIT: Many end-user interfaces are required to return
|
||||
* with an error if EINTR is set. Most uses of this function
|
||||
* is in internal, non-user logic. But are there cases where
|
||||
* the error should be returned.
|
||||
*/
|
||||
|
||||
ret = sem_wait(&g_qentry_sem);
|
||||
if (ret < 0)
|
||||
if (errcode == EINTR)
|
||||
{
|
||||
int errcode = get_errno();
|
||||
|
||||
/* EINTR is not an error! EINTR simply means that we were
|
||||
* awakened by a signal and we should try again.
|
||||
*
|
||||
* REVISIT: Many end-user interfaces are required to return
|
||||
* with an error if EINTR is set. Most uses of this function
|
||||
* is in internal, non-user logic. But are there cases where
|
||||
* the error should be returned.
|
||||
/* Force a success indication so that we will continue
|
||||
* looping.
|
||||
*/
|
||||
|
||||
if (errcode == EINTR)
|
||||
{
|
||||
/* Force a success indication so that we will continue
|
||||
* looping.
|
||||
*/
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Stop the loop and return a error */
|
||||
|
||||
DEBUGASSERT(errcode > 0);
|
||||
ret = -errcode;
|
||||
}
|
||||
ret = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* When we wake up from wait successfully, an I/O buffer chain
|
||||
* container was returned to the free list. However, if there
|
||||
* are concurrent allocations from interrupt handling, then I
|
||||
* suspect that there is a race condition. But no harm, we
|
||||
* will just wait again in that case.
|
||||
/* Stop the loop and return a error */
|
||||
|
||||
DEBUGASSERT(errcode > 0);
|
||||
ret = -errcode;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* When we wake up from wait successfully, an I/O buffer chain container was
|
||||
* freed and we hold a count for one IOB. Unless somehting
|
||||
* failed, we should have an IOB waiting for us in the
|
||||
* committed list.
|
||||
*/
|
||||
|
||||
qentry = iob_alloc_qcommitted();
|
||||
DEBUGASSERT(qentry != NULL);
|
||||
|
||||
if (qentry == NULL)
|
||||
{
|
||||
/* This should not fail, but we allow for that possibility to
|
||||
* handle any potential, non-obvious race condition. Perhaps
|
||||
* the free IOB ended up in the g_iob_free list?
|
||||
*
|
||||
* We need release our count so that it is available to
|
||||
* iob_tryalloc_qentry(), perhaps allowing another thread to
|
||||
* take our count. In that event, iob_tryalloc_qentry() will
|
||||
* fail above and we will have to wait again.
|
||||
*
|
||||
* TODO: Consider a design modification to permit us to
|
||||
* complete the allocation without losing our count.
|
||||
* iob_tryalloc(), perhaps allowing another thread to take our
|
||||
* count. In that event, iob_tryalloc() will fail above and
|
||||
* we will have to wait again.
|
||||
*/
|
||||
|
||||
sem_post(&g_qentry_sem);
|
||||
qentry = iob_tryalloc_qentry();
|
||||
}
|
||||
}
|
||||
}
|
||||
while (ret == OK && !qentry);
|
||||
|
||||
leave_critical_section(flags);
|
||||
return qentry;
|
||||
|
||||
+27
-7
@@ -74,7 +74,7 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
|
||||
* the next entry.
|
||||
*/
|
||||
|
||||
if (next)
|
||||
if (next != NULL)
|
||||
{
|
||||
/* Copy and decrement the total packet length, being careful to
|
||||
* do nothing too crazy.
|
||||
@@ -101,16 +101,36 @@ FAR struct iob_s *iob_free(FAR struct iob_s *iob)
|
||||
next, next->io_pktlen, next->io_len);
|
||||
}
|
||||
|
||||
/* Free the I/O buffer by adding it to the head of the free list. We don't
|
||||
* know what context we are called from so we use extreme measures to
|
||||
* protect the free list: We disable interrupts very briefly.
|
||||
/* Free the I/O buffer by adding it to the head of the free or the
|
||||
* committed list. We don't know what context we are called from so
|
||||
* we use extreme measures to protect the free list: We disable
|
||||
* interrupts very briefly.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
iob->io_flink = g_iob_freelist;
|
||||
g_iob_freelist = iob;
|
||||
|
||||
/* Signal that an IOB is available */
|
||||
/* Which list? If there is a task waiting for an IOB, then put
|
||||
* the IOB on either the free list or on the committed list where
|
||||
* it is reserved for that allocation (and not available to
|
||||
* iob_tryalloc()).
|
||||
*/
|
||||
|
||||
if (g_iob_sem.semcount < 0)
|
||||
{
|
||||
iob->io_flink = g_iob_committed;
|
||||
g_iob_committed = iob;
|
||||
}
|
||||
else
|
||||
{
|
||||
iob->io_flink = g_iob_freelist;
|
||||
g_iob_freelist = iob;
|
||||
}
|
||||
|
||||
/* Signal that an IOB is available. If there is a thread waiting
|
||||
* for an IOB, this will wake up exactly one thread. The semaphore
|
||||
* count will correctly indicated that the awakened task owns an
|
||||
* IOB and should find it in the committed list.
|
||||
*/
|
||||
|
||||
sem_post(&g_iob_sem);
|
||||
#if CONFIG_IOB_THROTTLE > 0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* mm/iob/iob_free_qentry.c
|
||||
*
|
||||
* Copyright (C) 2014, 2016 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2014, 2016-2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -68,16 +68,37 @@ FAR struct iob_qentry_s *iob_free_qentry(FAR struct iob_qentry_s *iobq)
|
||||
FAR struct iob_qentry_s *nextq = iobq->qe_flink;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Free the I/O buffer chain container by adding it to the head of the free
|
||||
* list. We don't know what context we are called from so we use extreme
|
||||
* measures to protect the free list: We disable interrupts very briefly.
|
||||
/* Free the I/O buffer chain container by adding it to the head of the
|
||||
* free or the committed list. We don't know what context we are called
|
||||
* from so we use extreme measures to protect the free list: We disable
|
||||
* interrupts very briefly.
|
||||
*/
|
||||
|
||||
flags = enter_critical_section();
|
||||
iobq->qe_flink = g_iob_freeqlist;
|
||||
g_iob_freeqlist = iobq;
|
||||
|
||||
/* Signal that an I/O buffer chain container is available */
|
||||
/* Which list? If there is a task waiting for an IOB, then put
|
||||
* the IOB on either the free list or on the committed list where
|
||||
* it is reserved for that allocation (and not available to
|
||||
* iob_tryalloc()).
|
||||
*/
|
||||
|
||||
if (g_iob_sem.semcount < 0)
|
||||
{
|
||||
iobq->qe_flink = g_iob_qcommitted;
|
||||
g_iob_qcommitted = iobq;
|
||||
}
|
||||
else
|
||||
{
|
||||
iobq->qe_flink = g_iob_freeqlist;
|
||||
g_iob_freeqlist = iobq;
|
||||
}
|
||||
|
||||
/* Signal that an I/O buffer chain container is available. If there
|
||||
* is a thread waiting for an I/O buffer chain container, this will
|
||||
* wake up exactly one thread. The semaphore count will correctly
|
||||
* indicated that the awakened task owns an I/O buffer chain container
|
||||
* and should find it in the committed list.
|
||||
*/
|
||||
|
||||
sem_post(&g_qentry_sem);
|
||||
leave_critical_section(flags);
|
||||
|
||||
+22
-3
@@ -1,7 +1,7 @@
|
||||
/****************************************************************************
|
||||
* mm/iob/iob_initialize.c
|
||||
*
|
||||
* Copyright (C) 2014 Gregory Nutt. All rights reserved.
|
||||
* Copyright (C) 2014, 2017 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
@@ -46,6 +46,14 @@
|
||||
|
||||
#include "iob.h"
|
||||
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef NULL
|
||||
# define NULL ((FAR void *)0)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Private Data
|
||||
****************************************************************************/
|
||||
@@ -65,10 +73,18 @@ static struct iob_qentry_s g_iob_qpool[CONFIG_IOB_NCHAINS];
|
||||
|
||||
FAR struct iob_s *g_iob_freelist;
|
||||
|
||||
/* A list of all free, unallocated I/O buffer queue containers */
|
||||
/* A list of I/O buffers that are committed for allocation */
|
||||
|
||||
FAR struct iob_s *g_iob_committed;
|
||||
|
||||
#if CONFIG_IOB_NCHAINS > 0
|
||||
/* A list of all free, unallocated I/O buffer queue containers */
|
||||
|
||||
FAR struct iob_qentry_s *g_iob_freeqlist;
|
||||
|
||||
/* A list of I/O buffer queue containers that are committed for allocation */
|
||||
|
||||
FAR struct iob_s *g_iob_qcommitted;
|
||||
#endif
|
||||
|
||||
/* Counting semaphores that tracks the number of free IOBs/qentries */
|
||||
@@ -114,8 +130,9 @@ void iob_initialize(void)
|
||||
g_iob_freelist = iob;
|
||||
}
|
||||
|
||||
sem_init(&g_iob_sem, 0, CONFIG_IOB_NBUFFERS);
|
||||
g_iob_committed = NULL;
|
||||
|
||||
sem_init(&g_iob_sem, 0, CONFIG_IOB_NBUFFERS);
|
||||
#if CONFIG_IOB_THROTTLE > 0
|
||||
sem_init(&g_throttle_sem, 0, CONFIG_IOB_NBUFFERS - CONFIG_IOB_THROTTLE);
|
||||
#endif
|
||||
@@ -133,6 +150,8 @@ void iob_initialize(void)
|
||||
g_iob_freeqlist = iobq;
|
||||
}
|
||||
|
||||
g_iob_qcommitted = NULL;
|
||||
|
||||
sem_init(&g_qentry_sem, 0, CONFIG_IOB_NCHAINS);
|
||||
#endif
|
||||
initialized = true;
|
||||
|
||||
@@ -61,9 +61,12 @@
|
||||
****************************************************************************/
|
||||
|
||||
static int netprocfs_linklayer(FAR struct netprocfs_file_s *netfile);
|
||||
static int netprocfs_ipaddresses(FAR struct netprocfs_file_s *netfile);
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
static int netprocfs_inet4addresses(FAR struct netprocfs_file_s *netfile);
|
||||
#endif
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
static int netprocfs_dripaddress(FAR struct netprocfs_file_s *netfile);
|
||||
static int netprocfs_inet6address(FAR struct netprocfs_file_s *netfile);
|
||||
static int netprocfs_inet6draddress(FAR struct netprocfs_file_s *netfile);
|
||||
#endif
|
||||
#ifdef CONFIG_NETDEV_STATISTICS
|
||||
static int netprocfs_rxstatistics_header(FAR struct netprocfs_file_s *netfile);
|
||||
@@ -83,10 +86,13 @@ static int netprocfs_errors(FAR struct netprocfs_file_s *netfile);
|
||||
|
||||
static const linegen_t g_linegen[] =
|
||||
{
|
||||
netprocfs_linklayer,
|
||||
netprocfs_ipaddresses
|
||||
netprocfs_linklayer
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
, netprocfs_inet4addresses
|
||||
#endif
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
, netprocfs_dripaddress
|
||||
, netprocfs_inet6address
|
||||
, netprocfs_inet6draddress
|
||||
#endif
|
||||
#ifdef CONFIG_NETDEV_STATISTICS
|
||||
, netprocfs_rxstatistics_header,
|
||||
@@ -255,25 +261,19 @@ static int netprocfs_linklayer(FAR struct netprocfs_file_s *netfile)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: netprocfs_ipaddresses
|
||||
* Name: netprocfs_inet4addresses
|
||||
****************************************************************************/
|
||||
|
||||
static int netprocfs_ipaddresses(FAR struct netprocfs_file_s *netfile)
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
static int netprocfs_inet4addresses(FAR struct netprocfs_file_s *netfile)
|
||||
{
|
||||
FAR struct net_driver_s *dev;
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
struct in_addr addr;
|
||||
#endif
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
uint8_t preflen;
|
||||
#endif
|
||||
int len = 0;
|
||||
|
||||
DEBUGASSERT(netfile != NULL && netfile->dev != NULL);
|
||||
dev = netfile->dev;
|
||||
|
||||
#ifdef CONFIG_NET_IPv4
|
||||
/* Show the IPv4 address */
|
||||
|
||||
addr.s_addr = dev->d_ipaddr;
|
||||
@@ -291,9 +291,25 @@ static int netprocfs_ipaddresses(FAR struct netprocfs_file_s *netfile)
|
||||
addr.s_addr = dev->d_netmask;
|
||||
len += snprintf(&netfile->line[len], NET_LINELEN - len,
|
||||
"Mask:%s\n\n", inet_ntoa(addr));
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: netprocfs_inet6address
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
static int netprocfs_inet6address(FAR struct netprocfs_file_s *netfile)
|
||||
{
|
||||
FAR struct net_driver_s *dev;
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
uint8_t preflen;
|
||||
int len = 0;
|
||||
|
||||
DEBUGASSERT(netfile != NULL && netfile->dev != NULL);
|
||||
dev = netfile->dev;
|
||||
|
||||
/* Convert the 128 network mask to a human friendly prefix length */
|
||||
|
||||
preflen = net_ipv6_mask2pref(dev->d_ipv6netmask);
|
||||
@@ -305,17 +321,17 @@ static int netprocfs_ipaddresses(FAR struct netprocfs_file_s *netfile)
|
||||
len += snprintf(&netfile->line[len], NET_LINELEN - len,
|
||||
"\tinet6 addr:%s/%d\n", addrstr, preflen);
|
||||
}
|
||||
#endif
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: netprocfs_dripaddress
|
||||
* Name: netprocfs_inet6draddress
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_NET_IPv6
|
||||
static int netprocfs_dripaddress(FAR struct netprocfs_file_s *netfile)
|
||||
static int netprocfs_inet6draddress(FAR struct netprocfs_file_s *netfile)
|
||||
{
|
||||
FAR struct net_driver_s *dev;
|
||||
char addrstr[INET6_ADDRSTRLEN];
|
||||
|
||||
+1
-1
@@ -54,7 +54,7 @@
|
||||
* to handle the longest line generated by this logic.
|
||||
*/
|
||||
|
||||
#define NET_LINELEN 64
|
||||
#define NET_LINELEN 80
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
|
||||
@@ -82,7 +82,7 @@ void net_ipv6_pref2mask(uint8_t preflen, net_ipv6addr_t mask)
|
||||
* 1..6 7..2 3..8 9..4 5..0 1..6 7..2 3..8
|
||||
*/
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
/* bit = {0, 16, 32, 48, 64, 80, 96, 112} */
|
||||
|
||||
@@ -92,7 +92,7 @@ void net_ipv6_pref2mask(uint8_t preflen, net_ipv6addr_t mask)
|
||||
{
|
||||
/* Eg. preflen = 38, bit = {0, 16, 32} */
|
||||
|
||||
if (preflen > (bit + 16))
|
||||
if (preflen >= (bit + 16))
|
||||
{
|
||||
/* Eg. preflen = 38, bit = {0, 16} */
|
||||
|
||||
@@ -102,7 +102,7 @@ void net_ipv6_pref2mask(uint8_t preflen, net_ipv6addr_t mask)
|
||||
{
|
||||
/* Eg. preflen = 38, bit = {32}
|
||||
* bit - preflen = 6
|
||||
* make = 0xffff << (16-6)
|
||||
* mask = 0xffff << (16-6)
|
||||
* = 0xfc00
|
||||
*/
|
||||
|
||||
@@ -111,7 +111,7 @@ void net_ipv6_pref2mask(uint8_t preflen, net_ipv6addr_t mask)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Eg. preflen=38, bit= {48, 64, 80, 112} */
|
||||
/* Eg. preflen=38, bit= {48, 64, 80, 96, 112} */
|
||||
|
||||
mask[i] = 0x0000;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user