diff options
-rw-r--r-- | drivers/net/arm/am79c961a.c | 77 |
1 files changed, 40 insertions, 37 deletions
diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index 084b67fbe7aa..79d88a0b00a3 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c | |||
@@ -196,6 +196,42 @@ am79c961_ramtest(struct net_device *dev, unsigned int val) | |||
196 | return errorcount; | 196 | return errorcount; |
197 | } | 197 | } |
198 | 198 | ||
199 | static void am79c961_mc_hash(char *addr, u16 *hash) | ||
200 | { | ||
201 | if (addr[0] & 0x01) { | ||
202 | int idx, bit; | ||
203 | u32 crc; | ||
204 | |||
205 | crc = ether_crc_le(ETH_ALEN, addr); | ||
206 | |||
207 | idx = crc >> 30; | ||
208 | bit = (crc >> 26) & 15; | ||
209 | |||
210 | hash[idx] |= 1 << bit; | ||
211 | } | ||
212 | } | ||
213 | |||
214 | static unsigned int am79c961_get_rx_mode(struct net_device *dev, u16 *hash) | ||
215 | { | ||
216 | unsigned int mode = MODE_PORT_10BT; | ||
217 | |||
218 | if (dev->flags & IFF_PROMISC) { | ||
219 | mode |= MODE_PROMISC; | ||
220 | memset(hash, 0xff, 4 * sizeof(*hash)); | ||
221 | } else if (dev->flags & IFF_ALLMULTI) { | ||
222 | memset(hash, 0xff, 4 * sizeof(*hash)); | ||
223 | } else { | ||
224 | struct netdev_hw_addr *ha; | ||
225 | |||
226 | memset(hash, 0, 4 * sizeof(*hash)); | ||
227 | |||
228 | netdev_for_each_mc_addr(ha, dev) | ||
229 | am79c961_mc_hash(ha->addr, hash); | ||
230 | } | ||
231 | |||
232 | return mode; | ||
233 | } | ||
234 | |||
199 | static void | 235 | static void |
200 | am79c961_init_for_open(struct net_device *dev) | 236 | am79c961_init_for_open(struct net_device *dev) |
201 | { | 237 | { |
@@ -203,6 +239,7 @@ am79c961_init_for_open(struct net_device *dev) | |||
203 | unsigned long flags; | 239 | unsigned long flags; |
204 | unsigned char *p; | 240 | unsigned char *p; |
205 | u_int hdr_addr, first_free_addr; | 241 | u_int hdr_addr, first_free_addr; |
242 | u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash); | ||
206 | int i; | 243 | int i; |
207 | 244 | ||
208 | /* | 245 | /* |
@@ -218,16 +255,12 @@ am79c961_init_for_open(struct net_device *dev) | |||
218 | write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */ | 255 | write_ireg (dev->base_addr, 2, 0x0000); /* MODE register selects media */ |
219 | 256 | ||
220 | for (i = LADRL; i <= LADRH; i++) | 257 | for (i = LADRL; i <= LADRH; i++) |
221 | write_rreg (dev->base_addr, i, 0); | 258 | write_rreg (dev->base_addr, i, multi_hash[i - LADRL]); |
222 | 259 | ||
223 | for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) | 260 | for (i = PADRL, p = dev->dev_addr; i <= PADRH; i++, p += 2) |
224 | write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); | 261 | write_rreg (dev->base_addr, i, p[0] | (p[1] << 8)); |
225 | 262 | ||
226 | i = MODE_PORT_10BT; | 263 | write_rreg (dev->base_addr, MODE, mode); |
227 | if (dev->flags & IFF_PROMISC) | ||
228 | i |= MODE_PROMISC; | ||
229 | |||
230 | write_rreg (dev->base_addr, MODE, i); | ||
231 | write_rreg (dev->base_addr, POLLINT, 0); | 264 | write_rreg (dev->base_addr, POLLINT, 0); |
232 | write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); | 265 | write_rreg (dev->base_addr, SIZERXR, -RX_BUFFERS); |
233 | write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); | 266 | write_rreg (dev->base_addr, SIZETXR, -TX_BUFFERS); |
@@ -340,21 +373,6 @@ am79c961_close(struct net_device *dev) | |||
340 | return 0; | 373 | return 0; |
341 | } | 374 | } |
342 | 375 | ||
343 | static void am79c961_mc_hash(char *addr, unsigned short *hash) | ||
344 | { | ||
345 | if (addr[0] & 0x01) { | ||
346 | int idx, bit; | ||
347 | u32 crc; | ||
348 | |||
349 | crc = ether_crc_le(ETH_ALEN, addr); | ||
350 | |||
351 | idx = crc >> 30; | ||
352 | bit = (crc >> 26) & 15; | ||
353 | |||
354 | hash[idx] |= 1 << bit; | ||
355 | } | ||
356 | } | ||
357 | |||
358 | /* | 376 | /* |
359 | * Set or clear promiscuous/multicast mode filter for this adapter. | 377 | * Set or clear promiscuous/multicast mode filter for this adapter. |
360 | */ | 378 | */ |
@@ -362,24 +380,9 @@ static void am79c961_setmulticastlist (struct net_device *dev) | |||
362 | { | 380 | { |
363 | struct dev_priv *priv = netdev_priv(dev); | 381 | struct dev_priv *priv = netdev_priv(dev); |
364 | unsigned long flags; | 382 | unsigned long flags; |
365 | unsigned short multi_hash[4], mode; | 383 | u16 multi_hash[4], mode = am79c961_get_rx_mode(dev, multi_hash); |
366 | int i, stopped; | 384 | int i, stopped; |
367 | 385 | ||
368 | mode = MODE_PORT_10BT; | ||
369 | |||
370 | if (dev->flags & IFF_PROMISC) { | ||
371 | mode |= MODE_PROMISC; | ||
372 | } else if (dev->flags & IFF_ALLMULTI) { | ||
373 | memset(multi_hash, 0xff, sizeof(multi_hash)); | ||
374 | } else { | ||
375 | struct netdev_hw_addr *ha; | ||
376 | |||
377 | memset(multi_hash, 0x00, sizeof(multi_hash)); | ||
378 | |||
379 | netdev_for_each_mc_addr(ha, dev) | ||
380 | am79c961_mc_hash(ha->addr, multi_hash); | ||
381 | } | ||
382 | |||
383 | spin_lock_irqsave(&priv->chip_lock, flags); | 386 | spin_lock_irqsave(&priv->chip_lock, flags); |
384 | 387 | ||
385 | stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP; | 388 | stopped = read_rreg(dev->base_addr, CSR0) & CSR0_STOP; |