Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #8676 from 0xc0170/dev_rollup
Rollup PR
- Loading branch information
Showing
42 changed files
with
2,234 additions
and
3,530 deletions.
There are no files selected for viewing
7 changes: 7 additions & 0 deletions
7
features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/mbed_lib.json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"name": "smsc9220-emac", | ||
"config": { | ||
"rx-ring-len": 1, | ||
"tx-ring-len": 1 | ||
} | ||
} |
338 changes: 338 additions & 0 deletions
338
features/netsocket/emac-drivers/TARGET_ARM_SSG/COMPONENT_SMSC9220/smsc9220_emac.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} |
Oops, something went wrong.