aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/mv643xx_eth.c174
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 *********************************************************/
1449static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) 1449static 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
1465static void init_mac_tables(struct mv643xx_eth_private *mp) 1462static 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
1478static void set_filter_table_entry(struct mv643xx_eth_private *mp, 1469static 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
1489static 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
1505static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) 1490static 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
1518static int addr_crc(unsigned char *addr) 1529static 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
1536static void mv643xx_eth_set_rx_mode(struct net_device *dev) 1547static 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
1560oom:
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
1602static 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
1608static 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;