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 2008 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_soft_ring.h> 36 37 38 /* 39 * Return the number of shares supported by the specified MAC. 40 */ 41 int 42 mac_share_capable(mac_handle_t mh) 43 { 44 mac_impl_t *mip = (mac_impl_t *)mh; 45 46 return (mip->mi_share_capab.ms_snum); 47 } 48 49 50 /* 51 * Allocate a share to the specified MAC client. Invoked when 52 * mac_client_open() is invoked with MAC_OPEN_FLAGS_SHARES_DESIRED set. 53 */ 54 void 55 i_mac_share_alloc(mac_client_impl_t *mcip) 56 { 57 mac_impl_t *mip = mcip->mci_mip; 58 int rv; 59 60 i_mac_perim_enter(mip); 61 62 ASSERT(mcip->mci_share == NULL); 63 64 if (mac_share_capable((mac_handle_t)mcip->mci_mip) == 0) { 65 DTRACE_PROBE1(i__mac__share__alloc__not__sup, 66 mac_client_impl_t *, mcip); 67 i_mac_perim_exit(mip); 68 return; 69 } 70 71 rv = mip->mi_share_capab.ms_salloc(mip->mi_share_capab.ms_handle, 72 &mcip->mci_share); 73 DTRACE_PROBE3(i__mac__share__alloc, mac_client_impl_t *, mcip, 74 int, rv, mac_share_handle_t, mcip->mci_share); 75 76 mcip->mci_state_flags &= ~MCIS_SHARE_BOUND; 77 78 i_mac_perim_exit(mip); 79 } 80 81 82 /* 83 * Free a share previously allocated through i_mac_share_alloc(). 84 * Safely handles the case when no shares were allocated to the MAC client. 85 */ 86 void 87 i_mac_share_free(mac_client_impl_t *mcip) 88 { 89 mac_impl_t *mip = mcip->mci_mip; 90 91 i_mac_perim_enter(mip); 92 93 /* MAC clients are required to unbind they shares before freeing them */ 94 ASSERT((mcip->mci_state_flags & MCIS_SHARE_BOUND) == 0); 95 96 if (mcip->mci_share == NULL) { 97 i_mac_perim_exit(mip); 98 return; 99 } 100 101 mip->mi_share_capab.ms_sfree(mcip->mci_share); 102 i_mac_perim_exit(mip); 103 } 104 105 106 /* 107 * Bind a share. After this operation the rings that were associated 108 * with the MAC client are mapped directly into the corresponding 109 * guest domain. 110 */ 111 int 112 mac_share_bind(mac_client_handle_t mch, uint64_t cookie, uint64_t *rcookie) 113 { 114 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 115 mac_impl_t *mip = mcip->mci_mip; 116 int rv; 117 118 i_mac_perim_enter(mip); 119 120 if (mcip->mci_share == NULL) { 121 i_mac_perim_exit(mip); 122 return (ENOTSUP); 123 } 124 125 ASSERT((mcip->mci_state_flags & MCIS_SHARE_BOUND) == 0); 126 127 /* 128 * Temporarly suspend the TX traffic for that client to make sure 129 * there are no in flight packets through a transmit ring 130 * which is being bound to another domain. 131 */ 132 mac_tx_client_quiesce(mcip, SRS_QUIESCE); 133 134 /* 135 * For the receive path, no traffic will be sent up through 136 * the rings to the IO domain. For TX, we need to ensure 137 * that traffic sent by the MAC client are sent through 138 * the default ring. 139 * 140 * For the transmit path we ensure that packets are sent through the 141 * default ring if the share of the MAC client is bound, see MAC_TX(). 142 */ 143 144 rv = mip->mi_share_capab.ms_sbind(mcip->mci_share, cookie, rcookie); 145 if (rv == 0) 146 mcip->mci_state_flags |= MCIS_SHARE_BOUND; 147 148 /* 149 * Resume transmit traffic for the MAC client. 150 */ 151 mac_tx_client_restart(mcip); 152 153 i_mac_perim_exit(mip); 154 155 return (rv); 156 } 157 158 159 /* 160 * Unbind a share. 161 */ 162 void 163 mac_share_unbind(mac_client_handle_t mch) 164 { 165 mac_client_impl_t *mcip = (mac_client_impl_t *)mch; 166 mac_impl_t *mip = mcip->mci_mip; 167 168 i_mac_perim_enter(mip); 169 170 if (mcip->mci_share == NULL) { 171 i_mac_perim_exit(mip); 172 return; 173 } 174 175 mip->mi_share_capab.ms_sunbind(mcip->mci_share); 176 177 mcip->mci_state_flags &= ~MCIS_SHARE_BOUND; 178 179 /* 180 * If the link state changed while the share was bound, the 181 * soft rings fanout associated with the client would have not 182 * been updated by mac_fanout_recompute(). Do the check here 183 * now that the share has been unbound. 184 */ 185 mac_fanout_recompute_client(mcip); 186 187 i_mac_perim_exit(mip); 188 } 189