diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/net/sis190.c | 154 |
1 files changed, 138 insertions, 16 deletions
diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index d915507e90eb..1e8e7111c261 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c | |||
@@ -232,6 +232,14 @@ enum sis190_eeprom_access_register_bits { | |||
232 | EEWOP = 0x00000100 // unused | 232 | EEWOP = 0x00000100 // unused |
233 | }; | 233 | }; |
234 | 234 | ||
235 | /* EEPROM Addresses */ | ||
236 | enum sis190_eeprom_address { | ||
237 | EEPROMSignature = 0x00, | ||
238 | EEPROMCLK = 0x01, // unused | ||
239 | EEPROMInfo = 0x02, | ||
240 | EEPROMMACAddr = 0x03 | ||
241 | }; | ||
242 | |||
235 | struct sis190_private { | 243 | struct sis190_private { |
236 | void __iomem *mmio_addr; | 244 | void __iomem *mmio_addr; |
237 | struct pci_dev *pci_dev; | 245 | struct pci_dev *pci_dev; |
@@ -1240,6 +1248,125 @@ static void sis190_tx_timeout(struct net_device *dev) | |||
1240 | netif_wake_queue(dev); | 1248 | netif_wake_queue(dev); |
1241 | } | 1249 | } |
1242 | 1250 | ||
1251 | static int __devinit sis190_get_mac_addr_from_eeprom(struct pci_dev *pdev, | ||
1252 | struct net_device *dev) | ||
1253 | { | ||
1254 | struct sis190_private *tp = netdev_priv(dev); | ||
1255 | void __iomem *ioaddr = tp->mmio_addr; | ||
1256 | u16 sig; | ||
1257 | int i; | ||
1258 | |||
1259 | net_probe(tp, KERN_INFO "%s: Read MAC address from EEPROM\n", | ||
1260 | pci_name(pdev)); | ||
1261 | |||
1262 | /* Check to see if there is a sane EEPROM */ | ||
1263 | sig = (u16) sis190_read_eeprom(ioaddr, EEPROMSignature); | ||
1264 | |||
1265 | if ((sig == 0xffff) || (sig == 0x0000)) { | ||
1266 | net_probe(tp, KERN_INFO "%s: Error EEPROM read %x.\n", | ||
1267 | pci_name(pdev), sig); | ||
1268 | return -EIO; | ||
1269 | } | ||
1270 | |||
1271 | /* Get MAC address from EEPROM */ | ||
1272 | for (i = 0; i < MAC_ADDR_LEN / 2; i++) { | ||
1273 | u16 w = sis190_read_eeprom(ioaddr, EEPROMMACAddr + i); | ||
1274 | |||
1275 | ((u16 *)dev->dev_addr)[0] = le16_to_cpu(w); | ||
1276 | } | ||
1277 | |||
1278 | return 0; | ||
1279 | } | ||
1280 | |||
1281 | /** | ||
1282 | * sis190_get_mac_addr_from_apc - Get MAC address for SiS965 model | ||
1283 | * @pdev: PCI device | ||
1284 | * @dev: network device to get address for | ||
1285 | * | ||
1286 | * SiS965 model, use APC CMOS RAM to store MAC address. | ||
1287 | * APC CMOS RAM is accessed through ISA bridge. | ||
1288 | * MAC address is read into @net_dev->dev_addr. | ||
1289 | */ | ||
1290 | static int __devinit sis190_get_mac_addr_from_apc(struct pci_dev *pdev, | ||
1291 | struct net_device *dev) | ||
1292 | { | ||
1293 | struct sis190_private *tp = netdev_priv(dev); | ||
1294 | struct pci_dev *isa_bridge; | ||
1295 | u8 reg, tmp8; | ||
1296 | int i; | ||
1297 | |||
1298 | net_probe(tp, KERN_INFO "%s: Read MAC address from APC.\n", | ||
1299 | pci_name(pdev)); | ||
1300 | |||
1301 | isa_bridge = pci_get_device(PCI_VENDOR_ID_SI, 0x0965, NULL); | ||
1302 | if (!isa_bridge) { | ||
1303 | net_probe(tp, KERN_INFO "%s: Can not find ISA bridge.\n", | ||
1304 | pci_name(pdev)); | ||
1305 | return -EIO; | ||
1306 | } | ||
1307 | |||
1308 | /* Enable port 78h & 79h to access APC Registers. */ | ||
1309 | pci_read_config_byte(isa_bridge, 0x48, &tmp8); | ||
1310 | reg = (tmp8 & ~0x02); | ||
1311 | pci_write_config_byte(isa_bridge, 0x48, reg); | ||
1312 | udelay(50); | ||
1313 | pci_read_config_byte(isa_bridge, 0x48, ®); | ||
1314 | |||
1315 | for (i = 0; i < MAC_ADDR_LEN; i++) { | ||
1316 | outb(0x9 + i, 0x78); | ||
1317 | dev->dev_addr[i] = inb(0x79); | ||
1318 | } | ||
1319 | |||
1320 | outb(0x12, 0x78); | ||
1321 | reg = inb(0x79); | ||
1322 | |||
1323 | /* Restore the value to ISA Bridge */ | ||
1324 | pci_write_config_byte(isa_bridge, 0x48, tmp8); | ||
1325 | pci_dev_put(isa_bridge); | ||
1326 | |||
1327 | return 0; | ||
1328 | } | ||
1329 | |||
1330 | /** | ||
1331 | * sis190_init_rxfilter - Initialize the Rx filter | ||
1332 | * @dev: network device to initialize | ||
1333 | * | ||
1334 | * Set receive filter address to our MAC address | ||
1335 | * and enable packet filtering. | ||
1336 | */ | ||
1337 | static inline void sis190_init_rxfilter(struct net_device *dev) | ||
1338 | { | ||
1339 | struct sis190_private *tp = netdev_priv(dev); | ||
1340 | void __iomem *ioaddr = tp->mmio_addr; | ||
1341 | u16 ctl; | ||
1342 | int i; | ||
1343 | |||
1344 | ctl = SIS_R16(RxMacControl); | ||
1345 | /* | ||
1346 | * Disable packet filtering before setting filter. | ||
1347 | * Note: SiS's driver writes 32 bits but RxMacControl is 16 bits | ||
1348 | * only and followed by RxMacAddr (6 bytes). Strange. -- FR | ||
1349 | */ | ||
1350 | SIS_W16(RxMacControl, ctl & ~0x0f00); | ||
1351 | |||
1352 | for (i = 0; i < MAC_ADDR_LEN; i++) | ||
1353 | SIS_W8(RxMacAddr + i, dev->dev_addr[i]); | ||
1354 | |||
1355 | SIS_W16(RxMacControl, ctl); | ||
1356 | SIS_PCI_COMMIT(); | ||
1357 | } | ||
1358 | |||
1359 | static int sis190_get_mac_addr(struct pci_dev *pdev, struct net_device *dev) | ||
1360 | { | ||
1361 | u8 from; | ||
1362 | |||
1363 | pci_read_config_byte(pdev, 0x73, &from); | ||
1364 | |||
1365 | return (from & 0x00000001) ? | ||
1366 | sis190_get_mac_addr_from_apc(pdev, dev) : | ||
1367 | sis190_get_mac_addr_from_eeprom(pdev, dev); | ||
1368 | } | ||
1369 | |||
1243 | static void sis190_set_speed_auto(struct net_device *dev) | 1370 | static void sis190_set_speed_auto(struct net_device *dev) |
1244 | { | 1371 | { |
1245 | struct sis190_private *tp = netdev_priv(dev); | 1372 | struct sis190_private *tp = netdev_priv(dev); |
@@ -1355,7 +1482,7 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, | |||
1355 | struct sis190_private *tp; | 1482 | struct sis190_private *tp; |
1356 | struct net_device *dev; | 1483 | struct net_device *dev; |
1357 | void __iomem *ioaddr; | 1484 | void __iomem *ioaddr; |
1358 | int i, rc; | 1485 | int rc; |
1359 | 1486 | ||
1360 | if (!printed_version) { | 1487 | if (!printed_version) { |
1361 | net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n"); | 1488 | net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n"); |
@@ -1371,18 +1498,11 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, | |||
1371 | tp = netdev_priv(dev); | 1498 | tp = netdev_priv(dev); |
1372 | ioaddr = tp->mmio_addr; | 1499 | ioaddr = tp->mmio_addr; |
1373 | 1500 | ||
1374 | /* Get MAC address */ | 1501 | rc = sis190_get_mac_addr(pdev, dev); |
1375 | /* Read node address from the EEPROM */ | 1502 | if (rc < 0) |
1376 | 1503 | goto err_release_board; | |
1377 | if (SIS_R32(ROMControl) & 0x4) { | ||
1378 | for (i = 0; i < 3; i++) { | ||
1379 | SIS_W16(RxMacAddr + 2*i, | ||
1380 | sis190_read_eeprom(ioaddr, 3 + i)); | ||
1381 | } | ||
1382 | } | ||
1383 | 1504 | ||
1384 | for (i = 0; i < MAC_ADDR_LEN; i++) | 1505 | sis190_init_rxfilter(dev); |
1385 | dev->dev_addr[i] = SIS_R8(RxMacAddr + i); | ||
1386 | 1506 | ||
1387 | INIT_WORK(&tp->phy_task, sis190_phy_task, dev); | 1507 | INIT_WORK(&tp->phy_task, sis190_phy_task, dev); |
1388 | 1508 | ||
@@ -1403,10 +1523,8 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, | |||
1403 | 1523 | ||
1404 | spin_lock_init(&tp->lock); | 1524 | spin_lock_init(&tp->lock); |
1405 | rc = register_netdev(dev); | 1525 | rc = register_netdev(dev); |
1406 | if (rc < 0) { | 1526 | if (rc < 0) |
1407 | sis190_release_board(pdev); | 1527 | goto err_release_board; |
1408 | goto out; | ||
1409 | } | ||
1410 | 1528 | ||
1411 | pci_set_drvdata(pdev, dev); | 1529 | pci_set_drvdata(pdev, dev); |
1412 | 1530 | ||
@@ -1423,6 +1541,10 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, | |||
1423 | sis190_set_speed_auto(dev); | 1541 | sis190_set_speed_auto(dev); |
1424 | out: | 1542 | out: |
1425 | return rc; | 1543 | return rc; |
1544 | |||
1545 | err_release_board: | ||
1546 | sis190_release_board(pdev); | ||
1547 | goto out; | ||
1426 | } | 1548 | } |
1427 | 1549 | ||
1428 | static void __devexit sis190_remove_one(struct pci_dev *pdev) | 1550 | static void __devexit sis190_remove_one(struct pci_dev *pdev) |