diff options
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/mv643xx_eth.c | 174 |
1 files changed, 104 insertions, 70 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index 3326587d8ce3..9f3ee7d6a5bc 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -1448,11 +1448,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = { | |||
1448 | /* address handling *********************************************************/ | 1448 | /* address handling *********************************************************/ |
1449 | static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) | 1449 | static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) |
1450 | { | 1450 | { |
1451 | unsigned int mac_h; | 1451 | unsigned int mac_h = rdlp(mp, MAC_ADDR_HIGH); |
1452 | unsigned int mac_l; | 1452 | unsigned int mac_l = rdlp(mp, MAC_ADDR_LOW); |
1453 | |||
1454 | mac_h = rdlp(mp, MAC_ADDR_HIGH); | ||
1455 | mac_l = rdlp(mp, MAC_ADDR_LOW); | ||
1456 | 1453 | ||
1457 | addr[0] = (mac_h >> 24) & 0xff; | 1454 | addr[0] = (mac_h >> 24) & 0xff; |
1458 | addr[1] = (mac_h >> 16) & 0xff; | 1455 | addr[1] = (mac_h >> 16) & 0xff; |
@@ -1462,57 +1459,71 @@ static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) | |||
1462 | addr[5] = mac_l & 0xff; | 1459 | addr[5] = mac_l & 0xff; |
1463 | } | 1460 | } |
1464 | 1461 | ||
1465 | static void init_mac_tables(struct mv643xx_eth_private *mp) | 1462 | static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) |
1466 | { | 1463 | { |
1467 | int i; | 1464 | wrlp(mp, MAC_ADDR_HIGH, |
1468 | 1465 | (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]); | |
1469 | for (i = 0; i < 0x100; i += 4) { | 1466 | wrlp(mp, MAC_ADDR_LOW, (addr[4] << 8) | addr[5]); |
1470 | wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0); | ||
1471 | wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0); | ||
1472 | } | ||
1473 | |||
1474 | for (i = 0; i < 0x10; i += 4) | ||
1475 | wrl(mp, UNICAST_TABLE(mp->port_num) + i, 0); | ||
1476 | } | 1467 | } |
1477 | 1468 | ||
1478 | static void set_filter_table_entry(struct mv643xx_eth_private *mp, | 1469 | static u32 uc_addr_filter_mask(struct net_device *dev) |
1479 | int table, unsigned char entry) | ||
1480 | { | 1470 | { |
1481 | unsigned int table_reg; | 1471 | struct dev_addr_list *uc_ptr; |
1482 | 1472 | u32 nibbles; | |
1483 | /* Set "accepts frame bit" at specified table entry */ | ||
1484 | table_reg = rdl(mp, table + (entry & 0xfc)); | ||
1485 | table_reg |= 0x01 << (8 * (entry & 3)); | ||
1486 | wrl(mp, table + (entry & 0xfc), table_reg); | ||
1487 | } | ||
1488 | 1473 | ||
1489 | static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) | 1474 | if (dev->flags & IFF_PROMISC) |
1490 | { | 1475 | return 0; |
1491 | unsigned int mac_h; | ||
1492 | unsigned int mac_l; | ||
1493 | int table; | ||
1494 | 1476 | ||
1495 | mac_l = (addr[4] << 8) | addr[5]; | 1477 | nibbles = 1 << (dev->dev_addr[5] & 0x0f); |
1496 | mac_h = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; | 1478 | for (uc_ptr = dev->uc_list; uc_ptr != NULL; uc_ptr = uc_ptr->next) { |
1479 | if (memcmp(dev->dev_addr, uc_ptr->da_addr, 5)) | ||
1480 | return 0; | ||
1481 | if ((dev->dev_addr[5] ^ uc_ptr->da_addr[5]) & 0xf0) | ||
1482 | return 0; | ||
1497 | 1483 | ||
1498 | wrlp(mp, MAC_ADDR_LOW, mac_l); | 1484 | nibbles |= 1 << (uc_ptr->da_addr[5] & 0x0f); |
1499 | wrlp(mp, MAC_ADDR_HIGH, mac_h); | 1485 | } |
1500 | 1486 | ||
1501 | table = UNICAST_TABLE(mp->port_num); | 1487 | return nibbles; |
1502 | set_filter_table_entry(mp, table, addr[5] & 0x0f); | ||
1503 | } | 1488 | } |
1504 | 1489 | ||
1505 | static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) | 1490 | static void mv643xx_eth_program_unicast_filter(struct net_device *dev) |
1506 | { | 1491 | { |
1507 | struct mv643xx_eth_private *mp = netdev_priv(dev); | 1492 | struct mv643xx_eth_private *mp = netdev_priv(dev); |
1493 | u32 port_config; | ||
1494 | u32 nibbles; | ||
1495 | int i; | ||
1508 | 1496 | ||
1509 | /* +2 is for the offset of the HW addr type */ | ||
1510 | memcpy(dev->dev_addr, addr + 2, 6); | ||
1511 | |||
1512 | init_mac_tables(mp); | ||
1513 | uc_addr_set(mp, dev->dev_addr); | 1497 | uc_addr_set(mp, dev->dev_addr); |
1514 | 1498 | ||
1515 | return 0; | 1499 | port_config = rdlp(mp, PORT_CONFIG); |
1500 | nibbles = uc_addr_filter_mask(dev); | ||
1501 | if (!nibbles) { | ||
1502 | port_config |= UNICAST_PROMISCUOUS_MODE; | ||
1503 | wrlp(mp, PORT_CONFIG, port_config); | ||
1504 | return; | ||
1505 | } | ||
1506 | |||
1507 | for (i = 0; i < 16; i += 4) { | ||
1508 | int off = UNICAST_TABLE(mp->port_num) + i; | ||
1509 | u32 v; | ||
1510 | |||
1511 | v = 0; | ||
1512 | if (nibbles & 1) | ||
1513 | v |= 0x00000001; | ||
1514 | if (nibbles & 2) | ||
1515 | v |= 0x00000100; | ||
1516 | if (nibbles & 4) | ||
1517 | v |= 0x00010000; | ||
1518 | if (nibbles & 8) | ||
1519 | v |= 0x01000000; | ||
1520 | nibbles >>= 4; | ||
1521 | |||
1522 | wrl(mp, off, v); | ||
1523 | } | ||
1524 | |||
1525 | port_config &= ~UNICAST_PROMISCUOUS_MODE; | ||
1526 | wrlp(mp, PORT_CONFIG, port_config); | ||
1516 | } | 1527 | } |
1517 | 1528 | ||
1518 | static int addr_crc(unsigned char *addr) | 1529 | static int addr_crc(unsigned char *addr) |
@@ -1533,24 +1544,22 @@ static int addr_crc(unsigned char *addr) | |||
1533 | return crc; | 1544 | return crc; |
1534 | } | 1545 | } |
1535 | 1546 | ||
1536 | static void mv643xx_eth_set_rx_mode(struct net_device *dev) | 1547 | static void mv643xx_eth_program_multicast_filter(struct net_device *dev) |
1537 | { | 1548 | { |
1538 | struct mv643xx_eth_private *mp = netdev_priv(dev); | 1549 | struct mv643xx_eth_private *mp = netdev_priv(dev); |
1539 | u32 port_config; | 1550 | u32 *mc_spec; |
1551 | u32 *mc_other; | ||
1540 | struct dev_addr_list *addr; | 1552 | struct dev_addr_list *addr; |
1541 | int i; | 1553 | int i; |
1542 | 1554 | ||
1543 | port_config = rdlp(mp, PORT_CONFIG); | ||
1544 | if (dev->flags & IFF_PROMISC) | ||
1545 | port_config |= UNICAST_PROMISCUOUS_MODE; | ||
1546 | else | ||
1547 | port_config &= ~UNICAST_PROMISCUOUS_MODE; | ||
1548 | wrlp(mp, PORT_CONFIG, port_config); | ||
1549 | |||
1550 | if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { | 1555 | if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { |
1551 | int port_num = mp->port_num; | 1556 | int port_num; |
1552 | u32 accept = 0x01010101; | 1557 | u32 accept; |
1558 | int i; | ||
1553 | 1559 | ||
1560 | oom: | ||
1561 | port_num = mp->port_num; | ||
1562 | accept = 0x01010101; | ||
1554 | for (i = 0; i < 0x100; i += 4) { | 1563 | for (i = 0; i < 0x100; i += 4) { |
1555 | wrl(mp, SPECIAL_MCAST_TABLE(port_num) + i, accept); | 1564 | wrl(mp, SPECIAL_MCAST_TABLE(port_num) + i, accept); |
1556 | wrl(mp, OTHER_MCAST_TABLE(port_num) + i, accept); | 1565 | wrl(mp, OTHER_MCAST_TABLE(port_num) + i, accept); |
@@ -1558,28 +1567,55 @@ static void mv643xx_eth_set_rx_mode(struct net_device *dev) | |||
1558 | return; | 1567 | return; |
1559 | } | 1568 | } |
1560 | 1569 | ||
1561 | for (i = 0; i < 0x100; i += 4) { | 1570 | mc_spec = kmalloc(0x200, GFP_KERNEL); |
1562 | wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0); | 1571 | if (mc_spec == NULL) |
1563 | wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0); | 1572 | goto oom; |
1564 | } | 1573 | mc_other = mc_spec + (0x100 >> 2); |
1574 | |||
1575 | memset(mc_spec, 0, 0x100); | ||
1576 | memset(mc_other, 0, 0x100); | ||
1565 | 1577 | ||
1566 | for (addr = dev->mc_list; addr != NULL; addr = addr->next) { | 1578 | for (addr = dev->mc_list; addr != NULL; addr = addr->next) { |
1567 | u8 *a = addr->da_addr; | 1579 | u8 *a = addr->da_addr; |
1568 | int table; | 1580 | u32 *table; |
1569 | 1581 | int entry; | |
1570 | if (addr->da_addrlen != 6) | ||
1571 | continue; | ||
1572 | 1582 | ||
1573 | if (memcmp(a, "\x01\x00\x5e\x00\x00", 5) == 0) { | 1583 | if (memcmp(a, "\x01\x00\x5e\x00\x00", 5) == 0) { |
1574 | table = SPECIAL_MCAST_TABLE(mp->port_num); | 1584 | table = mc_spec; |
1575 | set_filter_table_entry(mp, table, a[5]); | 1585 | entry = a[5]; |
1576 | } else { | 1586 | } else { |
1577 | int crc = addr_crc(a); | 1587 | table = mc_other; |
1578 | 1588 | entry = addr_crc(a); | |
1579 | table = OTHER_MCAST_TABLE(mp->port_num); | ||
1580 | set_filter_table_entry(mp, table, crc); | ||
1581 | } | 1589 | } |
1590 | |||
1591 | table[entry >> 2] |= 1 << (entry & 3); | ||
1582 | } | 1592 | } |
1593 | |||
1594 | for (i = 0; i < 0x100; i += 4) { | ||
1595 | wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, mc_spec[i >> 2]); | ||
1596 | wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, mc_other[i >> 2]); | ||
1597 | } | ||
1598 | |||
1599 | kfree(mc_spec); | ||
1600 | } | ||
1601 | |||
1602 | static void mv643xx_eth_set_rx_mode(struct net_device *dev) | ||
1603 | { | ||
1604 | mv643xx_eth_program_unicast_filter(dev); | ||
1605 | mv643xx_eth_program_multicast_filter(dev); | ||
1606 | } | ||
1607 | |||
1608 | static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) | ||
1609 | { | ||
1610 | struct sockaddr *sa = addr; | ||
1611 | |||
1612 | memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); | ||
1613 | |||
1614 | netif_addr_lock_bh(dev); | ||
1615 | mv643xx_eth_program_unicast_filter(dev); | ||
1616 | netif_addr_unlock_bh(dev); | ||
1617 | |||
1618 | return 0; | ||
1583 | } | 1619 | } |
1584 | 1620 | ||
1585 | 1621 | ||
@@ -1988,7 +2024,7 @@ static void port_start(struct mv643xx_eth_private *mp) | |||
1988 | /* | 2024 | /* |
1989 | * Add configured unicast address to address filter table. | 2025 | * Add configured unicast address to address filter table. |
1990 | */ | 2026 | */ |
1991 | uc_addr_set(mp, mp->dev->dev_addr); | 2027 | mv643xx_eth_program_unicast_filter(mp->dev); |
1992 | 2028 | ||
1993 | /* | 2029 | /* |
1994 | * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast | 2030 | * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast |
@@ -2084,8 +2120,6 @@ static int mv643xx_eth_open(struct net_device *dev) | |||
2084 | return -EAGAIN; | 2120 | return -EAGAIN; |
2085 | } | 2121 | } |
2086 | 2122 | ||
2087 | init_mac_tables(mp); | ||
2088 | |||
2089 | mv643xx_eth_recalc_skb_size(mp); | 2123 | mv643xx_eth_recalc_skb_size(mp); |
2090 | 2124 | ||
2091 | napi_enable(&mp->napi); | 2125 | napi_enable(&mp->napi); |
@@ -2667,7 +2701,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) | |||
2667 | dev->hard_start_xmit = mv643xx_eth_xmit; | 2701 | dev->hard_start_xmit = mv643xx_eth_xmit; |
2668 | dev->open = mv643xx_eth_open; | 2702 | dev->open = mv643xx_eth_open; |
2669 | dev->stop = mv643xx_eth_stop; | 2703 | dev->stop = mv643xx_eth_stop; |
2670 | dev->set_multicast_list = mv643xx_eth_set_rx_mode; | 2704 | dev->set_rx_mode = mv643xx_eth_set_rx_mode; |
2671 | dev->set_mac_address = mv643xx_eth_set_mac_address; | 2705 | dev->set_mac_address = mv643xx_eth_set_mac_address; |
2672 | dev->do_ioctl = mv643xx_eth_ioctl; | 2706 | dev->do_ioctl = mv643xx_eth_ioctl; |
2673 | dev->change_mtu = mv643xx_eth_change_mtu; | 2707 | dev->change_mtu = mv643xx_eth_change_mtu; |