aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/ns83820.c
diff options
context:
space:
mode:
authorJeff Garzik <jeff@garzik.org>2007-08-14 01:24:56 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-10-10 19:50:26 -0400
commit10096974adb6d62b9f8cf65c266632ea73040936 (patch)
tree8d229ccb9ebebc2892197fb860cf33092de44179 /drivers/net/ns83820.c
parent2808d2e83f9b48c2f68930b6746fed8efabc41e9 (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/ns83820.c')
-rw-r--r--drivers/net/ns83820.c151
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 */
1251static 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*/
1314static 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
1250static void ns83820_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) 1393static 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
1265static const struct ethtool_ops ops = { 1408static 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 */