1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * MAC Hybrid I/O related code. 28 */ 29 30 #include <sys/types.h> 31 #include <sys/sdt.h> 32 #include <sys/mac.h> 33 #include <sys/mac_impl.h> 34 #include <sys/mac_client_impl.h> 35 #include <sys/mac_client_priv.h> 36 #include <sys/mac_soft_ring.h> 37 38 39 /* 40 * Return the number of shares supported by the specified MAC. 41 */ 42 int 43 mac_share_capable(mac_handle_t mh) 44 { 45 mac_impl_t *mip = (mac_impl_t *)mh; 46 47 return (mip->mi_share_capab.ms_snum); 48 } 49 50 51 /* 52 * Allocate a share to the specified MAC client. Invoked when 53 * mac_client_open() is invoked with MAC_OPEN_FLAGS_SHARES_DESIRED set. 54 */ 55 void 56 i_mac_share_alloc(mac_client_impl_t *mcip) 57 { 58 mac_impl_t *mip = mcip->mci_mip; 59 int rv; 60 61 i_mac_perim_enter(mip); 62 63 ASSERT(mcip->mci_share == 0); 64 65 if (mac_share_capable((mac_handle_t)mcip->mci_mip) == 0) { 66 DTRACE_PROBE1(i__mac__share__alloc__not__sup, 67 mac_client_impl_t *, mcip); 68 i_mac_perim_exit(mip); 69 return; 70 } 71 72 rv = mip->mi_share_capab.ms_salloc(mip->mi_share_capab.ms_handle, 73 &mcip->mci_share); 74 DTRACE_PROBE3(i__mac__share__alloc, mac_client_impl_t *, mcip, 75 int, rv, mac_share_handle_t, mcip->mci_share); 76 77 mcip->mci_state_flags &= ~MCIS_SHARE_BOUND; 78 79 i_mac_perim_exit(mip); 80 } 81 82 83 /* 84 * Free a share previously allocated through i_mac_share_alloc(). 85 * Safely handles the case when no shares were allocated to the MAC client. 86 */ 87 void 88 i_mac_share_free(mac_client_impl_t *mcip) 89 { 90 mac_impl_t *mip = mcip->mci_mip; 91 92 i_mac_perim_enter(mip); 93 94 /* MAC clients are required to unbind they shares before freeing them */ 95 ASSERT((mcip->mci_state_flags & MCIS_SHARE_BOUND) == 0); 96 97 if (mcip->mci_share == 0) { 98 i_mac_perim_exit(mip); 99 return; 100 } 101 102 mip->mi_share_capab.ms_sfree(mcip->mci_share); 103 i_mac_perim_exit(mip); 104 } 105 106 107 /* 108 * Bind a share. After this operation the rings that were associated 109 * with the MAC client are mapped directly into the corresponding 110 * guest domain. 111 */ 112 int 113 mac_share_bind(mac_client_handle_t mch, uint64_t cookie, uint64_t *rcookie) 114 { 115 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 116 mac_impl_t *mip = mcip->mci_mip; 117 int rv; 118 119 i_mac_perim_enter(mip); 120 121 if (mcip->mci_share == 0) { 122 i_mac_perim_exit(mip); 123 return (ENOTSUP); 124 } 125 126 ASSERT((mcip->mci_state_flags & MCIS_SHARE_BOUND) == 0); 127 128 /* 129 * Temporarly suspend the TX traffic for that client to make sure 130 * there are no in flight packets through a transmit ring 131 * which is being bound to another domain. 132 */ 133 mac_tx_client_quiesce(mch); 134 135 /* 136 * For the receive path, no traffic will be sent up through 137 * the rings to the IO domain. For TX, we need to ensure 138 * that traffic sent by the MAC client are sent through 139 * the default ring. 140 * 141 * For the transmit path we ensure that packets are sent through the 142 * default ring if the share of the MAC client is bound, see MAC_TX(). 143 */ 144 145 rv = mip->mi_share_capab.ms_sbind(mcip->mci_share, cookie, rcookie); 146 if (rv == 0) 147 mcip->mci_state_flags |= MCIS_SHARE_BOUND; 148 149 /* 150 * Resume transmit traffic for the MAC client. 151 */ 152 mac_tx_client_restart(mch); 153 154 i_mac_perim_exit(mip); 155 156 return (rv); 157 } 158 159 160 /* 161 * Unbind a share. 162 */ 163 void 164 mac_share_unbind(mac_client_handle_t mch) 165 { 166 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 167 mac_impl_t *mip = mcip->mci_mip; 168 169 i_mac_perim_enter(mip); 170 171 if (mcip->mci_share == 0) { 172 i_mac_perim_exit(mip); 173 return; 174 } 175 176 mip->mi_share_capab.ms_sunbind(mcip->mci_share); 177 178 mcip->mci_state_flags &= ~MCIS_SHARE_BOUND; 179 180 /* 181 * If the link state changed while the share was bound, the 182 * soft rings fanout associated with the client would have not 183 * been updated by mac_fanout_recompute(). Do the check here 184 * now that the share has been unbound. 185 */ 186 mac_fanout_recompute_client(mcip, NULL); 187 188 i_mac_perim_exit(mip); 189 } 190