2828#include  " platform/mbed_power_mgmt.h" 
2929#include  " platform/mbed_error.h" 
3030#include  " CacheAlignedBuffer.h" 
31+ #include  " MbedCRC.h" 
3132
3233#include  " stm32xx_emac_config.h" 
3334#include  " stm32xx_emac.h" 
@@ -294,6 +295,12 @@ bool STM32_EMAC::low_level_init_successful()
294295        /*  HAL_ETH_Init returns TIMEOUT when Ethernet cable is not plugged */  ;
295296    }
296297
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+ 
297304    uint32_t  TempRegisterValue;
298305    if  (HAL_ETH_ReadPHYRegister (&EthHandle, 2 , &TempRegisterValue) != HAL_OK) {
299306        tr_error (" HAL_ETH_ReadPHYRegister 2 issue"  );
@@ -364,6 +371,12 @@ bool STM32_EMAC::low_level_init_successful()
364371        return  false ;
365372    }
366373
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+ 
367380    memset (&TxConfig, 0 , sizeof (ETH_TxPacketConfig));
368381    TxConfig.Attributes  = ETH_TX_PACKETS_FEATURES_CSUM | ETH_TX_PACKETS_FEATURES_CRCPAD;
369382    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)
934947
935948void  STM32_EMAC::add_multicast_group (const  uint8_t  *addr)
936949{
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 ();
938958}
939959
940960void  STM32_EMAC::remove_multicast_group (const  uint8_t  *addr)
941961{
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 ();
943989}
944990
945991void  STM32_EMAC::set_all_multicast (bool  all)
946992{
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 
9481012}
9491013
9501014void  STM32_EMAC::power_down ()
@@ -966,6 +1030,100 @@ STM32_EMAC &STM32_EMAC::get_instance()
9661030    return  emac;
9671031}
9681032
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+ 
9691127//  Weak so a module can override
9701128MBED_WEAK EMAC &EMAC::get_default_instance ()
9711129{
0 commit comments