mirror of https://github.com/ARMmbed/mbed-os.git
MPS2 CM3DS ethernet words instead of bytes
The functions smsc9220_receive_by_chunks and smsc9220_send_by_chunks are supposed to implement receiving and sending packets by chunks. However, the functions SMSC9220_EMAC::low_level_input and SMSC9220_EMAC::link_out, which call them respectively, already require or assemble the full packet. Also, smsc9220_receive_by_chunks doesn't implement the "chunks" part. This commit renames the functions to smsc9220_receive_packet and smsc9220_send_packet. The functions now do their operations by word instead of by bytes. The functions SMSC9220_EMAC::low_level_input and SMSC9220_EMAC::link_out already handle allocation, continuity and word alignment of the packet buffer.pull/15284/head
parent
f7aca62865
commit
fdf37c3217
|
@ -94,9 +94,8 @@ emac_mem_buf_t *SMSC9220_EMAC::low_level_input()
|
||||||
|
|
||||||
if (p != NULL) {
|
if (p != NULL) {
|
||||||
_RXLockMutex.lock();
|
_RXLockMutex.lock();
|
||||||
received_bytes = smsc9220_receive_by_chunks(dev,
|
received_bytes = smsc9220_receive_packet(dev,
|
||||||
(char*)_memory_manager->get_ptr(p),
|
_memory_manager->get_ptr(p));
|
||||||
_memory_manager->get_len(p));
|
|
||||||
if(received_bytes == 0){
|
if(received_bytes == 0){
|
||||||
_memory_manager->free(p);
|
_memory_manager->free(p);
|
||||||
p = nullptr;
|
p = nullptr;
|
||||||
|
@ -148,7 +147,6 @@ bool SMSC9220_EMAC::link_out(emac_mem_buf_t *buf)
|
||||||
if(buf == NULL) {
|
if(buf == NULL) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
uint32_t buffer_chain_length = 0;
|
|
||||||
enum smsc9220_error_t error = SMSC9220_ERROR_NONE;
|
enum smsc9220_error_t error = SMSC9220_ERROR_NONE;
|
||||||
/* If buffer is chained or not aligned then
|
/* If buffer is chained or not aligned then
|
||||||
* make a contiguous aligned copy of it */
|
* make a contiguous aligned copy of it */
|
||||||
|
@ -170,16 +168,12 @@ bool SMSC9220_EMAC::link_out(emac_mem_buf_t *buf)
|
||||||
buf = copy_buf;
|
buf = copy_buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
buffer_chain_length = _memory_manager->get_total_len(buf);
|
|
||||||
|
|
||||||
_TXLockMutex.lock();
|
_TXLockMutex.lock();
|
||||||
error = smsc9220_send_by_chunks(dev,
|
error = smsc9220_send_packet(dev,
|
||||||
buffer_chain_length,
|
_memory_manager->get_ptr(buf),
|
||||||
true,
|
|
||||||
(const char*)_memory_manager->get_ptr(buf),
|
|
||||||
_memory_manager->get_len(buf));
|
_memory_manager->get_len(buf));
|
||||||
_memory_manager->free(buf);
|
_memory_manager->free(buf);
|
||||||
_TXLockMutex.unlock();
|
_TXLockMutex.unlock();
|
||||||
return (error == SMSC9220_ERROR_NONE);
|
return (error == SMSC9220_ERROR_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -284,73 +284,6 @@ enum gpio_cfg_bits_t{
|
||||||
GPIO_CFG_GPIO2_LED_INDEX = 30U /*< GPIO2 set to LED3 */
|
GPIO_CFG_GPIO2_LED_INDEX = 30U /*< GPIO2 set to LED3 */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void fill_tx_fifo(const struct smsc9220_eth_dev_t* dev,
|
|
||||||
uint8_t *data, uint32_t size_bytes)
|
|
||||||
{
|
|
||||||
struct smsc9220_eth_reg_map_t* register_map =
|
|
||||||
(struct smsc9220_eth_reg_map_t*)dev->cfg->base;
|
|
||||||
|
|
||||||
uint32_t tx_data_port_tmp = 0;
|
|
||||||
uint8_t *tx_data_port_tmp_ptr = (uint8_t *)&tx_data_port_tmp;
|
|
||||||
|
|
||||||
/*If the data length is not a multiple of 4, then the beginning of the first
|
|
||||||
* DWORD of the TX DATA FIFO gets filled up with zeros and a byte offset is
|
|
||||||
* set accordingly to guarantee proper transmission.*/
|
|
||||||
uint32_t remainder_bytes = (size_bytes % 4);
|
|
||||||
uint32_t filler_bytes = (4 - remainder_bytes);
|
|
||||||
for(uint32_t i = 0; i < 4; i++){
|
|
||||||
if(i < filler_bytes){
|
|
||||||
tx_data_port_tmp_ptr[i] = 0;
|
|
||||||
} else {
|
|
||||||
tx_data_port_tmp_ptr[i] = data[i-filler_bytes];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
register_map->tx_data_port = tx_data_port_tmp;
|
|
||||||
size_bytes -= remainder_bytes;
|
|
||||||
data += remainder_bytes;
|
|
||||||
|
|
||||||
while (size_bytes > 0) {
|
|
||||||
/* Keep the same endianness in data as in the temp variable */
|
|
||||||
tx_data_port_tmp_ptr[0] = data[0];
|
|
||||||
tx_data_port_tmp_ptr[1] = data[1];
|
|
||||||
tx_data_port_tmp_ptr[2] = data[2];
|
|
||||||
tx_data_port_tmp_ptr[3] = data[3];
|
|
||||||
register_map->tx_data_port = tx_data_port_tmp;
|
|
||||||
data += 4;
|
|
||||||
size_bytes -= 4;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void empty_rx_fifo(const struct smsc9220_eth_dev_t* dev,
|
|
||||||
uint8_t *data, uint32_t size_bytes)
|
|
||||||
{
|
|
||||||
struct smsc9220_eth_reg_map_t* register_map =
|
|
||||||
(struct smsc9220_eth_reg_map_t*)dev->cfg->base;
|
|
||||||
|
|
||||||
uint32_t rx_data_port_tmp = 0;
|
|
||||||
uint8_t *rx_data_port_tmp_ptr = (uint8_t *)&rx_data_port_tmp;
|
|
||||||
|
|
||||||
uint32_t remainder_bytes = (size_bytes % 4);
|
|
||||||
size_bytes -= remainder_bytes;
|
|
||||||
|
|
||||||
while (size_bytes > 0) {
|
|
||||||
/* Keep the same endianness in data as in the temp variable */
|
|
||||||
rx_data_port_tmp = register_map->rx_data_port;
|
|
||||||
data[0] = rx_data_port_tmp_ptr[0];
|
|
||||||
data[1] = rx_data_port_tmp_ptr[1];
|
|
||||||
data[2] = rx_data_port_tmp_ptr[2];
|
|
||||||
data[3] = rx_data_port_tmp_ptr[3];
|
|
||||||
data += 4;
|
|
||||||
size_bytes -= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
rx_data_port_tmp = register_map->rx_data_port;
|
|
||||||
for(uint32_t i = 0; i < remainder_bytes; i++) {
|
|
||||||
data[i] = rx_data_port_tmp_ptr[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum smsc9220_error_t smsc9220_mac_regread(
|
enum smsc9220_error_t smsc9220_mac_regread(
|
||||||
const struct smsc9220_eth_dev_t* dev,
|
const struct smsc9220_eth_dev_t* dev,
|
||||||
enum smsc9220_mac_reg_offsets_t regoffset,
|
enum smsc9220_mac_reg_offsets_t regoffset,
|
||||||
|
@ -949,77 +882,45 @@ enum smsc9220_error_t smsc9220_init(
|
||||||
return SMSC9220_ERROR_NONE;
|
return SMSC9220_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum smsc9220_error_t smsc9220_send_by_chunks(
|
enum smsc9220_error_t smsc9220_send_packet (
|
||||||
const struct smsc9220_eth_dev_t* dev,
|
const struct smsc9220_eth_dev_t* dev,
|
||||||
uint32_t total_payload_length,
|
void *data, uint32_t dlen)
|
||||||
bool is_new_packet,
|
|
||||||
const char *data, uint32_t current_size)
|
|
||||||
{
|
{
|
||||||
struct smsc9220_eth_reg_map_t* register_map =
|
struct smsc9220_eth_reg_map_t* register_map =
|
||||||
(struct smsc9220_eth_reg_map_t*)dev->cfg->base;
|
(struct smsc9220_eth_reg_map_t*)dev->cfg->base;
|
||||||
bool is_first_segment = false;
|
uint32_t txcmd_a = 0, txcmd_b = 0;
|
||||||
bool is_last_segment = false;
|
|
||||||
uint32_t txcmd_a, txcmd_b = 0;
|
|
||||||
uint32_t tx_buffer_free_space = 0;
|
uint32_t tx_buffer_free_space = 0;
|
||||||
volatile uint32_t xmit_stat = 0;
|
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return SMSC9220_ERROR_PARAM;
|
return SMSC9220_ERROR_PARAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_new_packet) {
|
|
||||||
is_first_segment = true;
|
|
||||||
dev->data->ongoing_packet_length = total_payload_length;
|
|
||||||
dev->data->ongoing_packet_length_sent = 0;
|
|
||||||
} else if (dev->data->ongoing_packet_length != total_payload_length ||
|
|
||||||
dev->data->ongoing_packet_length_sent >= total_payload_length) {
|
|
||||||
return SMSC9220_ERROR_PARAM;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Would next chunk fit into buffer? */
|
/* Would next chunk fit into buffer? */
|
||||||
tx_buffer_free_space = GET_BIT_FIELD(register_map->tx_fifo_inf,
|
tx_buffer_free_space = GET_BIT_FIELD(register_map->tx_fifo_inf,
|
||||||
FIFO_USED_SPACE_MASK,
|
FIFO_USED_SPACE_MASK,
|
||||||
DATA_FIFO_USED_SPACE_POS);
|
DATA_FIFO_USED_SPACE_POS);
|
||||||
if (current_size > tx_buffer_free_space) {
|
if (dlen > tx_buffer_free_space) {
|
||||||
return SMSC9220_ERROR_INTERNAL; /* Not enough space in FIFO */
|
return SMSC9220_ERROR_INTERNAL; /* Not enough space in FIFO */
|
||||||
}
|
}
|
||||||
if ((dev->data->ongoing_packet_length_sent + current_size) ==
|
|
||||||
total_payload_length) {
|
|
||||||
is_last_segment = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
txcmd_a = 0;
|
|
||||||
txcmd_b = 0;
|
|
||||||
|
|
||||||
if (is_last_segment) {
|
|
||||||
SET_BIT(txcmd_a, TX_COMMAND_A_LAST_SEGMENT_INDEX);
|
|
||||||
}
|
|
||||||
if (is_first_segment) {
|
|
||||||
SET_BIT(txcmd_a, TX_COMMAND_A_FIRST_SEGMENT_INDEX);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t data_start_offset_bytes = (4 - (current_size % 4));
|
|
||||||
|
|
||||||
SET_BIT_FIELD(txcmd_a, TX_CMD_PKT_LEN_BYTES_MASK, 0, current_size);
|
|
||||||
SET_BIT_FIELD(txcmd_a, TX_CMD_DATA_START_OFFSET_BYTES_MASK,
|
|
||||||
TX_CMD_DATA_START_OFFSET_BYTES_POS,
|
|
||||||
data_start_offset_bytes);
|
|
||||||
|
|
||||||
SET_BIT_FIELD(txcmd_b, TX_CMD_PKT_LEN_BYTES_MASK, 0, current_size);
|
|
||||||
SET_BIT_FIELD(txcmd_b, TX_CMD_PKT_TAG_MASK, TX_CMD_PKT_TAG_POS,
|
|
||||||
current_size);
|
|
||||||
|
|
||||||
|
SET_BIT(txcmd_a, TX_COMMAND_A_LAST_SEGMENT_INDEX);
|
||||||
|
SET_BIT(txcmd_a, TX_COMMAND_A_FIRST_SEGMENT_INDEX);
|
||||||
|
SET_BIT_FIELD(txcmd_a, TX_CMD_PKT_LEN_BYTES_MASK, 0, dlen);
|
||||||
|
SET_BIT_FIELD(txcmd_b, TX_CMD_PKT_LEN_BYTES_MASK, 0, dlen);
|
||||||
|
SET_BIT_FIELD(txcmd_b, TX_CMD_PKT_TAG_MASK, TX_CMD_PKT_TAG_POS, dlen);
|
||||||
register_map->tx_data_port = txcmd_a;
|
register_map->tx_data_port = txcmd_a;
|
||||||
register_map->tx_data_port = txcmd_b;
|
register_map->tx_data_port = txcmd_b;
|
||||||
|
|
||||||
fill_tx_fifo(dev, (uint8_t *)data, current_size);
|
/* Ethernet data port is padding to 32bit aligned data */
|
||||||
|
uint32_t dwords_to_write = (dlen + 3) >> 2;
|
||||||
if (is_last_segment) {
|
uint32_t *data_ptr = (uint32_t *) data;
|
||||||
/* Pop status port for error check */
|
for(uint32_t i = 0; i < dwords_to_write; i++) {
|
||||||
xmit_stat = register_map->tx_status_port;
|
register_map->tx_data_port = data_ptr[i];
|
||||||
(void)xmit_stat;
|
|
||||||
}
|
}
|
||||||
dev->data->ongoing_packet_length_sent += current_size;
|
|
||||||
|
/* Pop status port for error check */
|
||||||
|
(void) (register_map->tx_status_port);
|
||||||
|
|
||||||
return SMSC9220_ERROR_NONE;
|
return SMSC9220_ERROR_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1033,10 +934,9 @@ uint32_t smsc9220_get_rxfifo_data_used_space(const struct
|
||||||
DATA_FIFO_USED_SPACE_POS);
|
DATA_FIFO_USED_SPACE_POS);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t smsc9220_receive_by_chunks(const struct smsc9220_eth_dev_t* dev,
|
uint32_t smsc9220_receive_packet(const struct smsc9220_eth_dev_t* dev,
|
||||||
char *data, uint32_t dlen)
|
void *data)
|
||||||
{
|
{
|
||||||
uint32_t rxfifo_inf = 0;
|
|
||||||
uint32_t rxfifo_stat = 0;
|
uint32_t rxfifo_stat = 0;
|
||||||
uint32_t packet_length_byte = 0;
|
uint32_t packet_length_byte = 0;
|
||||||
struct smsc9220_eth_reg_map_t* register_map =
|
struct smsc9220_eth_reg_map_t* register_map =
|
||||||
|
@ -1045,23 +945,22 @@ uint32_t smsc9220_receive_by_chunks(const struct smsc9220_eth_dev_t* dev,
|
||||||
if (!data) {
|
if (!data) {
|
||||||
return 0; /* Invalid input parameter, cannot read */
|
return 0; /* Invalid input parameter, cannot read */
|
||||||
}
|
}
|
||||||
rxfifo_inf = register_map->rx_fifo_inf;
|
|
||||||
|
|
||||||
if(rxfifo_inf & 0xFFFF) { /* If there's data */
|
/* Status port not empty from smsc9220_peek_next_packet_size */
|
||||||
rxfifo_stat = register_map->rx_status_port;
|
rxfifo_stat = register_map->rx_status_port;
|
||||||
if(rxfifo_stat != 0) { /* Fetch status of this packet */
|
packet_length_byte = GET_BIT_FIELD(rxfifo_stat,
|
||||||
/* Ethernet controller is padding to 32bit aligned data */
|
RX_FIFO_STATUS_PKT_LENGTH_MASK,
|
||||||
packet_length_byte = GET_BIT_FIELD(rxfifo_stat,
|
RX_FIFO_STATUS_PKT_LENGTH_POS);
|
||||||
RX_FIFO_STATUS_PKT_LENGTH_MASK,
|
packet_length_byte -= 4; /* Discard last word (CRC) */
|
||||||
RX_FIFO_STATUS_PKT_LENGTH_POS);
|
|
||||||
packet_length_byte -= 4;
|
/* Ethernet data port is padding to 32bit aligned data */
|
||||||
dev->data->current_rx_size_words = packet_length_byte;
|
uint32_t dwords_to_read = (packet_length_byte + 3) >> 2;
|
||||||
}
|
uint32_t *data_ptr = (uint32_t *) data;
|
||||||
|
for(uint32_t i = 0; i < dwords_to_read; i++) {
|
||||||
|
data_ptr[i] = register_map->rx_data_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
empty_rx_fifo(dev, (uint8_t *)data, packet_length_byte);
|
|
||||||
(void) (register_map->rx_data_port); /* Discard last word (CRC) */
|
(void) (register_map->rx_data_port); /* Discard last word (CRC) */
|
||||||
dev->data->current_rx_size_words = 0;
|
|
||||||
return packet_length_byte;
|
return packet_length_byte;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -480,40 +480,34 @@ uint32_t smsc9220_get_tx_data_fifo_size(const struct
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Sends data from the given buffer as an Ethernet packet.
|
* \brief Sends data from the given buffer as an Ethernet packet.
|
||||||
* The full packet length must be specified at the beginning
|
* The data to send must be a full packet.
|
||||||
* of a new packet transmission.
|
|
||||||
*
|
*
|
||||||
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
|
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
|
||||||
* \param[in] total_payload_length Length of the ethernet payload.
|
* \param[in] data Pointer to the word aligned packet buffer to be sent.
|
||||||
* Should be equal to the sum of passed buffers within a packet.
|
* \param[in] dlen Size of the packet in bytes.
|
||||||
* \param[in] is_new_packet Should be set to true if the input buffer has to
|
|
||||||
* be sent as the start of a new packet or as a full packet.
|
|
||||||
* \param[in] data Pointer to the data buffer to be sent.
|
|
||||||
* \param[in] current_size Size of the data in bytes.
|
|
||||||
*
|
*
|
||||||
* \return error code /ref smsc9220_error_t
|
* \return error code /ref smsc9220_error_t
|
||||||
*/
|
*/
|
||||||
enum smsc9220_error_t smsc9220_send_by_chunks(
|
enum smsc9220_error_t smsc9220_send_packet(
|
||||||
const struct smsc9220_eth_dev_t* dev,
|
const struct smsc9220_eth_dev_t* dev,
|
||||||
uint32_t total_payload_length,
|
void *data, uint32_t dlen);
|
||||||
bool is_new_packet,
|
|
||||||
const char *data, uint32_t current_size);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Reads an incoming Ethernet packet into the given buffer.
|
* \brief Reads an incoming Ethernet packet into the given buffer.
|
||||||
* Stops reading at packet border.
|
* Stops reading at packet border.
|
||||||
*
|
*
|
||||||
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
|
* \param[in] dev Ethernet device structure \ref smsc9220_eth_dev_t
|
||||||
* \param[in,out] data Pointer to a pre-allocated input buffer.
|
* \param[in,out] data Pointer to a pre-allocated word aligned input buffer.
|
||||||
* Allocating sufficient memory space is the caller's
|
* Availability of packets, as well as, alignment and
|
||||||
|
* allocating sufficient memory space is the caller's
|
||||||
* responsibility, which is typically done by calling
|
* responsibility, which is typically done by calling
|
||||||
* \ref smsc9220_peek_next_packet_size.
|
* \ref smsc9220_peek_next_packet_size.
|
||||||
* \param[in] dlen Length of the allocated data in bytes.
|
|
||||||
*
|
*
|
||||||
* \return Number of bytes read from the Rx FIFO into the given buffer.
|
* \return Number of bytes read from the Rx FIFO into the given buffer.
|
||||||
*/
|
*/
|
||||||
uint32_t smsc9220_receive_by_chunks(const struct smsc9220_eth_dev_t* dev,
|
uint32_t smsc9220_receive_packet(
|
||||||
char *data, uint32_t dlen);
|
const struct smsc9220_eth_dev_t* dev,
|
||||||
|
void *data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* \brief Get the used space of Rx fifo in bytes.
|
* \brief Get the used space of Rx fifo in bytes.
|
||||||
|
|
Loading…
Reference in New Issue