diff options
author | Francois Romieu <romieu@fr.zoreil.com> | 2005-07-30 07:10:21 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-07-30 18:20:59 -0400 |
commit | 43afb949a955a7d88f4baf43d5c676bf4c31ff6c (patch) | |
tree | e179f7694439d8668c6f0691a8b468d20746ede3 | |
parent | 4405d3b5ef0a870e8d70ee4a3d050c89fcc40a86 (diff) |
[PATCH] sis190: ethtool/mii support.
ethtool/mii support
Bug: disabling autonegotiation and setting the link parameters at the
same time does not provide the expected result. More investigation is
needed.
Note: past the initial probe/open time, the link is managed from user-space
or accessed through sis190_phy_task, i.e. in a usermode context. Whence the
very limited locking needs.
Signed-off-by: Francois Romieu <romieu@fr.zoreil.com>
Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
-rw-r--r-- | drivers/net/sis190.c | 60 |
1 files changed, 60 insertions, 0 deletions
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index e374cf43fed0..ff4f24e5f59c 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/moduleparam.h> | 22 | #include <linux/moduleparam.h> |
23 | #include <linux/netdevice.h> | 23 | #include <linux/netdevice.h> |
24 | #include <linux/rtnetlink.h> | ||
24 | #include <linux/etherdevice.h> | 25 | #include <linux/etherdevice.h> |
25 | #include <linux/ethtool.h> | 26 | #include <linux/ethtool.h> |
26 | #include <linux/pci.h> | 27 | #include <linux/pci.h> |
@@ -230,6 +231,7 @@ struct sis190_private { | |||
230 | struct work_struct phy_task; | 231 | struct work_struct phy_task; |
231 | struct timer_list timer; | 232 | struct timer_list timer; |
232 | u32 msg_enable; | 233 | u32 msg_enable; |
234 | struct mii_if_info mii_if; | ||
233 | }; | 235 | }; |
234 | 236 | ||
235 | const static struct { | 237 | const static struct { |
@@ -308,6 +310,20 @@ static int mdio_read(void __iomem *ioaddr, int reg) | |||
308 | return (u16) (SIS_R32(GMIIControl) >> EhnMIIdataShift); | 310 | return (u16) (SIS_R32(GMIIControl) >> EhnMIIdataShift); |
309 | } | 311 | } |
310 | 312 | ||
313 | static void __mdio_write(struct net_device *dev, int phy_id, int reg, int val) | ||
314 | { | ||
315 | struct sis190_private *tp = netdev_priv(dev); | ||
316 | |||
317 | mdio_write(tp->mmio_addr, reg, val); | ||
318 | } | ||
319 | |||
320 | static int __mdio_read(struct net_device *dev, int phy_id, int reg) | ||
321 | { | ||
322 | struct sis190_private *tp = netdev_priv(dev); | ||
323 | |||
324 | return mdio_read(tp->mmio_addr, reg); | ||
325 | } | ||
326 | |||
311 | static int sis190_read_eeprom(void __iomem *ioaddr, u32 reg) | 327 | static int sis190_read_eeprom(void __iomem *ioaddr, u32 reg) |
312 | { | 328 | { |
313 | unsigned int i; | 329 | unsigned int i; |
@@ -790,6 +806,8 @@ static void sis190_phy_task(void * data) | |||
790 | void __iomem *ioaddr = tp->mmio_addr; | 806 | void __iomem *ioaddr = tp->mmio_addr; |
791 | u16 val; | 807 | u16 val; |
792 | 808 | ||
809 | rtnl_lock(); | ||
810 | |||
793 | val = mdio_read(ioaddr, MII_BMCR); | 811 | val = mdio_read(ioaddr, MII_BMCR); |
794 | if (val & BMCR_RESET) { | 812 | if (val & BMCR_RESET) { |
795 | // FIXME: needlessly high ? -- FR 02/07/2005 | 813 | // FIXME: needlessly high ? -- FR 02/07/2005 |
@@ -843,6 +861,8 @@ static void sis190_phy_task(void * data) | |||
843 | p->msg); | 861 | p->msg); |
844 | netif_carrier_on(dev); | 862 | netif_carrier_on(dev); |
845 | } | 863 | } |
864 | |||
865 | rtnl_unlock(); | ||
846 | } | 866 | } |
847 | 867 | ||
848 | static void sis190_phy_timer(unsigned long __opaque) | 868 | static void sis190_phy_timer(unsigned long __opaque) |
@@ -1150,6 +1170,13 @@ static struct net_device * __devinit sis190_init_board(struct pci_dev *pdev) | |||
1150 | tp->pci_dev = pdev; | 1170 | tp->pci_dev = pdev; |
1151 | tp->mmio_addr = ioaddr; | 1171 | tp->mmio_addr = ioaddr; |
1152 | 1172 | ||
1173 | tp->mii_if.dev = dev; | ||
1174 | tp->mii_if.mdio_read = __mdio_read; | ||
1175 | tp->mii_if.mdio_write = __mdio_write; | ||
1176 | // tp->mii_if.phy_id = XXX; | ||
1177 | tp->mii_if.phy_id_mask = 0x1f; | ||
1178 | tp->mii_if.reg_num_mask = 0x1f; | ||
1179 | |||
1153 | sis190_irq_mask_and_ack(ioaddr); | 1180 | sis190_irq_mask_and_ack(ioaddr); |
1154 | 1181 | ||
1155 | sis190_soft_reset(ioaddr); | 1182 | sis190_soft_reset(ioaddr); |
@@ -1216,6 +1243,20 @@ static void sis190_set_speed_auto(struct net_device *dev) | |||
1216 | BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET); | 1243 | BMCR_ANENABLE | BMCR_ANRESTART | BMCR_RESET); |
1217 | } | 1244 | } |
1218 | 1245 | ||
1246 | static int sis190_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
1247 | { | ||
1248 | struct sis190_private *tp = netdev_priv(dev); | ||
1249 | |||
1250 | return mii_ethtool_gset(&tp->mii_if, cmd); | ||
1251 | } | ||
1252 | |||
1253 | static int sis190_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) | ||
1254 | { | ||
1255 | struct sis190_private *tp = netdev_priv(dev); | ||
1256 | |||
1257 | return mii_ethtool_sset(&tp->mii_if, cmd); | ||
1258 | } | ||
1259 | |||
1219 | static void sis190_get_drvinfo(struct net_device *dev, | 1260 | static void sis190_get_drvinfo(struct net_device *dev, |
1220 | struct ethtool_drvinfo *info) | 1261 | struct ethtool_drvinfo *info) |
1221 | { | 1262 | { |
@@ -1245,6 +1286,13 @@ static void sis190_get_regs(struct net_device *dev, struct ethtool_regs *regs, | |||
1245 | spin_unlock_irqrestore(&tp->lock, flags); | 1286 | spin_unlock_irqrestore(&tp->lock, flags); |
1246 | } | 1287 | } |
1247 | 1288 | ||
1289 | static int sis190_nway_reset(struct net_device *dev) | ||
1290 | { | ||
1291 | struct sis190_private *tp = netdev_priv(dev); | ||
1292 | |||
1293 | return mii_nway_restart(&tp->mii_if); | ||
1294 | } | ||
1295 | |||
1248 | static u32 sis190_get_msglevel(struct net_device *dev) | 1296 | static u32 sis190_get_msglevel(struct net_device *dev) |
1249 | { | 1297 | { |
1250 | struct sis190_private *tp = netdev_priv(dev); | 1298 | struct sis190_private *tp = netdev_priv(dev); |
@@ -1260,14 +1308,25 @@ static void sis190_set_msglevel(struct net_device *dev, u32 value) | |||
1260 | } | 1308 | } |
1261 | 1309 | ||
1262 | static struct ethtool_ops sis190_ethtool_ops = { | 1310 | static struct ethtool_ops sis190_ethtool_ops = { |
1311 | .get_settings = sis190_get_settings, | ||
1312 | .set_settings = sis190_set_settings, | ||
1263 | .get_drvinfo = sis190_get_drvinfo, | 1313 | .get_drvinfo = sis190_get_drvinfo, |
1264 | .get_regs_len = sis190_get_regs_len, | 1314 | .get_regs_len = sis190_get_regs_len, |
1265 | .get_regs = sis190_get_regs, | 1315 | .get_regs = sis190_get_regs, |
1266 | .get_link = ethtool_op_get_link, | 1316 | .get_link = ethtool_op_get_link, |
1267 | .get_msglevel = sis190_get_msglevel, | 1317 | .get_msglevel = sis190_get_msglevel, |
1268 | .set_msglevel = sis190_set_msglevel, | 1318 | .set_msglevel = sis190_set_msglevel, |
1319 | .nway_reset = sis190_nway_reset, | ||
1269 | }; | 1320 | }; |
1270 | 1321 | ||
1322 | static int sis190_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) | ||
1323 | { | ||
1324 | struct sis190_private *tp = netdev_priv(dev); | ||
1325 | |||
1326 | return !netif_running(dev) ? -EINVAL : | ||
1327 | generic_mii_ioctl(&tp->mii_if, if_mii(ifr), cmd, NULL); | ||
1328 | } | ||
1329 | |||
1271 | static int __devinit sis190_init_one(struct pci_dev *pdev, | 1330 | static int __devinit sis190_init_one(struct pci_dev *pdev, |
1272 | const struct pci_device_id *ent) | 1331 | const struct pci_device_id *ent) |
1273 | { | 1332 | { |
@@ -1308,6 +1367,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, | |||
1308 | 1367 | ||
1309 | dev->open = sis190_open; | 1368 | dev->open = sis190_open; |
1310 | dev->stop = sis190_close; | 1369 | dev->stop = sis190_close; |
1370 | dev->do_ioctl = sis190_ioctl; | ||
1311 | dev->get_stats = sis190_get_stats; | 1371 | dev->get_stats = sis190_get_stats; |
1312 | dev->tx_timeout = sis190_tx_timeout; | 1372 | dev->tx_timeout = sis190_tx_timeout; |
1313 | dev->watchdog_timeo = SIS190_TX_TIMEOUT; | 1373 | dev->watchdog_timeo = SIS190_TX_TIMEOUT; |