diff options
Diffstat (limited to 'usr/src/uts/common/io/mac/mac_provider.c')
-rw-r--r-- | usr/src/uts/common/io/mac/mac_provider.c | 353 |
1 files changed, 317 insertions, 36 deletions
diff --git a/usr/src/uts/common/io/mac/mac_provider.c b/usr/src/uts/common/io/mac/mac_provider.c index 43501e3505..f0fe17ae0a 100644 --- a/usr/src/uts/common/io/mac/mac_provider.c +++ b/usr/src/uts/common/io/mac/mac_provider.c @@ -40,6 +40,7 @@ #include <sys/mac_client_impl.h> #include <sys/mac_client_priv.h> #include <sys/mac_soft_ring.h> +#include <sys/mac_stat.h> #include <sys/dld.h> #include <sys/modctl.h> #include <sys/fs/dv_node.h> @@ -53,6 +54,8 @@ #include <sys/ddi_intr_impl.h> #include <sys/disp.h> #include <sys/sdt.h> +#include <sys/pattr.h> +#include <sys/strsun.h> /* * MAC Provider Interface. @@ -298,8 +301,7 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) /* * Register the private properties. */ - mac_register_priv_prop(mip, mregp->m_priv_props, - mregp->m_priv_prop_count); + mac_register_priv_prop(mip, mregp->m_priv_props); /* * Stash the driver callbacks into the mac_impl_t, but first sanity @@ -334,6 +336,9 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) * Initialize the capabilities */ + bzero(&mip->mi_rx_rings_cap, sizeof (mac_capab_rings_t)); + bzero(&mip->mi_tx_rings_cap, sizeof (mac_capab_rings_t)); + if (i_mac_capab_get((mac_handle_t)mip, MAC_CAPAB_VNIC, NULL)) mip->mi_state_flags |= MIS_IS_VNIC; @@ -371,18 +376,6 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) } /* - * The driver must set mc_tx entry point to NULL when it advertises - * CAP_RINGS for tx rings. - */ - if (mip->mi_tx_groups != NULL) { - if (mregp->m_callbacks->mc_tx != NULL) - goto fail; - } else { - if (mregp->m_callbacks->mc_tx == NULL) - goto fail; - } - - /* * Initialize MAC addresses. Must be called after mac_init_rings(). */ mac_init_macaddr(mip); @@ -396,7 +389,7 @@ mac_register(mac_register_t *mregp, mac_handle_t *mhp) /* * Initialize the kstats for this device. */ - mac_stat_create(mip); + mac_driver_stat_create(mip); /* Zero out any properties. */ bzero(&mip->mi_resource_props, sizeof (mac_resource_props_t)); @@ -466,7 +459,7 @@ fail: mip->mi_info.mi_unicst_addr = NULL; } - mac_stat_destroy(mip); + mac_driver_stat_delete(mip); if (mip->mi_type != NULL) { atomic_dec_32(&mip->mi_type->mt_ref); @@ -484,6 +477,7 @@ fail: mac_minor_rele(minor); } + mip->mi_state_flags = 0; mac_unregister_priv_prop(mip); /* @@ -532,7 +526,7 @@ mac_unregister(mac_handle_t mh) ASSERT(mip->mi_nactiveclients == 0 && !(mip->mi_state_flags & MIS_EXCLUSIVE)); - mac_stat_destroy(mip); + mac_driver_stat_delete(mip); (void) mod_hash_remove(i_mac_impl_hash, (mod_hash_key_t)mip->mi_name, &val); @@ -772,11 +766,7 @@ mac_rx_common(mac_handle_t mh, mac_resource_handle_t mrh, mblk_t *mp_chain) void mac_tx_update(mac_handle_t mh) { - /* - * Walk the list of MAC clients (mac_client_handle) - * and update - */ - i_mac_tx_srs_notify((mac_impl_t *)mh, NULL); + mac_tx_ring_update(mh, NULL); } /* @@ -959,6 +949,151 @@ mac_maxsdu_update(mac_handle_t mh, uint_t sdu_max) return (0); } +static void +mac_ring_intr_retarget(mac_group_t *group, mac_ring_t *ring) +{ + mac_client_impl_t *mcip; + flow_entry_t *flent; + mac_soft_ring_set_t *mac_rx_srs; + mac_cpus_t *srs_cpu; + int i; + + if (((mcip = MAC_GROUP_ONLY_CLIENT(group)) != NULL) && + (!ring->mr_info.mri_intr.mi_ddi_shared)) { + /* interrupt can be re-targeted */ + ASSERT(group->mrg_state == MAC_GROUP_STATE_RESERVED); + flent = mcip->mci_flent; + if (ring->mr_type == MAC_RING_TYPE_RX) { + for (i = 0; i < flent->fe_rx_srs_cnt; i++) { + mac_rx_srs = flent->fe_rx_srs[i]; + if (mac_rx_srs->srs_ring != ring) + continue; + srs_cpu = &mac_rx_srs->srs_cpu; + mutex_enter(&cpu_lock); + mac_rx_srs_retarget_intr(mac_rx_srs, + srs_cpu->mc_rx_intr_cpu); + mutex_exit(&cpu_lock); + break; + } + } else { + if (flent->fe_tx_srs != NULL) { + mutex_enter(&cpu_lock); + mac_tx_srs_retarget_intr( + flent->fe_tx_srs); + mutex_exit(&cpu_lock); + } + } + } +} + +/* + * Clients like aggr create pseudo rings (mac_ring_t) and expose them to + * their clients. There is a 1-1 mapping pseudo ring and the hardware + * ring. ddi interrupt handles are exported from the hardware ring to + * the pseudo ring. Thus when the interrupt handle changes, clients of + * aggr that are using the handle need to use the new handle and + * re-target their interrupts. + */ +static void +mac_pseudo_ring_intr_retarget(mac_impl_t *mip, mac_ring_t *ring, + ddi_intr_handle_t ddh) +{ + mac_ring_t *pring; + mac_group_t *pgroup; + mac_impl_t *pmip; + char macname[MAXNAMELEN]; + mac_perim_handle_t p_mph; + uint64_t saved_gen_num; + +again: + pring = (mac_ring_t *)ring->mr_prh; + pgroup = (mac_group_t *)pring->mr_gh; + pmip = (mac_impl_t *)pgroup->mrg_mh; + saved_gen_num = ring->mr_gen_num; + (void) strlcpy(macname, pmip->mi_name, MAXNAMELEN); + /* + * We need to enter aggr's perimeter. The locking hierarchy + * dictates that aggr's perimeter should be entered first + * and then the port's perimeter. So drop the port's + * perimeter, enter aggr's and then re-enter port's + * perimeter. + */ + i_mac_perim_exit(mip); + /* + * While we know pmip is the aggr's mip, there is a + * possibility that aggr could have unregistered by + * the time we exit port's perimeter (mip) and + * enter aggr's perimeter (pmip). To avoid that + * scenario, enter aggr's perimeter using its name. + */ + if (mac_perim_enter_by_macname(macname, &p_mph) != 0) + return; + i_mac_perim_enter(mip); + /* + * Check if the ring got assigned to another aggregation before + * be could enter aggr's and the port's perimeter. When a ring + * gets deleted from an aggregation, it calls mac_stop_ring() + * which increments the generation number. So checking + * generation number will be enough. + */ + if (ring->mr_gen_num != saved_gen_num && ring->mr_prh != NULL) { + i_mac_perim_exit(mip); + mac_perim_exit(p_mph); + i_mac_perim_enter(mip); + goto again; + } + + /* Check if pseudo ring is still present */ + if (ring->mr_prh != NULL) { + pring->mr_info.mri_intr.mi_ddi_handle = ddh; + pring->mr_info.mri_intr.mi_ddi_shared = + ring->mr_info.mri_intr.mi_ddi_shared; + if (ddh != NULL) + mac_ring_intr_retarget(pgroup, pring); + } + i_mac_perim_exit(mip); + mac_perim_exit(p_mph); +} +/* + * API called by driver to provide new interrupt handle for TX/RX rings. + * This usually happens when IRM (Interrupt Resource Manangement) + * framework either gives the driver more MSI-x interrupts or takes + * away MSI-x interrupts from the driver. + */ +void +mac_ring_intr_set(mac_ring_handle_t mrh, ddi_intr_handle_t ddh) +{ + mac_ring_t *ring = (mac_ring_t *)mrh; + mac_group_t *group = (mac_group_t *)ring->mr_gh; + mac_impl_t *mip = (mac_impl_t *)group->mrg_mh; + + i_mac_perim_enter(mip); + ring->mr_info.mri_intr.mi_ddi_handle = ddh; + if (ddh == NULL) { + /* Interrupts being reset */ + ring->mr_info.mri_intr.mi_ddi_shared = B_FALSE; + if (ring->mr_prh != NULL) { + mac_pseudo_ring_intr_retarget(mip, ring, ddh); + return; + } + } else { + /* New interrupt handle */ + mac_compare_ddi_handle(mip->mi_rx_groups, + mip->mi_rx_group_count, ring); + if (!ring->mr_info.mri_intr.mi_ddi_shared) { + mac_compare_ddi_handle(mip->mi_tx_groups, + mip->mi_tx_group_count, ring); + } + if (ring->mr_prh != NULL) { + mac_pseudo_ring_intr_retarget(mip, ring, ddh); + return; + } else { + mac_ring_intr_retarget(group, ring); + } + } + i_mac_perim_exit(mip); +} + /* PRIVATE FUNCTIONS, FOR INTERNAL USE ONLY */ /* @@ -1141,16 +1276,8 @@ mac_group_add_ring(mac_group_handle_t gh, int index) int ret; i_mac_perim_enter(mip); - - /* - * Only RX rings can be added or removed by drivers currently. - */ - ASSERT(group->mrg_type == MAC_RING_TYPE_RX); - ret = i_mac_group_add_ring(group, NULL, index); - i_mac_perim_exit(mip); - return (ret); } @@ -1166,13 +1293,167 @@ mac_group_rem_ring(mac_group_handle_t gh, mac_ring_handle_t rh) mac_impl_t *mip = (mac_impl_t *)group->mrg_mh; i_mac_perim_enter(mip); + i_mac_group_rem_ring(group, (mac_ring_t *)rh, B_TRUE); + i_mac_perim_exit(mip); +} - /* - * Only RX rings can be added or removed by drivers currently. - */ - ASSERT(group->mrg_type == MAC_RING_TYPE_RX); +/* + * mac_prop_info_*() callbacks called from the driver's prefix_propinfo() + * entry points. + */ - i_mac_group_rem_ring(group, (mac_ring_t *)rh, B_TRUE); +void +mac_prop_info_set_default_uint8(mac_prop_info_handle_t ph, uint8_t val) +{ + mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph; - i_mac_perim_exit(mip); + /* nothing to do if the caller doesn't want the default value */ + if (pr->pr_default == NULL) + return; + + ASSERT(pr->pr_default_size >= sizeof (uint8_t)); + + *(uint8_t *)(pr->pr_default) = val; + pr->pr_flags |= MAC_PROP_INFO_DEFAULT; +} + +void +mac_prop_info_set_default_uint64(mac_prop_info_handle_t ph, uint64_t val) +{ + mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph; + + /* nothing to do if the caller doesn't want the default value */ + if (pr->pr_default == NULL) + return; + + ASSERT(pr->pr_default_size >= sizeof (uint64_t)); + + bcopy(&val, pr->pr_default, sizeof (val)); + + pr->pr_flags |= MAC_PROP_INFO_DEFAULT; +} + +void +mac_prop_info_set_default_uint32(mac_prop_info_handle_t ph, uint32_t val) +{ + mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph; + + /* nothing to do if the caller doesn't want the default value */ + if (pr->pr_default == NULL) + return; + + ASSERT(pr->pr_default_size >= sizeof (uint32_t)); + + bcopy(&val, pr->pr_default, sizeof (val)); + + pr->pr_flags |= MAC_PROP_INFO_DEFAULT; +} + +void +mac_prop_info_set_default_str(mac_prop_info_handle_t ph, const char *str) +{ + mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph; + + /* nothing to do if the caller doesn't want the default value */ + if (pr->pr_default == NULL) + return; + + if (strlen(str) > pr->pr_default_size) + pr->pr_default_status = ENOBUFS; + else + (void) strlcpy(pr->pr_default, str, strlen(str)); + pr->pr_flags |= MAC_PROP_INFO_DEFAULT; +} + +void +mac_prop_info_set_default_link_flowctrl(mac_prop_info_handle_t ph, + link_flowctrl_t val) +{ + mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph; + + /* nothing to do if the caller doesn't want the default value */ + if (pr->pr_default == NULL) + return; + + ASSERT(pr->pr_default_size >= sizeof (link_flowctrl_t)); + + bcopy(&val, pr->pr_default, sizeof (val)); + + pr->pr_flags |= MAC_PROP_INFO_DEFAULT; +} + +void +mac_prop_info_set_range_uint32(mac_prop_info_handle_t ph, uint32_t min, + uint32_t max) +{ + mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph; + mac_propval_range_t *range = pr->pr_range; + + /* nothing to do if the caller doesn't want the range info */ + if (range == NULL) + return; + + range->mpr_count = 1; + range->mpr_type = MAC_PROPVAL_UINT32; + range->mpr_range_uint32[0].mpur_min = min; + range->mpr_range_uint32[0].mpur_max = max; + pr->pr_flags |= MAC_PROP_INFO_RANGE; +} + +void +mac_prop_info_set_perm(mac_prop_info_handle_t ph, uint8_t perm) +{ + mac_prop_info_state_t *pr = (mac_prop_info_state_t *)ph; + + pr->pr_perm = perm; + pr->pr_flags |= MAC_PROP_INFO_PERM; +} + +void mac_hcksum_get(mblk_t *mp, uint32_t *start, uint32_t *stuff, + uint32_t *end, uint32_t *value, uint32_t *flags_ptr) +{ + uint32_t flags; + + ASSERT(DB_TYPE(mp) == M_DATA); + + flags = DB_CKSUMFLAGS(mp) & HCK_FLAGS; + if ((flags & (HCK_PARTIALCKSUM | HCK_FULLCKSUM)) != 0) { + if (value != NULL) + *value = (uint32_t)DB_CKSUM16(mp); + if ((flags & HCK_PARTIALCKSUM) != 0) { + if (start != NULL) + *start = (uint32_t)DB_CKSUMSTART(mp); + if (stuff != NULL) + *stuff = (uint32_t)DB_CKSUMSTUFF(mp); + if (end != NULL) + *end = (uint32_t)DB_CKSUMEND(mp); + } + } + + if (flags_ptr != NULL) + *flags_ptr = flags; +} + +void mac_hcksum_set(mblk_t *mp, uint32_t start, uint32_t stuff, + uint32_t end, uint32_t value, uint32_t flags) +{ + ASSERT(DB_TYPE(mp) == M_DATA); + + DB_CKSUMSTART(mp) = (intptr_t)start; + DB_CKSUMSTUFF(mp) = (intptr_t)stuff; + DB_CKSUMEND(mp) = (intptr_t)end; + DB_CKSUMFLAGS(mp) = (uint16_t)flags; + DB_CKSUM16(mp) = (uint16_t)value; +} + +void +mac_lso_get(mblk_t *mp, uint32_t *mss, uint32_t *flags) +{ + ASSERT(DB_TYPE(mp) == M_DATA); + + if (flags != NULL) { + *flags = DB_CKSUMFLAGS(mp) & HW_LSO; + if ((*flags != 0) && (mss != NULL)) + *mss = (uint32_t)DB_LSOMSS(mp); + } } |