diff options
author | Stephen Hemminger <shemminger@osdl.org> | 2005-11-08 13:33:42 -0500 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-11-08 23:58:08 -0500 |
commit | 2cd8e5d36584653c62a6fdf0e7d9fbde5022b5d6 (patch) | |
tree | 6c3298644228adf71d26a34e8f0028d47c38973b /drivers | |
parent | 7e86306113ca9e418e49ff1c7c0984f8ffe8cf61 (diff) |
[PATCH] skge: add mii ioctl support
Basic MII ioctl support for skge driver.
Signed-off-by: Stephen Hemminger <shemminger@osdl.org>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/skge.c | 172 |
1 files changed, 114 insertions, 58 deletions
diff --git a/drivers/net/skge.c b/drivers/net/skge.c index f411c5c80410..a1cfead5827b 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/delay.h> | 37 | #include <linux/delay.h> |
38 | #include <linux/crc32.h> | 38 | #include <linux/crc32.h> |
39 | #include <linux/dma-mapping.h> | 39 | #include <linux/dma-mapping.h> |
40 | #include <linux/mii.h> | ||
40 | #include <asm/irq.h> | 41 | #include <asm/irq.h> |
41 | 42 | ||
42 | #include "skge.h" | 43 | #include "skge.h" |
@@ -88,8 +89,8 @@ MODULE_DEVICE_TABLE(pci, skge_id_table); | |||
88 | static int skge_up(struct net_device *dev); | 89 | static int skge_up(struct net_device *dev); |
89 | static int skge_down(struct net_device *dev); | 90 | static int skge_down(struct net_device *dev); |
90 | static void skge_tx_clean(struct skge_port *skge); | 91 | static void skge_tx_clean(struct skge_port *skge); |
91 | static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); | 92 | static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); |
92 | static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); | 93 | static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val); |
93 | static void genesis_get_stats(struct skge_port *skge, u64 *data); | 94 | static void genesis_get_stats(struct skge_port *skge, u64 *data); |
94 | static void yukon_get_stats(struct skge_port *skge, u64 *data); | 95 | static void yukon_get_stats(struct skge_port *skge, u64 *data); |
95 | static void yukon_init(struct skge_hw *hw, int port); | 96 | static void yukon_init(struct skge_hw *hw, int port); |
@@ -883,32 +884,37 @@ static void skge_link_down(struct skge_port *skge) | |||
883 | printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name); | 884 | printk(KERN_INFO PFX "%s: Link is down.\n", skge->netdev->name); |
884 | } | 885 | } |
885 | 886 | ||
886 | static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg) | 887 | static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) |
887 | { | 888 | { |
888 | int i; | 889 | int i; |
889 | u16 v; | ||
890 | 890 | ||
891 | xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); | 891 | xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr); |
892 | v = xm_read16(hw, port, XM_PHY_DATA); | 892 | xm_read16(hw, port, XM_PHY_DATA); |
893 | 893 | ||
894 | /* Need to wait for external PHY */ | 894 | /* Need to wait for external PHY */ |
895 | for (i = 0; i < PHY_RETRIES; i++) { | 895 | for (i = 0; i < PHY_RETRIES; i++) { |
896 | udelay(1); | 896 | udelay(1); |
897 | if (xm_read16(hw, port, XM_MMU_CMD) | 897 | if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY) |
898 | & XM_MMU_PHY_RDY) | ||
899 | goto ready; | 898 | goto ready; |
900 | } | 899 | } |
901 | 900 | ||
902 | printk(KERN_WARNING PFX "%s: phy read timed out\n", | 901 | return -ETIMEDOUT; |
903 | hw->dev[port]->name); | ||
904 | return 0; | ||
905 | ready: | 902 | ready: |
906 | v = xm_read16(hw, port, XM_PHY_DATA); | 903 | *val = xm_read16(hw, port, XM_PHY_DATA); |
907 | 904 | ||
905 | return 0; | ||
906 | } | ||
907 | |||
908 | static u16 xm_phy_read(struct skge_hw *hw, int port, u16 reg) | ||
909 | { | ||
910 | u16 v = 0; | ||
911 | if (__xm_phy_read(hw, port, reg, &v)) | ||
912 | printk(KERN_WARNING PFX "%s: phy read timed out\n", | ||
913 | hw->dev[port]->name); | ||
908 | return v; | 914 | return v; |
909 | } | 915 | } |
910 | 916 | ||
911 | static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) | 917 | static int xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) |
912 | { | 918 | { |
913 | int i; | 919 | int i; |
914 | 920 | ||
@@ -918,19 +924,11 @@ static void xm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) | |||
918 | goto ready; | 924 | goto ready; |
919 | udelay(1); | 925 | udelay(1); |
920 | } | 926 | } |
921 | printk(KERN_WARNING PFX "%s: phy write failed to come ready\n", | 927 | return -EIO; |
922 | hw->dev[port]->name); | ||
923 | |||
924 | 928 | ||
925 | ready: | 929 | ready: |
926 | xm_write16(hw, port, XM_PHY_DATA, val); | 930 | xm_write16(hw, port, XM_PHY_DATA, val); |
927 | for (i = 0; i < PHY_RETRIES; i++) { | 931 | return 0; |
928 | udelay(1); | ||
929 | if (!(xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_BUSY)) | ||
930 | return; | ||
931 | } | ||
932 | printk(KERN_WARNING PFX "%s: phy write timed out\n", | ||
933 | hw->dev[port]->name); | ||
934 | } | 932 | } |
935 | 933 | ||
936 | static void genesis_init(struct skge_hw *hw) | 934 | static void genesis_init(struct skge_hw *hw) |
@@ -1400,42 +1398,6 @@ static void genesis_mac_intr(struct skge_hw *hw, int port) | |||
1400 | } | 1398 | } |
1401 | } | 1399 | } |
1402 | 1400 | ||
1403 | static void gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) | ||
1404 | { | ||
1405 | int i; | ||
1406 | |||
1407 | gma_write16(hw, port, GM_SMI_DATA, val); | ||
1408 | gma_write16(hw, port, GM_SMI_CTRL, | ||
1409 | GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg)); | ||
1410 | for (i = 0; i < PHY_RETRIES; i++) { | ||
1411 | udelay(1); | ||
1412 | |||
1413 | if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY)) | ||
1414 | break; | ||
1415 | } | ||
1416 | } | ||
1417 | |||
1418 | static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg) | ||
1419 | { | ||
1420 | int i; | ||
1421 | |||
1422 | gma_write16(hw, port, GM_SMI_CTRL, | ||
1423 | GM_SMI_CT_PHY_AD(hw->phy_addr) | ||
1424 | | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD); | ||
1425 | |||
1426 | for (i = 0; i < PHY_RETRIES; i++) { | ||
1427 | udelay(1); | ||
1428 | if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) | ||
1429 | goto ready; | ||
1430 | } | ||
1431 | |||
1432 | printk(KERN_WARNING PFX "%s: phy read timeout\n", | ||
1433 | hw->dev[port]->name); | ||
1434 | return 0; | ||
1435 | ready: | ||
1436 | return gma_read16(hw, port, GM_SMI_DATA); | ||
1437 | } | ||
1438 | |||
1439 | static void genesis_link_up(struct skge_port *skge) | 1401 | static void genesis_link_up(struct skge_port *skge) |
1440 | { | 1402 | { |
1441 | struct skge_hw *hw = skge->hw; | 1403 | struct skge_hw *hw = skge->hw; |
@@ -1549,6 +1511,54 @@ static inline void bcom_phy_intr(struct skge_port *skge) | |||
1549 | 1511 | ||
1550 | } | 1512 | } |
1551 | 1513 | ||
1514 | static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val) | ||
1515 | { | ||
1516 | int i; | ||
1517 | |||
1518 | gma_write16(hw, port, GM_SMI_DATA, val); | ||
1519 | gma_write16(hw, port, GM_SMI_CTRL, | ||
1520 | GM_SMI_CT_PHY_AD(hw->phy_addr) | GM_SMI_CT_REG_AD(reg)); | ||
1521 | for (i = 0; i < PHY_RETRIES; i++) { | ||
1522 | udelay(1); | ||
1523 | |||
1524 | if (!(gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_BUSY)) | ||
1525 | return 0; | ||
1526 | } | ||
1527 | |||
1528 | printk(KERN_WARNING PFX "%s: phy write timeout\n", | ||
1529 | hw->dev[port]->name); | ||
1530 | return -EIO; | ||
1531 | } | ||
1532 | |||
1533 | static int __gm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val) | ||
1534 | { | ||
1535 | int i; | ||
1536 | |||
1537 | gma_write16(hw, port, GM_SMI_CTRL, | ||
1538 | GM_SMI_CT_PHY_AD(hw->phy_addr) | ||
1539 | | GM_SMI_CT_REG_AD(reg) | GM_SMI_CT_OP_RD); | ||
1540 | |||
1541 | for (i = 0; i < PHY_RETRIES; i++) { | ||
1542 | udelay(1); | ||
1543 | if (gma_read16(hw, port, GM_SMI_CTRL) & GM_SMI_CT_RD_VAL) | ||
1544 | goto ready; | ||
1545 | } | ||
1546 | |||
1547 | return -ETIMEDOUT; | ||
1548 | ready: | ||
1549 | *val = gma_read16(hw, port, GM_SMI_DATA); | ||
1550 | return 0; | ||
1551 | } | ||
1552 | |||
1553 | static u16 gm_phy_read(struct skge_hw *hw, int port, u16 reg) | ||
1554 | { | ||
1555 | u16 v = 0; | ||
1556 | if (__gm_phy_read(hw, port, reg, &v)) | ||
1557 | printk(KERN_WARNING PFX "%s: phy read timeout\n", | ||
1558 | hw->dev[port]->name); | ||
1559 | return v; | ||
1560 | } | ||
1561 | |||
1552 | /* Marvell Phy Initailization */ | 1562 | /* Marvell Phy Initailization */ |
1553 | static void yukon_init(struct skge_hw *hw, int port) | 1563 | static void yukon_init(struct skge_hw *hw, int port) |
1554 | { | 1564 | { |
@@ -1997,6 +2007,51 @@ static void yukon_phy_intr(struct skge_port *skge) | |||
1997 | /* XXX restart autonegotiation? */ | 2007 | /* XXX restart autonegotiation? */ |
1998 | } | 2008 | } |
1999 | 2009 | ||
2010 | /* Basic MII support */ | ||
2011 | static int skge_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
2012 | { | ||
2013 | struct mii_ioctl_data *data = if_mii(ifr); | ||
2014 | struct skge_port *skge = netdev_priv(dev); | ||
2015 | struct skge_hw *hw = skge->hw; | ||
2016 | int err = -EOPNOTSUPP; | ||
2017 | |||
2018 | if (!netif_running(dev)) | ||
2019 | return -ENODEV; /* Phy still in reset */ | ||
2020 | |||
2021 | switch(cmd) { | ||
2022 | case SIOCGMIIPHY: | ||
2023 | data->phy_id = hw->phy_addr; | ||
2024 | |||
2025 | /* fallthru */ | ||
2026 | case SIOCGMIIREG: { | ||
2027 | u16 val = 0; | ||
2028 | spin_lock_bh(&hw->phy_lock); | ||
2029 | if (hw->chip_id == CHIP_ID_GENESIS) | ||
2030 | err = __xm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); | ||
2031 | else | ||
2032 | err = __gm_phy_read(hw, skge->port, data->reg_num & 0x1f, &val); | ||
2033 | spin_unlock_bh(&hw->phy_lock); | ||
2034 | data->val_out = val; | ||
2035 | break; | ||
2036 | } | ||
2037 | |||
2038 | case SIOCSMIIREG: | ||
2039 | if (!capable(CAP_NET_ADMIN)) | ||
2040 | return -EPERM; | ||
2041 | |||
2042 | spin_lock_bh(&hw->phy_lock); | ||
2043 | if (hw->chip_id == CHIP_ID_GENESIS) | ||
2044 | err = xm_phy_write(hw, skge->port, data->reg_num & 0x1f, | ||
2045 | data->val_in); | ||
2046 | else | ||
2047 | err = gm_phy_write(hw, skge->port, data->reg_num & 0x1f, | ||
2048 | data->val_in); | ||
2049 | spin_unlock_bh(&hw->phy_lock); | ||
2050 | break; | ||
2051 | } | ||
2052 | return err; | ||
2053 | } | ||
2054 | |||
2000 | static void skge_ramset(struct skge_hw *hw, u16 q, u32 start, size_t len) | 2055 | static void skge_ramset(struct skge_hw *hw, u16 q, u32 start, size_t len) |
2001 | { | 2056 | { |
2002 | u32 end; | 2057 | u32 end; |
@@ -3058,6 +3113,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, | |||
3058 | SET_NETDEV_DEV(dev, &hw->pdev->dev); | 3113 | SET_NETDEV_DEV(dev, &hw->pdev->dev); |
3059 | dev->open = skge_up; | 3114 | dev->open = skge_up; |
3060 | dev->stop = skge_down; | 3115 | dev->stop = skge_down; |
3116 | dev->do_ioctl = skge_ioctl; | ||
3061 | dev->hard_start_xmit = skge_xmit_frame; | 3117 | dev->hard_start_xmit = skge_xmit_frame; |
3062 | dev->get_stats = skge_get_stats; | 3118 | dev->get_stats = skge_get_stats; |
3063 | if (hw->chip_id == CHIP_ID_GENESIS) | 3119 | if (hw->chip_id == CHIP_ID_GENESIS) |