/* * Main routine for the callbacks notifications thread */ static void i_mac_notify_thread(void *arg) { mac_impl_t *mip = arg; callb_cpr_t cprinfo; mac_cb_t *mcb; mac_cb_info_t *mcbi; mac_notify_cb_t *mncb; mcbi = &mip->mi_notify_cb_info; CALLB_CPR_INIT(&cprinfo, mcbi->mcbi_lockp, callb_generic_cpr, "i_mac_notify_thread"); mutex_enter(mcbi->mcbi_lockp); for (;;) { uint32_t bits; uint32_t type; bits = mip->mi_notify_bits; if (bits == 0) { CALLB_CPR_SAFE_BEGIN(&cprinfo); cv_wait(&mcbi->mcbi_cv, mcbi->mcbi_lockp); CALLB_CPR_SAFE_END(&cprinfo, mcbi->mcbi_lockp); continue; } mip->mi_notify_bits = 0; if ((bits & (1 << MAC_NNOTE)) != 0) { /* request to quit */ ASSERT(mip->mi_state_flags & MIS_DISABLED); break; } mutex_exit(mcbi->mcbi_lockp); /* * Log link changes on the actual link, but then do reports on * synthetic state (if part of a bridge). */ if ((bits & (1 << MAC_NOTE_LOWLINK)) != 0) { link_state_t newstate; mac_handle_t mh; i_mac_log_link_state(mip); newstate = mip->mi_lowlinkstate; if (mip->mi_bridge_link != NULL) { mutex_enter(&mip->mi_bridge_lock); if ((mh = mip->mi_bridge_link) != NULL) { newstate = mac_bridge_ls_cb(mh, newstate); } mutex_exit(&mip->mi_bridge_lock); } if (newstate != mip->mi_linkstate) { mip->mi_linkstate = newstate; bits |= 1 << MAC_NOTE_LINK; } } /* * Do notification callbacks for each notification type. */ for (type = 0; type < MAC_NNOTE; type++) { if ((bits & (1 << type)) == 0) { continue; } if (mac_notify_cb_list[type] != NULL) (*mac_notify_cb_list[type])(mip); /* * Walk the list of notifications. */ MAC_CALLBACK_WALKER_INC(&mip->mi_notify_cb_info); for (mcb = mip->mi_notify_cb_list; mcb != NULL; mcb = mcb->mcb_nextp) { mncb = (mac_notify_cb_t *)mcb->mcb_objp; mncb->mncb_fn(mncb->mncb_arg, type); } MAC_CALLBACK_WALKER_DCR(&mip->mi_notify_cb_info, &mip->mi_notify_cb_list); } mutex_enter(mcbi->mcbi_lockp); } mip->mi_state_flags |= MIS_NOTIFY_DONE; cv_broadcast(&mcbi->mcbi_cv); /* CALLB_CPR_EXIT drops the lock */ CALLB_CPR_EXIT(&cprinfo); thread_exit(); }
/* * mac_tx_soft_ring_drain * * The transmit side drain routine in case the soft ring was being * used to transmit packets. */ static void mac_tx_soft_ring_drain(mac_soft_ring_t *ringp) { mblk_t *mp; void *arg1; void *arg2; mblk_t *tail; uint_t saved_pkt_count, saved_size; boolean_t is_subflow; mac_tx_stats_t stats; mac_soft_ring_set_t *mac_srs = ringp->s_ring_set; saved_pkt_count = saved_size = 0; ringp->s_ring_run = curthread; ASSERT(mutex_owned(&ringp->s_ring_lock)); ASSERT(!(ringp->s_ring_state & S_RING_PROC)); ringp->s_ring_state |= S_RING_PROC; is_subflow = ((mac_srs->srs_type & SRST_FLOW) != 0); arg1 = ringp->s_ring_tx_arg1; arg2 = ringp->s_ring_tx_arg2; while (ringp->s_ring_first != NULL) { mp = ringp->s_ring_first; tail = ringp->s_ring_last; saved_pkt_count = ringp->s_ring_count; saved_size = ringp->s_ring_size; ringp->s_ring_first = NULL; ringp->s_ring_last = NULL; ringp->s_ring_count = 0; ringp->s_ring_size = 0; mutex_exit(&ringp->s_ring_lock); mp = mac_tx_send(arg1, arg2, mp, &stats); mutex_enter(&ringp->s_ring_lock); if (mp != NULL) { /* Device out of tx desc, set block */ tail->b_next = ringp->s_ring_first; ringp->s_ring_first = mp; ringp->s_ring_count += (saved_pkt_count - stats.ts_opackets); ringp->s_ring_size += (saved_size - stats.ts_obytes); if (ringp->s_ring_last == NULL) ringp->s_ring_last = tail; if (ringp->s_ring_tx_woken_up) { ringp->s_ring_tx_woken_up = B_FALSE; } else { ringp->s_ring_state |= S_RING_BLOCK; ringp->s_ring_blocked_cnt++; } ringp->s_ring_state &= ~S_RING_PROC; ringp->s_ring_run = NULL; return; } else { ringp->s_ring_tx_woken_up = B_FALSE; if (is_subflow) { FLOW_TX_STATS_UPDATE( mac_srs->srs_flent, &stats); } } } if (ringp->s_ring_count == 0 && ringp->s_ring_state & (S_RING_TX_HIWAT | S_RING_WAKEUP_CLIENT | S_RING_ENQUEUED)) { mac_tx_notify_cb_t *mtnfp; mac_cb_t *mcb; mac_client_impl_t *mcip = ringp->s_ring_mcip; boolean_t wakeup_required = B_FALSE; if (ringp->s_ring_state & (S_RING_TX_HIWAT|S_RING_WAKEUP_CLIENT)) { wakeup_required = B_TRUE; } ringp->s_ring_state &= ~(S_RING_TX_HIWAT | S_RING_WAKEUP_CLIENT | S_RING_ENQUEUED); mutex_exit(&ringp->s_ring_lock); if (wakeup_required) { /* Wakeup callback registered clients */ MAC_CALLBACK_WALKER_INC(&mcip->mci_tx_notify_cb_info); for (mcb = mcip->mci_tx_notify_cb_list; mcb != NULL; mcb = mcb->mcb_nextp) { mtnfp = (mac_tx_notify_cb_t *)mcb->mcb_objp; mtnfp->mtnf_fn(mtnfp->mtnf_arg, (mac_tx_cookie_t)ringp); } MAC_CALLBACK_WALKER_DCR(&mcip->mci_tx_notify_cb_info, &mcip->mci_tx_notify_cb_list); /* * If the client is not the primary MAC client, then we * need to send the notification to the clients upper * MAC, i.e. mci_upper_mip. */ mac_tx_notify(mcip->mci_upper_mip != NULL ? mcip->mci_upper_mip : mcip->mci_mip); } mutex_enter(&ringp->s_ring_lock); } ringp->s_ring_state &= ~S_RING_PROC; ringp->s_ring_run = NULL; }