diff options
Diffstat (limited to 'drivers/net/mv643xx_eth.c')
-rw-r--r-- | drivers/net/mv643xx_eth.c | 351 |
1 files changed, 210 insertions, 141 deletions
diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index bca7257c707a..ff2b613a7436 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c | |||
@@ -101,6 +101,7 @@ static void ethernet_phy_set(unsigned int eth_port_num, int phy_addr); | |||
101 | static int ethernet_phy_detect(unsigned int eth_port_num); | 101 | static int ethernet_phy_detect(unsigned int eth_port_num); |
102 | static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location); | 102 | static int mv643xx_mdio_read(struct net_device *dev, int phy_id, int location); |
103 | static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val); | 103 | static void mv643xx_mdio_write(struct net_device *dev, int phy_id, int location, int val); |
104 | static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd); | ||
104 | static struct ethtool_ops mv643xx_ethtool_ops; | 105 | static struct ethtool_ops mv643xx_ethtool_ops; |
105 | 106 | ||
106 | static char mv643xx_driver_name[] = "mv643xx_eth"; | 107 | static char mv643xx_driver_name[] = "mv643xx_eth"; |
@@ -457,6 +458,56 @@ static int mv643xx_eth_receive_queue(struct net_device *dev) | |||
457 | return received_packets; | 458 | return received_packets; |
458 | } | 459 | } |
459 | 460 | ||
461 | /* Set the mv643xx port configuration register for the speed/duplex mode. */ | ||
462 | static void mv643xx_eth_update_pscr(struct net_device *dev, | ||
463 | struct ethtool_cmd *ecmd) | ||
464 | { | ||
465 | struct mv643xx_private *mp = netdev_priv(dev); | ||
466 | int port_num = mp->port_num; | ||
467 | u32 o_pscr, n_pscr; | ||
468 | unsigned int channels; | ||
469 | |||
470 | o_pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); | ||
471 | n_pscr = o_pscr; | ||
472 | |||
473 | /* clear speed, duplex and rx buffer size fields */ | ||
474 | n_pscr &= ~(MV643XX_ETH_SET_MII_SPEED_TO_100 | | ||
475 | MV643XX_ETH_SET_GMII_SPEED_TO_1000 | | ||
476 | MV643XX_ETH_SET_FULL_DUPLEX_MODE | | ||
477 | MV643XX_ETH_MAX_RX_PACKET_MASK); | ||
478 | |||
479 | if (ecmd->duplex == DUPLEX_FULL) | ||
480 | n_pscr |= MV643XX_ETH_SET_FULL_DUPLEX_MODE; | ||
481 | |||
482 | if (ecmd->speed == SPEED_1000) | ||
483 | n_pscr |= MV643XX_ETH_SET_GMII_SPEED_TO_1000 | | ||
484 | MV643XX_ETH_MAX_RX_PACKET_9700BYTE; | ||
485 | else { | ||
486 | if (ecmd->speed == SPEED_100) | ||
487 | n_pscr |= MV643XX_ETH_SET_MII_SPEED_TO_100; | ||
488 | n_pscr |= MV643XX_ETH_MAX_RX_PACKET_1522BYTE; | ||
489 | } | ||
490 | |||
491 | if (n_pscr != o_pscr) { | ||
492 | if ((o_pscr & MV643XX_ETH_SERIAL_PORT_ENABLE) == 0) | ||
493 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), | ||
494 | n_pscr); | ||
495 | else { | ||
496 | channels = mv643xx_eth_port_disable_tx(port_num); | ||
497 | |||
498 | o_pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; | ||
499 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), | ||
500 | o_pscr); | ||
501 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), | ||
502 | n_pscr); | ||
503 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), | ||
504 | n_pscr); | ||
505 | if (channels) | ||
506 | mv643xx_eth_port_enable_tx(port_num, channels); | ||
507 | } | ||
508 | } | ||
509 | } | ||
510 | |||
460 | /* | 511 | /* |
461 | * mv643xx_eth_int_handler | 512 | * mv643xx_eth_int_handler |
462 | * | 513 | * |
@@ -539,13 +590,19 @@ static irqreturn_t mv643xx_eth_int_handler(int irq, void *dev_id, | |||
539 | } | 590 | } |
540 | /* PHY status changed */ | 591 | /* PHY status changed */ |
541 | if (eth_int_cause_ext & (BIT16 | BIT20)) { | 592 | if (eth_int_cause_ext & (BIT16 | BIT20)) { |
593 | struct ethtool_cmd cmd; | ||
594 | |||
542 | if (mii_link_ok(&mp->mii)) { | 595 | if (mii_link_ok(&mp->mii)) { |
596 | mii_ethtool_gset(&mp->mii, &cmd); | ||
597 | mv643xx_eth_update_pscr(dev, &cmd); | ||
543 | if (!netif_carrier_ok(dev)) { | 598 | if (!netif_carrier_ok(dev)) { |
544 | netif_carrier_on(dev); | 599 | netif_carrier_on(dev); |
545 | netif_wake_queue(dev); | 600 | if (mp->tx_ring_size > mp->tx_desc_count + |
546 | /* Start TX queue */ | 601 | MAX_DESCS_PER_SKB) { |
547 | mv643xx_eth_port_enable_tx(port_num, | 602 | netif_wake_queue(dev); |
548 | mp->port_tx_queue_command); | 603 | /* Start TX queue */ |
604 | mv643xx_eth_port_enable_tx(port_num, mp->port_tx_queue_command); | ||
605 | } | ||
549 | } | 606 | } |
550 | } else if (netif_carrier_ok(dev)) { | 607 | } else if (netif_carrier_ok(dev)) { |
551 | netif_stop_queue(dev); | 608 | netif_stop_queue(dev); |
@@ -729,6 +786,34 @@ static void ether_init_tx_desc_ring(struct mv643xx_private *mp) | |||
729 | mp->port_tx_queue_command = 1; | 786 | mp->port_tx_queue_command = 1; |
730 | } | 787 | } |
731 | 788 | ||
789 | static int mv643xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
790 | { | ||
791 | struct mv643xx_private *mp = netdev_priv(dev); | ||
792 | int err; | ||
793 | |||
794 | spin_lock_irq(&mp->lock); | ||
795 | err = mii_ethtool_sset(&mp->mii, cmd); | ||
796 | spin_unlock_irq(&mp->lock); | ||
797 | |||
798 | return err; | ||
799 | } | ||
800 | |||
801 | static int mv643xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
802 | { | ||
803 | struct mv643xx_private *mp = netdev_priv(dev); | ||
804 | int err; | ||
805 | |||
806 | spin_lock_irq(&mp->lock); | ||
807 | err = mii_ethtool_gset(&mp->mii, cmd); | ||
808 | spin_unlock_irq(&mp->lock); | ||
809 | |||
810 | /* The PHY may support 1000baseT_Half, but the mv643xx does not */ | ||
811 | cmd->supported &= ~SUPPORTED_1000baseT_Half; | ||
812 | cmd->advertising &= ~ADVERTISED_1000baseT_Half; | ||
813 | |||
814 | return err; | ||
815 | } | ||
816 | |||
732 | /* | 817 | /* |
733 | * mv643xx_eth_open | 818 | * mv643xx_eth_open |
734 | * | 819 | * |
@@ -842,6 +927,10 @@ static int mv643xx_eth_open(struct net_device *dev) | |||
842 | 927 | ||
843 | mv643xx_eth_rx_task(dev); /* Fill RX ring with skb's */ | 928 | mv643xx_eth_rx_task(dev); /* Fill RX ring with skb's */ |
844 | 929 | ||
930 | /* Clear any pending ethernet port interrupts */ | ||
931 | mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); | ||
932 | mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); | ||
933 | |||
845 | eth_port_start(dev); | 934 | eth_port_start(dev); |
846 | 935 | ||
847 | /* Interrupt Coalescing */ | 936 | /* Interrupt Coalescing */ |
@@ -854,16 +943,13 @@ static int mv643xx_eth_open(struct net_device *dev) | |||
854 | mp->tx_int_coal = | 943 | mp->tx_int_coal = |
855 | eth_port_set_tx_coal(port_num, 133000000, MV643XX_TX_COAL); | 944 | eth_port_set_tx_coal(port_num, 133000000, MV643XX_TX_COAL); |
856 | 945 | ||
857 | /* Clear any pending ethernet port interrupts */ | ||
858 | mv_write(MV643XX_ETH_INTERRUPT_CAUSE_REG(port_num), 0); | ||
859 | mv_write(MV643XX_ETH_INTERRUPT_CAUSE_EXTEND_REG(port_num), 0); | ||
860 | |||
861 | /* Unmask phy and link status changes interrupts */ | 946 | /* Unmask phy and link status changes interrupts */ |
862 | mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), | 947 | mv_write(MV643XX_ETH_INTERRUPT_EXTEND_MASK_REG(port_num), |
863 | INT_UNMASK_ALL_EXT); | 948 | INT_UNMASK_ALL_EXT); |
864 | 949 | ||
865 | /* Unmask RX buffer and TX end interrupt */ | 950 | /* Unmask RX buffer and TX end interrupt */ |
866 | mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL); | 951 | mv_write(MV643XX_ETH_INTERRUPT_MASK_REG(port_num), INT_UNMASK_ALL); |
952 | |||
867 | return 0; | 953 | return 0; |
868 | 954 | ||
869 | out_free_tx_skb: | 955 | out_free_tx_skb: |
@@ -1318,6 +1404,35 @@ static void mv643xx_netpoll(struct net_device *netdev) | |||
1318 | } | 1404 | } |
1319 | #endif | 1405 | #endif |
1320 | 1406 | ||
1407 | static void mv643xx_init_ethtool_cmd(struct net_device *dev, int phy_address, | ||
1408 | int speed, int duplex, | ||
1409 | struct ethtool_cmd *cmd) | ||
1410 | { | ||
1411 | struct mv643xx_private *mp = netdev_priv(dev); | ||
1412 | |||
1413 | memset(cmd, 0, sizeof(*cmd)); | ||
1414 | |||
1415 | cmd->port = PORT_MII; | ||
1416 | cmd->transceiver = XCVR_INTERNAL; | ||
1417 | cmd->phy_address = phy_address; | ||
1418 | |||
1419 | if (speed == 0) { | ||
1420 | cmd->autoneg = AUTONEG_ENABLE; | ||
1421 | /* mii lib checks, but doesn't use speed on AUTONEG_ENABLE */ | ||
1422 | cmd->speed = SPEED_100; | ||
1423 | cmd->advertising = ADVERTISED_10baseT_Half | | ||
1424 | ADVERTISED_10baseT_Full | | ||
1425 | ADVERTISED_100baseT_Half | | ||
1426 | ADVERTISED_100baseT_Full; | ||
1427 | if (mp->mii.supports_gmii) | ||
1428 | cmd->advertising |= ADVERTISED_1000baseT_Full; | ||
1429 | } else { | ||
1430 | cmd->autoneg = AUTONEG_DISABLE; | ||
1431 | cmd->speed = speed; | ||
1432 | cmd->duplex = duplex; | ||
1433 | } | ||
1434 | } | ||
1435 | |||
1321 | /*/ | 1436 | /*/ |
1322 | * mv643xx_eth_probe | 1437 | * mv643xx_eth_probe |
1323 | * | 1438 | * |
@@ -1338,6 +1453,10 @@ static int mv643xx_eth_probe(struct platform_device *pdev) | |||
1338 | u8 *p; | 1453 | u8 *p; |
1339 | struct resource *res; | 1454 | struct resource *res; |
1340 | int err; | 1455 | int err; |
1456 | struct ethtool_cmd cmd; | ||
1457 | u32 pscr; | ||
1458 | int duplex; | ||
1459 | int speed; | ||
1341 | 1460 | ||
1342 | dev = alloc_etherdev(sizeof(struct mv643xx_private)); | 1461 | dev = alloc_etherdev(sizeof(struct mv643xx_private)); |
1343 | if (!dev) | 1462 | if (!dev) |
@@ -1375,6 +1494,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) | |||
1375 | dev->tx_queue_len = mp->tx_ring_size; | 1494 | dev->tx_queue_len = mp->tx_ring_size; |
1376 | dev->base_addr = 0; | 1495 | dev->base_addr = 0; |
1377 | dev->change_mtu = mv643xx_eth_change_mtu; | 1496 | dev->change_mtu = mv643xx_eth_change_mtu; |
1497 | dev->do_ioctl = mv643xx_eth_do_ioctl; | ||
1378 | SET_ETHTOOL_OPS(dev, &mv643xx_ethtool_ops); | 1498 | SET_ETHTOOL_OPS(dev, &mv643xx_ethtool_ops); |
1379 | 1499 | ||
1380 | #ifdef MV643XX_CHECKSUM_OFFLOAD_TX | 1500 | #ifdef MV643XX_CHECKSUM_OFFLOAD_TX |
@@ -1452,10 +1572,35 @@ static int mv643xx_eth_probe(struct platform_device *pdev) | |||
1452 | pr_debug("MV643xx ethernet port %d: " | 1572 | pr_debug("MV643xx ethernet port %d: " |
1453 | "No PHY detected at addr %d\n", | 1573 | "No PHY detected at addr %d\n", |
1454 | port_num, ethernet_phy_get(port_num)); | 1574 | port_num, ethernet_phy_get(port_num)); |
1455 | return err; | 1575 | goto out; |
1456 | } | 1576 | } |
1457 | 1577 | ||
1578 | pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); | ||
1579 | pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; | ||
1580 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); | ||
1581 | pscr = mp->port_serial_control; | ||
1582 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); | ||
1583 | |||
1584 | if (!(pscr & MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX) && | ||
1585 | !(pscr & MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII)) | ||
1586 | speed = 0; | ||
1587 | else if (pscr & MV643XX_ETH_PORT_STATUS_GMII_1000) | ||
1588 | speed = SPEED_1000; | ||
1589 | else if (pscr & MV643XX_ETH_PORT_STATUS_MII_100) | ||
1590 | speed = SPEED_100; | ||
1591 | else | ||
1592 | speed = SPEED_10; | ||
1593 | |||
1594 | if (pscr & MV643XX_ETH_PORT_STATUS_FULL_DUPLEX) | ||
1595 | duplex = DUPLEX_FULL; | ||
1596 | else | ||
1597 | duplex = DUPLEX_HALF; | ||
1598 | |||
1599 | ethernet_phy_reset(mp->port_num); | ||
1458 | mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii); | 1600 | mp->mii.supports_gmii = mii_check_gmii_support(&mp->mii); |
1601 | mv643xx_init_ethtool_cmd(dev, mp->mii.phy_id, speed, duplex, &cmd); | ||
1602 | mv643xx_eth_update_pscr(dev, &cmd); | ||
1603 | mv643xx_set_settings(dev, &cmd); | ||
1459 | 1604 | ||
1460 | err = register_netdev(dev); | 1605 | err = register_netdev(dev); |
1461 | if (err) | 1606 | if (err) |
@@ -1775,8 +1920,6 @@ static void eth_port_init(struct mv643xx_private *mp) | |||
1775 | eth_port_reset(mp->port_num); | 1920 | eth_port_reset(mp->port_num); |
1776 | 1921 | ||
1777 | eth_port_init_mac_tables(mp->port_num); | 1922 | eth_port_init_mac_tables(mp->port_num); |
1778 | |||
1779 | ethernet_phy_reset(mp->port_num); | ||
1780 | } | 1923 | } |
1781 | 1924 | ||
1782 | /* | 1925 | /* |
@@ -1811,6 +1954,8 @@ static void eth_port_start(struct net_device *dev) | |||
1811 | struct mv643xx_private *mp = netdev_priv(dev); | 1954 | struct mv643xx_private *mp = netdev_priv(dev); |
1812 | unsigned int port_num = mp->port_num; | 1955 | unsigned int port_num = mp->port_num; |
1813 | int tx_curr_desc, rx_curr_desc; | 1956 | int tx_curr_desc, rx_curr_desc; |
1957 | u32 pscr; | ||
1958 | struct ethtool_cmd ethtool_cmd; | ||
1814 | 1959 | ||
1815 | /* Assignment of Tx CTRP of given queue */ | 1960 | /* Assignment of Tx CTRP of given queue */ |
1816 | tx_curr_desc = mp->tx_curr_desc_q; | 1961 | tx_curr_desc = mp->tx_curr_desc_q; |
@@ -1828,31 +1973,35 @@ static void eth_port_start(struct net_device *dev) | |||
1828 | /* Assign port configuration and command. */ | 1973 | /* Assign port configuration and command. */ |
1829 | mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num), mp->port_config); | 1974 | mv_write(MV643XX_ETH_PORT_CONFIG_REG(port_num), mp->port_config); |
1830 | 1975 | ||
1831 | mv_write(MV643XX_ETH_PORT_CONFIG_EXTEND_REG(port_num), | 1976 | pscr = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); |
1832 | mp->port_config_extend); | 1977 | pscr &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; |
1978 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); | ||
1833 | 1979 | ||
1980 | pscr &= ~MV643XX_ETH_FORCE_LINK_PASS; | ||
1981 | pscr |= MV643XX_ETH_DISABLE_AUTO_NEG_FOR_FLOW_CTRL | | ||
1982 | MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII | | ||
1983 | MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX | | ||
1984 | MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL | | ||
1985 | MV643XX_ETH_SERIAL_PORT_CONTROL_RESERVED; | ||
1834 | 1986 | ||
1835 | /* Increase the Rx side buffer size if supporting GigE */ | 1987 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); |
1836 | if (mp->port_serial_control & MV643XX_ETH_SET_GMII_SPEED_TO_1000) | ||
1837 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), | ||
1838 | (mp->port_serial_control & 0xfff1ffff) | (0x5 << 17)); | ||
1839 | else | ||
1840 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), | ||
1841 | mp->port_serial_control); | ||
1842 | 1988 | ||
1843 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), | 1989 | pscr |= MV643XX_ETH_SERIAL_PORT_ENABLE; |
1844 | mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)) | | 1990 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), pscr); |
1845 | MV643XX_ETH_SERIAL_PORT_ENABLE); | ||
1846 | 1991 | ||
1847 | /* Assign port SDMA configuration */ | 1992 | /* Assign port SDMA configuration */ |
1848 | mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num), | 1993 | mv_write(MV643XX_ETH_SDMA_CONFIG_REG(port_num), mp->port_sdma_config); |
1849 | mp->port_sdma_config); | ||
1850 | 1994 | ||
1851 | /* Enable port Rx. */ | 1995 | /* Enable port Rx. */ |
1852 | mv643xx_eth_port_enable_rx(port_num, mp->port_rx_queue_command); | 1996 | mv643xx_eth_port_enable_rx(port_num, mp->port_rx_queue_command); |
1853 | 1997 | ||
1854 | /* Disable port bandwidth limits by clearing MTU register */ | 1998 | /* Disable port bandwidth limits by clearing MTU register */ |
1855 | mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0); | 1999 | mv_write(MV643XX_ETH_MAXIMUM_TRANSMIT_UNIT(port_num), 0); |
2000 | |||
2001 | /* save phy settings across reset */ | ||
2002 | mv643xx_get_settings(dev, ðtool_cmd); | ||
2003 | ethernet_phy_reset(mp->port_num); | ||
2004 | mv643xx_set_settings(dev, ðtool_cmd); | ||
1856 | } | 2005 | } |
1857 | 2006 | ||
1858 | /* | 2007 | /* |
@@ -2324,6 +2473,12 @@ static void ethernet_phy_reset(unsigned int eth_port_num) | |||
2324 | eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data); | 2473 | eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data); |
2325 | phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ | 2474 | phy_reg_data |= 0x8000; /* Set bit 15 to reset the PHY */ |
2326 | eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data); | 2475 | eth_port_write_smi_reg(eth_port_num, 0, phy_reg_data); |
2476 | |||
2477 | /* wait for PHY to come out of reset */ | ||
2478 | do { | ||
2479 | udelay(1); | ||
2480 | eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data); | ||
2481 | } while (phy_reg_data & 0x8000); | ||
2327 | } | 2482 | } |
2328 | 2483 | ||
2329 | static void mv643xx_eth_port_enable_tx(unsigned int port_num, | 2484 | static void mv643xx_eth_port_enable_tx(unsigned int port_num, |
@@ -2417,20 +2572,13 @@ static void eth_port_reset(unsigned int port_num) | |||
2417 | 2572 | ||
2418 | /* Reset the Enable bit in the Configuration Register */ | 2573 | /* Reset the Enable bit in the Configuration Register */ |
2419 | reg_data = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); | 2574 | reg_data = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); |
2420 | reg_data &= ~MV643XX_ETH_SERIAL_PORT_ENABLE; | 2575 | reg_data &= ~(MV643XX_ETH_SERIAL_PORT_ENABLE | |
2576 | MV643XX_ETH_DO_NOT_FORCE_LINK_FAIL | | ||
2577 | MV643XX_ETH_FORCE_LINK_PASS); | ||
2421 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data); | 2578 | mv_write(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num), reg_data); |
2422 | } | 2579 | } |
2423 | 2580 | ||
2424 | 2581 | ||
2425 | static int eth_port_autoneg_supported(unsigned int eth_port_num) | ||
2426 | { | ||
2427 | unsigned int phy_reg_data0; | ||
2428 | |||
2429 | eth_port_read_smi_reg(eth_port_num, 0, &phy_reg_data0); | ||
2430 | |||
2431 | return phy_reg_data0 & 0x1000; | ||
2432 | } | ||
2433 | |||
2434 | /* | 2582 | /* |
2435 | * eth_port_read_smi_reg - Read PHY registers | 2583 | * eth_port_read_smi_reg - Read PHY registers |
2436 | * | 2584 | * |
@@ -2989,111 +3137,6 @@ static const struct mv643xx_stats mv643xx_gstrings_stats[] = { | |||
2989 | #define MV643XX_STATS_LEN \ | 3137 | #define MV643XX_STATS_LEN \ |
2990 | sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats) | 3138 | sizeof(mv643xx_gstrings_stats) / sizeof(struct mv643xx_stats) |
2991 | 3139 | ||
2992 | static int | ||
2993 | mv643xx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) | ||
2994 | { | ||
2995 | struct mv643xx_private *mp = netdev->priv; | ||
2996 | int port_num = mp->port_num; | ||
2997 | int autoneg = eth_port_autoneg_supported(port_num); | ||
2998 | int mode_10_bit; | ||
2999 | int auto_duplex; | ||
3000 | int half_duplex = 0; | ||
3001 | int full_duplex = 0; | ||
3002 | int auto_speed; | ||
3003 | int speed_10 = 0; | ||
3004 | int speed_100 = 0; | ||
3005 | int speed_1000 = 0; | ||
3006 | |||
3007 | u32 pcs = mv_read(MV643XX_ETH_PORT_SERIAL_CONTROL_REG(port_num)); | ||
3008 | u32 psr = mv_read(MV643XX_ETH_PORT_STATUS_REG(port_num)); | ||
3009 | |||
3010 | mode_10_bit = psr & MV643XX_ETH_PORT_STATUS_MODE_10_BIT; | ||
3011 | |||
3012 | if (mode_10_bit) { | ||
3013 | ecmd->supported = SUPPORTED_10baseT_Half; | ||
3014 | } else { | ||
3015 | ecmd->supported = (SUPPORTED_10baseT_Half | | ||
3016 | SUPPORTED_10baseT_Full | | ||
3017 | SUPPORTED_100baseT_Half | | ||
3018 | SUPPORTED_100baseT_Full | | ||
3019 | SUPPORTED_1000baseT_Full | | ||
3020 | (autoneg ? SUPPORTED_Autoneg : 0) | | ||
3021 | SUPPORTED_TP); | ||
3022 | |||
3023 | auto_duplex = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_FOR_DUPLX); | ||
3024 | auto_speed = !(pcs & MV643XX_ETH_DISABLE_AUTO_NEG_SPEED_GMII); | ||
3025 | |||
3026 | ecmd->advertising = ADVERTISED_TP; | ||
3027 | |||
3028 | if (autoneg) { | ||
3029 | ecmd->advertising |= ADVERTISED_Autoneg; | ||
3030 | |||
3031 | if (auto_duplex) { | ||
3032 | half_duplex = 1; | ||
3033 | full_duplex = 1; | ||
3034 | } else { | ||
3035 | if (pcs & MV643XX_ETH_SET_FULL_DUPLEX_MODE) | ||
3036 | full_duplex = 1; | ||
3037 | else | ||
3038 | half_duplex = 1; | ||
3039 | } | ||
3040 | |||
3041 | if (auto_speed) { | ||
3042 | speed_10 = 1; | ||
3043 | speed_100 = 1; | ||
3044 | speed_1000 = 1; | ||
3045 | } else { | ||
3046 | if (pcs & MV643XX_ETH_SET_GMII_SPEED_TO_1000) | ||
3047 | speed_1000 = 1; | ||
3048 | else if (pcs & MV643XX_ETH_SET_MII_SPEED_TO_100) | ||
3049 | speed_100 = 1; | ||
3050 | else | ||
3051 | speed_10 = 1; | ||
3052 | } | ||
3053 | |||
3054 | if (speed_10 & half_duplex) | ||
3055 | ecmd->advertising |= ADVERTISED_10baseT_Half; | ||
3056 | if (speed_10 & full_duplex) | ||
3057 | ecmd->advertising |= ADVERTISED_10baseT_Full; | ||
3058 | if (speed_100 & half_duplex) | ||
3059 | ecmd->advertising |= ADVERTISED_100baseT_Half; | ||
3060 | if (speed_100 & full_duplex) | ||
3061 | ecmd->advertising |= ADVERTISED_100baseT_Full; | ||
3062 | if (speed_1000) | ||
3063 | ecmd->advertising |= ADVERTISED_1000baseT_Full; | ||
3064 | } | ||
3065 | } | ||
3066 | |||
3067 | ecmd->port = PORT_TP; | ||
3068 | ecmd->phy_address = ethernet_phy_get(port_num); | ||
3069 | |||
3070 | ecmd->transceiver = XCVR_EXTERNAL; | ||
3071 | |||
3072 | if (netif_carrier_ok(netdev)) { | ||
3073 | if (mode_10_bit) | ||
3074 | ecmd->speed = SPEED_10; | ||
3075 | else { | ||
3076 | if (psr & MV643XX_ETH_PORT_STATUS_GMII_1000) | ||
3077 | ecmd->speed = SPEED_1000; | ||
3078 | else if (psr & MV643XX_ETH_PORT_STATUS_MII_100) | ||
3079 | ecmd->speed = SPEED_100; | ||
3080 | else | ||
3081 | ecmd->speed = SPEED_10; | ||
3082 | } | ||
3083 | |||
3084 | if (psr & MV643XX_ETH_PORT_STATUS_FULL_DUPLEX) | ||
3085 | ecmd->duplex = DUPLEX_FULL; | ||
3086 | else | ||
3087 | ecmd->duplex = DUPLEX_HALF; | ||
3088 | } else { | ||
3089 | ecmd->speed = -1; | ||
3090 | ecmd->duplex = -1; | ||
3091 | } | ||
3092 | |||
3093 | ecmd->autoneg = autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE; | ||
3094 | return 0; | ||
3095 | } | ||
3096 | |||
3097 | static void mv643xx_get_drvinfo(struct net_device *netdev, | 3140 | static void mv643xx_get_drvinfo(struct net_device *netdev, |
3098 | struct ethtool_drvinfo *drvinfo) | 3141 | struct ethtool_drvinfo *drvinfo) |
3099 | { | 3142 | { |
@@ -3140,15 +3183,41 @@ static void mv643xx_get_strings(struct net_device *netdev, uint32_t stringset, | |||
3140 | } | 3183 | } |
3141 | } | 3184 | } |
3142 | 3185 | ||
3186 | static u32 mv643xx_eth_get_link(struct net_device *dev) | ||
3187 | { | ||
3188 | struct mv643xx_private *mp = netdev_priv(dev); | ||
3189 | |||
3190 | return mii_link_ok(&mp->mii); | ||
3191 | } | ||
3192 | |||
3193 | static int mv643xx_eth_nway_restart(struct net_device *dev) | ||
3194 | { | ||
3195 | struct mv643xx_private *mp = netdev_priv(dev); | ||
3196 | |||
3197 | return mii_nway_restart(&mp->mii); | ||
3198 | } | ||
3199 | |||
3200 | static int mv643xx_eth_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
3201 | { | ||
3202 | struct mv643xx_private *mp = netdev_priv(dev); | ||
3203 | |||
3204 | return generic_mii_ioctl(&mp->mii, if_mii(ifr), cmd, NULL); | ||
3205 | } | ||
3206 | |||
3143 | static struct ethtool_ops mv643xx_ethtool_ops = { | 3207 | static struct ethtool_ops mv643xx_ethtool_ops = { |
3144 | .get_settings = mv643xx_get_settings, | 3208 | .get_settings = mv643xx_get_settings, |
3209 | .set_settings = mv643xx_set_settings, | ||
3145 | .get_drvinfo = mv643xx_get_drvinfo, | 3210 | .get_drvinfo = mv643xx_get_drvinfo, |
3146 | .get_link = ethtool_op_get_link, | 3211 | .get_link = mv643xx_eth_get_link, |
3147 | .get_sg = ethtool_op_get_sg, | 3212 | .get_sg = ethtool_op_get_sg, |
3148 | .set_sg = ethtool_op_set_sg, | 3213 | .set_sg = ethtool_op_set_sg, |
3149 | .get_strings = mv643xx_get_strings, | 3214 | .get_strings = mv643xx_get_strings, |
3150 | .get_stats_count = mv643xx_get_stats_count, | 3215 | .get_stats_count = mv643xx_get_stats_count, |
3151 | .get_ethtool_stats = mv643xx_get_ethtool_stats, | 3216 | .get_ethtool_stats = mv643xx_get_ethtool_stats, |
3217 | .get_strings = mv643xx_get_strings, | ||
3218 | .get_stats_count = mv643xx_get_stats_count, | ||
3219 | .get_ethtool_stats = mv643xx_get_ethtool_stats, | ||
3220 | .nway_reset = mv643xx_eth_nway_restart, | ||
3152 | }; | 3221 | }; |
3153 | 3222 | ||
3154 | /************* End ethtool support *************************/ | 3223 | /************* End ethtool support *************************/ |