Changeset View
Changeset View
Standalone View
Standalone View
sys/net/iflib.c
Show First 20 Lines • Show All 140 Lines • ▼ Show 20 Lines | |||||
struct iflib_rxq; | struct iflib_rxq; | ||||
typedef struct iflib_rxq *iflib_rxq_t; | typedef struct iflib_rxq *iflib_rxq_t; | ||||
struct iflib_fl; | struct iflib_fl; | ||||
typedef struct iflib_fl *iflib_fl_t; | typedef struct iflib_fl *iflib_fl_t; | ||||
struct iflib_ctx; | struct iflib_ctx; | ||||
static void iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid); | static void iru_init(if_rxd_update_t iru, iflib_rxq_t rxq, uint8_t flid); | ||||
static void iflib_timer(void *arg); | |||||
typedef struct iflib_filter_info { | typedef struct iflib_filter_info { | ||||
driver_filter_t *ifi_filter; | driver_filter_t *ifi_filter; | ||||
void *ifi_filter_arg; | void *ifi_filter_arg; | ||||
struct grouptask *ifi_task; | struct grouptask *ifi_task; | ||||
void *ifi_ctx; | void *ifi_ctx; | ||||
} *iflib_filter_info_t; | } *iflib_filter_info_t; | ||||
▲ Show 20 Lines • Show All 194 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
uint64_t ift_no_tx_dma_setup; | uint64_t ift_no_tx_dma_setup; | ||||
uint64_t ift_no_desc_avail; | uint64_t ift_no_desc_avail; | ||||
uint64_t ift_mbuf_defrag_failed; | uint64_t ift_mbuf_defrag_failed; | ||||
uint64_t ift_mbuf_defrag; | uint64_t ift_mbuf_defrag; | ||||
uint64_t ift_map_failed; | uint64_t ift_map_failed; | ||||
uint64_t ift_txd_encap_efbig; | uint64_t ift_txd_encap_efbig; | ||||
uint64_t ift_pullups; | uint64_t ift_pullups; | ||||
uint64_t ift_last_timer_tick; | |||||
struct mtx ift_mtx; | struct mtx ift_mtx; | ||||
struct mtx ift_db_mtx; | struct mtx ift_db_mtx; | ||||
/* constant values */ | /* constant values */ | ||||
if_ctx_t ift_ctx; | if_ctx_t ift_ctx; | ||||
struct ifmp_ring *ift_br; | struct ifmp_ring *ift_br; | ||||
struct grouptask ift_task; | struct grouptask ift_task; | ||||
▲ Show 20 Lines • Show All 544 Lines • ▼ Show 20 Lines | |||||
* methods should be handled by the individual drivers. | * methods should be handled by the individual drivers. | ||||
*/ | */ | ||||
static int | static int | ||||
iflib_netmap_txsync(struct netmap_kring *kring, int flags) | iflib_netmap_txsync(struct netmap_kring *kring, int flags) | ||||
{ | { | ||||
struct netmap_adapter *na = kring->na; | struct netmap_adapter *na = kring->na; | ||||
struct ifnet *ifp = na->ifp; | struct ifnet *ifp = na->ifp; | ||||
struct netmap_ring *ring = kring->ring; | struct netmap_ring *ring = kring->ring; | ||||
u_int nm_i; /* index into the netmap ring */ | u_int nm_i; /* index into the netmap kring */ | ||||
u_int nic_i; /* index into the NIC ring */ | u_int nic_i; /* index into the NIC ring */ | ||||
u_int n; | u_int n; | ||||
u_int const lim = kring->nkr_num_slots - 1; | u_int const lim = kring->nkr_num_slots - 1; | ||||
u_int const head = kring->rhead; | u_int const head = kring->rhead; | ||||
marius: Is there a particular reason for dropping this const? | |||||
Not Done Inline ActionsNo, this appears to have crept in from testing code. shurd: No, this appears to have crept in from testing code. | |||||
struct if_pkt_info pi; | struct if_pkt_info pi; | ||||
/* | /* | ||||
* interrupts on every tx packet are expensive so request | * interrupts on every tx packet are expensive so request | ||||
* them every half ring, or where NS_REPORT is set | * them every half ring, or where NS_REPORT is set | ||||
*/ | */ | ||||
u_int report_frequency = kring->nkr_num_slots >> 1; | u_int report_frequency = kring->nkr_num_slots >> 1; | ||||
/* device-specific */ | /* device-specific */ | ||||
if_ctx_t ctx = ifp->if_softc; | if_ctx_t ctx = ifp->if_softc; | ||||
iflib_txq_t txq = &ctx->ifc_txqs[kring->ring_id]; | iflib_txq_t txq = &ctx->ifc_txqs[kring->ring_id]; | ||||
if (txq->ift_sds.ifsd_map) | if (txq->ift_sds.ifsd_map) | ||||
bus_dmamap_sync(txq->ift_desc_tag, txq->ift_ifdi->idi_map, | bus_dmamap_sync(txq->ift_desc_tag, txq->ift_ifdi->idi_map, | ||||
BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); | ||||
/* | /* | ||||
* First part: process new packets to send. | * First part: process new packets to send. | ||||
* nm_i is the current index in the netmap ring, | * nm_i is the current index in the netmap kring, | ||||
* nic_i is the corresponding index in the NIC ring. | * nic_i is the corresponding index in the NIC ring. | ||||
* | * | ||||
* If we have packets to send (nm_i != head) | * If we have packets to send (nm_i != head) | ||||
* iterate over the netmap ring, fetch length and update | * iterate over the netmap ring, fetch length and update | ||||
* the corresponding slot in the NIC ring. Some drivers also | * the corresponding slot in the NIC ring. Some drivers also | ||||
* need to update the buffer's physical address in the NIC slot | * need to update the buffer's physical address in the NIC slot | ||||
* even NS_BUF_CHANGED is not set (PNMB computes the addresses). | * even NS_BUF_CHANGED is not set (PNMB computes the addresses). | ||||
* | * | ||||
* The netmap_reload_map() calls is especially expensive, | * The netmap_reload_map() calls is especially expensive, | ||||
* even when (as in this case) the tag is 0, so do only | * even when (as in this case) the tag is 0, so do only | ||||
* when the buffer has actually changed. | * when the buffer has actually changed. | ||||
* | * | ||||
* If possible do not set the report/intr bit on all slots, | * If possible do not set the report/intr bit on all slots, | ||||
* but only a few times per ring or when NS_REPORT is set. | * but only a few times per ring or when NS_REPORT is set. | ||||
* | * | ||||
* Finally, on 10G and faster drivers, it might be useful | * Finally, on 10G and faster drivers, it might be useful | ||||
* to prefetch the next slot and txr entry. | * to prefetch the next slot and txr entry. | ||||
*/ | */ | ||||
nm_i = netmap_idx_n2k(kring, kring->nr_hwcur); | nm_i = kring->nr_hwcur; | ||||
if (nm_i != head) { /* we have new packets to send */ | if (nm_i != head) { /* we have new packets to send */ | ||||
pkt_info_zero(&pi); | pkt_info_zero(&pi); | ||||
pi.ipi_segs = txq->ift_segs; | pi.ipi_segs = txq->ift_segs; | ||||
pi.ipi_qsidx = kring->ring_id; | pi.ipi_qsidx = kring->ring_id; | ||||
nic_i = netmap_idx_k2n(kring, nm_i); | nic_i = netmap_idx_k2n(kring, nm_i); | ||||
__builtin_prefetch(&ring->slot[nm_i]); | __builtin_prefetch(&ring->slot[nm_i]); | ||||
__builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i]); | __builtin_prefetch(&txq->ift_sds.ifsd_m[nic_i]); | ||||
Show All 36 Lines | for (n = 0; nm_i != head; n++) { | ||||
/* make sure changes to the buffer are synced */ | /* make sure changes to the buffer are synced */ | ||||
bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_sds.ifsd_map[nic_i], | bus_dmamap_sync(txq->ift_ifdi->idi_tag, txq->ift_sds.ifsd_map[nic_i], | ||||
BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREWRITE); | ||||
} | } | ||||
slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); | slot->flags &= ~(NS_REPORT | NS_BUF_CHANGED); | ||||
nm_i = nm_next(nm_i, lim); | nm_i = nm_next(nm_i, lim); | ||||
nic_i = nm_next(nic_i, lim); | nic_i = nm_next(nic_i, lim); | ||||
} | } | ||||
kring->nr_hwcur = head; | kring->nr_hwcur = nm_i; | ||||
/* synchronize the NIC ring */ | /* synchronize the NIC ring */ | ||||
if (txq->ift_sds.ifsd_map) | if (txq->ift_sds.ifsd_map) | ||||
bus_dmamap_sync(txq->ift_desc_tag, txq->ift_ifdi->idi_map, | bus_dmamap_sync(txq->ift_desc_tag, txq->ift_ifdi->idi_map, | ||||
BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE); | ||||
/* (re)start the tx unit up to slot nic_i (excluded) */ | /* (re)start the tx unit up to slot nic_i (excluded) */ | ||||
ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, nic_i); | ctx->isc_txd_flush(ctx->ifc_softc, txq->ift_id, nic_i); | ||||
} | } | ||||
/* | /* | ||||
* Second part: reclaim buffers for completed transmissions. | * Second part: reclaim buffers for completed transmissions. | ||||
* | * | ||||
* If there are unclaimed buffers, attempt to reclaim them. | * If there are unclaimed buffers, attempt to reclaim them. | ||||
* If none are reclaimed, and TX IRQs are not in use, do an initial | * If none are reclaimed, and TX IRQs are not in use, do an initial | ||||
* minimal delay, then trigger the tx handler which will spin in the | * minimal delay, then trigger the tx handler which will spin in the | ||||
* group task queue. | * group task queue. | ||||
*/ | */ | ||||
if (kring->nr_hwtail != nm_prev(head, lim)) { | if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) { | ||||
if (iflib_tx_credits_update(ctx, txq)) { | if (iflib_tx_credits_update(ctx, txq)) { | ||||
/* some tx completed, increment avail */ | /* some tx completed, increment avail */ | ||||
nic_i = txq->ift_cidx_processed; | nic_i = txq->ift_cidx_processed; | ||||
kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim); | kring->nr_hwtail = nm_prev(netmap_idx_n2k(kring, nic_i), lim); | ||||
} | } | ||||
else { | |||||
if (!(ctx->ifc_flags & IFC_NETMAP_TX_IRQ)) { | |||||
DELAY(1); | |||||
GROUPTASK_ENQUEUE(&ctx->ifc_txqs[txq->ift_id].ift_task); | |||||
} | } | ||||
if (!(ctx->ifc_flags & IFC_NETMAP_TX_IRQ)) | |||||
if (kring->nr_hwtail != nm_prev(kring->nr_hwcur, lim)) { | |||||
callout_reset_on(&txq->ift_timer, hz < 2000 ? 1 : hz / 1000, | |||||
iflib_timer, txq, txq->ift_timer.c_cpu); | |||||
} | } | ||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Reconcile kernel and user view of the receive ring. | * Reconcile kernel and user view of the receive ring. | ||||
* Same as for the txsync, this routine must be efficient. | * Same as for the txsync, this routine must be efficient. | ||||
* The caller guarantees a single invocations, but races against | * The caller guarantees a single invocations, but races against | ||||
* the rest of the driver should be handled here. | * the rest of the driver should be handled here. | ||||
Show All 9 Lines | |||||
iflib_netmap_rxsync(struct netmap_kring *kring, int flags) | iflib_netmap_rxsync(struct netmap_kring *kring, int flags) | ||||
{ | { | ||||
struct netmap_adapter *na = kring->na; | struct netmap_adapter *na = kring->na; | ||||
struct netmap_ring *ring = kring->ring; | struct netmap_ring *ring = kring->ring; | ||||
uint32_t nm_i; /* index into the netmap ring */ | uint32_t nm_i; /* index into the netmap ring */ | ||||
uint32_t nic_i; /* index into the NIC ring */ | uint32_t nic_i; /* index into the NIC ring */ | ||||
u_int i, n; | u_int i, n; | ||||
u_int const lim = kring->nkr_num_slots - 1; | u_int const lim = kring->nkr_num_slots - 1; | ||||
u_int const head = netmap_idx_n2k(kring, kring->rhead); | u_int const head = kring->rhead; | ||||
int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; | int force_update = (flags & NAF_FORCE_READ) || kring->nr_kflags & NKR_PENDINTR; | ||||
struct if_rxd_info ri; | struct if_rxd_info ri; | ||||
struct ifnet *ifp = na->ifp; | struct ifnet *ifp = na->ifp; | ||||
if_ctx_t ctx = ifp->if_softc; | if_ctx_t ctx = ifp->if_softc; | ||||
iflib_rxq_t rxq = &ctx->ifc_rxqs[kring->ring_id]; | iflib_rxq_t rxq = &ctx->ifc_rxqs[kring->ring_id]; | ||||
iflib_fl_t fl = rxq->ifr_fl; | iflib_fl_t fl = rxq->ifr_fl; | ||||
if (head > lim) | if (head > lim) | ||||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | for (i = 0; i < rxq->ifr_nfl; i++) { | ||||
} | } | ||||
if (n) { /* update the state variables */ | if (n) { /* update the state variables */ | ||||
if (netmap_no_pendintr && !force_update) { | if (netmap_no_pendintr && !force_update) { | ||||
/* diagnostics */ | /* diagnostics */ | ||||
iflib_rx_miss ++; | iflib_rx_miss ++; | ||||
iflib_rx_miss_bufs += n; | iflib_rx_miss_bufs += n; | ||||
} | } | ||||
fl->ifl_cidx = nic_i; | fl->ifl_cidx = nic_i; | ||||
kring->nr_hwtail = netmap_idx_k2n(kring, nm_i); | kring->nr_hwtail = nm_i; | ||||
} | } | ||||
kring->nr_kflags &= ~NKR_PENDINTR; | kring->nr_kflags &= ~NKR_PENDINTR; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Second part: skip past packets that userspace has released. | * Second part: skip past packets that userspace has released. | ||||
* (kring->nr_hwcur to head excluded), | * (kring->nr_hwcur to head excluded), | ||||
* and make the buffers available for reception. | * and make the buffers available for reception. | ||||
* As usual nm_i is the index in the netmap ring, | * As usual nm_i is the index in the netmap ring, | ||||
* nic_i is the index in the NIC ring, and | * nic_i is the index in the NIC ring, and | ||||
* nm_i == (nic_i + kring->nkr_hwofs) % ring_size | * nm_i == (nic_i + kring->nkr_hwofs) % ring_size | ||||
*/ | */ | ||||
/* XXX not sure how this will work with multiple free lists */ | /* XXX not sure how this will work with multiple free lists */ | ||||
nm_i = netmap_idx_n2k(kring, kring->nr_hwcur); | nm_i = kring->nr_hwcur; | ||||
return (netmap_fl_refill(rxq, kring, nm_i, false)); | return (netmap_fl_refill(rxq, kring, nm_i, false)); | ||||
} | } | ||||
static void | static void | ||||
iflib_netmap_intr(struct netmap_adapter *na, int onoff) | iflib_netmap_intr(struct netmap_adapter *na, int onoff) | ||||
{ | { | ||||
struct ifnet *ifp = na->ifp; | struct ifnet *ifp = na->ifp; | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | iflib_netmap_rxq_init(if_ctx_t ctx, iflib_rxq_t rxq) | ||||
slot = netmap_reset(na, NR_RX, rxq->ifr_id, 0); | slot = netmap_reset(na, NR_RX, rxq->ifr_id, 0); | ||||
if (slot == NULL) | if (slot == NULL) | ||||
return; | return; | ||||
nm_i = netmap_idx_n2k(kring, 0); | nm_i = netmap_idx_n2k(kring, 0); | ||||
netmap_fl_refill(rxq, kring, nm_i, true); | netmap_fl_refill(rxq, kring, nm_i, true); | ||||
} | } | ||||
static void | |||||
iflib_netmap_timer_adjust(if_ctx_t ctx, uint16_t txqid, uint32_t *reset_on) | |||||
{ | |||||
struct netmap_kring *kring; | |||||
kring = NA(ctx->ifc_ifp)->tx_rings[txqid]; | |||||
if (kring->nr_hwcur != nm_next(kring->nr_hwtail, kring->nkr_num_slots - 1)) { | |||||
if (ctx->isc_txd_credits_update(ctx->ifc_softc, txqid, false)) | |||||
netmap_tx_irq(ctx->ifc_ifp, txqid); | |||||
if (!(ctx->ifc_flags & IFC_NETMAP_TX_IRQ)) { | |||||
if (hz < 2000) | |||||
*reset_on = 1; | |||||
else | |||||
*reset_on = hz / 1000; | |||||
} | |||||
} | |||||
} | |||||
#define iflib_netmap_detach(ifp) netmap_detach(ifp) | #define iflib_netmap_detach(ifp) netmap_detach(ifp) | ||||
#else | #else | ||||
#define iflib_netmap_txq_init(ctx, txq) | #define iflib_netmap_txq_init(ctx, txq) | ||||
#define iflib_netmap_rxq_init(ctx, rxq) | #define iflib_netmap_rxq_init(ctx, rxq) | ||||
#define iflib_netmap_detach(ifp) | #define iflib_netmap_detach(ifp) | ||||
#define iflib_netmap_attach(ctx) (0) | #define iflib_netmap_attach(ctx) (0) | ||||
#define netmap_rx_irq(ifp, qid, budget) (0) | #define netmap_rx_irq(ifp, qid, budget) (0) | ||||
#define netmap_tx_irq(ifp, qid) do {} while (0) | #define netmap_tx_irq(ifp, qid) do {} while (0) | ||||
#define iflib_netmap_timer_adjust(ctx, txqid, reset_on) | |||||
#endif | #endif | ||||
#if defined(__i386__) || defined(__amd64__) | #if defined(__i386__) || defined(__amd64__) | ||||
static __inline void | static __inline void | ||||
prefetch(void *x) | prefetch(void *x) | ||||
{ | { | ||||
__asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x)); | __asm volatile("prefetcht0 %0" :: "m" (*(unsigned long *)x)); | ||||
▲ Show 20 Lines • Show All 936 Lines • ▼ Show 20 Lines | |||||
* | * | ||||
*/ | */ | ||||
static void | static void | ||||
iflib_timer(void *arg) | iflib_timer(void *arg) | ||||
{ | { | ||||
iflib_txq_t txq = arg; | iflib_txq_t txq = arg; | ||||
if_ctx_t ctx = txq->ift_ctx; | if_ctx_t ctx = txq->ift_ctx; | ||||
if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; | if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; | ||||
uint64_t this_tick = ticks; | |||||
uint32_t reset_on = hz / 2; | |||||
if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) | if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) | ||||
return; | return; | ||||
/* | /* | ||||
** Check on the state of the TX queue(s), this | ** Check on the state of the TX queue(s), this | ||||
** can be done without the lock because its RO | ** can be done without the lock because its RO | ||||
** and the HUNG state will be static if set. | ** and the HUNG state will be static if set. | ||||
*/ | */ | ||||
if (this_tick - txq->ift_last_timer_tick >= hz / 2) { | |||||
txq->ift_last_timer_tick = this_tick; | |||||
IFDI_TIMER(ctx, txq->ift_id); | IFDI_TIMER(ctx, txq->ift_id); | ||||
if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) && | if ((txq->ift_qstatus == IFLIB_QUEUE_HUNG) && | ||||
((txq->ift_cleaned_prev == txq->ift_cleaned) || | ((txq->ift_cleaned_prev == txq->ift_cleaned) || | ||||
(sctx->isc_pause_frames == 0))) | (sctx->isc_pause_frames == 0))) | ||||
goto hung; | goto hung; | ||||
if (ifmp_ring_is_stalled(txq->ift_br)) | if (ifmp_ring_is_stalled(txq->ift_br)) | ||||
txq->ift_qstatus = IFLIB_QUEUE_HUNG; | txq->ift_qstatus = IFLIB_QUEUE_HUNG; | ||||
txq->ift_cleaned_prev = txq->ift_cleaned; | txq->ift_cleaned_prev = txq->ift_cleaned; | ||||
} | |||||
#ifdef DEV_NETMAP | |||||
if (if_getcapenable(ctx->ifc_ifp) & IFCAP_NETMAP) | |||||
iflib_netmap_timer_adjust(ctx, txq->ift_id, &reset_on); | |||||
#endif | |||||
/* handle any laggards */ | /* handle any laggards */ | ||||
if (txq->ift_db_pending) | if (txq->ift_db_pending) | ||||
GROUPTASK_ENQUEUE(&txq->ift_task); | GROUPTASK_ENQUEUE(&txq->ift_task); | ||||
sctx->isc_pause_frames = 0; | sctx->isc_pause_frames = 0; | ||||
if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) | if (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING) | ||||
callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, txq->ift_timer.c_cpu); | callout_reset_on(&txq->ift_timer, reset_on, iflib_timer, txq, txq->ift_timer.c_cpu); | ||||
return; | return; | ||||
hung: | hung: | ||||
device_printf(ctx->ifc_dev, "TX(%d) desc avail = %d, pidx = %d\n", | device_printf(ctx->ifc_dev, "TX(%d) desc avail = %d, pidx = %d\n", | ||||
txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx); | txq->ift_id, TXQ_AVAIL(txq), txq->ift_pidx); | ||||
STATE_LOCK(ctx); | STATE_LOCK(ctx); | ||||
if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); | if_setdrvflagbits(ctx->ifc_ifp, IFF_DRV_OACTIVE, IFF_DRV_RUNNING); | ||||
ctx->ifc_flags |= (IFC_DO_WATCHDOG|IFC_DO_RESET); | ctx->ifc_flags |= (IFC_DO_WATCHDOG|IFC_DO_RESET); | ||||
iflib_admin_intr_deferred(ctx); | iflib_admin_intr_deferred(ctx); | ||||
▲ Show 20 Lines • Show All 1,497 Lines • ▼ Show 20 Lines | _task_fn_tx(void *context) | ||||
struct ifnet *ifp = ctx->ifc_ifp; | struct ifnet *ifp = ctx->ifc_ifp; | ||||
#ifdef IFLIB_DIAGNOSTICS | #ifdef IFLIB_DIAGNOSTICS | ||||
txq->ift_cpu_exec_count[curcpu]++; | txq->ift_cpu_exec_count[curcpu]++; | ||||
#endif | #endif | ||||
if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) | if (!(if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING)) | ||||
return; | return; | ||||
if (if_getcapenable(ifp) & IFCAP_NETMAP) { | if (if_getcapenable(ifp) & IFCAP_NETMAP) { | ||||
/* | |||||
* If there are no available credits, and TX IRQs are not in use, | |||||
* re-schedule the task immediately. | |||||
*/ | |||||
if (ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, false)) | if (ctx->isc_txd_credits_update(ctx->ifc_softc, txq->ift_id, false)) | ||||
netmap_tx_irq(ifp, txq->ift_id); | netmap_tx_irq(ifp, txq->ift_id); | ||||
IFDI_TX_QUEUE_INTR_ENABLE(ctx, txq->ift_id); | IFDI_TX_QUEUE_INTR_ENABLE(ctx, txq->ift_id); | ||||
return; | return; | ||||
} | } | ||||
if (txq->ift_db_pending) | if (txq->ift_db_pending) | ||||
ifmp_ring_enqueue(txq->ift_br, (void **)&txq, 1, TX_BATCH_SIZE); | ifmp_ring_enqueue(txq->ift_br, (void **)&txq, 1, TX_BATCH_SIZE); | ||||
ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE); | ifmp_ring_check_drainage(txq->ift_br, TX_BATCH_SIZE); | ||||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
_task_fn_admin(void *context) | _task_fn_admin(void *context) | ||||
{ | { | ||||
if_ctx_t ctx = context; | if_ctx_t ctx = context; | ||||
if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; | if_softc_ctx_t sctx = &ctx->ifc_softc_ctx; | ||||
iflib_txq_t txq; | iflib_txq_t txq; | ||||
int i; | int i; | ||||
bool oactive, running, do_reset, do_watchdog; | bool oactive, running, do_reset, do_watchdog; | ||||
uint32_t reset_on = hz / 2; | |||||
STATE_LOCK(ctx); | STATE_LOCK(ctx); | ||||
running = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING); | running = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_RUNNING); | ||||
oactive = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE); | oactive = (if_getdrvflags(ctx->ifc_ifp) & IFF_DRV_OACTIVE); | ||||
do_reset = (ctx->ifc_flags & IFC_DO_RESET); | do_reset = (ctx->ifc_flags & IFC_DO_RESET); | ||||
do_watchdog = (ctx->ifc_flags & IFC_DO_WATCHDOG); | do_watchdog = (ctx->ifc_flags & IFC_DO_WATCHDOG); | ||||
ctx->ifc_flags &= ~(IFC_DO_RESET|IFC_DO_WATCHDOG); | ctx->ifc_flags &= ~(IFC_DO_RESET|IFC_DO_WATCHDOG); | ||||
STATE_UNLOCK(ctx); | STATE_UNLOCK(ctx); | ||||
if ((!running & !oactive) && | if ((!running & !oactive) && | ||||
!(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN)) | !(ctx->ifc_sctx->isc_flags & IFLIB_ADMIN_ALWAYS_RUN)) | ||||
return; | return; | ||||
CTX_LOCK(ctx); | CTX_LOCK(ctx); | ||||
for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) { | for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) { | ||||
CALLOUT_LOCK(txq); | CALLOUT_LOCK(txq); | ||||
callout_stop(&txq->ift_timer); | callout_stop(&txq->ift_timer); | ||||
CALLOUT_UNLOCK(txq); | CALLOUT_UNLOCK(txq); | ||||
} | } | ||||
if (do_watchdog) { | if (do_watchdog) { | ||||
ctx->ifc_watchdog_events++; | ctx->ifc_watchdog_events++; | ||||
IFDI_WATCHDOG_RESET(ctx); | IFDI_WATCHDOG_RESET(ctx); | ||||
} | } | ||||
IFDI_UPDATE_ADMIN_STATUS(ctx); | IFDI_UPDATE_ADMIN_STATUS(ctx); | ||||
for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) | for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) { | ||||
callout_reset_on(&txq->ift_timer, hz/2, iflib_timer, txq, txq->ift_timer.c_cpu); | #ifdef DEV_NETMAP | ||||
reset_on = hz / 2; | |||||
if (if_getcapenable(ctx->ifc_ifp) & IFCAP_NETMAP) | |||||
iflib_netmap_timer_adjust(ctx, txq->ift_id, &reset_on); | |||||
#endif | |||||
callout_reset_on(&txq->ift_timer, reset_on, iflib_timer, txq, txq->ift_timer.c_cpu); | |||||
} | |||||
IFDI_LINK_INTR_ENABLE(ctx); | IFDI_LINK_INTR_ENABLE(ctx); | ||||
if (do_reset) | if (do_reset) | ||||
iflib_if_init_locked(ctx); | iflib_if_init_locked(ctx); | ||||
CTX_UNLOCK(ctx); | CTX_UNLOCK(ctx); | ||||
if (LINK_ACTIVE(ctx) == 0) | if (LINK_ACTIVE(ctx) == 0) | ||||
return; | return; | ||||
for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) | for (txq = ctx->ifc_txqs, i = 0; i < sctx->isc_ntxqsets; i++, txq++) | ||||
▲ Show 20 Lines • Show All 2,604 Lines • Show Last 20 Lines |
Is there a particular reason for dropping this const?