xref: /illumos-gate/usr/src/uts/common/io/mac/mac_hio.c (revision 46b592853d0f4f11781b6b0a7533f267c6aee132)
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