cxgb(4): add knob to get packet timestamps from the hardware.

The T3 ASIC can provide an incoming packet's timestamp instead of its RSS hash.
The timestamp is just a counter running off the card's clock.  With a 175MHz
clock an increment represents ~5.7ns and the 32 bit value wraps around in ~25s.

# sysctl -d dev.cxgbc.0.pkt_timestamp
dev.cxgbc.0.pkt_timestamp: provide packet timestamp instead of connection hash

# sysctl -d dev.cxgbc.0.core_clock
dev.cxgbc.0.core_clock: core clock frequency (in KHz)
# sysctl dev.cxgbc.0.core_clock
dev.cxgbc.0.core_clock: 175000
This commit is contained in:
Navdeep Parhar 2010-06-12 22:33:04 +00:00
parent 06eace6376
commit 27d1c65e8e
2 changed files with 53 additions and 16 deletions

View File

@ -388,6 +388,8 @@ struct adapter {
char reglockbuf[ADAPTER_LOCK_NAME_LEN]; char reglockbuf[ADAPTER_LOCK_NAME_LEN];
char mdiolockbuf[ADAPTER_LOCK_NAME_LEN]; char mdiolockbuf[ADAPTER_LOCK_NAME_LEN];
char elmerlockbuf[ADAPTER_LOCK_NAME_LEN]; char elmerlockbuf[ADAPTER_LOCK_NAME_LEN];
int timestamp;
}; };
struct t3_rx_mode { struct t3_rx_mode {

View File

@ -2961,6 +2961,7 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
struct lro_ctrl *lro_ctrl = &qs->lro.ctrl; struct lro_ctrl *lro_ctrl = &qs->lro.ctrl;
struct mbuf *offload_mbufs[RX_BUNDLE_SIZE]; struct mbuf *offload_mbufs[RX_BUNDLE_SIZE];
int ngathered = 0; int ngathered = 0;
struct t3_mbuf_hdr *mh = &rspq->rspq_mh;
#ifdef DEBUG #ifdef DEBUG
static int last_holdoff = 0; static int last_holdoff = 0;
if (cxgb_debug && rspq->holdoff_tmr != last_holdoff) { if (cxgb_debug && rspq->holdoff_tmr != last_holdoff) {
@ -2984,9 +2985,9 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
if (cxgb_debug) if (cxgb_debug)
printf("async notification\n"); printf("async notification\n");
if (rspq->rspq_mh.mh_head == NULL) { if (mh->mh_head == NULL) {
rspq->rspq_mh.mh_head = m_gethdr(M_DONTWAIT, MT_DATA); mh->mh_head = m_gethdr(M_DONTWAIT, MT_DATA);
m = rspq->rspq_mh.mh_head; m = mh->mh_head;
} else { } else {
m = m_gethdr(M_DONTWAIT, MT_DATA); m = m_gethdr(M_DONTWAIT, MT_DATA);
} }
@ -3005,27 +3006,28 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
DPRINTF("IMM DATA VALID opcode=0x%x rspq->cidx=%d\n", DPRINTF("IMM DATA VALID opcode=0x%x rspq->cidx=%d\n",
r->rss_hdr.opcode, rspq->cidx); r->rss_hdr.opcode, rspq->cidx);
if (rspq->rspq_mh.mh_head == NULL) if (mh->mh_head == NULL)
rspq->rspq_mh.mh_head = m_gethdr(M_DONTWAIT, MT_DATA); mh->mh_head = m_gethdr(M_DONTWAIT, MT_DATA);
else else
m = m_gethdr(M_DONTWAIT, MT_DATA); m = m_gethdr(M_DONTWAIT, MT_DATA);
if (rspq->rspq_mh.mh_head == NULL && m == NULL) { if (mh->mh_head == NULL && m == NULL) {
no_mem: no_mem:
rspq->next_holdoff = NOMEM_INTR_DELAY; rspq->next_holdoff = NOMEM_INTR_DELAY;
budget_left--; budget_left--;
break; break;
} }
get_imm_packet(adap, r, rspq->rspq_mh.mh_head); get_imm_packet(adap, r, mh->mh_head);
eop = 1; eop = 1;
rspq->imm_data++; rspq->imm_data++;
} else if (r->len_cq) { } else if (r->len_cq) {
int drop_thresh = eth ? SGE_RX_DROP_THRES : 0; int drop_thresh = eth ? SGE_RX_DROP_THRES : 0;
eop = get_packet(adap, drop_thresh, qs, &rspq->rspq_mh, r); eop = get_packet(adap, drop_thresh, qs, mh, r);
if (eop) { if (eop) {
rspq->rspq_mh.mh_head->m_flags |= M_FLOWID; if (r->rss_hdr.hash_type && !adap->timestamp)
rspq->rspq_mh.mh_head->m_pkthdr.flowid = rss_hash; mh->mh_head->m_flags |= M_FLOWID;
mh->mh_head->m_pkthdr.flowid = rss_hash;
} }
ethpad = 2; ethpad = 2;
@ -3050,20 +3052,20 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
rspq->credits = 0; rspq->credits = 0;
} }
if (!eth && eop) { if (!eth && eop) {
rspq->rspq_mh.mh_head->m_pkthdr.csum_data = rss_csum; mh->mh_head->m_pkthdr.csum_data = rss_csum;
/* /*
* XXX size mismatch * XXX size mismatch
*/ */
m_set_priority(rspq->rspq_mh.mh_head, rss_hash); m_set_priority(mh->mh_head, rss_hash);
ngathered = rx_offload(&adap->tdev, rspq, ngathered = rx_offload(&adap->tdev, rspq,
rspq->rspq_mh.mh_head, offload_mbufs, ngathered); mh->mh_head, offload_mbufs, ngathered);
rspq->rspq_mh.mh_head = NULL; mh->mh_head = NULL;
DPRINTF("received offload packet\n"); DPRINTF("received offload packet\n");
} else if (eth && eop) { } else if (eth && eop) {
struct mbuf *m = rspq->rspq_mh.mh_head; struct mbuf *m = mh->mh_head;
t3_rx_eth(adap, rspq, m, ethpad); t3_rx_eth(adap, rspq, m, ethpad);
@ -3092,7 +3094,7 @@ process_responses(adapter_t *adap, struct sge_qset *qs, int budget)
struct ifnet *ifp = m->m_pkthdr.rcvif; struct ifnet *ifp = m->m_pkthdr.rcvif;
(*ifp->if_input)(ifp, m); (*ifp->if_input)(ifp, m);
} }
rspq->rspq_mh.mh_head = NULL; mh->mh_head = NULL;
} }
__refill_fl_lt(adap, &qs->fl[0], 32); __refill_fl_lt(adap, &qs->fl[0], 32);
@ -3459,6 +3461,29 @@ t3_set_coalesce_usecs(SYSCTL_HANDLER_ARGS)
return (0); return (0);
} }
static int
t3_pkt_timestamp(SYSCTL_HANDLER_ARGS)
{
adapter_t *sc = arg1;
int rc, timestamp;
if ((sc->flags & FULL_INIT_DONE) == 0)
return (ENXIO);
timestamp = sc->timestamp;
rc = sysctl_handle_int(oidp, &timestamp, arg2, req);
if (rc != 0)
return (rc);
if (timestamp != sc->timestamp) {
t3_set_reg_field(sc, A_TP_PC_CONFIG2, F_ENABLERXPKTTMSTPRSS,
timestamp ? F_ENABLERXPKTTMSTPRSS : 0);
sc->timestamp = timestamp;
}
return (0);
}
void void
t3_add_attach_sysctls(adapter_t *sc) t3_add_attach_sysctls(adapter_t *sc)
@ -3493,6 +3518,10 @@ t3_add_attach_sysctls(adapter_t *sc)
"txq_overrun", "txq_overrun",
CTLFLAG_RD, &txq_fills, CTLFLAG_RD, &txq_fills,
0, "#times txq overrun"); 0, "#times txq overrun");
SYSCTL_ADD_INT(ctx, children, OID_AUTO,
"core_clock",
CTLFLAG_RD, &sc->params.vpd.cclk,
0, "core clock frequency (in KHz)");
} }
@ -3537,6 +3566,12 @@ t3_add_configured_sysctls(adapter_t *sc)
0, t3_set_coalesce_usecs, 0, t3_set_coalesce_usecs,
"I", "interrupt coalescing timer (us)"); "I", "interrupt coalescing timer (us)");
SYSCTL_ADD_PROC(ctx, children, OID_AUTO,
"pkt_timestamp",
CTLTYPE_INT | CTLFLAG_RW, sc,
0, t3_pkt_timestamp,
"I", "provide packet timestamp instead of connection hash");
for (i = 0; i < sc->params.nports; i++) { for (i = 0; i < sc->params.nports; i++) {
struct port_info *pi = &sc->port[i]; struct port_info *pi = &sc->port[i];
struct sysctl_oid *poid; struct sysctl_oid *poid;