Skip to content

Commit dee3506

Browse files
author
Cruz Monrreal
authored
Merge pull request #8676 from 0xc0170/dev_rollup
Rollup PR
2 parents e635613 + 5a63a04 commit dee3506

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2234
-3530
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "smsc9220-emac",
3+
"config": {
4+
"rx-ring-len": 1,
5+
"tx-ring-len": 1
6+
}
7+
}
Lines changed: 338 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,338 @@
1+
/*
2+
* Copyright (c) 2018 Arm Limited
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include <ctype.h>
18+
#include <stdio.h>
19+
#include <string.h>
20+
#include <stdlib.h>
21+
22+
#include "mbed_interface.h"
23+
#include "mbed_wait_api.h"
24+
#include "mbed_assert.h"
25+
#include "netsocket/nsapi_types.h"
26+
#include "mbed_shared_queues.h"
27+
28+
#include "smsc9220_emac.h"
29+
#include "smsc9220_eth_drv.h"
30+
31+
#ifndef SMSC9220_ETH
32+
#error "SMSC9220_ETH should be defined, check device_cfg.h!"
33+
#endif
34+
35+
#ifndef SMSC9220_Ethernet_Interrupt_Handler
36+
#error "SMSC9220_Ethernet_Interrupt_Handler should be defined to platform's \
37+
Ethernet IRQ handler!"
38+
#endif
39+
40+
static SMSC9220_EMAC *board_emac_pointer = NULL;
41+
const struct smsc9220_eth_dev_t* SMSC9220_EMAC::dev = &SMSC9220_ETH_DEV;
42+
43+
extern "C" void SMSC9220_Ethernet_Interrupt_Handler(void)
44+
{
45+
if (smsc9220_get_interrupt(SMSC9220_EMAC::dev,
46+
SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL)) {
47+
board_emac_pointer->rx_isr();
48+
smsc9220_clear_interrupt(SMSC9220_EMAC::dev,
49+
SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL);
50+
smsc9220_disable_interrupt(SMSC9220_EMAC::dev,
51+
SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL);
52+
}
53+
}
54+
55+
SMSC9220_EMAC::SMSC9220_EMAC() : receiver_thread(LINK_STATUS_THREAD_PRIORITY,
56+
(uint32_t)LINK_STATUS_THREAD_STACKSIZE)
57+
{
58+
}
59+
60+
/** \brief Ethernet receive interrupt handler
61+
*
62+
* This function handles the receive interrupt.
63+
*/
64+
void SMSC9220_EMAC::rx_isr()
65+
{
66+
receiver_thread.flags_set(FLAG_RX);
67+
}
68+
69+
/** \brief Allocates a emac_mem_buf_t and returns the data from the incoming
70+
* packet.
71+
*
72+
* \return a emac_mem_buf_t filled with the received packet
73+
* (including MAC header)
74+
*/
75+
emac_mem_buf_t *SMSC9220_EMAC::low_level_input()
76+
{
77+
emac_mem_buf_t *p = NULL;
78+
uint32_t message_length = 0;
79+
80+
message_length = smsc9220_peek_next_packet_size(dev);
81+
if (message_length == 0) {
82+
return p;
83+
} else {
84+
/* The Ethernet controller cannot remove CRC from the end of the
85+
* incoming packet, thus it should be taken into account when
86+
* calculating the actual message length.*/
87+
message_length -= CRC_LENGTH_BYTES;
88+
}
89+
90+
p = _memory_manager->alloc_heap(message_length, SMSC9220_BUFF_ALIGNMENT);
91+
92+
if (p != NULL) {
93+
_RXLockMutex.lock();
94+
smsc9220_receive_by_chunks(dev, (char*)_memory_manager->get_ptr(p),
95+
_memory_manager->get_len(p));
96+
_RXLockMutex.unlock();
97+
}
98+
99+
return p;
100+
}
101+
102+
/** \brief Receiver thread.
103+
*
104+
* Woken by thread flags to receive packets or clean up transmit
105+
*
106+
* \param[in] params pointer to the interface data
107+
*/
108+
void SMSC9220_EMAC::receiver_thread_function(void* params)
109+
{
110+
struct SMSC9220_EMAC *smsc9220_enet = static_cast<SMSC9220_EMAC *>(params);
111+
112+
while(1) {
113+
uint32_t flags = ThisThread::flags_wait_any(FLAG_RX);
114+
115+
if (flags & FLAG_RX) {
116+
smsc9220_enet->packet_rx();
117+
}
118+
}
119+
}
120+
121+
/** \brief Packet reception task
122+
*
123+
* This task is called when a packet is received. It will
124+
* pass the packet to the Network Stack.
125+
*/
126+
void SMSC9220_EMAC::packet_rx()
127+
{
128+
emac_mem_buf_t *p;
129+
p = low_level_input();
130+
if(p != NULL) {
131+
_emac_link_input_cb(p);
132+
}
133+
smsc9220_enable_interrupt(dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL);
134+
}
135+
136+
bool SMSC9220_EMAC::link_out(emac_mem_buf_t *buf)
137+
{
138+
if(buf == NULL) {
139+
return false;
140+
} else {
141+
uint32_t buffer_chain_length = 0;
142+
enum smsc9220_error_t error = SMSC9220_ERROR_NONE;
143+
/* If buffer is chained or not aligned then
144+
* make a contiguous aligned copy of it */
145+
if (_memory_manager->get_next(buf) ||
146+
reinterpret_cast<uint32_t>(_memory_manager->get_ptr(buf)) %
147+
SMSC9220_BUFF_ALIGNMENT) {
148+
emac_mem_buf_t *copy_buf;
149+
copy_buf = _memory_manager->alloc_heap(
150+
_memory_manager->get_total_len(buf),
151+
SMSC9220_BUFF_ALIGNMENT);
152+
if (NULL == copy_buf) {
153+
_memory_manager->free(buf);
154+
return false;
155+
}
156+
157+
/* Copy to new buffer and free original */
158+
_memory_manager->copy(copy_buf, buf);
159+
_memory_manager->free(buf);
160+
buf = copy_buf;
161+
}
162+
163+
buffer_chain_length = _memory_manager->get_total_len(buf);
164+
165+
_TXLockMutex.lock();
166+
error = smsc9220_send_by_chunks(dev,
167+
buffer_chain_length,
168+
true,
169+
(const char*)_memory_manager->get_ptr(buf),
170+
_memory_manager->get_len(buf));
171+
if (error != SMSC9220_ERROR_NONE) {
172+
_TXLockMutex.unlock();
173+
return false;
174+
}
175+
_TXLockMutex.unlock();
176+
return true;
177+
}
178+
}
179+
180+
void SMSC9220_EMAC::link_status_task()
181+
{
182+
uint32_t phy_basic_status_reg_value = 0;
183+
bool current_link_status_up = false;
184+
185+
/* Get current status */
186+
smsc9220_phy_regread(dev, SMSC9220_PHY_REG_OFFSET_BSTATUS,
187+
&phy_basic_status_reg_value);
188+
189+
current_link_status_up = (bool)(phy_basic_status_reg_value &
190+
(1ul << (PHY_REG_BSTATUS_LINK_STATUS_INDEX)));
191+
192+
/* Compare with previous state */
193+
if (current_link_status_up != _prev_link_status_up) {
194+
_emac_link_state_cb(current_link_status_up);
195+
_prev_link_status_up = current_link_status_up;
196+
}
197+
198+
}
199+
200+
bool SMSC9220_EMAC::power_up()
201+
{
202+
board_emac_pointer = this;
203+
receiver_thread.start(callback(&SMSC9220_EMAC::receiver_thread_function,
204+
this));
205+
206+
/* Initialize the hardware */
207+
enum smsc9220_error_t init_successful = smsc9220_init(dev, &wait_ms);
208+
if (init_successful != SMSC9220_ERROR_NONE) {
209+
return false;
210+
}
211+
212+
/* Init FIFO level interrupts: use Rx status level irq to trigger
213+
* interrupts for any non-processed packets, while Tx is not irq driven */
214+
smsc9220_set_fifo_level_irq(dev, SMSC9220_FIFO_LEVEL_IRQ_RX_STATUS_POS,
215+
SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN);
216+
smsc9220_set_fifo_level_irq(dev, SMSC9220_FIFO_LEVEL_IRQ_TX_STATUS_POS,
217+
SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MIN);
218+
smsc9220_set_fifo_level_irq(dev, SMSC9220_FIFO_LEVEL_IRQ_TX_DATA_POS,
219+
SMSC9220_FIFO_LEVEL_IRQ_LEVEL_MAX);
220+
221+
/* Enable Ethernet interrupts in NVIC */
222+
NVIC_EnableIRQ(ETHERNET_IRQn);
223+
smsc9220_enable_interrupt(dev, SMSC9220_INTERRUPT_RX_STATUS_FIFO_LEVEL);
224+
225+
/* Trigger thread to deal with any RX packets that arrived
226+
* before receiver_thread was started */
227+
rx_isr();
228+
_prev_link_status_up = PHY_STATE_LINK_DOWN;
229+
mbed::mbed_event_queue()->call(mbed::callback(this,
230+
&SMSC9220_EMAC::link_status_task));
231+
232+
/* Allow the Link Status task to detect the initial link state */
233+
wait_ms(10);
234+
_link_status_task_handle = mbed::mbed_event_queue()->call_every(
235+
LINK_STATUS_TASK_PERIOD_MS,
236+
mbed::callback(this,
237+
&SMSC9220_EMAC::link_status_task));
238+
239+
return true;
240+
}
241+
242+
uint32_t SMSC9220_EMAC::get_mtu_size() const
243+
{
244+
return SMSC9220_ETH_MTU_SIZE;
245+
}
246+
247+
uint32_t SMSC9220_EMAC::get_align_preference() const
248+
{
249+
return SMSC9220_BUFF_ALIGNMENT;
250+
}
251+
252+
void SMSC9220_EMAC::get_ifname(char *name, uint8_t size) const
253+
{
254+
memcpy(name, SMSC9220_ETH_IF_NAME, (size < sizeof(SMSC9220_ETH_IF_NAME)) ?
255+
size : sizeof(SMSC9220_ETH_IF_NAME));
256+
}
257+
258+
uint8_t SMSC9220_EMAC::get_hwaddr_size() const
259+
{
260+
return SMSC9220_HWADDR_SIZE;
261+
}
262+
263+
bool SMSC9220_EMAC::get_hwaddr(uint8_t *addr) const
264+
{
265+
if(smsc9220_read_mac_address(dev, (char*)addr) == SMSC9220_ERROR_NONE) {
266+
return true;
267+
} else {
268+
return false;
269+
}
270+
}
271+
272+
void SMSC9220_EMAC::set_hwaddr(const uint8_t *addr)
273+
{
274+
if (!addr) {
275+
return;
276+
}
277+
278+
memcpy(_hwaddr, addr, sizeof _hwaddr);
279+
uint32_t mac_low = 0;
280+
uint32_t mac_high = 0;
281+
282+
/* Using local variables to make sure the right alignment is used */
283+
memcpy((void*)&mac_low, (void*)addr, 4);
284+
memcpy((void*)&mac_high, (void*)(addr+4), 2);
285+
286+
if (smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_ADDRL, mac_low)) {
287+
return;
288+
}
289+
if (smsc9220_mac_regwrite(dev, SMSC9220_MAC_REG_OFFSET_ADDRH, mac_high)) {
290+
return;
291+
}
292+
}
293+
294+
void SMSC9220_EMAC::set_link_input_cb(emac_link_input_cb_t input_cb)
295+
{
296+
_emac_link_input_cb = input_cb;
297+
}
298+
299+
void SMSC9220_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb)
300+
{
301+
_emac_link_state_cb = state_cb;
302+
}
303+
304+
void SMSC9220_EMAC::add_multicast_group(const uint8_t *addr)
305+
{
306+
// No action for now
307+
}
308+
309+
void SMSC9220_EMAC::remove_multicast_group(const uint8_t *addr)
310+
{
311+
// No action for now
312+
}
313+
314+
void SMSC9220_EMAC::set_all_multicast(bool all)
315+
{
316+
// No action for now
317+
}
318+
319+
void SMSC9220_EMAC::power_down()
320+
{
321+
// No action for now
322+
}
323+
324+
void SMSC9220_EMAC::set_memory_manager(EMACMemoryManager &mem_mngr)
325+
{
326+
_memory_manager = &mem_mngr;
327+
}
328+
329+
330+
SMSC9220_EMAC &SMSC9220_EMAC::get_instance() {
331+
static SMSC9220_EMAC emac;
332+
return emac;
333+
}
334+
335+
/* Weak so a module can override */
336+
MBED_WEAK EMAC &EMAC::get_default_instance() {
337+
return SMSC9220_EMAC::get_instance();
338+
}

0 commit comments

Comments
 (0)