diff options
author | Jeff Garzik <jeff@garzik.org> | 2007-08-14 01:24:56 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:50:26 -0400 |
commit | 10096974adb6d62b9f8cf65c266632ea73040936 (patch) | |
tree | 8d229ccb9ebebc2892197fb860cf33092de44179 /drivers/net | |
parent | 2808d2e83f9b48c2f68930b6746fed8efabc41e9 (diff) |
[netdrvr] ns83820: add ethtool media support
Split out from patch authored by Dan Faerch <dan@hacker.dk>.
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ns83820.c | 151 |
1 files changed, 148 insertions, 3 deletions
diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index ea80e6cb3dec..6e65d61a3fe0 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c | |||
@@ -1,4 +1,4 @@ | |||
1 | #define VERSION "0.22" | 1 | #define VERSION "0.23" |
2 | /* ns83820.c by Benjamin LaHaise with contributions. | 2 | /* ns83820.c by Benjamin LaHaise with contributions. |
3 | * | 3 | * |
4 | * Questions/comments/discussion to linux-ns83820@kvack.org. | 4 | * Questions/comments/discussion to linux-ns83820@kvack.org. |
@@ -1247,6 +1247,149 @@ static struct net_device_stats *ns83820_get_stats(struct net_device *ndev) | |||
1247 | return &dev->stats; | 1247 | return &dev->stats; |
1248 | } | 1248 | } |
1249 | 1249 | ||
1250 | /* Let ethtool retrieve info */ | ||
1251 | static int ns83820_get_settings(struct net_device *ndev, | ||
1252 | struct ethtool_cmd *cmd) | ||
1253 | { | ||
1254 | struct ns83820 *dev = PRIV(ndev); | ||
1255 | u32 cfg, tanar, tbicr; | ||
1256 | int have_optical = 0; | ||
1257 | int fullduplex = 0; | ||
1258 | |||
1259 | /* | ||
1260 | * Here's the list of available ethtool commands from other drivers: | ||
1261 | * cmd->advertising = | ||
1262 | * cmd->speed = | ||
1263 | * cmd->duplex = | ||
1264 | * cmd->port = 0; | ||
1265 | * cmd->phy_address = | ||
1266 | * cmd->transceiver = 0; | ||
1267 | * cmd->autoneg = | ||
1268 | * cmd->maxtxpkt = 0; | ||
1269 | * cmd->maxrxpkt = 0; | ||
1270 | */ | ||
1271 | |||
1272 | /* read current configuration */ | ||
1273 | cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; | ||
1274 | tanar = readl(dev->base + TANAR); | ||
1275 | tbicr = readl(dev->base + TBICR); | ||
1276 | |||
1277 | if (dev->CFG_cache & CFG_TBI_EN) { | ||
1278 | /* we have an optical interface */ | ||
1279 | have_optical = 1; | ||
1280 | fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0; | ||
1281 | |||
1282 | } else { | ||
1283 | /* We have copper */ | ||
1284 | fullduplex = (cfg & CFG_DUPSTS) ? 1 : 0; | ||
1285 | } | ||
1286 | |||
1287 | cmd->supported = SUPPORTED_Autoneg; | ||
1288 | |||
1289 | /* we have optical interface */ | ||
1290 | if (dev->CFG_cache & CFG_TBI_EN) { | ||
1291 | cmd->supported |= SUPPORTED_1000baseT_Half | | ||
1292 | SUPPORTED_1000baseT_Full | | ||
1293 | SUPPORTED_FIBRE; | ||
1294 | cmd->port = PORT_FIBRE; | ||
1295 | } /* TODO: else copper related support */ | ||
1296 | |||
1297 | cmd->duplex = fullduplex ? DUPLEX_FULL : DUPLEX_HALF; | ||
1298 | switch (cfg / CFG_SPDSTS0 & 3) { | ||
1299 | case 2: | ||
1300 | cmd->speed = SPEED_1000; | ||
1301 | break; | ||
1302 | case 1: | ||
1303 | cmd->speed = SPEED_100; | ||
1304 | break; | ||
1305 | default: | ||
1306 | cmd->speed = SPEED_10; | ||
1307 | break; | ||
1308 | } | ||
1309 | cmd->autoneg = (tbicr & TBICR_MR_AN_ENABLE) ? 1: 0; | ||
1310 | return 0; | ||
1311 | } | ||
1312 | |||
1313 | /* Let ethool change settings*/ | ||
1314 | static int ns83820_set_settings(struct net_device *ndev, | ||
1315 | struct ethtool_cmd *cmd) | ||
1316 | { | ||
1317 | struct ns83820 *dev = PRIV(ndev); | ||
1318 | u32 cfg, tanar; | ||
1319 | int have_optical = 0; | ||
1320 | int fullduplex = 0; | ||
1321 | |||
1322 | /* read current configuration */ | ||
1323 | cfg = readl(dev->base + CFG) ^ SPDSTS_POLARITY; | ||
1324 | tanar = readl(dev->base + TANAR); | ||
1325 | |||
1326 | if (dev->CFG_cache & CFG_TBI_EN) { | ||
1327 | /* we have optical */ | ||
1328 | have_optical = 1; | ||
1329 | fullduplex = (tanar & TANAR_FULL_DUP); | ||
1330 | |||
1331 | } else { | ||
1332 | /* we have copper */ | ||
1333 | fullduplex = cfg & CFG_DUPSTS; | ||
1334 | } | ||
1335 | |||
1336 | spin_lock_irq(&dev->misc_lock); | ||
1337 | spin_lock(&dev->tx_lock); | ||
1338 | |||
1339 | /* Set duplex */ | ||
1340 | if (cmd->duplex != fullduplex) { | ||
1341 | if (have_optical) { | ||
1342 | /*set full duplex*/ | ||
1343 | if (cmd->duplex == DUPLEX_FULL) { | ||
1344 | /* force full duplex */ | ||
1345 | writel(readl(dev->base + TXCFG) | ||
1346 | | TXCFG_CSI | TXCFG_HBI | TXCFG_ATP, | ||
1347 | dev->base + TXCFG); | ||
1348 | writel(readl(dev->base + RXCFG) | RXCFG_RX_FD, | ||
1349 | dev->base + RXCFG); | ||
1350 | /* Light up full duplex LED */ | ||
1351 | writel(readl(dev->base + GPIOR) | GPIOR_GP1_OUT, | ||
1352 | dev->base + GPIOR); | ||
1353 | } else { | ||
1354 | /*TODO: set half duplex */ | ||
1355 | } | ||
1356 | |||
1357 | } else { | ||
1358 | /*we have copper*/ | ||
1359 | /* TODO: Set duplex for copper cards */ | ||
1360 | } | ||
1361 | printk(KERN_INFO "%s: Duplex set via ethtool\n", | ||
1362 | ndev->name); | ||
1363 | } | ||
1364 | |||
1365 | /* Set autonegotiation */ | ||
1366 | if (1) { | ||
1367 | if (cmd->autoneg == AUTONEG_ENABLE) { | ||
1368 | /* restart auto negotiation */ | ||
1369 | writel(TBICR_MR_AN_ENABLE | TBICR_MR_RESTART_AN, | ||
1370 | dev->base + TBICR); | ||
1371 | writel(TBICR_MR_AN_ENABLE, dev->base + TBICR); | ||
1372 | dev->linkstate = LINK_AUTONEGOTIATE; | ||
1373 | |||
1374 | printk(KERN_INFO "%s: autoneg enabled via ethtool\n", | ||
1375 | ndev->name); | ||
1376 | } else { | ||
1377 | /* disable auto negotiation */ | ||
1378 | writel(0x00000000, dev->base + TBICR); | ||
1379 | } | ||
1380 | |||
1381 | printk(KERN_INFO "%s: autoneg %s via ethtool\n", ndev->name, | ||
1382 | cmd->autoneg ? "ENABLED" : "DISABLED"); | ||
1383 | } | ||
1384 | |||
1385 | phy_intr(ndev); | ||
1386 | spin_unlock(&dev->tx_lock); | ||
1387 | spin_unlock_irq(&dev->misc_lock); | ||
1388 | |||
1389 | return 0; | ||
1390 | } | ||
1391 | /* end ethtool get/set support -df */ | ||
1392 | |||
1250 | static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) | 1393 | static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) |
1251 | { | 1394 | { |
1252 | struct ns83820 *dev = PRIV(ndev); | 1395 | struct ns83820 *dev = PRIV(ndev); |
@@ -1263,8 +1406,10 @@ static u32 ns83820_get_link(struct net_device *ndev) | |||
1263 | } | 1406 | } |
1264 | 1407 | ||
1265 | static const struct ethtool_ops ops = { | 1408 | static const struct ethtool_ops ops = { |
1266 | .get_drvinfo = ns83820_get_drvinfo, | 1409 | .get_settings = ns83820_get_settings, |
1267 | .get_link = ns83820_get_link | 1410 | .set_settings = ns83820_set_settings, |
1411 | .get_drvinfo = ns83820_get_drvinfo, | ||
1412 | .get_link = ns83820_get_link | ||
1268 | }; | 1413 | }; |
1269 | 1414 | ||
1270 | /* this function is called in irq context from the ISR */ | 1415 | /* this function is called in irq context from the ISR */ |