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:
parent
06eace6376
commit
27d1c65e8e
@ -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 {
|
||||||
|
@ -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, ×tamp, 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;
|
||||||
|
Loading…
Reference in New Issue
Block a user