mirror of https://github.com/ARMmbed/mbed-os.git
Reduce K64F Ethernet driver to 1 thread
Save 1K of RAM by using only 1 thread for RX and TX, and running the PHY check in lwIP's context.pull/4996/head
parent
4978a08ae2
commit
65639e80fc
|
@ -52,8 +52,7 @@ extern void k66f_init_eth_hardware(void);
|
||||||
/* K64F EMAC driver data structure */
|
/* K64F EMAC driver data structure */
|
||||||
struct k64f_enetdata {
|
struct k64f_enetdata {
|
||||||
struct netif *netif; /**< Reference back to LWIP parent netif */
|
struct netif *netif; /**< Reference back to LWIP parent netif */
|
||||||
sys_sem_t RxReadySem; /**< RX packet ready semaphore */
|
osThreadId_t thread; /**< Processing thread */
|
||||||
sys_sem_t TxCleanSem; /**< TX cleanup thread wakeup semaphore */
|
|
||||||
sys_mutex_t TXLockMutex; /**< TX critical section mutex */
|
sys_mutex_t TXLockMutex; /**< TX critical section mutex */
|
||||||
sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */
|
sys_sem_t xTXDCountSem; /**< TX free buffer counting semaphore */
|
||||||
uint8_t tx_consume_index, tx_produce_index; /**< TX buffers ring */
|
uint8_t tx_consume_index, tx_produce_index; /**< TX buffers ring */
|
||||||
|
@ -61,15 +60,24 @@ struct k64f_enetdata {
|
||||||
|
|
||||||
static struct k64f_enetdata k64f_enetdata;
|
static struct k64f_enetdata k64f_enetdata;
|
||||||
|
|
||||||
/** \brief Driver transmit and receive thread priorities
|
/* \brief Flags for worker thread */
|
||||||
*
|
#define FLAG_TX 1
|
||||||
* Thread priorities for receive thread and TX cleanup thread. Alter
|
#define FLAG_RX 2
|
||||||
* to prioritize receive or transmit bandwidth. In a heavily loaded
|
|
||||||
* system or with LEIP_DEBUG enabled, the priorities might be better
|
/** \brief Driver thread priority */
|
||||||
* the same. */
|
#define THREAD_PRIORITY (osPriorityNormal)
|
||||||
#define RX_PRIORITY (osPriorityNormal)
|
|
||||||
#define TX_PRIORITY (osPriorityNormal)
|
#ifdef LWIP_DEBUG
|
||||||
#define PHY_PRIORITY (osPriorityNormal)
|
#define THREAD_STACKSIZE (DEFAULT_THREAD_STACKSIZE * 5)
|
||||||
|
#else
|
||||||
|
#define THREAD_STACKSIZE DEFAULT_THREAD_STACKSIZE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void k64f_phy_task(void *data);
|
||||||
|
static void packet_rx(struct k64f_enetdata *k64f_enet);
|
||||||
|
static void packet_tx(struct k64f_enetdata *k64f_enet);
|
||||||
|
|
||||||
|
#define PHY_TASK_PERIOD_MS 200
|
||||||
|
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Buffer management
|
* Buffer management
|
||||||
|
@ -132,12 +140,12 @@ static void k64f_tx_reclaim(struct k64f_enetdata *k64f_enet)
|
||||||
*/
|
*/
|
||||||
void enet_mac_rx_isr()
|
void enet_mac_rx_isr()
|
||||||
{
|
{
|
||||||
sys_sem_signal(&k64f_enetdata.RxReadySem);
|
osThreadFlagsSet(k64f_enetdata.thread, FLAG_RX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void enet_mac_tx_isr()
|
void enet_mac_tx_isr()
|
||||||
{
|
{
|
||||||
sys_sem_signal(&k64f_enetdata.TxCleanSem);
|
osThreadFlagsSet(k64f_enetdata.thread, FLAG_TX);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param)
|
void ethernet_callback(ENET_Type *base, enet_handle_t *handle, enet_event_t event, void *param)
|
||||||
|
@ -461,26 +469,56 @@ void k64f_enetif_input(struct netif *netif, int idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \brief Worker thread.
|
||||||
|
*
|
||||||
|
* Woken by thread flags to receive packets or clean up transmit
|
||||||
|
*
|
||||||
|
* \param[in] pvParameters pointer to the interface data
|
||||||
|
*/
|
||||||
|
static void emac_thread(void* pvParameters)
|
||||||
|
{
|
||||||
|
struct k64f_enetdata *k64f_enet = pvParameters;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
uint32_t flags = osThreadFlagsWait(FLAG_RX|FLAG_TX, osFlagsWaitAny, PHY_TASK_PERIOD_MS);
|
||||||
|
if (flags == osFlagsErrorTimeout) {
|
||||||
|
// Rather than calling strictly every period, we call when idle
|
||||||
|
// for that period - hopefully good enough. We run this task
|
||||||
|
// from lwIP's thread rather than our RX/TX thread, as PHY reads can
|
||||||
|
// be slow, and we don't want them to interfere with data pumping.
|
||||||
|
// This is analogous to the way the PHY polling works in the Nanostack
|
||||||
|
// version of the driver
|
||||||
|
tcpip_callback_with_block(k64f_phy_task, k64f_enet->netif, 0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LWIP_ASSERT("osThreadFlagsWait error", !(flags & osFlagsError));
|
||||||
|
|
||||||
|
if (flags & FLAG_RX) {
|
||||||
|
packet_rx(k64f_enet);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & FLAG_TX) {
|
||||||
|
packet_tx(k64f_enet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** \brief Packet reception task
|
/** \brief Packet reception task
|
||||||
*
|
*
|
||||||
* This task is called when a packet is received. It will
|
* This task is called when a packet is received. It will
|
||||||
* pass the packet to the LWIP core.
|
* pass the packet to the LWIP core.
|
||||||
*
|
*
|
||||||
* \param[in] pvParameters pointer to the interface data
|
* \param[in] k64f_enet pointer to the interface data
|
||||||
*/
|
*/
|
||||||
static void packet_rx(void* pvParameters) {
|
static void packet_rx(struct k64f_enetdata *k64f_enet)
|
||||||
struct k64f_enetdata *k64f_enet = pvParameters;
|
{
|
||||||
int idx = 0;
|
static int idx = 0;
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* Wait for receive task to wakeup */
|
|
||||||
sys_arch_sem_wait(&k64f_enet->RxReadySem, 0);
|
|
||||||
|
|
||||||
while ((g_handle.rxBdCurrent->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK) == 0) {
|
while ((g_handle.rxBdCurrent->control & ENET_BUFFDESCRIPTOR_RX_EMPTY_MASK) == 0) {
|
||||||
k64f_enetif_input(k64f_enet->netif, idx);
|
k64f_enetif_input(k64f_enet->netif, idx);
|
||||||
idx = (idx + 1) % ENET_RX_RING_LEN;
|
idx = (idx + 1) % ENET_RX_RING_LEN;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Transmit cleanup task
|
/** \brief Transmit cleanup task
|
||||||
|
@ -489,16 +527,11 @@ static void packet_rx(void* pvParameters) {
|
||||||
* reclaims the pbuf and descriptor used for the packet once
|
* reclaims the pbuf and descriptor used for the packet once
|
||||||
* the packet has been transferred.
|
* the packet has been transferred.
|
||||||
*
|
*
|
||||||
* \param[in] pvParameters pointer to the interface data
|
* \param[in] k64f_enet pointer to the interface data
|
||||||
*/
|
*/
|
||||||
static void packet_tx(void* pvParameters) {
|
static void packet_tx(struct k64f_enetdata *k64f_enet)
|
||||||
struct k64f_enetdata *k64f_enet = pvParameters;
|
{
|
||||||
|
|
||||||
while (1) {
|
|
||||||
/* Wait for transmit cleanup task to wakeup */
|
|
||||||
sys_arch_sem_wait(&k64f_enet->TxCleanSem, 0);
|
|
||||||
k64f_tx_reclaim(k64f_enet);
|
k64f_tx_reclaim(k64f_enet);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Low level output of a packet. Never call this from an
|
/** \brief Low level output of a packet. Never call this from an
|
||||||
|
@ -569,7 +602,6 @@ static err_t k64f_low_level_output(struct netif *netif, struct pbuf *p)
|
||||||
* PHY task: monitor link
|
* PHY task: monitor link
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
|
|
||||||
#define PHY_TASK_PERIOD_MS 200
|
|
||||||
#define STATE_UNKNOWN (-1)
|
#define STATE_UNKNOWN (-1)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -578,7 +610,7 @@ typedef struct {
|
||||||
phy_duplex_t duplex;
|
phy_duplex_t duplex;
|
||||||
} PHY_STATE;
|
} PHY_STATE;
|
||||||
|
|
||||||
int phy_link_status() {
|
int phy_link_status(void) {
|
||||||
bool connection_status;
|
bool connection_status;
|
||||||
uint32_t phyAddr = 0;
|
uint32_t phyAddr = 0;
|
||||||
|
|
||||||
|
@ -586,40 +618,40 @@ int phy_link_status() {
|
||||||
return (int)connection_status;
|
return (int)connection_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void k64f_phy_task(void *data) {
|
static void k64f_phy_task(void *data)
|
||||||
struct netif *netif = (struct netif*)data;
|
{
|
||||||
bool connection_status;
|
struct netif *netif = data;
|
||||||
PHY_STATE crt_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN};
|
|
||||||
PHY_STATE prev_state;
|
static PHY_STATE prev_state = {STATE_UNKNOWN, (phy_speed_t)STATE_UNKNOWN, (phy_duplex_t)STATE_UNKNOWN};
|
||||||
uint32_t phyAddr = 0;
|
|
||||||
uint32_t rcr = 0;
|
uint32_t phyAddr = 0;
|
||||||
|
|
||||||
prev_state = crt_state;
|
|
||||||
while (true) {
|
|
||||||
// Get current status
|
// Get current status
|
||||||
|
PHY_STATE crt_state;
|
||||||
|
bool connection_status;
|
||||||
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
|
PHY_GetLinkStatus(ENET, phyAddr, &connection_status);
|
||||||
crt_state.connected = connection_status ? 1 : 0;
|
crt_state.connected = connection_status;
|
||||||
// Get the actual PHY link speed
|
// Get the actual PHY link speed
|
||||||
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex);
|
PHY_GetLinkSpeedDuplex(ENET, phyAddr, &crt_state.speed, &crt_state.duplex);
|
||||||
|
|
||||||
// Compare with previous state
|
// Compare with previous state
|
||||||
if (crt_state.connected != prev_state.connected) {
|
if (crt_state.connected != prev_state.connected) {
|
||||||
if (crt_state.connected)
|
// We're called from lwIP's tcpip thread, so can call link functions directly
|
||||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_up, (void*) netif, 1);
|
if (crt_state.connected) {
|
||||||
else
|
netif_set_link_up(netif);
|
||||||
tcpip_callback_with_block((tcpip_callback_fn)netif_set_link_down, (void*) netif, 1);
|
} else {
|
||||||
|
netif_set_link_down(netif);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (crt_state.speed != prev_state.speed) {
|
if (crt_state.speed != prev_state.speed) {
|
||||||
rcr = ENET->RCR;
|
uint32_t rcr = ENET->RCR;
|
||||||
rcr &= ~ENET_RCR_RMII_10T_MASK;
|
rcr &= ~ENET_RCR_RMII_10T_MASK;
|
||||||
rcr |= ENET_RCR_RMII_10T(!crt_state.speed);
|
rcr |= ENET_RCR_RMII_10T(!crt_state.speed);
|
||||||
ENET->RCR = rcr;
|
ENET->RCR = rcr;
|
||||||
}
|
}
|
||||||
|
|
||||||
prev_state = crt_state;
|
prev_state = crt_state;
|
||||||
osDelay(PHY_TASK_PERIOD_MS);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -707,27 +739,13 @@ err_t eth_arch_enetif_init(struct netif *netif)
|
||||||
err = sys_mutex_new(&k64f_enetdata.TXLockMutex);
|
err = sys_mutex_new(&k64f_enetdata.TXLockMutex);
|
||||||
LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
|
LWIP_ASSERT("TXLockMutex creation error", (err == ERR_OK));
|
||||||
|
|
||||||
/* Packet receive task */
|
|
||||||
err = sys_sem_new(&k64f_enetdata.RxReadySem, 0);
|
|
||||||
LWIP_ASSERT("RxReadySem creation error", (err == ERR_OK));
|
|
||||||
|
|
||||||
#ifdef LWIP_DEBUG
|
|
||||||
sys_thread_new("k64f_emac_rx_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE*5, RX_PRIORITY);
|
|
||||||
#else
|
|
||||||
sys_thread_new("k64f_emac_thread", packet_rx, netif->state, DEFAULT_THREAD_STACKSIZE, RX_PRIORITY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Transmit cleanup task */
|
|
||||||
err = sys_sem_new(&k64f_enetdata.TxCleanSem, 0);
|
|
||||||
LWIP_ASSERT("TxCleanSem creation error", (err == ERR_OK));
|
|
||||||
sys_thread_new("k64f_emac_txclean_thread", packet_tx, netif->state, DEFAULT_THREAD_STACKSIZE, TX_PRIORITY);
|
|
||||||
|
|
||||||
/* PHY monitoring task */
|
|
||||||
sys_thread_new("k64f_emac_phy_thread", k64f_phy_task, netif, DEFAULT_THREAD_STACKSIZE, PHY_PRIORITY);
|
|
||||||
|
|
||||||
/* Allow the PHY task to detect the initial link state and set up the proper flags */
|
/* Allow the PHY task to detect the initial link state and set up the proper flags */
|
||||||
|
tcpip_callback_with_block(k64f_phy_task, netif, 1);
|
||||||
osDelay(10);
|
osDelay(10);
|
||||||
|
|
||||||
|
/* Worker thread */
|
||||||
|
k64f_enetdata.thread = sys_thread_new("k64f_emac_thread", emac_thread, netif->state, THREAD_STACKSIZE, THREAD_PRIORITY)->id;
|
||||||
|
|
||||||
return ERR_OK;
|
return ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue