Skip to content

Commit

Permalink
Merge pull request #8676 from 0xc0170/dev_rollup
Browse files Browse the repository at this point in the history
Rollup PR
  • Loading branch information
Cruz Monrreal committed Nov 8, 2018
2 parents e635613 + 5a63a04 commit dee3506
Show file tree
Hide file tree
Showing 42 changed files with 2,234 additions and 3,530 deletions.
@@ -0,0 +1,7 @@
{
"name": "smsc9220-emac",
"config": {
"rx-ring-len": 1,
"tx-ring-len": 1
}
}
@@ -0,0 +1,338 @@
/*
* Copyright (c) 2018 Arm Limited
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "mbed_interface.h"
#include "mbed_wait_api.h"
#include "mbed_assert.h"
#include "netsocket/nsapi_types.h"
#include "mbed_shared_queues.h"

#include "smsc9220_emac.h"
#include "smsc9220_eth_drv.h"

#ifndef SMSC9220_ETH
#error "SMSC9220_ETH should be defined, check device_cfg.h!"
#endif

#ifndef SMSC9220_Ethernet_Interrupt_Handler
#error "SMSC9220_Ethernet_Interrupt_Handler should be defined to platform's \
Ethernet IRQ handler!"
#endif
static SMSC9220_EMAC *board_emac_pointer = NULL;
const struct smsc9220_eth_dev_t* SMSC9220_EMAC::dev = &SMSC9220_ETH_DEV;
extern "C" void SMSC9220_Ethernet_Interrupt_Handler(void)
{
if (smsc9220_get_interrupt(SMSC9220_EMAC::dev,
SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL)) {
board_emac_pointer->rx_isr();
smsc9220_clear_interrupt(SMSC9220_EMAC::dev,
SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL);
smsc9220_disable_interrupt(SMSC9220_EMAC::dev,
SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL);
}
}
SMSC9220_EMAC::SMSC9220_EMAC() : receiver_thread(LINK_STATUS_THREAD_PRIORITY,
(uint32_t)LINK_STATUS_THREAD_STACKSIZE)
{
}
/** \brief Ethernet receive interrupt handler
*
* This function handles the receive interrupt.
*/
void SMSC9220_EMAC::rx_isr()
{
receiver_thread.flags_set(FLAG_RX);
}
/** \brief Allocates a emac_mem_buf_t and returns the data from the incoming
* packet.
*
* \return a emac_mem_buf_t filled with the received packet
* (including MAC header)
*/
emac_mem_buf_t *SMSC9220_EMAC::low_level_input()
{
emac_mem_buf_t *p = NULL;
uint32_t message_length = 0;
message_length = smsc9220_peek_next_packet_size(dev);
if (message_length == 0) {
return p;
} else {
/* The Ethernet controller cannot remove CRC from the end of the
* incoming packet, thus it should be taken into account when
* calculating the actual message length.*/
message_length -= CRC_LENGTH_BYTES;
}
p = _memory_manager->alloc_heap(message_length, SMSC9220_BUFF_ALIGNMENT);
if (p != NULL) {
_RXLockMutex.lock();
smsc9220_receive_by_chunks(dev, (char*)_memory_manager->get_ptr(p),
_memory_manager->get_len(p));
_RXLockMutex.unlock();
}
return p;
}
/** \brief Receiver thread.
*
* Woken by thread flags to receive packets or clean up transmit
*
* \param[in] params pointer to the interface data
*/
void SMSC9220_EMAC::receiver_thread_function(void* params)
{
struct SMSC9220_EMAC *smsc9220_enet = static_cast<SMSC9220_EMAC *>(params);
while(1) {
uint32_t flags = ThisThread::flags_wait_any(FLAG_RX);
if (flags & FLAG_RX) {
smsc9220_enet->packet_rx();
}
}
}
/** \brief Packet reception task
*
* This task is called when a packet is received. It will
* pass the packet to the Network Stack.
*/
void SMSC9220_EMAC::packet_rx()
{
emac_mem_buf_t *p;
p = low_level_input();
if(p != NULL) {
_emac_link_input_cb(p);
}
smsc9220_enable_interrupt(dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL);
}
bool SMSC9220_EMAC::link_out(emac_mem_buf_t *buf)
{
if(buf == NULL) {
return false;
} else {
uint32_t buffer_chain_length = 0;
enum smsc9220_error_t error = SMSC9220_ERROR_NONE;
/* If buffer is chained or not aligned then
* make a contiguous aligned copy of it */
if (_memory_manager->get_next(buf) ||
reinterpret_cast<uint32_t>(_memory_manager->get_ptr(buf)) %
SMSC9220_BUFF_ALIGNMENT) {
emac_mem_buf_t *copy_buf;
copy_buf = _memory_manager->alloc_heap(
_memory_manager->get_total_len(buf),
SMSC9220_BUFF_ALIGNMENT);
if (NULL == copy_buf) {
_memory_manager->free(buf);
return false;
}
/* Copy to new buffer and free original */
_memory_manager->copy(copy_buf, buf);
_memory_manager->free(buf);
buf = copy_buf;
}
buffer_chain_length = _memory_manager->get_total_len(buf);
_TXLockMutex.lock();
error = smsc9220_send_by_chunks(dev,
buffer_chain_length,
true,
(const char*)_memory_manager->get_ptr(buf),
_memory_manager->get_len(buf));
if (error != SMSC9220_ERROR_NONE) {
_TXLockMutex.unlock();
return false;
}
_TXLockMutex.unlock();
return true;
}
}
void SMSC9220_EMAC::link_status_task()
{
uint32_t phy_basic_status_reg_value = 0;
bool current_link_status_up = false;
/* Get current status */
smsc9220_phy_regread(dev, SMSC9220_PHY_REG_OFFSET_BSTATUS,
&phy_basic_status_reg_value);
current_link_status_up = (bool)(phy_basic_status_reg_value &
(1ul << (PHY_REG_BSTATUS_LINK_STATUS_INDEX)));
/* Compare with previous state */
if (current_link_status_up != _prev_link_status_up) {
_emac_link_state_cb(current_link_status_up);
_prev_link_status_up = current_link_status_up;
}
}
bool SMSC9220_EMAC::power_up()
{
board_emac_pointer = this;
receiver_thread.start(callback(&SMSC9220_EMAC::receiver_thread_function,
this));
/* Initialize the hardware */
enum smsc9220_error_t init_successful = smsc9220_init(dev, &wait_ms);
if (init_successful != SMSC9220_ERROR_NONE) {
return false;
}
/* Init FIFO level interrupts: use Rx status level irq to trigger
* interrupts for any non-processed packets, while Tx is not irq driven */
smsc9220_set_fifo_level_irq(dev, SMSC9220_FIFO_LEVEL_IRQ_RX_STATUS_POS,
SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN);
smsc9220_set_fifo_level_irq(dev, SMSC9220_FIFO_LEVEL_IRQ_TX_STATUS_POS,
SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN);
smsc9220_set_fifo_level_irq(dev, SMSC9220_FIFO_LEVEL_IRQ_TX_DATA_POS,
SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MAX);
/* Enable Ethernet interrupts in NVIC */
NVIC_EnableIRQ(ETHERNET_IRQn);
smsc9220_enable_interrupt(dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL);
/* Trigger thread to deal with any RX packets that arrived
* before receiver_thread was started */
rx_isr();
_prev_link_status_up = PHY_STATE_LINK_DOWN;
mbed::mbed_event_queue()->call(mbed::callback(this,
&SMSC9220_EMAC::link_status_task));
/* Allow the Link Status task to detect the initial link state */
wait_ms(10);
_link_status_task_handle = mbed::mbed_event_queue()->call_every(
LINK_STATUS_TASK_PERIOD_MS,
mbed::callback(this,
&SMSC9220_EMAC::link_status_task));
return true;
}
uint32_t SMSC9220_EMAC::get_mtu_size() const
{
return SMSC9220_ETH_MTU_SIZE;
}
uint32_t SMSC9220_EMAC::get_align_preference() const
{
return SMSC9220_BUFF_ALIGNMENT;
}
void SMSC9220_EMAC::get_ifname(char *name, uint8_t size) const
{
memcpy(name, SMSC9220_ETH_IF_NAME, (size < sizeof(SMSC9220_ETH_IF_NAME)) ?
size : sizeof(SMSC9220_ETH_IF_NAME));
}
uint8_t SMSC9220_EMAC::get_hwaddr_size() const
{
return SMSC9220_HWADDR_SIZE;
}
bool SMSC9220_EMAC::get_hwaddr(uint8_t *addr) const
{
if(smsc9220_read_mac_address(dev, (char*)addr) == SMSC9220_ERROR_NONE) {
return true;
} else {
return false;
}
}
void SMSC9220_EMAC::set_hwaddr(const uint8_t *addr)
{
if (!addr) {
return;
}
memcpy(_hwaddr, addr, sizeof _hwaddr);
uint32_t mac_low = 0;
uint32_t mac_high = 0;
/* Using local variables to make sure the right alignment is used */
memcpy((void*)&mac_low, (void*)addr, 4);
memcpy((void*)&mac_high, (void*)(addr+4), 2);
if (smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_ADDRL, mac_low)) {
return;
}
if (smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_ADDRH, mac_high)) {
return;
}
}
void SMSC9220_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb)
{
_emac_link_input_cb = input_cb;
}
void SMSC9220_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb)
{
_emac_link_state_cb = state_cb;
}
void SMSC9220_EMAC::add_multicast_group(const uint8_t *addr)
{
// No action for now
}
void SMSC9220_EMAC::remove_multicast_group(const uint8_t *addr)
{
// No action for now
}
void SMSC9220_EMAC::set_all_multicast(bool all)
{
// No action for now
}
void SMSC9220_EMAC::power_down()
{
// No action for now
}
void SMSC9220_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr)
{
_memory_manager = &mem_mngr;
}
SMSC9220_EMAC &SMSC9220_EMAC::get_instance() {
static SMSC9220_EMAC emac;
return emac;
}
/* Weak so a module can override */
MBED_WEAK EMAC &EMAC::get_default_instance() {
return SMSC9220_EMAC::get_instance();
}

0 comments on commit dee3506

Please sign in to comment.