28
28
#include " platform/mbed_power_mgmt.h"
29
29
#include " platform/mbed_error.h"
30
30
#include " CacheAlignedBuffer.h"
31
+ #include " MbedCRC.h"
31
32
32
33
#include " stm32xx_emac_config.h"
33
34
#include " stm32xx_emac.h"
@@ -294,6 +295,12 @@ bool STM32_EMAC::low_level_init_successful()
294
295
/* HAL_ETH_Init returns TIMEOUT when Ethernet cable is not plugged */ ;
295
296
}
296
297
298
+ // Set MAC address
299
+ writeMACAddress (MACAddr, &EthHandle.Instance ->MACA0HR , &EthHandle.Instance ->MACA0LR );
300
+
301
+ // Enable multicast hash and perfect filter
302
+ EthHandle.Instance ->MACFFR = ETH_MACFFR_HM | ETH_MACFFR_HPF;
303
+
297
304
uint32_t TempRegisterValue;
298
305
if (HAL_ETH_ReadPHYRegister (&EthHandle, 2 , &TempRegisterValue) != HAL_OK) {
299
306
tr_error (" HAL_ETH_ReadPHYRegister 2 issue" );
@@ -364,6 +371,12 @@ bool STM32_EMAC::low_level_init_successful()
364
371
return false ;
365
372
}
366
373
374
+ // Set MAC address
375
+ writeMACAddress (MACAddr, &EthHandle.Instance ->MACA0HR , &EthHandle.Instance ->MACA0LR );
376
+
377
+ // Enable multicast hash and perfect filter
378
+ EthHandle.Instance ->MACPFR = ETH_MACPFR_HMC | ETH_MACPFR_HPF;
379
+
367
380
memset (&TxConfig, 0 , sizeof (ETH_TxPacketConfig));
368
381
TxConfig.Attributes = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
369
382
TxConfig.ChecksumCtrl = ETH_CHECKSUM_IPHDR_PAYLOAD_INSERT_PHDR_CALC;
@@ -934,17 +947,68 @@ void STM32_EMAC::set_link_state_cb(emac_link_state_change_cb_t state_cb)
934
947
935
948
void STM32_EMAC::add_multicast_group (const uint8_t *addr)
936
949
{
937
- /* No-op at this stage */
950
+ if (numSubscribedMcastMacs >= MBED_CONF_STM32_EMAC_MAX_MCAST_SUBSCRIBES)
951
+ {
952
+ tr_error (" Out of multicast group entries (currently have %d). Increase the 'stm32-emac.max-mcast-subscribes' JSON option!" , MBED_CONF_STM32_EMAC_MAX_MCAST_SUBSCRIBES);
953
+ return ;
954
+ }
955
+
956
+ memcpy (mcastMacs[numSubscribedMcastMacs++].data (), addr, 6 );
957
+ populateMcastFilterRegs ();
938
958
}
939
959
940
960
void STM32_EMAC::remove_multicast_group (const uint8_t *addr)
941
961
{
942
- /* No-op at this stage */
962
+ // Find MAC address in the subscription list
963
+ auto macsEndIter = std::begin (mcastMacs) + numSubscribedMcastMacs;
964
+ auto toRemoveIter = std::find_if (std::begin (mcastMacs), macsEndIter, [&](auto element) {
965
+ return memcmp (element.data (), addr, 6 ) == 0 ;
966
+ });
967
+
968
+ if (toRemoveIter == macsEndIter)
969
+ {
970
+ tr_warning (" Tried to remove mcast group that was not added" );
971
+ return ;
972
+ }
973
+
974
+ // Swap the MAC addr to be removed to the end of the list, if it is not there already
975
+ auto lastElementIter = macsEndIter - 1 ;
976
+ if (toRemoveIter != std::begin (mcastMacs) && toRemoveIter != lastElementIter)
977
+ {
978
+ std::swap (*toRemoveIter, *lastElementIter);
979
+ }
980
+
981
+ // 'remove' the last element by changing the length
982
+ numSubscribedMcastMacs--;
983
+
984
+ // Rebuild the MAC registers with that MAC removed.
985
+ // Technically it would be more performance efficient to remove just this MAC address, but that gets complex
986
+ // once you throw the hash filter into the mix. Unless you are subscribed to insane numbers of mcast addrs,
987
+ // it's easier to just rebuild it all.
988
+ populateMcastFilterRegs ();
943
989
}
944
990
945
991
void STM32_EMAC::set_all_multicast (bool all)
946
992
{
947
- /* No-op at this stage */
993
+ #if defined(ETH_IP_VERSION_V2)
994
+ if (all)
995
+ {
996
+ EthHandle.Instance ->MACPFR |= ETH_MACPFR_PM;
997
+ }
998
+ else
999
+ {
1000
+ EthHandle.Instance ->MACPFR &= ~ETH_MACPFR_PM;
1001
+ }
1002
+ #else
1003
+ if (all)
1004
+ {
1005
+ EthHandle.Instance ->MACFFR |= ETH_MACFFR_PM;
1006
+ }
1007
+ else
1008
+ {
1009
+ EthHandle.Instance ->MACFFR &= ~ETH_MACFFR_PM;
1010
+ }
1011
+ #endif
948
1012
}
949
1013
950
1014
void STM32_EMAC::power_down ()
@@ -966,6 +1030,100 @@ STM32_EMAC &STM32_EMAC::get_instance()
966
1030
return emac;
967
1031
}
968
1032
1033
+ void STM32_EMAC::populateMcastFilterRegs () {
1034
+ const size_t NUM_PERFECT_FILTER_REGS = 3 ;
1035
+
1036
+ const size_t numPerfectFilterMacs = std::min (NUM_PERFECT_FILTER_REGS, numSubscribedMcastMacs);
1037
+ const size_t numHashFilterMacs = numSubscribedMcastMacs - numPerfectFilterMacs;
1038
+
1039
+ for (size_t perfFiltIdx = 0 ; perfFiltIdx < NUM_PERFECT_FILTER_REGS; ++perfFiltIdx)
1040
+ {
1041
+ // Find MAC addr registers (they aren't in an array :/)
1042
+ uint32_t volatile * highReg;
1043
+ uint32_t volatile * lowReg;
1044
+
1045
+ if (perfFiltIdx == 0 )
1046
+ {
1047
+ highReg = &EthHandle.Instance ->MACA1HR ;
1048
+ lowReg = &EthHandle.Instance ->MACA1LR ;
1049
+ }
1050
+ else if (perfFiltIdx == 1 )
1051
+ {
1052
+ highReg = &EthHandle.Instance ->MACA2HR ;
1053
+ lowReg = &EthHandle.Instance ->MACA2LR ;
1054
+ }
1055
+ else
1056
+ {
1057
+ highReg = &EthHandle.Instance ->MACA3HR ;
1058
+ lowReg = &EthHandle.Instance ->MACA3LR ;
1059
+ }
1060
+
1061
+ if (perfFiltIdx < numPerfectFilterMacs)
1062
+ {
1063
+ tr_debug (" Using perfect filtering for %02" PRIx8 " :%02" PRIx8 " :%02" PRIx8 " :%02" PRIx8 " :%02" PRIx8 " :%02" PRIx8,
1064
+ mcastMacs[perfFiltIdx][0 ], mcastMacs[perfFiltIdx][1 ], mcastMacs[perfFiltIdx][2 ],
1065
+ mcastMacs[perfFiltIdx][3 ], mcastMacs[perfFiltIdx][4 ], mcastMacs[perfFiltIdx][5 ]);
1066
+ writeMACAddress (mcastMacs[perfFiltIdx].data (), highReg, lowReg);
1067
+ }
1068
+ else
1069
+ {
1070
+ // Write zeroes to disable this mac addr entry
1071
+ *highReg = 0 ;
1072
+ *lowReg = 0 ;
1073
+ }
1074
+ }
1075
+
1076
+ #if defined(ETH_IP_VERSION_V2)
1077
+ uint32_t volatile * hashRegs[] = {
1078
+ &EthHandle.Instance ->MACHT1R ,
1079
+ &EthHandle.Instance ->MACHT0R
1080
+ };
1081
+ #else
1082
+ uint32_t volatile * hashRegs[] = {
1083
+ &EthHandle.Instance ->MACHTHR ,
1084
+ &EthHandle.Instance ->MACHTLR
1085
+ };
1086
+ #endif
1087
+
1088
+ // Reset hash filter regs
1089
+ *hashRegs[0 ] = 0 ;
1090
+ *hashRegs[1 ] = 0 ;
1091
+
1092
+ // Note: as always, the datasheet description of how to do this CRC was vague and slightly wrong.
1093
+ // This forum thread figured it out: https://community.st.com/t5/stm32-mcus-security/calculating-ethernet-multicast-filter-hash-value/td-p/416984
1094
+ // What the datasheet SHOULD say is:
1095
+ // Compute the Ethernet CRC-32 of the MAC address, with initial value of 1s, final XOR of ones, and input reflection on but output reflection off
1096
+ // Then, take the upper 6 bits and use that to index the hash table.
1097
+
1098
+ mbed::MbedCRC<POLY_32BIT_ANSI> crcCalc (0xFFFFFFFF , 0xFFFFFFFF , true , false );
1099
+ for (size_t hashFiltIdx = 0 ; hashFiltIdx < numHashFilterMacs; ++hashFiltIdx)
1100
+ {
1101
+ auto & currMacAddr = mcastMacs[hashFiltIdx + numPerfectFilterMacs];
1102
+
1103
+ tr_debug (" Using hash filtering for %02" PRIx8 " :%02" PRIx8 " :%02" PRIx8 " :%02" PRIx8 " :%02" PRIx8 " :%02" PRIx8,
1104
+ currMacAddr[0 ], currMacAddr[1 ], currMacAddr[2 ],
1105
+ currMacAddr[3 ], currMacAddr[4 ], currMacAddr[5 ]);
1106
+
1107
+ // Compute Ethernet CRC-32 of the MAC address
1108
+ uint32_t crc;
1109
+ crcCalc.compute (currMacAddr.data (), currMacAddr.size (), &crc);
1110
+
1111
+ // Take upper 6 bits
1112
+ uint32_t hashVal = crc >> 26 ;
1113
+
1114
+ // Set correct bit in hash filter
1115
+ *hashRegs[hashVal >> 5 ] |= (1 << (hashVal & 0x1F ));
1116
+ }
1117
+ }
1118
+
1119
+ void STM32_EMAC::writeMACAddress (const uint8_t *MAC, volatile uint32_t *addrHighReg, volatile uint32_t *addrLowReg) {
1120
+ /* Set MAC addr bits 32 to 47 */
1121
+ *addrHighReg = (static_cast <uint32_t >(MAC[5 ]) << 8 ) | static_cast <uint32_t >(MAC[4 ]) | ETH_MACA1HR_AE_Msk;
1122
+ /* Set MAC addr bits 0 to 31 */
1123
+ *addrLowReg = (static_cast <uint32_t >(MAC[3 ]) << 24 ) | (static_cast <uint32_t >(MAC[2 ]) << 16 ) |
1124
+ (static_cast <uint32_t >(MAC[1 ]) << 8 ) | static_cast <uint32_t >(MAC[0 ]);
1125
+ }
1126
+
969
1127
// Weak so a module can override
970
1128
MBED_WEAK EMAC &EMAC::get_default_instance ()
971
1129
{
0 commit comments