int octeon_eth_send_makecmd_gbuf(struct octeon_eth_softc *sc, struct mbuf *m0, uint64_t *gbuf, int *rsegs) { struct mbuf *m; int segs = 0; uint32_t laddr, rlen, nlen; for (m = m0; m != NULL; m = m->m_next) { if (__predict_false(m->m_len == 0)) continue; #if 0 OCTEON_ETH_KASSERT(((uint32_t)m->m_data & (PAGE_SIZE - 1)) == (kvtophys((vaddr_t)m->m_data) & (PAGE_SIZE - 1))); #endif /* * aligned 4k */ laddr = (uintptr_t)m->m_data & (PAGE_SIZE - 1); if (laddr + m->m_len > PAGE_SIZE) { /* XXX */ rlen = PAGE_SIZE - laddr; nlen = m->m_len - rlen; *(gbuf + segs) = octeon_eth_send_makecmd_w1(rlen, KVTOPHYS(m->m_data)); segs++; if (segs > 63) { return 1; } /* XXX */ } else { rlen = 0; nlen = m->m_len; } *(gbuf + segs) = octeon_eth_send_makecmd_w1(nlen, KVTOPHYS((caddr_t)m->m_data + rlen)); segs++; if (segs > 63) { return 1; } } OCTEON_ETH_KASSERT(m == NULL); *rsegs = segs; return 0; }
int octeon_eth_send_makecmd(struct octeon_eth_softc *sc, struct mbuf *m, uint64_t *gbuf, uint64_t *rpko_cmd_w0, uint64_t *rpko_cmd_w1) { uint64_t pko_cmd_w0, pko_cmd_w1; int ipoffp1; int segs; int result = 0; if (octeon_eth_send_makecmd_gbuf(sc, m, gbuf, &segs)) { log(LOG_WARNING, "%s: large number of transmission" " data segments", sc->sc_dev.dv_xname); result = 1; goto done; } /* Get the IP packet offset for TCP/UDP checksum offloading. */ ipoffp1 = (m->m_pkthdr.csum_flags & (M_TCP_CSUM_OUT | M_UDP_CSUM_OUT)) ? (ETHER_HDR_LEN + 1) : 0; /* * segs == 1 -> link mode (single continuous buffer) * WORD1[size] is number of bytes pointed by segment * * segs > 1 -> gather mode (scatter-gather buffer) * WORD1[size] is number of segments */ pko_cmd_w0 = octeon_eth_send_makecmd_w0(sc->sc_fau_done.fd_regno, 0, m->m_pkthdr.len, segs, ipoffp1); pko_cmd_w1 = octeon_eth_send_makecmd_w1( (segs == 1) ? m->m_pkthdr.len : segs, (segs == 1) ? KVTOPHYS(m->m_data) : XKPHYS_TO_PHYS(gbuf)); *rpko_cmd_w0 = pko_cmd_w0; *rpko_cmd_w1 = pko_cmd_w1; done: return result; }
int octeon_eth_send_makecmd_gbuf(struct octeon_eth_softc *sc, struct mbuf *m0, uint64_t *gbuf, int *rsegs) { struct mbuf *m; int segs = 0; for (m = m0; m != NULL; m = m->m_next) { if (__predict_false(m->m_len == 0)) continue; if (segs >= OCTEON_POOL_SIZE_SG / sizeof(uint64_t)) return 1; gbuf[segs] = octeon_eth_send_makecmd_w1(m->m_len, KVTOPHYS(m->m_data)); segs++; } *rsegs = segs; return 0; }
int octeon_eth_send_makecmd(struct octeon_eth_softc *sc, struct mbuf *m, uint64_t *gbuf, uint64_t *rpko_cmd_w0, uint64_t *rpko_cmd_w1) { uint64_t pko_cmd_w0, pko_cmd_w1; int segs; int result = 0; if (octeon_eth_send_makecmd_gbuf(sc, m, gbuf, &segs)) { log(LOG_WARNING, "%s: large number of transmission" " data segments", sc->sc_dev.dv_xname); result = 1; goto done; } /* * segs == 1 -> link mode (single continuous buffer) * WORD1[size] is number of bytes pointed by segment * * segs > 1 -> gather mode (scatter-gather buffer) * WORD1[size] is number of segments */ pko_cmd_w0 = octeon_eth_send_makecmd_w0(sc->sc_fau_done.fd_regno, 0, m->m_pkthdr.len, segs); pko_cmd_w1 = octeon_eth_send_makecmd_w1( (segs == 1) ? m->m_pkthdr.len : segs, (segs == 1) ? KVTOPHYS(m->m_data) : XKPHYS_TO_PHYS(gbuf)); *rpko_cmd_w0 = pko_cmd_w0; *rpko_cmd_w1 = pko_cmd_w1; done: return result; }