| @@ -1,14 +1,14 @@ | | | @@ -1,14 +1,14 @@ |
1 | /* $NetBSD: if_pcn.c,v 1.72 2019/10/11 14:22:46 msaitoh Exp $ */ | | 1 | /* $NetBSD: if_pcn.c,v 1.73 2020/01/29 06:46:58 thorpej Exp $ */ |
2 | | | 2 | |
3 | /* | | 3 | /* |
4 | * Copyright (c) 2001 Wasabi Systems, Inc. | | 4 | * Copyright (c) 2001 Wasabi Systems, Inc. |
5 | * All rights reserved. | | 5 | * All rights reserved. |
6 | * | | 6 | * |
7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. | | 7 | * Written by Jason R. Thorpe for Wasabi Systems, Inc. |
8 | * | | 8 | * |
9 | * Redistribution and use in source and binary forms, with or without | | 9 | * Redistribution and use in source and binary forms, with or without |
10 | * modification, are permitted provided that the following conditions | | 10 | * modification, are permitted provided that the following conditions |
11 | * are met: | | 11 | * are met: |
12 | * 1. Redistributions of source code must retain the above copyright | | 12 | * 1. Redistributions of source code must retain the above copyright |
13 | * notice, this list of conditions and the following disclaimer. | | 13 | * notice, this list of conditions and the following disclaimer. |
14 | * 2. Redistributions in binary form must reproduce the above copyright | | 14 | * 2. Redistributions in binary form must reproduce the above copyright |
| @@ -55,27 +55,27 @@ | | | @@ -55,27 +55,27 @@ |
55 | * Ethernet Controller with Integrated PHY | | 55 | * Ethernet Controller with Integrated PHY |
56 | * | | 56 | * |
57 | * This also supports the virtual PCnet-PCI Ethernet interface found | | 57 | * This also supports the virtual PCnet-PCI Ethernet interface found |
58 | * in VMware. | | 58 | * in VMware. |
59 | * | | 59 | * |
60 | * TODO: | | 60 | * TODO: |
61 | * | | 61 | * |
62 | * * Split this into bus-specific and bus-independent portions. | | 62 | * * Split this into bus-specific and bus-independent portions. |
63 | * The core could also be used for the ILACC (Am79900) 32-bit | | 63 | * The core could also be used for the ILACC (Am79900) 32-bit |
64 | * Ethernet chip (XXX only if we use an ILACC-compatible SWSTYLE). | | 64 | * Ethernet chip (XXX only if we use an ILACC-compatible SWSTYLE). |
65 | */ | | 65 | */ |
66 | | | 66 | |
67 | #include <sys/cdefs.h> | | 67 | #include <sys/cdefs.h> |
68 | __KERNEL_RCSID(0, "$NetBSD: if_pcn.c,v 1.72 2019/10/11 14:22:46 msaitoh Exp $"); | | 68 | __KERNEL_RCSID(0, "$NetBSD: if_pcn.c,v 1.73 2020/01/29 06:46:58 thorpej Exp $"); |
69 | | | 69 | |
70 | #include <sys/param.h> | | 70 | #include <sys/param.h> |
71 | #include <sys/systm.h> | | 71 | #include <sys/systm.h> |
72 | #include <sys/callout.h> | | 72 | #include <sys/callout.h> |
73 | #include <sys/mbuf.h> | | 73 | #include <sys/mbuf.h> |
74 | #include <sys/malloc.h> | | 74 | #include <sys/malloc.h> |
75 | #include <sys/kernel.h> | | 75 | #include <sys/kernel.h> |
76 | #include <sys/socket.h> | | 76 | #include <sys/socket.h> |
77 | #include <sys/ioctl.h> | | 77 | #include <sys/ioctl.h> |
78 | #include <sys/errno.h> | | 78 | #include <sys/errno.h> |
79 | #include <sys/device.h> | | 79 | #include <sys/device.h> |
80 | #include <sys/queue.h> | | 80 | #include <sys/queue.h> |
81 | | | 81 | |
| @@ -1153,27 +1153,27 @@ static void | | | @@ -1153,27 +1153,27 @@ static void |
1153 | pcn_watchdog(struct ifnet *ifp) | | 1153 | pcn_watchdog(struct ifnet *ifp) |
1154 | { | | 1154 | { |
1155 | struct pcn_softc *sc = ifp->if_softc; | | 1155 | struct pcn_softc *sc = ifp->if_softc; |
1156 | | | 1156 | |
1157 | /* | | 1157 | /* |
1158 | * Since we're not interrupting every packet, sweep | | 1158 | * Since we're not interrupting every packet, sweep |
1159 | * up before we report an error. | | 1159 | * up before we report an error. |
1160 | */ | | 1160 | */ |
1161 | pcn_txintr(sc); | | 1161 | pcn_txintr(sc); |
1162 | | | 1162 | |
1163 | if (sc->sc_txfree != PCN_NTXDESC) { | | 1163 | if (sc->sc_txfree != PCN_NTXDESC) { |
1164 | printf("%s: device timeout (txfree %d txsfree %d)\n", | | 1164 | printf("%s: device timeout (txfree %d txsfree %d)\n", |
1165 | device_xname(sc->sc_dev), sc->sc_txfree, sc->sc_txsfree); | | 1165 | device_xname(sc->sc_dev), sc->sc_txfree, sc->sc_txsfree); |
1166 | ifp->if_oerrors++; | | 1166 | if_statinc(ifp, if_oerrors); |
1167 | | | 1167 | |
1168 | /* Reset the interface. */ | | 1168 | /* Reset the interface. */ |
1169 | (void) pcn_init(ifp); | | 1169 | (void) pcn_init(ifp); |
1170 | } | | 1170 | } |
1171 | | | 1171 | |
1172 | /* Try to get more packets going. */ | | 1172 | /* Try to get more packets going. */ |
1173 | pcn_start(ifp); | | 1173 | pcn_start(ifp); |
1174 | } | | 1174 | } |
1175 | | | 1175 | |
1176 | /* | | 1176 | /* |
1177 | * pcn_ioctl: [ifnet interface function] | | 1177 | * pcn_ioctl: [ifnet interface function] |
1178 | * | | 1178 | * |
1179 | * Handle control requests from the operator. | | 1179 | * Handle control requests from the operator. |
| @@ -1238,52 +1238,52 @@ pcn_intr(void *arg) | | | @@ -1238,52 +1238,52 @@ pcn_intr(void *arg) |
1238 | if (csr0 & LE_C0_RINT) { | | 1238 | if (csr0 & LE_C0_RINT) { |
1239 | PCN_EVCNT_INCR(&sc->sc_ev_rxintr); | | 1239 | PCN_EVCNT_INCR(&sc->sc_ev_rxintr); |
1240 | wantinit = pcn_rxintr(sc); | | 1240 | wantinit = pcn_rxintr(sc); |
1241 | } | | 1241 | } |
1242 | | | 1242 | |
1243 | if (csr0 & LE_C0_TINT) { | | 1243 | if (csr0 & LE_C0_TINT) { |
1244 | PCN_EVCNT_INCR(&sc->sc_ev_txintr); | | 1244 | PCN_EVCNT_INCR(&sc->sc_ev_txintr); |
1245 | pcn_txintr(sc); | | 1245 | pcn_txintr(sc); |
1246 | } | | 1246 | } |
1247 | | | 1247 | |
1248 | if (csr0 & LE_C0_ERR) { | | 1248 | if (csr0 & LE_C0_ERR) { |
1249 | if (csr0 & LE_C0_BABL) { | | 1249 | if (csr0 & LE_C0_BABL) { |
1250 | PCN_EVCNT_INCR(&sc->sc_ev_babl); | | 1250 | PCN_EVCNT_INCR(&sc->sc_ev_babl); |
1251 | ifp->if_oerrors++; | | 1251 | if_statinc(ifp, if_oerrors); |
1252 | } | | 1252 | } |
1253 | if (csr0 & LE_C0_MISS) { | | 1253 | if (csr0 & LE_C0_MISS) { |
1254 | PCN_EVCNT_INCR(&sc->sc_ev_miss); | | 1254 | PCN_EVCNT_INCR(&sc->sc_ev_miss); |
1255 | ifp->if_ierrors++; | | 1255 | if_statinc(ifp, if_ierrors); |
1256 | } | | 1256 | } |
1257 | if (csr0 & LE_C0_MERR) { | | 1257 | if (csr0 & LE_C0_MERR) { |
1258 | PCN_EVCNT_INCR(&sc->sc_ev_merr); | | 1258 | PCN_EVCNT_INCR(&sc->sc_ev_merr); |
1259 | printf("%s: memory error\n", | | 1259 | printf("%s: memory error\n", |
1260 | device_xname(sc->sc_dev)); | | 1260 | device_xname(sc->sc_dev)); |
1261 | wantinit = 1; | | 1261 | wantinit = 1; |
1262 | break; | | 1262 | break; |
1263 | } | | 1263 | } |
1264 | } | | 1264 | } |
1265 | | | 1265 | |
1266 | if ((csr0 & LE_C0_RXON) == 0) { | | 1266 | if ((csr0 & LE_C0_RXON) == 0) { |
1267 | printf("%s: receiver disabled\n", | | 1267 | printf("%s: receiver disabled\n", |
1268 | device_xname(sc->sc_dev)); | | 1268 | device_xname(sc->sc_dev)); |
1269 | ifp->if_ierrors++; | | 1269 | if_statinc(ifp, if_ierrors); |
1270 | wantinit = 1; | | 1270 | wantinit = 1; |
1271 | } | | 1271 | } |
1272 | | | 1272 | |
1273 | if ((csr0 & LE_C0_TXON) == 0) { | | 1273 | if ((csr0 & LE_C0_TXON) == 0) { |
1274 | printf("%s: transmitter disabled\n", | | 1274 | printf("%s: transmitter disabled\n", |
1275 | device_xname(sc->sc_dev)); | | 1275 | device_xname(sc->sc_dev)); |
1276 | ifp->if_oerrors++; | | 1276 | if_statinc(ifp, if_oerrors); |
1277 | wantinit = 1; | | 1277 | wantinit = 1; |
1278 | } | | 1278 | } |
1279 | } | | 1279 | } |
1280 | | | 1280 | |
1281 | if (handled) { | | 1281 | if (handled) { |
1282 | if (wantinit) | | 1282 | if (wantinit) |
1283 | pcn_init(ifp); | | 1283 | pcn_init(ifp); |
1284 | | | 1284 | |
1285 | /* Try to get more packets going. */ | | 1285 | /* Try to get more packets going. */ |
1286 | if_schedule_deferred_start(ifp); | | 1286 | if_schedule_deferred_start(ifp); |
1287 | } | | 1287 | } |
1288 | | | 1288 | |
1289 | return handled; | | 1289 | return handled; |
| @@ -1339,27 +1339,27 @@ pcn_txintr(struct pcn_softc *sc) | | | @@ -1339,27 +1339,27 @@ pcn_txintr(struct pcn_softc *sc) |
1339 | | | 1339 | |
1340 | tmd1 = le32toh(sc->sc_txdescs[txs->txs_lastdesc].tmd1); | | 1340 | tmd1 = le32toh(sc->sc_txdescs[txs->txs_lastdesc].tmd1); |
1341 | if (tmd1 & LE_T1_OWN) | | 1341 | if (tmd1 & LE_T1_OWN) |
1342 | break; | | 1342 | break; |
1343 | | | 1343 | |
1344 | /* | | 1344 | /* |
1345 | * Slightly annoying -- we have to loop through the | | 1345 | * Slightly annoying -- we have to loop through the |
1346 | * descriptors we've used looking for ERR, since it | | 1346 | * descriptors we've used looking for ERR, since it |
1347 | * can appear on any descriptor in the chain. | | 1347 | * can appear on any descriptor in the chain. |
1348 | */ | | 1348 | */ |
1349 | for (j = txs->txs_firstdesc;; j = PCN_NEXTTX(j)) { | | 1349 | for (j = txs->txs_firstdesc;; j = PCN_NEXTTX(j)) { |
1350 | tmd = le32toh(sc->sc_txdescs[j].tmd1); | | 1350 | tmd = le32toh(sc->sc_txdescs[j].tmd1); |
1351 | if (tmd & LE_T1_ERR) { | | 1351 | if (tmd & LE_T1_ERR) { |
1352 | ifp->if_oerrors++; | | 1352 | if_statinc(ifp, if_oerrors); |
1353 | if (sc->sc_swstyle == LE_B20_SSTYLE_PCNETPCI3) | | 1353 | if (sc->sc_swstyle == LE_B20_SSTYLE_PCNETPCI3) |
1354 | tmd2 = le32toh(sc->sc_txdescs[j].tmd0); | | 1354 | tmd2 = le32toh(sc->sc_txdescs[j].tmd0); |
1355 | else | | 1355 | else |
1356 | tmd2 = le32toh(sc->sc_txdescs[j].tmd2); | | 1356 | tmd2 = le32toh(sc->sc_txdescs[j].tmd2); |
1357 | if (tmd2 & LE_T2_UFLO) { | | 1357 | if (tmd2 & LE_T2_UFLO) { |
1358 | if (sc->sc_xmtsp < LE_C80_XMTSP_MAX) { | | 1358 | if (sc->sc_xmtsp < LE_C80_XMTSP_MAX) { |
1359 | sc->sc_xmtsp++; | | 1359 | sc->sc_xmtsp++; |
1360 | printf("%s: transmit " | | 1360 | printf("%s: transmit " |
1361 | "underrun; new threshold: " | | 1361 | "underrun; new threshold: " |
1362 | "%s\n", | | 1362 | "%s\n", |
1363 | device_xname(sc->sc_dev), | | 1363 | device_xname(sc->sc_dev), |
1364 | sc->sc_xmtsp_desc[ | | 1364 | sc->sc_xmtsp_desc[ |
1365 | sc->sc_xmtsp]); | | 1365 | sc->sc_xmtsp]); |
| @@ -1370,41 +1370,41 @@ pcn_txintr(struct pcn_softc *sc) | | | @@ -1370,41 +1370,41 @@ pcn_txintr(struct pcn_softc *sc) |
1370 | LE_C80_XMTFW(sc->sc_xmtfw)); | | 1370 | LE_C80_XMTFW(sc->sc_xmtfw)); |
1371 | pcn_csr_write(sc, LE_CSR5, | | 1371 | pcn_csr_write(sc, LE_CSR5, |
1372 | sc->sc_csr5); | | 1372 | sc->sc_csr5); |
1373 | } else { | | 1373 | } else { |
1374 | printf("%s: transmit " | | 1374 | printf("%s: transmit " |
1375 | "underrun\n", | | 1375 | "underrun\n", |
1376 | device_xname(sc->sc_dev)); | | 1376 | device_xname(sc->sc_dev)); |
1377 | } | | 1377 | } |
1378 | } else if (tmd2 & LE_T2_BUFF) { | | 1378 | } else if (tmd2 & LE_T2_BUFF) { |
1379 | printf("%s: transmit buffer error\n", | | 1379 | printf("%s: transmit buffer error\n", |
1380 | device_xname(sc->sc_dev)); | | 1380 | device_xname(sc->sc_dev)); |
1381 | } | | 1381 | } |
1382 | if (tmd2 & LE_T2_LCOL) | | 1382 | if (tmd2 & LE_T2_LCOL) |
1383 | ifp->if_collisions++; | | 1383 | if_statinc(ifp, if_collisions); |
1384 | if (tmd2 & LE_T2_RTRY) | | 1384 | if (tmd2 & LE_T2_RTRY) |
1385 | ifp->if_collisions += 16; | | 1385 | if_statadd(ifp, if_collisions, 16); |
1386 | goto next_packet; | | 1386 | goto next_packet; |
1387 | } | | 1387 | } |
1388 | if (j == txs->txs_lastdesc) | | 1388 | if (j == txs->txs_lastdesc) |
1389 | break; | | 1389 | break; |
1390 | } | | 1390 | } |
1391 | if (tmd1 & LE_T1_ONE) | | 1391 | if (tmd1 & LE_T1_ONE) |
1392 | ifp->if_collisions++; | | 1392 | if_statinc(ifp, if_collisions); |
1393 | else if (tmd & LE_T1_MORE) { | | 1393 | else if (tmd & LE_T1_MORE) { |
1394 | /* Real number is unknown. */ | | 1394 | /* Real number is unknown. */ |
1395 | ifp->if_collisions += 2; | | 1395 | if_statadd(ifp, if_collisions, 2); |
1396 | } | | 1396 | } |
1397 | ifp->if_opackets++; | | 1397 | if_statinc(ifp, if_opackets); |
1398 | next_packet: | | 1398 | next_packet: |
1399 | sc->sc_txfree += txs->txs_dmamap->dm_nsegs; | | 1399 | sc->sc_txfree += txs->txs_dmamap->dm_nsegs; |
1400 | bus_dmamap_sync(sc->sc_dmat, txs->txs_dmamap, | | 1400 | bus_dmamap_sync(sc->sc_dmat, txs->txs_dmamap, |
1401 | 0, txs->txs_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); | | 1401 | 0, txs->txs_dmamap->dm_mapsize, BUS_DMASYNC_POSTWRITE); |
1402 | bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap); | | 1402 | bus_dmamap_unload(sc->sc_dmat, txs->txs_dmamap); |
1403 | m_freem(txs->txs_mbuf); | | 1403 | m_freem(txs->txs_mbuf); |
1404 | txs->txs_mbuf = NULL; | | 1404 | txs->txs_mbuf = NULL; |
1405 | } | | 1405 | } |
1406 | | | 1406 | |
1407 | /* Update the dirty transmit buffer pointer. */ | | 1407 | /* Update the dirty transmit buffer pointer. */ |
1408 | sc->sc_txsdirty = i; | | 1408 | sc->sc_txsdirty = i; |
1409 | | | 1409 | |
1410 | /* | | 1410 | /* |
| @@ -1451,27 +1451,27 @@ pcn_rxintr(struct pcn_softc *sc) | | | @@ -1451,27 +1451,27 @@ pcn_rxintr(struct pcn_softc *sc) |
1451 | /* Make sure the packet is in a single buffer. */ | | 1451 | /* Make sure the packet is in a single buffer. */ |
1452 | if ((rmd1 & (LE_R1_STP | LE_R1_ENP)) != | | 1452 | if ((rmd1 & (LE_R1_STP | LE_R1_ENP)) != |
1453 | (LE_R1_STP | LE_R1_ENP)) { | | 1453 | (LE_R1_STP | LE_R1_ENP)) { |
1454 | printf("%s: packet spilled into next buffer\n", | | 1454 | printf("%s: packet spilled into next buffer\n", |
1455 | device_xname(sc->sc_dev)); | | 1455 | device_xname(sc->sc_dev)); |
1456 | return 1; /* pcn_intr() will re-init */ | | 1456 | return 1; /* pcn_intr() will re-init */ |
1457 | } | | 1457 | } |
1458 | | | 1458 | |
1459 | /* | | 1459 | /* |
1460 | * If the packet had an error, simple recycle the | | 1460 | * If the packet had an error, simple recycle the |
1461 | * buffer. | | 1461 | * buffer. |
1462 | */ | | 1462 | */ |
1463 | if (rmd1 & LE_R1_ERR) { | | 1463 | if (rmd1 & LE_R1_ERR) { |
1464 | ifp->if_ierrors++; | | 1464 | if_statinc(ifp, if_ierrors); |
1465 | /* | | 1465 | /* |
1466 | * If we got an overflow error, chances | | 1466 | * If we got an overflow error, chances |
1467 | * are there will be a CRC error. In | | 1467 | * are there will be a CRC error. In |
1468 | * this case, just print the overflow | | 1468 | * this case, just print the overflow |
1469 | * error, and skip the others. | | 1469 | * error, and skip the others. |
1470 | */ | | 1470 | */ |
1471 | if (rmd1 & LE_R1_OFLO) | | 1471 | if (rmd1 & LE_R1_OFLO) |
1472 | printf("%s: overflow error\n", | | 1472 | printf("%s: overflow error\n", |
1473 | device_xname(sc->sc_dev)); | | 1473 | device_xname(sc->sc_dev)); |
1474 | else { | | 1474 | else { |
1475 | #define PRINTIT(x, str) \ | | 1475 | #define PRINTIT(x, str) \ |
1476 | if (rmd1 & (x)) \ | | 1476 | if (rmd1 & (x)) \ |
1477 | printf("%s: %s\n", \ | | 1477 | printf("%s: %s\n", \ |
| @@ -1520,27 +1520,27 @@ pcn_rxintr(struct pcn_softc *sc) | | | @@ -1520,27 +1520,27 @@ pcn_rxintr(struct pcn_softc *sc) |
1520 | if (m == NULL) | | 1520 | if (m == NULL) |
1521 | goto dropit; | | 1521 | goto dropit; |
1522 | m->m_data += 2; | | 1522 | m->m_data += 2; |
1523 | memcpy(mtod(m, void *), | | 1523 | memcpy(mtod(m, void *), |
1524 | mtod(rxs->rxs_mbuf, void *), len); | | 1524 | mtod(rxs->rxs_mbuf, void *), len); |
1525 | PCN_INIT_RXDESC(sc, i); | | 1525 | PCN_INIT_RXDESC(sc, i); |
1526 | bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, | | 1526 | bus_dmamap_sync(sc->sc_dmat, rxs->rxs_dmamap, 0, |
1527 | rxs->rxs_dmamap->dm_mapsize, | | 1527 | rxs->rxs_dmamap->dm_mapsize, |
1528 | BUS_DMASYNC_PREREAD); | | 1528 | BUS_DMASYNC_PREREAD); |
1529 | } else { | | 1529 | } else { |
1530 | m = rxs->rxs_mbuf; | | 1530 | m = rxs->rxs_mbuf; |
1531 | if (pcn_add_rxbuf(sc, i) != 0) { | | 1531 | if (pcn_add_rxbuf(sc, i) != 0) { |
1532 | dropit: | | 1532 | dropit: |
1533 | ifp->if_ierrors++; | | 1533 | if_statinc(ifp, if_ierrors); |
1534 | PCN_INIT_RXDESC(sc, i); | | 1534 | PCN_INIT_RXDESC(sc, i); |
1535 | bus_dmamap_sync(sc->sc_dmat, | | 1535 | bus_dmamap_sync(sc->sc_dmat, |
1536 | rxs->rxs_dmamap, 0, | | 1536 | rxs->rxs_dmamap, 0, |
1537 | rxs->rxs_dmamap->dm_mapsize, | | 1537 | rxs->rxs_dmamap->dm_mapsize, |
1538 | BUS_DMASYNC_PREREAD); | | 1538 | BUS_DMASYNC_PREREAD); |
1539 | continue; | | 1539 | continue; |
1540 | } | | 1540 | } |
1541 | } | | 1541 | } |
1542 | | | 1542 | |
1543 | m_set_rcvif(m, ifp); | | 1543 | m_set_rcvif(m, ifp); |
1544 | m->m_pkthdr.len = m->m_len = len; | | 1544 | m->m_pkthdr.len = m->m_len = len; |
1545 | | | 1545 | |
1546 | /* Pass it on. */ | | 1546 | /* Pass it on. */ |