aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorDale Farnsworth <dale@farnsworth.org>2006-01-16 18:50:02 -0500
committerJeff Garzik <jgarzik@pobox.com>2006-01-17 07:23:37 -0500
commit16e0301831767ee1b8e5e022cc08e76f9f8a8938 (patch)
tree3562f2195c66c8486b83b960e20e67b62054e01e /drivers/net
parent4eaa3cb35b22cccc53846ce2820e244b1fb04f0b (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.c201
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 @@
80static int eth_port_link_is_up(unsigned int eth_port_num); 80static int eth_port_link_is_up(unsigned int eth_port_num);
81static void eth_port_uc_addr_get(struct net_device *dev, 81static void eth_port_uc_addr_get(struct net_device *dev,
82 unsigned char *MacAddr); 82 unsigned char *MacAddr);
83static void eth_port_set_multicast_list(struct net_device *);
83static int mv643xx_eth_real_open(struct net_device *); 84static int mv643xx_eth_real_open(struct net_device *);
84static int mv643xx_eth_real_stop(struct net_device *); 85static int mv643xx_eth_real_stop(struct net_device *);
85static int mv643xx_eth_change_mtu(struct net_device *, int); 86static 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 */
2059static 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 */
2088static 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 */
2181static 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