diff options
Diffstat (limited to 'drivers/net/b44.c')
| -rw-r--r-- | drivers/net/b44.c | 277 |
1 files changed, 240 insertions, 37 deletions
diff --git a/drivers/net/b44.c b/drivers/net/b44.c index d8233e0b7899..a7e4ba5a580f 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c | |||
| @@ -29,8 +29,8 @@ | |||
| 29 | 29 | ||
| 30 | #define DRV_MODULE_NAME "b44" | 30 | #define DRV_MODULE_NAME "b44" |
| 31 | #define PFX DRV_MODULE_NAME ": " | 31 | #define PFX DRV_MODULE_NAME ": " |
| 32 | #define DRV_MODULE_VERSION "1.00" | 32 | #define DRV_MODULE_VERSION "1.01" |
| 33 | #define DRV_MODULE_RELDATE "Apr 7, 2006" | 33 | #define DRV_MODULE_RELDATE "Jun 16, 2006" |
| 34 | 34 | ||
| 35 | #define B44_DEF_MSG_ENABLE \ | 35 | #define B44_DEF_MSG_ENABLE \ |
| 36 | (NETIF_MSG_DRV | \ | 36 | (NETIF_MSG_DRV | \ |
| @@ -75,6 +75,15 @@ | |||
| 75 | /* minimum number of free TX descriptors required to wake up TX process */ | 75 | /* minimum number of free TX descriptors required to wake up TX process */ |
| 76 | #define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4) | 76 | #define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4) |
| 77 | 77 | ||
| 78 | /* b44 internal pattern match filter info */ | ||
| 79 | #define B44_PATTERN_BASE 0x400 | ||
| 80 | #define B44_PATTERN_SIZE 0x80 | ||
| 81 | #define B44_PMASK_BASE 0x600 | ||
| 82 | #define B44_PMASK_SIZE 0x10 | ||
| 83 | #define B44_MAX_PATTERNS 16 | ||
| 84 | #define B44_ETHIPV6UDP_HLEN 62 | ||
| 85 | #define B44_ETHIPV4UDP_HLEN 42 | ||
| 86 | |||
| 78 | static char version[] __devinitdata = | 87 | static char version[] __devinitdata = |
| 79 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; | 88 | DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; |
| 80 | 89 | ||
| @@ -101,7 +110,7 @@ MODULE_DEVICE_TABLE(pci, b44_pci_tbl); | |||
| 101 | 110 | ||
| 102 | static void b44_halt(struct b44 *); | 111 | static void b44_halt(struct b44 *); |
| 103 | static void b44_init_rings(struct b44 *); | 112 | static void b44_init_rings(struct b44 *); |
| 104 | static void b44_init_hw(struct b44 *); | 113 | static void b44_init_hw(struct b44 *, int); |
| 105 | 114 | ||
| 106 | static int dma_desc_align_mask; | 115 | static int dma_desc_align_mask; |
| 107 | static int dma_desc_sync_size; | 116 | static int dma_desc_sync_size; |
| @@ -873,7 +882,7 @@ static int b44_poll(struct net_device *netdev, int *budget) | |||
| 873 | spin_lock_irq(&bp->lock); | 882 | spin_lock_irq(&bp->lock); |
| 874 | b44_halt(bp); | 883 | b44_halt(bp); |
| 875 | b44_init_rings(bp); | 884 | b44_init_rings(bp); |
| 876 | b44_init_hw(bp); | 885 | b44_init_hw(bp, 1); |
| 877 | netif_wake_queue(bp->dev); | 886 | netif_wake_queue(bp->dev); |
| 878 | spin_unlock_irq(&bp->lock); | 887 | spin_unlock_irq(&bp->lock); |
| 879 | done = 1; | 888 | done = 1; |
| @@ -942,7 +951,7 @@ static void b44_tx_timeout(struct net_device *dev) | |||
| 942 | 951 | ||
| 943 | b44_halt(bp); | 952 | b44_halt(bp); |
| 944 | b44_init_rings(bp); | 953 | b44_init_rings(bp); |
| 945 | b44_init_hw(bp); | 954 | b44_init_hw(bp, 1); |
| 946 | 955 | ||
| 947 | spin_unlock_irq(&bp->lock); | 956 | spin_unlock_irq(&bp->lock); |
| 948 | 957 | ||
| @@ -1059,7 +1068,7 @@ static int b44_change_mtu(struct net_device *dev, int new_mtu) | |||
| 1059 | b44_halt(bp); | 1068 | b44_halt(bp); |
| 1060 | dev->mtu = new_mtu; | 1069 | dev->mtu = new_mtu; |
| 1061 | b44_init_rings(bp); | 1070 | b44_init_rings(bp); |
| 1062 | b44_init_hw(bp); | 1071 | b44_init_hw(bp, 1); |
| 1063 | spin_unlock_irq(&bp->lock); | 1072 | spin_unlock_irq(&bp->lock); |
| 1064 | 1073 | ||
| 1065 | b44_enable_ints(bp); | 1074 | b44_enable_ints(bp); |
| @@ -1356,13 +1365,15 @@ static int b44_set_mac_addr(struct net_device *dev, void *p) | |||
| 1356 | * packet processing. Invoked with bp->lock held. | 1365 | * packet processing. Invoked with bp->lock held. |
| 1357 | */ | 1366 | */ |
| 1358 | static void __b44_set_rx_mode(struct net_device *); | 1367 | static void __b44_set_rx_mode(struct net_device *); |
| 1359 | static void b44_init_hw(struct b44 *bp) | 1368 | static void b44_init_hw(struct b44 *bp, int full_reset) |
| 1360 | { | 1369 | { |
| 1361 | u32 val; | 1370 | u32 val; |
| 1362 | 1371 | ||
| 1363 | b44_chip_reset(bp); | 1372 | b44_chip_reset(bp); |
| 1364 | b44_phy_reset(bp); | 1373 | if (full_reset) { |
| 1365 | b44_setup_phy(bp); | 1374 | b44_phy_reset(bp); |
| 1375 | b44_setup_phy(bp); | ||
| 1376 | } | ||
| 1366 | 1377 | ||
| 1367 | /* Enable CRC32, set proper LED modes and power on PHY */ | 1378 | /* Enable CRC32, set proper LED modes and power on PHY */ |
| 1368 | bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); | 1379 | bw32(bp, B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); |
| @@ -1376,16 +1387,21 @@ static void b44_init_hw(struct b44 *bp) | |||
| 1376 | bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); | 1387 | bw32(bp, B44_TXMAXLEN, bp->dev->mtu + ETH_HLEN + 8 + RX_HEADER_LEN); |
| 1377 | 1388 | ||
| 1378 | bw32(bp, B44_TX_WMARK, 56); /* XXX magic */ | 1389 | bw32(bp, B44_TX_WMARK, 56); /* XXX magic */ |
| 1379 | bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); | 1390 | if (full_reset) { |
| 1380 | bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); | 1391 | bw32(bp, B44_DMATX_CTRL, DMATX_CTRL_ENABLE); |
| 1381 | bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | | 1392 | bw32(bp, B44_DMATX_ADDR, bp->tx_ring_dma + bp->dma_offset); |
| 1382 | (bp->rx_offset << DMARX_CTRL_ROSHIFT))); | 1393 | bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | |
| 1383 | bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); | 1394 | (bp->rx_offset << DMARX_CTRL_ROSHIFT))); |
| 1395 | bw32(bp, B44_DMARX_ADDR, bp->rx_ring_dma + bp->dma_offset); | ||
| 1384 | 1396 | ||
| 1385 | bw32(bp, B44_DMARX_PTR, bp->rx_pending); | 1397 | bw32(bp, B44_DMARX_PTR, bp->rx_pending); |
| 1386 | bp->rx_prod = bp->rx_pending; | 1398 | bp->rx_prod = bp->rx_pending; |
| 1387 | 1399 | ||
| 1388 | bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); | 1400 | bw32(bp, B44_MIB_CTRL, MIB_CTRL_CLR_ON_READ); |
| 1401 | } else { | ||
| 1402 | bw32(bp, B44_DMARX_CTRL, (DMARX_CTRL_ENABLE | | ||
| 1403 | (bp->rx_offset << DMARX_CTRL_ROSHIFT))); | ||
| 1404 | } | ||
| 1389 | 1405 | ||
| 1390 | val = br32(bp, B44_ENET_CTRL); | 1406 | val = br32(bp, B44_ENET_CTRL); |
| 1391 | bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); | 1407 | bw32(bp, B44_ENET_CTRL, (val | ENET_CTRL_ENABLE)); |
| @@ -1401,7 +1417,7 @@ static int b44_open(struct net_device *dev) | |||
| 1401 | goto out; | 1417 | goto out; |
| 1402 | 1418 | ||
| 1403 | b44_init_rings(bp); | 1419 | b44_init_rings(bp); |
| 1404 | b44_init_hw(bp); | 1420 | b44_init_hw(bp, 1); |
| 1405 | 1421 | ||
| 1406 | b44_check_phy(bp); | 1422 | b44_check_phy(bp); |
| 1407 | 1423 | ||
| @@ -1450,6 +1466,140 @@ static void b44_poll_controller(struct net_device *dev) | |||
| 1450 | } | 1466 | } |
| 1451 | #endif | 1467 | #endif |
| 1452 | 1468 | ||
| 1469 | static void bwfilter_table(struct b44 *bp, u8 *pp, u32 bytes, u32 table_offset) | ||
| 1470 | { | ||
| 1471 | u32 i; | ||
| 1472 | u32 *pattern = (u32 *) pp; | ||
| 1473 | |||
| 1474 | for (i = 0; i < bytes; i += sizeof(u32)) { | ||
| 1475 | bw32(bp, B44_FILT_ADDR, table_offset + i); | ||
| 1476 | bw32(bp, B44_FILT_DATA, pattern[i / sizeof(u32)]); | ||
| 1477 | } | ||
| 1478 | } | ||
| 1479 | |||
| 1480 | static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset) | ||
| 1481 | { | ||
| 1482 | int magicsync = 6; | ||
| 1483 | int k, j, len = offset; | ||
| 1484 | int ethaddr_bytes = ETH_ALEN; | ||
| 1485 | |||
| 1486 | memset(ppattern + offset, 0xff, magicsync); | ||
| 1487 | for (j = 0; j < magicsync; j++) | ||
| 1488 | set_bit(len++, (unsigned long *) pmask); | ||
| 1489 | |||
| 1490 | for (j = 0; j < B44_MAX_PATTERNS; j++) { | ||
| 1491 | if ((B44_PATTERN_SIZE - len) >= ETH_ALEN) | ||
| 1492 | ethaddr_bytes = ETH_ALEN; | ||
| 1493 | else | ||
| 1494 | ethaddr_bytes = B44_PATTERN_SIZE - len; | ||
| 1495 | if (ethaddr_bytes <=0) | ||
| 1496 | break; | ||
| 1497 | for (k = 0; k< ethaddr_bytes; k++) { | ||
| 1498 | ppattern[offset + magicsync + | ||
| 1499 | (j * ETH_ALEN) + k] = macaddr[k]; | ||
| 1500 | len++; | ||
| 1501 | set_bit(len, (unsigned long *) pmask); | ||
| 1502 | } | ||
| 1503 | } | ||
| 1504 | return len - 1; | ||
| 1505 | } | ||
| 1506 | |||
| 1507 | /* Setup magic packet patterns in the b44 WOL | ||
| 1508 | * pattern matching filter. | ||
| 1509 | */ | ||
| 1510 | static void b44_setup_pseudo_magicp(struct b44 *bp) | ||
| 1511 | { | ||
| 1512 | |||
| 1513 | u32 val; | ||
| 1514 | int plen0, plen1, plen2; | ||
| 1515 | u8 *pwol_pattern; | ||
| 1516 | u8 pwol_mask[B44_PMASK_SIZE]; | ||
| 1517 | |||
| 1518 | pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL); | ||
| 1519 | if (!pwol_pattern) { | ||
| 1520 | printk(KERN_ERR PFX "Memory not available for WOL\n"); | ||
| 1521 | return; | ||
| 1522 | } | ||
| 1523 | |||
| 1524 | /* Ipv4 magic packet pattern - pattern 0.*/ | ||
| 1525 | memset(pwol_pattern, 0, B44_PATTERN_SIZE); | ||
| 1526 | memset(pwol_mask, 0, B44_PMASK_SIZE); | ||
| 1527 | plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, | ||
| 1528 | B44_ETHIPV4UDP_HLEN); | ||
| 1529 | |||
| 1530 | bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE); | ||
| 1531 | bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE); | ||
| 1532 | |||
| 1533 | /* Raw ethernet II magic packet pattern - pattern 1 */ | ||
| 1534 | memset(pwol_pattern, 0, B44_PATTERN_SIZE); | ||
| 1535 | memset(pwol_mask, 0, B44_PMASK_SIZE); | ||
| 1536 | plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, | ||
| 1537 | ETH_HLEN); | ||
| 1538 | |||
| 1539 | bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, | ||
| 1540 | B44_PATTERN_BASE + B44_PATTERN_SIZE); | ||
| 1541 | bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, | ||
| 1542 | B44_PMASK_BASE + B44_PMASK_SIZE); | ||
| 1543 | |||
| 1544 | /* Ipv6 magic packet pattern - pattern 2 */ | ||
| 1545 | memset(pwol_pattern, 0, B44_PATTERN_SIZE); | ||
| 1546 | memset(pwol_mask, 0, B44_PMASK_SIZE); | ||
| 1547 | plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask, | ||
| 1548 | B44_ETHIPV6UDP_HLEN); | ||
| 1549 | |||
| 1550 | bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, | ||
| 1551 | B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE); | ||
| 1552 | bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, | ||
| 1553 | B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE); | ||
| 1554 | |||
| 1555 | kfree(pwol_pattern); | ||
| 1556 | |||
| 1557 | /* set these pattern's lengths: one less than each real length */ | ||
| 1558 | val = plen0 | (plen1 << 8) | (plen2 << 16) | WKUP_LEN_ENABLE_THREE; | ||
| 1559 | bw32(bp, B44_WKUP_LEN, val); | ||
| 1560 | |||
| 1561 | /* enable wakeup pattern matching */ | ||
| 1562 | val = br32(bp, B44_DEVCTRL); | ||
| 1563 | bw32(bp, B44_DEVCTRL, val | DEVCTRL_PFE); | ||
| 1564 | |||
| 1565 | } | ||
| 1566 | |||
| 1567 | static void b44_setup_wol(struct b44 *bp) | ||
| 1568 | { | ||
| 1569 | u32 val; | ||
| 1570 | u16 pmval; | ||
| 1571 | |||
| 1572 | bw32(bp, B44_RXCONFIG, RXCONFIG_ALLMULTI); | ||
| 1573 | |||
| 1574 | if (bp->flags & B44_FLAG_B0_ANDLATER) { | ||
| 1575 | |||
| 1576 | bw32(bp, B44_WKUP_LEN, WKUP_LEN_DISABLE); | ||
| 1577 | |||
| 1578 | val = bp->dev->dev_addr[2] << 24 | | ||
| 1579 | bp->dev->dev_addr[3] << 16 | | ||
| 1580 | bp->dev->dev_addr[4] << 8 | | ||
| 1581 | bp->dev->dev_addr[5]; | ||
| 1582 | bw32(bp, B44_ADDR_LO, val); | ||
| 1583 | |||
| 1584 | val = bp->dev->dev_addr[0] << 8 | | ||
| 1585 | bp->dev->dev_addr[1]; | ||
| 1586 | bw32(bp, B44_ADDR_HI, val); | ||
| 1587 | |||
| 1588 | val = br32(bp, B44_DEVCTRL); | ||
| 1589 | bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE); | ||
| 1590 | |||
| 1591 | } else { | ||
| 1592 | b44_setup_pseudo_magicp(bp); | ||
| 1593 | } | ||
| 1594 | |||
| 1595 | val = br32(bp, B44_SBTMSLOW); | ||
| 1596 | bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE); | ||
| 1597 | |||
| 1598 | pci_read_config_word(bp->pdev, SSB_PMCSR, &pmval); | ||
| 1599 | pci_write_config_word(bp->pdev, SSB_PMCSR, pmval | SSB_PE); | ||
| 1600 | |||
| 1601 | } | ||
| 1602 | |||
| 1453 | static int b44_close(struct net_device *dev) | 1603 | static int b44_close(struct net_device *dev) |
| 1454 | { | 1604 | { |
| 1455 | struct b44 *bp = netdev_priv(dev); | 1605 | struct b44 *bp = netdev_priv(dev); |
| @@ -1475,6 +1625,11 @@ static int b44_close(struct net_device *dev) | |||
| 1475 | 1625 | ||
| 1476 | netif_poll_enable(dev); | 1626 | netif_poll_enable(dev); |
| 1477 | 1627 | ||
| 1628 | if (bp->flags & B44_FLAG_WOL_ENABLE) { | ||
| 1629 | b44_init_hw(bp, 0); | ||
| 1630 | b44_setup_wol(bp); | ||
| 1631 | } | ||
| 1632 | |||
| 1478 | b44_free_consistent(bp); | 1633 | b44_free_consistent(bp); |
| 1479 | 1634 | ||
| 1480 | return 0; | 1635 | return 0; |
| @@ -1620,8 +1775,6 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
| 1620 | { | 1775 | { |
| 1621 | struct b44 *bp = netdev_priv(dev); | 1776 | struct b44 *bp = netdev_priv(dev); |
| 1622 | 1777 | ||
| 1623 | if (!netif_running(dev)) | ||
| 1624 | return -EAGAIN; | ||
| 1625 | cmd->supported = (SUPPORTED_Autoneg); | 1778 | cmd->supported = (SUPPORTED_Autoneg); |
| 1626 | cmd->supported |= (SUPPORTED_100baseT_Half | | 1779 | cmd->supported |= (SUPPORTED_100baseT_Half | |
| 1627 | SUPPORTED_100baseT_Full | | 1780 | SUPPORTED_100baseT_Full | |
| @@ -1649,6 +1802,12 @@ static int b44_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
| 1649 | XCVR_INTERNAL : XCVR_EXTERNAL; | 1802 | XCVR_INTERNAL : XCVR_EXTERNAL; |
| 1650 | cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ? | 1803 | cmd->autoneg = (bp->flags & B44_FLAG_FORCE_LINK) ? |
| 1651 | AUTONEG_DISABLE : AUTONEG_ENABLE; | 1804 | AUTONEG_DISABLE : AUTONEG_ENABLE; |
| 1805 | if (cmd->autoneg == AUTONEG_ENABLE) | ||
| 1806 | cmd->advertising |= ADVERTISED_Autoneg; | ||
| 1807 | if (!netif_running(dev)){ | ||
| 1808 | cmd->speed = 0; | ||
| 1809 | cmd->duplex = 0xff; | ||
| 1810 | } | ||
| 1652 | cmd->maxtxpkt = 0; | 1811 | cmd->maxtxpkt = 0; |
| 1653 | cmd->maxrxpkt = 0; | 1812 | cmd->maxrxpkt = 0; |
| 1654 | return 0; | 1813 | return 0; |
| @@ -1658,9 +1817,6 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
| 1658 | { | 1817 | { |
| 1659 | struct b44 *bp = netdev_priv(dev); | 1818 | struct b44 *bp = netdev_priv(dev); |
| 1660 | 1819 | ||
| 1661 | if (!netif_running(dev)) | ||
| 1662 | return -EAGAIN; | ||
| 1663 | |||
| 1664 | /* We do not support gigabit. */ | 1820 | /* We do not support gigabit. */ |
| 1665 | if (cmd->autoneg == AUTONEG_ENABLE) { | 1821 | if (cmd->autoneg == AUTONEG_ENABLE) { |
| 1666 | if (cmd->advertising & | 1822 | if (cmd->advertising & |
| @@ -1677,28 +1833,39 @@ static int b44_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | |||
| 1677 | spin_lock_irq(&bp->lock); | 1833 | spin_lock_irq(&bp->lock); |
| 1678 | 1834 | ||
| 1679 | if (cmd->autoneg == AUTONEG_ENABLE) { | 1835 | if (cmd->autoneg == AUTONEG_ENABLE) { |
| 1680 | bp->flags &= ~B44_FLAG_FORCE_LINK; | 1836 | bp->flags &= ~(B44_FLAG_FORCE_LINK | |
| 1681 | bp->flags &= ~(B44_FLAG_ADV_10HALF | | 1837 | B44_FLAG_100_BASE_T | |
| 1838 | B44_FLAG_FULL_DUPLEX | | ||
| 1839 | B44_FLAG_ADV_10HALF | | ||
| 1682 | B44_FLAG_ADV_10FULL | | 1840 | B44_FLAG_ADV_10FULL | |
| 1683 | B44_FLAG_ADV_100HALF | | 1841 | B44_FLAG_ADV_100HALF | |
| 1684 | B44_FLAG_ADV_100FULL); | 1842 | B44_FLAG_ADV_100FULL); |
| 1685 | if (cmd->advertising & ADVERTISE_10HALF) | 1843 | if (cmd->advertising == 0) { |
| 1686 | bp->flags |= B44_FLAG_ADV_10HALF; | 1844 | bp->flags |= (B44_FLAG_ADV_10HALF | |
| 1687 | if (cmd->advertising & ADVERTISE_10FULL) | 1845 | B44_FLAG_ADV_10FULL | |
| 1688 | bp->flags |= B44_FLAG_ADV_10FULL; | 1846 | B44_FLAG_ADV_100HALF | |
| 1689 | if (cmd->advertising & ADVERTISE_100HALF) | 1847 | B44_FLAG_ADV_100FULL); |
| 1690 | bp->flags |= B44_FLAG_ADV_100HALF; | 1848 | } else { |
| 1691 | if (cmd->advertising & ADVERTISE_100FULL) | 1849 | if (cmd->advertising & ADVERTISED_10baseT_Half) |
| 1692 | bp->flags |= B44_FLAG_ADV_100FULL; | 1850 | bp->flags |= B44_FLAG_ADV_10HALF; |
| 1851 | if (cmd->advertising & ADVERTISED_10baseT_Full) | ||
| 1852 | bp->flags |= B44_FLAG_ADV_10FULL; | ||
| 1853 | if (cmd->advertising & ADVERTISED_100baseT_Half) | ||
| 1854 | bp->flags |= B44_FLAG_ADV_100HALF; | ||
| 1855 | if (cmd->advertising & ADVERTISED_100baseT_Full) | ||
| 1856 | bp->flags |= B44_FLAG_ADV_100FULL; | ||
| 1857 | } | ||
| 1693 | } else { | 1858 | } else { |
| 1694 | bp->flags |= B44_FLAG_FORCE_LINK; | 1859 | bp->flags |= B44_FLAG_FORCE_LINK; |
| 1860 | bp->flags &= ~(B44_FLAG_100_BASE_T | B44_FLAG_FULL_DUPLEX); | ||
| 1695 | if (cmd->speed == SPEED_100) | 1861 | if (cmd->speed == SPEED_100) |
| 1696 | bp->flags |= B44_FLAG_100_BASE_T; | 1862 | bp->flags |= B44_FLAG_100_BASE_T; |
| 1697 | if (cmd->duplex == DUPLEX_FULL) | 1863 | if (cmd->duplex == DUPLEX_FULL) |
| 1698 | bp->flags |= B44_FLAG_FULL_DUPLEX; | 1864 | bp->flags |= B44_FLAG_FULL_DUPLEX; |
| 1699 | } | 1865 | } |
| 1700 | 1866 | ||
| 1701 | b44_setup_phy(bp); | 1867 | if (netif_running(dev)) |
| 1868 | b44_setup_phy(bp); | ||
| 1702 | 1869 | ||
| 1703 | spin_unlock_irq(&bp->lock); | 1870 | spin_unlock_irq(&bp->lock); |
| 1704 | 1871 | ||
| @@ -1734,7 +1901,7 @@ static int b44_set_ringparam(struct net_device *dev, | |||
| 1734 | 1901 | ||
| 1735 | b44_halt(bp); | 1902 | b44_halt(bp); |
| 1736 | b44_init_rings(bp); | 1903 | b44_init_rings(bp); |
| 1737 | b44_init_hw(bp); | 1904 | b44_init_hw(bp, 1); |
| 1738 | netif_wake_queue(bp->dev); | 1905 | netif_wake_queue(bp->dev); |
| 1739 | spin_unlock_irq(&bp->lock); | 1906 | spin_unlock_irq(&bp->lock); |
| 1740 | 1907 | ||
| @@ -1777,7 +1944,7 @@ static int b44_set_pauseparam(struct net_device *dev, | |||
| 1777 | if (bp->flags & B44_FLAG_PAUSE_AUTO) { | 1944 | if (bp->flags & B44_FLAG_PAUSE_AUTO) { |
| 1778 | b44_halt(bp); | 1945 | b44_halt(bp); |
| 1779 | b44_init_rings(bp); | 1946 | b44_init_rings(bp); |
| 1780 | b44_init_hw(bp); | 1947 | b44_init_hw(bp, 1); |
| 1781 | } else { | 1948 | } else { |
| 1782 | __b44_set_flow_ctrl(bp, bp->flags); | 1949 | __b44_set_flow_ctrl(bp, bp->flags); |
| 1783 | } | 1950 | } |
| @@ -1819,12 +1986,40 @@ static void b44_get_ethtool_stats(struct net_device *dev, | |||
| 1819 | spin_unlock_irq(&bp->lock); | 1986 | spin_unlock_irq(&bp->lock); |
| 1820 | } | 1987 | } |
| 1821 | 1988 | ||
| 1989 | static void b44_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
| 1990 | { | ||
| 1991 | struct b44 *bp = netdev_priv(dev); | ||
| 1992 | |||
| 1993 | wol->supported = WAKE_MAGIC; | ||
| 1994 | if (bp->flags & B44_FLAG_WOL_ENABLE) | ||
| 1995 | wol->wolopts = WAKE_MAGIC; | ||
| 1996 | else | ||
| 1997 | wol->wolopts = 0; | ||
| 1998 | memset(&wol->sopass, 0, sizeof(wol->sopass)); | ||
| 1999 | } | ||
| 2000 | |||
| 2001 | static int b44_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) | ||
| 2002 | { | ||
| 2003 | struct b44 *bp = netdev_priv(dev); | ||
| 2004 | |||
| 2005 | spin_lock_irq(&bp->lock); | ||
| 2006 | if (wol->wolopts & WAKE_MAGIC) | ||
| 2007 | bp->flags |= B44_FLAG_WOL_ENABLE; | ||
| 2008 | else | ||
| 2009 | bp->flags &= ~B44_FLAG_WOL_ENABLE; | ||
| 2010 | spin_unlock_irq(&bp->lock); | ||
| 2011 | |||
| 2012 | return 0; | ||
| 2013 | } | ||
| 2014 | |||
| 1822 | static struct ethtool_ops b44_ethtool_ops = { | 2015 | static struct ethtool_ops b44_ethtool_ops = { |
| 1823 | .get_drvinfo = b44_get_drvinfo, | 2016 | .get_drvinfo = b44_get_drvinfo, |
| 1824 | .get_settings = b44_get_settings, | 2017 | .get_settings = b44_get_settings, |
| 1825 | .set_settings = b44_set_settings, | 2018 | .set_settings = b44_set_settings, |
| 1826 | .nway_reset = b44_nway_reset, | 2019 | .nway_reset = b44_nway_reset, |
| 1827 | .get_link = ethtool_op_get_link, | 2020 | .get_link = ethtool_op_get_link, |
| 2021 | .get_wol = b44_get_wol, | ||
| 2022 | .set_wol = b44_set_wol, | ||
| 1828 | .get_ringparam = b44_get_ringparam, | 2023 | .get_ringparam = b44_get_ringparam, |
| 1829 | .set_ringparam = b44_set_ringparam, | 2024 | .set_ringparam = b44_set_ringparam, |
| 1830 | .get_pauseparam = b44_get_pauseparam, | 2025 | .get_pauseparam = b44_get_pauseparam, |
| @@ -1903,6 +2098,10 @@ static int __devinit b44_get_invariants(struct b44 *bp) | |||
| 1903 | /* XXX - really required? | 2098 | /* XXX - really required? |
| 1904 | bp->flags |= B44_FLAG_BUGGY_TXPTR; | 2099 | bp->flags |= B44_FLAG_BUGGY_TXPTR; |
| 1905 | */ | 2100 | */ |
| 2101 | |||
| 2102 | if (ssb_get_core_rev(bp) >= 7) | ||
| 2103 | bp->flags |= B44_FLAG_B0_ANDLATER; | ||
| 2104 | |||
| 1906 | out: | 2105 | out: |
| 1907 | return err; | 2106 | return err; |
| 1908 | } | 2107 | } |
| @@ -2103,6 +2302,10 @@ static int b44_suspend(struct pci_dev *pdev, pm_message_t state) | |||
| 2103 | spin_unlock_irq(&bp->lock); | 2302 | spin_unlock_irq(&bp->lock); |
| 2104 | 2303 | ||
| 2105 | free_irq(dev->irq, dev); | 2304 | free_irq(dev->irq, dev); |
| 2305 | if (bp->flags & B44_FLAG_WOL_ENABLE) { | ||
| 2306 | b44_init_hw(bp, 0); | ||
| 2307 | b44_setup_wol(bp); | ||
| 2308 | } | ||
| 2106 | pci_disable_device(pdev); | 2309 | pci_disable_device(pdev); |
| 2107 | return 0; | 2310 | return 0; |
| 2108 | } | 2311 | } |
| @@ -2125,7 +2328,7 @@ static int b44_resume(struct pci_dev *pdev) | |||
| 2125 | spin_lock_irq(&bp->lock); | 2328 | spin_lock_irq(&bp->lock); |
| 2126 | 2329 | ||
| 2127 | b44_init_rings(bp); | 2330 | b44_init_rings(bp); |
| 2128 | b44_init_hw(bp); | 2331 | b44_init_hw(bp, 1); |
| 2129 | netif_device_attach(bp->dev); | 2332 | netif_device_attach(bp->dev); |
| 2130 | spin_unlock_irq(&bp->lock); | 2333 | spin_unlock_irq(&bp->lock); |
| 2131 | 2334 | ||
