diff options
author | Dale Farnsworth <dale@farnsworth.org> | 2006-01-16 18:50:02 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2006-01-17 07:23:37 -0500 |
commit | 16e0301831767ee1b8e5e022cc08e76f9f8a8938 (patch) | |
tree | 3562f2195c66c8486b83b960e20e67b62054e01e /drivers/net | |
parent | 4eaa3cb35b22cccc53846ce2820e244b1fb04f0b (diff) |
[PATCH] mv643xx_eth: Add multicast support
This code is adapted from code in a ppc-specific version of the driver.
Signed-off-by: Dale Farnsworth <dale@farnsworth.org>
mv643xx_eth.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 197 insertions(+), 4 deletions(-)
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/mv643xx_eth.c | 201 |
1 files changed, 197 insertions, 4 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 88a59d9715ac..f100ca7d3ee2 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -80,6 +80,7 @@ | |||
80 | static int eth_port_link_is_up(unsigned int eth_port_num); | 80 | static int eth_port_link_is_up(unsigned int eth_port_num); |
81 | static void eth_port_uc_addr_get(struct net_device *dev, | 81 | static void eth_port_uc_addr_get(struct net_device *dev, |
82 | unsigned char *MacAddr); | 82 | unsigned char *MacAddr); |
83 | static void eth_port_set_multicast_list(struct net_device *); | ||
83 | static int mv643xx_eth_real_open(struct net_device *); | 84 | static int mv643xx_eth_real_open(struct net_device *); |
84 | static int mv643xx_eth_real_stop(struct net_device *); | 85 | static int mv643xx_eth_real_stop(struct net_device *); |
85 | static int mv643xx_eth_change_mtu(struct net_device *, int); | 86 | static int mv643xx_eth_change_mtu(struct net_device *, int); |
@@ -269,6 +270,8 @@ static void mv643xx_eth_set_rx_mode(struct net_device *dev) | |||
269 | mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; | 270 | mp->port_config &= ~(u32) MV643XX_ETH_UNICAST_PROMISCUOUS_MODE; |
270 | 271 | ||
271 | mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config); | 272 | mv_write(MV643XX_ETH_PORT_CONFIG_REG(mp->port_num), mp->port_config); |
273 | |||
274 | eth_port_set_multicast_list(dev); | ||
272 | } | 275 | } |
273 | 276 | ||
274 | /* | 277 | /* |
@@ -2045,6 +2048,196 @@ static int eth_port_uc_addr(unsigned int eth_port_num, unsigned char uc_nibble, | |||
2045 | } | 2048 | } |
2046 | 2049 | ||
2047 | /* | 2050 | /* |
2051 | * The entries in each table are indexed by a hash of a packet's MAC | ||
2052 | * address. One bit in each entry determines whether the packet is | ||
2053 | * accepted. There are 4 entries (each 8 bits wide) in each register | ||
2054 | * of the table. The bits in each entry are defined as follows: | ||
2055 | * 0 Accept=1, Drop=0 | ||
2056 | * 3-1 Queue (ETH_Q0=0) | ||
2057 | * 7-4 Reserved = 0; | ||
2058 | */ | ||
2059 | static void eth_port_set_filter_table_entry(int table, unsigned char entry) | ||
2060 | { | ||
2061 | unsigned int table_reg; | ||
2062 | unsigned int tbl_offset; | ||
2063 | unsigned int reg_offset; | ||
2064 | |||
2065 | tbl_offset = (entry / 4) * 4; /* Register offset of DA table entry */ | ||
2066 | reg_offset = entry % 4; /* Entry offset within the register */ | ||
2067 | |||
2068 | /* Set "accepts frame bit" at specified table entry */ | ||
2069 | table_reg = mv_read(table + tbl_offset); | ||
2070 | table_reg |= 0x01 << (8 * reg_offset); | ||
2071 | mv_write(table + tbl_offset, table_reg); | ||
2072 | } | ||
2073 | |||
2074 | /* | ||
2075 | * eth_port_mc_addr - Multicast address settings. | ||
2076 | * | ||
2077 | * The MV device supports multicast using two tables: | ||
2078 | * 1) Special Multicast Table for MAC addresses of the form | ||
2079 | * 0x01-00-5E-00-00-XX (where XX is between 0x00 and 0x_FF). | ||
2080 | * The MAC DA[7:0] bits are used as a pointer to the Special Multicast | ||
2081 | * Table entries in the DA-Filter table. | ||
2082 | * 2) Other Multicast Table for multicast of another type. A CRC-8bit | ||
2083 | * is used as an index to the Other Multicast Table entries in the | ||
2084 | * DA-Filter table. This function calculates the CRC-8bit value. | ||
2085 | * In either case, eth_port_set_filter_table_entry() is then called | ||
2086 | * to set to set the actual table entry. | ||
2087 | */ | ||
2088 | static void eth_port_mc_addr(unsigned int eth_port_num, unsigned char *p_addr) | ||
2089 | { | ||
2090 | unsigned int mac_h; | ||
2091 | unsigned int mac_l; | ||
2092 | unsigned char crc_result = 0; | ||
2093 | int table; | ||
2094 | int mac_array[48]; | ||
2095 | int crc[8]; | ||
2096 | int i; | ||
2097 | |||
2098 | if ((p_addr[0] == 0x01) && (p_addr[1] == 0x00) && | ||
2099 | (p_addr[2] == 0x5E) && (p_addr[3] == 0x00) && (p_addr[4] == 0x00)) { | ||
2100 | table = MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE | ||
2101 | (eth_port_num); | ||
2102 | eth_port_set_filter_table_entry(table, p_addr[5]); | ||
2103 | return; | ||
2104 | } | ||
2105 | |||
2106 | /* Calculate CRC-8 out of the given address */ | ||
2107 | mac_h = (p_addr[0] << 8) | (p_addr[1]); | ||
2108 | mac_l = (p_addr[2] << 24) | (p_addr[3] << 16) | | ||
2109 | (p_addr[4] << 8) | (p_addr[5] << 0); | ||
2110 | |||
2111 | for (i = 0; i < 32; i++) | ||
2112 | mac_array[i] = (mac_l >> i) & 0x1; | ||
2113 | for (i = 32; i < 48; i++) | ||
2114 | mac_array[i] = (mac_h >> (i - 32)) & 0x1; | ||
2115 | |||
2116 | crc[0] = mac_array[45] ^ mac_array[43] ^ mac_array[40] ^ mac_array[39] ^ | ||
2117 | mac_array[35] ^ mac_array[34] ^ mac_array[31] ^ mac_array[30] ^ | ||
2118 | mac_array[28] ^ mac_array[23] ^ mac_array[21] ^ mac_array[19] ^ | ||
2119 | mac_array[18] ^ mac_array[16] ^ mac_array[14] ^ mac_array[12] ^ | ||
2120 | mac_array[8] ^ mac_array[7] ^ mac_array[6] ^ mac_array[0]; | ||
2121 | |||
2122 | crc[1] = mac_array[46] ^ mac_array[45] ^ mac_array[44] ^ mac_array[43] ^ | ||
2123 | mac_array[41] ^ mac_array[39] ^ mac_array[36] ^ mac_array[34] ^ | ||
2124 | mac_array[32] ^ mac_array[30] ^ mac_array[29] ^ mac_array[28] ^ | ||
2125 | mac_array[24] ^ mac_array[23] ^ mac_array[22] ^ mac_array[21] ^ | ||
2126 | mac_array[20] ^ mac_array[18] ^ mac_array[17] ^ mac_array[16] ^ | ||
2127 | mac_array[15] ^ mac_array[14] ^ mac_array[13] ^ mac_array[12] ^ | ||
2128 | mac_array[9] ^ mac_array[6] ^ mac_array[1] ^ mac_array[0]; | ||
2129 | |||
2130 | crc[2] = mac_array[47] ^ mac_array[46] ^ mac_array[44] ^ mac_array[43] ^ | ||
2131 | mac_array[42] ^ mac_array[39] ^ mac_array[37] ^ mac_array[34] ^ | ||
2132 | mac_array[33] ^ mac_array[29] ^ mac_array[28] ^ mac_array[25] ^ | ||
2133 | mac_array[24] ^ mac_array[22] ^ mac_array[17] ^ mac_array[15] ^ | ||
2134 | mac_array[13] ^ mac_array[12] ^ mac_array[10] ^ mac_array[8] ^ | ||
2135 | mac_array[6] ^ mac_array[2] ^ mac_array[1] ^ mac_array[0]; | ||
2136 | |||
2137 | crc[3] = mac_array[47] ^ mac_array[45] ^ mac_array[44] ^ mac_array[43] ^ | ||
2138 | mac_array[40] ^ mac_array[38] ^ mac_array[35] ^ mac_array[34] ^ | ||
2139 | mac_array[30] ^ mac_array[29] ^ mac_array[26] ^ mac_array[25] ^ | ||
2140 | mac_array[23] ^ mac_array[18] ^ mac_array[16] ^ mac_array[14] ^ | ||
2141 | mac_array[13] ^ mac_array[11] ^ mac_array[9] ^ mac_array[7] ^ | ||
2142 | mac_array[3] ^ mac_array[2] ^ mac_array[1]; | ||
2143 | |||
2144 | crc[4] = mac_array[46] ^ mac_array[45] ^ mac_array[44] ^ mac_array[41] ^ | ||
2145 | mac_array[39] ^ mac_array[36] ^ mac_array[35] ^ mac_array[31] ^ | ||
2146 | mac_array[30] ^ mac_array[27] ^ mac_array[26] ^ mac_array[24] ^ | ||
2147 | mac_array[19] ^ mac_array[17] ^ mac_array[15] ^ mac_array[14] ^ | ||
2148 | mac_array[12] ^ mac_array[10] ^ mac_array[8] ^ mac_array[4] ^ | ||
2149 | mac_array[3] ^ mac_array[2]; | ||
2150 | |||
2151 | crc[5] = mac_array[47] ^ mac_array[46] ^ mac_array[45] ^ mac_array[42] ^ | ||
2152 | mac_array[40] ^ mac_array[37] ^ mac_array[36] ^ mac_array[32] ^ | ||
2153 | mac_array[31] ^ mac_array[28] ^ mac_array[27] ^ mac_array[25] ^ | ||
2154 | mac_array[20] ^ mac_array[18] ^ mac_array[16] ^ mac_array[15] ^ | ||
2155 | mac_array[13] ^ mac_array[11] ^ mac_array[9] ^ mac_array[5] ^ | ||
2156 | mac_array[4] ^ mac_array[3]; | ||
2157 | |||
2158 | crc[6] = mac_array[47] ^ mac_array[46] ^ mac_array[43] ^ mac_array[41] ^ | ||
2159 | mac_array[38] ^ mac_array[37] ^ mac_array[33] ^ mac_array[32] ^ | ||
2160 | mac_array[29] ^ mac_array[28] ^ mac_array[26] ^ mac_array[21] ^ | ||
2161 | mac_array[19] ^ mac_array[17] ^ mac_array[16] ^ mac_array[14] ^ | ||
2162 | mac_array[12] ^ mac_array[10] ^ mac_array[6] ^ mac_array[5] ^ | ||
2163 | mac_array[4]; | ||
2164 | |||
2165 | crc[7] = mac_array[47] ^ mac_array[44] ^ mac_array[42] ^ mac_array[39] ^ | ||
2166 | mac_array[38] ^ mac_array[34] ^ mac_array[33] ^ mac_array[30] ^ | ||
2167 | mac_array[29] ^ mac_array[27] ^ mac_array[22] ^ mac_array[20] ^ | ||
2168 | mac_array[18] ^ mac_array[17] ^ mac_array[15] ^ mac_array[13] ^ | ||
2169 | mac_array[11] ^ mac_array[7] ^ mac_array[6] ^ mac_array[5]; | ||
2170 | |||
2171 | for (i = 0; i < 8; i++) | ||
2172 | crc_result = crc_result | (crc[i] << i); | ||
2173 | |||
2174 | table = MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num); | ||
2175 | eth_port_set_filter_table_entry(table, crc_result); | ||
2176 | } | ||
2177 | |||
2178 | /* | ||
2179 | * Set the entire multicast list based on dev->mc_list. | ||
2180 | */ | ||
2181 | static void eth_port_set_multicast_list(struct net_device *dev) | ||
2182 | { | ||
2183 | |||
2184 | struct dev_mc_list *mc_list; | ||
2185 | int i; | ||
2186 | int table_index; | ||
2187 | struct mv643xx_private *mp = netdev_priv(dev); | ||
2188 | unsigned int eth_port_num = mp->port_num; | ||
2189 | |||
2190 | /* If the device is in promiscuous mode or in all multicast mode, | ||
2191 | * we will fully populate both multicast tables with accept. | ||
2192 | * This is guaranteed to yield a match on all multicast addresses... | ||
2193 | */ | ||
2194 | if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI)) { | ||
2195 | for (table_index = 0; table_index <= 0xFC; table_index += 4) { | ||
2196 | /* Set all entries in DA filter special multicast | ||
2197 | * table (Ex_dFSMT) | ||
2198 | * Set for ETH_Q0 for now | ||
2199 | * Bits | ||
2200 | * 0 Accept=1, Drop=0 | ||
2201 | * 3-1 Queue ETH_Q0=0 | ||
2202 | * 7-4 Reserved = 0; | ||
2203 | */ | ||
2204 | mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101); | ||
2205 | |||
2206 | /* Set all entries in DA filter other multicast | ||
2207 | * table (Ex_dFOMT) | ||
2208 | * Set for ETH_Q0 for now | ||
2209 | * Bits | ||
2210 | * 0 Accept=1, Drop=0 | ||
2211 | * 3-1 Queue ETH_Q0=0 | ||
2212 | * 7-4 Reserved = 0; | ||
2213 | */ | ||
2214 | mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE(eth_port_num) + table_index, 0x01010101); | ||
2215 | } | ||
2216 | return; | ||
2217 | } | ||
2218 | |||
2219 | /* We will clear out multicast tables every time we get the list. | ||
2220 | * Then add the entire new list... | ||
2221 | */ | ||
2222 | for (table_index = 0; table_index <= 0xFC; table_index += 4) { | ||
2223 | /* Clear DA filter special multicast table (Ex_dFSMT) */ | ||
2224 | mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE | ||
2225 | (eth_port_num) + table_index, 0); | ||
2226 | |||
2227 | /* Clear DA filter other multicast table (Ex_dFOMT) */ | ||
2228 | mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE | ||
2229 | (eth_port_num) + table_index, 0); | ||
2230 | } | ||
2231 | |||
2232 | /* Get pointer to net_device multicast list and add each one... */ | ||
2233 | for (i = 0, mc_list = dev->mc_list; | ||
2234 | (i < 256) && (mc_list != NULL) && (i < dev->mc_count); | ||
2235 | i++, mc_list = mc_list->next) | ||
2236 | if (mc_list->dmi_addrlen == 6) | ||
2237 | eth_port_mc_addr(eth_port_num, mc_list->dmi_addr); | ||
2238 | } | ||
2239 | |||
2240 | /* | ||
2048 | * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables | 2241 | * eth_port_init_mac_tables - Clear all entrance in the UC, SMC and OMC tables |
2049 | * | 2242 | * |
2050 | * DESCRIPTION: | 2243 | * DESCRIPTION: |
@@ -2071,11 +2264,11 @@ static void eth_port_init_mac_tables(unsigned int eth_port_num) | |||
2071 | 2264 | ||
2072 | for (table_index = 0; table_index <= 0xFC; table_index += 4) { | 2265 | for (table_index = 0; table_index <= 0xFC; table_index += 4) { |
2073 | /* Clear DA filter special multicast table (Ex_dFSMT) */ | 2266 | /* Clear DA filter special multicast table (Ex_dFSMT) */ |
2074 | mv_write((MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE | 2267 | mv_write(MV643XX_ETH_DA_FILTER_SPECIAL_MULTICAST_TABLE_BASE |
2075 | (eth_port_num) + table_index), 0); | 2268 | (eth_port_num) + table_index, 0); |
2076 | /* Clear DA filter other multicast table (Ex_dFOMT) */ | 2269 | /* Clear DA filter other multicast table (Ex_dFOMT) */ |
2077 | mv_write((MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE | 2270 | mv_write(MV643XX_ETH_DA_FILTER_OTHER_MULTICAST_TABLE_BASE |
2078 | (eth_port_num) + table_index), 0); | 2271 | (eth_port_num) + table_index, 0); |
2079 | } | 2272 | } |
2080 | } | 2273 | } |
2081 | 2274 | ||