Skip to content

Commit ef7b16d

Browse files
committed
CM3DS: fix non aligned access in Ethernet driver
This patch changes the way data is put in the TX_DATA_PORT register when sending packet over Ethernet. When this driver is compiled with release compilation profile (space optimization compiler options) with Arm compiler version 5, the line: SMSC9220->TX_DATA_PORT = *pktptr; generates the assembly instruction to get the pktptr pointed value: LDM r2!, {r3} with pktptr = r2 However, the code does not prevent the pktptr value from being unaligned (to a 32 bits boundary) in that zone and the LDM instruction causes a HardFault if this is the case. When the compiler option is not activated (debug and develop compilation profiles), the compiler generates LDR instruction instead which does not cause a HardFault. The ARM v7-M states page B3-601: "Unaligned load-store multiples and word or halfword exclusive accesses always fault." To face that problem, we check if the data pointer is aligned or not. If it is, we apply the same algorithm than before. If not, a local variable is created and we copy in it, byte per byte, the contents at the unaligned pointer. However, it will impact performances adding 8 instructions (one LD and one ST for each copied byte). Change-Id: I11f6e82ce5521960d2ecf499f718f76fec29c0b0 Signed-off-by: Hugues de Valon <[email protected]>
1 parent 5b8ff81 commit ef7b16d

File tree

2 files changed

+73
-13
lines changed

2 files changed

+73
-13
lines changed

features/FEATURE_LWIP/lwip-interface/lwip-eth/arch/TARGET_CM3DS_MPS2/lwipopts_conf.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2017 ARM Limited
1+
/* Copyright (c) 2017-2018 ARM Limited
22
*
33
* Licensed under the Apache License, Version 2.0 (the "License");
44
* you may not use this file except in compliance with the License.
@@ -22,12 +22,22 @@
2222
/* size is 1522 bytes to accommodate the four-byte VLAN tag. */
2323
#define ETH_MAX_FLEN 1522u /* recommended size for a VLAN frame */
2424

25-
/* Maximum Transfer Unit
26-
* The IEEE 802.3 specification limits the data portion of the 802.3 frame
27-
* to a minimum of 46 and a maximum of 1500 bytes, this is on L3 level.
28-
*/
25+
/*
26+
* Maximum Transfer Unit
27+
* The IEEE 802.3 specification limits the data portion of the 802.3 frame
28+
* to a minimum of 46 and a maximum of 1522 bytes, this is on L2 level.
29+
*/
2930
#define ETH_L2_HEADER_LEN 22u
3031

3132
#define ETH_MAX_PAYLOAD_LEN (ETH_MAX_FLEN - ETH_L2_HEADER_LEN)
3233

34+
/*
35+
* Set this value to 2 to ensure that payload address of packet buffers is
36+
* aligned on a 32 bits boundary.
37+
* The padding is removed before passing the packet to the ethernet driver,
38+
* hence defining this value to 2 will not prevent alignment issues inside the
39+
* ethernet driver.
40+
*/
41+
#define ETH_PAD_SIZE 0
42+
3343
#endif /* LWIPOPTS_CONF_H */

targets/TARGET_ARM_SSG/TARGET_CM3DS_MPS2/SDK/smsc9220_eth.c

Lines changed: 58 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* mbed Microcontroller Library
2-
* Copyright (c) 2017 ARM Limited
2+
* Copyright (c) 2017-2018 ARM Limited
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -426,6 +426,53 @@ static int smsc9220_check_id(void)
426426
return 0;
427427
}
428428

429+
/**
430+
* \brief Fill the SMSC9220 TX FIFO with a number of words at an aligned
431+
* address.
432+
*
433+
* \param[in] data Pointer to the aligned data that should be sent.
434+
* \param[in] dwords_to_write Number of data words to write.
435+
*/
436+
static void fill_tx_fifo_aligned(unsigned int *data,
437+
unsigned int dwords_to_write)
438+
{
439+
while (dwords_to_write > 0) {
440+
SMSC9220->TX_DATA_PORT = *data;
441+
data++;
442+
dwords_to_write--;
443+
}
444+
}
445+
446+
/**
447+
* \brief Fill the SMSC9220 TX FIFO with a number of words at an unaligned
448+
* address. This function ensures that loading words at that address will
449+
* not generate unaligned access which can trigger an exception to the
450+
* processor.
451+
*
452+
* \param[in] data Pointer to the unaligned data that should be sent.
453+
* \param[in] dwords_to_write Number of data words to write.
454+
*/
455+
static void fill_tx_fifo_unaligned(uint8_t *data, unsigned int dwords_to_write)
456+
{
457+
/*
458+
* Prevent unaligned word access from data pointer, 4 bytes are copied to
459+
* this variable for each word that need to be sent.
460+
*/
461+
unsigned int tx_data_port_tmp = 0;
462+
uint8_t *tx_data_port_tmp_ptr = (uint8_t *)&tx_data_port_tmp;
463+
464+
while (dwords_to_write > 0) {
465+
/* Keep the same endianness in data than in the temp variable */
466+
tx_data_port_tmp_ptr[0] = data[0];
467+
tx_data_port_tmp_ptr[1] = data[1];
468+
tx_data_port_tmp_ptr[2] = data[2];
469+
tx_data_port_tmp_ptr[3] = data[3];
470+
SMSC9220->TX_DATA_PORT = tx_data_port_tmp;
471+
data += 4;
472+
dwords_to_write--;
473+
}
474+
}
475+
429476
/*----------------------------------------------------------------------------
430477
Public API
431478
*----------------------------------------------------------------------------*/
@@ -574,7 +621,6 @@ int smsc9220_send_by_chunks(unsigned int total_packet_length, int is_new_packet,
574621
int is_last_segment = 0; /* signing this is the last segment of the packet to be sent */
575622
unsigned int txcmd_a, txcmd_b = 0;
576623
unsigned int dwords_to_write = 0;
577-
unsigned int *pktptr = 0;
578624
unsigned int xmit_inf = 0;
579625
unsigned int tx_buffer_free_space = 0;
580626
volatile unsigned int xmit_stat = 0;
@@ -602,7 +648,6 @@ int smsc9220_send_by_chunks(unsigned int total_packet_length, int is_new_packet,
602648
is_last_segment = 1;
603649
}
604650

605-
pktptr = (unsigned int *) data;
606651
txcmd_a = 0;
607652
txcmd_b = 0;
608653

@@ -616,11 +661,16 @@ int smsc9220_send_by_chunks(unsigned int total_packet_length, int is_new_packet,
616661
SMSC9220->TX_DATA_PORT = txcmd_b;
617662
dwords_to_write = (current_size + 3) >> 2;
618663

619-
/* PIO Copy to FIFO. Could replace this with DMA. */
620-
while(dwords_to_write > 0) {
621-
SMSC9220->TX_DATA_PORT = *pktptr;
622-
pktptr++;
623-
dwords_to_write--;
664+
/*
665+
* Copy to TX FIFO
666+
* The function to use depends on the alignment of the data pointer on a 32
667+
* bits boundary.
668+
*/
669+
if (((unsigned int)data % sizeof(uint32_t)) == 0) {
670+
/* Cast is safe because we know data is aligned */
671+
fill_tx_fifo_aligned((unsigned int *)data, dwords_to_write);
672+
} else {
673+
fill_tx_fifo_unaligned((uint8_t *)data, dwords_to_write);
624674
}
625675

626676
if (is_last_segment) {

0 commit comments

Comments
 (0)