diff --git a/arch/arm/src/lpc17xx/lpc17_emacram.h b/arch/arm/src/lpc17xx/lpc17_emacram.h index 16a3b00c15..ec332b4f9c 100644 --- a/arch/arm/src/lpc17xx/lpc17_emacram.h +++ b/arch/arm/src/lpc17xx/lpc17_emacram.h @@ -60,7 +60,7 @@ #endif /* Is networking enabled? Is the LPC17xx Ethernet device enabled? Does this chip have - * and Ethernet controlloer? Yes... then we will replace the above default definitions. + * and Ethernet controller? Yes... then we will replace the above default definitions. */ #if defined(CONFIG_NET) && defined(CONFIG_LPC17_ETHERNET) && LPC17_NETHCONTROLLERS > 0 @@ -124,7 +124,7 @@ /* EMAC DMA RAM and descriptor definitions. The configured number of descriptors * will determine the organization and the size of the descriptor and status tables. * There is a complex interaction between the maximum packet size (CONFIG_NET_ETH_MTU) - * and the number of Rx and Tx descriptors that can be suppored (CONFIG_NET_NRXDESC + * and the number of Rx and Tx descriptors that can be supported (CONFIG_NET_NRXDESC * and CONFIG_NET_NTXDESC): Small buffers -> more packets. This is something that * needs to be tuned for you system. * diff --git a/arch/arm/src/lpc17xx/lpc17_ethernet.c b/arch/arm/src/lpc17xx/lpc17_ethernet.c index fdda0fe4c3..c13dc2473c 100644 --- a/arch/arm/src/lpc17xx/lpc17_ethernet.c +++ b/arch/arm/src/lpc17xx/lpc17_ethernet.c @@ -361,11 +361,17 @@ static void lpc17_txtimeout(int argc, uint32_t arg, ...); /* NuttX callback functions */ +#ifdef CONFIG_NET_ICMPv6 +static void lpc17_ipv6multicast(FAR struct lpc17_ethmac_s *priv); +#endif static int lpc17_ifup(struct net_driver_s *dev); static int lpc17_ifdown(struct net_driver_s *dev); static int lpc17_txavail(struct net_driver_s *dev); -#ifdef CONFIG_NET_IGMP +#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6) +static uint32_t lpc17_calcethcrc(const uint8_t *data, size_t length); static int lpc17_addmac(struct net_driver_s *dev, const uint8_t *mac); +#endif +#ifdef CONFIG_NET_IGMP static int lpc17_rmmac(struct net_driver_s *dev, const uint8_t *mac); #endif @@ -1422,6 +1428,79 @@ static void lpc17_polltimer(int argc, uint32_t arg, ...) (void)wd_start(priv->lp_txpoll, LPC17_WDDELAY, lpc17_polltimer, 1, arg); } +/**************************************************************************** + * Function: lpc17_ipv6multicast + * + * Description: + * Configure the IPv6 multicast MAC address. + * + * Parameters: + * priv - A reference to the private driver state structure + * + * Returned Value: + * OK on success; Negated errno on failure. + * + * Assumptions: + * + ****************************************************************************/ + +#ifdef CONFIG_NET_ICMPv6 +static void lpc17_ipv6multicast(FAR struct lpc17_ethmac_s *priv) +{ + struct net_driver_s *dev; + uint16_t tmp16; + uint8_t mac[6]; + + /* For ICMPv6, we need to add the IPv6 multicast address + * + * For IPv6 multicast addresses, the Ethernet MAC is derived by + * the four low-order octets OR'ed with the MAC 33:33:00:00:00:00, + * so for example the IPv6 address FF02:DEAD:BEEF::1:3 would map + * to the Ethernet MAC address 33:33:00:01:00:03. + * + * NOTES: This appears correct for the ICMPv6 Router Solicitation + * Message, but the ICMPv6 Neighbor Solicitation message seems to + * use 33:33:ff:01:00:03. + */ + + mac[0] = 0x33; + mac[1] = 0x33; + + dev = &priv->dev; + tmp16 = dev->d_ipv6addr[6]; + mac[2] = 0xff; + mac[3] = tmp16 >> 8; + + tmp16 = dev->d_ipv6addr[7]; + mac[4] = tmp16 & 0xff; + mac[5] = tmp16 >> 8; + + nvdbg("IPv6 Multicast: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + (void)lpc17_addmac(dev, mac); + +#ifdef CONFIG_NET_ICMPv6_AUTOCONF + /* Add the IPv6 all link-local nodes Ethernet address. This is the + * address that we expect to receive ICMPv6 Router Advertisement + * packets. + */ + + (void)lpc17_addmac(dev, g_ipv6_ethallnodes.ether_addr_octet); + +#endif /* CONFIG_NET_ICMPv6_AUTOCONF */ +#ifdef CONFIG_NET_ICMPv6_ROUTER + /* Add the IPv6 all link-local routers Ethernet address. This is the + * address that we expect to receive ICMPv6 Router Solicitation + * packets. + */ + + (void)lpc17_addmac(dev, g_ipv6_ethallrouters.ether_addr_octet); + +#endif /* CONFIG_NET_ICMPv6_ROUTER */ +} +#endif /* CONFIG_NET_ICMPv6 */ + /**************************************************************************** * Function: lpc17_ifup * @@ -1476,6 +1555,12 @@ static int lpc17_ifup(struct net_driver_s *dev) (uint32_t)priv->lp_dev.d_mac.ether_addr_octet[0]; lpc17_putreg(regval, LPC17_ETH_SA2); +#ifdef CONFIG_NET_ICMPv6 + /* Set up the IPv6 multicast address */ + + lpc17_ipv6multicast(priv); +#endif + /* Initialize Ethernet interface for the PHY setup */ lpc17_macmode(priv->lp_mode); @@ -1685,6 +1770,99 @@ static int lpc17_txavail(struct net_driver_s *dev) return OK; } +/**************************************************************************** + * Function: lpc17_calcethcrc + * + * Description: + * Function to calculate the CRC used by LPC17 to check an Ethernet frame + * + * Algorithm adapted from LPC17xx sample code that contains this notice: + * + * Software that is described herein is for illustrative purposes only + * which provides customers with programming information regarding the + * products. This software is supplied "AS IS" without any warranties. + * NXP Semiconductors assumes no responsibility or liability for the + * use of the software, conveys no license or title under any patent, + * copyright, or mask work right to the product. NXP Semiconductors + * reserves the right to make changes in the software without + * notification. NXP Semiconductors also make no representation or + * warranty that such application will be suitable for the specified + * use without further testing or modification. + * + * Parameters: + * data - the data to be checked + * length - length of the data + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6) +static uint32_t lpc17_calcethcrc(const uint8_t *data, size_t length) +{ + char byte; + int crc; + int q0; + int q1; + int q2; + int q3; + int i; + int j; + + crc = 0xffffffff; + for (i = 0; i < frame_len; i++) + { + byte = *frame_no_fcs++; + for (j = 0; j < 2; j++) + { + if (((crc >> 28) ^ (byte >> 3)) & 0x00000001) + { + q3 = 0x04c11db7; + } + else + { + q3 = 0x00000000; + } + + if (((crc >> 29) ^ (byte >> 2)) & 0x00000001) + { + q2 = 0x09823b6e; + } + else + { + q2 = 0x00000000; + } + + if (((crc >> 30) ^ (byte >> 1)) & 0x00000001) + { + q1 = 0x130476dc; + } + else + { + q1 = 0x00000000; + } + + if (((crc >> 31) ^ (byte >> 0)) & 0x00000001) + { + q0 = 0x2608EDB8; + } + else + { + q0 = 0x00000000; + } + + crc = (crc << 4) ^ q3 ^ q2 ^ q1 ^ q0; + byte >>= 4; + } + } + + return crc; +} +#endif /* CONFIG_NET_IGMP || CONFIG_NET_ICMPv6 */ + /**************************************************************************** * Function: lpc17_addmac * @@ -1703,17 +1881,62 @@ static int lpc17_txavail(struct net_driver_s *dev) * ****************************************************************************/ -#ifdef CONFIG_NET_IGMP +#if defined(CONFIG_NET_IGMP) || defined(CONFIG_NET_ICMPv6) static int lpc17_addmac(struct net_driver_s *dev, const uint8_t *mac) { - struct lpc17_driver_s *priv = (struct lpc17_driver_s *)dev->d_private; + uintptr_t regaddr; + uint32_t regval; + uint32_t crc; + unsigned int ndx; - /* Add the MAC address to the hardware multicast routing table */ + nllvdbg("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + /* Hash function: + * + * The standard Ethernet cyclic redundancy check (CRC) function is + * calculated from the 6 byte MAC address. Bits [28:23] out of the 32-bit + * CRC result are taken to form the hash. The 6-bit hash is used to access + * the hash table: it is used as an index in the 64-bit HashFilter register + * that has been programmed with accept values. If the selected accept value + * is 1, the frame is accepted. + */ + + crc = lpc17_calcethcrc(mac, 6); + ndx = (crc >> 23) & 0x3f; + + /* Add the MAC address to the hardware multicast hash table */ + + if (ndx > 31) + { + regaddr = LPC17_ETH_HASHFLH; /* Hash filter table MSBs register */ + ndx -= 32; + } + else + { + regaddr = LPC17_ETH_HASHFLL; /* Hash filter table LSBs register */ + } + + regval = lpc17_getreg(regaddr); + regval |= 1 << ndx; + lpc17_putreg(regval, regaddr); + + /* Enabled multicast address filtering in the RxFilterControl register: + * + * AcceptUnicastHashEn: When set to ’1’, unicast frames that pass the + * imperfect hash filter are accepted. + * AcceptMulticastHashEn When set to ’1’, multicast frames that pass the + * imperfect hash filter are accepted. + */ + + regval = lpc17_getreg(LPC17_ETH_RXFLCTRL); + regval &= ~ETH_RXFLCTRL_UCASTHASHEN; + regval |= ETH_RXFLCTRL_MCASTHASHEN; + lpc17_putreg(regval, LPC17_ETH_RXFLCTRL); -#warning "Not implemented" return OK; } -#endif +#endif /* CONFIG_NET_IGMP || CONFIG_NET_ICMPv6 */ /**************************************************************************** * Function: lpc17_rmmac @@ -1736,11 +1959,63 @@ static int lpc17_addmac(struct net_driver_s *dev, const uint8_t *mac) #ifdef CONFIG_NET_IGMP static int lpc17_rmmac(struct net_driver_s *dev, const uint8_t *mac) { - struct lpc17_driver_s *priv = (struct lpc17_driver_s *)dev->d_private; + uintptr_t regaddr1; + uintptr_t regaddr2; + uint32_t regval; + uint32_t crc; + unsigned int ndx; - /* Add the MAC address to the hardware multicast routing table */ + nllvdbg("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + + /* Hash function: + * + * The standard Ethernet cyclic redundancy check (CRC) function is + * calculated from the 6 byte MAC address. Bits [28:23] out of the 32-bit + * CRC result are taken to form the hash. The 6-bit hash is used to access + * the hash table: it is used as an index in the 64-bit HashFilter register + * that has been programmed with accept values. If the selected accept value + * is 1, the frame is accepted. + */ + + crc = lpc17_calcethcrc(mac, 6); + ndx = (crc >> 23) & 0x3f; + + /* Remove the MAC address to the hardware multicast hash table */ + + if (ndx > 31) + { + regaddr1 = LPC17_ETH_HASHFLH; /* Hash filter table MSBs register */ + regaddr2 = LPC17_ETH_HASHFLL; /* Hash filter table LSBs register */ + ndx -= 32; + } + else + { + regaddr1 = LPC17_ETH_HASHFLL; /* Hash filter table LSBs register */ + regaddr2 = LPC17_ETH_HASHFLH; /* Hash filter table MSBs register */ + } + + regval = lpc17_getreg(regaddr1); + regval &= ~(1 << ndx); + lpc17_putreg(regval, regaddr1); + + /* If there are no longer addresses being filtered , disable multicast + * filtering. + */ + + if (regval == 0 && lpc17_getreg(regaddr2) == 0) + { + /* AcceptUnicastHashEn: When set to ’1’, unicast frames that pass the + * imperfect hash filter are accepted. + * AcceptMulticastHashEn When set to ’1’, multicast frames that pass the + * imperfect hash filter are accepted. + */ + + regval = lpc17_getreg(LPC17_ETH_RXFLCTRL); + regval &= ~(ETH_RXFLCTRL_UCASTHASHEN | ETH_RXFLCTRL_MCASTHASHEN); + lpc17_putreg(regval, LPC17_ETH_RXFLCTRL); + } -#warning "Not implemented" return OK; } #endif diff --git a/configs/olimex-lpc1766stk/nettest/setenv.sh b/configs/olimex-lpc1766stk/nettest/setenv.sh index 551e4042dc..1a1fb344b7 100755 --- a/configs/olimex-lpc1766stk/nettest/setenv.sh +++ b/configs/olimex-lpc1766stk/nettest/setenv.sh @@ -50,8 +50,9 @@ fi # This is the Cygwin path to the location where I installed the CodeSourcery # toolchain under windows. You will also have to edit this if you install # the CodeSourcery toolchain in any other location -# export TOOLCHAIN_BIN="/cygdrive/c/Program Files (x86)/CodeSourcery/Sourcery G++ Lite/bin" -# export TOOLCHAIN_BIN="/cygdrive/c/Program Files (x86)/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_EABI/bin" +#export TOOLCHAIN_BIN="/cygdrive/c/Program Files (x86)/CodeSourcery/Sourcery G++ Lite/bin" +#export TOOLCHAIN_BIN="/cygdrive/c/Program Files (x86)/CodeSourcery/Sourcery_CodeBench_Lite_for_ARM_EABI/bin" +#export TOOLCHAIN_BIN="/cygdrive/c/Users/MyName/MentorGraphics/Sourcery_CodeBench_Lite_for_ARM_EABI/bin" # These are the Cygwin paths to the locations where I installed the Atollic # toolchain under windows. You will also have to edit this if you install