1/* 2 * Copyright (c) 1998-2002 Katsushi Kobayashi and Hidetoshi Shimokawa 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright --- 16 unchanged lines hidden (view full) --- 25 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 27 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 29 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * |
33 * $FreeBSD: head/sys/dev/firewire/fwohci.c 109892 2003-01-26 18:38:06Z simokawa $ |
34 * 35 */ 36 37#define ATRQ_CH 0 38#define ATRS_CH 1 39#define ARRQ_CH 2 40#define ARRS_CH 3 41#define ITX_CH 4 --- 781 unchanged lines hidden (view full) --- 823 ohcifp->mode.common.spd = 0; 824 ohcifp->mode.common.tcode = FWOHCITCODE_PHY; 825 } else { 826 ohcifp->mode.asycomm.dst = ntohs(fp->mode.hdr.dst); 827 ohcifp->mode.asycomm.srcbus = OHCI_ASYSRCBUS; 828 ohcifp->mode.asycomm.tlrt |= FWRETRY_X; 829 } 830 db = &db_tr->db[0]; |
831 db->db.desc.control = OHCI_OUTPUT_MORE | OHCI_KEY_ST2; 832 db->db.desc.reqcount = hdr_len; |
833 db->db.desc.status = 0; 834/* Specify bound timer of asy. responce */ 835 if(&sc->atrs == dbch){ 836 db->db.desc.count 837 = (OREAD(sc, OHCI_CYCLETIMER) >> 12) + (1 << 13); 838 } 839 840 db_tr->dbcnt = 2; 841 db = &db_tr->db[db_tr->dbcnt]; 842 if(len > hdr_off){ 843 if (xfer->mbuf == NULL) { 844 db->db.desc.addr 845 = vtophys(xfer->send.buf + xfer->send.off) + hdr_off; |
846 db->db.desc.control = OHCI_OUTPUT_MORE; 847 db->db.desc.reqcount = len - hdr_off; |
848 db->db.desc.status = 0; 849 850 db_tr->dbcnt++; 851 } else { 852 int mchain=0; 853 /* XXX we assume mbuf chain is shorter than ndesc */ 854 for (m = xfer->mbuf; m != NULL; m = m->m_next) { 855 if (m->m_len == 0) 856 /* unrecoverable error could occur. */ 857 continue; 858 mchain++; 859 if (db_tr->dbcnt >= dbch->ndesc) 860 continue; 861 db->db.desc.addr 862 = vtophys(mtod(m, caddr_t)); |
863 db->db.desc.control = OHCI_OUTPUT_MORE; 864 db->db.desc.reqcount = m->m_len; |
865 db->db.desc.status = 0; 866 db++; 867 db_tr->dbcnt++; 868 } 869 if (mchain > dbch->ndesc - 2) 870 device_printf(sc->fc.dev, 871 "dbch->ndesc(%d) is too small for" 872 " mbuf chain(%d), trancated.\n", 873 dbch->ndesc, mchain); 874 } 875 } 876 if (maxdesc < db_tr->dbcnt) { 877 maxdesc = db_tr->dbcnt; 878 if (bootverbose) 879 device_printf(sc->fc.dev, "maxdesc: %d\n", maxdesc); 880 } 881 /* last db */ 882 LAST_DB(db_tr, db); |
883 db->db.desc.control |= OHCI_OUTPUT_LAST |
884 | OHCI_INTERRUPT_ALWAYS 885 | OHCI_BRANCH_ALWAYS; 886 db->db.desc.depend = vtophys(STAILQ_NEXT(db_tr, link)->db); 887 888 if(fsegment == -1 ) 889 fsegment = db_tr->dbcnt; 890 if (dbch->pdb_tr != NULL) { 891 LAST_DB(dbch->pdb_tr, db); --- 403 unchanged lines hidden (view full) --- 1295 1296static int 1297fwohci_tx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1298{ 1299 int err = 0; 1300 int idb, z, i, dmach = 0; 1301 u_int32_t off = NULL; 1302 struct fwohcidb_tr *db_tr; |
1303 volatile struct fwohcidb *db; |
1304 1305 if(!(dbch->xferq.flag & FWXFERQ_EXTBUF)){ 1306 err = EINVAL; 1307 return err; 1308 } 1309 z = dbch->ndesc; 1310 for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ 1311 if( &sc->it[dmach] == dbch){ --- 14 unchanged lines hidden (view full) --- 1326 db_tr = dbch->top; 1327 for( idb = 0 ; idb < dbch->ndb ; idb ++){ 1328 fwohci_add_tx_buf(db_tr, 1329 dbch->xferq.psize, dbch->xferq.flag, 1330 dbch->xferq.buf + dbch->xferq.psize * idb); 1331 if(STAILQ_NEXT(db_tr, link) == NULL){ 1332 break; 1333 } |
1334 db = db_tr->db; 1335 db[0].db.desc.depend = db[db_tr->dbcnt - 1].db.desc.depend |
1336 = vtophys(STAILQ_NEXT(db_tr, link)->db) | z; |
1337 if(dbch->xferq.flag & FWXFERQ_EXTBUF){ 1338 if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){ |
1339 db[db_tr->dbcnt - 1].db.desc.control |
1340 |= OHCI_INTERRUPT_ALWAYS; |
1341 /* OHCI 1.1 and above */ |
1342 db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 1343#if 0 1344 db[0].db.desc.depend &= ~0xf; 1345 db[db_tr->dbcnt - 1].db.desc.depend &= ~0xf; 1346#endif |
1347 } 1348 } 1349 db_tr = STAILQ_NEXT(db_tr, link); 1350 } 1351 dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend &= 0xfffffff0; 1352 return err; 1353} 1354 1355static int 1356fwohci_rx_enable(struct fwohci_softc *sc, struct fwohci_dbch *dbch) 1357{ 1358 int err = 0; |
1359 int idb, z, i, dmach = 0, ldesc; |
1360 u_int32_t off = NULL; 1361 struct fwohcidb_tr *db_tr; |
1362 volatile struct fwohcidb *db; |
1363 1364 z = dbch->ndesc; 1365 if(&sc->arrq == dbch){ 1366 off = OHCI_ARQOFF; 1367 }else if(&sc->arrs == dbch){ 1368 off = OHCI_ARSOFF; 1369 }else{ 1370 for(dmach = 0 ; dmach < sc->fc.nisodma ; dmach++){ --- 30 unchanged lines hidden (view full) --- 1401 fwohci_add_rx_buf(db_tr, 1402 dbch->xferq.psize, dbch->xferq.flag, 1403 dbch->xferq.buf + dbch->xferq.psize * idb, 1404 dbch->dummy + sizeof(u_int32_t) * idb); 1405 } 1406 if(STAILQ_NEXT(db_tr, link) == NULL){ 1407 break; 1408 } |
1409 db = db_tr->db; 1410 ldesc = db_tr->dbcnt - 1; 1411 db[ldesc].db.desc.depend |
1412 = vtophys(STAILQ_NEXT(db_tr, link)->db) | z; 1413 if(dbch->xferq.flag & FWXFERQ_EXTBUF){ 1414 if(((idb + 1 ) % dbch->xferq.bnpacket) == 0){ |
1415 db[ldesc].db.desc.control |
1416 |= OHCI_INTERRUPT_ALWAYS; |
1417 db[ldesc].db.desc.depend &= ~0xf; |
1418 } 1419 } 1420 db_tr = STAILQ_NEXT(db_tr, link); 1421 } 1422 dbch->bottom->db[db_tr->dbcnt - 1].db.desc.depend &= 0xfffffff0; 1423 dbch->buf_offset = 0; 1424 if(dbch->xferq.flag & FWXFERQ_STREAM){ 1425 return err; --- 54 unchanged lines hidden (view full) --- 1480 fwohci_db_init(dbch); 1481 if ((dbch->flags & FWOHCI_DBCH_INIT) == 0) 1482 return ENOMEM; 1483 err = fwohci_tx_enable(sc, dbch); 1484 } 1485 if(err) 1486 return err; 1487 |
1488 ldesc = dbch->ndesc - 1; |
1489 s = splfw(); 1490 prev = STAILQ_LAST(&it->stdma, fw_bulkxfer, link); 1491 while ((chunk = STAILQ_FIRST(&it->stvalid)) != NULL) { 1492 volatile struct fwohcidb *db; 1493 1494 fwohci_txbufdb(sc, dmach, chunk); |
1495#if 0 |
1496 db = ((struct fwohcidb_tr *)(chunk->end))->db; 1497 db[ldesc].db.desc.status = db[0].db.desc.status = 0; 1498 db[ldesc].db.desc.count = db[0].db.desc.count = 0; 1499 db[ldesc].db.desc.depend &= ~0xf; 1500 db[0].db.desc.depend &= ~0xf; |
1501#endif |
1502 if (prev != NULL) { 1503 db = ((struct fwohcidb_tr *)(prev->end))->db; |
1504 db[ldesc].db.desc.control |= OHCI_BRANCH_ALWAYS; 1505#if 0 /* if bulkxfer->npacket changes */ |
1506 db[ldesc].db.desc.depend = db[0].db.desc.depend = 1507 vtophys(((struct fwohcidb_tr *) 1508 (chunk->start))->db) | dbch->ndesc; |
1509#else 1510 db[0].db.desc.depend |= dbch->ndesc; 1511 db[ldesc].db.desc.depend |= dbch->ndesc; 1512#endif |
1513 } 1514 STAILQ_REMOVE_HEAD(&it->stvalid, link); 1515 STAILQ_INSERT_TAIL(&it->stdma, chunk, link); 1516 prev = chunk; 1517 } 1518 splx(s); 1519 stat = OREAD(sc, OHCI_ITCTL(dmach)); 1520 if (stat & (OHCI_CNTL_DMA_ACTIVE | OHCI_CNTL_CYCMATCH_S)) --- 100 unchanged lines hidden (view full) --- 1621 while ((chunk = STAILQ_FIRST(&ir->stfree)) != NULL) { 1622 volatile struct fwohcidb *db; 1623 1624 db = ((struct fwohcidb_tr *)(chunk->end))->db; 1625 db[ldesc].db.desc.status = db[ldesc].db.desc.count = 0; 1626 db[ldesc].db.desc.depend &= ~0xf; 1627 if (prev != NULL) { 1628 db = ((struct fwohcidb_tr *)(prev->end))->db; |
1629#if 0 |
1630 db[ldesc].db.desc.depend = 1631 vtophys(((struct fwohcidb_tr *) 1632 (chunk->start))->db) | dbch->ndesc; |
1633#else 1634 db[ldesc].db.desc.depend |= dbch->ndesc; 1635#endif |
1636 } 1637 STAILQ_REMOVE_HEAD(&ir->stfree, link); 1638 STAILQ_INSERT_TAIL(&ir->stdma, chunk, link); 1639 prev = chunk; 1640 } 1641 splx(s); 1642 stat = OREAD(sc, OHCI_IRCTL(dmach)); 1643 if (stat & OHCI_CNTL_DMA_ACTIVE) --- 575 unchanged lines hidden (view full) --- 2219 "INT", 2220 "BR ", 2221 "len", 2222 "Addr", 2223 "Depend", 2224 "Stat", 2225 "Cnt"); 2226 for( i = 0 ; i <= max ; i ++){ |
2227 key = db[i].db.desc.control & OHCI_KEY_MASK; |
2228#if __FreeBSD_version >= 500000 2229 printf("%08tx %s %s %s %s %5d %08x %08x %04x:%04x", 2230#else 2231 printf("%08x %s %s %s %s %5d %08x %08x %04x:%04x", 2232#endif 2233 vtophys(&db[i]), |
2234 dbcode[(db[i].db.desc.control >> 12) & 0xf], 2235 dbkey[(db[i].db.desc.control >> 8) & 0x7], 2236 dbcond[(db[i].db.desc.control >> 4) & 0x3], 2237 dbcond[(db[i].db.desc.control >> 2) & 0x3], 2238 db[i].db.desc.reqcount, |
2239 db[i].db.desc.addr, 2240 db[i].db.desc.depend, 2241 db[i].db.desc.status, 2242 db[i].db.desc.count); 2243 stat = db[i].db.desc.status; 2244 if(stat & 0xff00){ 2245 printf(" %s%s%s%s%s%s %s(%x)\n", 2246 stat & OHCI_CNTL_DMA_RUN ? "RUN," : "", --- 13 unchanged lines hidden (view full) --- 2260 db[i+1].db.immed[0], 2261 db[i+1].db.immed[1], 2262 db[i+1].db.immed[2], 2263 db[i+1].db.immed[3]); 2264 } 2265 if(key == OHCI_KEY_DEVICE){ 2266 return; 2267 } |
2268 if((db[i].db.desc.control & OHCI_BRANCH_MASK) |
2269 == OHCI_BRANCH_ALWAYS){ 2270 return; 2271 } |
2272 if((db[i].db.desc.control & OHCI_CMD_MASK) |
2273 == OHCI_OUTPUT_LAST){ 2274 return; 2275 } |
2276 if((db[i].db.desc.control & OHCI_CMD_MASK) |
2277 == OHCI_INPUT_LAST){ 2278 return; 2279 } 2280 if(key == OHCI_KEY_ST2 ){ 2281 i++; 2282 } 2283 } 2284 return; --- 22 unchanged lines hidden (view full) --- 2307#endif 2308} 2309 2310void 2311fwohci_txbufdb(struct fwohci_softc *sc, int dmach, struct fw_bulkxfer *bulkxfer) 2312{ 2313 struct fwohcidb_tr *db_tr, *fdb_tr; 2314 struct fwohci_dbch *dbch; |
2315 volatile struct fwohcidb *db; |
2316 struct fw_pkt *fp; 2317 volatile struct fwohci_txpkthdr *ohcifp; 2318 unsigned short chtag; 2319 int idb; 2320 2321 dbch = &sc->it[dmach]; 2322 chtag = sc->it[dmach].xferq.flag & 0xff; 2323 2324 db_tr = (struct fwohcidb_tr *)(bulkxfer->start); 2325 fdb_tr = (struct fwohcidb_tr *)(bulkxfer->end); 2326/* 2327device_printf(sc->fc.dev, "DB %08x %08x %08x\n", bulkxfer, vtophys(db_tr->db), vtophys(fdb_tr->db)); 2328*/ 2329 for( idb = 0 ; idb < bulkxfer->npacket ; idb ++){ |
2330 db = db_tr->db; 2331#if 0 2332 db[0].db.desc.control 2333 = OHCI_OUTPUT_MORE | OHCI_KEY_ST2; 2334 db[0].db.desc.reqcount = 8; 2335#endif |
2336 fp = (struct fw_pkt *)db_tr->buf; |
2337 ohcifp = (volatile struct fwohci_txpkthdr *) db[1].db.immed; |
2338 ohcifp->mode.ld[0] = ntohl(fp->mode.ld[0]); 2339 ohcifp->mode.stream.len = ntohs(fp->mode.stream.len); 2340 ohcifp->mode.stream.chtag = chtag; 2341 ohcifp->mode.stream.tcode = 0xa; 2342 ohcifp->mode.stream.spd = 0; 2343 |
2344 db[2].db.desc.reqcount = ntohs(fp->mode.stream.len); 2345 db[2].db.desc.status = 0; 2346 db[2].db.desc.count = 0; 2347#if 0 /* if bulkxfer->npackets changes */ 2348 db[2].db.desc.control = OHCI_OUTPUT_LAST |
2349 | OHCI_UPDATE |
2350 | OHCI_BRANCH_ALWAYS; 2351 db[0].db.desc.depend = 2352 = db[dbch->ndesc - 1].db.desc.depend |
2353 = vtophys(STAILQ_NEXT(db_tr, link)->db) | dbch->ndesc; |
2354#else 2355 db[0].db.desc.depend |= dbch->ndesc; 2356 db[dbch->ndesc - 1].db.desc.depend |= dbch->ndesc; 2357#endif |
2358 bulkxfer->end = (caddr_t)db_tr; 2359 db_tr = STAILQ_NEXT(db_tr, link); 2360 } |
2361 db = ((struct fwohcidb_tr *)bulkxfer->end)->db; 2362 db[0].db.desc.depend &= ~0xf; 2363 db[dbch->ndesc - 1].db.desc.depend &= ~0xf; 2364#if 0 /* if bulkxfer->npackets changes */ 2365 db[dbch->ndesc - 1].db.desc.control |= OHCI_INTERRUPT_ALWAYS; |
2366 /* OHCI 1.1 and above */ |
2367 db[0].db.desc.control |= OHCI_INTERRUPT_ALWAYS; 2368#endif 2369/* |
2370 db_tr = (struct fwohcidb_tr *)bulkxfer->start; 2371 fdb_tr = (struct fwohcidb_tr *)bulkxfer->end; |
2372device_printf(sc->fc.dev, "DB %08x %3d %08x %08x\n", bulkxfer, bulkxfer->npacket, vtophys(db_tr->db), vtophys(fdb_tr->db)); 2373*/ 2374 return; 2375} 2376 2377static int 2378fwohci_add_tx_buf(struct fwohcidb_tr *db_tr, unsigned short size, 2379 int mode, void *buf) 2380{ 2381 volatile struct fwohcidb *db = db_tr->db; 2382 int err = 0; 2383 if(buf == 0){ 2384 err = EINVAL; 2385 return err; 2386 } 2387 db_tr->buf = buf; 2388 db_tr->dbcnt = 3; 2389 db_tr->dummy = NULL; 2390 |
2391 db[0].db.desc.control = OHCI_OUTPUT_MORE | OHCI_KEY_ST2; 2392 db[0].db.desc.reqcount = 8; |
2393 db[2].db.desc.addr = vtophys(buf) + sizeof(u_int32_t); |
2394 db[2].db.desc.control = 2395 OHCI_OUTPUT_LAST | OHCI_UPDATE | OHCI_BRANCH_ALWAYS; 2396#if 1 |
2397 db[0].db.desc.status = 0; 2398 db[0].db.desc.count = 0; |
2399 db[2].db.desc.status = 0; 2400 db[2].db.desc.count = 0; |
2401#endif |
2402 if( mode & FWXFERQ_STREAM ){ |
2403 if(mode & FWXFERQ_PACKET ){ |
2404 db[2].db.desc.control |= OHCI_INTERRUPT_ALWAYS; |
2405 } |
2406 } else { 2407 printf("fwohci_add_tx_buf: who calls me?"); |
2408 } |
2409 return 1; 2410} 2411 2412int 2413fwohci_add_rx_buf(struct fwohcidb_tr *db_tr, unsigned short size, int mode, 2414 void *buf, void *dummy) 2415{ 2416 volatile struct fwohcidb *db = db_tr->db; --- 21 unchanged lines hidden (view full) --- 2438 db_tr->dummy = dummy; 2439 dsiz[0] = sizeof(u_int32_t); 2440 dsiz[1] = size; 2441 dbuf[0] = dummy; 2442 dbuf[1] = buf; 2443 } 2444 for(i = 0 ; i < db_tr->dbcnt ; i++){ 2445 db[i].db.desc.addr = vtophys(dbuf[i]) ; |
2446 db[i].db.desc.control = OHCI_INPUT_MORE; 2447 db[i].db.desc.reqcount = dsiz[i]; |
2448 if( mode & FWXFERQ_STREAM ){ |
2449 db[i].db.desc.control |= OHCI_UPDATE; |
2450 } 2451 db[i].db.desc.status = 0; 2452 db[i].db.desc.count = dsiz[i]; 2453 } 2454 if( mode & FWXFERQ_STREAM ){ |
2455 db[db_tr->dbcnt - 1].db.desc.control |= OHCI_INPUT_LAST; |
2456 if(mode & FWXFERQ_PACKET ){ |
2457 db[db_tr->dbcnt - 1].db.desc.control |
2458 |= OHCI_INTERRUPT_ALWAYS; 2459 } 2460 } |
2461 db[db_tr->dbcnt - 1].db.desc.control |= OHCI_BRANCH_ALWAYS; |
2462 return 1; 2463} 2464 2465static void 2466fwohci_ircv(struct fwohci_softc *sc, struct fwohci_dbch *dbch, int count) 2467{ 2468 struct fwohcidb_tr *db_tr = dbch->top, *odb_tr; 2469 struct firewire_comm *fc = (struct firewire_comm *)sc; --- 319 unchanged lines hidden --- |